Yes, this is super-hacky. The FAT code is quite ugly, and this doesn't improve things. But it doesn't make it significantly worse either. The better option would be a massive FAT re-write to get rid of the hacky way that fat_file_ls() works. Volunteers welcome.
Signed-off-by: Rob Clark <robdcl...@gmail.com> --- fs/fat/fat.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++----------- fs/fs.c | 2 +- include/fat.h | 4 ++- 3 files changed, 81 insertions(+), 19 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 9ad18f96ff..3d5dde0d9e 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -14,6 +14,7 @@ #include <config.h> #include <exports.h> #include <fat.h> +#include <fs.h> #include <asm/byteorder.h> #include <part.h> #include <malloc.h> @@ -575,17 +576,25 @@ static __u8 mkcksum(const char name[8], const char ext[3]) /* * Get the directory entry associated with 'filename' from the directory * starting at 'startsect' + * + * Last two args are only used for dols==LS_READDIR */ __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) +static dir_entry *get_dentfromdir(fsdata *mydata, char *filename, + dir_entry *retdent, int dols, + loff_t pos, struct fs_dirent *d) { __u16 prevcksum = 0xffff; __u32 curclust = START(retdent); int files = 0, dirs = 0; + int readdir = 0; + + if (dols == LS_READDIR) { + readdir = 1; + dols = 0; + } debug("get_dentfromdir: %s\n", filename); @@ -618,7 +627,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, get_vfatname(mydata, curclust, get_dentfromdir_block, dentptr, l_name); - if (dols) { + if (dols || readdir) { int isdir; char dirc; int doit = 0; @@ -637,7 +646,14 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, } } if (doit) { - if (dirc == ' ') { + if (readdir) { + if ((dirs + files - 1) == pos) { + strcpy(d->name, l_name); + if (!isdir) + d->size = FAT2CPU32(dentptr->size); + return NULL; + } + } else if (dirc == ' ') { printf(" %8u %s%c\n", FAT2CPU32(dentptr->size), l_name, @@ -668,7 +684,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, } if (vfat_enabled) { __u8 csum = mkcksum(dentptr->name, dentptr->ext); - if (dols && csum == prevcksum) { + if ((dols || readdir) && csum == prevcksum) { prevcksum = 0xffff; dentptr++; continue; @@ -676,7 +692,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, } get_name(dentptr, s_name); - if (dols) { + if (dols || readdir) { int isdir = (dentptr->attr & ATTR_DIR); char dirc; int doit = 0; @@ -694,7 +710,14 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect, } if (doit) { - if (dirc == ' ') { + if (readdir) { + if ((dirs + files - 1) == pos) { + strcpy(d->name, s_name); + if (!isdir) + d->size = FAT2CPU32(dentptr->size); + return NULL; + } + } else if (dirc == ' ') { printf(" %8u %s%c\n", FAT2CPU32(dentptr->size), s_name, dirc); @@ -825,13 +848,14 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, __u32 cursect; int idx, isdir = 0; int files = 0, dirs = 0; - int ret = -1; + int ret = (dols == LS_READDIR) ? -ENOTDIR : -1; int firsttime; __u32 root_cluster = 0; __u32 read_blk; int rootdir_size = 0; int buffer_blk_cnt; int do_read; + int readdir = (dols == LS_READDIR); __u8 *dir_ptr; if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) { @@ -1012,7 +1036,16 @@ root_reparse: } } if (doit) { - if (dirc == ' ') { + if (readdir) { + if ((dirs + files - 1) == pos) { + struct fs_dirent *d = buffer; + strcpy(d->name, l_name); + if (!isdir) + d->size = FAT2CPU32(dentptr->size); + ret = 0; + goto exit; + } + } else if (dirc == ' ') { printf(" %8u %s%c\n", FAT2CPU32(dentptr->size), l_name, @@ -1035,7 +1068,9 @@ root_reparse: } } else if (dentptr->name[0] == 0) { debug("RootDentname == NULL - %d\n", i); - if (dols == LS_ROOT) { + if (readdir) { + ret = -ENOENT; + } else if (dols == LS_ROOT) { printf("\n%d file(s), %d dir(s)\n\n", files, dirs); ret = 0; @@ -1070,7 +1105,16 @@ root_reparse: } } if (doit) { - if (dirc == ' ') { + if (readdir) { + if ((dirs + files - 1) == pos) { + struct fs_dirent *d = buffer; + strcpy(d->name, s_name); + if (!isdir) + d->size = FAT2CPU32(dentptr->size); + ret = 0; + goto exit; + } + } else if (dirc == ' ') { printf(" %8u %s%c\n", FAT2CPU32(dentptr->size), s_name, dirc); @@ -1138,7 +1182,9 @@ root_reparse: /* If end of rootdir reached */ if (rootdir_end) { - if (dols == LS_ROOT) { + if (readdir) { + ret = -ENOENT; + } else if (dols == LS_ROOT) { printf("\n%d file(s), %d dir(s)\n\n", files, dirs); *size = 0; @@ -1150,9 +1196,12 @@ rootdir_done: firsttime = 1; + if (readdir && dols == LS_ROOT) { + ret = -ENOENT; + goto exit; + } + while (isdir) { - int startsect = mydata->data_begin - + START(dentptr) * mydata->clust_size; dir_entry dent; char *nextname = NULL; @@ -1177,10 +1226,14 @@ rootdir_done: } } - if (get_dentfromdir(mydata, startsect, subname, dentptr, - isdir ? 0 : dols) == NULL) { + if (get_dentfromdir(mydata, subname, dentptr, + isdir ? 0 : dols, pos, buffer) == NULL) { if (dols && !isdir) *size = 0; + if (dols == LS_READDIR) { + struct fs_dirent *dent = buffer; + ret = dent->name[0] ? 0 : -ENOENT; + } goto exit; } @@ -1353,6 +1406,13 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, return ret; } +int fat_readdir(const char *filename, loff_t offset, struct fs_dirent *dent) +{ + loff_t actread; + return do_fat_read_at(filename, offset, dent, sizeof(*dent), + LS_READDIR, 0, &actread); +} + void fat_close(void) { } diff --git a/fs/fs.c b/fs/fs.c index 5720ceec49..d6a2cdb22f 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -119,7 +119,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, #endif .uuid = fs_uuid_unsupported, - .readdir = fs_readdir_unsupported, + .readdir = fat_readdir, }, #endif #ifdef CONFIG_FS_EXT4 diff --git a/include/fat.h b/include/fat.h index 71879f01ca..0ef3f5be16 100644 --- a/include/fat.h +++ b/include/fat.h @@ -61,8 +61,8 @@ /* 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 LS_READDIR 3 /* read directory entry at specified offset */ #define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') @@ -210,5 +210,7 @@ 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); +struct fs_dirent; +int fat_readdir(const char *filename, loff_t offset, struct fs_dirent *dir); void fat_close(void); #endif /* _FAT_H_ */ -- 2.13.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot