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 /* 3571f95118Swdenk * Convert a string to lowercase. 3671f95118Swdenk */ 3771f95118Swdenk static void 3871f95118Swdenk downcase(char *str) 3971f95118Swdenk { 4071f95118Swdenk while (*str != '\0') { 4171f95118Swdenk TOLOWER(*str); 4271f95118Swdenk str++; 4371f95118Swdenk } 4471f95118Swdenk } 4571f95118Swdenk 467205e407Swdenk static block_dev_desc_t *cur_dev = NULL; 477205e407Swdenk static unsigned long part_offset = 0; 487205e407Swdenk static int cur_part = 1; 497205e407Swdenk 507205e407Swdenk #define DOS_PART_TBL_OFFSET 0x1be 517205e407Swdenk #define DOS_PART_MAGIC_OFFSET 0x1fe 527205e407Swdenk #define DOS_FS_TYPE_OFFSET 0x36 5371f95118Swdenk 5471f95118Swdenk int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr) 5571f95118Swdenk { 567205e407Swdenk startblock += part_offset; 577205e407Swdenk if (cur_dev == NULL) 587205e407Swdenk return -1; 597205e407Swdenk if (cur_dev->block_read) { 603e3b9569SPeter Pearse return cur_dev->block_read (cur_dev->dev 613e3b9569SPeter Pearse , startblock, getsize, (unsigned long *)bufptr); 6271f95118Swdenk } 6371f95118Swdenk return -1; 6471f95118Swdenk } 6571f95118Swdenk 6671f95118Swdenk 6771f95118Swdenk int 687205e407Swdenk fat_register_device(block_dev_desc_t *dev_desc, int part_no) 6971f95118Swdenk { 707205e407Swdenk unsigned char buffer[SECTOR_SIZE]; 71566a494fSHeiko Schocher disk_partition_t info; 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 } 86dd60d122SJon Loeliger #if (defined(CONFIG_CMD_IDE) || \ 87*75eb82ecSunsik Kim defined(CONFIG_CMD_MG_DISK) || \ 888c5170a7SSonic Zhang defined(CONFIG_CMD_SATA) || \ 89dd60d122SJon Loeliger defined(CONFIG_CMD_SCSI) || \ 90dd60d122SJon Loeliger defined(CONFIG_CMD_USB) || \ 9102df4a27SAndy Fleming defined(CONFIG_MMC) || \ 92b0d8f5bfSPeter Pearse defined(CONFIG_SYSTEMACE) ) 93566a494fSHeiko Schocher /* First we assume, there is a MBR */ 947205e407Swdenk if (!get_partition_info (dev_desc, part_no, &info)) { 957205e407Swdenk part_offset = info.start; 967205e407Swdenk cur_part = part_no; 97566a494fSHeiko Schocher } else if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3)) { 98566a494fSHeiko Schocher /* ok, we assume we are on a PBR only */ 99566a494fSHeiko Schocher cur_part = 1; 100566a494fSHeiko Schocher part_offset = 0; 101566a494fSHeiko Schocher } else { 102bf1060eaSWolfgang Denk printf ("** Partition %d not valid on device %d **\n", 103bf1060eaSWolfgang Denk part_no, dev_desc->dev); 1047205e407Swdenk return -1; 1057205e407Swdenk } 10602df4a27SAndy Fleming 1077205e407Swdenk #else 108566a494fSHeiko Schocher if (!strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) { 109566a494fSHeiko Schocher /* ok, we assume we are on a PBR only */ 110566a494fSHeiko Schocher cur_part = 1; 111566a494fSHeiko Schocher part_offset = 0; 112566a494fSHeiko Schocher info.start = part_offset; 113566a494fSHeiko Schocher } else { 1147205e407Swdenk /* FIXME we need to determine the start block of the 1157205e407Swdenk * partition where the DOS FS resides. This can be done 1167205e407Swdenk * by using the get_partition_info routine. For this 1177205e407Swdenk * purpose the libpart must be included. 1187205e407Swdenk */ 1197205e407Swdenk part_offset = 32; 1207205e407Swdenk cur_part = 1; 1217205e407Swdenk } 122566a494fSHeiko Schocher #endif 12371f95118Swdenk return 0; 12471f95118Swdenk } 12571f95118Swdenk 12671f95118Swdenk 12771f95118Swdenk /* 12871f95118Swdenk * Get the first occurence of a directory delimiter ('/' or '\') in a string. 12971f95118Swdenk * Return index into string if found, -1 otherwise. 13071f95118Swdenk */ 13171f95118Swdenk static int 13271f95118Swdenk dirdelim(char *str) 13371f95118Swdenk { 13471f95118Swdenk char *start = str; 13571f95118Swdenk 13671f95118Swdenk while (*str != '\0') { 13771f95118Swdenk if (ISDIRDELIM(*str)) return str - start; 13871f95118Swdenk str++; 13971f95118Swdenk } 14071f95118Swdenk return -1; 14171f95118Swdenk } 14271f95118Swdenk 14371f95118Swdenk 14471f95118Swdenk /* 14571f95118Swdenk * Match volume_info fs_type strings. 14671f95118Swdenk * Return 0 on match, -1 otherwise. 14771f95118Swdenk */ 14871f95118Swdenk static int 14971f95118Swdenk compare_sign(char *str1, char *str2) 15071f95118Swdenk { 15171f95118Swdenk char *end = str1+SIGNLEN; 15271f95118Swdenk 15371f95118Swdenk while (str1 != end) { 15471f95118Swdenk if (*str1 != *str2) { 15571f95118Swdenk return -1; 15671f95118Swdenk } 15771f95118Swdenk str1++; 15871f95118Swdenk str2++; 15971f95118Swdenk } 16071f95118Swdenk 16171f95118Swdenk return 0; 16271f95118Swdenk } 16371f95118Swdenk 16471f95118Swdenk 16571f95118Swdenk /* 16671f95118Swdenk * Extract zero terminated short name from a directory entry. 16771f95118Swdenk */ 16871f95118Swdenk static void get_name (dir_entry *dirent, char *s_name) 16971f95118Swdenk { 17071f95118Swdenk char *ptr; 17171f95118Swdenk 17271f95118Swdenk memcpy (s_name, dirent->name, 8); 17371f95118Swdenk s_name[8] = '\0'; 17471f95118Swdenk ptr = s_name; 17571f95118Swdenk while (*ptr && *ptr != ' ') 17671f95118Swdenk ptr++; 17771f95118Swdenk if (dirent->ext[0] && dirent->ext[0] != ' ') { 17871f95118Swdenk *ptr = '.'; 17971f95118Swdenk ptr++; 18071f95118Swdenk memcpy (ptr, dirent->ext, 3); 18171f95118Swdenk ptr[3] = '\0'; 18271f95118Swdenk while (*ptr && *ptr != ' ') 18371f95118Swdenk ptr++; 18471f95118Swdenk } 18571f95118Swdenk *ptr = '\0'; 18671f95118Swdenk if (*s_name == DELETED_FLAG) 18771f95118Swdenk *s_name = '\0'; 18871f95118Swdenk else if (*s_name == aRING) 1893c2c2f42SRemy Bohmer *s_name = DELETED_FLAG; 19071f95118Swdenk downcase (s_name); 19171f95118Swdenk } 19271f95118Swdenk 19371f95118Swdenk /* 19471f95118Swdenk * Get the entry at index 'entry' in a FAT (12/16/32) table. 19571f95118Swdenk * On failure 0x00 is returned. 19671f95118Swdenk */ 19771f95118Swdenk static __u32 19871f95118Swdenk get_fatent(fsdata *mydata, __u32 entry) 19971f95118Swdenk { 20071f95118Swdenk __u32 bufnum; 20171f95118Swdenk __u32 offset; 20271f95118Swdenk __u32 ret = 0x00; 20371f95118Swdenk 20471f95118Swdenk switch (mydata->fatsize) { 20571f95118Swdenk case 32: 20671f95118Swdenk bufnum = entry / FAT32BUFSIZE; 20771f95118Swdenk offset = entry - bufnum * FAT32BUFSIZE; 20871f95118Swdenk break; 20971f95118Swdenk case 16: 21071f95118Swdenk bufnum = entry / FAT16BUFSIZE; 21171f95118Swdenk offset = entry - bufnum * FAT16BUFSIZE; 21271f95118Swdenk break; 21371f95118Swdenk case 12: 21471f95118Swdenk bufnum = entry / FAT12BUFSIZE; 21571f95118Swdenk offset = entry - bufnum * FAT12BUFSIZE; 21671f95118Swdenk break; 21771f95118Swdenk 21871f95118Swdenk default: 21971f95118Swdenk /* Unsupported FAT size */ 22071f95118Swdenk return ret; 22171f95118Swdenk } 22271f95118Swdenk 22371f95118Swdenk /* Read a new block of FAT entries into the cache. */ 22471f95118Swdenk if (bufnum != mydata->fatbufnum) { 22571f95118Swdenk int getsize = FATBUFSIZE/FS_BLOCK_SIZE; 22671f95118Swdenk __u8 *bufptr = mydata->fatbuf; 22771f95118Swdenk __u32 fatlength = mydata->fatlength; 22871f95118Swdenk __u32 startblock = bufnum * FATBUFBLOCKS; 22971f95118Swdenk 23071f95118Swdenk fatlength *= SECTOR_SIZE; /* We want it in bytes now */ 23171f95118Swdenk startblock += mydata->fat_sect; /* Offset from start of disk */ 23271f95118Swdenk 23371f95118Swdenk if (getsize > fatlength) getsize = fatlength; 23471f95118Swdenk if (disk_read(startblock, getsize, bufptr) < 0) { 23571f95118Swdenk FAT_DPRINT("Error reading FAT blocks\n"); 23671f95118Swdenk return ret; 23771f95118Swdenk } 23871f95118Swdenk mydata->fatbufnum = bufnum; 23971f95118Swdenk } 24071f95118Swdenk 24171f95118Swdenk /* Get the actual entry from the table */ 24271f95118Swdenk switch (mydata->fatsize) { 24371f95118Swdenk case 32: 24471f95118Swdenk ret = FAT2CPU32(((__u32*)mydata->fatbuf)[offset]); 24571f95118Swdenk break; 24671f95118Swdenk case 16: 24771f95118Swdenk ret = FAT2CPU16(((__u16*)mydata->fatbuf)[offset]); 24871f95118Swdenk break; 24971f95118Swdenk case 12: { 25071f95118Swdenk __u32 off16 = (offset*3)/4; 25171f95118Swdenk __u16 val1, val2; 25271f95118Swdenk 25371f95118Swdenk switch (offset & 0x3) { 25471f95118Swdenk case 0: 25571f95118Swdenk ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); 25671f95118Swdenk ret &= 0xfff; 25771f95118Swdenk break; 25871f95118Swdenk case 1: 25971f95118Swdenk val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); 26071f95118Swdenk val1 &= 0xf000; 26171f95118Swdenk val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); 26271f95118Swdenk val2 &= 0x00ff; 26371f95118Swdenk ret = (val2 << 4) | (val1 >> 12); 26471f95118Swdenk break; 26571f95118Swdenk case 2: 26671f95118Swdenk val1 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]); 26771f95118Swdenk val1 &= 0xff00; 26871f95118Swdenk val2 = FAT2CPU16(((__u16*)mydata->fatbuf)[off16+1]); 26971f95118Swdenk val2 &= 0x000f; 27071f95118Swdenk ret = (val2 << 8) | (val1 >> 8); 27171f95118Swdenk break; 27271f95118Swdenk case 3: 27371f95118Swdenk ret = FAT2CPU16(((__u16*)mydata->fatbuf)[off16]);; 27471f95118Swdenk ret = (ret & 0xfff0) >> 4; 27571f95118Swdenk break; 27671f95118Swdenk default: 27771f95118Swdenk break; 27871f95118Swdenk } 27971f95118Swdenk } 28071f95118Swdenk break; 28171f95118Swdenk } 28271f95118Swdenk FAT_DPRINT("ret: %d, offset: %d\n", ret, offset); 28371f95118Swdenk 28471f95118Swdenk return ret; 28571f95118Swdenk } 28671f95118Swdenk 28771f95118Swdenk 28871f95118Swdenk /* 28971f95118Swdenk * Read at most 'size' bytes from the specified cluster into 'buffer'. 29071f95118Swdenk * Return 0 on success, -1 otherwise. 29171f95118Swdenk */ 29271f95118Swdenk static int 29371f95118Swdenk get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size) 29471f95118Swdenk { 29571f95118Swdenk int idx = 0; 29671f95118Swdenk __u32 startsect; 29771f95118Swdenk 29871f95118Swdenk if (clustnum > 0) { 29971f95118Swdenk startsect = mydata->data_begin + clustnum*mydata->clust_size; 30071f95118Swdenk } else { 30171f95118Swdenk startsect = mydata->rootdir_sect; 30271f95118Swdenk } 30371f95118Swdenk 30471f95118Swdenk FAT_DPRINT("gc - clustnum: %d, startsect: %d\n", clustnum, startsect); 3057205e407Swdenk if (disk_read(startsect, size/FS_BLOCK_SIZE , buffer) < 0) { 30671f95118Swdenk FAT_DPRINT("Error reading data\n"); 30771f95118Swdenk return -1; 30871f95118Swdenk } 3097205e407Swdenk if(size % FS_BLOCK_SIZE) { 31071f95118Swdenk __u8 tmpbuf[FS_BLOCK_SIZE]; 3117205e407Swdenk idx= size/FS_BLOCK_SIZE; 31271f95118Swdenk if (disk_read(startsect + idx, 1, tmpbuf) < 0) { 31371f95118Swdenk FAT_DPRINT("Error reading data\n"); 31471f95118Swdenk return -1; 31571f95118Swdenk } 3167205e407Swdenk buffer += idx*FS_BLOCK_SIZE; 31771f95118Swdenk 3187205e407Swdenk memcpy(buffer, tmpbuf, size % FS_BLOCK_SIZE); 31971f95118Swdenk return 0; 32071f95118Swdenk } 32171f95118Swdenk 32271f95118Swdenk return 0; 32371f95118Swdenk } 32471f95118Swdenk 32571f95118Swdenk 32671f95118Swdenk /* 32771f95118Swdenk * Read at most 'maxsize' bytes from the file associated with 'dentptr' 32871f95118Swdenk * into 'buffer'. 32971f95118Swdenk * Return the number of bytes read or -1 on fatal errors. 33071f95118Swdenk */ 33171f95118Swdenk static long 33271f95118Swdenk get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, 33371f95118Swdenk unsigned long maxsize) 33471f95118Swdenk { 33571f95118Swdenk unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0; 33671f95118Swdenk unsigned int bytesperclust = mydata->clust_size * SECTOR_SIZE; 33771f95118Swdenk __u32 curclust = START(dentptr); 3387205e407Swdenk __u32 endclust, newclust; 3397205e407Swdenk unsigned long actsize; 34071f95118Swdenk 34171f95118Swdenk FAT_DPRINT("Filesize: %ld bytes\n", filesize); 34271f95118Swdenk 34371f95118Swdenk if (maxsize > 0 && filesize > maxsize) filesize = maxsize; 34471f95118Swdenk 34571f95118Swdenk FAT_DPRINT("Reading: %ld bytes\n", filesize); 34671f95118Swdenk 3477205e407Swdenk actsize=bytesperclust; 3487205e407Swdenk endclust=curclust; 34971f95118Swdenk do { 3507205e407Swdenk /* search for consecutive clusters */ 3517205e407Swdenk while(actsize < filesize) { 3527205e407Swdenk newclust = get_fatent(mydata, endclust); 3537205e407Swdenk if((newclust -1)!=endclust) 3547205e407Swdenk goto getit; 3558ce4e5c2Smichael if (CHECK_CLUST(newclust, mydata->fatsize)) { 3567205e407Swdenk FAT_DPRINT("curclust: 0x%x\n", newclust); 3577205e407Swdenk FAT_DPRINT("Invalid FAT entry\n"); 3587205e407Swdenk return gotsize; 3597205e407Swdenk } 3607205e407Swdenk endclust=newclust; 3617205e407Swdenk actsize+= bytesperclust; 3627205e407Swdenk } 3637205e407Swdenk /* actsize >= file size */ 3647205e407Swdenk actsize -= bytesperclust; 3657205e407Swdenk /* get remaining clusters */ 3667205e407Swdenk if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 36771f95118Swdenk FAT_ERROR("Error reading cluster\n"); 36871f95118Swdenk return -1; 36971f95118Swdenk } 3707205e407Swdenk /* get remaining bytes */ 3717205e407Swdenk gotsize += (int)actsize; 3727205e407Swdenk filesize -= actsize; 3737205e407Swdenk buffer += actsize; 3747205e407Swdenk actsize= filesize; 3757205e407Swdenk if (get_cluster(mydata, endclust, buffer, (int)actsize) != 0) { 3767205e407Swdenk FAT_ERROR("Error reading cluster\n"); 3777205e407Swdenk return -1; 3787205e407Swdenk } 3797205e407Swdenk gotsize+=actsize; 3807205e407Swdenk return gotsize; 3817205e407Swdenk getit: 3827205e407Swdenk if (get_cluster(mydata, curclust, buffer, (int)actsize) != 0) { 3837205e407Swdenk FAT_ERROR("Error reading cluster\n"); 3847205e407Swdenk return -1; 3857205e407Swdenk } 3867205e407Swdenk gotsize += (int)actsize; 3877205e407Swdenk filesize -= actsize; 3887205e407Swdenk buffer += actsize; 3897205e407Swdenk curclust = get_fatent(mydata, endclust); 3908ce4e5c2Smichael if (CHECK_CLUST(curclust, mydata->fatsize)) { 39171f95118Swdenk FAT_DPRINT("curclust: 0x%x\n", curclust); 39271f95118Swdenk FAT_ERROR("Invalid FAT entry\n"); 39371f95118Swdenk return gotsize; 39471f95118Swdenk } 3957205e407Swdenk actsize=bytesperclust; 3967205e407Swdenk endclust=curclust; 39771f95118Swdenk } while (1); 39871f95118Swdenk } 39971f95118Swdenk 40071f95118Swdenk 40171f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 40271f95118Swdenk /* 40371f95118Swdenk * Extract the file name information from 'slotptr' into 'l_name', 40471f95118Swdenk * starting at l_name[*idx]. 40571f95118Swdenk * Return 1 if terminator (zero byte) is found, 0 otherwise. 40671f95118Swdenk */ 40771f95118Swdenk static int 40871f95118Swdenk slot2str(dir_slot *slotptr, char *l_name, int *idx) 40971f95118Swdenk { 41071f95118Swdenk int j; 41171f95118Swdenk 41271f95118Swdenk for (j = 0; j <= 8; j += 2) { 41371f95118Swdenk l_name[*idx] = slotptr->name0_4[j]; 41471f95118Swdenk if (l_name[*idx] == 0x00) return 1; 41571f95118Swdenk (*idx)++; 41671f95118Swdenk } 41771f95118Swdenk for (j = 0; j <= 10; j += 2) { 41871f95118Swdenk l_name[*idx] = slotptr->name5_10[j]; 41971f95118Swdenk if (l_name[*idx] == 0x00) return 1; 42071f95118Swdenk (*idx)++; 42171f95118Swdenk } 42271f95118Swdenk for (j = 0; j <= 2; j += 2) { 42371f95118Swdenk l_name[*idx] = slotptr->name11_12[j]; 42471f95118Swdenk if (l_name[*idx] == 0x00) return 1; 42571f95118Swdenk (*idx)++; 42671f95118Swdenk } 42771f95118Swdenk 42871f95118Swdenk return 0; 42971f95118Swdenk } 43071f95118Swdenk 43171f95118Swdenk 43271f95118Swdenk /* 43371f95118Swdenk * Extract the full long filename starting at 'retdent' (which is really 43471f95118Swdenk * a slot) into 'l_name'. If successful also copy the real directory entry 43571f95118Swdenk * into 'retdent' 43671f95118Swdenk * Return 0 on success, -1 otherwise. 43771f95118Swdenk */ 4387e4b9b4fSBryan Wu __attribute__ ((__aligned__(__alignof__(dir_entry)))) 4395fa66df6Swdenk __u8 get_vfatname_block[MAX_CLUSTSIZE]; 44071f95118Swdenk static int 44171f95118Swdenk get_vfatname(fsdata *mydata, int curclust, __u8 *cluster, 44271f95118Swdenk dir_entry *retdent, char *l_name) 44371f95118Swdenk { 44471f95118Swdenk dir_entry *realdent; 44571f95118Swdenk dir_slot *slotptr = (dir_slot*) retdent; 44671f95118Swdenk __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE; 4472d1a537dSwdenk __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; 44871f95118Swdenk int idx = 0; 44971f95118Swdenk 45071f95118Swdenk while ((__u8*)slotptr < nextclust) { 45171f95118Swdenk if (counter == 0) break; 4522d1a537dSwdenk if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) 4532d1a537dSwdenk return -1; 45471f95118Swdenk slotptr++; 45571f95118Swdenk counter--; 45671f95118Swdenk } 45771f95118Swdenk 45871f95118Swdenk if ((__u8*)slotptr >= nextclust) { 45971f95118Swdenk dir_slot *slotptr2; 46071f95118Swdenk 46171f95118Swdenk slotptr--; 46271f95118Swdenk curclust = get_fatent(mydata, curclust); 4638ce4e5c2Smichael if (CHECK_CLUST(curclust, mydata->fatsize)) { 46471f95118Swdenk FAT_DPRINT("curclust: 0x%x\n", curclust); 46571f95118Swdenk FAT_ERROR("Invalid FAT entry\n"); 46671f95118Swdenk return -1; 46771f95118Swdenk } 4685fa66df6Swdenk if (get_cluster(mydata, curclust, get_vfatname_block, 46971f95118Swdenk mydata->clust_size * SECTOR_SIZE) != 0) { 47071f95118Swdenk FAT_DPRINT("Error: reading directory block\n"); 47171f95118Swdenk return -1; 47271f95118Swdenk } 4735fa66df6Swdenk slotptr2 = (dir_slot*) get_vfatname_block; 47471f95118Swdenk while (slotptr2->id > 0x01) { 47571f95118Swdenk slotptr2++; 47671f95118Swdenk } 47771f95118Swdenk /* Save the real directory entry */ 47871f95118Swdenk realdent = (dir_entry*)slotptr2 + 1; 4795fa66df6Swdenk while ((__u8*)slotptr2 >= get_vfatname_block) { 48071f95118Swdenk slot2str(slotptr2, l_name, &idx); 48171f95118Swdenk slotptr2--; 48271f95118Swdenk } 48371f95118Swdenk } else { 48471f95118Swdenk /* Save the real directory entry */ 48571f95118Swdenk realdent = (dir_entry*)slotptr; 48671f95118Swdenk } 48771f95118Swdenk 48871f95118Swdenk do { 48971f95118Swdenk slotptr--; 49071f95118Swdenk if (slot2str(slotptr, l_name, &idx)) break; 4912d1a537dSwdenk } while (!(slotptr->id & LAST_LONG_ENTRY_MASK)); 49271f95118Swdenk 49371f95118Swdenk l_name[idx] = '\0'; 49471f95118Swdenk if (*l_name == DELETED_FLAG) *l_name = '\0'; 4953c2c2f42SRemy Bohmer else if (*l_name == aRING) *l_name = DELETED_FLAG; 49671f95118Swdenk downcase(l_name); 49771f95118Swdenk 49871f95118Swdenk /* Return the real directory entry */ 49971f95118Swdenk memcpy(retdent, realdent, sizeof(dir_entry)); 50071f95118Swdenk 50171f95118Swdenk return 0; 50271f95118Swdenk } 50371f95118Swdenk 50471f95118Swdenk 50571f95118Swdenk /* Calculate short name checksum */ 50671f95118Swdenk static __u8 50771f95118Swdenk mkcksum(const char *str) 50871f95118Swdenk { 50971f95118Swdenk int i; 51071f95118Swdenk __u8 ret = 0; 51171f95118Swdenk 51271f95118Swdenk for (i = 0; i < 11; i++) { 51371f95118Swdenk ret = (((ret&1)<<7)|((ret&0xfe)>>1)) + str[i]; 51471f95118Swdenk } 51571f95118Swdenk 51671f95118Swdenk return ret; 51771f95118Swdenk } 51871f95118Swdenk #endif 51971f95118Swdenk 52071f95118Swdenk 52171f95118Swdenk /* 52271f95118Swdenk * Get the directory entry associated with 'filename' from the directory 52371f95118Swdenk * starting at 'startsect' 52471f95118Swdenk */ 5257e4b9b4fSBryan Wu __attribute__ ((__aligned__(__alignof__(dir_entry)))) 5265fa66df6Swdenk __u8 get_dentfromdir_block[MAX_CLUSTSIZE]; 52771f95118Swdenk static dir_entry *get_dentfromdir (fsdata * mydata, int startsect, 52871f95118Swdenk char *filename, dir_entry * retdent, 52971f95118Swdenk int dols) 53071f95118Swdenk { 53171f95118Swdenk __u16 prevcksum = 0xffff; 53271f95118Swdenk __u32 curclust = START (retdent); 53371f95118Swdenk int files = 0, dirs = 0; 53471f95118Swdenk 53571f95118Swdenk FAT_DPRINT ("get_dentfromdir: %s\n", filename); 53671f95118Swdenk while (1) { 53771f95118Swdenk dir_entry *dentptr; 53871f95118Swdenk int i; 53971f95118Swdenk 5405fa66df6Swdenk if (get_cluster (mydata, curclust, get_dentfromdir_block, 54171f95118Swdenk mydata->clust_size * SECTOR_SIZE) != 0) { 54271f95118Swdenk FAT_DPRINT ("Error: reading directory block\n"); 54371f95118Swdenk return NULL; 54471f95118Swdenk } 5455fa66df6Swdenk dentptr = (dir_entry *) get_dentfromdir_block; 54671f95118Swdenk for (i = 0; i < DIRENTSPERCLUST; i++) { 54771f95118Swdenk char s_name[14], l_name[256]; 54871f95118Swdenk 54971f95118Swdenk l_name[0] = '\0'; 550855a496fSwdenk if (dentptr->name[0] == DELETED_FLAG) { 551855a496fSwdenk dentptr++; 552855a496fSwdenk continue; 553855a496fSwdenk } 55471f95118Swdenk if ((dentptr->attr & ATTR_VOLUME)) { 55571f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 55671f95118Swdenk if ((dentptr->attr & ATTR_VFAT) && 5572d1a537dSwdenk (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 55871f95118Swdenk prevcksum = ((dir_slot *) dentptr) 55971f95118Swdenk ->alias_checksum; 5605fa66df6Swdenk get_vfatname (mydata, curclust, get_dentfromdir_block, 56171f95118Swdenk dentptr, l_name); 56271f95118Swdenk if (dols) { 56371f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 56471f95118Swdenk char dirc; 56571f95118Swdenk int doit = 0; 56671f95118Swdenk 56771f95118Swdenk if (isdir) { 56871f95118Swdenk dirs++; 56971f95118Swdenk dirc = '/'; 57071f95118Swdenk doit = 1; 57171f95118Swdenk } else { 57271f95118Swdenk dirc = ' '; 57371f95118Swdenk if (l_name[0] != 0) { 57471f95118Swdenk files++; 57571f95118Swdenk doit = 1; 57671f95118Swdenk } 57771f95118Swdenk } 57871f95118Swdenk if (doit) { 57971f95118Swdenk if (dirc == ' ') { 58071f95118Swdenk printf (" %8ld %s%c\n", 58171f95118Swdenk (long) FAT2CPU32 (dentptr->size), 58271f95118Swdenk l_name, dirc); 58371f95118Swdenk } else { 58471f95118Swdenk printf (" %s%c\n", l_name, dirc); 58571f95118Swdenk } 58671f95118Swdenk } 58771f95118Swdenk dentptr++; 58871f95118Swdenk continue; 58971f95118Swdenk } 59071f95118Swdenk FAT_DPRINT ("vfatname: |%s|\n", l_name); 59171f95118Swdenk } else 59271f95118Swdenk #endif 59371f95118Swdenk { 59471f95118Swdenk /* Volume label or VFAT entry */ 59571f95118Swdenk dentptr++; 59671f95118Swdenk continue; 59771f95118Swdenk } 59871f95118Swdenk } 59971f95118Swdenk if (dentptr->name[0] == 0) { 60071f95118Swdenk if (dols) { 60171f95118Swdenk printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); 60271f95118Swdenk } 60371f95118Swdenk FAT_DPRINT ("Dentname == NULL - %d\n", i); 60471f95118Swdenk return NULL; 60571f95118Swdenk } 60671f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 60771f95118Swdenk if (dols && mkcksum (dentptr->name) == prevcksum) { 60871f95118Swdenk dentptr++; 60971f95118Swdenk continue; 61071f95118Swdenk } 61171f95118Swdenk #endif 61271f95118Swdenk get_name (dentptr, s_name); 61371f95118Swdenk if (dols) { 61471f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 61571f95118Swdenk char dirc; 61671f95118Swdenk int doit = 0; 61771f95118Swdenk 61871f95118Swdenk if (isdir) { 61971f95118Swdenk dirs++; 62071f95118Swdenk dirc = '/'; 62171f95118Swdenk doit = 1; 62271f95118Swdenk } else { 62371f95118Swdenk dirc = ' '; 62471f95118Swdenk if (s_name[0] != 0) { 62571f95118Swdenk files++; 62671f95118Swdenk doit = 1; 62771f95118Swdenk } 62871f95118Swdenk } 62971f95118Swdenk if (doit) { 63071f95118Swdenk if (dirc == ' ') { 63171f95118Swdenk printf (" %8ld %s%c\n", 63271f95118Swdenk (long) FAT2CPU32 (dentptr->size), s_name, 63371f95118Swdenk dirc); 63471f95118Swdenk } else { 63571f95118Swdenk printf (" %s%c\n", s_name, dirc); 63671f95118Swdenk } 63771f95118Swdenk } 63871f95118Swdenk dentptr++; 63971f95118Swdenk continue; 64071f95118Swdenk } 64171f95118Swdenk if (strcmp (filename, s_name) && strcmp (filename, l_name)) { 64271f95118Swdenk FAT_DPRINT ("Mismatch: |%s|%s|\n", s_name, l_name); 64371f95118Swdenk dentptr++; 64471f95118Swdenk continue; 64571f95118Swdenk } 64671f95118Swdenk memcpy (retdent, dentptr, sizeof (dir_entry)); 64771f95118Swdenk 64871f95118Swdenk FAT_DPRINT ("DentName: %s", s_name); 64971f95118Swdenk FAT_DPRINT (", start: 0x%x", START (dentptr)); 65071f95118Swdenk FAT_DPRINT (", size: 0x%x %s\n", 65171f95118Swdenk FAT2CPU32 (dentptr->size), 65271f95118Swdenk (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); 65371f95118Swdenk 65471f95118Swdenk return retdent; 65571f95118Swdenk } 65671f95118Swdenk curclust = get_fatent (mydata, curclust); 6578ce4e5c2Smichael if (CHECK_CLUST(curclust, mydata->fatsize)) { 65871f95118Swdenk FAT_DPRINT ("curclust: 0x%x\n", curclust); 65971f95118Swdenk FAT_ERROR ("Invalid FAT entry\n"); 66071f95118Swdenk return NULL; 66171f95118Swdenk } 66271f95118Swdenk } 66371f95118Swdenk 66471f95118Swdenk return NULL; 66571f95118Swdenk } 66671f95118Swdenk 66771f95118Swdenk 66871f95118Swdenk /* 66971f95118Swdenk * Read boot sector and volume info from a FAT filesystem 67071f95118Swdenk */ 67171f95118Swdenk static int 67271f95118Swdenk read_bootsectandvi(boot_sector *bs, volume_info *volinfo, int *fatsize) 67371f95118Swdenk { 67471f95118Swdenk __u8 block[FS_BLOCK_SIZE]; 67571f95118Swdenk volume_info *vistart; 67665f7d410SWolfgang Denk char *fstype; 67771f95118Swdenk 67871f95118Swdenk if (disk_read(0, 1, block) < 0) { 67971f95118Swdenk FAT_DPRINT("Error: reading block\n"); 68071f95118Swdenk return -1; 68171f95118Swdenk } 68271f95118Swdenk 68371f95118Swdenk memcpy(bs, block, sizeof(boot_sector)); 68471f95118Swdenk bs->reserved = FAT2CPU16(bs->reserved); 68571f95118Swdenk bs->fat_length = FAT2CPU16(bs->fat_length); 68671f95118Swdenk bs->secs_track = FAT2CPU16(bs->secs_track); 68771f95118Swdenk bs->heads = FAT2CPU16(bs->heads); 68871f95118Swdenk #if 0 /* UNUSED */ 68971f95118Swdenk bs->hidden = FAT2CPU32(bs->hidden); 69071f95118Swdenk #endif 69171f95118Swdenk bs->total_sect = FAT2CPU32(bs->total_sect); 69271f95118Swdenk 69371f95118Swdenk /* FAT32 entries */ 69471f95118Swdenk if (bs->fat_length == 0) { 69571f95118Swdenk /* Assume FAT32 */ 69671f95118Swdenk bs->fat32_length = FAT2CPU32(bs->fat32_length); 69771f95118Swdenk bs->flags = FAT2CPU16(bs->flags); 69871f95118Swdenk bs->root_cluster = FAT2CPU32(bs->root_cluster); 69971f95118Swdenk bs->info_sector = FAT2CPU16(bs->info_sector); 70071f95118Swdenk bs->backup_boot = FAT2CPU16(bs->backup_boot); 70171f95118Swdenk vistart = (volume_info*) (block + sizeof(boot_sector)); 70271f95118Swdenk *fatsize = 32; 70371f95118Swdenk } else { 70471f95118Swdenk vistart = (volume_info*) &(bs->fat32_length); 70571f95118Swdenk *fatsize = 0; 70671f95118Swdenk } 70771f95118Swdenk memcpy(volinfo, vistart, sizeof(volume_info)); 70871f95118Swdenk 70965f7d410SWolfgang Denk /* 71065f7d410SWolfgang Denk * Terminate fs_type string. Writing past the end of vistart 71165f7d410SWolfgang Denk * is ok - it's just the buffer. 71265f7d410SWolfgang Denk */ 71365f7d410SWolfgang Denk fstype = vistart->fs_type; 71465f7d410SWolfgang Denk fstype[8] = '\0'; 71571f95118Swdenk 71671f95118Swdenk if (*fatsize == 32) { 71771f95118Swdenk if (compare_sign(FAT32_SIGN, vistart->fs_type) == 0) { 71871f95118Swdenk return 0; 71971f95118Swdenk } 72071f95118Swdenk } else { 72171f95118Swdenk if (compare_sign(FAT12_SIGN, vistart->fs_type) == 0) { 72271f95118Swdenk *fatsize = 12; 72371f95118Swdenk return 0; 72471f95118Swdenk } 72571f95118Swdenk if (compare_sign(FAT16_SIGN, vistart->fs_type) == 0) { 72671f95118Swdenk *fatsize = 16; 72771f95118Swdenk return 0; 72871f95118Swdenk } 72971f95118Swdenk } 73071f95118Swdenk 73171f95118Swdenk FAT_DPRINT("Error: broken fs_type sign\n"); 73271f95118Swdenk return -1; 73371f95118Swdenk } 73471f95118Swdenk 7357e4b9b4fSBryan Wu __attribute__ ((__aligned__(__alignof__(dir_entry)))) 7367e4b9b4fSBryan Wu __u8 do_fat_read_block[MAX_CLUSTSIZE]; 73720cc00ddSstroese long 73871f95118Swdenk do_fat_read (const char *filename, void *buffer, unsigned long maxsize, 73971f95118Swdenk int dols) 74071f95118Swdenk { 741d06a5f7eSWolfgang Denk #if CONFIG_NIOS /* NIOS CPU cannot access big automatic arrays */ 742d06a5f7eSWolfgang Denk static 743d06a5f7eSWolfgang Denk #endif 74471f95118Swdenk char fnamecopy[2048]; 74571f95118Swdenk boot_sector bs; 74671f95118Swdenk volume_info volinfo; 74771f95118Swdenk fsdata datablock; 74871f95118Swdenk fsdata *mydata = &datablock; 74971f95118Swdenk dir_entry *dentptr; 75071f95118Swdenk __u16 prevcksum = 0xffff; 75171f95118Swdenk char *subname = ""; 75271f95118Swdenk int rootdir_size, cursect; 75371f95118Swdenk int idx, isdir = 0; 75471f95118Swdenk int files = 0, dirs = 0; 75571f95118Swdenk long ret = 0; 75671f95118Swdenk int firsttime; 75771f95118Swdenk 75871f95118Swdenk if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { 75971f95118Swdenk FAT_DPRINT ("Error: reading boot sector\n"); 76071f95118Swdenk return -1; 76171f95118Swdenk } 76271f95118Swdenk if (mydata->fatsize == 32) { 76371f95118Swdenk mydata->fatlength = bs.fat32_length; 76471f95118Swdenk } else { 76571f95118Swdenk mydata->fatlength = bs.fat_length; 76671f95118Swdenk } 76771f95118Swdenk mydata->fat_sect = bs.reserved; 76871f95118Swdenk cursect = mydata->rootdir_sect 76971f95118Swdenk = mydata->fat_sect + mydata->fatlength * bs.fats; 77071f95118Swdenk mydata->clust_size = bs.cluster_size; 77171f95118Swdenk if (mydata->fatsize == 32) { 77271f95118Swdenk rootdir_size = mydata->clust_size; 77371f95118Swdenk mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */ 77471f95118Swdenk - (mydata->clust_size * 2); 77571f95118Swdenk } else { 77671f95118Swdenk rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0]) 77771f95118Swdenk * sizeof (dir_entry)) / SECTOR_SIZE; 77871f95118Swdenk mydata->data_begin = mydata->rootdir_sect + rootdir_size 77971f95118Swdenk - (mydata->clust_size * 2); 78071f95118Swdenk } 78171f95118Swdenk mydata->fatbufnum = -1; 78271f95118Swdenk 78371f95118Swdenk FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize, 78471f95118Swdenk mydata->fatlength); 78571f95118Swdenk FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n" 78671f95118Swdenk "Data begins at: %d\n", 78771f95118Swdenk mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE, 78871f95118Swdenk rootdir_size, mydata->data_begin); 78971f95118Swdenk FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size); 79071f95118Swdenk 79171f95118Swdenk /* "cwd" is always the root... */ 79271f95118Swdenk while (ISDIRDELIM (*filename)) 79371f95118Swdenk filename++; 79471f95118Swdenk /* Make a copy of the filename and convert it to lowercase */ 79571f95118Swdenk strcpy (fnamecopy, filename); 79671f95118Swdenk downcase (fnamecopy); 79771f95118Swdenk if (*fnamecopy == '\0') { 79871f95118Swdenk if (!dols) 79971f95118Swdenk return -1; 80071f95118Swdenk dols = LS_ROOT; 80171f95118Swdenk } else if ((idx = dirdelim (fnamecopy)) >= 0) { 80271f95118Swdenk isdir = 1; 80371f95118Swdenk fnamecopy[idx] = '\0'; 80471f95118Swdenk subname = fnamecopy + idx + 1; 80571f95118Swdenk /* Handle multiple delimiters */ 80671f95118Swdenk while (ISDIRDELIM (*subname)) 80771f95118Swdenk subname++; 80871f95118Swdenk } else if (dols) { 80971f95118Swdenk isdir = 1; 81071f95118Swdenk } 81171f95118Swdenk 81271f95118Swdenk while (1) { 81371f95118Swdenk int i; 81471f95118Swdenk 8155fa66df6Swdenk if (disk_read (cursect, mydata->clust_size, do_fat_read_block) < 0) { 81671f95118Swdenk FAT_DPRINT ("Error: reading rootdir block\n"); 81771f95118Swdenk return -1; 81871f95118Swdenk } 8195fa66df6Swdenk dentptr = (dir_entry *) do_fat_read_block; 82071f95118Swdenk for (i = 0; i < DIRENTSPERBLOCK; i++) { 82171f95118Swdenk char s_name[14], l_name[256]; 82271f95118Swdenk 82371f95118Swdenk l_name[0] = '\0'; 82471f95118Swdenk if ((dentptr->attr & ATTR_VOLUME)) { 82571f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 82671f95118Swdenk if ((dentptr->attr & ATTR_VFAT) && 8272d1a537dSwdenk (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) { 82871f95118Swdenk prevcksum = ((dir_slot *) dentptr)->alias_checksum; 8295fa66df6Swdenk get_vfatname (mydata, 0, do_fat_read_block, dentptr, l_name); 83071f95118Swdenk if (dols == LS_ROOT) { 83171f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 83271f95118Swdenk char dirc; 83371f95118Swdenk int doit = 0; 83471f95118Swdenk 83571f95118Swdenk if (isdir) { 83671f95118Swdenk dirs++; 83771f95118Swdenk dirc = '/'; 83871f95118Swdenk doit = 1; 83971f95118Swdenk } else { 84071f95118Swdenk dirc = ' '; 84171f95118Swdenk if (l_name[0] != 0) { 84271f95118Swdenk files++; 84371f95118Swdenk doit = 1; 84471f95118Swdenk } 84571f95118Swdenk } 84671f95118Swdenk if (doit) { 84771f95118Swdenk if (dirc == ' ') { 84871f95118Swdenk printf (" %8ld %s%c\n", 84971f95118Swdenk (long) FAT2CPU32 (dentptr->size), 85071f95118Swdenk l_name, dirc); 85171f95118Swdenk } else { 85271f95118Swdenk printf (" %s%c\n", l_name, dirc); 85371f95118Swdenk } 85471f95118Swdenk } 85571f95118Swdenk dentptr++; 85671f95118Swdenk continue; 85771f95118Swdenk } 85871f95118Swdenk FAT_DPRINT ("Rootvfatname: |%s|\n", l_name); 85971f95118Swdenk } else 86071f95118Swdenk #endif 86171f95118Swdenk { 86271f95118Swdenk /* Volume label or VFAT entry */ 86371f95118Swdenk dentptr++; 86471f95118Swdenk continue; 86571f95118Swdenk } 86671f95118Swdenk } else if (dentptr->name[0] == 0) { 86771f95118Swdenk FAT_DPRINT ("RootDentname == NULL - %d\n", i); 86871f95118Swdenk if (dols == LS_ROOT) { 86971f95118Swdenk printf ("\n%d file(s), %d dir(s)\n\n", files, dirs); 87071f95118Swdenk return 0; 87171f95118Swdenk } 87271f95118Swdenk return -1; 87371f95118Swdenk } 87471f95118Swdenk #ifdef CONFIG_SUPPORT_VFAT 87571f95118Swdenk else if (dols == LS_ROOT 87671f95118Swdenk && mkcksum (dentptr->name) == prevcksum) { 87771f95118Swdenk dentptr++; 87871f95118Swdenk continue; 87971f95118Swdenk } 88071f95118Swdenk #endif 88171f95118Swdenk get_name (dentptr, s_name); 88271f95118Swdenk if (dols == LS_ROOT) { 88371f95118Swdenk int isdir = (dentptr->attr & ATTR_DIR); 88471f95118Swdenk char dirc; 88571f95118Swdenk int doit = 0; 88671f95118Swdenk 88771f95118Swdenk if (isdir) { 88871f95118Swdenk dirc = '/'; 889a43278a4Swdenk if (s_name[0] != 0) { 890a43278a4Swdenk dirs++; 89171f95118Swdenk doit = 1; 892a43278a4Swdenk } 89371f95118Swdenk } else { 89471f95118Swdenk dirc = ' '; 89571f95118Swdenk if (s_name[0] != 0) { 89671f95118Swdenk files++; 89771f95118Swdenk doit = 1; 89871f95118Swdenk } 89971f95118Swdenk } 90071f95118Swdenk if (doit) { 90171f95118Swdenk if (dirc == ' ') { 90271f95118Swdenk printf (" %8ld %s%c\n", 90371f95118Swdenk (long) FAT2CPU32 (dentptr->size), s_name, 90471f95118Swdenk dirc); 90571f95118Swdenk } else { 90671f95118Swdenk printf (" %s%c\n", s_name, dirc); 90771f95118Swdenk } 90871f95118Swdenk } 90971f95118Swdenk dentptr++; 91071f95118Swdenk continue; 91171f95118Swdenk } 91271f95118Swdenk if (strcmp (fnamecopy, s_name) && strcmp (fnamecopy, l_name)) { 91371f95118Swdenk FAT_DPRINT ("RootMismatch: |%s|%s|\n", s_name, l_name); 91471f95118Swdenk dentptr++; 91571f95118Swdenk continue; 91671f95118Swdenk } 91771f95118Swdenk if (isdir && !(dentptr->attr & ATTR_DIR)) 91871f95118Swdenk return -1; 91971f95118Swdenk 92071f95118Swdenk FAT_DPRINT ("RootName: %s", s_name); 92171f95118Swdenk FAT_DPRINT (", start: 0x%x", START (dentptr)); 92271f95118Swdenk FAT_DPRINT (", size: 0x%x %s\n", 92371f95118Swdenk FAT2CPU32 (dentptr->size), isdir ? "(DIR)" : ""); 92471f95118Swdenk 92571f95118Swdenk goto rootdir_done; /* We got a match */ 92671f95118Swdenk } 92771f95118Swdenk cursect++; 92871f95118Swdenk } 92971f95118Swdenk rootdir_done: 93071f95118Swdenk 93171f95118Swdenk firsttime = 1; 93271f95118Swdenk while (isdir) { 93371f95118Swdenk int startsect = mydata->data_begin 93471f95118Swdenk + START (dentptr) * mydata->clust_size; 93571f95118Swdenk dir_entry dent; 93671f95118Swdenk char *nextname = NULL; 93771f95118Swdenk 93871f95118Swdenk dent = *dentptr; 93971f95118Swdenk dentptr = &dent; 94071f95118Swdenk 94171f95118Swdenk idx = dirdelim (subname); 94271f95118Swdenk if (idx >= 0) { 94371f95118Swdenk subname[idx] = '\0'; 94471f95118Swdenk nextname = subname + idx + 1; 94571f95118Swdenk /* Handle multiple delimiters */ 94671f95118Swdenk while (ISDIRDELIM (*nextname)) 94771f95118Swdenk nextname++; 94871f95118Swdenk if (dols && *nextname == '\0') 94971f95118Swdenk firsttime = 0; 95071f95118Swdenk } else { 95171f95118Swdenk if (dols && firsttime) { 95271f95118Swdenk firsttime = 0; 95371f95118Swdenk } else { 95471f95118Swdenk isdir = 0; 95571f95118Swdenk } 95671f95118Swdenk } 95771f95118Swdenk 95871f95118Swdenk if (get_dentfromdir (mydata, startsect, subname, dentptr, 95971f95118Swdenk isdir ? 0 : dols) == NULL) { 96071f95118Swdenk if (dols && !isdir) 96171f95118Swdenk return 0; 96271f95118Swdenk return -1; 96371f95118Swdenk } 96471f95118Swdenk 96571f95118Swdenk if (idx >= 0) { 96671f95118Swdenk if (!(dentptr->attr & ATTR_DIR)) 96771f95118Swdenk return -1; 96871f95118Swdenk subname = nextname; 96971f95118Swdenk } 97071f95118Swdenk } 97171f95118Swdenk ret = get_contents (mydata, dentptr, buffer, maxsize); 97271f95118Swdenk FAT_DPRINT ("Size: %d, got: %ld\n", FAT2CPU32 (dentptr->size), ret); 97371f95118Swdenk 97471f95118Swdenk return ret; 97571f95118Swdenk } 97671f95118Swdenk 97771f95118Swdenk 97871f95118Swdenk int 97971f95118Swdenk file_fat_detectfs(void) 98071f95118Swdenk { 98171f95118Swdenk boot_sector bs; 98271f95118Swdenk volume_info volinfo; 98371f95118Swdenk int fatsize; 9847205e407Swdenk char vol_label[12]; 98571f95118Swdenk 9867205e407Swdenk if(cur_dev==NULL) { 9877205e407Swdenk printf("No current device\n"); 9887205e407Swdenk return 1; 9897205e407Swdenk } 990dd60d122SJon Loeliger #if defined(CONFIG_CMD_IDE) || \ 991*75eb82ecSunsik Kim defined(CONFIG_CMD_MG_DISK) || \ 9928c5170a7SSonic Zhang defined(CONFIG_CMD_SATA) || \ 993dd60d122SJon Loeliger defined(CONFIG_CMD_SCSI) || \ 994dd60d122SJon Loeliger defined(CONFIG_CMD_USB) || \ 99521f6f963SAndy Fleming defined(CONFIG_MMC) 9967205e407Swdenk printf("Interface: "); 9977205e407Swdenk switch(cur_dev->if_type) { 9987205e407Swdenk case IF_TYPE_IDE : printf("IDE"); break; 9998c5170a7SSonic Zhang case IF_TYPE_SATA : printf("SATA"); break; 10007205e407Swdenk case IF_TYPE_SCSI : printf("SCSI"); break; 10017205e407Swdenk case IF_TYPE_ATAPI : printf("ATAPI"); break; 10027205e407Swdenk case IF_TYPE_USB : printf("USB"); break; 10037205e407Swdenk case IF_TYPE_DOC : printf("DOC"); break; 10047205e407Swdenk case IF_TYPE_MMC : printf("MMC"); break; 10057205e407Swdenk default : printf("Unknown"); 10067205e407Swdenk } 10077205e407Swdenk printf("\n Device %d: ",cur_dev->dev); 10087205e407Swdenk dev_print(cur_dev); 10097205e407Swdenk #endif 10107205e407Swdenk if(read_bootsectandvi(&bs, &volinfo, &fatsize)) { 10117205e407Swdenk printf("\nNo valid FAT fs found\n"); 10127205e407Swdenk return 1; 10137205e407Swdenk } 10147205e407Swdenk memcpy (vol_label, volinfo.volume_label, 11); 10157205e407Swdenk vol_label[11] = '\0'; 10167205e407Swdenk volinfo.fs_type[5]='\0'; 10173e3b9569SPeter Pearse printf("Partition %d: Filesystem: %s \"%s\"\n" 10183e3b9569SPeter Pearse ,cur_part,volinfo.fs_type,vol_label); 10197205e407Swdenk return 0; 102071f95118Swdenk } 102171f95118Swdenk 102271f95118Swdenk 102371f95118Swdenk int 102471f95118Swdenk file_fat_ls(const char *dir) 102571f95118Swdenk { 102671f95118Swdenk return do_fat_read(dir, NULL, 0, LS_YES); 102771f95118Swdenk } 102871f95118Swdenk 102971f95118Swdenk 103071f95118Swdenk long 103171f95118Swdenk file_fat_read(const char *filename, void *buffer, unsigned long maxsize) 103271f95118Swdenk { 10337205e407Swdenk printf("reading %s\n",filename); 103471f95118Swdenk return do_fat_read(filename, buffer, maxsize, LS_NO); 103571f95118Swdenk } 1036