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 <fs.h> 18 #include <asm/byteorder.h> 19 #include <part.h> 20 #include <malloc.h> 21 #include <memalign.h> 22 #include <linux/compiler.h> 23 #include <linux/ctype.h> 24 25 #ifdef CONFIG_SUPPORT_VFAT 26 static const int vfat_enabled = 1; 27 #else 28 static const int vfat_enabled = 0; 29 #endif 30 31 /* 32 * Convert a string to lowercase. Converts at most 'len' characters, 33 * 'len' may be larger than the length of 'str' if 'str' is NULL 34 * terminated. 35 */ 36 static void downcase(char *str, size_t len) 37 { 38 while (*str != '\0' && len--) { 39 *str = tolower(*str); 40 str++; 41 } 42 } 43 44 static struct blk_desc *cur_dev; 45 static disk_partition_t cur_part_info; 46 47 #define DOS_BOOT_MAGIC_OFFSET 0x1fe 48 #define DOS_FS_TYPE_OFFSET 0x36 49 #define DOS_FS32_TYPE_OFFSET 0x52 50 51 static int disk_read(__u32 block, __u32 nr_blocks, void *buf) 52 { 53 ulong ret; 54 55 if (!cur_dev) 56 return -1; 57 58 ret = blk_dread(cur_dev, cur_part_info.start + block, nr_blocks, buf); 59 60 if (ret != nr_blocks) 61 return -1; 62 63 return ret; 64 } 65 66 int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info) 67 { 68 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); 69 70 cur_dev = dev_desc; 71 cur_part_info = *info; 72 73 /* Make sure it has a valid FAT header */ 74 if (disk_read(0, 1, buffer) != 1) { 75 cur_dev = NULL; 76 return -1; 77 } 78 79 /* Check if it's actually a DOS volume */ 80 if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) { 81 cur_dev = NULL; 82 return -1; 83 } 84 85 /* Check for FAT12/FAT16/FAT32 filesystem */ 86 if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3)) 87 return 0; 88 if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5)) 89 return 0; 90 91 cur_dev = NULL; 92 return -1; 93 } 94 95 int fat_register_device(struct blk_desc *dev_desc, int part_no) 96 { 97 disk_partition_t info; 98 99 /* First close any currently found FAT filesystem */ 100 cur_dev = NULL; 101 102 /* Read the partition table, if present */ 103 if (part_get_info(dev_desc, part_no, &info)) { 104 if (part_no != 0) { 105 printf("** Partition %d not valid on device %d **\n", 106 part_no, dev_desc->devnum); 107 return -1; 108 } 109 110 info.start = 0; 111 info.size = dev_desc->lba; 112 info.blksz = dev_desc->blksz; 113 info.name[0] = 0; 114 info.type[0] = 0; 115 info.bootable = 0; 116 #if CONFIG_IS_ENABLED(PARTITION_UUIDS) 117 info.uuid[0] = 0; 118 #endif 119 } 120 121 return fat_set_blk_dev(dev_desc, &info); 122 } 123 124 /* 125 * Extract zero terminated short name from a directory entry. 126 */ 127 static void get_name(dir_entry *dirent, char *s_name) 128 { 129 char *ptr; 130 131 memcpy(s_name, dirent->name, 8); 132 s_name[8] = '\0'; 133 ptr = s_name; 134 while (*ptr && *ptr != ' ') 135 ptr++; 136 if (dirent->lcase & CASE_LOWER_BASE) 137 downcase(s_name, (unsigned)(ptr - s_name)); 138 if (dirent->ext[0] && dirent->ext[0] != ' ') { 139 *ptr++ = '.'; 140 memcpy(ptr, dirent->ext, 3); 141 if (dirent->lcase & CASE_LOWER_EXT) 142 downcase(ptr, 3); 143 ptr[3] = '\0'; 144 while (*ptr && *ptr != ' ') 145 ptr++; 146 } 147 *ptr = '\0'; 148 if (*s_name == DELETED_FLAG) 149 *s_name = '\0'; 150 else if (*s_name == aRING) 151 *s_name = DELETED_FLAG; 152 } 153 154 static int flush_dirty_fat_buffer(fsdata *mydata); 155 #if !defined(CONFIG_FAT_WRITE) 156 /* Stub for read only operation */ 157 int flush_dirty_fat_buffer(fsdata *mydata) 158 { 159 (void)(mydata); 160 return 0; 161 } 162 #endif 163 164 /* 165 * Get the entry at index 'entry' in a FAT (12/16/32) table. 166 * On failure 0x00 is returned. 167 */ 168 static __u32 get_fatent(fsdata *mydata, __u32 entry) 169 { 170 __u32 bufnum; 171 __u32 offset, off8; 172 __u32 ret = 0x00; 173 174 if (CHECK_CLUST(entry, mydata->fatsize)) { 175 printf("Error: Invalid FAT entry: 0x%08x\n", entry); 176 return ret; 177 } 178 179 switch (mydata->fatsize) { 180 case 32: 181 bufnum = entry / FAT32BUFSIZE; 182 offset = entry - bufnum * FAT32BUFSIZE; 183 break; 184 case 16: 185 bufnum = entry / FAT16BUFSIZE; 186 offset = entry - bufnum * FAT16BUFSIZE; 187 break; 188 case 12: 189 bufnum = entry / FAT12BUFSIZE; 190 offset = entry - bufnum * FAT12BUFSIZE; 191 break; 192 193 default: 194 /* Unsupported FAT size */ 195 return ret; 196 } 197 198 debug("FAT%d: entry: 0x%08x = %d, offset: 0x%04x = %d\n", 199 mydata->fatsize, entry, entry, offset, offset); 200 201 /* Read a new block of FAT entries into the cache. */ 202 if (bufnum != mydata->fatbufnum) { 203 __u32 getsize = FATBUFBLOCKS; 204 __u8 *bufptr = mydata->fatbuf; 205 __u32 fatlength = mydata->fatlength; 206 __u32 startblock = bufnum * FATBUFBLOCKS; 207 208 /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */ 209 if (startblock + getsize > fatlength) 210 getsize = fatlength - startblock; 211 212 startblock += mydata->fat_sect; /* Offset from start of disk */ 213 214 /* Write back the fatbuf to the disk */ 215 if (flush_dirty_fat_buffer(mydata) < 0) 216 return -1; 217 218 if (disk_read(startblock, getsize, bufptr) < 0) { 219 debug("Error reading FAT blocks\n"); 220 return ret; 221 } 222 mydata->fatbufnum = bufnum; 223 } 224 225 /* Get the actual entry from the table */ 226 switch (mydata->fatsize) { 227 case 32: 228 ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]); 229 break; 230 case 16: 231 ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]); 232 break; 233 case 12: 234 off8 = (offset * 3) / 2; 235 /* fatbut + off8 may be unaligned, read in byte granularity */ 236 ret = mydata->fatbuf[off8] + (mydata->fatbuf[off8 + 1] << 8); 237 238 if (offset & 0x1) 239 ret >>= 4; 240 ret &= 0xfff; 241 } 242 debug("FAT%d: ret: 0x%08x, entry: 0x%08x, offset: 0x%04x\n", 243 mydata->fatsize, ret, entry, offset); 244 245 return ret; 246 } 247 248 /* 249 * Read at most 'size' bytes from the specified cluster into 'buffer'. 250 * Return 0 on success, -1 otherwise. 251 */ 252 static int 253 get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) 254 { 255 __u32 idx = 0; 256 __u32 startsect; 257 int ret; 258 259 if (clustnum > 0) { 260 startsect = clust_to_sect(mydata, clustnum); 261 } else { 262 startsect = mydata->rootdir_sect; 263 } 264 265 debug("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); 266 267 if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) { 268 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); 269 270 printf("FAT: Misaligned buffer address (%p)\n", buffer); 271 272 while (size >= mydata->sect_size) { 273 ret = disk_read(startsect++, 1, tmpbuf); 274 if (ret != 1) { 275 debug("Error reading data (got %d)\n", ret); 276 return -1; 277 } 278 279 memcpy(buffer, tmpbuf, mydata->sect_size); 280 buffer += mydata->sect_size; 281 size -= mydata->sect_size; 282 } 283 } else { 284 idx = size / mydata->sect_size; 285 ret = disk_read(startsect, idx, buffer); 286 if (ret != idx) { 287 debug("Error reading data (got %d)\n", ret); 288 return -1; 289 } 290 startsect += idx; 291 idx *= mydata->sect_size; 292 buffer += idx; 293 size -= idx; 294 } 295 if (size) { 296 ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size); 297 298 ret = disk_read(startsect, 1, tmpbuf); 299 if (ret != 1) { 300 debug("Error reading data (got %d)\n", ret); 301 return -1; 302 } 303 304 memcpy(buffer, tmpbuf, size); 305 } 306 307 return 0; 308 } 309 310 /* 311 * Read at most 'maxsize' bytes from 'pos' in the file associated with 'dentptr' 312 * into 'buffer'. 313 * Update the number of bytes read in *gotsize or return -1 on fatal errors. 314 */ 315 __u8 get_contents_vfatname_block[MAX_CLUSTSIZE] 316 __aligned(ARCH_DMA_MINALIGN); 317 318 static int get_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, 319 __u8 *buffer, loff_t maxsize, loff_t *gotsize) 320 { 321 loff_t filesize = FAT2CPU32(dentptr->size); 322 unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; 323 __u32 curclust = START(dentptr); 324 __u32 endclust, newclust; 325 loff_t actsize; 326 327 *gotsize = 0; 328 debug("Filesize: %llu bytes\n", filesize); 329 330 if (pos >= filesize) { 331 debug("Read position past EOF: %llu\n", pos); 332 return 0; 333 } 334 335 if (maxsize > 0 && filesize > pos + maxsize) 336 filesize = pos + maxsize; 337 338 debug("%llu bytes\n", filesize); 339 340 actsize = bytesperclust; 341 342 /* go to cluster at pos */ 343 while (actsize <= pos) { 344 curclust = get_fatent(mydata, curclust); 345 if (CHECK_CLUST(curclust, mydata->fatsize)) { 346 debug("curclust: 0x%x\n", curclust); 347 debug("Invalid FAT entry\n"); 348 return 0; 349 } 350 actsize += bytesperclust; 351 } 352 353 /* actsize > pos */ 354 actsize -= bytesperclust; 355 filesize -= actsize; 356 pos -= actsize; 357 358 /* align to beginning of next cluster if any */ 359 if (pos) { 360 actsize = min(filesize, (loff_t)bytesperclust); 361 if (get_cluster(mydata, curclust, get_contents_vfatname_block, 362 (int)actsize) != 0) { 363 printf("Error reading cluster\n"); 364 return -1; 365 } 366 filesize -= actsize; 367 actsize -= pos; 368 memcpy(buffer, get_contents_vfatname_block + pos, actsize); 369 *gotsize += actsize; 370 if (!filesize) 371 return 0; 372 buffer += actsize; 373 374 curclust = get_fatent(mydata, curclust); 375 if (CHECK_CLUST(curclust, mydata->fatsize)) { 376 debug("curclust: 0x%x\n", curclust); 377 debug("Invalid FAT entry\n"); 378 return 0; 379 } 380 } 381 382 actsize = bytesperclust; 383 endclust = curclust; 384 385 do { 386 /* search for consecutive clusters */ 387 while (actsize < filesize) { 388 newclust = get_fatent(mydata, endclust); 389 if ((newclust - 1) != endclust) 390 goto getit; 391 if (CHECK_CLUST(newclust, mydata->fatsize)) { 392 debug("curclust: 0x%x\n", newclust); 393 debug("Invalid FAT entry\n"); 394 return 0; 395 } 396 endclust = newclust; 397 actsize += bytesperclust; 398 } 399 400 /* get remaining bytes */ 401 actsize = filesize; 402 if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 403 printf("Error reading cluster\n"); 404 return -1; 405 } 406 *gotsize += actsize; 407 return 0; 408 getit: 409 if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 410 printf("Error reading cluster\n"); 411 return -1; 412 } 413 *gotsize += (int)actsize; 414 filesize -= actsize; 415 buffer += actsize; 416 417 curclust = get_fatent(mydata, endclust); 418 if (CHECK_CLUST(curclust, mydata->fatsize)) { 419 debug("curclust: 0x%x\n", curclust); 420 printf("Invalid FAT entry\n"); 421 return 0; 422 } 423 actsize = bytesperclust; 424 endclust = curclust; 425 } while (1); 426 } 427 428 /* 429 * Extract the file name information from 'slotptr' into 'l_name', 430 * starting at l_name[*idx]. 431 * Return 1 if terminator (zero byte) is found, 0 otherwise. 432 */ 433 static int slot2str(dir_slot *slotptr, char *l_name, int *idx) 434 { 435 int j; 436 437 for (j = 0; j <= 8; j += 2) { 438 l_name[*idx] = slotptr->name0_4[j]; 439 if (l_name[*idx] == 0x00) 440 return 1; 441 (*idx)++; 442 } 443 for (j = 0; j <= 10; j += 2) { 444 l_name[*idx] = slotptr->name5_10[j]; 445 if (l_name[*idx] == 0x00) 446 return 1; 447 (*idx)++; 448 } 449 for (j = 0; j <= 2; j += 2) { 450 l_name[*idx] = slotptr->name11_12[j]; 451 if (l_name[*idx] == 0x00) 452 return 1; 453 (*idx)++; 454 } 455 456 return 0; 457 } 458 459 /* Calculate short name checksum */ 460 static __u8 mkcksum(const char name[8], const char ext[3]) 461 { 462 int i; 463 464 __u8 ret = 0; 465 466 for (i = 0; i < 8; i++) 467 ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + name[i]; 468 for (i = 0; i < 3; i++) 469 ret = (((ret & 1) << 7) | ((ret & 0xfe) >> 1)) + ext[i]; 470 471 return ret; 472 } 473 474 /* 475 * TODO these should go away once fat_write is reworked to use the 476 * directory iterator 477 */ 478 __u8 get_dentfromdir_block[MAX_CLUSTSIZE] 479 __aligned(ARCH_DMA_MINALIGN); 480 __u8 do_fat_read_at_block[MAX_CLUSTSIZE] 481 __aligned(ARCH_DMA_MINALIGN); 482 483 /* 484 * Read boot sector and volume info from a FAT filesystem 485 */ 486 static int 487 read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) 488 { 489 __u8 *block; 490 volume_info *vistart; 491 int ret = 0; 492 493 if (cur_dev == NULL) { 494 debug("Error: no device selected\n"); 495 return -1; 496 } 497 498 block = memalign(ARCH_DMA_MINALIGN, cur_dev->blksz); 499 if (block == NULL) { 500 debug("Error: allocating block\n"); 501 return -1; 502 } 503 504 if (disk_read(0, 1, block) < 0) { 505 debug("Error: reading block\n"); 506 goto fail; 507 } 508 509 memcpy(bs, block, sizeof(boot_sector)); 510 bs->reserved = FAT2CPU16(bs->reserved); 511 bs->fat_length = FAT2CPU16(bs->fat_length); 512 bs->secs_track = FAT2CPU16(bs->secs_track); 513 bs->heads = FAT2CPU16(bs->heads); 514 bs->total_sect = FAT2CPU32(bs->total_sect); 515 516 /* FAT32 entries */ 517 if (bs->fat_length == 0) { 518 /* Assume FAT32 */ 519 bs->fat32_length = FAT2CPU32(bs->fat32_length); 520 bs->flags = FAT2CPU16(bs->flags); 521 bs->root_cluster = FAT2CPU32(bs->root_cluster); 522 bs->info_sector = FAT2CPU16(bs->info_sector); 523 bs->backup_boot = FAT2CPU16(bs->backup_boot); 524 vistart = (volume_info *)(block + sizeof(boot_sector)); 525 *fatsize = 32; 526 } else { 527 vistart = (volume_info *)&(bs->fat32_length); 528 *fatsize = 0; 529 } 530 memcpy(volinfo, vistart, sizeof(volume_info)); 531 532 if (*fatsize == 32) { 533 if (strncmp(FAT32_SIGN, vistart->fs_type, SIGNLEN) == 0) 534 goto exit; 535 } else { 536 if (strncmp(FAT12_SIGN, vistart->fs_type, SIGNLEN) == 0) { 537 *fatsize = 12; 538 goto exit; 539 } 540 if (strncmp(FAT16_SIGN, vistart->fs_type, SIGNLEN) == 0) { 541 *fatsize = 16; 542 goto exit; 543 } 544 } 545 546 debug("Error: broken fs_type sign\n"); 547 fail: 548 ret = -1; 549 exit: 550 free(block); 551 return ret; 552 } 553 554 static int get_fs_info(fsdata *mydata) 555 { 556 boot_sector bs; 557 volume_info volinfo; 558 int ret; 559 560 ret = read_bootsectandvi(&bs, &volinfo, &mydata->fatsize); 561 if (ret) { 562 debug("Error: reading boot sector\n"); 563 return ret; 564 } 565 566 if (mydata->fatsize == 32) { 567 mydata->fatlength = bs.fat32_length; 568 } else { 569 mydata->fatlength = bs.fat_length; 570 } 571 572 mydata->fat_sect = bs.reserved; 573 574 mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; 575 576 mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0]; 577 mydata->clust_size = bs.cluster_size; 578 if (mydata->sect_size != cur_part_info.blksz) { 579 printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n", 580 mydata->sect_size, cur_part_info.blksz); 581 return -1; 582 } 583 584 if (mydata->fatsize == 32) { 585 mydata->data_begin = mydata->rootdir_sect - 586 (mydata->clust_size * 2); 587 mydata->root_cluster = bs.root_cluster; 588 } else { 589 mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + 590 bs.dir_entries[0]) * 591 sizeof(dir_entry)) / 592 mydata->sect_size; 593 mydata->data_begin = mydata->rootdir_sect + 594 mydata->rootdir_size - 595 (mydata->clust_size * 2); 596 mydata->root_cluster = 597 sect_to_clust(mydata, mydata->rootdir_sect); 598 } 599 600 mydata->fatbufnum = -1; 601 mydata->fat_dirty = 0; 602 mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE); 603 if (mydata->fatbuf == NULL) { 604 debug("Error: allocating memory\n"); 605 return -1; 606 } 607 608 if (vfat_enabled) 609 debug("VFAT Support enabled\n"); 610 611 debug("FAT%d, fat_sect: %d, fatlength: %d\n", 612 mydata->fatsize, mydata->fat_sect, mydata->fatlength); 613 debug("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" 614 "Data begins at: %d\n", 615 mydata->root_cluster, 616 mydata->rootdir_sect, 617 mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); 618 debug("Sector size: %d, cluster size: %d\n", mydata->sect_size, 619 mydata->clust_size); 620 621 return 0; 622 } 623 624 625 /* 626 * Directory iterator, to simplify filesystem traversal 627 * 628 * Implements an iterator pattern to traverse directory tables, 629 * transparently handling directory tables split across multiple 630 * clusters, and the difference between FAT12/FAT16 root directory 631 * (contiguous) and subdirectories + FAT32 root (chained). 632 * 633 * Rough usage: 634 * 635 * for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) { 636 * // to traverse down to a subdirectory pointed to by 637 * // current iterator position: 638 * fat_itr_child(&itr, &itr); 639 * } 640 * 641 * For more complete example, see fat_itr_resolve() 642 */ 643 644 typedef struct { 645 fsdata *fsdata; /* filesystem parameters */ 646 unsigned clust; /* current cluster */ 647 int last_cluster; /* set once we've read last cluster */ 648 int is_root; /* is iterator at root directory */ 649 int remaining; /* remaining dent's in current cluster */ 650 651 /* current iterator position values: */ 652 dir_entry *dent; /* current directory entry */ 653 char l_name[VFAT_MAXLEN_BYTES]; /* long (vfat) name */ 654 char s_name[14]; /* short 8.3 name */ 655 char *name; /* l_name if there is one, else s_name */ 656 657 /* storage for current cluster in memory: */ 658 u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); 659 } fat_itr; 660 661 static int fat_itr_isdir(fat_itr *itr); 662 663 /** 664 * fat_itr_root() - initialize an iterator to start at the root 665 * directory 666 * 667 * @itr: iterator to initialize 668 * @fsdata: filesystem data for the partition 669 * @return 0 on success, else -errno 670 */ 671 static int fat_itr_root(fat_itr *itr, fsdata *fsdata) 672 { 673 if (get_fs_info(fsdata)) 674 return -ENXIO; 675 676 itr->fsdata = fsdata; 677 itr->clust = fsdata->root_cluster; 678 itr->dent = NULL; 679 itr->remaining = 0; 680 itr->last_cluster = 0; 681 itr->is_root = 1; 682 683 return 0; 684 } 685 686 /** 687 * fat_itr_child() - initialize an iterator to descend into a sub- 688 * directory 689 * 690 * Initializes 'itr' to iterate the contents of the directory at 691 * the current cursor position of 'parent'. It is an error to 692 * call this if the current cursor of 'parent' is pointing at a 693 * regular file. 694 * 695 * Note that 'itr' and 'parent' can be the same pointer if you do 696 * not need to preserve 'parent' after this call, which is useful 697 * for traversing directory structure to resolve a file/directory. 698 * 699 * @itr: iterator to initialize 700 * @parent: the iterator pointing at a directory entry in the 701 * parent directory of the directory to iterate 702 */ 703 static void fat_itr_child(fat_itr *itr, fat_itr *parent) 704 { 705 fsdata *mydata = parent->fsdata; /* for silly macros */ 706 unsigned clustnum = START(parent->dent); 707 708 assert(fat_itr_isdir(parent)); 709 710 itr->fsdata = parent->fsdata; 711 if (clustnum > 0) { 712 itr->clust = clustnum; 713 } else { 714 itr->clust = parent->fsdata->root_cluster; 715 } 716 itr->dent = NULL; 717 itr->remaining = 0; 718 itr->last_cluster = 0; 719 itr->is_root = 0; 720 } 721 722 static void *next_cluster(fat_itr *itr) 723 { 724 fsdata *mydata = itr->fsdata; /* for silly macros */ 725 int ret; 726 u32 sect; 727 728 /* have we reached the end? */ 729 if (itr->last_cluster) 730 return NULL; 731 732 sect = clust_to_sect(itr->fsdata, itr->clust); 733 734 debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n", 735 sect, itr->fsdata->clust_size, DIRENTSPERBLOCK); 736 737 /* 738 * NOTE: do_fat_read_at() had complicated logic to deal w/ 739 * vfat names that span multiple clusters in the fat16 case, 740 * which get_dentfromdir() probably also needed (and was 741 * missing). And not entirely sure what fat32 didn't have 742 * the same issue.. We solve that by only caring about one 743 * dent at a time and iteratively constructing the vfat long 744 * name. 745 */ 746 ret = disk_read(sect, itr->fsdata->clust_size, 747 itr->block); 748 if (ret < 0) { 749 debug("Error: reading block\n"); 750 return NULL; 751 } 752 753 if (itr->is_root && itr->fsdata->fatsize != 32) { 754 itr->clust++; 755 sect = clust_to_sect(itr->fsdata, itr->clust); 756 if (sect - itr->fsdata->rootdir_sect >= 757 itr->fsdata->rootdir_size) { 758 debug("cursect: 0x%x\n", itr->clust); 759 itr->last_cluster = 1; 760 } 761 } else { 762 itr->clust = get_fatent(itr->fsdata, itr->clust); 763 if (CHECK_CLUST(itr->clust, itr->fsdata->fatsize)) { 764 debug("cursect: 0x%x\n", itr->clust); 765 itr->last_cluster = 1; 766 } 767 } 768 769 return itr->block; 770 } 771 772 static dir_entry *next_dent(fat_itr *itr) 773 { 774 if (itr->remaining == 0) { 775 struct dir_entry *dent = next_cluster(itr); 776 unsigned nbytes = itr->fsdata->sect_size * 777 itr->fsdata->clust_size; 778 779 /* have we reached the last cluster? */ 780 if (!dent) 781 return NULL; 782 783 itr->remaining = nbytes / sizeof(dir_entry) - 1; 784 itr->dent = dent; 785 } else { 786 itr->remaining--; 787 itr->dent++; 788 } 789 790 /* have we reached the last valid entry? */ 791 if (itr->dent->name[0] == 0) 792 return NULL; 793 794 return itr->dent; 795 } 796 797 static dir_entry *extract_vfat_name(fat_itr *itr) 798 { 799 struct dir_entry *dent = itr->dent; 800 int seqn = itr->dent->name[0] & ~LAST_LONG_ENTRY_MASK; 801 u8 chksum, alias_checksum = ((dir_slot *)dent)->alias_checksum; 802 int n = 0; 803 804 while (seqn--) { 805 char buf[13]; 806 int idx = 0; 807 808 slot2str((dir_slot *)dent, buf, &idx); 809 810 /* shift accumulated long-name up and copy new part in: */ 811 memmove(itr->l_name + idx, itr->l_name, n); 812 memcpy(itr->l_name, buf, idx); 813 n += idx; 814 815 dent = next_dent(itr); 816 if (!dent) 817 return NULL; 818 } 819 820 itr->l_name[n] = '\0'; 821 822 chksum = mkcksum(dent->name, dent->ext); 823 824 /* checksum mismatch could mean deleted file, etc.. skip it: */ 825 if (chksum != alias_checksum) { 826 debug("** chksum=%x, alias_checksum=%x, l_name=%s, s_name=%8s.%3s\n", 827 chksum, alias_checksum, itr->l_name, dent->name, dent->ext); 828 return NULL; 829 } 830 831 return dent; 832 } 833 834 /** 835 * fat_itr_next() - step to the next entry in a directory 836 * 837 * Must be called once on a new iterator before the cursor is valid. 838 * 839 * @itr: the iterator to iterate 840 * @return boolean, 1 if success or 0 if no more entries in the 841 * current directory 842 */ 843 static int fat_itr_next(fat_itr *itr) 844 { 845 dir_entry *dent; 846 847 itr->name = NULL; 848 849 while (1) { 850 dent = next_dent(itr); 851 if (!dent) 852 return 0; 853 854 if (dent->name[0] == DELETED_FLAG || 855 dent->name[0] == aRING) 856 continue; 857 858 if (dent->attr & ATTR_VOLUME) { 859 if (vfat_enabled && 860 (dent->attr & ATTR_VFAT) == ATTR_VFAT && 861 (dent->name[0] & LAST_LONG_ENTRY_MASK)) { 862 dent = extract_vfat_name(itr); 863 if (!dent) 864 continue; 865 itr->name = itr->l_name; 866 break; 867 } else { 868 /* Volume label or VFAT entry, skip */ 869 continue; 870 } 871 } 872 873 break; 874 } 875 876 get_name(dent, itr->s_name); 877 if (!itr->name) 878 itr->name = itr->s_name; 879 880 return 1; 881 } 882 883 /** 884 * fat_itr_isdir() - is current cursor position pointing to a directory 885 * 886 * @itr: the iterator 887 * @return true if cursor is at a directory 888 */ 889 static int fat_itr_isdir(fat_itr *itr) 890 { 891 return !!(itr->dent->attr & ATTR_DIR); 892 } 893 894 /* 895 * Helpers: 896 */ 897 898 #define TYPE_FILE 0x1 899 #define TYPE_DIR 0x2 900 #define TYPE_ANY (TYPE_FILE | TYPE_DIR) 901 902 /** 903 * fat_itr_resolve() - traverse directory structure to resolve the 904 * requested path. 905 * 906 * Traverse directory structure to the requested path. If the specified 907 * path is to a directory, this will descend into the directory and 908 * leave it iterator at the start of the directory. If the path is to a 909 * file, it will leave the iterator in the parent directory with current 910 * cursor at file's entry in the directory. 911 * 912 * @itr: iterator initialized to root 913 * @path: the requested path 914 * @type: bitmask of allowable file types 915 * @return 0 on success or -errno 916 */ 917 static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) 918 { 919 const char *next; 920 921 /* chomp any extra leading slashes: */ 922 while (path[0] && ISDIRDELIM(path[0])) 923 path++; 924 925 /* are we at the end? */ 926 if (strlen(path) == 0) { 927 if (!(type & TYPE_DIR)) 928 return -ENOENT; 929 return 0; 930 } 931 932 /* find length of next path entry: */ 933 next = path; 934 while (next[0] && !ISDIRDELIM(next[0])) 935 next++; 936 937 while (fat_itr_next(itr)) { 938 int match = 0; 939 unsigned n = max(strlen(itr->name), (size_t)(next - path)); 940 941 /* check both long and short name: */ 942 if (!strncasecmp(path, itr->name, n)) 943 match = 1; 944 else if (itr->name != itr->s_name && 945 !strncasecmp(path, itr->s_name, n)) 946 match = 1; 947 948 if (!match) 949 continue; 950 951 if (fat_itr_isdir(itr)) { 952 /* recurse into directory: */ 953 fat_itr_child(itr, itr); 954 return fat_itr_resolve(itr, next, type); 955 } else if (next[0]) { 956 /* 957 * If next is not empty then we have a case 958 * like: /path/to/realfile/nonsense 959 */ 960 debug("bad trailing path: %s\n", next); 961 return -ENOENT; 962 } else if (!(type & TYPE_FILE)) { 963 return -ENOTDIR; 964 } else { 965 return 0; 966 } 967 } 968 969 return -ENOENT; 970 } 971 972 int file_fat_detectfs(void) 973 { 974 boot_sector bs; 975 volume_info volinfo; 976 int fatsize; 977 char vol_label[12]; 978 979 if (cur_dev == NULL) { 980 printf("No current device\n"); 981 return 1; 982 } 983 984 #if defined(CONFIG_IDE) || \ 985 defined(CONFIG_SATA) || \ 986 defined(CONFIG_SCSI) || \ 987 defined(CONFIG_CMD_USB) || \ 988 defined(CONFIG_MMC) 989 printf("Interface: "); 990 switch (cur_dev->if_type) { 991 case IF_TYPE_IDE: 992 printf("IDE"); 993 break; 994 case IF_TYPE_SATA: 995 printf("SATA"); 996 break; 997 case IF_TYPE_SCSI: 998 printf("SCSI"); 999 break; 1000 case IF_TYPE_ATAPI: 1001 printf("ATAPI"); 1002 break; 1003 case IF_TYPE_USB: 1004 printf("USB"); 1005 break; 1006 case IF_TYPE_DOC: 1007 printf("DOC"); 1008 break; 1009 case IF_TYPE_MMC: 1010 printf("MMC"); 1011 break; 1012 default: 1013 printf("Unknown"); 1014 } 1015 1016 printf("\n Device %d: ", cur_dev->devnum); 1017 dev_print(cur_dev); 1018 #endif 1019 1020 if (read_bootsectandvi(&bs, &volinfo, &fatsize)) { 1021 printf("\nNo valid FAT fs found\n"); 1022 return 1; 1023 } 1024 1025 memcpy(vol_label, volinfo.volume_label, 11); 1026 vol_label[11] = '\0'; 1027 volinfo.fs_type[5] = '\0'; 1028 1029 printf("Filesystem: %s \"%s\"\n", volinfo.fs_type, vol_label); 1030 1031 return 0; 1032 } 1033 1034 int fat_exists(const char *filename) 1035 { 1036 fsdata fsdata; 1037 fat_itr *itr; 1038 int ret; 1039 1040 itr = malloc(sizeof(fat_itr)); 1041 ret = fat_itr_root(itr, &fsdata); 1042 if (ret) 1043 return 0; 1044 1045 ret = fat_itr_resolve(itr, filename, TYPE_ANY); 1046 free(fsdata.fatbuf); 1047 free(itr); 1048 return ret == 0; 1049 } 1050 1051 int fat_size(const char *filename, loff_t *size) 1052 { 1053 fsdata fsdata; 1054 fat_itr *itr; 1055 int ret; 1056 1057 itr = malloc(sizeof(fat_itr)); 1058 ret = fat_itr_root(itr, &fsdata); 1059 if (ret) 1060 return ret; 1061 1062 ret = fat_itr_resolve(itr, filename, TYPE_FILE); 1063 if (ret) { 1064 /* 1065 * Directories don't have size, but fs_size() is not 1066 * expected to fail if passed a directory path: 1067 */ 1068 free(fsdata.fatbuf); 1069 fat_itr_root(itr, &fsdata); 1070 if (!fat_itr_resolve(itr, filename, TYPE_DIR)) { 1071 *size = 0; 1072 ret = 0; 1073 } 1074 goto out; 1075 } 1076 1077 *size = FAT2CPU32(itr->dent->size); 1078 free(fsdata.fatbuf); 1079 out: 1080 free(itr); 1081 return ret; 1082 } 1083 1084 int file_fat_read_at(const char *filename, loff_t pos, void *buffer, 1085 loff_t maxsize, loff_t *actread) 1086 { 1087 fsdata fsdata; 1088 fat_itr *itr; 1089 int ret; 1090 1091 itr = malloc(sizeof(fat_itr)); 1092 ret = fat_itr_root(itr, &fsdata); 1093 if (ret) 1094 return ret; 1095 1096 ret = fat_itr_resolve(itr, filename, TYPE_FILE); 1097 if (ret) 1098 goto out; 1099 1100 printf("reading %s\n", filename); 1101 ret = get_contents(&fsdata, itr->dent, pos, buffer, maxsize, actread); 1102 1103 out: 1104 free(fsdata.fatbuf); 1105 free(itr); 1106 return ret; 1107 } 1108 1109 int file_fat_read(const char *filename, void *buffer, int maxsize) 1110 { 1111 loff_t actread; 1112 int ret; 1113 1114 ret = file_fat_read_at(filename, 0, buffer, maxsize, &actread); 1115 if (ret) 1116 return ret; 1117 else 1118 return actread; 1119 } 1120 1121 int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, 1122 loff_t *actread) 1123 { 1124 int ret; 1125 1126 ret = file_fat_read_at(filename, offset, buf, len, actread); 1127 if (ret) 1128 printf("** Unable to read file %s **\n", filename); 1129 1130 return ret; 1131 } 1132 1133 typedef struct { 1134 struct fs_dir_stream parent; 1135 struct fs_dirent dirent; 1136 fsdata fsdata; 1137 fat_itr itr; 1138 } fat_dir; 1139 1140 int fat_opendir(const char *filename, struct fs_dir_stream **dirsp) 1141 { 1142 fat_dir *dir = calloc(1, sizeof(*dir)); 1143 int ret; 1144 1145 if (!dir) 1146 return -ENOMEM; 1147 1148 ret = fat_itr_root(&dir->itr, &dir->fsdata); 1149 if (ret) 1150 goto fail; 1151 1152 ret = fat_itr_resolve(&dir->itr, filename, TYPE_DIR); 1153 if (ret) 1154 goto fail; 1155 1156 *dirsp = (struct fs_dir_stream *)dir; 1157 return 0; 1158 1159 fail: 1160 free(dir->fsdata.fatbuf); 1161 free(dir); 1162 return ret; 1163 } 1164 1165 int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) 1166 { 1167 fat_dir *dir = (fat_dir *)dirs; 1168 struct fs_dirent *dent = &dir->dirent; 1169 1170 if (!fat_itr_next(&dir->itr)) 1171 return -ENOENT; 1172 1173 memset(dent, 0, sizeof(*dent)); 1174 strcpy(dent->name, dir->itr.name); 1175 1176 if (fat_itr_isdir(&dir->itr)) { 1177 dent->type = FS_DT_DIR; 1178 } else { 1179 dent->type = FS_DT_REG; 1180 dent->size = FAT2CPU32(dir->itr.dent->size); 1181 } 1182 1183 *dentp = dent; 1184 1185 return 0; 1186 } 1187 1188 void fat_closedir(struct fs_dir_stream *dirs) 1189 { 1190 fat_dir *dir = (fat_dir *)dirs; 1191 free(dir->fsdata.fatbuf); 1192 free(dir); 1193 } 1194 1195 void fat_close(void) 1196 { 1197 } 1198