xref: /rk3399_rockchip-uboot/fs/fat/fat.c (revision a43278a43d522fba7fea0ed3045b718a9c8d22ac)
171f95118Swdenk /*
271f95118Swdenk  * fat.c
371f95118Swdenk  *
471f95118Swdenk  * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg
571f95118Swdenk  *
671f95118Swdenk  * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6
771f95118Swdenk  * 2003-03-10 - kharris@nexus-tech.net - ported to uboot
871f95118Swdenk  *
971f95118Swdenk  * See file CREDITS for list of people who contributed to this
1071f95118Swdenk  * project.
1171f95118Swdenk  *
1271f95118Swdenk  * This program is free software; you can redistribute it and/or
1371f95118Swdenk  * modify it under the terms of the GNU General Public License as
1471f95118Swdenk  * published by the Free Software Foundation; either version 2 of
1571f95118Swdenk  * the License, or (at your option) any later version.
1671f95118Swdenk  *
1771f95118Swdenk  * This program is distributed in the hope that it will be useful,
1871f95118Swdenk  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1971f95118Swdenk  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2071f95118Swdenk  * GNU General Public License for more details.
2171f95118Swdenk  *
2271f95118Swdenk  * You should have received a copy of the GNU General Public License
2371f95118Swdenk  * along with this program; if not, write to the Free Software
2471f95118Swdenk  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
2571f95118Swdenk  * MA 02111-1307 USA
2671f95118Swdenk  */
2771f95118Swdenk 
2871f95118Swdenk #include <common.h>
2971f95118Swdenk #include <config.h>
3071f95118Swdenk #include <fat.h>
3171f95118Swdenk #include <asm/byteorder.h>
327205e407Swdenk #include <part.h>
3371f95118Swdenk 
3471f95118Swdenk #if (CONFIG_COMMANDS & CFG_CMD_FAT)
3571f95118Swdenk 
3671f95118Swdenk /*
3771f95118Swdenk  * Convert a string to lowercase.
3871f95118Swdenk  */
3971f95118Swdenk static void
4071f95118Swdenk downcase(char *str)
4171f95118Swdenk {
4271f95118Swdenk 	while (*str != '\0') {
4371f95118Swdenk 		TOLOWER(*str);
4471f95118Swdenk 		str++;
4571f95118Swdenk 	}
4671f95118Swdenk }
4771f95118Swdenk 
487205e407Swdenk static  block_dev_desc_t *cur_dev = NULL;
497205e407Swdenk static unsigned long part_offset = 0;
507205e407Swdenk static int cur_part = 1;
517205e407Swdenk 
527205e407Swdenk #define DOS_PART_TBL_OFFSET	0x1be
537205e407Swdenk #define DOS_PART_MAGIC_OFFSET	0x1fe
547205e407Swdenk #define DOS_FS_TYPE_OFFSET	0x36
5571f95118Swdenk 
5671f95118Swdenk int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr)
5771f95118Swdenk {
587205e407Swdenk 	startblock += part_offset;
597205e407Swdenk 	if (cur_dev == NULL)
607205e407Swdenk 		return -1;
617205e407Swdenk 	if (cur_dev->block_read) {
627205e407Swdenk 		return cur_dev->block_read (cur_dev->dev, startblock, getsize, (unsigned long *)bufptr);
6371f95118Swdenk 	}
6471f95118Swdenk 	return -1;
6571f95118Swdenk }
6671f95118Swdenk 
6771f95118Swdenk 
6871f95118Swdenk int
697205e407Swdenk fat_register_device(block_dev_desc_t *dev_desc, int part_no)
7071f95118Swdenk {
717205e407Swdenk 	unsigned char buffer[SECTOR_SIZE];
727205e407Swdenk 
737205e407Swdenk 	if (!dev_desc->block_read)
747205e407Swdenk 		return -1;
757205e407Swdenk 	cur_dev=dev_desc;
767205e407Swdenk 	/* check if we have a MBR (on floppies we have only a PBR) */
777205e407Swdenk 	if (dev_desc->block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1) {
787205e407Swdenk 		printf ("** Can't read from device %d **\n", dev_desc->dev);
797205e407Swdenk 		return -1;
807205e407Swdenk 	}
817205e407Swdenk 	if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
827205e407Swdenk 		buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
837205e407Swdenk 		/* no signature found */
847205e407Swdenk 		return -1;
857205e407Swdenk 	}
867205e407Swdenk 	if(!strncmp(&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) {
877205e407Swdenk 		/* ok, we assume we are on a PBR only */
887205e407Swdenk 		cur_part = 1;
897205e407Swdenk 		part_offset=0;
907205e407Swdenk 	}
917205e407Swdenk 	else {
927205e407Swdenk #if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)
937205e407Swdenk 		disk_partition_t info;
947205e407Swdenk 		if(!get_partition_info(dev_desc, part_no, &info)) {
957205e407Swdenk 			part_offset = info.start;
967205e407Swdenk 			cur_part = part_no;
977205e407Swdenk 		}
987205e407Swdenk 		else {
997205e407Swdenk 			printf ("** Partition %d not valid on device %d **\n",part_no,dev_desc->dev);
1007205e407Swdenk 			return -1;
1017205e407Swdenk 		}
1027205e407Swdenk #else
1037205e407Swdenk 		/* FIXME we need to determine the start block of the
1047205e407Swdenk 		 * partition where the DOS FS resides. This can be done
1057205e407Swdenk 		 * by using the get_partition_info routine. For this
1067205e407Swdenk 		 * purpose the libpart must be included.
1077205e407Swdenk 		 */
1087205e407Swdenk 		part_offset=32;
1097205e407Swdenk 		cur_part = 1;
1107205e407Swdenk #endif
1117205e407Swdenk 	}
11271f95118Swdenk 	return 0;
11371f95118Swdenk }
11471f95118Swdenk 
11571f95118Swdenk 
11671f95118Swdenk /*
11771f95118Swdenk  * Get the first occurence of a directory delimiter ('/' or '\') in a string.
11871f95118Swdenk  * Return index into string if found, -1 otherwise.
11971f95118Swdenk  */
12071f95118Swdenk static int
12171f95118Swdenk dirdelim(char *str)
12271f95118Swdenk {
12371f95118Swdenk 	char *start = str;
12471f95118Swdenk 
12571f95118Swdenk 	while (*str != '\0') {
12671f95118Swdenk 		if (ISDIRDELIM(*str)) return str - start;
12771f95118Swdenk 		str++;
12871f95118Swdenk 	}
12971f95118Swdenk 	return -1;
13071f95118Swdenk }
13171f95118Swdenk 
13271f95118Swdenk 
13371f95118Swdenk /*
13471f95118Swdenk  * Match volume_info fs_type strings.
13571f95118Swdenk  * Return 0 on match, -1 otherwise.
13671f95118Swdenk  */
13771f95118Swdenk static int
13871f95118Swdenk compare_sign(char *str1, char *str2)
13971f95118Swdenk {
14071f95118Swdenk 	char *end = str1+SIGNLEN;
14171f95118Swdenk 
14271f95118Swdenk 	while (str1 != end) {
14371f95118Swdenk 		if (*str1 != *str2) {
14471f95118Swdenk 			return -1;
14571f95118Swdenk 		}
14671f95118Swdenk 		str1++;
14771f95118Swdenk 		str2++;
14871f95118Swdenk 	}
14971f95118Swdenk 
15071f95118Swdenk 	return 0;
15171f95118Swdenk }
15271f95118Swdenk 
15371f95118Swdenk 
15471f95118Swdenk /*
15571f95118Swdenk  * Extract zero terminated short name from a directory entry.
15671f95118Swdenk  */
15771f95118Swdenk static void get_name (dir_entry *dirent, char *s_name)
15871f95118Swdenk {
15971f95118Swdenk 	char *ptr;
16071f95118Swdenk 
16171f95118Swdenk 	memcpy (s_name, dirent->name, 8);
16271f95118Swdenk 	s_name[8] = '\0';
16371f95118Swdenk 	ptr = s_name;
16471f95118Swdenk 	while (*ptr && *ptr != ' ')
16571f95118Swdenk 		ptr++;
16671f95118Swdenk 	if (dirent->ext[0] && dirent->ext[0] != ' ') {
16771f95118Swdenk 		*ptr = '.';
16871f95118Swdenk 		ptr++;
16971f95118Swdenk 		memcpy (ptr, dirent->ext, 3);
17071f95118Swdenk 		ptr[3] = '\0';
17171f95118Swdenk 		while (*ptr && *ptr != ' ')
17271f95118Swdenk 			ptr++;
17371f95118Swdenk 	}
17471f95118Swdenk 	*ptr = '\0';
17571f95118Swdenk 	if (*s_name == DELETED_FLAG)
17671f95118Swdenk 		*s_name = '\0';
17771f95118Swdenk 	else if (*s_name == aRING)
17871f95118Swdenk 		*s_name = '�';
17971f95118Swdenk 	downcase (s_name);
18071f95118Swdenk }
18171f95118Swdenk 
18271f95118Swdenk /*
18371f95118Swdenk  * Get the entry at index 'entry' in a FAT (12/16/32) table.
18471f95118Swdenk  * On failure 0x00 is returned.
18571f95118Swdenk  */
18671f95118Swdenk static __u32
18771f95118Swdenk get_fatent(fsdata *mydata, __u32 entry)
18871f95118Swdenk {
18971f95118Swdenk 	__u32 bufnum;
19071f95118Swdenk 	__u32 offset;
19171f95118Swdenk 	__u32 ret = 0x00;
19271f95118Swdenk 
19371f95118Swdenk 	switch (mydata->fatsize) {
19471f95118Swdenk 	case 32:
19571f95118Swdenk 		bufnum = entry / FAT32BUFSIZE;
19671f95118Swdenk 		offset = entry - bufnum * FAT32BUFSIZE;
19771f95118Swdenk 		break;
19871f95118Swdenk 	case 16:
19971f95118Swdenk 		bufnum = entry / FAT16BUFSIZE;
20071f95118Swdenk 		offset = entry - bufnum * FAT16BUFSIZE;
20171f95118Swdenk 		break;
20271f95118Swdenk 	case 12:
20371f95118Swdenk 		bufnum = entry / FAT12BUFSIZE;
20471f95118Swdenk 		offset = entry - bufnum * FAT12BUFSIZE;
20571f95118Swdenk 		break;
20671f95118Swdenk 
20771f95118Swdenk 	default:
20871f95118Swdenk 		/* Unsupported FAT size */
20971f95118Swdenk 		return ret;
21071f95118Swdenk 	}
21171f95118Swdenk 
21271f95118Swdenk 	/* Read a new block of FAT entries into the cache. */
21371f95118Swdenk 	if (bufnum != mydata->fatbufnum) {
21471f95118Swdenk 		int getsize = FATBUFSIZE/FS_BLOCK_SIZE;
21571f95118Swdenk 		__u8 *bufptr = mydata->fatbuf;
21671f95118Swdenk 		__u32 fatlength = mydata->fatlength;
21771f95118Swdenk 		__u32 startblock = bufnum * FATBUFBLOCKS;
21871f95118Swdenk 
21971f95118Swdenk 		fatlength *= SECTOR_SIZE;	/* We want it in bytes now */
22071f95118Swdenk 		startblock += mydata->fat_sect;	/* Offset from start of disk */
22171f95118Swdenk 
22271f95118Swdenk 		if (getsize > fatlength) getsize = fatlength;
22371f95118Swdenk 		if (disk_read(startblock, getsize, bufptr) < 0) {
22471f95118Swdenk 			FAT_DPRINT("Error reading FAT blocks\n");
22571f95118Swdenk 			return ret;
22671f95118Swdenk 		}
22771f95118Swdenk 		mydata->fatbufnum = bufnum;
22871f95118Swdenk 	}
22971f95118Swdenk 
23071f95118Swdenk 	/* Get the actual entry from the table */
23171f95118Swdenk 	switch (mydata->fatsize) {
23271f95118Swdenk 	case 32:
23371f95118Swdenk 		ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]);
23471f95118Swdenk 		break;
23571f95118Swdenk 	case 16:
23671f95118Swdenk 		ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]);
23771f95118Swdenk 		break;
23871f95118Swdenk 	case 12: {
23971f95118Swdenk 		__u32 off16 = (offset*3)/4;
24071f95118Swdenk 		__u16 val1, val2;
24171f95118Swdenk 
24271f95118Swdenk 		switch (offset & 0x3) {
24371f95118Swdenk 		case 0:
24471f95118Swdenk 			ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
24571f95118Swdenk 			ret &= 0xfff;
24671f95118Swdenk 			break;
24771f95118Swdenk 		case 1:
24871f95118Swdenk 			val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
24971f95118Swdenk 			val1 &= 0xf000;
25071f95118Swdenk 			val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]);
25171f95118Swdenk 			val2 &= 0x00ff;
25271f95118Swdenk 			ret = (val2 << 4) | (val1 >> 12);
25371f95118Swdenk 			break;
25471f95118Swdenk 		case 2:
25571f95118Swdenk 			val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);
25671f95118Swdenk 			val1 &= 0xff00;
25771f95118Swdenk 			val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]);
25871f95118Swdenk 			val2 &= 0x000f;
25971f95118Swdenk 			ret = (val2 << 8) | (val1 >> 8);
26071f95118Swdenk 			break;
26171f95118Swdenk 		case 3:
26271f95118Swdenk 			ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);;
26371f95118Swdenk 			ret = (ret & 0xfff0) >> 4;
26471f95118Swdenk 			break;
26571f95118Swdenk 		default:
26671f95118Swdenk 			break;
26771f95118Swdenk 		}
26871f95118Swdenk 	}
26971f95118Swdenk 	break;
27071f95118Swdenk 	}
27171f95118Swdenk 	FAT_DPRINT("ret: %d, offset: %d\n", ret, offset);
27271f95118Swdenk 
27371f95118Swdenk 	return ret;
27471f95118Swdenk }
27571f95118Swdenk 
27671f95118Swdenk 
27771f95118Swdenk /*
27871f95118Swdenk  * Read at most 'size' bytes from the specified cluster into 'buffer'.
27971f95118Swdenk  * Return 0 on success, -1 otherwise.
28071f95118Swdenk  */
28171f95118Swdenk static int
28271f95118Swdenk get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
28371f95118Swdenk {
28471f95118Swdenk 	int idx = 0;
28571f95118Swdenk 	__u32 startsect;
28671f95118Swdenk 
28771f95118Swdenk 	if (clustnum > 0) {
28871f95118Swdenk 		startsect = mydata->data_begin + clustnum*mydata->clust_size;
28971f95118Swdenk 	} else {
29071f95118Swdenk 		startsect = mydata->rootdir_sect;
29171f95118Swdenk 	}
29271f95118Swdenk 
29371f95118Swdenk 	FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect);
2947205e407Swdenk 	if (disk_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0) {
29571f95118Swdenk 		FAT_DPRINT("Error reading data\n");
29671f95118Swdenk 		return -1;
29771f95118Swdenk 	}
2987205e407Swdenk 	if(size % FS_BLOCK_SIZE) {
29971f95118Swdenk 		__u8 tmpbuf[FS_BLOCK_SIZE];
3007205e407Swdenk 		idx= size/FS_BLOCK_SIZE;
30171f95118Swdenk 		if (disk_read(startsect + idx, 1, tmpbuf) < 0) {
30271f95118Swdenk 			FAT_DPRINT("Error reading data\n");
30371f95118Swdenk 			return -1;
30471f95118Swdenk 		}
3057205e407Swdenk 		buffer += idx*FS_BLOCK_SIZE;
30671f95118Swdenk 
3077205e407Swdenk 		memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE);
30871f95118Swdenk 		return 0;
30971f95118Swdenk 	}
31071f95118Swdenk 
31171f95118Swdenk 	return 0;
31271f95118Swdenk }
31371f95118Swdenk 
31471f95118Swdenk 
31571f95118Swdenk /*
31671f95118Swdenk  * Read at most 'maxsize' bytes from the file associated with 'dentptr'
31771f95118Swdenk  * into 'buffer'.
31871f95118Swdenk  * Return the number of bytes read or -1 on fatal errors.
31971f95118Swdenk  */
32071f95118Swdenk static long
32171f95118Swdenk get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
32271f95118Swdenk 	     unsigned long maxsize)
32371f95118Swdenk {
32471f95118Swdenk 	unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
32571f95118Swdenk 	unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE;
32671f95118Swdenk 	__u32 curclust = START(dentptr);
3277205e407Swdenk 	__u32 endclust, newclust;
3287205e407Swdenk 	unsigned long actsize;
32971f95118Swdenk 
33071f95118Swdenk 	FAT_DPRINT("Filesize: %ld bytes\n", filesize);
33171f95118Swdenk 
33271f95118Swdenk 	if (maxsize > 0 && filesize > maxsize) filesize = maxsize;
33371f95118Swdenk 
33471f95118Swdenk 	FAT_DPRINT("Reading: %ld bytes\n", filesize);
33571f95118Swdenk 
3367205e407Swdenk 	actsize=bytesperclust;
3377205e407Swdenk 	endclust=curclust;
33871f95118Swdenk 	do {
3397205e407Swdenk 		/* search for consecutive clusters */
3407205e407Swdenk 		while(actsize < filesize) {
3417205e407Swdenk 			newclust = get_fatent(mydata, endclust);
3427205e407Swdenk 			if((newclust -1)!=endclust)
3437205e407Swdenk 				goto getit;
3447205e407Swdenk 			if (newclust <= 0x0001 || newclust >= 0xfff0) {
3457205e407Swdenk 				FAT_DPRINT("curclust: 0x%x\n", newclust);
3467205e407Swdenk 				FAT_DPRINT("Invalid FAT entry\n");
3477205e407Swdenk 				return gotsize;
3487205e407Swdenk 			}
3497205e407Swdenk 			endclust=newclust;
3507205e407Swdenk 			actsize+= bytesperclust;
3517205e407Swdenk 		}
3527205e407Swdenk 		/* actsize >= file size */
3537205e407Swdenk 		actsize -= bytesperclust;
3547205e407Swdenk 		/* get remaining clusters */
3557205e407Swdenk 		if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
35671f95118Swdenk 			FAT_ERROR("Error reading cluster\n");
35771f95118Swdenk 			return -1;
35871f95118Swdenk 		}
3597205e407Swdenk 		/* get remaining bytes */
3607205e407Swdenk 		gotsize += (int)actsize;
3617205e407Swdenk 		filesize -= actsize;
3627205e407Swdenk 		buffer += actsize;
3637205e407Swdenk 		actsize= filesize;
3647205e407Swdenk 		if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
3657205e407Swdenk 			FAT_ERROR("Error reading cluster\n");
3667205e407Swdenk 			return -1;
3677205e407Swdenk 		}
3687205e407Swdenk 		gotsize+=actsize;
3697205e407Swdenk 		return gotsize;
3707205e407Swdenk getit:
3717205e407Swdenk 		if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
3727205e407Swdenk 			FAT_ERROR("Error reading cluster\n");
3737205e407Swdenk 			return -1;
3747205e407Swdenk 		}
3757205e407Swdenk 		gotsize += (int)actsize;
3767205e407Swdenk 		filesize -= actsize;
3777205e407Swdenk 		buffer += actsize;
3787205e407Swdenk 		curclust = get_fatent(mydata, endclust);
37971f95118Swdenk 		if (curclust <= 0x0001 || curclust >= 0xfff0) {
38071f95118Swdenk 			FAT_DPRINT("curclust: 0x%x\n", curclust);
38171f95118Swdenk 			FAT_ERROR("Invalid FAT entry\n");
38271f95118Swdenk 			return gotsize;
38371f95118Swdenk 		}
3847205e407Swdenk 		actsize=bytesperclust;
3857205e407Swdenk 		endclust=curclust;
38671f95118Swdenk 	} while (1);
38771f95118Swdenk }
38871f95118Swdenk 
38971f95118Swdenk 
39071f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT
39171f95118Swdenk /*
39271f95118Swdenk  * Extract the file name information from 'slotptr' into 'l_name',
39371f95118Swdenk  * starting at l_name[*idx].
39471f95118Swdenk  * Return 1 if terminator (zero byte) is found, 0 otherwise.
39571f95118Swdenk  */
39671f95118Swdenk static int
39771f95118Swdenk slot2str(dir_slot *slotptr, char *l_name, int *idx)
39871f95118Swdenk {
39971f95118Swdenk 	int j;
40071f95118Swdenk 
40171f95118Swdenk 	for (j = 0; j <= 8; j += 2) {
40271f95118Swdenk 		l_name[*idx] = slotptr->name0_4[j];
40371f95118Swdenk 		if (l_name[*idx] == 0x00) return 1;
40471f95118Swdenk 		(*idx)++;
40571f95118Swdenk 	}
40671f95118Swdenk 	for (j = 0; j <= 10; j += 2) {
40771f95118Swdenk 		l_name[*idx] = slotptr->name5_10[j];
40871f95118Swdenk 		if (l_name[*idx] == 0x00) return 1;
40971f95118Swdenk 		(*idx)++;
41071f95118Swdenk 	}
41171f95118Swdenk 	for (j = 0; j <= 2; j += 2) {
41271f95118Swdenk 		l_name[*idx] = slotptr->name11_12[j];
41371f95118Swdenk 		if (l_name[*idx] == 0x00) return 1;
41471f95118Swdenk 		(*idx)++;
41571f95118Swdenk 	}
41671f95118Swdenk 
41771f95118Swdenk 	return 0;
41871f95118Swdenk }
41971f95118Swdenk 
42071f95118Swdenk 
42171f95118Swdenk /*
42271f95118Swdenk  * Extract the full long filename starting at 'retdent' (which is really
42371f95118Swdenk  * a slot) into 'l_name'. If successful also copy the real directory entry
42471f95118Swdenk  * into 'retdent'
42571f95118Swdenk  * Return 0 on success, -1 otherwise.
42671f95118Swdenk  */
42771f95118Swdenk static int
42871f95118Swdenk get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
42971f95118Swdenk 	     dir_entry *retdent, char *l_name)
43071f95118Swdenk {
43171f95118Swdenk 	dir_entry *realdent;
43271f95118Swdenk 	dir_slot  *slotptr = (dir_slot*) retdent;
43371f95118Swdenk 	__u8	  *nextclust = cluster + mydata->clust_size * SECTOR_SIZE;
43471f95118Swdenk 	__u8	   counter = slotptr->id & 0xf;
43571f95118Swdenk 	int idx = 0;
43671f95118Swdenk 
43771f95118Swdenk 	while ((__u8*)slotptr < nextclust) {
43871f95118Swdenk 		if (counter == 0) break;
43971f95118Swdenk 		if ((slotptr->id & 0x0f) != counter) return -1;
44071f95118Swdenk 		slotptr++;
44171f95118Swdenk 		counter--;
44271f95118Swdenk 	}
44371f95118Swdenk 
44471f95118Swdenk 	if ((__u8*)slotptr >= nextclust) {
44571f95118Swdenk 		__u8	 block[MAX_CLUSTSIZE];
44671f95118Swdenk 		dir_slot *slotptr2;
44771f95118Swdenk 
44871f95118Swdenk 		slotptr--;
44971f95118Swdenk 		curclust = get_fatent(mydata, curclust);
45071f95118Swdenk 		if (curclust <= 0x0001 || curclust >= 0xfff0) {
45171f95118Swdenk 			FAT_DPRINT("curclust: 0x%x\n", curclust);
45271f95118Swdenk 			FAT_ERROR("Invalid FAT entry\n");
45371f95118Swdenk 			return -1;
45471f95118Swdenk 		}
45571f95118Swdenk 		if (get_cluster(mydata, curclust, block,
45671f95118Swdenk 				mydata->clust_size * SECTOR_SIZE) != 0) {
45771f95118Swdenk 			FAT_DPRINT("Error: reading directory block\n");
45871f95118Swdenk 			return -1;
45971f95118Swdenk 		}
46071f95118Swdenk 		slotptr2 = (dir_slot*) block;
46171f95118Swdenk 		while (slotptr2->id > 0x01) {
46271f95118Swdenk 			slotptr2++;
46371f95118Swdenk 		}
46471f95118Swdenk 		/* Save the real directory entry */
46571f95118Swdenk 		realdent = (dir_entry*)slotptr2 + 1;
46671f95118Swdenk 		while ((__u8*)slotptr2 >= block) {
46771f95118Swdenk 			slot2str(slotptr2, l_name, &idx);
46871f95118Swdenk 			slotptr2--;
46971f95118Swdenk 		}
47071f95118Swdenk 	} else {
47171f95118Swdenk 		/* Save the real directory entry */
47271f95118Swdenk 		realdent = (dir_entry*)slotptr;
47371f95118Swdenk 	}
47471f95118Swdenk 
47571f95118Swdenk 	do {
47671f95118Swdenk 		slotptr--;
47771f95118Swdenk 		if (slot2str(slotptr, l_name, &idx)) break;
47871f95118Swdenk 	} while (!(slotptr->id & 0x40));
47971f95118Swdenk 
48071f95118Swdenk 	l_name[idx] = '\0';
48171f95118Swdenk 	if (*l_name == DELETED_FLAG) *l_name = '\0';
48271f95118Swdenk 	else if (*l_name == aRING) *l_name = '�';
48371f95118Swdenk 	downcase(l_name);
48471f95118Swdenk 
48571f95118Swdenk 	/* Return the real directory entry */
48671f95118Swdenk 	memcpy(retdent, realdent, sizeof(dir_entry));
48771f95118Swdenk 
48871f95118Swdenk 	return 0;
48971f95118Swdenk }
49071f95118Swdenk 
49171f95118Swdenk 
49271f95118Swdenk /* Calculate short name checksum */
49371f95118Swdenk static __u8
49471f95118Swdenk mkcksum(const char *str)
49571f95118Swdenk {
49671f95118Swdenk 	int i;
49771f95118Swdenk 	__u8 ret = 0;
49871f95118Swdenk 
49971f95118Swdenk 	for (i = 0; i < 11; i++) {
50071f95118Swdenk 		ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i];
50171f95118Swdenk 	}
50271f95118Swdenk 
50371f95118Swdenk 	return ret;
50471f95118Swdenk }
50571f95118Swdenk #endif
50671f95118Swdenk 
50771f95118Swdenk 
50871f95118Swdenk /*
50971f95118Swdenk  * Get the directory entry associated with 'filename' from the directory
51071f95118Swdenk  * starting at 'startsect'
51171f95118Swdenk  */
51271f95118Swdenk static dir_entry *get_dentfromdir (fsdata * mydata, int startsect,
51371f95118Swdenk 				   char *filename, dir_entry * retdent,
51471f95118Swdenk 				   int dols)
51571f95118Swdenk {
51671f95118Swdenk     __u16 prevcksum = 0xffff;
51771f95118Swdenk     __u8 block[MAX_CLUSTSIZE];
51871f95118Swdenk     __u32 curclust = START (retdent);
51971f95118Swdenk     int files = 0, dirs = 0;
52071f95118Swdenk 
52171f95118Swdenk     FAT_DPRINT ("get_dentfromdir: %s\n", filename);
52271f95118Swdenk     while (1) {
52371f95118Swdenk 	dir_entry *dentptr;
52471f95118Swdenk 	int i;
52571f95118Swdenk 
52671f95118Swdenk 	if (get_cluster (mydata, curclust, block,
52771f95118Swdenk 		 mydata->clust_size * SECTOR_SIZE) != 0) {
52871f95118Swdenk 	    FAT_DPRINT ("Error: reading directory block\n");
52971f95118Swdenk 	    return NULL;
53071f95118Swdenk 	}
53171f95118Swdenk 	dentptr = (dir_entry *) block;
53271f95118Swdenk 	for (i = 0; i < DIRENTSPERCLUST; i++) {
53371f95118Swdenk 	    char s_name[14], l_name[256];
53471f95118Swdenk 
53571f95118Swdenk 	    l_name[0] = '\0';
53671f95118Swdenk 	    if ((dentptr->attr & ATTR_VOLUME)) {
53771f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT
53871f95118Swdenk 		if ((dentptr->attr & ATTR_VFAT) &&
53971f95118Swdenk 		    (dentptr->name[0] & 0x40)) {
54071f95118Swdenk 		    prevcksum = ((dir_slot *) dentptr)
54171f95118Swdenk 			    ->alias_checksum;
54271f95118Swdenk 		    get_vfatname (mydata, curclust, block,
54371f95118Swdenk 				  dentptr, l_name);
54471f95118Swdenk 		    if (dols) {
54571f95118Swdenk 			int isdir = (dentptr->attr & ATTR_DIR);
54671f95118Swdenk 			char dirc;
54771f95118Swdenk 			int doit = 0;
54871f95118Swdenk 
54971f95118Swdenk 			if (isdir) {
55071f95118Swdenk 			    dirs++;
55171f95118Swdenk 			    dirc = '/';
55271f95118Swdenk 			    doit = 1;
55371f95118Swdenk 			} else {
55471f95118Swdenk 			    dirc = ' ';
55571f95118Swdenk 			    if (l_name[0] != 0) {
55671f95118Swdenk 				files++;
55771f95118Swdenk 				doit = 1;
55871f95118Swdenk 			    }
55971f95118Swdenk 			}
56071f95118Swdenk 			if (doit) {
56171f95118Swdenk 			    if (dirc == ' ') {
56271f95118Swdenk 				printf (" %8ld   %s%c\n",
56371f95118Swdenk 					(long) FAT2CPU32 (dentptr->size),
56471f95118Swdenk 					l_name, dirc);
56571f95118Swdenk 			    } else {
56671f95118Swdenk 				printf ("            %s%c\n", l_name, dirc);
56771f95118Swdenk 			    }
56871f95118Swdenk 			}
56971f95118Swdenk 			dentptr++;
57071f95118Swdenk 			continue;
57171f95118Swdenk 		    }
57271f95118Swdenk 		    FAT_DPRINT ("vfatname: |%s|\n", l_name);
57371f95118Swdenk 		} else
57471f95118Swdenk #endif
57571f95118Swdenk 		{
57671f95118Swdenk 		    /* Volume label or VFAT entry */
57771f95118Swdenk 		    dentptr++;
57871f95118Swdenk 		    continue;
57971f95118Swdenk 		}
58071f95118Swdenk 	    }
58171f95118Swdenk 	    if (dentptr->name[0] == 0) {
58271f95118Swdenk 		if (dols) {
58371f95118Swdenk 		    printf ("\n%d file(s), %d dir(s)\n\n", files, dirs);
58471f95118Swdenk 		}
58571f95118Swdenk 		FAT_DPRINT ("Dentname == NULL - %d\n", i);
58671f95118Swdenk 		return NULL;
58771f95118Swdenk 	    }
58871f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT
58971f95118Swdenk 	    if (dols && mkcksum (dentptr->name) == prevcksum) {
59071f95118Swdenk 		dentptr++;
59171f95118Swdenk 		continue;
59271f95118Swdenk 	    }
59371f95118Swdenk #endif
59471f95118Swdenk 	    get_name (dentptr, s_name);
59571f95118Swdenk 	    if (dols) {
59671f95118Swdenk 		int isdir = (dentptr->attr & ATTR_DIR);
59771f95118Swdenk 		char dirc;
59871f95118Swdenk 		int doit = 0;
59971f95118Swdenk 
60071f95118Swdenk 		if (isdir) {
60171f95118Swdenk 		    dirs++;
60271f95118Swdenk 		    dirc = '/';
60371f95118Swdenk 		    doit = 1;
60471f95118Swdenk 		} else {
60571f95118Swdenk 		    dirc = ' ';
60671f95118Swdenk 		    if (s_name[0] != 0) {
60771f95118Swdenk 			files++;
60871f95118Swdenk 			doit = 1;
60971f95118Swdenk 		    }
61071f95118Swdenk 		}
61171f95118Swdenk 		if (doit) {
61271f95118Swdenk 		    if (dirc == ' ') {
61371f95118Swdenk 			printf (" %8ld   %s%c\n",
61471f95118Swdenk 				(long) FAT2CPU32 (dentptr->size), s_name,
61571f95118Swdenk 				dirc);
61671f95118Swdenk 		    } else {
61771f95118Swdenk 			printf ("            %s%c\n", s_name, dirc);
61871f95118Swdenk 		    }
61971f95118Swdenk 		}
62071f95118Swdenk 		dentptr++;
62171f95118Swdenk 		continue;
62271f95118Swdenk 	    }
62371f95118Swdenk 	    if (strcmp (filename, s_name) && strcmp (filename, l_name)) {
62471f95118Swdenk 		FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name);
62571f95118Swdenk 		dentptr++;
62671f95118Swdenk 		continue;
62771f95118Swdenk 	    }
62871f95118Swdenk 	    memcpy (retdent, dentptr, sizeof (dir_entry));
62971f95118Swdenk 
63071f95118Swdenk 	    FAT_DPRINT ("DentName: %s", s_name);
63171f95118Swdenk 	    FAT_DPRINT (", start: 0x%x", START (dentptr));
63271f95118Swdenk 	    FAT_DPRINT (", size:  0x%x %s\n",
63371f95118Swdenk 			FAT2CPU32 (dentptr->size),
63471f95118Swdenk 			(dentptr->attr & ATTR_DIR) ? "(DIR)" : "");
63571f95118Swdenk 
63671f95118Swdenk 	    return retdent;
63771f95118Swdenk 	}
63871f95118Swdenk 	curclust = get_fatent (mydata, curclust);
63971f95118Swdenk 	if (curclust <= 0x0001 || curclust >= 0xfff0) {
64071f95118Swdenk 	    FAT_DPRINT ("curclust: 0x%x\n", curclust);
64171f95118Swdenk 	    FAT_ERROR ("Invalid FAT entry\n");
64271f95118Swdenk 	    return NULL;
64371f95118Swdenk 	}
64471f95118Swdenk     }
64571f95118Swdenk 
64671f95118Swdenk     return NULL;
64771f95118Swdenk }
64871f95118Swdenk 
64971f95118Swdenk 
65071f95118Swdenk /*
65171f95118Swdenk  * Read boot sector and volume info from a FAT filesystem
65271f95118Swdenk  */
65371f95118Swdenk static int
65471f95118Swdenk read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize)
65571f95118Swdenk {
65671f95118Swdenk 	__u8 block[FS_BLOCK_SIZE];
65771f95118Swdenk 	volume_info *vistart;
65871f95118Swdenk 
65971f95118Swdenk 	if (disk_read(0, 1, block) < 0) {
66071f95118Swdenk 		FAT_DPRINT("Error: reading block\n");
66171f95118Swdenk 		return -1;
66271f95118Swdenk 	}
66371f95118Swdenk 
66471f95118Swdenk 	memcpy(bs, block, sizeof(boot_sector));
66571f95118Swdenk 	bs->reserved	= FAT2CPU16(bs->reserved);
66671f95118Swdenk 	bs->fat_length	= FAT2CPU16(bs->fat_length);
66771f95118Swdenk 	bs->secs_track	= FAT2CPU16(bs->secs_track);
66871f95118Swdenk 	bs->heads	= FAT2CPU16(bs->heads);
66971f95118Swdenk #if 0 /* UNUSED */
67071f95118Swdenk 	bs->hidden	= FAT2CPU32(bs->hidden);
67171f95118Swdenk #endif
67271f95118Swdenk 	bs->total_sect	= FAT2CPU32(bs->total_sect);
67371f95118Swdenk 
67471f95118Swdenk 	/* FAT32 entries */
67571f95118Swdenk 	if (bs->fat_length == 0) {
67671f95118Swdenk 		/* Assume FAT32 */
67771f95118Swdenk 		bs->fat32_length = FAT2CPU32(bs->fat32_length);
67871f95118Swdenk 		bs->flags	 = FAT2CPU16(bs->flags);
67971f95118Swdenk 		bs->root_cluster = FAT2CPU32(bs->root_cluster);
68071f95118Swdenk 		bs->info_sector  = FAT2CPU16(bs->info_sector);
68171f95118Swdenk 		bs->backup_boot  = FAT2CPU16(bs->backup_boot);
68271f95118Swdenk 		vistart = (volume_info*) (block + sizeof(boot_sector));
68371f95118Swdenk 		*fatsize = 32;
68471f95118Swdenk 	} else {
68571f95118Swdenk 		vistart = (volume_info*) &(bs->fat32_length);
68671f95118Swdenk 		*fatsize = 0;
68771f95118Swdenk 	}
68871f95118Swdenk 	memcpy(volinfo, vistart, sizeof(volume_info));
68971f95118Swdenk 
69071f95118Swdenk 	/* Terminate fs_type string. Writing past the end of vistart
69171f95118Swdenk 	   is ok - it's just the buffer. */
69271f95118Swdenk 	vistart->fs_type[8] = '\0';
69371f95118Swdenk 
69471f95118Swdenk 	if (*fatsize == 32) {
69571f95118Swdenk 		if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) {
69671f95118Swdenk 			return 0;
69771f95118Swdenk 		}
69871f95118Swdenk 	} else {
69971f95118Swdenk 		if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) {
70071f95118Swdenk 			*fatsize = 12;
70171f95118Swdenk 			return 0;
70271f95118Swdenk 		}
70371f95118Swdenk 		if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) {
70471f95118Swdenk 			*fatsize = 16;
70571f95118Swdenk 			return 0;
70671f95118Swdenk 		}
70771f95118Swdenk 	}
70871f95118Swdenk 
70971f95118Swdenk 	FAT_DPRINT("Error: broken fs_type sign\n");
71071f95118Swdenk 	return -1;
71171f95118Swdenk }
71271f95118Swdenk 
71371f95118Swdenk 
71471f95118Swdenk static long
71571f95118Swdenk do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
71671f95118Swdenk 	     int dols)
71771f95118Swdenk {
7187205e407Swdenk     __u8 block[MAX_CLUSTSIZE];  /* Block buffer */
71971f95118Swdenk     char fnamecopy[2048];
72071f95118Swdenk     boot_sector bs;
72171f95118Swdenk     volume_info volinfo;
72271f95118Swdenk     fsdata datablock;
72371f95118Swdenk     fsdata *mydata = &datablock;
72471f95118Swdenk     dir_entry *dentptr;
72571f95118Swdenk     __u16 prevcksum = 0xffff;
72671f95118Swdenk     char *subname = "";
72771f95118Swdenk     int rootdir_size, cursect;
72871f95118Swdenk     int idx, isdir = 0;
72971f95118Swdenk     int files = 0, dirs = 0;
73071f95118Swdenk     long ret = 0;
73171f95118Swdenk     int firsttime;
73271f95118Swdenk 
73371f95118Swdenk     if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) {
73471f95118Swdenk 	FAT_DPRINT ("Error: reading boot sector\n");
73571f95118Swdenk 	return -1;
73671f95118Swdenk     }
73771f95118Swdenk     if (mydata->fatsize == 32) {
73871f95118Swdenk 	mydata->fatlength = bs.fat32_length;
73971f95118Swdenk     } else {
74071f95118Swdenk 	mydata->fatlength = bs.fat_length;
74171f95118Swdenk     }
74271f95118Swdenk     mydata->fat_sect = bs.reserved;
74371f95118Swdenk     cursect = mydata->rootdir_sect
74471f95118Swdenk 	    = mydata->fat_sect + mydata->fatlength * bs.fats;
74571f95118Swdenk     mydata->clust_size = bs.cluster_size;
74671f95118Swdenk     if (mydata->fatsize == 32) {
74771f95118Swdenk 	rootdir_size = mydata->clust_size;
74871f95118Swdenk 	mydata->data_begin = mydata->rootdir_sect   /* + rootdir_size */
74971f95118Swdenk 		- (mydata->clust_size * 2);
75071f95118Swdenk     } else {
75171f95118Swdenk 	rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0])
75271f95118Swdenk 			* sizeof (dir_entry)) / SECTOR_SIZE;
75371f95118Swdenk 	mydata->data_begin = mydata->rootdir_sect + rootdir_size
75471f95118Swdenk 		- (mydata->clust_size * 2);
75571f95118Swdenk     }
75671f95118Swdenk     mydata->fatbufnum = -1;
75771f95118Swdenk 
75871f95118Swdenk     FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize,
75971f95118Swdenk 		mydata->fatlength);
76071f95118Swdenk     FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n"
76171f95118Swdenk 		"Data begins at: %d\n",
76271f95118Swdenk 		mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE,
76371f95118Swdenk 		rootdir_size, mydata->data_begin);
76471f95118Swdenk     FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size);
76571f95118Swdenk 
76671f95118Swdenk     /* "cwd" is always the root... */
76771f95118Swdenk     while (ISDIRDELIM (*filename))
76871f95118Swdenk 	filename++;
76971f95118Swdenk     /* Make a copy of the filename and convert it to lowercase */
77071f95118Swdenk     strcpy (fnamecopy, filename);
77171f95118Swdenk     downcase (fnamecopy);
77271f95118Swdenk     if (*fnamecopy == '\0') {
77371f95118Swdenk 	if (!dols)
77471f95118Swdenk 	    return -1;
77571f95118Swdenk 	dols = LS_ROOT;
77671f95118Swdenk     } else if ((idx = dirdelim (fnamecopy)) >= 0) {
77771f95118Swdenk 	isdir = 1;
77871f95118Swdenk 	fnamecopy[idx] = '\0';
77971f95118Swdenk 	subname = fnamecopy + idx + 1;
78071f95118Swdenk 	/* Handle multiple delimiters */
78171f95118Swdenk 	while (ISDIRDELIM (*subname))
78271f95118Swdenk 	    subname++;
78371f95118Swdenk     } else if (dols) {
78471f95118Swdenk 	isdir = 1;
78571f95118Swdenk     }
78671f95118Swdenk 
78771f95118Swdenk     while (1) {
78871f95118Swdenk 	int i;
78971f95118Swdenk 
7907205e407Swdenk 	if (disk_read (cursect, mydata->clust_size, block) < 0) {
79171f95118Swdenk 	    FAT_DPRINT ("Error: reading rootdir block\n");
79271f95118Swdenk 	    return -1;
79371f95118Swdenk 	}
79471f95118Swdenk 	dentptr = (dir_entry *) block;
79571f95118Swdenk 	for (i = 0; i < DIRENTSPERBLOCK; i++) {
79671f95118Swdenk 	    char s_name[14], l_name[256];
79771f95118Swdenk 
79871f95118Swdenk 	    l_name[0] = '\0';
79971f95118Swdenk 	    if ((dentptr->attr & ATTR_VOLUME)) {
80071f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT
80171f95118Swdenk 		if ((dentptr->attr & ATTR_VFAT) &&
80271f95118Swdenk 		    (dentptr->name[0] & 0x40)) {
80371f95118Swdenk 		    prevcksum = ((dir_slot *) dentptr)->alias_checksum;
80471f95118Swdenk 		    get_vfatname (mydata, 0, block, dentptr, l_name);
80571f95118Swdenk 		    if (dols == LS_ROOT) {
80671f95118Swdenk 			int isdir = (dentptr->attr & ATTR_DIR);
80771f95118Swdenk 			char dirc;
80871f95118Swdenk 			int doit = 0;
80971f95118Swdenk 
81071f95118Swdenk 			if (isdir) {
81171f95118Swdenk 			    dirs++;
81271f95118Swdenk 			    dirc = '/';
81371f95118Swdenk 			    doit = 1;
81471f95118Swdenk 			} else {
81571f95118Swdenk 			    dirc = ' ';
81671f95118Swdenk 			    if (l_name[0] != 0) {
81771f95118Swdenk 				files++;
81871f95118Swdenk 				doit = 1;
81971f95118Swdenk 			    }
82071f95118Swdenk 			}
82171f95118Swdenk 			if (doit) {
82271f95118Swdenk 			    if (dirc == ' ') {
82371f95118Swdenk 				printf (" %8ld   %s%c\n",
82471f95118Swdenk 					(long) FAT2CPU32 (dentptr->size),
82571f95118Swdenk 					l_name, dirc);
82671f95118Swdenk 			    } else {
82771f95118Swdenk 				printf ("            %s%c\n", l_name, dirc);
82871f95118Swdenk 			    }
82971f95118Swdenk 			}
83071f95118Swdenk 			dentptr++;
83171f95118Swdenk 			continue;
83271f95118Swdenk 		    }
83371f95118Swdenk 		    FAT_DPRINT ("Rootvfatname: |%s|\n", l_name);
83471f95118Swdenk 		} else
83571f95118Swdenk #endif
83671f95118Swdenk 		{
83771f95118Swdenk 		    /* Volume label or VFAT entry */
83871f95118Swdenk 		    dentptr++;
83971f95118Swdenk 		    continue;
84071f95118Swdenk 		}
84171f95118Swdenk 	    } else if (dentptr->name[0] == 0) {
84271f95118Swdenk 		FAT_DPRINT ("RootDentname == NULL - %d\n", i);
84371f95118Swdenk 		if (dols == LS_ROOT) {
84471f95118Swdenk 		    printf ("\n%d file(s), %d dir(s)\n\n", files, dirs);
84571f95118Swdenk 		    return 0;
84671f95118Swdenk 		}
84771f95118Swdenk 		return -1;
84871f95118Swdenk 	    }
84971f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT
85071f95118Swdenk 	    else if (dols == LS_ROOT
85171f95118Swdenk 		     && mkcksum (dentptr->name) == prevcksum) {
85271f95118Swdenk 		dentptr++;
85371f95118Swdenk 		continue;
85471f95118Swdenk 	    }
85571f95118Swdenk #endif
85671f95118Swdenk 	    get_name (dentptr, s_name);
85771f95118Swdenk 	    if (dols == LS_ROOT) {
85871f95118Swdenk 		int isdir = (dentptr->attr & ATTR_DIR);
85971f95118Swdenk 		char dirc;
86071f95118Swdenk 		int doit = 0;
86171f95118Swdenk 
86271f95118Swdenk 		if (isdir) {
86371f95118Swdenk 		    dirc = '/';
864*a43278a4Swdenk 		    if (s_name[0] != 0) {
865*a43278a4Swdenk 			dirs++;
86671f95118Swdenk 			doit = 1;
867*a43278a4Swdenk 		    }
86871f95118Swdenk 		} else {
86971f95118Swdenk 		    dirc = ' ';
87071f95118Swdenk 		    if (s_name[0] != 0) {
87171f95118Swdenk 			files++;
87271f95118Swdenk 			doit = 1;
87371f95118Swdenk 		    }
87471f95118Swdenk 		}
87571f95118Swdenk 		if (doit) {
87671f95118Swdenk 		    if (dirc == ' ') {
87771f95118Swdenk 			printf (" %8ld   %s%c\n",
87871f95118Swdenk 				(long) FAT2CPU32 (dentptr->size), s_name,
87971f95118Swdenk 				dirc);
88071f95118Swdenk 		    } else {
88171f95118Swdenk 			printf ("            %s%c\n", s_name, dirc);
88271f95118Swdenk 		    }
88371f95118Swdenk 		}
88471f95118Swdenk 		dentptr++;
88571f95118Swdenk 		continue;
88671f95118Swdenk 	    }
88771f95118Swdenk 	    if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) {
88871f95118Swdenk 		FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name);
88971f95118Swdenk 		dentptr++;
89071f95118Swdenk 		continue;
89171f95118Swdenk 	    }
89271f95118Swdenk 	    if (isdir && !(dentptr->attr & ATTR_DIR))
89371f95118Swdenk 		return -1;
89471f95118Swdenk 
89571f95118Swdenk 	    FAT_DPRINT ("RootName: %s", s_name);
89671f95118Swdenk 	    FAT_DPRINT (", start: 0x%x", START (dentptr));
89771f95118Swdenk 	    FAT_DPRINT (", size:  0x%x %s\n",
89871f95118Swdenk 			FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : "");
89971f95118Swdenk 
90071f95118Swdenk 	    goto rootdir_done;  /* We got a match */
90171f95118Swdenk 	}
90271f95118Swdenk 	cursect++;
90371f95118Swdenk     }
90471f95118Swdenk   rootdir_done:
90571f95118Swdenk 
90671f95118Swdenk     firsttime = 1;
90771f95118Swdenk     while (isdir) {
90871f95118Swdenk 	int startsect = mydata->data_begin
90971f95118Swdenk 		+ START (dentptr) * mydata->clust_size;
91071f95118Swdenk 	dir_entry dent;
91171f95118Swdenk 	char *nextname = NULL;
91271f95118Swdenk 
91371f95118Swdenk 	dent = *dentptr;
91471f95118Swdenk 	dentptr = &dent;
91571f95118Swdenk 
91671f95118Swdenk 	idx = dirdelim (subname);
91771f95118Swdenk 	if (idx >= 0) {
91871f95118Swdenk 	    subname[idx] = '\0';
91971f95118Swdenk 	    nextname = subname + idx + 1;
92071f95118Swdenk 	    /* Handle multiple delimiters */
92171f95118Swdenk 	    while (ISDIRDELIM (*nextname))
92271f95118Swdenk 		nextname++;
92371f95118Swdenk 	    if (dols && *nextname == '\0')
92471f95118Swdenk 		firsttime = 0;
92571f95118Swdenk 	} else {
92671f95118Swdenk 	    if (dols && firsttime) {
92771f95118Swdenk 		firsttime = 0;
92871f95118Swdenk 	    } else {
92971f95118Swdenk 		isdir = 0;
93071f95118Swdenk 	    }
93171f95118Swdenk 	}
93271f95118Swdenk 
93371f95118Swdenk 	if (get_dentfromdir (mydata, startsect, subname, dentptr,
93471f95118Swdenk 			     isdir ? 0 : dols) == NULL) {
93571f95118Swdenk 	    if (dols && !isdir)
93671f95118Swdenk 		return 0;
93771f95118Swdenk 	    return -1;
93871f95118Swdenk 	}
93971f95118Swdenk 
94071f95118Swdenk 	if (idx >= 0) {
94171f95118Swdenk 	    if (!(dentptr->attr & ATTR_DIR))
94271f95118Swdenk 		return -1;
94371f95118Swdenk 	    subname = nextname;
94471f95118Swdenk 	}
94571f95118Swdenk     }
94671f95118Swdenk     ret = get_contents (mydata, dentptr, buffer, maxsize);
94771f95118Swdenk     FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret);
94871f95118Swdenk 
94971f95118Swdenk     return ret;
95071f95118Swdenk }
95171f95118Swdenk 
95271f95118Swdenk 
95371f95118Swdenk int
95471f95118Swdenk file_fat_detectfs(void)
95571f95118Swdenk {
95671f95118Swdenk 	boot_sector	bs;
95771f95118Swdenk 	volume_info	volinfo;
95871f95118Swdenk 	int		fatsize;
9597205e407Swdenk 	char	vol_label[12];
96071f95118Swdenk 
9617205e407Swdenk 	if(cur_dev==NULL) {
9627205e407Swdenk 		printf("No current device\n");
9637205e407Swdenk 		return 1;
9647205e407Swdenk 	}
9657205e407Swdenk #if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)
9667205e407Swdenk 	printf("Interface:  ");
9677205e407Swdenk 	switch(cur_dev->if_type) {
9687205e407Swdenk 		case IF_TYPE_IDE :	printf("IDE"); break;
9697205e407Swdenk 		case IF_TYPE_SCSI :	printf("SCSI"); break;
9707205e407Swdenk 		case IF_TYPE_ATAPI :	printf("ATAPI"); break;
9717205e407Swdenk 		case IF_TYPE_USB :	printf("USB"); break;
9727205e407Swdenk 		case IF_TYPE_DOC :	printf("DOC"); break;
9737205e407Swdenk 		case IF_TYPE_MMC :	printf("MMC"); break;
9747205e407Swdenk 		default :		printf("Unknown");
9757205e407Swdenk 	}
9767205e407Swdenk 	printf("\n  Device %d: ",cur_dev->dev);
9777205e407Swdenk 	dev_print(cur_dev);
9787205e407Swdenk #endif
9797205e407Swdenk 	if(read_bootsectandvi(&bs, &volinfo, &fatsize)) {
9807205e407Swdenk 		printf("\nNo valid FAT fs found\n");
9817205e407Swdenk 		return 1;
9827205e407Swdenk 	}
9837205e407Swdenk 	memcpy (vol_label, volinfo.volume_label, 11);
9847205e407Swdenk 	vol_label[11] = '\0';
9857205e407Swdenk 	volinfo.fs_type[5]='\0';
9867205e407Swdenk 	printf("Partition %d: Filesystem: %s \"%s\"\n",cur_part,volinfo.fs_type,vol_label);
9877205e407Swdenk 	return 0;
98871f95118Swdenk }
98971f95118Swdenk 
99071f95118Swdenk 
99171f95118Swdenk int
99271f95118Swdenk file_fat_ls(const char *dir)
99371f95118Swdenk {
99471f95118Swdenk 	return do_fat_read(dir, NULL, 0, LS_YES);
99571f95118Swdenk }
99671f95118Swdenk 
99771f95118Swdenk 
99871f95118Swdenk long
99971f95118Swdenk file_fat_read(const char *filename, void *buffer, unsigned long maxsize)
100071f95118Swdenk {
10017205e407Swdenk 	printf("reading %s\n",filename);
100271f95118Swdenk 	return do_fat_read(filename, buffer, maxsize, LS_NO);
100371f95118Swdenk }
100471f95118Swdenk 
100571f95118Swdenk #endif /* #if (CONFIG_COMMANDS & CFG_CMD_FAT) */
1006