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->fat_dirty = 0; 880 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); 881 if (mydata->fatbuf == NULL) { 882 debug("Error: allocating memory\n"); 883 return -1; 884 } 885 886 if (vfat_enabled) 887 debug("VFAT Support enabled\n"); 888 889 debug("FAT%d, fat_sect: %d, fatlength: %d\n", 890 mydata->fatsize, mydata->fat_sect, mydata->fatlength); 891 debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" 892 "Data begins at: %d\n", 893 root_cluster, 894 mydata->rootdir_sect, 895 mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); 896 debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, 897 mydata->clust_size); 898 899 /* "cwd" is always the root... */ 900 while (ISDIRDELIM(*filename)) 901 filename++; 902 903 /* Make a copy of the filename and convert it to lowercase */ 904 strcpy(fnamecopy, filename); 905 downcase(fnamecopy); 906 907 root_reparse: 908 if (*fnamecopy == '\0') { 909 if (!dols) 910 goto exit; 911 912 dols = LS_ROOT; 913 } else if ((idx = dirdelim(fnamecopy)) >= 0) { 914 isdir = 1; 915 fnamecopy[idx] = '\0'; 916 subname = fnamecopy + idx + 1; 917 918 /* Handle multiple delimiters */ 919 while (ISDIRDELIM(*subname)) 920 subname++; 921 } else if (dols) { 922 isdir = 1; 923 } 924 925 buffer_blk_cnt = 0; 926 firsttime = 1; 927 while (1) { 928 int i; 929 930 if (mydata->fatsize == 32 || firsttime) { 931 dir_ptr = do_fat_read_at_block; 932 firsttime = 0; 933 } else { 934 /** 935 * FAT16 sector buffer modification: 936 * Each loop, the second buffered block is moved to 937 * the buffer begin, and two next sectors are read 938 * next to the previously moved one. So the sector 939 * buffer keeps always 3 sectors for fat16. 940 * And the current sector is the buffer second sector 941 * beside the "firsttime" read, when it is the first one. 942 * 943 * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1] 944 * n = computed root dir sector 945 * loop | cursect-1 | cursect | cursect+1 | 946 * 0 | sector n+0 | sector n+1 | none | 947 * 1 | none | sector n+0 | sector n+1 | 948 * 0 | sector n+1 | sector n+2 | sector n+3 | 949 * 1 | sector n+3 | ... 950 */ 951 dir_ptr = (do_fat_read_at_block + mydata->sect_size); 952 memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size); 953 } 954 955 do_read = 1; 956 957 if (mydata->fatsize == 32 && buffer_blk_cnt) 958 do_read = 0; 959 960 if (do_read) { 961 read_blk = (mydata->fatsize == 32) ? 962 mydata->clust_size : PREFETCH_BLOCKS; 963 964 debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", 965 cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK); 966 967 if (disk_read(cursect, read_blk, dir_ptr) < 0) { 968 debug("Error: reading rootdir block\n"); 969 goto exit; 970 } 971 972 dentptr = (dir_entry *)dir_ptr; 973 } 974 975 for (i = 0; i < DIRENTSPERBLOCK; i++) { 976 char s_name[14], l_name[VFAT_MAXLEN_BYTES]; 977 __u8 csum; 978 979 l_name[0] = '\0'; 980 if (dentptr->name[0] == DELETED_FLAG) { 981 dentptr++; 982 continue; 983 } 984 985 if (vfat_enabled) 986 csum = mkcksum(dentptr->name, dentptr->ext); 987 988 if (dentptr->attr & ATTR_VOLUME) { 989 if (vfat_enabled && 990 (dentptr->attr & ATTR_VFAT) == ATTR_VFAT && 991 (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 992 prevcksum = 993 ((dir_slot *)dentptr)->alias_checksum; 994 995 get_vfatname(mydata, 996 root_cluster, 997 dir_ptr, 998 dentptr, l_name); 999 1000 if (dols == LS_ROOT) { 1001 char dirc; 1002 int doit = 0; 1003 int isdir = 1004 (dentptr->attr & ATTR_DIR); 1005 1006 if (isdir) { 1007 dirs++; 1008 dirc = '/'; 1009 doit = 1; 1010 } else { 1011 dirc = ' '; 1012 if (l_name[0] != 0) { 1013 files++; 1014 doit = 1; 1015 } 1016 } 1017 if (doit) { 1018 if (dirc == ' ') { 1019 printf(" %8u %s%c\n", 1020 FAT2CPU32(dentptr->size), 1021 l_name, 1022 dirc); 1023 } else { 1024 printf(" %s%c\n", 1025 l_name, 1026 dirc); 1027 } 1028 } 1029 dentptr++; 1030 continue; 1031 } 1032 debug("Rootvfatname: |%s|\n", 1033 l_name); 1034 } else { 1035 /* Volume label or VFAT entry */ 1036 dentptr++; 1037 continue; 1038 } 1039 } else if (dentptr->name[0] == 0) { 1040 debug("RootDentname == NULL - %d\n", i); 1041 if (dols == LS_ROOT) { 1042 printf("\n%d file(s), %d dir(s)\n\n", 1043 files, dirs); 1044 ret = 0; 1045 } 1046 goto exit; 1047 } 1048 else if (vfat_enabled && 1049 dols == LS_ROOT && csum == prevcksum) { 1050 prevcksum = 0xffff; 1051 dentptr++; 1052 continue; 1053 } 1054 1055 get_name(dentptr, s_name); 1056 1057 if (dols == LS_ROOT) { 1058 int isdir = (dentptr->attr & ATTR_DIR); 1059 char dirc; 1060 int doit = 0; 1061 1062 if (isdir) { 1063 dirc = '/'; 1064 if (s_name[0] != 0) { 1065 dirs++; 1066 doit = 1; 1067 } 1068 } else { 1069 dirc = ' '; 1070 if (s_name[0] != 0) { 1071 files++; 1072 doit = 1; 1073 } 1074 } 1075 if (doit) { 1076 if (dirc == ' ') { 1077 printf(" %8u %s%c\n", 1078 FAT2CPU32(dentptr->size), 1079 s_name, dirc); 1080 } else { 1081 printf(" %s%c\n", 1082 s_name, dirc); 1083 } 1084 } 1085 dentptr++; 1086 continue; 1087 } 1088 1089 if (strcmp(fnamecopy, s_name) 1090 && strcmp(fnamecopy, l_name)) { 1091 debug("RootMismatch: |%s|%s|\n", s_name, 1092 l_name); 1093 dentptr++; 1094 continue; 1095 } 1096 1097 if (isdir && !(dentptr->attr & ATTR_DIR)) 1098 goto exit; 1099 1100 debug("RootName: %s", s_name); 1101 debug(", start: 0x%x", START(dentptr)); 1102 debug(", size: 0x%x %s\n", 1103 FAT2CPU32(dentptr->size), 1104 isdir ? "(DIR)" : ""); 1105 1106 goto rootdir_done; /* We got a match */ 1107 } 1108 debug("END LOOP: buffer_blk_cnt=%d clust_size=%d\n", buffer_blk_cnt, 1109 mydata->clust_size); 1110 1111 /* 1112 * On FAT32 we must fetch the FAT entries for the next 1113 * root directory clusters when a cluster has been 1114 * completely processed. 1115 */ 1116 ++buffer_blk_cnt; 1117 int rootdir_end = 0; 1118 if (mydata->fatsize == 32) { 1119 if (buffer_blk_cnt == mydata->clust_size) { 1120 int nxtsect = 0; 1121 int nxt_clust = 0; 1122 1123 nxt_clust = get_fatent(mydata, root_cluster); 1124 rootdir_end = CHECK_CLUST(nxt_clust, 32); 1125 1126 nxtsect = mydata->data_begin + 1127 (nxt_clust * mydata->clust_size); 1128 1129 root_cluster = nxt_clust; 1130 1131 cursect = nxtsect; 1132 buffer_blk_cnt = 0; 1133 } 1134 } else { 1135 if (buffer_blk_cnt == PREFETCH_BLOCKS) 1136 buffer_blk_cnt = 0; 1137 1138 rootdir_end = (++cursect - mydata->rootdir_sect >= 1139 rootdir_size); 1140 } 1141 1142 /* If end of rootdir reached */ 1143 if (rootdir_end) { 1144 if (dols == LS_ROOT) { 1145 printf("\n%d file(s), %d dir(s)\n\n", 1146 files, dirs); 1147 *size = 0; 1148 } 1149 goto exit; 1150 } 1151 } 1152 rootdir_done: 1153 1154 firsttime = 1; 1155 1156 while (isdir) { 1157 int startsect = mydata->data_begin 1158 + START(dentptr) * mydata->clust_size; 1159 dir_entry dent; 1160 char *nextname = NULL; 1161 1162 dent = *dentptr; 1163 dentptr = &dent; 1164 1165 idx = dirdelim(subname); 1166 1167 if (idx >= 0) { 1168 subname[idx] = '\0'; 1169 nextname = subname + idx + 1; 1170 /* Handle multiple delimiters */ 1171 while (ISDIRDELIM(*nextname)) 1172 nextname++; 1173 if (dols && *nextname == '\0') 1174 firsttime = 0; 1175 } else { 1176 if (dols && firsttime) { 1177 firsttime = 0; 1178 } else { 1179 isdir = 0; 1180 } 1181 } 1182 1183 if (get_dentfromdir(mydata, startsect, subname, dentptr, 1184 isdir ? 0 : dols) == NULL) { 1185 if (dols && !isdir) 1186 *size = 0; 1187 goto exit; 1188 } 1189 1190 if (isdir && !(dentptr->attr & ATTR_DIR)) 1191 goto exit; 1192 1193 /* 1194 * If we are looking for a directory, and found a directory 1195 * type entry, and the entry is for the root directory (as 1196 * denoted by a cluster number of 0), jump back to the start 1197 * of the function, since at least on FAT12/16, the root dir 1198 * lives in a hard-coded location and needs special handling 1199 * to parse, rather than simply following the cluster linked 1200 * list in the FAT, like other directories. 1201 */ 1202 if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) { 1203 /* 1204 * Modify the filename to remove the prefix that gets 1205 * back to the root directory, so the initial root dir 1206 * parsing code can continue from where we are without 1207 * confusion. 1208 */ 1209 strcpy(fnamecopy, nextname ?: ""); 1210 /* 1211 * Set up state the same way as the function does when 1212 * first started. This is required for the root dir 1213 * parsing code operates in its expected environment. 1214 */ 1215 subname = ""; 1216 cursect = mydata->rootdir_sect; 1217 isdir = 0; 1218 goto root_reparse; 1219 } 1220 1221 if (idx >= 0) 1222 subname = nextname; 1223 } 1224 1225 if (dogetsize) { 1226 *size = FAT2CPU32(dentptr->size); 1227 ret = 0; 1228 } else { 1229 ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size); 1230 } 1231 debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size); 1232 1233 exit: 1234 free(mydata->fatbuf); 1235 return ret; 1236 } 1237 1238 int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols, 1239 loff_t *actread) 1240 { 1241 return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread); 1242 } 1243 1244 int file_fat_detectfs(void) 1245 { 1246 boot_sector bs; 1247 volume_info volinfo; 1248 int fatsize; 1249 char vol_label[12]; 1250 1251 if (cur_dev == NULL) { 1252 printf("No current device\n"); 1253 return 1; 1254 } 1255 1256 #if defined(CONFIG_CMD_IDE) || \ 1257 defined(CONFIG_CMD_SATA) || \ 1258 defined(CONFIG_SCSI) || \ 1259 defined(CONFIG_CMD_USB) || \ 1260 defined(CONFIG_MMC) 1261 printf("Interface: "); 1262 switch (cur_dev->if_type) { 1263 case IF_TYPE_IDE: 1264 printf("IDE"); 1265 break; 1266 case IF_TYPE_SATA: 1267 printf("SATA"); 1268 break; 1269 case IF_TYPE_SCSI: 1270 printf("SCSI"); 1271 break; 1272 case IF_TYPE_ATAPI: 1273 printf("ATAPI"); 1274 break; 1275 case IF_TYPE_USB: 1276 printf("USB"); 1277 break; 1278 case IF_TYPE_DOC: 1279 printf("DOC"); 1280 break; 1281 case IF_TYPE_MMC: 1282 printf("MMC"); 1283 break; 1284 default: 1285 printf("Unknown"); 1286 } 1287 1288 printf("\n Device %d: ", cur_dev->devnum); 1289 dev_print(cur_dev); 1290 #endif 1291 1292 if (read_bootsectandvi(&bs, &volinfo, &fatsize)) { 1293 printf("\nNo valid FAT fs found\n"); 1294 return 1; 1295 } 1296 1297 memcpy(vol_label, volinfo.volume_label, 11); 1298 vol_label[11] = '\0'; 1299 volinfo.fs_type[5] = '\0'; 1300 1301 printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label); 1302 1303 return 0; 1304 } 1305 1306 int file_fat_ls(const char *dir) 1307 { 1308 loff_t size; 1309 1310 return do_fat_read(dir, NULL, 0, LS_YES, &size); 1311 } 1312 1313 int fat_exists(const char *filename) 1314 { 1315 int ret; 1316 loff_t size; 1317 1318 ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size); 1319 return ret == 0; 1320 } 1321 1322 int fat_size(const char *filename, loff_t *size) 1323 { 1324 return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, size); 1325 } 1326 1327 int file_fat_read_at(const char *filename, loff_t pos, void *buffer, 1328 loff_t maxsize, loff_t *actread) 1329 { 1330 printf("reading %s\n", filename); 1331 return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0, 1332 actread); 1333 } 1334 1335 int file_fat_read(const char *filename, void *buffer, int maxsize) 1336 { 1337 loff_t actread; 1338 int ret; 1339 1340 ret = file_fat_read_at(filename, 0, buffer, maxsize, &actread); 1341 if (ret) 1342 return ret; 1343 else 1344 return actread; 1345 } 1346 1347 int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, 1348 loff_t *actread) 1349 { 1350 int ret; 1351 1352 ret = file_fat_read_at(filename, offset, buf, len, actread); 1353 if (ret) 1354 printf("** Unable to read file %s **\n", filename); 1355 1356 return ret; 1357 } 1358 1359 void fat_close(void) 1360 { 1361 } 1362