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