[U-Boot] [PATCH v2 4/8] fs: add fs_readdir()
Rob Clark
robdclark at gmail.com
Mon Aug 14 13:16:16 UTC 2017
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.
Modelled after POSIX opendir()/readdir()/closedir(). Unlike the other
fs APIs, this is stateful (ie. state is held in the FS_DIR "directory
stream"), to avoid re-traversing of the directory structure at each
step. The directory stream must be released with closedir() when it
is no longer needed.
Signed-off-by: Rob Clark <robdclark at gmail.com>
---
disk/part.c | 31 ++++++++++++--------
fs/fs.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/fs.h | 55 +++++++++++++++++++++++++++++++++++
include/part.h | 4 +++
4 files changed, 169 insertions(+), 12 deletions(-)
diff --git a/disk/part.c b/disk/part.c
index e640a55163..3eb58a4805 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -327,6 +327,24 @@ int part_get_info(struct blk_desc *dev_desc, int part,
return -1;
}
+int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info)
+{
+ info->start = 0;
+ info->size = dev_desc->lba;
+ info->blksz = dev_desc->blksz;
+ info->bootable = 0;
+ strcpy((char *)info->type, BOOT_PART_TYPE);
+ strcpy((char *)info->name, "Whole Disk");
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+ info->uuid[0] = 0;
+#endif
+#ifdef CONFIG_PARTITION_TYPE_GUID
+ info->type_guid[0] = 0;
+#endif
+
+ return 0;
+}
+
int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
struct blk_desc **dev_desc)
{
@@ -519,18 +537,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
- info->start = 0;
- info->size = (*dev_desc)->lba;
- info->blksz = (*dev_desc)->blksz;
- info->bootable = 0;
- strcpy((char *)info->type, BOOT_PART_TYPE);
- strcpy((char *)info->name, "Whole Disk");
-#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
- info->uuid[0] = 0;
-#endif
-#ifdef CONFIG_PARTITION_TYPE_GUID
- info->type_guid[0] = 0;
-#endif
+ part_get_info_whole_disk(*dev_desc, info);
ret = 0;
goto cleanup;
diff --git a/fs/fs.c b/fs/fs.c
index 595ff1fe69..1b4f41920d 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -21,6 +21,7 @@
DECLARE_GLOBAL_DATA_PTR;
static struct blk_desc *fs_dev_desc;
+static int fs_dev_part;
static disk_partition_t fs_partition;
static int fs_type = FS_TYPE_ANY;
@@ -69,6 +70,11 @@ static inline int fs_uuid_unsupported(char *uuid_str)
return -1;
}
+static inline int fs_opendir_unsupported(const char *filename, FS_DIR **dirp)
+{
+ return -EACCES;
+}
+
struct fstype_info {
int fstype;
char *name;
@@ -92,6 +98,9 @@ struct fstype_info {
loff_t len, loff_t *actwrite);
void (*close)(void);
int (*uuid)(char *uuid_str);
+ int (*opendir)(const char *filename, FS_DIR **dirp);
+ int (*readdir)(FS_DIR *dirp);
+ void (*closedir)(FS_DIR *dirp);
};
static struct fstype_info fstypes[] = {
@@ -112,6 +121,7 @@ static struct fstype_info fstypes[] = {
.write = fs_write_unsupported,
#endif
.uuid = fs_uuid_unsupported,
+ .opendir = fs_opendir_unsupported,
},
#endif
#ifdef CONFIG_FS_EXT4
@@ -131,6 +141,7 @@ static struct fstype_info fstypes[] = {
.write = fs_write_unsupported,
#endif
.uuid = ext4fs_uuid,
+ .opendir = fs_opendir_unsupported,
},
#endif
#ifdef CONFIG_SANDBOX
@@ -146,6 +157,7 @@ static struct fstype_info fstypes[] = {
.read = fs_read_sandbox,
.write = fs_write_sandbox,
.uuid = fs_uuid_unsupported,
+ .opendir = fs_opendir_unsupported,
},
#endif
#ifdef CONFIG_CMD_UBIFS
@@ -161,6 +173,7 @@ static struct fstype_info fstypes[] = {
.read = ubifs_read,
.write = fs_write_unsupported,
.uuid = fs_uuid_unsupported,
+ .opendir = fs_opendir_unsupported,
},
#endif
{
@@ -175,6 +188,7 @@ static struct fstype_info fstypes[] = {
.read = fs_read_unsupported,
.write = fs_write_unsupported,
.uuid = fs_uuid_unsupported,
+ .opendir = fs_opendir_unsupported,
},
};
@@ -228,6 +242,31 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
if (!info->probe(fs_dev_desc, &fs_partition)) {
fs_type = info->fstype;
+ fs_dev_part = part;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/* set current blk device w/ blk_desc + partition # */
+int fs_set_blk_dev2(struct blk_desc *desc, int part)
+{
+ struct fstype_info *info;
+ int ret, i;
+
+ if (part >= 1)
+ ret = part_get_info(desc, part, &fs_partition);
+ else
+ ret = part_get_info_whole_disk(desc, &fs_partition);
+ if (ret)
+ return ret;
+ fs_dev_desc = desc;
+
+ for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
+ if (!info->probe(fs_dev_desc, &fs_partition)) {
+ fs_type = info->fstype;
return 0;
}
}
@@ -334,6 +373,58 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
return ret;
}
+FS_DIR *fs_opendir(const char *filename)
+{
+ struct fstype_info *info = fs_get_info(fs_type);
+ FS_DIR *dirp = NULL;
+ int ret;
+
+ ret = info->opendir(filename, &dirp);
+ fs_close();
+ if (ret) {
+ errno = -ret;
+ return NULL;
+ }
+
+ dirp->desc = fs_dev_desc;
+ dirp->part = fs_dev_part;
+
+ return dirp;
+}
+
+struct fs_dirent *fs_readdir(FS_DIR *dirp)
+{
+ struct fstype_info *info;
+ int ret;
+
+ fs_set_blk_dev2(dirp->desc, dirp->part);
+ info = fs_get_info(fs_type);
+
+ memset(&dirp->dirent, 0, sizeof(dirp->dirent));
+
+ ret = info->readdir(dirp);
+ fs_close();
+ if (ret)
+ return NULL;
+
+ return &dirp->dirent;;
+}
+
+void fs_closedir(FS_DIR *dirp)
+{
+ struct fstype_info *info;
+
+ if (!dirp)
+ return;
+
+ fs_set_blk_dev2(dirp->desc, dirp->part);
+ info = fs_get_info(fs_type);
+
+ info->closedir(dirp);
+ fs_close();
+}
+
+
int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int fstype)
{
diff --git a/include/fs.h b/include/fs.h
index 2f2aca8378..0a6a366078 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -26,6 +26,8 @@
*/
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype);
+int fs_set_blk_dev2(struct blk_desc *desc, int part);
+
/*
* Print the list of files on the partition previously set by fs_set_blk_dev(),
* in directory "dirname".
@@ -78,6 +80,59 @@ int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
loff_t *actwrite);
+/* Add additional FS_DT_* as supported by additional filesystems:*/
+#define FS_DT_DIR 0x4 /* directory */
+#define FS_DT_REG 0x8 /* regular file */
+
+/*
+ * A directory entry.
+ */
+struct fs_dirent {
+ unsigned type; /* one of FS_DT_* */
+ loff_t size;
+ char name[256];
+};
+
+typedef struct _FS_DIR FS_DIR;
+
+/*
+ * fs_opendir - Open a directory
+ *
+ * @filename: the path to directory to open
+ * @return a pointer to the directory stream or NULL on error and errno
+ * set appropriately
+ */
+FS_DIR *fs_opendir(const char *filename);
+
+/*
+ * fs_readdir - Read the next directory entry in the directory stream.
+ *
+ * @dirp: the directory stream
+ * @return the next directory entry (only valid until next fs_readdir() or
+ * fs_closedir() call, do not attempt to free()) or NULL if the end of
+ * the directory is reached.
+ */
+struct fs_dirent *fs_readdir(FS_DIR *dirp);
+
+/*
+ * fs_closedir - close a directory stream
+ *
+ * @dirp: the directory stream
+ */
+void fs_closedir(FS_DIR *dirp);
+
+/*
+ * private to fs implementations, would be in fs.c but we need to let
+ * implementations subclass:
+ */
+
+struct _FS_DIR {
+ struct fs_dirent dirent;
+ /* private to fs layer: */
+ struct blk_desc *desc;
+ int part;
+};
+
/*
* Common implementation for various filesystem commands, optionally limited
* to a specific filesystem type via the fstype parameter.
diff --git a/include/part.h b/include/part.h
index 0cd803a933..48e8ff6d8a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -98,6 +98,7 @@ int host_get_dev_err(int dev, struct blk_desc **blk_devp);
/* disk/part.c */
int part_get_info(struct blk_desc *dev_desc, int part, disk_partition_t *info);
+int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info);
void part_print(struct blk_desc *dev_desc);
void part_init(struct blk_desc *dev_desc);
void dev_print(struct blk_desc *dev_desc);
@@ -203,6 +204,9 @@ static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; }
static inline int part_get_info(struct blk_desc *dev_desc, int part,
disk_partition_t *info) { return -1; }
+static inline int part_get_info_whole_disk(struct blk_desc *dev_desc,
+ disk_partition_t *info)
+{ return -1; }
static inline void part_print(struct blk_desc *dev_desc) {}
static inline void part_init(struct blk_desc *dev_desc) {}
static inline void dev_print(struct blk_desc *dev_desc) {}
--
2.13.0
More information about the U-Boot
mailing list