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