Needed to support efi file protocol. The fallback.efi loader wants to be able to read the contents of the /EFI directory to find an OS to boot.
Currently only implemented for FAT, but that is all that UEFI is required to support. Signed-off-by: Rob Clark <robdcl...@gmail.com> --- fs/fat/fat.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++------------- fs/fs.c | 25 +++++++++++++++++++++++++ include/fat.h | 4 +++- include/fs.h | 21 +++++++++++++++++++++ 4 files changed, 95 insertions(+), 14 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 9ad18f96ff..04d8616598 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, @@ -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,7 +848,7 @@ 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; @@ -906,7 +929,8 @@ root_reparse: if (!dols) goto exit; - dols = LS_ROOT; + if (dols == LS_YES) + dols = LS_ROOT; } else if ((idx = dirdelim(fnamecopy)) >= 0) { isdir = 1; fnamecopy[idx] = '\0'; @@ -1151,8 +1175,6 @@ rootdir_done: firsttime = 1; while (isdir) { - int startsect = mydata->data_begin - + START(dentptr) * mydata->clust_size; dir_entry dent; char *nextname = NULL; @@ -1177,10 +1199,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 +1379,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 595ff1fe69..42a028a6ce 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -69,6 +69,12 @@ static inline int fs_uuid_unsupported(char *uuid_str) return -1; } +static inline int fs_readdir_unsupported(const char *filename, loff_t offset, + struct fs_dirent *dent) +{ + return -ENXIO; +} + struct fstype_info { int fstype; char *name; @@ -92,6 +98,7 @@ struct fstype_info { loff_t len, loff_t *actwrite); void (*close)(void); int (*uuid)(char *uuid_str); + int (*readdir)(const char *filename, loff_t offset, struct fs_dirent *dent); }; static struct fstype_info fstypes[] = { @@ -112,6 +119,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, #endif .uuid = fs_uuid_unsupported, + .readdir = fat_readdir, }, #endif #ifdef CONFIG_FS_EXT4 @@ -131,6 +139,7 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, #endif .uuid = ext4fs_uuid, + .readdir = fs_readdir_unsupported, }, #endif #ifdef CONFIG_SANDBOX @@ -146,6 +155,7 @@ static struct fstype_info fstypes[] = { .read = fs_read_sandbox, .write = fs_write_sandbox, .uuid = fs_uuid_unsupported, + .readdir = fs_readdir_unsupported, }, #endif #ifdef CONFIG_CMD_UBIFS @@ -161,6 +171,7 @@ static struct fstype_info fstypes[] = { .read = ubifs_read, .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, + .readdir = fs_readdir_unsupported, }, #endif { @@ -175,6 +186,7 @@ static struct fstype_info fstypes[] = { .read = fs_read_unsupported, .write = fs_write_unsupported, .uuid = fs_uuid_unsupported, + .readdir = fs_readdir_unsupported, }, }; @@ -334,6 +346,19 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, return ret; } +int fs_readdir(const char *filename, loff_t offset, struct fs_dirent *dent) +{ + struct fstype_info *info = fs_get_info(fs_type); + int ret; + + memset(dent, 0, sizeof(*dent)); + + ret = info->readdir(filename, offset, dent); + fs_close(); + + return ret; +} + int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int fstype) { 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_ */ diff --git a/include/fs.h b/include/fs.h index 2f2aca8378..71051d7c66 100644 --- a/include/fs.h +++ b/include/fs.h @@ -79,6 +79,27 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, loff_t *actwrite); /* + * A directory entry. + */ +struct fs_dirent { + loff_t size; + char name[256]; +}; + +/* + * fs_readdir - Read a directory. + * + * @filename: Name of file to read from + * @offset: The offset into the directory to read, ie. offset of N returns + * the N'th directory entry + * @dent: on success, filled in with directory entry + * @return 0 on success, -ENOTDIR if specified file is not a directory, + * or -ENOENT if offset is beyond last directory entry, or -ENXIO if + * operation is not supported. + */ +int fs_readdir(const char *filename, loff_t offset, struct fs_dirent *dent); + +/* * Common implementation for various filesystem commands, optionally limited * to a specific filesystem type via the fstype parameter. */ -- 2.13.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot