[U-Boot] [PATCH 4/8] fs: add fs_readdir()

Rob Clark robdclark at gmail.com
Sun Aug 13 10:45:24 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>
---
 fs/fs.c      | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/fs.h | 55 +++++++++++++++++++++++++++++++++++++
 2 files changed, 143 insertions(+)

diff --git a/fs/fs.c b/fs/fs.c
index 595ff1fe69..f9ea3480e9 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,28 @@ 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;
+
+	ret = part_get_info(desc, part, &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 +370,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.
-- 
2.13.0



More information about the U-Boot mailing list