]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
fs: Fix issue with finding files in FAT32 partition
authorSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Mon, 19 Nov 2018 10:58:55 +0000 (16:28 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Mon, 19 Nov 2018 11:52:30 +0000 (12:52 +0100)
This patch reverts the below commits which were actually revert
to upstream patches. The earlier reverts were peformed for fixing
the FAT16 issue in u-boot. But, with those previous reverts,
the actual and most used FAT32 was broken. The issue is that
u-boot is not able to find all files present in partition, it can
only be able to find few files in partition.
So, this patch workarounds this by reverting the below
commits.

Revert "fat/fs: convert to directory iterators"
(sha1: 9681876a0dc3ca4812714c715c7df7f54460068c)
Revert "fat/fs: move ls to generic implementation"
(sha1: 57bade54516ca9f99cd1118316fa759b1ffe151f)
Revert "fs/fat: fix case for FAT shortnames"
(sha1: f975d9c5c1f992751573d8928f18bc750499c978)

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
fs/fat/fat.c
fs/fat/fat_write.c
fs/fs.c
include/fat.h

index 8d19a5e6d0982e679af22964b19328e425a5b90b..d16883fa10d4af14be4391c33944dbc7d2a65c13 100644 (file)
@@ -29,11 +29,13 @@ static const int vfat_enabled = 0;
 #endif
 
 /*
- * Convert a string to lowercase.
+ * Convert a string to lowercase.  Converts at most 'len' characters,
+ * 'len' may be larger than the length of 'str' if 'str' is NULL
+ * terminated.
  */
-static void downcase(char *str)
+static void downcase(char *str, size_t len)
 {
-       while (*str != '\0') {
+       while (*str != '\0' && len--) {
                *str = tolower(*str);
                str++;
        }
@@ -119,22 +121,6 @@ int fat_register_device(struct blk_desc *dev_desc, int part_no)
        return fat_set_blk_dev(dev_desc, &info);
 }
 
-/*
- * Get the first occurence of a directory delimiter ('/' or '\') in a string.
- * Return index into string if found, -1 otherwise.
- */
-static int dirdelim(char *str)
-{
-       char *start = str;
-
-       while (*str != '\0') {
-               if (ISDIRDELIM(*str))
-                       return str - start;
-               str++;
-       }
-       return -1;
-}
-
 /*
  * Extract zero terminated short name from a directory entry.
  */
@@ -147,10 +133,13 @@ static void get_name(dir_entry *dirent, char *s_name)
        ptr = s_name;
        while (*ptr && *ptr != ' ')
                ptr++;
+       if (dirent->lcase & CASE_LOWER_BASE)
+               downcase(s_name, (unsigned)(ptr - s_name));
        if (dirent->ext[0] && dirent->ext[0] != ' ') {
-               *ptr = '.';
-               ptr++;
+               *ptr++ = '.';
                memcpy(ptr, dirent->ext, 3);
+               if (dirent->lcase & CASE_LOWER_EXT)
+                       downcase(ptr, 3);
                ptr[3] = '\0';
                while (*ptr && *ptr != ' ')
                        ptr++;
@@ -160,7 +149,6 @@ static void get_name(dir_entry *dirent, char *s_name)
                *s_name = '\0';
        else if (*s_name == aRING)
                *s_name = DELETED_FLAG;
-       downcase(s_name);
 }
 
 static int flush_dirty_fat_buffer(fsdata *mydata);
@@ -468,95 +456,6 @@ static int slot2str(dir_slot *slotptr, char *l_name, int *idx)
        return 0;
 }
 
-/*
- * Extract the full long filename starting at 'retdent' (which is really
- * a slot) into 'l_name'. If successful also copy the real directory entry
- * into 'retdent'
- * Return 0 on success, -1 otherwise.
- */
-static int
-get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
-            dir_entry *retdent, char *l_name)
-{
-       dir_entry *realdent;
-       dir_slot *slotptr = (dir_slot *)retdent;
-       __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
-                                                       PREFETCH_BLOCKS :
-                                                       mydata->clust_size);
-       __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
-       int idx = 0;
-
-       if (counter > VFAT_MAXSEQ) {
-               debug("Error: VFAT name is too long\n");
-               return -1;
-       }
-
-       while ((__u8 *)slotptr < buflimit) {
-               if (counter == 0)
-                       break;
-               if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
-                       return -1;
-               slotptr++;
-               counter--;
-       }
-
-       if ((__u8 *)slotptr >= buflimit) {
-               dir_slot *slotptr2;
-
-               if (curclust == 0)
-                       return -1;
-               curclust = get_fatent(mydata, curclust);
-               if (CHECK_CLUST(curclust, mydata->fatsize)) {
-                       debug("curclust: 0x%x\n", curclust);
-                       printf("Invalid FAT entry\n");
-                       return -1;
-               }
-
-               if (get_cluster(mydata, curclust, get_contents_vfatname_block,
-                               mydata->clust_size * mydata->sect_size) != 0) {
-                       debug("Error: reading directory block\n");
-                       return -1;
-               }
-
-               slotptr2 = (dir_slot *)get_contents_vfatname_block;
-               while (counter > 0) {
-                       if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
-                           & 0xff) != counter)
-                               return -1;
-                       slotptr2++;
-                       counter--;
-               }
-
-               /* Save the real directory entry */
-               realdent = (dir_entry *)slotptr2;
-               while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
-                       slotptr2--;
-                       slot2str(slotptr2, l_name, &idx);
-               }
-       } else {
-               /* Save the real directory entry */
-               realdent = (dir_entry *)slotptr;
-       }
-
-       do {
-               slotptr--;
-               if (slot2str(slotptr, l_name, &idx))
-                       break;
-       } while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
-
-       l_name[idx] = '\0';
-       if (*l_name == DELETED_FLAG)
-               *l_name = '\0';
-       else if (*l_name == aRING)
-               *l_name = DELETED_FLAG;
-       downcase(l_name);
-
-       /* Return the real directory entry */
-       memcpy(retdent, realdent, sizeof(dir_entry));
-
-       return 0;
-}
-
 /* Calculate short name checksum */
 static __u8 mkcksum(const char name[8], const char ext[3])
 {
@@ -573,169 +472,13 @@ static __u8 mkcksum(const char name[8], const char ext[3])
 }
 
 /*
- * Get the directory entry associated with 'filename' from the directory
- * starting at 'startsect'
+ * TODO these should go away once fat_write is reworked to use the
+ * directory iterator
  */
 __u8 get_dentfromdir_block[MAX_CLUSTSIZE]
        __aligned(ARCH_DMA_MINALIGN);
-
-static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
-                                 char *filename, dir_entry *retdent,
-                                 int dols)
-{
-       __u16 prevcksum = 0xffff;
-       __u32 curclust = START(retdent);
-       int files = 0, dirs = 0;
-
-       debug("get_dentfromdir: %s\n", filename);
-
-       while (1) {
-               dir_entry *dentptr;
-
-               int i;
-
-               if (get_cluster(mydata, curclust, get_dentfromdir_block,
-                               mydata->clust_size * mydata->sect_size) != 0) {
-                       debug("Error: reading directory block\n");
-                       return NULL;
-               }
-
-               dentptr = (dir_entry *)get_dentfromdir_block;
-
-               for (i = 0; i < DIRENTSPERCLUST; i++) {
-                       char s_name[14], l_name[VFAT_MAXLEN_BYTES];
-
-                       l_name[0] = '\0';
-                       if (dentptr->name[0] == DELETED_FLAG) {
-                               dentptr++;
-                               continue;
-                       }
-                       if ((dentptr->attr & ATTR_VOLUME)) {
-                               if (vfat_enabled &&
-                                   (dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
-                                   (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
-                                       prevcksum = ((dir_slot *)dentptr)->alias_checksum;
-                                       get_vfatname(mydata, curclust,
-                                                    get_dentfromdir_block,
-                                                    dentptr, l_name);
-                                       if (dols) {
-                                               int isdir;
-                                               char dirc;
-                                               int doit = 0;
-
-                                               isdir = (dentptr->attr & ATTR_DIR);
-
-                                               if (isdir) {
-                                                       dirs++;
-                                                       dirc = '/';
-                                                       doit = 1;
-                                               } else {
-                                                       dirc = ' ';
-                                                       if (l_name[0] != 0) {
-                                                               files++;
-                                                               doit = 1;
-                                                       }
-                                               }
-                                               if (doit) {
-                                                       if (dirc == ' ') {
-                                                               printf(" %8u   %s%c\n",
-                                                                      FAT2CPU32(dentptr->size),
-                                                                       l_name,
-                                                                       dirc);
-                                                       } else {
-                                                               printf("            %s%c\n",
-                                                                       l_name,
-                                                                       dirc);
-                                                       }
-                                               }
-                                               dentptr++;
-                                               continue;
-                                       }
-                                       debug("vfatname: |%s|\n", l_name);
-                               } else {
-                                       /* Volume label or VFAT entry */
-                                       dentptr++;
-                                       continue;
-                               }
-                       }
-                       if (dentptr->name[0] == 0) {
-                               if (dols) {
-                                       printf("\n%d file(s), %d dir(s)\n\n",
-                                               files, dirs);
-                               }
-                               debug("Dentname == NULL - %d\n", i);
-                               return NULL;
-                       }
-                       if (vfat_enabled) {
-                               __u8 csum = mkcksum(dentptr->name, dentptr->ext);
-                               if (dols && csum == prevcksum) {
-                                       prevcksum = 0xffff;
-                                       dentptr++;
-                                       continue;
-                               }
-                       }
-
-                       get_name(dentptr, s_name);
-                       if (dols) {
-                               int isdir = (dentptr->attr & ATTR_DIR);
-                               char dirc;
-                               int doit = 0;
-
-                               if (isdir) {
-                                       dirs++;
-                                       dirc = '/';
-                                       doit = 1;
-                               } else {
-                                       dirc = ' ';
-                                       if (s_name[0] != 0) {
-                                               files++;
-                                               doit = 1;
-                                       }
-                               }
-
-                               if (doit) {
-                                       if (dirc == ' ') {
-                                               printf(" %8u   %s%c\n",
-                                                      FAT2CPU32(dentptr->size),
-                                                       s_name, dirc);
-                                       } else {
-                                               printf("            %s%c\n",
-                                                       s_name, dirc);
-                                       }
-                               }
-
-                               dentptr++;
-                               continue;
-                       }
-
-                       if (strcmp(filename, s_name)
-                           && strcmp(filename, l_name)) {
-                               debug("Mismatch: |%s|%s|\n", s_name, l_name);
-                               dentptr++;
-                               continue;
-                       }
-
-                       memcpy(retdent, dentptr, sizeof(dir_entry));
-
-                       debug("DentName: %s", s_name);
-                       debug(", start: 0x%x", START(dentptr));
-                       debug(", size:  0x%x %s\n",
-                             FAT2CPU32(dentptr->size),
-                             (dentptr->attr & ATTR_DIR) ? "(DIR)" : "");
-
-                       return retdent;
-               }
-
-               curclust = get_fatent(mydata, curclust);
-               if (CHECK_CLUST(curclust, mydata->fatsize)) {
-                       debug("curclust: 0x%x\n", curclust);
-                       printf("Invalid FAT entry\n");
-                       return NULL;
-               }
-       }
-
-       return NULL;
-}
+__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
+       __aligned(ARCH_DMA_MINALIGN);
 
 /*
  * Read boot sector and volume info from a FAT filesystem
@@ -878,374 +621,6 @@ static int get_fs_info(fsdata *mydata)
        return 0;
 }
 
-__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
-       __aligned(ARCH_DMA_MINALIGN);
-
-int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
-                  loff_t maxsize, int dols, int dogetsize, loff_t *size)
-{
-       char fnamecopy[2048];
-       fsdata datablock;
-       fsdata *mydata = &datablock;
-       dir_entry *dentptr = NULL;
-       __u16 prevcksum = 0xffff;
-       char *subname = "";
-       __u32 cursect;
-       int idx, isdir = 0;
-       int files = 0, dirs = 0;
-       int ret = -1;
-       int firsttime;
-       __u32 root_cluster = 0;
-       __u32 read_blk;
-       int rootdir_size = 0;
-       int buffer_blk_cnt;
-       int do_read;
-       __u8 *dir_ptr;
-
-       if (get_fs_info(mydata))
-               return -1;
-
-       cursect = mydata->rootdir_sect;
-
-       /* "cwd" is always the root... */
-       while (ISDIRDELIM(*filename))
-               filename++;
-
-       /* Make a copy of the filename and convert it to lowercase */
-       strcpy(fnamecopy, filename);
-       downcase(fnamecopy);
-
-root_reparse:
-       if (*fnamecopy == '\0') {
-               if (!dols)
-                       goto exit;
-
-               dols = LS_ROOT;
-       } else if ((idx = dirdelim(fnamecopy)) >= 0) {
-               isdir = 1;
-               fnamecopy[idx] = '\0';
-               subname = fnamecopy + idx + 1;
-
-               /* Handle multiple delimiters */
-               while (ISDIRDELIM(*subname))
-                       subname++;
-       } else if (dols) {
-               isdir = 1;
-       }
-
-       buffer_blk_cnt = 0;
-       firsttime = 1;
-       while (1) {
-               int i;
-
-               if (mydata->fatsize == 32 || firsttime) {
-                       dir_ptr = do_fat_read_at_block;
-                       firsttime = 0;
-               } else {
-                       /**
-                        * FAT16 sector buffer modification:
-                        * Each loop, the second buffered block is moved to
-                        * the buffer begin, and two next sectors are read
-                        * next to the previously moved one. So the sector
-                        * buffer keeps always 3 sectors for fat16.
-                        * And the current sector is the buffer second sector
-                        * beside the "firsttime" read, when it is the first one.
-                        *
-                        * PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1]
-                        * n = computed root dir sector
-                        * loop |  cursect-1  | cursect    | cursect+1  |
-                        *   0  |  sector n+0 | sector n+1 | none       |
-                        *   1  |  none       | sector n+0 | sector n+1 |
-                        *   0  |  sector n+1 | sector n+2 | sector n+3 |
-                        *   1  |  sector n+3 | ...
-                       */
-                       dir_ptr = (do_fat_read_at_block + mydata->sect_size);
-                       memcpy(do_fat_read_at_block, dir_ptr, mydata->sect_size);
-               }
-
-               do_read = 1;
-
-               if (mydata->fatsize == 32 && buffer_blk_cnt)
-                       do_read = 0;
-
-               if (do_read) {
-                       read_blk = (mydata->fatsize == 32) ?
-                                   mydata->clust_size : PREFETCH_BLOCKS;
-
-                       debug("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
-                               cursect, read_blk, mydata->clust_size, DIRENTSPERBLOCK);
-
-                       if (disk_read(cursect, read_blk, dir_ptr) < 0) {
-                               debug("Error: reading rootdir block\n");
-                               goto exit;
-                       }
-
-                       dentptr = (dir_entry *)dir_ptr;
-               }
-
-               for (i = 0; i < DIRENTSPERBLOCK; i++) {
-                       char s_name[14], l_name[VFAT_MAXLEN_BYTES];
-                       __u8 csum;
-
-                       l_name[0] = '\0';
-                       if (dentptr->name[0] == DELETED_FLAG) {
-                               dentptr++;
-                               continue;
-                       }
-
-                       if (vfat_enabled)
-                               csum = mkcksum(dentptr->name, dentptr->ext);
-
-                       if (dentptr->attr & ATTR_VOLUME) {
-                               if (vfat_enabled &&
-                                   (dentptr->attr & ATTR_VFAT) == ATTR_VFAT &&
-                                   (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
-                                       prevcksum =
-                                               ((dir_slot *)dentptr)->alias_checksum;
-
-                                       get_vfatname(mydata,
-                                                    root_cluster,
-                                                    dir_ptr,
-                                                    dentptr, l_name);
-
-                                       if (dols == LS_ROOT) {
-                                               char dirc;
-                                               int doit = 0;
-                                               int isdir =
-                                                       (dentptr->attr & ATTR_DIR);
-
-                                               if (isdir) {
-                                                       dirs++;
-                                                       dirc = '/';
-                                                       doit = 1;
-                                               } else {
-                                                       dirc = ' ';
-                                                       if (l_name[0] != 0) {
-                                                               files++;
-                                                               doit = 1;
-                                                       }
-                                               }
-                                               if (doit) {
-                                                       if (dirc == ' ') {
-                                                               printf(" %8u   %s%c\n",
-                                                                      FAT2CPU32(dentptr->size),
-                                                                       l_name,
-                                                                       dirc);
-                                                       } else {
-                                                               printf("            %s%c\n",
-                                                                       l_name,
-                                                                       dirc);
-                                                       }
-                                               }
-                                               dentptr++;
-                                               continue;
-                                       }
-                                       debug("Rootvfatname: |%s|\n",
-                                              l_name);
-                               } else {
-                                       /* Volume label or VFAT entry */
-                                       dentptr++;
-                                       continue;
-                               }
-                       } else if (dentptr->name[0] == 0) {
-                               debug("RootDentname == NULL - %d\n", i);
-                               if (dols == LS_ROOT) {
-                                       printf("\n%d file(s), %d dir(s)\n\n",
-                                               files, dirs);
-                                       ret = 0;
-                               }
-                               goto exit;
-                       }
-                       else if (vfat_enabled &&
-                                dols == LS_ROOT && csum == prevcksum) {
-                               prevcksum = 0xffff;
-                               dentptr++;
-                               continue;
-                       }
-
-                       get_name(dentptr, s_name);
-
-                       if (dols == LS_ROOT) {
-                               int isdir = (dentptr->attr & ATTR_DIR);
-                               char dirc;
-                               int doit = 0;
-
-                               if (isdir) {
-                                       dirc = '/';
-                                       if (s_name[0] != 0) {
-                                               dirs++;
-                                               doit = 1;
-                                       }
-                               } else {
-                                       dirc = ' ';
-                                       if (s_name[0] != 0) {
-                                               files++;
-                                               doit = 1;
-                                       }
-                               }
-                               if (doit) {
-                                       if (dirc == ' ') {
-                                               printf(" %8u   %s%c\n",
-                                                      FAT2CPU32(dentptr->size),
-                                                       s_name, dirc);
-                                       } else {
-                                               printf("            %s%c\n",
-                                                       s_name, dirc);
-                                       }
-                               }
-                               dentptr++;
-                               continue;
-                       }
-
-                       if (strcmp(fnamecopy, s_name)
-                           && strcmp(fnamecopy, l_name)) {
-                               debug("RootMismatch: |%s|%s|\n", s_name,
-                                      l_name);
-                               dentptr++;
-                               continue;
-                       }
-
-                       if (isdir && !(dentptr->attr & ATTR_DIR))
-                               goto exit;
-
-                       debug("RootName: %s", s_name);
-                       debug(", start: 0x%x", START(dentptr));
-                       debug(", size:  0x%x %s\n",
-                              FAT2CPU32(dentptr->size),
-                              isdir ? "(DIR)" : "");
-
-                       goto rootdir_done;      /* We got a match */
-               }
-               debug("END LOOP: buffer_blk_cnt=%d   clust_size=%d\n", buffer_blk_cnt,
-                      mydata->clust_size);
-
-               /*
-                * On FAT32 we must fetch the FAT entries for the next
-                * root directory clusters when a cluster has been
-                * completely processed.
-                */
-               ++buffer_blk_cnt;
-               int rootdir_end = 0;
-               if (mydata->fatsize == 32) {
-                       if (buffer_blk_cnt == mydata->clust_size) {
-                               int nxtsect = 0;
-                               int nxt_clust = 0;
-
-                               nxt_clust = get_fatent(mydata, root_cluster);
-                               rootdir_end = CHECK_CLUST(nxt_clust, 32);
-
-                               nxtsect = mydata->data_begin +
-                                       (nxt_clust * mydata->clust_size);
-
-                               root_cluster = nxt_clust;
-
-                               cursect = nxtsect;
-                               buffer_blk_cnt = 0;
-                       }
-               } else {
-                       if (buffer_blk_cnt == PREFETCH_BLOCKS)
-                               buffer_blk_cnt = 0;
-
-                       rootdir_end = (++cursect - mydata->rootdir_sect >=
-                                      rootdir_size);
-               }
-
-               /* If end of rootdir reached */
-               if (rootdir_end) {
-                       if (dols == LS_ROOT) {
-                               printf("\n%d file(s), %d dir(s)\n\n",
-                                      files, dirs);
-                               *size = 0;
-                       }
-                       goto exit;
-               }
-       }
-rootdir_done:
-
-       firsttime = 1;
-
-       while (isdir) {
-               int startsect = mydata->data_begin
-                       + START(dentptr) * mydata->clust_size;
-               dir_entry dent;
-               char *nextname = NULL;
-
-               dent = *dentptr;
-               dentptr = &dent;
-
-               idx = dirdelim(subname);
-
-               if (idx >= 0) {
-                       subname[idx] = '\0';
-                       nextname = subname + idx + 1;
-                       /* Handle multiple delimiters */
-                       while (ISDIRDELIM(*nextname))
-                               nextname++;
-                       if (dols && *nextname == '\0')
-                               firsttime = 0;
-               } else {
-                       if (dols && firsttime) {
-                               firsttime = 0;
-                       } else {
-                               isdir = 0;
-                       }
-               }
-
-               if (get_dentfromdir(mydata, startsect, subname, dentptr,
-                                    isdir ? 0 : dols) == NULL) {
-                       if (dols && !isdir)
-                               *size = 0;
-                       goto exit;
-               }
-
-               if (isdir && !(dentptr->attr & ATTR_DIR))
-                       goto exit;
-
-               /*
-                * If we are looking for a directory, and found a directory
-                * type entry, and the entry is for the root directory (as
-                * denoted by a cluster number of 0), jump back to the start
-                * of the function, since at least on FAT12/16, the root dir
-                * lives in a hard-coded location and needs special handling
-                * to parse, rather than simply following the cluster linked
-                * list in the FAT, like other directories.
-                */
-               if (isdir && (dentptr->attr & ATTR_DIR) && !START(dentptr)) {
-                       /*
-                        * Modify the filename to remove the prefix that gets
-                        * back to the root directory, so the initial root dir
-                        * parsing code can continue from where we are without
-                        * confusion.
-                        */
-                       strcpy(fnamecopy, nextname ?: "");
-                       /*
-                        * Set up state the same way as the function does when
-                        * first started. This is required for the root dir
-                        * parsing code operates in its expected environment.
-                        */
-                       subname = "";
-                       cursect = mydata->rootdir_sect;
-                       isdir = 0;
-                       goto root_reparse;
-               }
-
-               if (idx >= 0)
-                       subname = nextname;
-       }
-
-       if (dogetsize) {
-               *size = FAT2CPU32(dentptr->size);
-               ret = 0;
-       } else {
-               ret = get_contents(mydata, dentptr, pos, buffer, maxsize, size);
-       }
-       debug("Size: %u, got: %llu\n", FAT2CPU32(dentptr->size), *size);
-
-exit:
-       free(mydata->fatbuf);
-       return ret;
-}
-
 
 /*
  * Directory iterator, to simplify filesystem traversal
@@ -1595,12 +970,6 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
        return -ENOENT;
 }
 
-int do_fat_read(const char *filename, void *buffer, loff_t maxsize, int dols,
-               loff_t *actread)
-{
-       return do_fat_read_at(filename, 0, buffer, maxsize, dols, 0, actread);
-}
-
 int file_fat_detectfs(void)
 {
        boot_sector bs;
@@ -1663,33 +1032,88 @@ int file_fat_detectfs(void)
        return 0;
 }
 
-int file_fat_ls(const char *dir)
-{
-       loff_t size;
-
-       return do_fat_read(dir, NULL, 0, LS_YES, &size);
-}
-
 int fat_exists(const char *filename)
 {
+       fsdata fsdata;
+       fat_itr *itr;
        int ret;
-       loff_t size;
 
-       ret = do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, &size);
+       itr = malloc_cache_aligned(sizeof(fat_itr));
+       if (!itr)
+               return 0;
+       ret = fat_itr_root(itr, &fsdata);
+       if (ret)
+               goto out;
+
+       ret = fat_itr_resolve(itr, filename, TYPE_ANY);
+       free(fsdata.fatbuf);
+out:
+       free(itr);
        return ret == 0;
 }
 
 int fat_size(const char *filename, loff_t *size)
 {
-       return do_fat_read_at(filename, 0, NULL, 0, LS_NO, 1, size);
+       fsdata fsdata;
+       fat_itr *itr;
+       int ret;
+
+       itr = malloc_cache_aligned(sizeof(fat_itr));
+       if (!itr)
+               return -ENOMEM;
+       ret = fat_itr_root(itr, &fsdata);
+       if (ret)
+               goto out_free_itr;
+
+       ret = fat_itr_resolve(itr, filename, TYPE_FILE);
+       if (ret) {
+               /*
+                * Directories don't have size, but fs_size() is not
+                * expected to fail if passed a directory path:
+                */
+               free(fsdata.fatbuf);
+               fat_itr_root(itr, &fsdata);
+               if (!fat_itr_resolve(itr, filename, TYPE_DIR)) {
+                       *size = 0;
+                       ret = 0;
+               }
+               goto out_free_both;
+       }
+
+       *size = FAT2CPU32(itr->dent->size);
+out_free_both:
+       free(fsdata.fatbuf);
+out_free_itr:
+       free(itr);
+       return ret;
 }
 
 int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
                     loff_t maxsize, loff_t *actread)
 {
+       fsdata fsdata;
+       fat_itr *itr;
+       int ret;
+
+       itr = malloc_cache_aligned(sizeof(fat_itr));
+       if (!itr)
+               return -ENOMEM;
+       ret = fat_itr_root(itr, &fsdata);
+       if (ret)
+               goto out_free_itr;
+
+       ret = fat_itr_resolve(itr, filename, TYPE_FILE);
+       if (ret)
+               goto out_free_both;
+
        printf("reading %s\n", filename);
-       return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO, 0,
-                             actread);
+       ret = get_contents(&fsdata, itr->dent, pos, buffer, maxsize, actread);
+
+out_free_both:
+       free(fsdata.fatbuf);
+out_free_itr:
+       free(itr);
+       return ret;
 }
 
 int file_fat_read(const char *filename, void *buffer, int maxsize)
index c2151e385cdd33d6325a4fe954824ad3c87368a1..9d2e0ed74c8c7ced6e42759c5f0e39de5349d828 100644 (file)
@@ -345,7 +345,7 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
                *l_name = '\0';
        else if (*l_name == aRING)
                *l_name = DELETED_FLAG;
-       downcase(l_name);
+       downcase(l_name, INT_MAX);
 
        /* Return the real directory entry */
        *retdent = realdent;
@@ -979,7 +979,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,
 
        memcpy(l_filename, filename, name_len);
        l_filename[name_len] = 0; /* terminate the string */
-       downcase(l_filename);
+       downcase(l_filename, INT_MAX);
 
        startsect = mydata->rootdir_sect;
        retdent = find_directory_entry(mydata, startsect,
diff --git a/fs/fs.c b/fs/fs.c
index 4377417e3ed19050cabdea86cc06267af5c5e7cb..9c4d67faf82324c44d051ab4c14ed8734784b0a1 100644 (file)
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -38,6 +38,35 @@ static inline int fs_ls_unsupported(const char *dirname)
        return -1;
 }
 
+/* generic implementation of ls in terms of opendir/readdir/closedir */
+__maybe_unused
+static int fs_ls_generic(const char *dirname)
+{
+       struct fs_dir_stream *dirs;
+       struct fs_dirent *dent;
+       int nfiles = 0, ndirs = 0;
+
+       dirs = fs_opendir(dirname);
+       if (!dirs)
+               return -errno;
+
+       while ((dent = fs_readdir(dirs))) {
+               if (dent->type == FS_DT_DIR) {
+                       printf("            %s/\n", dent->name);
+                       ndirs++;
+               } else {
+                       printf(" %8lld   %s\n", dent->size, dent->name);
+                       nfiles++;
+               }
+       }
+
+       fs_closedir(dirs);
+
+       printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs);
+
+       return 0;
+}
+
 static inline int fs_exists_unsupported(const char *filename)
 {
        return 0;
@@ -124,7 +153,7 @@ static struct fstype_info fstypes[] = {
                .null_dev_desc_ok = false,
                .probe = fat_set_blk_dev,
                .close = fat_close,
-               .ls = file_fat_ls,
+               .ls = fs_ls_generic,
                .exists = fat_exists,
                .size = fat_size,
                .read = fat_read_file,
@@ -134,7 +163,9 @@ static struct fstype_info fstypes[] = {
                .write = fs_write_unsupported,
 #endif
                .uuid = fs_uuid_unsupported,
-               .opendir = fs_opendir_unsupported,
+               .opendir = fat_opendir,
+               .readdir = fat_readdir,
+               .closedir = fat_closedir,
        },
 #endif
 #ifdef CONFIG_FS_EXT4
index 89e891737d60cf3e22db918ca0fef91f8738ee8b..bdeda95e6debebad99523451efdcc14f584d7e44 100644 (file)
@@ -11,6 +11,7 @@
 #define _FAT_H_
 
 #include <asm/byteorder.h>
+#include <fs.h>
 
 #define CONFIG_SUPPORT_VFAT
 /* Maximum Long File Name length supported here is 128 UTF-16 code units */
  */
 #define LAST_LONG_ENTRY_MASK   0x40
 
-/* Flags telling whether we should read a file or list a directory */
-#define LS_NO          0
-#define LS_YES         1
-#define LS_DIR         1
-#define LS_ROOT                2
-
 #define ISDIRDELIM(c)  ((c) == '/' || (c) == '\\')
 
 #define FSTYPE_NONE    (-1)
@@ -133,10 +128,14 @@ typedef struct volume_info
        /* Boot sign comes last, 2 bytes */
 } volume_info;
 
+/* see dir_entry::lcase: */
+#define CASE_LOWER_BASE        8       /* base (name) is lower case */
+#define CASE_LOWER_EXT 16      /* extension is lower case */
+
 typedef struct dir_entry {
        char    name[8],ext[3]; /* Name and extension */
        __u8    attr;           /* Attribute bits */
-       __u8    lcase;          /* Case for base and extension */
+       __u8    lcase;          /* Case for name and ext (CASE_LOWER_x) */
        __u8    ctime_ms;       /* Creation time, milliseconds */
        __u16   ctime;          /* Creation time */
        __u16   cdate;          /* Creation date */
@@ -189,7 +188,6 @@ static inline u32 sect_to_clust(fsdata *fsdata, u32 sect)
 }
 
 int file_fat_detectfs(void);
-int file_fat_ls(const char *dir);
 int fat_exists(const char *filename);
 int fat_size(const char *filename, loff_t *size);
 int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
@@ -202,5 +200,8 @@ int file_fat_write(const char *filename, void *buf, loff_t offset, loff_t len,
                   loff_t *actwrite);
 int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
                  loff_t *actread);
+int fat_opendir(const char *filename, struct fs_dir_stream **dirsp);
+int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
+void fat_closedir(struct fs_dir_stream *dirs);
 void fat_close(void);
 #endif /* _FAT_H_ */