1 /* 2 * fat.c 3 * 4 * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg 5 * 6 * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6 7 * 2003-03-10 - kharris@nexus-tech.net - ported to uboot 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <blk.h> 14 #include <config.h> 15 #include <exports.h> 16 #include <fat.h> 17 #include <asm/byteorder.h> 18 #include <part.h> 19 #include <malloc.h> 20 #include <memalign.h> 21 #include <linux/compiler.h> 22 #include <linux/ctype.h> 23 24 #ifdef CONFIG_SUPPORT_VFAT 25 static const int vfat_enabled = 1; 26 #else 27 static const int vfat_enabled = 0; 28 #endif 29 30 /* 31 * Convert a string to lowercase. 32 */ 33 static void downcase(char *str) 34 { 35 while (*str != '\0') { 36 *str = tolower(*str); 37 str++; 38 } 39 } 40 41 static struct blk_desc *cur_dev; 42 static disk_partition_t cur_part_info; 43 44 #define DOS_BOOT_MAGIC_OFFSET 0x1fe 45 #define DOS_FS_TYPE_OFFSET 0x36 46 #define DOS_FS32_TYPE_OFFSET 0x52 47 48 static int disk_read(__u32 block, __u32 nr_blocks, void *buf) 49 { 50 ulong ret; 51 52 if (!cur_dev) 53 return -1; 54 55 ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf); 56 57 if (nr_blocks && ret == 0) 58 return -1; 59 60 return ret; 61 } 62 63 int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info) 64 { 65 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); 66 67 cur_dev = dev_desc; 68 cur_part_info = *info; 69 70 /* Make sure it has a valid FAT header */ 71 if (disk_read(0, 1, buffer) != 1) { 72 cur_dev = NULL; 73 return -1; 74 } 75 76 /* Check if it's actually a DOS volume */ 77 if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { 78 cur_dev = NULL; 79 return -1; 80 } 81 82 /* Check for FAT12/FAT16/FAT32 filesystem */ 83 if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) 84 return 0; 85 if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) 86 return 0; 87 88 cur_dev = NULL; 89 return -1; 90 } 91 92 int fat_register_device(struct blk_desc *dev_desc, int part_no) 93 { 94 disk_partition_t info; 95 96 /* First close any currently found FAT filesystem */ 97 cur_dev = NULL; 98 99 /* Read the partition table, if present */ 100 if (part_get_info(dev_desc, part_no, &info)) { 101 if (part_no != 0) { 102 printf("** Partition %d not valid on device %d **\n", 103 part_no, dev_desc->devnum); 104 return -1; 105 } 106 107 info.start = 0; 108 info.size = dev_desc->lba; 109 info.blksz = dev_desc->blksz; 110 info.name[0] = 0; 111 info.type[0] = 0; 112 info.bootable = 0; 113 #ifdef CONFIG_PARTITION_UUIDS 114 info.uuid[0] = 0; 115 #endif 116 } 117 118 return fat_set_blk_dev(dev_desc, &info); 119 } 120 121 /* 122 * Get the first occurence of a directory delimiter ('/' or '\') in a string. 123 * Return index into string if found, -1 otherwise. 124 */ 125 static int dirdelim(char *str) 126 { 127 char *start = str; 128 129 while (*str != '\0') { 130 if (ISDIRDELIM(*str)) 131 return str - start; 132 str++; 133 } 134 return -1; 135 } 136 137 /* 138 * Extract zero terminated short name from a directory entry. 139 */ 140 static void get_name(dir_entry *dirent, char *s_name) 141 { 142 char *ptr; 143 144 memcpy(s_name, dirent->name, 8); 145 s_name[8] = '\0'; 146 ptr = s_name; 147 while (*ptr && *ptr != ' ') 148 ptr++; 149 if (dirent->ext[0] && dirent->ext[0] != ' ') { 150 *ptr = '.'; 151 ptr++; 152 memcpy(ptr, dirent->ext, 3); 153 ptr[3] = '\0'; 154 while (*ptr && *ptr != ' ') 155 ptr++; 156 } 157 *ptr = '\0'; 158 if (*s_name == DELETED_FLAG) 159 *s_name = '\0'; 160 else if (*s_name == aRING) 161 *s_name = DELETED_FLAG; 162 downcase(s_name); 163 } 164 165 /* 166 * Get the entry at index 'entry' in a FAT (12/16/32) table. 167 * On failure 0x00 is returned. 168 */ 169 static __u32 get_fatent(fsdata *mydata, __u32 entry) 170 { 171 __u32 bufnum; 172 __u32 off16, offset; 173 __u32 ret = 0x00; 174 __u16 val1, val2; 175 176 switch (mydata->fatsize) { 177 case 32: 178 bufnum = entry / FAT32BUFSIZE; 179 offset = entry - bufnum * FAT32BUFSIZE; 180 break; 181 case 16: 182 bufnum = entry / FAT16BUFSIZE; 183 offset = entry - bufnum * FAT16BUFSIZE; 184 break; 185 case 12: 186 bufnum = entry / FAT12BUFSIZE; 187 offset = entry - bufnum * FAT12BUFSIZE; 188 break; 189 190 default: 191 /* Unsupported FAT size */ 192 return ret; 193 } 194 195 debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n", 196 mydata->fatsize, entry, entry, offset, offset); 197 198 /* Read a new block of FAT entries into the cache. */ 199 if (bufnum != mydata->fatbufnum) { 200 __u32 getsize = FATBUFBLOCKS; 201 __u8 *bufptr = mydata->fatbuf; 202 __u32 fatlength = mydata->fatlength; 203 __u32 startblock = bufnum * FATBUFBLOCKS; 204 205 /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ 206 if (startblock + getsize > fatlength) 207 getsize = fatlength - startblock; 208 209 startblock += mydata->fat_sect; /* Offset from start of disk */ 210 211 if (disk_read(startblock, getsize, bufptr) < 0) { 212 debug("Error reading FAT blocks\n"); 213 return ret; 214 } 215 mydata->fatbufnum = bufnum; 216 } 217 218 /* Get the actual entry from the table */ 219 switch (mydata->fatsize) { 220 case 32: 221 ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); 222 break; 223 case 16: 224 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); 225 break; 226 case 12: 227 off16 = (offset * 3) / 4; 228 229 switch (offset & 0x3) { 230 case 0: 231 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]); 232 ret &= 0xfff; 233 break; 234 case 1: 235 val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); 236 val1 &= 0xf000; 237 val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); 238 val2 &= 0x00ff; 239 ret = (val2 << 4) | (val1 >> 12); 240 break; 241 case 2: 242 val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); 243 val1 &= 0xff00; 244 val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]); 245 val2 &= 0x000f; 246 ret = (val2 << 8) | (val1 >> 8); 247 break; 248 case 3: 249 ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]); 250 ret = (ret & 0xfff0) >> 4; 251 break; 252 default: 253 break; 254 } 255 break; 256 } 257 debug("FAT%d: ret: %08x, offset: %04x\n", 258 mydata->fatsize, ret, offset); 259 260 return ret; 261 } 262 263 /* 264 * Read at most 'size' bytes from the specified cluster into 'buffer'. 265 * Return 0 on success, -1 otherwise. 266 */ 267 static int 268 get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) 269 { 270 __u32 idx = 0; 271 __u32 startsect; 272 int ret; 273 274 if (clustnum > 0) { 275 startsect = mydata->data_begin + 276 clustnum * mydata->clust_size; 277 } else { 278 startsect = mydata->rootdir_sect; 279 } 280 281 debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); 282 283 if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { 284 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); 285 286 printf("FAT: Misaligned buffer address (%p)\n", buffer); 287 288 while (size >= mydata->sect_size) { 289 ret = disk_read(startsect++, 1, tmpbuf); 290 if (ret != 1) { 291 debug("Error reading data (got %d)\n", ret); 292 return -1; 293 } 294 295 memcpy(buffer, tmpbuf, mydata->sect_size); 296 buffer += mydata->sect_size; 297 size -= mydata->sect_size; 298 } 299 } else { 300 idx = size / mydata->sect_size; 301 ret = disk_read(startsect, idx, buffer); 302 if (ret != idx) { 303 debug("Error reading data (got %d)\n", ret); 304 return -1; 305 } 306 startsect += idx; 307 idx *= mydata->sect_size; 308 buffer += idx; 309 size -= idx; 310 } 311 if (size) { 312 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); 313 314 ret = disk_read(startsect, 1, tmpbuf); 315 if (ret != 1) { 316 debug("Error reading data (got %d)\n", ret); 317 return -1; 318 } 319 320 memcpy(buffer, tmpbuf, size); 321 } 322 323 return 0; 324 } 325 326 /* 327 * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr' 328 * into 'buffer'. 329 * Update the number of bytes read in *gotsize or return -1 on fatal errors. 330 */ 331 __u8 get_contents_vfatname_block[MAX_CLUSTSIZE] 332 __aligned(ARCH_DMA_MINALIGN); 333 334 static int get_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, 335 __u8 *buffer, loff_t maxsize, loff_t *gotsize) 336 { 337 loff_t filesize = FAT2CPU32(dentptr->size); 338 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; 339 __u32 curclust = START(dentptr); 340 __u32 endclust, newclust; 341 loff_t actsize; 342 343 *gotsize = 0; 344 debug("Filesize: %llu bytes\n", filesize); 345 346 if (pos >= filesize) { 347 debug("Read position past EOF: %llu\n", pos); 348 return 0; 349 } 350 351 if (maxsize > 0 && filesize > pos + maxsize) 352 filesize = pos + maxsize; 353 354 debug("%llu bytes\n", filesize); 355 356 actsize = bytesperclust; 357 358 /* go to cluster at pos */ 359 while (actsize <= pos) { 360 curclust = get_fatent(mydata, curclust); 361 if (CHECK_CLUST(curclust, mydata->fatsize)) { 362 debug("curclust: 0x%x\n", curclust); 363 debug("Invalid FAT entry\n"); 364 return 0; 365 } 366 actsize += bytesperclust; 367 } 368 369 /* actsize > pos */ 370 actsize -= bytesperclust; 371 filesize -= actsize; 372 pos -= actsize; 373 374 /* align to beginning of next cluster if any */ 375 if (pos) { 376 actsize = min(filesize, (loff_t)bytesperclust); 377 if (get_cluster(mydata, curclust, get_contents_vfatname_block, 378 (int)actsize) != 0) { 379 printf("Error reading cluster\n"); 380 return -1; 381 } 382 filesize -= actsize; 383 actsize -= pos; 384 memcpy(buffer, get_contents_vfatname_block + pos, actsize); 385 *gotsize += actsize; 386 if (!filesize) 387 return 0; 388 buffer += actsize; 389 390 curclust = get_fatent(mydata, curclust); 391 if (CHECK_CLUST(curclust, mydata->fatsize)) { 392 debug("curclust: 0x%x\n", curclust); 393 debug("Invalid FAT entry\n"); 394 return 0; 395 } 396 } 397 398 actsize = bytesperclust; 399 endclust = curclust; 400 401 do { 402 /* search for consecutive clusters */ 403 while (actsize < filesize) { 404 newclust = get_fatent(mydata, endclust); 405 if ((newclust - 1) != endclust) 406 goto getit; 407 if (CHECK_CLUST(newclust, mydata->fatsize)) { 408 debug("curclust: 0x%x\n", newclust); 409 debug("Invalid FAT entry\n"); 410 return 0; 411 } 412 endclust = newclust; 413 actsize += bytesperclust; 414 } 415 416 /* get remaining bytes */ 417 actsize = filesize; 418 if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 419 printf("Error reading cluster\n"); 420 return -1; 421 } 422 *gotsize += actsize; 423 return 0; 424 getit: 425 if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 426 printf("Error reading cluster\n"); 427 return -1; 428 } 429 *gotsize += (int)actsize; 430 filesize -= actsize; 431 buffer += actsize; 432 433 curclust = get_fatent(mydata, endclust); 434 if (CHECK_CLUST(curclust, mydata->fatsize)) { 435 debug("curclust: 0x%x\n", curclust); 436 printf("Invalid FAT entry\n"); 437 return 0; 438 } 439 actsize = bytesperclust; 440 endclust = curclust; 441 } while (1); 442 } 443 444 /* 445 * Extract the file name information from 'slotptr' into 'l_name', 446 * starting at l_name[*idx]. 447 * Return 1 if terminator (zero byte) is found, 0 otherwise. 448 */ 449 static int slot2str(dir_slot *slotptr, char *l_name, int *idx) 450 { 451 int j; 452 453 for (j = 0; j <= 8; j += 2) { 454 l_name[*idx] = slotptr->name0_4[j]; 455 if (l_name[*idx] == 0x00) 456 return 1; 457 (*idx)++; 458 } 459 for (j = 0; j <= 10; j += 2) { 460 l_name[*idx] = slotptr->name5_10[j]; 461 if (l_name[*idx] == 0x00) 462 return 1; 463 (*idx)++; 464 } 465 for (j = 0; j <= 2; j += 2) { 466 l_name[*idx] = slotptr->name11_12[j]; 467 if (l_name[*idx] == 0x00) 468 return 1; 469 (*idx)++; 470 } 471 472 return 0; 473 } 474 475 /* 476 * Extract the full long filename starting at 'retdent' (which is really 477 * a slot) into 'l_name'. If successful also copy the real directory entry 478 * into 'retdent' 479 * Return 0 on success, -1 otherwise. 480 */ 481 static int 482 get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, 483 dir_entry *retdent, char *l_name) 484 { 485 dir_entry *realdent; 486 dir_slot *slotptr = (dir_slot *)retdent; 487 __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ? 488 PREFETCH_BLOCKS : 489 mydata->clust_size); 490 __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; 491 int idx = 0; 492 493 if (counter > VFAT_MAXSEQ) { 494 debug("Error: VFAT name is too long\n"); 495 return -1; 496 } 497 498 while ((__u8 *)slotptr < buflimit) { 499 if (counter == 0) 500 break; 501 if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) 502 return -1; 503 slotptr++; 504 counter--; 505 } 506 507 if ((__u8 *)slotptr >= buflimit) { 508 dir_slot *slotptr2; 509 510 if (curclust == 0) 511 return -1; 512 curclust = get_fatent(mydata, curclust); 513 if (CHECK_CLUST(curclust, mydata->fatsize)) { 514 debug("curclust: 0x%x\n", curclust); 515 printf("Invalid FAT entry\n"); 516 return -1; 517 } 518 519 if (get_cluster(mydata, curclust, get_contents_vfatname_block, 520 mydata->clust_size * mydata->sect_size) != 0) { 521 debug("Error: reading directory block\n"); 522 return -1; 523 } 524 525 slotptr2 = (dir_slot *)get_contents_vfatname_block; 526 while (counter > 0) { 527 if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) 528 & 0xff) != counter) 529 return -1; 530 slotptr2++; 531 counter--; 532 } 533 534 /* Save the real directory entry */ 535 realdent = (dir_entry *)slotptr2; 536 while ((__u8 *)slotptr2 > get_contents_vfatname_block) { 537 slotptr2--; 538 slot2str(slotptr2, l_name, &idx); 539 } 540 } else { 541 /* Save the real directory entry */ 542 realdent = (dir_entry *)slotptr; 543 } 544 545 do { 546 slotptr--; 547 if (slot2str(slotptr, l_name, &idx)) 548 break; 549 } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); 550 551 l_name[idx] = '\0'; 552 if (*l_name == DELETED_FLAG) 553 *l_name = '\0'; 554 else if (*l_name == aRING) 555 *l_name = DELETED_FLAG; 556 downcase(l_name); 557 558 /* Return the real directory entry */ 559 memcpy(retdent, realdent, sizeof(dir_entry)); 560 561 return 0; 562 } 563 564 /* Calculate short name checksum */ 565 static __u8 mkcksum(const char name[8], const char ext[3]) 566 { 567 int i; 568 569 __u8 ret = 0; 570 571 for (i = 0; i < 8; i++) 572 ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i]; 573 for (i = 0; i < 3; i++) 574 ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i]; 575 576 return ret; 577 } 578 579 /* 580 * Get the directory entry associated with 'filename' from the directory 581 * starting at 'startsect' 582 */ 583 __u8 get_dentfromdir_block[MAX_CLUSTSIZE] 584 __aligned(ARCH_DMA_MINALIGN); 585 586 static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, 587 char *filename, dir_entry *retdent, 588 int dols) 589 { 590 __u16 prevcksum = 0xffff; 591 __u32 curclust = START(retdent); 592 int files = 0, dirs = 0; 593 594 debug("get_dentfromdir: %s\n", filename); 595 596 while (1) { 597 dir_entry *dentptr; 598 599 int i; 600 601 if (get_cluster(mydata, curclust, get_dentfromdir_block, 602 mydata->clust_size * mydata->sect_size) != 0) { 603 debug("Error: reading directory block\n"); 604 return NULL; 605 } 606 607 dentptr = (dir_entry *)get_dentfromdir_block; 608 609 for (i = 0; i < DIRENTSPERCLUST; i++) { 610 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 611 612 l_name[0] = '\0'; 613 if (dentptr->name[0] == DELETED_FLAG) { 614 dentptr++; 615 continue; 616 } 617 if ((dentptr->attr & ATTR_VOLUME)) { 618 if (vfat_enabled && 619 (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && 620 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 621 prevcksum = ((dir_slot *)dentptr)->alias_checksum; 622 get_vfatname(mydata, curclust, 623 get_dentfromdir_block, 624 dentptr, l_name); 625 if (dols) { 626 int isdir; 627 char dirc; 628 int doit = 0; 629 630 isdir = (dentptr->attr & ATTR_DIR); 631 632 if (isdir) { 633 dirs++; 634 dirc = '/'; 635 doit = 1; 636 } else { 637 dirc = ' '; 638 if (l_name[0] != 0) { 639 files++; 640 doit = 1; 641 } 642 } 643 if (doit) { 644 if (dirc == ' ') { 645 printf(" %8u %s%c\n", 646 FAT2CPU32(dentptr->size), 647 l_name, 648 dirc); 649 } else { 650 printf(" %s%c\n", 651 l_name, 652 dirc); 653 } 654 } 655 dentptr++; 656 continue; 657 } 658 debug("vfatname: |%s|\n", l_name); 659 } else { 660 /* Volume label or VFAT entry */ 661 dentptr++; 662 continue; 663 } 664 } 665 if (dentptr->name[0] == 0) { 666 if (dols) { 667 printf("\n%d file(s), %d dir(s)\n\n", 668 files, dirs); 669 } 670 debug("Dentname == NULL - %d\n", i); 671 return NULL; 672 } 673 if (vfat_enabled) { 674 __u8 csum = mkcksum(dentptr->name, dentptr->ext); 675 if (dols && csum == prevcksum) { 676 prevcksum = 0xffff; 677 dentptr++; 678 continue; 679 } 680 } 681 682 get_name(dentptr, s_name); 683 if (dols) { 684 int isdir = (dentptr->attr & ATTR_DIR); 685 char dirc; 686 int doit = 0; 687 688 if (isdir) { 689 dirs++; 690 dirc = '/'; 691 doit = 1; 692 } else { 693 dirc = ' '; 694 if (s_name[0] != 0) { 695 files++; 696 doit = 1; 697 } 698 } 699 700 if (doit) { 701 if (dirc == ' ') { 702 printf(" %8u %s%c\n", 703 FAT2CPU32(dentptr->size), 704 s_name, dirc); 705 } else { 706 printf(" %s%c\n", 707 s_name, dirc); 708 } 709 } 710 711 dentptr++; 712 continue; 713 } 714 715 if (strcmp(filename, s_name) 716 && strcmp(filename, l_name)) { 717 debug("Mismatch: |%s|%s|\n", s_name, l_name); 718 dentptr++; 719 continue; 720 } 721 722 memcpy(retdent, dentptr, sizeof(dir_entry)); 723 724 debug("DentName: %s", s_name); 725 debug(", start: 0x%x", START(dentptr)); 726 debug(", size: 0x%x %s\n", 727 FAT2CPU32(dentptr->size), 728 (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); 729 730 return retdent; 731 } 732 733 curclust = get_fatent(mydata, curclust); 734 if (CHECK_CLUST(curclust, mydata->fatsize)) { 735 debug("curclust: 0x%x\n", curclust); 736 printf("Invalid FAT entry\n"); 737 return NULL; 738 } 739 } 740 741 return NULL; 742 } 743 744 /* 745 * Read boot sector and volume info from a FAT filesystem 746 */ 747 static int 748 read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) 749 { 750 __u8 *block; 751 volume_info *vistart; 752 int ret = 0; 753 754 if (cur_dev == NULL) { 755 debug("Error: no device selected\n"); 756 return -1; 757 } 758 759 block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz); 760 if (block == NULL) { 761 debug("Error: allocating block\n"); 762 return -1; 763 } 764 765 if (disk_read(0, 1, block) < 0) { 766 debug("Error: reading block\n"); 767 goto fail; 768 } 769 770 memcpy(bs, block, sizeof(boot_sector)); 771 bs->reserved = FAT2CPU16(bs->reserved); 772 bs->fat_length = FAT2CPU16(bs->fat_length); 773 bs->secs_track = FAT2CPU16(bs->secs_track); 774 bs->heads = FAT2CPU16(bs->heads); 775 bs->total_sect = FAT2CPU32(bs->total_sect); 776 777 /* FAT32 entries */ 778 if (bs->fat_length == 0) { 779 /* Assume FAT32 */ 780 bs->fat32_length = FAT2CPU32(bs->fat32_length); 781 bs->flags = FAT2CPU16(bs->flags); 782 bs->root_cluster = FAT2CPU32(bs->root_cluster); 783 bs->info_sector = FAT2CPU16(bs->info_sector); 784 bs->backup_boot = FAT2CPU16(bs->backup_boot); 785 vistart = (volume_info *)(block + sizeof(boot_sector)); 786 *fatsize = 32; 787 } else { 788 vistart = (volume_info *)&(bs->fat32_length); 789 *fatsize = 0; 790 } 791 memcpy(volinfo, vistart, sizeof(volume_info)); 792 793 if (*fatsize == 32) { 794 if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0) 795 goto exit; 796 } else { 797 if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) { 798 *fatsize = 12; 799 goto exit; 800 } 801 if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) { 802 *fatsize = 16; 803 goto exit; 804 } 805 } 806 807 debug("Error: broken fs_type sign\n"); 808 fail: 809 ret = -1; 810 exit: 811 free(block); 812 return ret; 813 } 814 815 __u8 do_fat_read_at_block[MAX_CLUSTSIZE] 816 __aligned(ARCH_DMA_MINALIGN); 817 818 int do_fat_read_at(const char *filename, loff_t pos, void *buffer, 819 loff_t maxsize, int dols, int dogetsize, loff_t *size) 820 { 821 char fnamecopy[2048]; 822 boot_sector bs; 823 volume_info volinfo; 824 fsdata datablock; 825 fsdata *mydata = &datablock; 826 dir_entry *dentptr = NULL; 827 __u16 prevcksum = 0xffff; 828 char *subname = ""; 829 __u32 cursect; 830 int idx, isdir = 0; 831 int files = 0, dirs = 0; 832 int ret = -1; 833 int firsttime; 834 __u32 root_cluster = 0; 835 __u32 read_blk; 836 int rootdir_size = 0; 837 int buffer_blk_cnt; 838 int do_read; 839 __u8 *dir_ptr; 840 841 if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { 842 debug("Error: reading boot sector\n"); 843 return -1; 844 } 845 846 if (mydata->fatsize == 32) { 847 root_cluster = bs.root_cluster; 848 mydata->fatlength = bs.fat32_length; 849 } else { 850 mydata->fatlength = bs.fat_length; 851 } 852 853 mydata->fat_sect = bs.reserved; 854 855 cursect = mydata->rootdir_sect 856 = mydata->fat_sect + mydata->fatlength * bs.fats; 857 858 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 859 mydata->clust_size = bs.cluster_size; 860 if (mydata->sect_size != cur_part_info.blksz) { 861 printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n", 862 mydata->sect_size, cur_part_info.blksz); 863 return -1; 864 } 865 866 if (mydata->fatsize == 32) { 867 mydata->data_begin = mydata->rootdir_sect - 868 (mydata->clust_size * 2); 869 } else { 870 rootdir_size = ((bs.dir_entries[1] * (int)256 + 871 bs.dir_entries[0]) * 872 sizeof(dir_entry)) / 873 mydata->sect_size; 874 mydata->data_begin = mydata->rootdir_sect + 875 rootdir_size - 876 (mydata->clust_size * 2); 877 } 878 879 mydata->fatbufnum = -1; 880 mydata->fat_dirty = 0; 881 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); 882 if (mydata->fatbuf == NULL) { 883 debug("Error: allocating memory\n"); 884 return -1; 885 } 886 887 if (vfat_enabled) 888 debug("VFAT Support enabled\n"); 889 890 debug("FAT%d, fat_sect: %d, fatlength: %d\n", 891 mydata->fatsize, mydata->fat_sect, mydata->fatlength); 892 debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" 893 "Data begins at: %d\n", 894 root_cluster, 895 mydata->rootdir_sect, 896 mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); 897 debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, 898 mydata->clust_size); 899 900 /* "cwd" is always the root... */ 901 while (ISDIRDELIM(*filename)) 902 filename++; 903 904 /* Make a copy of the filename and convert it to lowercase */ 905 strcpy(fnamecopy, filename); 906 downcase(fnamecopy); 907 908 root_reparse: 909 if (*fnamecopy == '\0') { 910 if (!dols) 911 goto exit; 912 913 dols = LS_ROOT; 914 } else if ((idx = dirdelim(fnamecopy)) >= 0) { 915 isdir = 1; 916 fnamecopy[idx] = '\0'; 917 subname = fnamecopy + idx + 1; 918 919 /* Handle multiple delimiters */ 920 while (ISDIRDELIM(*subname)) 921 subname++; 922 } else if (dols) { 923 isdir = 1; 924 } 925 926 buffer_blk_cnt = 0; 927 firsttime = 1; 928 while (1) { 929 int i; 930 931 if (mydata->fatsize == 32 || firsttime) { 932 dir_ptr = do_fat_read_at_block; 933 firsttime = 0; 934 } else { 935 /** 936 * FAT16 sector buffer modification: 937 * Each loop, the second buffered block is moved to 938 * the buffer begin, and two next sectors are read 939 * next to the previously moved one. So the sector 940 * buffer keeps always 3 sectors for fat16. 941 * And the current sector is the buffer second sector 942 * beside the "firsttime" read, when it is the first one. 943 * 944 * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1] 945 * n = computed root dir sector 946 * loop | cursect-1 | cursect | cursect+1 | 947 * 0 | sector n+0 | sector n+1 | none | 948 * 1 | none | sector n+0 | sector n+1 | 949 * 0 | sector n+1 | sector n+2 | sector n+3 | 950 * 1 | sector n+3 | ... 951 */ 952 dir_ptr = (do_fat_read_at_block + mydata->sect_size); 953 memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size); 954 } 955 956 do_read = 1; 957 958 if (mydata->fatsize == 32 && buffer_blk_cnt) 959 do_read = 0; 960 961 if (do_read) { 962 read_blk = (mydata->fatsize == 32) ? 963 mydata->clust_size : PREFETCH_BLOCKS; 964 965 debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", 966 cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK); 967 968 if (disk_read(cursect, read_blk, dir_ptr) < 0) { 969 debug("Error: reading rootdir block\n"); 970 goto exit; 971 } 972 973 dentptr = (dir_entry *)dir_ptr; 974 } 975 976 for (i = 0; i < DIRENTSPERBLOCK; i++) { 977 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 978 __u8 csum; 979 980 l_name[0] = '\0'; 981 if (dentptr->name[0] == DELETED_FLAG) { 982 dentptr++; 983 continue; 984 } 985 986 if (vfat_enabled) 987 csum = mkcksum(dentptr->name, dentptr->ext); 988 989 if (dentptr->attr & ATTR_VOLUME) { 990 if (vfat_enabled && 991 (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && 992 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 993 prevcksum = 994 ((dir_slot *)dentptr)->alias_checksum; 995 996 get_vfatname(mydata, 997 root_cluster, 998 dir_ptr, 999 dentptr, l_name); 1000 1001 if (dols == LS_ROOT) { 1002 char dirc; 1003 int doit = 0; 1004 int isdir = 1005 (dentptr->attr & ATTR_DIR); 1006 1007 if (isdir) { 1008 dirs++; 1009 dirc = '/'; 1010 doit = 1; 1011 } else { 1012 dirc = ' '; 1013 if (l_name[0] != 0) { 1014 files++; 1015 doit = 1; 1016 } 1017 } 1018 if (doit) { 1019 if (dirc == ' ') { 1020 printf(" %8u %s%c\n", 1021 FAT2CPU32(dentptr->size), 1022 l_name, 1023 dirc); 1024 } else { 1025 printf(" %s%c\n", 1026 l_name, 1027 dirc); 1028 } 1029 } 1030 dentptr++; 1031 continue; 1032 } 1033 debug("Rootvfatname: |%s|\n", 1034 l_name); 1035 } else { 1036 /* Volume label or VFAT entry */ 1037 dentptr++; 1038 continue; 1039 } 1040 } else if (dentptr->name[0] == 0) { 1041 debug("RootDentname == NULL - %d\n", i); 1042 if (dols == LS_ROOT) { 1043 printf("\n%d file(s), %d dir(s)\n\n", 1044 files, dirs); 1045 ret = 0; 1046 } 1047 goto exit; 1048 } 1049 else if (vfat_enabled && 1050 dols == LS_ROOT && csum == prevcksum) { 1051 prevcksum = 0xffff; 1052 dentptr++; 1053 continue; 1054 } 1055 1056 get_name(dentptr, s_name); 1057 1058 if (dols == LS_ROOT) { 1059 int isdir = (dentptr->attr & ATTR_DIR); 1060 char dirc; 1061 int doit = 0; 1062 1063 if (isdir) { 1064 dirc = '/'; 1065 if (s_name[0] != 0) { 1066 dirs++; 1067 doit = 1; 1068 } 1069 } else { 1070 dirc = ' '; 1071 if (s_name[0] != 0) { 1072 files++; 1073 doit = 1; 1074 } 1075 } 1076 if (doit) { 1077 if (dirc == ' ') { 1078 printf(" %8u %s%c\n", 1079 FAT2CPU32(dentptr->size), 1080 s_name, dirc); 1081 } else { 1082 printf(" %s%c\n", 1083 s_name, dirc); 1084 } 1085 } 1086 dentptr++; 1087 continue; 1088 } 1089 1090 if (strcmp(fnamecopy, s_name) 1091 && strcmp(fnamecopy, l_name)) { 1092 debug("RootMismatch: |%s|%s|\n", s_name, 1093 l_name); 1094 dentptr++; 1095 continue; 1096 } 1097 1098 if (isdir && !(dentptr->attr & ATTR_DIR)) 1099 goto exit; 1100 1101 debug("RootName: %s", s_name); 1102 debug(", start: 0x%x", START(dentptr)); 1103 debug(", size: 0x%x %s\n", 1104 FAT2CPU32(dentptr->size), 1105 isdir ? "(DIR)" : ""); 1106 1107 goto rootdir_done; /* We got a match */ 1108 } 1109 debug("END LOOP: buffer_blk_cnt=%d clust_size=%d\n", buffer_blk_cnt, 1110 mydata->clust_size); 1111 1112 /* 1113 * On FAT32 we must fetch the FAT entries for the next 1114 * root directory clusters when a cluster has been 1115 * completely processed. 1116 */ 1117 ++buffer_blk_cnt; 1118 int rootdir_end = 0; 1119 if (mydata->fatsize == 32) { 1120 if (buffer_blk_cnt == mydata->clust_size) { 1121 int nxtsect = 0; 1122 int nxt_clust = 0; 1123 1124 nxt_clust = get_fatent(mydata, root_cluster); 1125 rootdir_end = CHECK_CLUST(nxt_clust, 32); 1126 1127 nxtsect = mydata->data_begin + 1128 (nxt_clust * mydata->clust_size); 1129 1130 root_cluster = nxt_clust; 1131 1132 cursect = nxtsect; 1133 buffer_blk_cnt = 0; 1134 } 1135 } else { 1136 if (buffer_blk_cnt == PREFETCH_BLOCKS) 1137 buffer_blk_cnt = 0; 1138 1139 rootdir_end = (++cursect - mydata->rootdir_sect >= 1140 rootdir_size); 1141 } 1142 1143 /* If end of rootdir reached */ 1144 if (rootdir_end) { 1145 if (dols == LS_ROOT) { 1146 printf("\n%d file(s), %d dir(s)\n\n", 1147 files, dirs); 1148 *size = 0; 1149 } 1150 goto exit; 1151 } 1152 } 1153 rootdir_done: 1154 1155 firsttime = 1; 1156 1157 while (isdir) { 1158 int startsect = mydata->data_begin 1159 + START(dentptr) * mydata->clust_size; 1160 dir_entry dent; 1161 char *nextname = NULL; 1162 1163 dent = *dentptr; 1164 dentptr = &dent; 1165 1166 idx = dirdelim(subname); 1167 1168 if (idx >= 0) { 1169 subname[idx] = '\0'; 1170 nextname = subname + idx + 1; 1171 /* Handle multiple delimiters */ 1172 while (ISDIRDELIM(*nextname)) 1173 nextname++; 1174 if (dols && *nextname == '\0') 1175 firsttime = 0; 1176 } else { 1177 if (dols && firsttime) { 1178 firsttime = 0; 1179 } else { 1180 isdir = 0; 1181 } 1182 } 1183 1184 if (get_dentfromdir(mydata, startsect, subname, dentptr, 1185 isdir ? 0 : dols) == NULL) { 1186 if (dols && !isdir) 1187 *size = 0; 1188 goto exit; 1189 } 1190 1191 if (isdir && !(dentptr->attr & ATTR_DIR)) 1192 goto exit; 1193 1194 /* 1195 * If we are looking for a directory, and found a directory 1196 * type entry, and the entry is for the root directory (as 1197 * denoted by a cluster number of 0), jump back to the start 1198 * of the function, since at least on FAT12/16, the root dir 1199 * lives in a hard-coded location and needs special handling 1200 * to parse, rather than simply following the cluster linked 1201 * list in the FAT, like other directories. 1202 */ 1203 if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) { 1204 /* 1205 * Modify the filename to remove the prefix that gets 1206 * back to the root directory, so the initial root dir 1207 * parsing code can continue from where we are without 1208 * confusion. 1209 */ 1210 strcpy(fnamecopy, nextname ?: ""); 1211 /* 1212 * Set up state the same way as the function does when 1213 * first started. This is required for the root dir 1214 * parsing code operates in its expected environment. 1215 */ 1216 subname = ""; 1217 cursect = mydata->rootdir_sect; 1218 isdir = 0; 1219 goto root_reparse; 1220 } 1221 1222 if (idx >= 0) 1223 subname = nextname; 1224 } 1225 1226 if (dogetsize) { 1227 *size = FAT2CPU32(dentptr->size); 1228 ret = 0; 1229 } else { 1230 ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size); 1231 } 1232 debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size); 1233 1234 exit: 1235 free(mydata->fatbuf); 1236 return ret; 1237 } 1238 1239 int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols, 1240 loff_t *actread) 1241 { 1242 return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread); 1243 } 1244 1245 int file_fat_detectfs(void) 1246 { 1247 boot_sector bs; 1248 volume_info volinfo; 1249 int fatsize; 1250 char vol_label[12]; 1251 1252 if (cur_dev == NULL) { 1253 printf("No current device\n"); 1254 return 1; 1255 } 1256 1257 #if defined(CONFIG_CMD_IDE) || \ 1258 defined(CONFIG_CMD_SATA) || \ 1259 defined(CONFIG_SCSI) || \ 1260 defined(CONFIG_CMD_USB) || \ 1261 defined(CONFIG_MMC) 1262 printf("Interface: "); 1263 switch (cur_dev->if_type) { 1264 case IF_TYPE_IDE: 1265 printf("IDE"); 1266 break; 1267 case IF_TYPE_SATA: 1268 printf("SATA"); 1269 break; 1270 case IF_TYPE_SCSI: 1271 printf("SCSI"); 1272 break; 1273 case IF_TYPE_ATAPI: 1274 printf("ATAPI"); 1275 break; 1276 case IF_TYPE_USB: 1277 printf("USB"); 1278 break; 1279 case IF_TYPE_DOC: 1280 printf("DOC"); 1281 break; 1282 case IF_TYPE_MMC: 1283 printf("MMC"); 1284 break; 1285 default: 1286 printf("Unknown"); 1287 } 1288 1289 printf("\n Device %d: ", cur_dev->devnum); 1290 dev_print(cur_dev); 1291 #endif 1292 1293 if (read_bootsectandvi(&bs, &volinfo, &fatsize)) { 1294 printf("\nNo valid FAT fs found\n"); 1295 return 1; 1296 } 1297 1298 memcpy(vol_label, volinfo.volume_label, 11); 1299 vol_label[11] = '\0'; 1300 volinfo.fs_type[5] = '\0'; 1301 1302 printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label); 1303 1304 return 0; 1305 } 1306 1307 int file_fat_ls(const char *dir) 1308 { 1309 loff_t size; 1310 1311 return do_fat_read(dir, NULL, 0, LS_YES, &size); 1312 } 1313 1314 int fat_exists(const char *filename) 1315 { 1316 int ret; 1317 loff_t size; 1318 1319 ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size); 1320 return ret == 0; 1321 } 1322 1323 int fat_size(const char *filename, loff_t *size) 1324 { 1325 return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, size); 1326 } 1327 1328 int file_fat_read_at(const char *filename, loff_t pos, void *buffer, 1329 loff_t maxsize, loff_t *actread) 1330 { 1331 printf("reading %s\n", filename); 1332 return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0, 1333 actread); 1334 } 1335 1336 int file_fat_read(const char *filename, void *buffer, int maxsize) 1337 { 1338 loff_t actread; 1339 int ret; 1340 1341 ret = file_fat_read_at(filename, 0, buffer, maxsize, &actread); 1342 if (ret) 1343 return ret; 1344 else 1345 return actread; 1346 } 1347 1348 int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, 1349 loff_t *actread) 1350 { 1351 int ret; 1352 1353 ret = file_fat_read_at(filename, offset, buf, len, actread); 1354 if (ret) 1355 printf("** Unable to read file %s **\n", filename); 1356 1357 return ret; 1358 } 1359 1360 void fat_close(void) 1361 { 1362 } 1363