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