1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * FAT file system File: cfe_fatfs.c 5 * 6 * This module knows how to read files from a FAT formatted 7 * file system (12 or 16 bit fats only for now) 8 * 9 * Eventually, we'll also include support for the FAT Translation 10 * Layer (FTL) on PCMCIA flash file systems. 11 * 12 * Author: Mitch Lichtenberg 13 * 14 ********************************************************************* 15 * 16 * Copyright 2000,2001,2002,2003 17 * Broadcom Corporation. All rights reserved. 18 * 19 * This software is furnished under license and may be used and 20 * copied only in accordance with the following terms and 21 * conditions. Subject to these conditions, you may download, 22 * copy, install, use, modify and distribute modified or unmodified 23 * copies of this software in source and/or binary form. No title 24 * or ownership is transferred hereby. 25 * 26 * 1) Any source code used, modified or distributed must reproduce 27 * and retain this copyright notice and list of conditions 28 * as they appear in the source file. 29 * 30 * 2) No right is granted to use any trade name, trademark, or 31 * logo of Broadcom Corporation. The "Broadcom Corporation" 32 * name may not be used to endorse or promote products derived 33 * from this software without the prior written permission of 34 * Broadcom Corporation. 35 * 36 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 37 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 38 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 39 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 40 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 41 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 44 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 45 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 46 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 47 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 48 * THE POSSIBILITY OF SUCH DAMAGE. 49 ********************************************************************* */ 50 51#include "cfe.h" 52 53#include "cfe_fileops.h" 54 55#include "cfe_loader.h" 56 57 58/* ********************************************************************* 59 * Constants 60 ********************************************************************* */ 61 62#define SECTORSIZE 512 63#define DIRENTRYSIZE 32 64#define DIRPERSECTOR (SECTORSIZE/DIRENTRYSIZE) 65 66/*#define _FATFS_DEBUG_*/ 67 68/* 69 * Bios Parameter Block offsets and values 70 */ 71 72#define BPB_JMPINSTR 0x00 73#define BPB_JMPINSTR_VALUE 0xEB 74#define BPB_JMPINSTR_VALUE2 0xE9 75#define BPB_SEAL 0x1FE 76#define BPB_SEAL_VALUE 0xAA55 77 78#define BPB_BYTESPERSECTOR 0x0B 79#define BPB_SECTORSPERCLUSTER 0x0D 80#define BPB_RESERVEDSECTORS 0x0E 81#define BPB_NUMFATS 0x10 82#define BPB_MAXROOTDIR 0x11 83#define BPB_TOTALSECTORS 0x13 84#define BPB_SECTORSPERFAT 0x16 85#define BPB_SECTORSPERTRACK 0x18 86#define BPB_NUMHEADS 0x1A 87#define BPB_HIDDENSECTORS 0x1C 88#define BPB_SYSTEMID 54 89#define BPB_MEDIADESCRIPTOR 21 90#define BPB_SIGNATURE 38 91#define BPB_SIGNATURE_VALUE1 0x28 92#define BPB_SIGNATURE_VALUE2 0x29 93 94/* 95 * Partition types 96 */ 97 98#define PARTTYPE_EMPTY 0 99#define PARTTYPE_FAT12 1 100#define PARTTYPE_FAT16 4 101#define PARTTYPE_FAT16BIG 6 102#define PARTTYPE_FAT32 0x0B 103 104/* 105 * Partition table offsets 106 */ 107#define PTABLE_STATUS 0 108#define PTABLE_STARTHEAD 1 109#define PTABLE_STARTSECCYL 2 /* 2 bytes */ 110#define PTABLE_TYPE 4 111#define PTABLE_ENDHEAD 5 112#define PTABLE_ENDSECCYL 6 /* 2 bytes */ 113#define PTABLE_BOOTSECTOR 8 /* 4 bytes */ 114#define PTABLE_NUMSECTORS 12 /* 4 bytes */ 115 116#define PTABLE_SIZE 16 117#define PTABLE_COUNT 4 118#define PTABLE_OFFSET (512-2-(PTABLE_COUNT*PTABLE_SIZE)) 119 120#define PTABLE_STATUS_ACTIVE 0x80 121 122/* 123 * Directory attributes 124 */ 125 126#define ATTRIB_NORMAL 0x00 127#define ATTRIB_READONLY 0x01 128#define ATTRIB_HIDDEN 0x02 129#define ATTRIB_SYSTEM 0x04 130#define ATTRIB_LABEL 0x08 131#define ATTRIB_DIR 0x10 132#define ATTRIB_ARCHIVE 0x20 133 134#define ATTRIB_LFN 0x0F 135 136/* 137 * Macros to read fields in directory & BPB entries 138 */ 139 140#define READWORD(buffer,x) (((unsigned int) (buffer)[(x)]) | \ 141 (((unsigned int) (buffer)[(x)+1]) << 8)) 142 143#define READWORD32(buffer,x) (READWORD(buffer,(x)) | (READWORD(buffer,(x)+2) << 16)) 144 145#define READBYTE(buffer,x) ((unsigned int) (buffer)[(x)]) 146 147/* 148 * Directory entry offsets and values 149 */ 150 151#define DIR_CHECKSUM 13 152#define DIR_FILELENGTH 28 153#define DIR_STARTCLUSTER 26 154#define DIR_ATTRIB 11 155#define DIR_NAMEOFFSET 0 156#define DIR_NAMELEN 8 157#define DIR_EXTOFFSET 8 158#define DIR_EXTLEN 3 159 160#define DIRENTRY_CHECKSUM(e) READBYTE(e,DIR_CHECKSUM) 161#define DIRENTRY_FILELENGTH(e) READWORD32(e,DIR_FILELENGTH) 162#define DIRENTRY_STARTCLUSTER(e) READWORD(e,DIR_STARTCLUSTER) 163#define DIRENTRY_ATTRIB(e) READBYTE(e,DIR_ATTRIB) 164 165#define DIRENTRY_LAST 0 166#define DIRENTRY_DELETED 0xE5 167#define DIRENTRY_PARENTDIR 0x2E 168 169#define DIRENTRY_LFNIDX(e) READBYTE(e,0) 170#define LFNIDX_MASK 0x1F 171#define LFNIDX_END 0x40 172#define LFNIDX_MAX 20 173 174/* ********************************************************************* 175 * Types 176 ********************************************************************* */ 177 178/* 179 * Internalized BPB 180 */ 181 182typedef struct bpb_s { 183 unsigned int bpb_bytespersector; 184 unsigned int bpb_sectorspercluster; 185 unsigned int bpb_reservedsectors; 186 unsigned int bpb_numfats; 187 unsigned int bpb_maxrootdir; 188 unsigned int bpb_totalsectors; 189 unsigned int bpb_sectorsperfat; 190 unsigned int bpb_sectorspertrack; 191 unsigned int bpb_numheads; 192 unsigned int bpb_hiddensectors; 193} bpb_t; 194 195/* 196 * FAT Filesystem descriptor - contains working information 197 * about an "open" file system 198 */ 199 200typedef struct fatfs_s { 201 int fat_fh; 202 int fat_refcnt; 203 bpb_t fat_bpb; 204 int fat_bits; 205 int fat_partstart; 206 uint8_t fat_dirsector[SECTORSIZE]; 207 int fat_dirsecnum; 208 uint8_t fat_fatsector[SECTORSIZE]; 209 int fat_fatsecnum; 210} fatfs_t; 211 212/* 213 * FAT Chain - describes a series of FAT entries 214 */ 215 216typedef struct fatchain_s { 217 int fat_start; 218 uint16_t *fat_entries; 219 int fat_count; 220} fatchain_t; 221 222/* 223 * FAT File descriptor - contains working information 224 * about an open file (including the filesystem info) 225 */ 226 227typedef struct fatfile_s { 228 fatfs_t *ff_fat; 229 int ff_filelength; 230 fatchain_t ff_chain; 231 int ff_curpos; 232 int ff_cursector; 233 uint8_t ff_sector[SECTORSIZE]; 234} fatfile_t; 235 236/* ********************************************************************* 237 * Prototypes 238 ********************************************************************* */ 239 240static int fatfs_fileop_xinit(void **fsctx,void *filename); 241static int fatfs_fileop_pinit(void **fsctx,void *filename); 242static int fatfs_fileop_open(void **ref,void *fsctx,char *filename,int mode); 243static int fatfs_fileop_read(void *ref,hsaddr_t buf,int len); 244static int fatfs_fileop_write(void *ref,hsaddr_t buf,int len); 245static int fatfs_fileop_seek(void *ref,int offset,int how); 246static void fatfs_fileop_close(void *ref); 247static void fatfs_fileop_uninit(void *fsctx); 248 249static int fatfs_check_for_partition_table(fatfs_t *fatfs); 250 251/* ********************************************************************* 252 * FAT fileio dispatch table 253 ********************************************************************* */ 254 255/* 256 * Raw FAT (no partition table) - used only on floppies 257 */ 258 259const fileio_dispatch_t fatfs_fileops = { 260 "rfat", 261 LOADFLG_NOBB, 262 fatfs_fileop_xinit, 263 fatfs_fileop_open, 264 fatfs_fileop_read, 265 fatfs_fileop_write, 266 fatfs_fileop_seek, 267 fatfs_fileop_close, 268 fatfs_fileop_uninit 269}; 270 271/* 272 * Partitioned FAT - used on Zip disks, removable hard disks, 273 * hard disks, flash cards, etc. 274 */ 275 276const fileio_dispatch_t pfatfs_fileops = { 277 "fat", 278 LOADFLG_NOBB, 279 fatfs_fileop_pinit, 280 fatfs_fileop_open, 281 fatfs_fileop_read, 282 fatfs_fileop_write, 283 fatfs_fileop_seek, 284 fatfs_fileop_close, 285 fatfs_fileop_uninit 286}; 287 288 289/* ********************************************************************* 290 * fat_readsector(fatfs,sector,numsec,buffer) 291 * 292 * Read one or more sectors from the disk into memory 293 * 294 * Input parameters: 295 * fatfs - fat filesystem descriptor 296 * sector - sector number 297 * numsec - number of sectors to read 298 * buffer - buffer to read sectors into 299 * 300 * Return value: 301 * 0 if ok 302 * else error code 303 ********************************************************************* */ 304 305static int fat_readsector(fatfs_t *fatfs,int sector,int numsec,uint8_t *buffer) 306{ 307 int res; 308 309 res = cfe_readblk(fatfs->fat_fh,(sector+fatfs->fat_partstart)*SECTORSIZE, 310 PTR2HSADDR(buffer),numsec*SECTORSIZE); 311 312 if (res != numsec*SECTORSIZE) return CFE_ERR_IOERR; 313 314 return 0; 315} 316 317 318/* ********************************************************************* 319 * fat_dumpbpb(bpb) 320 * 321 * Debug function; display fields in a BPB 322 * 323 * Input parameters: 324 * bpb - BIOS parameter block structure 325 * 326 * Return value: 327 * nothing 328 ********************************************************************* */ 329 330#ifdef _FATFS_DEBUG_ 331static void fat_dumpbpb(bpb_t *bpb) 332{ 333 xprintf("Bytes per sector %d\n",bpb->bpb_bytespersector); 334 xprintf("Sectors per cluster %d\n",bpb->bpb_sectorspercluster); 335 xprintf("Reserved sectors %d\n",bpb->bpb_reservedsectors); 336 xprintf("Number of FATs %d\n",bpb->bpb_numfats); 337 xprintf("Root dir entries %d\n",bpb->bpb_maxrootdir); 338 xprintf("Total sectors %d\n",bpb->bpb_totalsectors); 339 xprintf("Sectors per FAT %d\n",bpb->bpb_sectorsperfat); 340 xprintf("Sectors per track %d\n",bpb->bpb_sectorspertrack); 341 xprintf("Number of heads %d\n",bpb->bpb_numheads); 342 xprintf("Hidden sectors %d\n",bpb->bpb_hiddensectors); 343} 344#endif 345 346/* ********************************************************************* 347 * fat_findpart(fatfs) 348 * 349 * For partitioned disks, locate the active partition 350 * and set "fat_partstart" accordingly 351 * 352 * Input parameters: 353 * fatfs - FAT filesystem descriptor 354 * 355 * Return value: 356 * 0 if we found a valid partition table; else error code 357 ********************************************************************* */ 358 359static int fat_findpart(fatfs_t *fatfs) 360{ 361 uint8_t buffer[SECTORSIZE]; 362 uint8_t *part; 363 int res; 364 int idx; 365 366 fatfs->fat_partstart = 0; /* make sure we get real boot sector */ 367 res = fat_readsector(fatfs,0,1,buffer); 368 if (res < 0) return res; 369 370 /* 371 * Normally you're supposed to check for a JMP instruction. 372 * At least that's what many people do. Flash MBRs don't start 373 * with JMP instructions, so just look for the seal. 374 * 375 * 376 * if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) { 377 * return CFE_ERR_BADFILESYS; 378 * } 379 */ 380 381 /* 382 * Check the seal at the end of th sector 383 */ 384 385 if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS; 386 387 /* 388 * Look for an active FAT partition. The partition we want must 389 * be the active one. We do not deal with extended partitions 390 * here. Hey, this is supposed to be boot code! 391 */ 392 393 part = &buffer[PTABLE_OFFSET]; 394 for (idx = 0; idx < PTABLE_COUNT; idx++) { 395 if ((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) && 396 ((part[PTABLE_TYPE] == PARTTYPE_FAT12) || 397 (part[PTABLE_TYPE] == PARTTYPE_FAT16) || 398 (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) { 399 break; 400 } 401 402 part += PTABLE_SIZE; 403 } 404 405 if (idx == PTABLE_COUNT) return CFE_ERR_BADFILESYS; 406 407 /* 408 * The info we want is really just the pointer to the 409 * boot (BPB) sector. Get that and we'll use it for an 410 * offset into the disk later. 411 */ 412 413 fatfs->fat_partstart = READWORD32(part,PTABLE_BOOTSECTOR); 414 415 return 0; 416} 417 418 419/* ********************************************************************* 420 * fat_readbpb(fatfs) 421 * 422 * Read and internalize the BIOS Parameter Block 423 * 424 * Input parameters: 425 * fatfs - FAT filesystem descriptor 426 * 427 * Return value: 428 * 0 if ok 429 * else error code (usually, BPB is not valid) 430 ********************************************************************* */ 431 432static int fat_readbpb(fatfs_t *fatfs) 433{ 434 uint8_t buffer[SECTORSIZE]; 435 int res; 436 int datasectors; 437 438 res = fat_readsector(fatfs,0,1,buffer); 439 if (res < 0) return res; 440 441 if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) return CFE_ERR_BADFILESYS; 442 if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS; 443 444 fatfs->fat_bpb.bpb_bytespersector = READWORD(buffer,BPB_BYTESPERSECTOR); 445 fatfs->fat_bpb.bpb_sectorspercluster = READBYTE(buffer,BPB_SECTORSPERCLUSTER); 446 fatfs->fat_bpb.bpb_reservedsectors = READWORD(buffer,BPB_RESERVEDSECTORS); 447 fatfs->fat_bpb.bpb_numfats = READBYTE(buffer,BPB_NUMFATS); 448 fatfs->fat_bpb.bpb_maxrootdir = READWORD(buffer,BPB_MAXROOTDIR); 449 fatfs->fat_bpb.bpb_totalsectors = READWORD(buffer,BPB_TOTALSECTORS); 450 fatfs->fat_bpb.bpb_sectorsperfat = READWORD(buffer,BPB_SECTORSPERFAT); 451 fatfs->fat_bpb.bpb_sectorspertrack = READWORD(buffer,BPB_SECTORSPERTRACK); 452 fatfs->fat_bpb.bpb_numheads = READWORD(buffer,BPB_NUMHEADS); 453 fatfs->fat_bpb.bpb_hiddensectors = READWORD(buffer,BPB_HIDDENSECTORS); 454 455 if (fatfs->fat_bpb.bpb_bytespersector != SECTORSIZE) return CFE_ERR_BADFILESYS; 456 if (fatfs->fat_bpb.bpb_numfats > 2) return CFE_ERR_BADFILESYS; 457 458 /* 459 * XXX sanity check other fields 460 */ 461 462 /* Count data clusters to select FAT12 or FAT16 */ 463 datasectors = fatfs->fat_bpb.bpb_totalsectors - 464 (fatfs->fat_bpb.bpb_reservedsectors + 465 (fatfs->fat_bpb.bpb_maxrootdir * DIRENTRYSIZE)/SECTORSIZE + 466 (fatfs->fat_bpb.bpb_numfats * fatfs->fat_bpb.bpb_sectorsperfat)); 467 fatfs->fat_bits = 468 ((datasectors / fatfs->fat_bpb.bpb_sectorspercluster) > 4084) ? 16 : 12; 469 470#ifdef _FATFS_DEBUG_ 471 fat_dumpbpb(&(fatfs->fat_bpb)); 472#endif 473 474 return 0; 475} 476 477 478 479/* ********************************************************************* 480 * fat_getentry(fatfs,entry) 481 * 482 * Read a FAT entry. This is more involved than you'd think, 483 * since we have to deal with 12 and 16 (and someday 32) bit FATs, 484 * and the nasty case where a 12-bit FAT entry crosses a sector 485 * boundary. 486 * 487 * Input parameters: 488 * fatfs - FAT filesystem descriptor 489 * entry - index of FAT entry 490 * 491 * Return value: 492 * FAT entry, or <0 if an error occured 493 ********************************************************************* */ 494 495static int fat_getfatentry(fatfs_t *fatfs,int entry) 496{ 497 int fatsect; 498 int byteoffset; 499 int fatstart; 500 int fatoffset; 501 uint8_t b1,b2,b3; 502 int res; 503 504 fatstart = fatfs->fat_bpb.bpb_reservedsectors; 505 506 if (fatfs->fat_bits == 12) { 507 int odd; 508 odd = entry & 1; 509 byteoffset = ((entry & ~1) * 3) / 2; 510 fatsect = byteoffset / SECTORSIZE; 511 fatoffset = byteoffset % SECTORSIZE; 512 513 if (fatfs->fat_fatsecnum != fatsect) { 514 res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector); 515 if (res < 0) { 516 return res; 517 } 518 fatfs->fat_fatsecnum = fatsect; 519 } 520 521 b1 = fatfs->fat_fatsector[fatoffset]; 522 523 if ((fatoffset+1) >= SECTORSIZE) { 524 res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector); 525 if (res < 0) { 526 return res; 527 } 528 fatfs->fat_fatsecnum = fatsect+1; 529 fatoffset -= SECTORSIZE; 530 } 531 532 b2 = fatfs->fat_fatsector[fatoffset+1]; 533 534 if ((fatoffset+2) >= SECTORSIZE) { 535 res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector); 536 if (res < 0) { 537 return res; 538 } 539 fatfs->fat_fatsecnum = fatsect+1; 540 fatoffset -= SECTORSIZE; 541 } 542 543 b3 = fatfs->fat_fatsector[fatoffset+2]; 544 545 if (odd) { 546 return ((unsigned int) b3 << 4) + ((unsigned int) (b2 & 0xF0) >> 4); 547 } 548 else { 549 return ((unsigned int) (b2 & 0x0F) << 8) + ((unsigned int) b1); 550 } 551 552 } 553 else { 554 byteoffset = entry * 2; 555 fatsect = byteoffset / SECTORSIZE; 556 fatoffset = byteoffset % SECTORSIZE; 557 558 if (fatfs->fat_fatsecnum != fatsect) { 559 res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector); 560 if (res < 0) { 561 return res; 562 } 563 fatfs->fat_fatsecnum = fatsect; 564 } 565 566 b1 = fatfs->fat_fatsector[fatoffset]; 567 b2 = fatfs->fat_fatsector[fatoffset+1]; 568 return ((unsigned int) b1) + (((unsigned int) b2) << 8); 569 } 570} 571 572/* ********************************************************************* 573 * fat_getrootdirentry(fatfs,entryidx,entry) 574 * 575 * Read a root directory entry. The FAT12/16 root directory 576 * is a contiguous group of sectors, whose size is specified in 577 * the BPB. This routine just digs out an entry from there 578 * 579 * Input parameters: 580 * fatfs - FAT filesystem descriptor 581 * entryidx - 0-based entry index to read 582 * entry - pointer to directory entry (32 bytes) 583 * 584 * Return value: 585 * 0 if ok 586 * <0 if error occured 587 ********************************************************************* */ 588 589static int fat_getrootdirentry(fatfs_t *fatfs,int entryidx,uint8_t *entry) 590{ 591 int rootdirstart; 592 int rootdirsize; 593 int dirsecnum; 594 int res; 595 596 if (entryidx >= fatfs->fat_bpb.bpb_maxrootdir) { 597 memset(entry,0,DIRENTRYSIZE); 598 return CFE_ERR_INV_PARAM; 599 } 600 601 rootdirstart = fatfs->fat_bpb.bpb_reservedsectors + 602 fatfs->fat_bpb.bpb_numfats * fatfs->fat_bpb.bpb_sectorsperfat; 603 604 rootdirsize = fatfs->fat_bpb.bpb_maxrootdir / DIRENTRYSIZE; 605 606 dirsecnum = rootdirstart + entryidx / DIRPERSECTOR; 607 608 if (fatfs->fat_dirsecnum != dirsecnum) { 609 res = fat_readsector(fatfs,dirsecnum,1,fatfs->fat_dirsector); 610 if (res < 0) { 611 return res; 612 } 613 fatfs->fat_dirsecnum = dirsecnum; 614 } 615 616 memcpy(entry,&(fatfs->fat_dirsector[(entryidx % DIRPERSECTOR)*DIRENTRYSIZE]), 617 DIRENTRYSIZE); 618 619 return 0; 620} 621 622/* ********************************************************************* 623 * fat_checksumname(name) 624 * 625 * Calculate the "long filename" checksum for a given short name. 626 * All LFN directory entries associated with the short name are 627 * given the same checksum byte, to help keep the long name 628 * consistent. 629 * 630 * Input parameters: 631 * name - pointer to 32-byte directory entry 632 * 633 * Return value: 634 * checksum value 635 ********************************************************************* */ 636 637static uint8_t fat_checksumname(uint8_t *name) 638{ 639 uint8_t sum = 0; 640 uint8_t newbit; 641 int idx; 642 643 for (idx = 0; idx < 11; idx++) { 644 newbit = (sum & 1) ? 0x80 : 0x00; 645 sum >>= 1; 646 sum |= newbit; 647 sum += name[idx]; 648 } 649 650 return sum; 651} 652 653#ifdef _FATFS_DEBUG_ 654void fat_dumpdirentry(uint8_t *entry); 655void fat_dumpdirentry(uint8_t *entry) 656{ 657 uint8_t name[32]; 658 int idx; 659 660 if (entry[11] != ATTRIB_LFN) { 661 memcpy(name,entry,11); 662 name[11] = 0; 663 xprintf("%s %02X %04X %d\n", 664 name,DIRENTRY_ATTRIB(entry), 665 DIRENTRY_STARTCLUSTER(entry), 666 DIRENTRY_FILELENGTH(entry)); 667 } 668 else { 669 for (idx = 0; idx < 5; idx++) { 670 name[idx] = entry[(idx*2)+1]; 671 } 672 for (idx = 0; idx < 6; idx++) { 673 name[idx+5] = entry[(idx*2)+14]; 674 } 675 for (idx = 0; idx < 2; idx++) { 676 name[idx+11] = entry[(idx*2)+28]; 677 } 678 name[13] = '\0'; 679 xprintf("%02X: %s %04X cksum %02X\n",entry[0], 680 name,READWORD(entry,0x1A),entry[13]); 681 } 682} 683#endif 684 685 686/* ********************************************************************* 687 * fat_walkfatchain(fat,start,arg,func) 688 * 689 * Walk a FAT chain, calling a callback routine for each entry 690 * we find along the way. 691 * 692 * Input parameters: 693 * fat - FAT filesystem descriptor 694 * start - starting FAT entry (from the directory, usually) 695 * arg - argument to pass to callback routine 696 * func - function to call for each FAT entry 697 * 698 * Return value: 699 * 0 if all elements processed 700 * <0 if error occured 701 * >0 if callback routine returned a nonzero value 702 ********************************************************************* */ 703 704static int fat_walkfatchain(fatfs_t *fat,int start, 705 void *arg, 706 int (*func)(fatfs_t *fat, 707 int e, 708 int prev_e, 709 void *arg)) 710{ 711 int prev_e = 0; 712 int ending_e; 713 int e; 714 int res = 0; 715 716 e = start; 717 718 /* Note: ending FAT entry can be 0x(F)FF8..0x(F)FFF. We assume that the 719 'getfatentry' call won't return values above that. */ 720 if (fat->fat_bits == 12) { 721 ending_e = 0xFF8; 722 } 723 else { 724 ending_e = 0xFFF8; 725 } 726 727 while (e < ending_e) { 728 res = (*func)(fat,e,prev_e,arg); 729 if (res) break; 730 prev_e = e; 731 e = fat_getfatentry(fat,e); 732 if (e < 0) return e; 733 } 734 735 return res; 736} 737 738/* ********************************************************************* 739 * fat_getwalkfunc(fat,e,prev_e,arg) 740 * 741 * Callback routien to collect all of the FAT entries into 742 * a FAT chain descriptor 743 * 744 * Input parameters: 745 * fat - FAT filesystem descriptor 746 * e - current entry 747 * prev_e - previous entry (0 if first entry) 748 * arg - argument passed to fat_walkfatchain 749 * 750 * Return value: 751 * 0 to keep walking 752 * else value to return from fat_walkfatchain 753 ********************************************************************* */ 754 755static int fat_getwalkfunc(fatfs_t *fat,int e, 756 int prev_e,void *arg) 757{ 758 fatchain_t *chain = arg; 759 760 if (chain->fat_entries) { 761 chain->fat_entries[chain->fat_count] = (uint16_t) e; 762 } 763 764 chain->fat_count++; 765 766 return 0; 767} 768 769/* ********************************************************************* 770 * fat_getchain(fat,start,chain) 771 * 772 * Walk an entire FAT chain and remember the chain in a 773 * FAT chain descriptor 774 * 775 * Input parameters: 776 * fat - FAT filesystem descriptor 777 * start - starting FAT entry 778 * chain - chain descriptor 779 * 780 * Return value: 781 * 0 if ok 782 * else error code 783 ********************************************************************* */ 784 785static int fat_getchain(fatfs_t *fat,int start,fatchain_t *chain) 786{ 787 int res; 788 789 chain->fat_entries = NULL; 790 chain->fat_count = 0; 791 chain->fat_start = start; 792 793 /* 794 * walk once to count the entries. 795 * 796 * For regular files, you probably don't have to do this 797 * since you can predict exactly how many FAT entries 798 * there are given the file length. 799 */ 800 801 res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc); 802 if (res < 0) return res; 803 804 /* 805 * allocate space for the entries. Include one extra 806 * slot for the first entry, since the first entry 807 * does not actually appear in the FAT (the fat is 808 * only the 'next' pointers). 809 */ 810 811 if (chain->fat_count == 0) return 0; 812 chain->fat_entries = KMALLOC((chain->fat_count+1)*sizeof(uint16_t),0); 813 chain->fat_count = 0; 814 815 /* 816 * walk again to collect entries 817 */ 818 res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc); 819 if (res < 0) return res; 820 821 return chain->fat_count; 822} 823 824 825/* ********************************************************************* 826 * fat_freechain(chain) 827 * 828 * Free memory associated with a FAT chain 829 * 830 * Input parameters: 831 * chain - chain descriptor 832 * 833 * Return value: 834 * nothing 835 ********************************************************************* */ 836 837static void fat_freechain(fatchain_t *chain) 838{ 839 if (chain->fat_entries) { 840 KFREE(chain->fat_entries); 841 chain->fat_entries = NULL; 842 } 843 chain->fat_count = 0; 844} 845 846/* ********************************************************************* 847 * fat_clusteridx(fat,chain,idx) 848 * 849 * Index into a FAT chain and return the nth cluster number 850 * from the chain 851 * 852 * Input parameters: 853 * fat - fat filesystem descriptor 854 * chain - chain descriptor 855 * idx - index into FAT chain 856 * 857 * Return value: 858 * FAT entry at the nth index, or 859 * <0 if an error occured 860 ********************************************************************* */ 861static int fat_clusteridx(fatfs_t *fat,fatchain_t *chain,int idx) 862{ 863 if (idx >= chain->fat_count) return CFE_ERR_INV_PARAM; /* error! */ 864 return (int) (unsigned int) chain->fat_entries[idx]; 865} 866 867/* ********************************************************************* 868 * fat_sectoridx(fat,chain,idx) 869 * 870 * Return the sector nunber of the nth sector in a given 871 * FAT chain. This routine knows how to translate cluster 872 * numbers into sector numbers. 873 * 874 * Input parameters: 875 * fat - FAT filesystem descriptor 876 * chain - FAT chain 877 * idx - index of which sector to find 878 * 879 * Return value: 880 * sector number 881 * <0 if an error occured 882 ********************************************************************* */ 883static int fat_sectoridx(fatfs_t *fat,fatchain_t *chain,int idx) 884{ 885 int clusteridx; 886 int sectoridx; 887 int sector; 888 int fatentry; 889 890 clusteridx = idx / fat->fat_bpb.bpb_sectorspercluster; 891 sectoridx = idx % fat->fat_bpb.bpb_sectorspercluster; 892 893 fatentry = fat_clusteridx(fat,chain,clusteridx); 894 895 if (fatentry < 0) xprintf("ran off end of fat chain!\n"); 896 if (fatentry < 2) xprintf("fat entries should be >= 2\n"); 897 898 sector = fat->fat_bpb.bpb_reservedsectors + 899 (fat->fat_bpb.bpb_maxrootdir * DIRENTRYSIZE)/SECTORSIZE + 900 (fat->fat_bpb.bpb_numfats * fat->fat_bpb.bpb_sectorsperfat) + 901 (fatentry - 2) * fat->fat_bpb.bpb_sectorspercluster + 902 sectoridx; 903 904 return sector; 905} 906 907/* ********************************************************************* 908 * fat_getsubdirentry(fat,chain,idx,direntry) 909 * 910 * This routine is similar to fat_getrootdirentry except it 911 * works on a subdirectory. FAT subdirectories are like files 912 * containing directory entries, so we use the "get nth sector 913 * in chain" routines to walk the chains of sectors reading directory 914 * entries. 915 * 916 * Input parameters: 917 * fat - FAT filesystem descriptor 918 * chain - FAT chain 919 * idx - index of entry to read 920 * direntry - place to put directory entry we read 921 * 922 * Return value: 923 * 0 if ok 924 * else error code 925 ********************************************************************* */ 926 927static int fat_getsubdirentry(fatfs_t *fat,fatchain_t *chain, 928 int idx,uint8_t *direntry) 929{ 930 int sector; 931 int res; 932 933 sector = fat_sectoridx(fat,chain,idx/DIRPERSECTOR); 934 935 if (sector < 0) return sector; 936 937 if (fat->fat_dirsecnum != sector) { 938 res = fat_readsector(fat,sector,1,fat->fat_dirsector); 939 if (res < 0) { 940 return res; 941 } 942 fat->fat_dirsecnum = sector; 943 } 944 945 memcpy(direntry,&(fat->fat_dirsector[(idx % DIRPERSECTOR)*DIRENTRYSIZE]), 946 DIRENTRYSIZE); 947 948 return 0; 949} 950 951/* ********************************************************************* 952 * fat_getshortname(direntry,name) 953 * 954 * Read the short filename from a directory entry, converting 955 * it into its classic 8.3 form 956 * 957 * Input parameters: 958 * direntry - directory entry 959 * name - place to put 8.3 name 960 * 961 * Return value: 962 * nothing 963 ********************************************************************* */ 964 965static void fat_getshortname(uint8_t *direntry,char *name) 966{ 967 int idx; 968 969 /* 970 * Collect the base file name 971 */ 972 973 for (idx = DIR_NAMEOFFSET; idx < (DIR_NAMEOFFSET+DIR_NAMELEN); idx++) { 974 if (direntry[idx] == ' ') break; 975 *name++ = direntry[idx]; 976 } 977 978 /* 979 * Put in the dot for the extension only if there 980 * is an extension. 981 */ 982 983 if (direntry[DIR_EXTOFFSET] != ' ') *name++ = '.'; 984 985 /* 986 * Collect the extension 987 */ 988 989 for (idx = DIR_EXTOFFSET; idx < (DIR_EXTOFFSET+DIR_EXTLEN); idx++) { 990 if (direntry[idx] == ' ') break; 991 *name++ = direntry[idx]; 992 } 993 994 *name = '\0'; 995} 996 997 998/* ********************************************************************* 999 * fat_getlongname(fat,chain,diridx,shortentry,longname) 1000 * 1001 * Look backwards in the directory to locate the long file name 1002 * that corresponds to the short file name passed in 'shortentry' 1003 * 1004 * Input parameters: 1005 * fat - FAT filesystem descriptor 1006 * chain - chain describing current directory, or NULL 1007 * if the current directory is the root directory 1008 * diridx - index of the short file name 1009 * shortentry - points to the short directory entry 1010 * longname - buffer to receive long file name (up to 261 chars) 1011 * 1012 * Return value: 1013 * 0 if ok 1014 * else error code 1015 ********************************************************************* */ 1016 1017static int fat_getlongname(fatfs_t *fat,fatchain_t *chain,int diridx, 1018 uint8_t *shortentry,char *longname) 1019{ 1020 int lfnidx = 1; 1021 uint8_t checksum; 1022 uint8_t direntry[DIRENTRYSIZE]; 1023 int idx; 1024 char *lfnptr; 1025 int badlfn = 0; 1026 1027 *longname = '\0'; 1028 1029 /* 1030 * idx is the entry # of the short name 1031 */ 1032 1033 checksum = fat_checksumname(shortentry); 1034 1035 /* 1036 * Start working backwards from current entry 1037 * and collect pieces of the lfn 1038 */ 1039 1040 lfnptr = longname; 1041 diridx--; 1042 1043 while (diridx >= 0) { 1044 1045 /* 1046 * Read previous entry 1047 */ 1048 1049 if (chain) { 1050 fat_getsubdirentry(fat,chain,diridx,direntry); 1051 } 1052 else { 1053 fat_getrootdirentry(fat,diridx,direntry); 1054 } 1055 1056 /* 1057 * Checksum must match, it must have the right entry index, 1058 * and it must have the LFN attribute 1059 */ 1060 1061 if (DIRENTRY_CHECKSUM(direntry) != checksum) { 1062 badlfn = 1; 1063 break; 1064 } 1065 if ((DIRENTRY_LFNIDX(direntry) & LFNIDX_MASK) != lfnidx) { 1066 badlfn = 1; 1067 break; 1068 } 1069 1070 if (DIRENTRY_ATTRIB(direntry) != ATTRIB_LFN) { 1071 badlfn = 1; 1072 break; 1073 } 1074 1075 /* 1076 * Collect the chars from the filename. Note we 1077 * don't deal well with real unicode chars here. 1078 */ 1079 1080 for (idx = 0; idx < 5; idx++) { 1081 *lfnptr++ = direntry[(idx*2)+1]; 1082 } 1083 for (idx = 0; idx < 6; idx++) { 1084 *lfnptr++ = direntry[(idx*2)+14]; 1085 } 1086 for (idx = 0; idx < 2; idx++) { 1087 *lfnptr++ = direntry[(idx*2)+28]; 1088 } 1089 1090 /* 1091 * Don't go too far 1092 */ 1093 1094 if (DIRENTRY_LFNIDX(direntry) & LFNIDX_END) break; 1095 lfnidx++; 1096 if (lfnidx > LFNIDX_MAX) { 1097 badlfn = 1; 1098 break; 1099 } 1100 1101 diridx--; 1102 } 1103 1104 /* 1105 * Null terminate the lfn 1106 */ 1107 1108 *lfnptr = 0; 1109 1110 if (badlfn) { 1111 longname[0] = 0; 1112 return CFE_ERR_FILENOTFOUND; 1113 } 1114 1115 return 0; 1116} 1117 1118 1119/* ********************************************************************* 1120 * fat_scandir(fat,chain,name,direntry) 1121 * 1122 * Scan a single directory looking for a file name 1123 * 1124 * Input parameters: 1125 * fat - FAT filesystem descriptor 1126 * chain - FAT chain for directory or NULL for root directory 1127 * name - name of file to look for (short or long name) 1128 * direntry - place to put directory entry if we find one 1129 * 1130 * Return value: 1131 * 1 if name was found 1132 * 0 if name was not found 1133 * else <0 is error code 1134 ********************************************************************* */ 1135 1136 1137static int fat_scandir(fatfs_t *fat,fatchain_t *chain, 1138 char *name,uint8_t *direntry) 1139{ 1140 int idx; 1141 int count; 1142 char shortname[16]; 1143 char longname[280]; 1144 1145 /* 1146 * Get directory size 1147 */ 1148 1149 if (chain) { 1150 count = (chain->fat_count * fat->fat_bpb.bpb_sectorspercluster) * DIRPERSECTOR; 1151 } 1152 else { 1153 count = (int) fat->fat_bpb.bpb_maxrootdir; 1154 } 1155 1156 /* 1157 * Scan whole directory 1158 */ 1159 1160 for (idx = 0; idx < count; idx++) { 1161 1162 /* 1163 * Get entry by root or chain depending... 1164 */ 1165 1166 if (chain) { 1167 fat_getsubdirentry(fat,chain,idx,direntry); 1168 } 1169 else { 1170 fat_getrootdirentry(fat,idx,direntry); 1171 } 1172 1173 /* 1174 * Ignore stuff we don't want to see 1175 */ 1176 1177 if (direntry[0] == DIRENTRY_LAST) break; /* stop if at end of dir */ 1178 if (direntry[0] == DIRENTRY_DELETED) continue; /* skip deleted entries */ 1179 if (direntry[0] == DIRENTRY_PARENTDIR) continue; /* skip ./.. entries */ 1180 1181 if (DIRENTRY_ATTRIB(direntry) == ATTRIB_LFN) continue; /* skip LFNs */ 1182 if (DIRENTRY_ATTRIB(direntry) & ATTRIB_LABEL) continue; /* skip volume labels */ 1183 1184 /* 1185 * Get actual file names from directory 1186 */ 1187 1188 fat_getshortname(direntry,shortname); 1189 fat_getlongname(fat,chain,idx,direntry,longname); 1190 1191 1192 if (name) { 1193 if (strcmpi(name,shortname) == 0) return 1; 1194 if (longname[0] && (strcmpi(name,longname) == 0)) return 1; 1195 } 1196 else { 1197 xprintf("%-30s",longname[0] ? longname : shortname); 1198// xprintf(" Clus=%04X",DIRENTRY_STARTCLUSTER(direntry)); 1199// xprintf(" Attrib=%02X",DIRENTRY_ATTRIB(direntry)); 1200// xprintf(" Size=%d",DIRENTRY_FILELENGTH(direntry)); 1201 xprintf("%d",DIRENTRY_FILELENGTH(direntry)); 1202 xprintf("\n"); 1203 } 1204 } 1205 1206 return 0; 1207} 1208 1209/* ********************************************************************* 1210 * fat_findfile(fat,name,direntry) 1211 * 1212 * Locate a directory entry given a complete path name 1213 * 1214 * Input parameters: 1215 * fat - FAT filesystem descriptor 1216 * name - name of file to locate (forward or reverse slashses ok) 1217 * direntry - place to put directory entry we find 1218 * 1219 * Return value: 1220 * 0 if file not found 1221 * 1 if file was found 1222 * <0 if error occurs 1223 ********************************************************************* */ 1224 1225static int fat_findfile(fatfs_t *fat,char *name,uint8_t *direntry) 1226{ 1227 char *namecopy; 1228 char *namepart; 1229 char *ptr; 1230 fatchain_t chain; 1231 int res; 1232 int e; 1233 1234 /* 1235 * Copy the name, we're going to hack it up 1236 */ 1237 1238 namecopy = strdup(name); 1239 1240 /* 1241 * Chew off the first piece up to the first slash. Remove 1242 * a leading slash if it is there. 1243 */ 1244 1245 ptr = namecopy; 1246 1247 if ((*ptr == '/') || (*ptr == '\\')) ptr++; 1248 1249 namepart = ptr; 1250 while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; 1251 if (*ptr) *ptr++ = '\0'; 1252 1253 /* 1254 * Scan the root directory looking for the first piece 1255 */ 1256 1257 res = fat_scandir(fat,NULL,namepart,direntry); 1258 if (res == 0) { 1259 KFREE(namecopy); 1260 return 0; /* file not found */ 1261 } 1262 1263 1264 /* 1265 * Start scanning subdirectories until we run out 1266 * of directory components. 1267 */ 1268 1269 namepart = ptr; 1270 while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; 1271 if (*ptr) *ptr++ = '\0'; 1272 if (!*namepart) namepart = NULL; 1273 1274 1275 while (namepart) { 1276 1277 /* 1278 * Scan the subdirectory 1279 */ 1280 1281 e = DIRENTRY_STARTCLUSTER(direntry); 1282 memset(&chain,0,sizeof(chain)); 1283 fat_getchain(fat,e,&chain); 1284 res = fat_scandir(fat,&chain,namepart,direntry); 1285 if (res == 0) { 1286 break; 1287 } 1288 fat_freechain(&chain); 1289 1290 /* 1291 * Advance to the next piece 1292 */ 1293 1294 namepart = ptr; 1295 while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; 1296 if (*ptr) *ptr++ = '\0'; 1297 if (!*namepart) namepart = NULL; 1298 1299 /* 1300 * If there's more to go and we hit something that 1301 * is not a directory, stop here. 1302 */ 1303 1304 if (namepart && !(DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) { 1305 res = 0; 1306 } 1307 } 1308 1309 KFREE(namecopy); 1310 1311 /* 1312 * The last piece we enumerate has to be a file. 1313 */ 1314 1315 if ((res > 0) && 1316 (DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) { 1317 return 0; 1318 } 1319 1320 return res; 1321} 1322 1323 1324/* ********************************************************************* 1325 * fat_init(fat,name) 1326 * 1327 * Create the filesystem descriptor and attach to the hardware 1328 * device. 1329 * 1330 * Input parameters: 1331 * fat - filesystem descriptor 1332 * name - hardware device name 1333 * part - true to look for partition tables 1334 * 1335 * Return value: 1336 * 0 if ok 1337 * else error code 1338 ********************************************************************* */ 1339 1340static int fat_init(fatfs_t *fat,char *name,int part) 1341{ 1342 int res; 1343 1344 memset(fat,0,sizeof(fatfs_t)); 1345 fat->fat_dirsecnum = -1; 1346 fat->fat_fatsecnum = -1; 1347 1348 fat->fat_fh = cfe_open(name); 1349 1350 if (fat->fat_fh < 0) return fat->fat_fh; 1351 1352 res = fatfs_check_for_partition_table(fat); 1353 /* If we were able to figure it out, use that as the default */ 1354 if (res >= 0) part = res; 1355 1356 if (part) { 1357 res = fat_findpart(fat); 1358 if (res < 0) { 1359 cfe_close(fat->fat_fh); 1360 fat->fat_fh = -1; 1361 return res; 1362 } 1363 } 1364 1365 res = fat_readbpb(fat); 1366 if (res != 0) { 1367 cfe_close(fat->fat_fh); 1368 fat->fat_fh = -1; 1369 return res; 1370 } 1371 1372 return 0; 1373} 1374 1375/* ********************************************************************* 1376 * fat_uninit(fat) 1377 * 1378 * Uninit the filesystem descriptor and release any resources 1379 * we allocated. 1380 * 1381 * Input parameters: 1382 * fat - filesystem descriptor 1383 * 1384 * Return value: 1385 * nothing 1386 ********************************************************************* */ 1387 1388static void fat_uninit(fatfs_t *fat) 1389{ 1390 if (fat->fat_fh >= 0) cfe_close(fat->fat_fh); 1391 fat->fat_fh = -1; 1392} 1393 1394int fatfs_fileop_dir(void *fsctx); 1395int fatfs_fileop_dir(void *fsctx) 1396{ 1397 fatfs_t *fatfs = fsctx; 1398 uint8_t direntry[32]; 1399 1400 fat_scandir(fatfs,NULL,NULL,direntry); 1401 1402 return 0; 1403} 1404 1405/* ********************************************************************* 1406 * fatfs_fileop_init(fsctx,devname) 1407 * 1408 * Create a FAT filesystem context and open the associated 1409 * block device. 1410 * 1411 * Input parameters: 1412 * fsctx - file system context (return pointer) 1413 * devname - device name to open 1414 * part - true to look for a partition table 1415 * 1416 * Return value: 1417 * 0 if ok, else error 1418 ********************************************************************* */ 1419 1420static int fatfs_fileop_init(void **fsctx,char *devname,int part) 1421{ 1422 int res; 1423 fatfs_t *fatfs; 1424 1425 /* 1426 * Allocate a file system context 1427 */ 1428 1429 fatfs = (fatfs_t *) KMALLOC(sizeof(fatfs_t),0); 1430 if (!fatfs) return CFE_ERR_NOMEM; 1431 1432 /* 1433 * Open a handle to the underlying device 1434 */ 1435 1436 res = fat_init(fatfs,devname,part); 1437 if (res != 0) { 1438 KFREE(fatfs); 1439 return res; 1440 } 1441 1442 *fsctx = fatfs; 1443 1444 return 0; 1445} 1446 1447/* ********************************************************************* 1448 * fatfs_check_for_partition_table(fatfs) 1449 * 1450 * This routine attempts to determine if the disk contains a 1451 * partition table or if it contains a standard MS-DOS boot recod. 1452 * We try to find both, and return what we find, or an error 1453 * if it is still unclear. 1454 * 1455 * Input parameters: 1456 * fatfs - fat filesystem context 1457 * 1458 * Return value: 1459 * 0 if no partition table 1460 * 1 if partition table 1461 * <0 = error occured, could not tell or I/O error 1462 ********************************************************************* */ 1463 1464static int fatfs_check_for_partition_table(fatfs_t *fatfs) 1465{ 1466 int res; 1467 uint8_t buffer[SECTORSIZE]; 1468 uint8_t *part; 1469 int idx; 1470 int foundit = 0; 1471 1472 /* 1473 * Read sector 0 1474 */ 1475 1476 fatfs->fat_partstart = 0; 1477 res = fat_readsector(fatfs,0,1,buffer); 1478 if (res < 0) return res; 1479 1480 /* 1481 * Check the seal at the end of the sector. Both 1482 * boot sector and MBR should contain this seal. 1483 */ 1484 if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) { 1485 res = CFE_ERR_BADFILESYS; 1486 return res; 1487 } 1488 1489 /* 1490 * See Microsoft Knowledgebase article # Q140418, it contains 1491 * a good description of the boot sector format. 1492 * 1493 * If the extended information is present, and SystemID is "FAT" 1494 * and the "bytes per sector" is 512, assume it's a regular boot block 1495 */ 1496 1497 if (((buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE1) || 1498 (buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE2)) && 1499 (memcmp(&buffer[BPB_SYSTEMID],"FAT",3) == 0) && 1500 (READWORD(buffer,BPB_BYTESPERSECTOR) == 512)) { 1501 /* Not partitioned */ 1502 res = 0; 1503 return res; 1504 } 1505 1506 /* If no extended information is present, check a few other key values. */ 1507 1508 if ((READWORD(buffer,BPB_BYTESPERSECTOR) == 512) && 1509 (READWORD(buffer,BPB_RESERVEDSECTORS) >= 1) && 1510 ((READWORD(buffer,BPB_MEDIADESCRIPTOR) & 0xF0) == 0xF0)) { 1511 res = 0; 1512 return res; 1513 } 1514 1515 /* 1516 * If we're still confused, look for a partition table with a valid FAT 1517 * partition on it. We might not detect a partition table that has 1518 * only non-FAT partitions on it, like a disk with all Linux partitions, 1519 * but that is fine here in the FATFS module, since we only want to 1520 * find FAT partitions anyway. 1521 */ 1522 part = &buffer[PTABLE_OFFSET]; 1523 for (idx = 0; idx < PTABLE_COUNT; idx++) { 1524 1525 if (((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) || 1526 (part[PTABLE_STATUS] == 0x00)) && 1527 ((part[PTABLE_TYPE] == PARTTYPE_FAT12) || 1528 (part[PTABLE_TYPE] == PARTTYPE_FAT16) || 1529 (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) { 1530 foundit = 1; 1531 res = 1; /*Partition table present*/ 1532 break; 1533 } 1534 part += PTABLE_SIZE; 1535 } 1536 1537 /* 1538 * If at this point we did not find what we were looking for, 1539 * return an error. 1540 */ 1541 if (foundit) { 1542 res = 1; /*Partition table is present.*/ 1543 } 1544 else { 1545 /*Error! We can't decide if partition table exists or not*/ 1546 res = CFE_ERR_BADFILESYS; 1547 } 1548 1549 return res; 1550} 1551 1552static int fatfs_fileop_xinit(void **fsctx,void *dev) 1553{ 1554 char *devname = (char *) dev; 1555 1556 return fatfs_fileop_init(fsctx,devname,0); 1557} 1558 1559static int fatfs_fileop_pinit(void **fsctx,void *dev) 1560{ 1561 char *devname = (char *) dev; 1562 1563 return fatfs_fileop_init(fsctx,devname,1); 1564} 1565 1566 1567 1568/* ********************************************************************* 1569 * fatfs_fileop_open(ref,name) 1570 * 1571 * Open a file on the FAT device. 1572 * 1573 * Input parameters: 1574 * ref - place to store pointer to fileinfo 1575 * fsctx - filesystem context 1576 * name - name of file to open 1577 * 1578 * Return value: 1579 * 0 if ok 1580 * else error code 1581 ********************************************************************* */ 1582 1583static int fatfs_fileop_open(void **ref,void *fsctx,char *name,int mode) 1584{ 1585 int res; 1586 uint8_t direntry[DIRENTRYSIZE]; 1587 fatfile_t *ff; 1588 fatfs_t *fatfs; 1589 1590 if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; 1591 1592 fatfs = (fatfs_t *) fsctx; 1593 1594 ff = (fatfile_t *) KMALLOC(sizeof(fatfile_t),0); 1595 if (ff == NULL) return CFE_ERR_NOMEM; 1596 1597 memset(ff,0,sizeof(fatfile_t)); 1598 1599 ff->ff_fat = fatfs; 1600 1601 res = fat_findfile(ff->ff_fat,name,direntry); 1602 if (res <= 0) { 1603 return CFE_ERR_FILENOTFOUND; /* not found */ 1604 } 1605 1606 /* 1607 * Okay, the file was found. Enumerate the FAT chain 1608 * associated with this file. 1609 */ 1610 1611 ff->ff_filelength = DIRENTRY_FILELENGTH(direntry); 1612 1613 ff->ff_curpos = 0; 1614 ff->ff_cursector = -1; 1615 1616 res = fat_getchain(ff->ff_fat, 1617 DIRENTRY_STARTCLUSTER(direntry), 1618 &(ff->ff_chain)); 1619 1620 if (res < 0) { 1621 KFREE(ff); 1622 return res; 1623 } 1624 1625 /* 1626 * Return the file handle 1627 */ 1628 1629 1630 fatfs->fat_refcnt++; 1631 *ref = (void *) ff; 1632 return 0; 1633} 1634 1635 1636/* ********************************************************************* 1637 * fatfs_fileop_close(ref) 1638 * 1639 * Close the file. 1640 * 1641 * Input parameters: 1642 * ref - pointer to open file information 1643 * 1644 * Return value: 1645 * nothing 1646 ********************************************************************* */ 1647 1648static void fatfs_fileop_close(void *ref) 1649{ 1650 fatfile_t *file = (fatfile_t *) ref; 1651 fatfs_t *fatctx = file->ff_fat; 1652 1653 fatctx->fat_refcnt--; 1654 1655 fat_freechain(&(file->ff_chain)); 1656 KFREE(file); 1657} 1658 1659 1660/* ********************************************************************* 1661 * fatfs_fileop_uninit(ref) 1662 * 1663 * Uninitialize the file system. 1664 * 1665 * Input parameters: 1666 * fsctx - filesystem context 1667 * 1668 * Return value: 1669 * nothing 1670 ********************************************************************* */ 1671static void fatfs_fileop_uninit(void *fsctx) 1672{ 1673 fatfs_t *fatctx = (fatfs_t *) fsctx; 1674 1675 if (fatctx->fat_refcnt) { 1676 xprintf("fatfs_fileop_unint: warning: refcnt should be zero\n"); 1677 } 1678 1679 fat_uninit(fatctx); 1680 1681 KFREE(fatctx); 1682} 1683 1684 1685/* ********************************************************************* 1686 * fatfs_fileop_seek(ref,offset,how) 1687 * 1688 * Move the file pointer within the file 1689 * 1690 * Input parameters: 1691 * ref - pointer to open file information 1692 * offset - new file location or distance to move 1693 * how - method for moving 1694 * 1695 * Return value: 1696 * new file offset 1697 * <0 if error occured 1698 ********************************************************************* */ 1699 1700static int fatfs_fileop_seek(void *ref,int offset,int how) 1701{ 1702 fatfile_t *file = (fatfile_t *) ref; 1703 1704 switch (how) { 1705 case FILE_SEEK_BEGINNING: 1706 file->ff_curpos = offset; 1707 break; 1708 case FILE_SEEK_CURRENT: 1709 file->ff_curpos += offset; 1710 break; 1711 default: 1712 break; 1713 } 1714 1715 if (file->ff_curpos >= file->ff_filelength) { 1716 file->ff_curpos = file->ff_filelength; 1717 } 1718 1719 return file->ff_curpos; 1720} 1721 1722 1723/* ********************************************************************* 1724 * fatfs_fileop_read(ref,buf,len) 1725 * 1726 * Read data from the file. 1727 * 1728 * Input parameters: 1729 * ref - pointer to open file information 1730 * buf - buffer to read data into 1731 * len - number of bytes to read 1732 * 1733 * Return value: 1734 * number of bytes read 1735 * <0 if error occured 1736 * 0 means eof 1737 ********************************************************************* */ 1738 1739static int fatfs_fileop_read(void *ref,hsaddr_t buf,int len) 1740{ 1741 fatfile_t *file = (fatfile_t *) ref; 1742 int amtcopy; 1743 int ttlcopy = 0; 1744 int offset; 1745 int sector; 1746 int secidx; 1747 int origpos; 1748 int res; 1749 uint8_t temp_buf[SECTORSIZE]; 1750 1751 /* 1752 * Remember orig position in case we have an error 1753 */ 1754 1755 origpos = file->ff_curpos; 1756 1757 /* 1758 * bounds check the length based on the file length 1759 */ 1760 1761 if ((file->ff_curpos + len) > file->ff_filelength) { 1762 len = file->ff_filelength - file->ff_curpos; 1763 } 1764 1765 res = 0; 1766 1767 /* 1768 * while ther is still data to be transferred 1769 */ 1770 1771 1772 while (len) { 1773 1774 /* 1775 * Calculate the sector offset and index in the sector 1776 */ 1777 1778 offset = file->ff_curpos % SECTORSIZE; 1779 secidx = file->ff_curpos / SECTORSIZE; 1780 1781 sector = fat_sectoridx(file->ff_fat,&(file->ff_chain),secidx); 1782 1783 if (sector < 0) { 1784 xprintf("should not happen, sector = -1!\n"); 1785 return sector; 1786 } 1787 1788 /* 1789 * first transfer up to the sector boundary 1790 */ 1791 1792 amtcopy = len; 1793 if (amtcopy > (SECTORSIZE-offset)) { 1794 amtcopy = (SECTORSIZE-offset); 1795 } 1796 1797 /* 1798 * If transferring exactly a sector, on a sector 1799 * boundary, read the data directly into the user buffer 1800 * 1801 * Extra credit: See if we can transfer more than one 1802 * sector at a time, by determining if we can read a run of 1803 * contiguous sectors (very likely) 1804 * 1805 * Otherwise: read into the sector buffer and 1806 * transfer the data to user memory. 1807 */ 1808 1809 if ((offset == 0) && (amtcopy == SECTORSIZE)) { 1810 res = fat_readsector(file->ff_fat,sector,1,temp_buf); 1811 if (res < 0) { 1812 xprintf("I/O error!\n"); 1813 break; 1814 } 1815 hs_memcpy_to_hs(buf,temp_buf,amtcopy); 1816 } 1817 else { 1818 if (file->ff_cursector != sector) { 1819 res = fat_readsector(file->ff_fat,sector,1,file->ff_sector); 1820 if (res < 0) { 1821 break; 1822 } 1823 file->ff_cursector = sector; 1824 } 1825 hs_memcpy_to_hs(buf,&(file->ff_sector[offset]),amtcopy); 1826 } 1827 1828 /* 1829 * Adjust/update all our pointers. 1830 */ 1831 1832 buf += amtcopy; 1833 file->ff_curpos += amtcopy; 1834 ttlcopy += amtcopy; 1835 len -= amtcopy; 1836 1837 /* 1838 * see if we ran off the end of the file. Should not 1839 * be necessary. 1840 */ 1841 1842 if (file->ff_curpos >= file->ff_filelength) { 1843 /* should not be necessary */ 1844 break; 1845 } 1846 } 1847 1848 /* 1849 * If an error occured, get out now. 1850 */ 1851 1852 if (res < 0) { 1853 file->ff_curpos = origpos; 1854 return res; 1855 } 1856 1857 return ttlcopy; 1858 1859} 1860 1861static int fatfs_fileop_write(void *ref,hsaddr_t buf,int len) 1862{ 1863 return CFE_ERR_UNSUPPORTED; 1864} 1865 1866 1867#if 0 1868 1869void main(int argc,char *argv[]) 1870{ 1871 fatfs_t fat; 1872 int idx; 1873 unsigned int e; 1874 uint8_t direntry[DIRENTRYSIZE]; 1875 fatchain_t chain; 1876 int res; 1877 1878 1879 fat_init(&fat,"floppy.raw"); 1880 1881 1882 if (fat_readbpb(&fat) == 0) { 1883 fat_dumpbpb(&fat.fat_bpb); 1884 } 1885 1886#if 0 1887 for (idx = 0; idx < (int) fat.fat_bpb.bpb_maxrootdir; idx++) { 1888 fat_getrootdirentry(&fat,idx,direntry); 1889 if (direntry[0] == 0) break; 1890 if (direntry[0] == 0xE5) continue; 1891 xprintf("%3d: ",idx); 1892 fat_dumpdirentry(direntry); 1893 } 1894#endif 1895 1896 fat_scandir(&fat,NULL,NULL,direntry); 1897 1898 for (e = 0x150; e < 0x160; e++) { 1899 xprintf("Entry %03X is %03X\n",e,fat_getfatentry(&fat,e)); 1900 } 1901 1902#if 0 1903 e = 0x36E; 1904 while (e != 0xFFF) { 1905 e = fat_getfatentry(&fat,e); 1906 xprintf("%03X ",e); 1907 } 1908#endif 1909 1910 1911 xprintf("\n\n"); 1912 e = 0x36E; 1913 memset(&chain,0,sizeof(chain)); 1914 fat_getchain(&fat,e,&chain); 1915 fat_scandir(&fat,&chain,NULL,direntry); 1916 fat_freechain(&chain); 1917 1918 xprintf("\n\n"); 1919 e = 0x36F; 1920 memset(&chain,0,sizeof(chain)); 1921 fat_getchain(&fat,e,&chain); 1922 fat_scandir(&fat,&chain,NULL,direntry); 1923 fat_freechain(&chain); 1924 1925 xprintf("\n\n"); 1926 e = 0x370; 1927 memset(&chain,0,sizeof(chain)); 1928 fat_getchain(&fat,e,&chain); 1929 fat_scandir(&fat,&chain,NULL,direntry); 1930 fat_freechain(&chain); 1931 1932 xprintf("\n\n"); 1933 1934 res = fat_findfile(&fat,argc > 1 ? argv[1] : "/usr/local/include/ansidecl.h",direntry); 1935 xprintf("res = %d\n",res); 1936 1937 if (res) fat_dumpdirentry(direntry); 1938 1939 close(fat.fat_fh); 1940} 1941 1942void main(int argc,char *argv[]) 1943{ 1944 void *ref; 1945 int res; 1946 char buffer[257]; 1947 int total = 0; 1948 1949// res = fatfs_fileop_open(&ref,"floppy.raw:/usr/local/include/bfdlink.h"); 1950 res = fatfs_fileop_open(&ref,"floppy.raw:/idedrv.h"); 1951 1952 if (res != 0) { 1953 xprintf("Could not open file: %d\n",res); 1954 exit(1); 1955 } 1956 1957 for (;;) { 1958 res = fatfs_fileop_read(ref,buffer,39); 1959// xprintf("read returned %d\n",res); 1960 if (res <= 0) break; 1961 1962 if (res > 0) { 1963 total += res; 1964 buffer[res] = 0; 1965 xprintf("%s",buffer); 1966 } 1967 } 1968 1969 if (res < 0) xprintf("error! \n"); 1970 1971 xprintf("[total %d]\n",total); 1972 1973 fatfs_fileop_close(ref); 1974 1975 exit(0); 1976 1977} 1978 1979#endif 1980