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 { 9280885a9dSwdenk #if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ 93a5bbcc3cSwdenk (CONFIG_COMMANDS & CFG_CMD_USB) || defined(CONFIG_SYSTEMACE) 947205e407Swdenk disk_partition_t info; 957205e407Swdenk if(!get_partition_info(dev_desc, part_no, &info)) { 967205e407Swdenk part_offset = info.start; 977205e407Swdenk cur_part = part_no; 987205e407Swdenk } 997205e407Swdenk else { 1007205e407Swdenk printf ("** Partition %d not valid on device %d **\n",part_no,dev_desc->dev); 1017205e407Swdenk return -1; 1027205e407Swdenk } 1037205e407Swdenk #else 1047205e407Swdenk /* FIXME we need to determine the start block of the 1057205e407Swdenk * partition where the DOS FS resides. This can be done 1067205e407Swdenk * by using the get_partition_info routine. For this 1077205e407Swdenk * purpose the libpart must be included. 1087205e407Swdenk */ 1097205e407Swdenk part_offset=32; 1107205e407Swdenk cur_part = 1; 1117205e407Swdenk #endif 1127205e407Swdenk } 11371f95118Swdenk return 0; 11471f95118Swdenk } 11571f95118Swdenk 11671f95118Swdenk 11771f95118Swdenk /* 11871f95118Swdenk * Get the first occurence of a directory delimiter ('/' or '\') in a string. 11971f95118Swdenk * Return index into string if found, -1 otherwise. 12071f95118Swdenk */ 12171f95118Swdenk static int 12271f95118Swdenk dirdelim(char *str) 12371f95118Swdenk { 12471f95118Swdenk char *start = str; 12571f95118Swdenk 12671f95118Swdenk while (*str != '\0') { 12771f95118Swdenk if (ISDIRDELIM(*str)) return str - start; 12871f95118Swdenk str++; 12971f95118Swdenk } 13071f95118Swdenk return -1; 13171f95118Swdenk } 13271f95118Swdenk 13371f95118Swdenk 13471f95118Swdenk /* 13571f95118Swdenk * Match volume_info fs_type strings. 13671f95118Swdenk * Return 0 on match, -1 otherwise. 13771f95118Swdenk */ 13871f95118Swdenk static int 13971f95118Swdenk compare_sign(char *str1, char *str2) 14071f95118Swdenk { 14171f95118Swdenk char *end = str1+SIGNLEN; 14271f95118Swdenk 14371f95118Swdenk while (str1 != end) { 14471f95118Swdenk if (*str1 != *str2) { 14571f95118Swdenk return -1; 14671f95118Swdenk } 14771f95118Swdenk str1++; 14871f95118Swdenk str2++; 14971f95118Swdenk } 15071f95118Swdenk 15171f95118Swdenk return 0; 15271f95118Swdenk } 15371f95118Swdenk 15471f95118Swdenk 15571f95118Swdenk /* 15671f95118Swdenk * Extract zero terminated short name from a directory entry. 15771f95118Swdenk */ 15871f95118Swdenk static void get_name (dir_entry *dirent, char *s_name) 15971f95118Swdenk { 16071f95118Swdenk char *ptr; 16171f95118Swdenk 16271f95118Swdenk memcpy (s_name, dirent->name, 8); 16371f95118Swdenk s_name[8] = '\0'; 16471f95118Swdenk ptr = s_name; 16571f95118Swdenk while (*ptr && *ptr != ' ') 16671f95118Swdenk ptr++; 16771f95118Swdenk if (dirent->ext[0] && dirent->ext[0] != ' ') { 16871f95118Swdenk *ptr = '.'; 16971f95118Swdenk ptr++; 17071f95118Swdenk memcpy (ptr, dirent->ext, 3); 17171f95118Swdenk ptr[3] = '\0'; 17271f95118Swdenk while (*ptr && *ptr != ' ') 17371f95118Swdenk ptr++; 17471f95118Swdenk } 17571f95118Swdenk *ptr = '\0'; 17671f95118Swdenk if (*s_name == DELETED_FLAG) 17771f95118Swdenk *s_name = '\0'; 17871f95118Swdenk else if (*s_name == aRING) 17971f95118Swdenk *s_name = '�'; 18071f95118Swdenk downcase (s_name); 18171f95118Swdenk } 18271f95118Swdenk 18371f95118Swdenk /* 18471f95118Swdenk * Get the entry at index 'entry' in a FAT (12/16/32) table. 18571f95118Swdenk * On failure 0x00 is returned. 18671f95118Swdenk */ 18771f95118Swdenk static __u32 18871f95118Swdenk get_fatent(fsdata *mydata, __u32 entry) 18971f95118Swdenk { 19071f95118Swdenk __u32 bufnum; 19171f95118Swdenk __u32 offset; 19271f95118Swdenk __u32 ret = 0x00; 19371f95118Swdenk 19471f95118Swdenk switch (mydata->fatsize) { 19571f95118Swdenk case 32: 19671f95118Swdenk bufnum = entry / FAT32BUFSIZE; 19771f95118Swdenk offset = entry - bufnum * FAT32BUFSIZE; 19871f95118Swdenk break; 19971f95118Swdenk case 16: 20071f95118Swdenk bufnum = entry / FAT16BUFSIZE; 20171f95118Swdenk offset = entry - bufnum * FAT16BUFSIZE; 20271f95118Swdenk break; 20371f95118Swdenk case 12: 20471f95118Swdenk bufnum = entry / FAT12BUFSIZE; 20571f95118Swdenk offset = entry - bufnum * FAT12BUFSIZE; 20671f95118Swdenk break; 20771f95118Swdenk 20871f95118Swdenk default: 20971f95118Swdenk /* Unsupported FAT size */ 21071f95118Swdenk return ret; 21171f95118Swdenk } 21271f95118Swdenk 21371f95118Swdenk /* Read a new block of FAT entries into the cache. */ 21471f95118Swdenk if (bufnum != mydata->fatbufnum) { 21571f95118Swdenk int getsize = FATBUFSIZE/FS_BLOCK_SIZE; 21671f95118Swdenk __u8 *bufptr = mydata->fatbuf; 21771f95118Swdenk __u32 fatlength = mydata->fatlength; 21871f95118Swdenk __u32 startblock = bufnum * FATBUFBLOCKS; 21971f95118Swdenk 22071f95118Swdenk fatlength *= SECTOR_SIZE; /* We want it in bytes now */ 22171f95118Swdenk startblock += mydata->fat_sect; /* Offset from start of disk */ 22271f95118Swdenk 22371f95118Swdenk if (getsize > fatlength) getsize = fatlength; 22471f95118Swdenk if (disk_read(startblock, getsize, bufptr) < 0) { 22571f95118Swdenk FAT_DPRINT("Error reading FAT blocks\n"); 22671f95118Swdenk return ret; 22771f95118Swdenk } 22871f95118Swdenk mydata->fatbufnum = bufnum; 22971f95118Swdenk } 23071f95118Swdenk 23171f95118Swdenk /* Get the actual entry from the table */ 23271f95118Swdenk switch (mydata->fatsize) { 23371f95118Swdenk case 32: 23471f95118Swdenk ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]); 23571f95118Swdenk break; 23671f95118Swdenk case 16: 23771f95118Swdenk ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]); 23871f95118Swdenk break; 23971f95118Swdenk case 12: { 24071f95118Swdenk __u32 off16 = (offset*3)/4; 24171f95118Swdenk __u16 val1, val2; 24271f95118Swdenk 24371f95118Swdenk switch (offset & 0x3) { 24471f95118Swdenk case 0: 24571f95118Swdenk ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); 24671f95118Swdenk ret &= 0xfff; 24771f95118Swdenk break; 24871f95118Swdenk case 1: 24971f95118Swdenk val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); 25071f95118Swdenk val1 &= 0xf000; 25171f95118Swdenk val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); 25271f95118Swdenk val2 &= 0x00ff; 25371f95118Swdenk ret = (val2 << 4) | (val1 >> 12); 25471f95118Swdenk break; 25571f95118Swdenk case 2: 25671f95118Swdenk val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); 25771f95118Swdenk val1 &= 0xff00; 25871f95118Swdenk val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); 25971f95118Swdenk val2 &= 0x000f; 26071f95118Swdenk ret = (val2 << 8) | (val1 >> 8); 26171f95118Swdenk break; 26271f95118Swdenk case 3: 26371f95118Swdenk ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);; 26471f95118Swdenk ret = (ret & 0xfff0) >> 4; 26571f95118Swdenk break; 26671f95118Swdenk default: 26771f95118Swdenk break; 26871f95118Swdenk } 26971f95118Swdenk } 27071f95118Swdenk break; 27171f95118Swdenk } 27271f95118Swdenk FAT_DPRINT("ret: %d, offset: %d\n", ret, offset); 27371f95118Swdenk 27471f95118Swdenk return ret; 27571f95118Swdenk } 27671f95118Swdenk 27771f95118Swdenk 27871f95118Swdenk /* 27971f95118Swdenk * Read at most 'size' bytes from the specified cluster into 'buffer'. 28071f95118Swdenk * Return 0 on success, -1 otherwise. 28171f95118Swdenk */ 28271f95118Swdenk static int 28371f95118Swdenk get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) 28471f95118Swdenk { 28571f95118Swdenk int idx = 0; 28671f95118Swdenk __u32 startsect; 28771f95118Swdenk 28871f95118Swdenk if (clustnum > 0) { 28971f95118Swdenk startsect = mydata->data_begin + clustnum*mydata->clust_size; 29071f95118Swdenk } else { 29171f95118Swdenk startsect = mydata->rootdir_sect; 29271f95118Swdenk } 29371f95118Swdenk 29471f95118Swdenk FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); 2957205e407Swdenk if (disk_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0) { 29671f95118Swdenk FAT_DPRINT("Error reading data\n"); 29771f95118Swdenk return -1; 29871f95118Swdenk } 2997205e407Swdenk if(size % FS_BLOCK_SIZE) { 30071f95118Swdenk __u8 tmpbuf[FS_BLOCK_SIZE]; 3017205e407Swdenk idx= size/FS_BLOCK_SIZE; 30271f95118Swdenk if (disk_read(startsect + idx, 1, tmpbuf) < 0) { 30371f95118Swdenk FAT_DPRINT("Error reading data\n"); 30471f95118Swdenk return -1; 30571f95118Swdenk } 3067205e407Swdenk buffer += idx*FS_BLOCK_SIZE; 30771f95118Swdenk 3087205e407Swdenk memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE); 30971f95118Swdenk return 0; 31071f95118Swdenk } 31171f95118Swdenk 31271f95118Swdenk return 0; 31371f95118Swdenk } 31471f95118Swdenk 31571f95118Swdenk 31671f95118Swdenk /* 31771f95118Swdenk * Read at most 'maxsize' bytes from the file associated with 'dentptr' 31871f95118Swdenk * into 'buffer'. 31971f95118Swdenk * Return the number of bytes read or -1 on fatal errors. 32071f95118Swdenk */ 32171f95118Swdenk static long 32271f95118Swdenk get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, 32371f95118Swdenk unsigned long maxsize) 32471f95118Swdenk { 32571f95118Swdenk unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; 32671f95118Swdenk unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE; 32771f95118Swdenk __u32 curclust = START(dentptr); 3287205e407Swdenk __u32 endclust, newclust; 3297205e407Swdenk unsigned long actsize; 33071f95118Swdenk 33171f95118Swdenk FAT_DPRINT("Filesize: %ld bytes\n", filesize); 33271f95118Swdenk 33371f95118Swdenk if (maxsize > 0 && filesize > maxsize) filesize = maxsize; 33471f95118Swdenk 33571f95118Swdenk FAT_DPRINT("Reading: %ld bytes\n", filesize); 33671f95118Swdenk 3377205e407Swdenk actsize=bytesperclust; 3387205e407Swdenk endclust=curclust; 33971f95118Swdenk do { 3407205e407Swdenk /* search for consecutive clusters */ 3417205e407Swdenk while(actsize < filesize) { 3427205e407Swdenk newclust = get_fatent(mydata, endclust); 3437205e407Swdenk if((newclust -1)!=endclust) 3447205e407Swdenk goto getit; 3457205e407Swdenk if (newclust <= 0x0001 || newclust >= 0xfff0) { 3467205e407Swdenk FAT_DPRINT("curclust: 0x%x\n", newclust); 3477205e407Swdenk FAT_DPRINT("Invalid FAT entry\n"); 3487205e407Swdenk return gotsize; 3497205e407Swdenk } 3507205e407Swdenk endclust=newclust; 3517205e407Swdenk actsize+= bytesperclust; 3527205e407Swdenk } 3537205e407Swdenk /* actsize >= file size */ 3547205e407Swdenk actsize -= bytesperclust; 3557205e407Swdenk /* get remaining clusters */ 3567205e407Swdenk if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 35771f95118Swdenk FAT_ERROR("Error reading cluster\n"); 35871f95118Swdenk return -1; 35971f95118Swdenk } 3607205e407Swdenk /* get remaining bytes */ 3617205e407Swdenk gotsize += (int)actsize; 3627205e407Swdenk filesize -= actsize; 3637205e407Swdenk buffer += actsize; 3647205e407Swdenk actsize= filesize; 3657205e407Swdenk if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) { 3667205e407Swdenk FAT_ERROR("Error reading cluster\n"); 3677205e407Swdenk return -1; 3687205e407Swdenk } 3697205e407Swdenk gotsize+=actsize; 3707205e407Swdenk return gotsize; 3717205e407Swdenk getit: 3727205e407Swdenk if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 3737205e407Swdenk FAT_ERROR("Error reading cluster\n"); 3747205e407Swdenk return -1; 3757205e407Swdenk } 3767205e407Swdenk gotsize += (int)actsize; 3777205e407Swdenk filesize -= actsize; 3787205e407Swdenk buffer += actsize; 3797205e407Swdenk curclust = get_fatent(mydata, endclust); 38071f95118Swdenk if (curclust <= 0x0001 || curclust >= 0xfff0) { 38171f95118Swdenk FAT_DPRINT("curclust: 0x%x\n", curclust); 38271f95118Swdenk FAT_ERROR("Invalid FAT entry\n"); 38371f95118Swdenk return gotsize; 38471f95118Swdenk } 3857205e407Swdenk actsize=bytesperclust; 3867205e407Swdenk endclust=curclust; 38771f95118Swdenk } while (1); 38871f95118Swdenk } 38971f95118Swdenk 39071f95118Swdenk 39171f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 39271f95118Swdenk /* 39371f95118Swdenk * Extract the file name information from 'slotptr' into 'l_name', 39471f95118Swdenk * starting at l_name[*idx]. 39571f95118Swdenk * Return 1 if terminator (zero byte) is found, 0 otherwise. 39671f95118Swdenk */ 39771f95118Swdenk static int 39871f95118Swdenk slot2str(dir_slot *slotptr, char *l_name, int *idx) 39971f95118Swdenk { 40071f95118Swdenk int j; 40171f95118Swdenk 40271f95118Swdenk for (j = 0; j <= 8; j += 2) { 40371f95118Swdenk l_name[*idx] = slotptr->name0_4[j]; 40471f95118Swdenk if (l_name[*idx] == 0x00) return 1; 40571f95118Swdenk (*idx)++; 40671f95118Swdenk } 40771f95118Swdenk for (j = 0; j <= 10; j += 2) { 40871f95118Swdenk l_name[*idx] = slotptr->name5_10[j]; 40971f95118Swdenk if (l_name[*idx] == 0x00) return 1; 41071f95118Swdenk (*idx)++; 41171f95118Swdenk } 41271f95118Swdenk for (j = 0; j <= 2; j += 2) { 41371f95118Swdenk l_name[*idx] = slotptr->name11_12[j]; 41471f95118Swdenk if (l_name[*idx] == 0x00) return 1; 41571f95118Swdenk (*idx)++; 41671f95118Swdenk } 41771f95118Swdenk 41871f95118Swdenk return 0; 41971f95118Swdenk } 42071f95118Swdenk 42171f95118Swdenk 42271f95118Swdenk /* 42371f95118Swdenk * Extract the full long filename starting at 'retdent' (which is really 42471f95118Swdenk * a slot) into 'l_name'. If successful also copy the real directory entry 42571f95118Swdenk * into 'retdent' 42671f95118Swdenk * Return 0 on success, -1 otherwise. 42771f95118Swdenk */ 4285fa66df6Swdenk __u8 get_vfatname_block[MAX_CLUSTSIZE]; 42971f95118Swdenk static int 43071f95118Swdenk get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, 43171f95118Swdenk dir_entry *retdent, char *l_name) 43271f95118Swdenk { 43371f95118Swdenk dir_entry *realdent; 43471f95118Swdenk dir_slot *slotptr = (dir_slot*) retdent; 43571f95118Swdenk __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE; 4362d1a537dSwdenk __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; 43771f95118Swdenk int idx = 0; 43871f95118Swdenk 43971f95118Swdenk while ((__u8*)slotptr < nextclust) { 44071f95118Swdenk if (counter == 0) break; 4412d1a537dSwdenk if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) 4422d1a537dSwdenk return -1; 44371f95118Swdenk slotptr++; 44471f95118Swdenk counter--; 44571f95118Swdenk } 44671f95118Swdenk 44771f95118Swdenk if ((__u8*)slotptr >= nextclust) { 44871f95118Swdenk dir_slot *slotptr2; 44971f95118Swdenk 45071f95118Swdenk slotptr--; 45171f95118Swdenk curclust = get_fatent(mydata, curclust); 45271f95118Swdenk if (curclust <= 0x0001 || curclust >= 0xfff0) { 45371f95118Swdenk FAT_DPRINT("curclust: 0x%x\n", curclust); 45471f95118Swdenk FAT_ERROR("Invalid FAT entry\n"); 45571f95118Swdenk return -1; 45671f95118Swdenk } 4575fa66df6Swdenk if (get_cluster(mydata, curclust, get_vfatname_block, 45871f95118Swdenk mydata->clust_size * SECTOR_SIZE) != 0) { 45971f95118Swdenk FAT_DPRINT("Error: reading directory block\n"); 46071f95118Swdenk return -1; 46171f95118Swdenk } 4625fa66df6Swdenk slotptr2 = (dir_slot*) get_vfatname_block; 46371f95118Swdenk while (slotptr2->id > 0x01) { 46471f95118Swdenk slotptr2++; 46571f95118Swdenk } 46671f95118Swdenk /* Save the real directory entry */ 46771f95118Swdenk realdent = (dir_entry*)slotptr2 + 1; 4685fa66df6Swdenk while ((__u8*)slotptr2 >= get_vfatname_block) { 46971f95118Swdenk slot2str(slotptr2, l_name, &idx); 47071f95118Swdenk slotptr2--; 47171f95118Swdenk } 47271f95118Swdenk } else { 47371f95118Swdenk /* Save the real directory entry */ 47471f95118Swdenk realdent = (dir_entry*)slotptr; 47571f95118Swdenk } 47671f95118Swdenk 47771f95118Swdenk do { 47871f95118Swdenk slotptr--; 47971f95118Swdenk if (slot2str(slotptr, l_name, &idx)) break; 4802d1a537dSwdenk } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); 48171f95118Swdenk 48271f95118Swdenk l_name[idx] = '\0'; 48371f95118Swdenk if (*l_name == DELETED_FLAG) *l_name = '\0'; 48471f95118Swdenk else if (*l_name == aRING) *l_name = '�'; 48571f95118Swdenk downcase(l_name); 48671f95118Swdenk 48771f95118Swdenk /* Return the real directory entry */ 48871f95118Swdenk memcpy(retdent, realdent, sizeof(dir_entry)); 48971f95118Swdenk 49071f95118Swdenk return 0; 49171f95118Swdenk } 49271f95118Swdenk 49371f95118Swdenk 49471f95118Swdenk /* Calculate short name checksum */ 49571f95118Swdenk static __u8 49671f95118Swdenk mkcksum(const char *str) 49771f95118Swdenk { 49871f95118Swdenk int i; 49971f95118Swdenk __u8 ret = 0; 50071f95118Swdenk 50171f95118Swdenk for (i = 0; i < 11; i++) { 50271f95118Swdenk ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i]; 50371f95118Swdenk } 50471f95118Swdenk 50571f95118Swdenk return ret; 50671f95118Swdenk } 50771f95118Swdenk #endif 50871f95118Swdenk 50971f95118Swdenk 51071f95118Swdenk /* 51171f95118Swdenk * Get the directory entry associated with 'filename' from the directory 51271f95118Swdenk * starting at 'startsect' 51371f95118Swdenk */ 5145fa66df6Swdenk __u8 get_dentfromdir_block[MAX_CLUSTSIZE]; 51571f95118Swdenk static dir_entry *get_dentfromdir (fsdata * mydata, int startsect, 51671f95118Swdenk char *filename, dir_entry * retdent, 51771f95118Swdenk int dols) 51871f95118Swdenk { 51971f95118Swdenk __u16 prevcksum = 0xffff; 52071f95118Swdenk __u32 curclust = START (retdent); 52171f95118Swdenk int files = 0, dirs = 0; 52271f95118Swdenk 52371f95118Swdenk FAT_DPRINT ("get_dentfromdir: %s\n", filename); 52471f95118Swdenk while (1) { 52571f95118Swdenk dir_entry *dentptr; 52671f95118Swdenk int i; 52771f95118Swdenk 5285fa66df6Swdenk if (get_cluster (mydata, curclust, get_dentfromdir_block, 52971f95118Swdenk mydata->clust_size * SECTOR_SIZE) != 0) { 53071f95118Swdenk FAT_DPRINT ("Error: reading directory block\n"); 53171f95118Swdenk return NULL; 53271f95118Swdenk } 5335fa66df6Swdenk dentptr = (dir_entry *) get_dentfromdir_block; 53471f95118Swdenk for (i = 0; i < DIRENTSPERCLUST; i++) { 53571f95118Swdenk char s_name[14], l_name[256]; 53671f95118Swdenk 53771f95118Swdenk l_name[0] = '\0'; 538855a496fSwdenk if (dentptr->name[0] == DELETED_FLAG) { 539855a496fSwdenk dentptr++; 540855a496fSwdenk continue; 541855a496fSwdenk } 54271f95118Swdenk if ((dentptr->attr & ATTR_VOLUME)) { 54371f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 54471f95118Swdenk if ((dentptr->attr & ATTR_VFAT) && 5452d1a537dSwdenk (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 54671f95118Swdenk prevcksum = ((dir_slot *) dentptr) 54771f95118Swdenk ->alias_checksum; 5485fa66df6Swdenk get_vfatname (mydata, curclust, get_dentfromdir_block, 54971f95118Swdenk dentptr, l_name); 55071f95118Swdenk if (dols) { 55171f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 55271f95118Swdenk char dirc; 55371f95118Swdenk int doit = 0; 55471f95118Swdenk 55571f95118Swdenk if (isdir) { 55671f95118Swdenk dirs++; 55771f95118Swdenk dirc = '/'; 55871f95118Swdenk doit = 1; 55971f95118Swdenk } else { 56071f95118Swdenk dirc = ' '; 56171f95118Swdenk if (l_name[0] != 0) { 56271f95118Swdenk files++; 56371f95118Swdenk doit = 1; 56471f95118Swdenk } 56571f95118Swdenk } 56671f95118Swdenk if (doit) { 56771f95118Swdenk if (dirc == ' ') { 56871f95118Swdenk printf (" %8ld %s%c\n", 56971f95118Swdenk (long) FAT2CPU32 (dentptr->size), 57071f95118Swdenk l_name, dirc); 57171f95118Swdenk } else { 57271f95118Swdenk printf (" %s%c\n", l_name, dirc); 57371f95118Swdenk } 57471f95118Swdenk } 57571f95118Swdenk dentptr++; 57671f95118Swdenk continue; 57771f95118Swdenk } 57871f95118Swdenk FAT_DPRINT ("vfatname: |%s|\n", l_name); 57971f95118Swdenk } else 58071f95118Swdenk #endif 58171f95118Swdenk { 58271f95118Swdenk /* Volume label or VFAT entry */ 58371f95118Swdenk dentptr++; 58471f95118Swdenk continue; 58571f95118Swdenk } 58671f95118Swdenk } 58771f95118Swdenk if (dentptr->name[0] == 0) { 58871f95118Swdenk if (dols) { 58971f95118Swdenk printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); 59071f95118Swdenk } 59171f95118Swdenk FAT_DPRINT ("Dentname == NULL - %d\n", i); 59271f95118Swdenk return NULL; 59371f95118Swdenk } 59471f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 59571f95118Swdenk if (dols && mkcksum (dentptr->name) == prevcksum) { 59671f95118Swdenk dentptr++; 59771f95118Swdenk continue; 59871f95118Swdenk } 59971f95118Swdenk #endif 60071f95118Swdenk get_name (dentptr, s_name); 60171f95118Swdenk if (dols) { 60271f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 60371f95118Swdenk char dirc; 60471f95118Swdenk int doit = 0; 60571f95118Swdenk 60671f95118Swdenk if (isdir) { 60771f95118Swdenk dirs++; 60871f95118Swdenk dirc = '/'; 60971f95118Swdenk doit = 1; 61071f95118Swdenk } else { 61171f95118Swdenk dirc = ' '; 61271f95118Swdenk if (s_name[0] != 0) { 61371f95118Swdenk files++; 61471f95118Swdenk doit = 1; 61571f95118Swdenk } 61671f95118Swdenk } 61771f95118Swdenk if (doit) { 61871f95118Swdenk if (dirc == ' ') { 61971f95118Swdenk printf (" %8ld %s%c\n", 62071f95118Swdenk (long) FAT2CPU32 (dentptr->size), s_name, 62171f95118Swdenk dirc); 62271f95118Swdenk } else { 62371f95118Swdenk printf (" %s%c\n", s_name, dirc); 62471f95118Swdenk } 62571f95118Swdenk } 62671f95118Swdenk dentptr++; 62771f95118Swdenk continue; 62871f95118Swdenk } 62971f95118Swdenk if (strcmp (filename, s_name) && strcmp (filename, l_name)) { 63071f95118Swdenk FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name); 63171f95118Swdenk dentptr++; 63271f95118Swdenk continue; 63371f95118Swdenk } 63471f95118Swdenk memcpy (retdent, dentptr, sizeof (dir_entry)); 63571f95118Swdenk 63671f95118Swdenk FAT_DPRINT ("DentName: %s", s_name); 63771f95118Swdenk FAT_DPRINT (", start: 0x%x", START (dentptr)); 63871f95118Swdenk FAT_DPRINT (", size: 0x%x %s\n", 63971f95118Swdenk FAT2CPU32 (dentptr->size), 64071f95118Swdenk (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); 64171f95118Swdenk 64271f95118Swdenk return retdent; 64371f95118Swdenk } 64471f95118Swdenk curclust = get_fatent (mydata, curclust); 64571f95118Swdenk if (curclust <= 0x0001 || curclust >= 0xfff0) { 64671f95118Swdenk FAT_DPRINT ("curclust: 0x%x\n", curclust); 64771f95118Swdenk FAT_ERROR ("Invalid FAT entry\n"); 64871f95118Swdenk return NULL; 64971f95118Swdenk } 65071f95118Swdenk } 65171f95118Swdenk 65271f95118Swdenk return NULL; 65371f95118Swdenk } 65471f95118Swdenk 65571f95118Swdenk 65671f95118Swdenk /* 65771f95118Swdenk * Read boot sector and volume info from a FAT filesystem 65871f95118Swdenk */ 65971f95118Swdenk static int 66071f95118Swdenk read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) 66171f95118Swdenk { 66271f95118Swdenk __u8 block[FS_BLOCK_SIZE]; 66371f95118Swdenk volume_info *vistart; 66471f95118Swdenk 66571f95118Swdenk if (disk_read(0, 1, block) < 0) { 66671f95118Swdenk FAT_DPRINT("Error: reading block\n"); 66771f95118Swdenk return -1; 66871f95118Swdenk } 66971f95118Swdenk 67071f95118Swdenk memcpy(bs, block, sizeof(boot_sector)); 67171f95118Swdenk bs->reserved = FAT2CPU16(bs->reserved); 67271f95118Swdenk bs->fat_length = FAT2CPU16(bs->fat_length); 67371f95118Swdenk bs->secs_track = FAT2CPU16(bs->secs_track); 67471f95118Swdenk bs->heads = FAT2CPU16(bs->heads); 67571f95118Swdenk #if 0 /* UNUSED */ 67671f95118Swdenk bs->hidden = FAT2CPU32(bs->hidden); 67771f95118Swdenk #endif 67871f95118Swdenk bs->total_sect = FAT2CPU32(bs->total_sect); 67971f95118Swdenk 68071f95118Swdenk /* FAT32 entries */ 68171f95118Swdenk if (bs->fat_length == 0) { 68271f95118Swdenk /* Assume FAT32 */ 68371f95118Swdenk bs->fat32_length = FAT2CPU32(bs->fat32_length); 68471f95118Swdenk bs->flags = FAT2CPU16(bs->flags); 68571f95118Swdenk bs->root_cluster = FAT2CPU32(bs->root_cluster); 68671f95118Swdenk bs->info_sector = FAT2CPU16(bs->info_sector); 68771f95118Swdenk bs->backup_boot = FAT2CPU16(bs->backup_boot); 68871f95118Swdenk vistart = (volume_info*) (block + sizeof(boot_sector)); 68971f95118Swdenk *fatsize = 32; 69071f95118Swdenk } else { 69171f95118Swdenk vistart = (volume_info*) &(bs->fat32_length); 69271f95118Swdenk *fatsize = 0; 69371f95118Swdenk } 69471f95118Swdenk memcpy(volinfo, vistart, sizeof(volume_info)); 69571f95118Swdenk 69671f95118Swdenk /* Terminate fs_type string. Writing past the end of vistart 69771f95118Swdenk is ok - it's just the buffer. */ 69871f95118Swdenk vistart->fs_type[8] = '\0'; 69971f95118Swdenk 70071f95118Swdenk if (*fatsize == 32) { 70171f95118Swdenk if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) { 70271f95118Swdenk return 0; 70371f95118Swdenk } 70471f95118Swdenk } else { 70571f95118Swdenk if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) { 70671f95118Swdenk *fatsize = 12; 70771f95118Swdenk return 0; 70871f95118Swdenk } 70971f95118Swdenk if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) { 71071f95118Swdenk *fatsize = 16; 71171f95118Swdenk return 0; 71271f95118Swdenk } 71371f95118Swdenk } 71471f95118Swdenk 71571f95118Swdenk FAT_DPRINT("Error: broken fs_type sign\n"); 71671f95118Swdenk return -1; 71771f95118Swdenk } 71871f95118Swdenk 71971f95118Swdenk 7205fa66df6Swdenk __u8 do_fat_read_block[MAX_CLUSTSIZE]; /* Block buffer */ 72120cc00ddSstroese long 72271f95118Swdenk do_fat_read (const char *filename, void *buffer, unsigned long maxsize, 72371f95118Swdenk int dols) 72471f95118Swdenk { 725*d06a5f7eSWolfgang Denk #if CONFIG_NIOS /* NIOS CPU cannot access big automatic arrays */ 726*d06a5f7eSWolfgang Denk static 727*d06a5f7eSWolfgang Denk #endif 72871f95118Swdenk char fnamecopy[2048]; 72971f95118Swdenk boot_sector bs; 73071f95118Swdenk volume_info volinfo; 73171f95118Swdenk fsdata datablock; 73271f95118Swdenk fsdata *mydata = &datablock; 73371f95118Swdenk dir_entry *dentptr; 73471f95118Swdenk __u16 prevcksum = 0xffff; 73571f95118Swdenk char *subname = ""; 73671f95118Swdenk int rootdir_size, cursect; 73771f95118Swdenk int idx, isdir = 0; 73871f95118Swdenk int files = 0, dirs = 0; 73971f95118Swdenk long ret = 0; 74071f95118Swdenk int firsttime; 74171f95118Swdenk 74271f95118Swdenk if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { 74371f95118Swdenk FAT_DPRINT ("Error: reading boot sector\n"); 74471f95118Swdenk return -1; 74571f95118Swdenk } 74671f95118Swdenk if (mydata->fatsize == 32) { 74771f95118Swdenk mydata->fatlength = bs.fat32_length; 74871f95118Swdenk } else { 74971f95118Swdenk mydata->fatlength = bs.fat_length; 75071f95118Swdenk } 75171f95118Swdenk mydata->fat_sect = bs.reserved; 75271f95118Swdenk cursect = mydata->rootdir_sect 75371f95118Swdenk = mydata->fat_sect + mydata->fatlength * bs.fats; 75471f95118Swdenk mydata->clust_size = bs.cluster_size; 75571f95118Swdenk if (mydata->fatsize == 32) { 75671f95118Swdenk rootdir_size = mydata->clust_size; 75771f95118Swdenk mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ 75871f95118Swdenk - (mydata->clust_size * 2); 75971f95118Swdenk } else { 76071f95118Swdenk rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0]) 76171f95118Swdenk * sizeof (dir_entry)) / SECTOR_SIZE; 76271f95118Swdenk mydata->data_begin = mydata->rootdir_sect + rootdir_size 76371f95118Swdenk - (mydata->clust_size * 2); 76471f95118Swdenk } 76571f95118Swdenk mydata->fatbufnum = -1; 76671f95118Swdenk 76771f95118Swdenk FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, 76871f95118Swdenk mydata->fatlength); 76971f95118Swdenk FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" 77071f95118Swdenk "Data begins at: %d\n", 77171f95118Swdenk mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE, 77271f95118Swdenk rootdir_size, mydata->data_begin); 77371f95118Swdenk FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); 77471f95118Swdenk 77571f95118Swdenk /* "cwd" is always the root... */ 77671f95118Swdenk while (ISDIRDELIM (*filename)) 77771f95118Swdenk filename++; 77871f95118Swdenk /* Make a copy of the filename and convert it to lowercase */ 77971f95118Swdenk strcpy (fnamecopy, filename); 78071f95118Swdenk downcase (fnamecopy); 78171f95118Swdenk if (*fnamecopy == '\0') { 78271f95118Swdenk if (!dols) 78371f95118Swdenk return -1; 78471f95118Swdenk dols = LS_ROOT; 78571f95118Swdenk } else if ((idx = dirdelim (fnamecopy)) >= 0) { 78671f95118Swdenk isdir = 1; 78771f95118Swdenk fnamecopy[idx] = '\0'; 78871f95118Swdenk subname = fnamecopy + idx + 1; 78971f95118Swdenk /* Handle multiple delimiters */ 79071f95118Swdenk while (ISDIRDELIM (*subname)) 79171f95118Swdenk subname++; 79271f95118Swdenk } else if (dols) { 79371f95118Swdenk isdir = 1; 79471f95118Swdenk } 79571f95118Swdenk 79671f95118Swdenk while (1) { 79771f95118Swdenk int i; 79871f95118Swdenk 7995fa66df6Swdenk if (disk_read (cursect, mydata->clust_size, do_fat_read_block) < 0) { 80071f95118Swdenk FAT_DPRINT ("Error: reading rootdir block\n"); 80171f95118Swdenk return -1; 80271f95118Swdenk } 8035fa66df6Swdenk dentptr = (dir_entry *) do_fat_read_block; 80471f95118Swdenk for (i = 0; i < DIRENTSPERBLOCK; i++) { 80571f95118Swdenk char s_name[14], l_name[256]; 80671f95118Swdenk 80771f95118Swdenk l_name[0] = '\0'; 80871f95118Swdenk if ((dentptr->attr & ATTR_VOLUME)) { 80971f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 81071f95118Swdenk if ((dentptr->attr & ATTR_VFAT) && 8112d1a537dSwdenk (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 81271f95118Swdenk prevcksum = ((dir_slot *) dentptr)->alias_checksum; 8135fa66df6Swdenk get_vfatname (mydata, 0, do_fat_read_block, dentptr, l_name); 81471f95118Swdenk if (dols == LS_ROOT) { 81571f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 81671f95118Swdenk char dirc; 81771f95118Swdenk int doit = 0; 81871f95118Swdenk 81971f95118Swdenk if (isdir) { 82071f95118Swdenk dirs++; 82171f95118Swdenk dirc = '/'; 82271f95118Swdenk doit = 1; 82371f95118Swdenk } else { 82471f95118Swdenk dirc = ' '; 82571f95118Swdenk if (l_name[0] != 0) { 82671f95118Swdenk files++; 82771f95118Swdenk doit = 1; 82871f95118Swdenk } 82971f95118Swdenk } 83071f95118Swdenk if (doit) { 83171f95118Swdenk if (dirc == ' ') { 83271f95118Swdenk printf (" %8ld %s%c\n", 83371f95118Swdenk (long) FAT2CPU32 (dentptr->size), 83471f95118Swdenk l_name, dirc); 83571f95118Swdenk } else { 83671f95118Swdenk printf (" %s%c\n", l_name, dirc); 83771f95118Swdenk } 83871f95118Swdenk } 83971f95118Swdenk dentptr++; 84071f95118Swdenk continue; 84171f95118Swdenk } 84271f95118Swdenk FAT_DPRINT ("Rootvfatname: |%s|\n", l_name); 84371f95118Swdenk } else 84471f95118Swdenk #endif 84571f95118Swdenk { 84671f95118Swdenk /* Volume label or VFAT entry */ 84771f95118Swdenk dentptr++; 84871f95118Swdenk continue; 84971f95118Swdenk } 85071f95118Swdenk } else if (dentptr->name[0] == 0) { 85171f95118Swdenk FAT_DPRINT ("RootDentname == NULL - %d\n", i); 85271f95118Swdenk if (dols == LS_ROOT) { 85371f95118Swdenk printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); 85471f95118Swdenk return 0; 85571f95118Swdenk } 85671f95118Swdenk return -1; 85771f95118Swdenk } 85871f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 85971f95118Swdenk else if (dols == LS_ROOT 86071f95118Swdenk && mkcksum (dentptr->name) == prevcksum) { 86171f95118Swdenk dentptr++; 86271f95118Swdenk continue; 86371f95118Swdenk } 86471f95118Swdenk #endif 86571f95118Swdenk get_name (dentptr, s_name); 86671f95118Swdenk if (dols == LS_ROOT) { 86771f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 86871f95118Swdenk char dirc; 86971f95118Swdenk int doit = 0; 87071f95118Swdenk 87171f95118Swdenk if (isdir) { 87271f95118Swdenk dirc = '/'; 873a43278a4Swdenk if (s_name[0] != 0) { 874a43278a4Swdenk dirs++; 87571f95118Swdenk doit = 1; 876a43278a4Swdenk } 87771f95118Swdenk } else { 87871f95118Swdenk dirc = ' '; 87971f95118Swdenk if (s_name[0] != 0) { 88071f95118Swdenk files++; 88171f95118Swdenk doit = 1; 88271f95118Swdenk } 88371f95118Swdenk } 88471f95118Swdenk if (doit) { 88571f95118Swdenk if (dirc == ' ') { 88671f95118Swdenk printf (" %8ld %s%c\n", 88771f95118Swdenk (long) FAT2CPU32 (dentptr->size), s_name, 88871f95118Swdenk dirc); 88971f95118Swdenk } else { 89071f95118Swdenk printf (" %s%c\n", s_name, dirc); 89171f95118Swdenk } 89271f95118Swdenk } 89371f95118Swdenk dentptr++; 89471f95118Swdenk continue; 89571f95118Swdenk } 89671f95118Swdenk if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { 89771f95118Swdenk FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name); 89871f95118Swdenk dentptr++; 89971f95118Swdenk continue; 90071f95118Swdenk } 90171f95118Swdenk if (isdir && !(dentptr->attr & ATTR_DIR)) 90271f95118Swdenk return -1; 90371f95118Swdenk 90471f95118Swdenk FAT_DPRINT ("RootName: %s", s_name); 90571f95118Swdenk FAT_DPRINT (", start: 0x%x", START (dentptr)); 90671f95118Swdenk FAT_DPRINT (", size: 0x%x %s\n", 90771f95118Swdenk FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : ""); 90871f95118Swdenk 90971f95118Swdenk goto rootdir_done; /* We got a match */ 91071f95118Swdenk } 91171f95118Swdenk cursect++; 91271f95118Swdenk } 91371f95118Swdenk rootdir_done: 91471f95118Swdenk 91571f95118Swdenk firsttime = 1; 91671f95118Swdenk while (isdir) { 91771f95118Swdenk int startsect = mydata->data_begin 91871f95118Swdenk + START (dentptr) * mydata->clust_size; 91971f95118Swdenk dir_entry dent; 92071f95118Swdenk char *nextname = NULL; 92171f95118Swdenk 92271f95118Swdenk dent = *dentptr; 92371f95118Swdenk dentptr = &dent; 92471f95118Swdenk 92571f95118Swdenk idx = dirdelim (subname); 92671f95118Swdenk if (idx >= 0) { 92771f95118Swdenk subname[idx] = '\0'; 92871f95118Swdenk nextname = subname + idx + 1; 92971f95118Swdenk /* Handle multiple delimiters */ 93071f95118Swdenk while (ISDIRDELIM (*nextname)) 93171f95118Swdenk nextname++; 93271f95118Swdenk if (dols && *nextname == '\0') 93371f95118Swdenk firsttime = 0; 93471f95118Swdenk } else { 93571f95118Swdenk if (dols && firsttime) { 93671f95118Swdenk firsttime = 0; 93771f95118Swdenk } else { 93871f95118Swdenk isdir = 0; 93971f95118Swdenk } 94071f95118Swdenk } 94171f95118Swdenk 94271f95118Swdenk if (get_dentfromdir (mydata, startsect, subname, dentptr, 94371f95118Swdenk isdir ? 0 : dols) == NULL) { 94471f95118Swdenk if (dols && !isdir) 94571f95118Swdenk return 0; 94671f95118Swdenk return -1; 94771f95118Swdenk } 94871f95118Swdenk 94971f95118Swdenk if (idx >= 0) { 95071f95118Swdenk if (!(dentptr->attr & ATTR_DIR)) 95171f95118Swdenk return -1; 95271f95118Swdenk subname = nextname; 95371f95118Swdenk } 95471f95118Swdenk } 95571f95118Swdenk ret = get_contents (mydata, dentptr, buffer, maxsize); 95671f95118Swdenk FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret); 95771f95118Swdenk 95871f95118Swdenk return ret; 95971f95118Swdenk } 96071f95118Swdenk 96171f95118Swdenk 96271f95118Swdenk int 96371f95118Swdenk file_fat_detectfs(void) 96471f95118Swdenk { 96571f95118Swdenk boot_sector bs; 96671f95118Swdenk volume_info volinfo; 96771f95118Swdenk int fatsize; 9687205e407Swdenk char vol_label[12]; 96971f95118Swdenk 9707205e407Swdenk if(cur_dev==NULL) { 9717205e407Swdenk printf("No current device\n"); 9727205e407Swdenk return 1; 9737205e407Swdenk } 974a2663ea4Swdenk #if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ 975a2663ea4Swdenk (CONFIG_COMMANDS & CFG_CMD_USB) || (CONFIG_MMC) 9767205e407Swdenk printf("Interface: "); 9777205e407Swdenk switch(cur_dev->if_type) { 9787205e407Swdenk case IF_TYPE_IDE : printf("IDE"); break; 9797205e407Swdenk case IF_TYPE_SCSI : printf("SCSI"); break; 9807205e407Swdenk case IF_TYPE_ATAPI : printf("ATAPI"); break; 9817205e407Swdenk case IF_TYPE_USB : printf("USB"); break; 9827205e407Swdenk case IF_TYPE_DOC : printf("DOC"); break; 9837205e407Swdenk case IF_TYPE_MMC : printf("MMC"); break; 9847205e407Swdenk default : printf("Unknown"); 9857205e407Swdenk } 9867205e407Swdenk printf("\n Device %d: ",cur_dev->dev); 9877205e407Swdenk dev_print(cur_dev); 9887205e407Swdenk #endif 9897205e407Swdenk if(read_bootsectandvi(&bs, &volinfo, &fatsize)) { 9907205e407Swdenk printf("\nNo valid FAT fs found\n"); 9917205e407Swdenk return 1; 9927205e407Swdenk } 9937205e407Swdenk memcpy (vol_label, volinfo.volume_label, 11); 9947205e407Swdenk vol_label[11] = '\0'; 9957205e407Swdenk volinfo.fs_type[5]='\0'; 9967205e407Swdenk printf("Partition %d: Filesystem: %s \"%s\"\n",cur_part,volinfo.fs_type,vol_label); 9977205e407Swdenk return 0; 99871f95118Swdenk } 99971f95118Swdenk 100071f95118Swdenk 100171f95118Swdenk int 100271f95118Swdenk file_fat_ls(const char *dir) 100371f95118Swdenk { 100471f95118Swdenk return do_fat_read(dir, NULL, 0, LS_YES); 100571f95118Swdenk } 100671f95118Swdenk 100771f95118Swdenk 100871f95118Swdenk long 100971f95118Swdenk file_fat_read(const char *filename, void *buffer, unsigned long maxsize) 101071f95118Swdenk { 10117205e407Swdenk printf("reading %s\n",filename); 101271f95118Swdenk return do_fat_read(filename, buffer, maxsize, LS_NO); 101371f95118Swdenk } 101471f95118Swdenk 101571f95118Swdenk #endif /* #if (CONFIG_COMMANDS & CFG_CMD_FAT) */ 1016