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