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