[U-Boot,v1,01/15] fs: add fs_readdir()

Message ID 20170810182948.27653-2-robdclark@gmail.com
State New
Delegated to: Alexander Graf
Headers show

Commit Message

Rob Clark Aug. 10, 2017, 6:29 p.m.
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.

Also included is an ls2 command which implements ls on top of
fs_readdir(), to more easily test the readdir functionality.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 cmd/fs.c     | 14 +++++++++++
 fs/fs.c      | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/fs.h | 23 +++++++++++++++++
 3 files changed, 117 insertions(+)

Comments

Heinrich Schuchardt Aug. 11, 2017, 4:06 p.m. | #1
On 08/10/2017 08:29 PM, Rob Clark wrote:
> 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.
> 
> Also included is an ls2 command which implements ls on top of
> fs_readdir(), to more easily test the readdir functionality.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  cmd/fs.c     | 14 +++++++++++
>  fs/fs.c      | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/fs.h | 23 +++++++++++++++++
>  3 files changed, 117 insertions(+)
> 
> diff --git a/cmd/fs.c b/cmd/fs.c
> index abfe5be172..58ddcec1a9 100644
> --- a/cmd/fs.c
> +++ b/cmd/fs.c
> @@ -75,6 +75,20 @@ U_BOOT_CMD(
>  	"      device type 'interface' instance 'dev'."
>  )
>  
> +static int do_ls2_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
> +				char * const argv[])
> +{
> +	return do_ls2(cmdtp, flag, argc, argv, FS_TYPE_ANY);
> +}
> +
> +U_BOOT_CMD(
> +	ls2,	4,	1,	do_ls2_wrapper,
> +	"list files in a directory using fs_readdir (default /)",
> +	"<interface> [<dev[:part]> [directory]]\n"
> +	"    - List files in directory 'directory' of partition 'part' on\n"
> +	"      device type 'interface' instance 'dev'."
> +)
> +
>  static int do_fstype_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
>  				char * const argv[])
>  {
> diff --git a/fs/fs.c b/fs/fs.c
> index 595ff1fe69..5720ceec49 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 = fs_readdir_unsupported,
>  	},
>  #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)
>  {
> @@ -440,6 +465,61 @@ int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
>  	return 0;
>  }
>  
> +int do_ls2(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
> +	int fstype)
> +{
> +	const char *filename = argc >= 4 ? argv[3] : "/";

Do we really want to update filename and dev_part_str if argc is illegal?

I would suggest to put the assignments below the argc check.

Could you, please, add comment lines above the function describing the
usage of argv[0..3].

Best regards

Heinrich

> +	const char *ifname = argv[1];
> +	const char *dev_part_str = (argc >= 3) ? argv[2] : NULL;
> +	loff_t offset = 0;
> +	int ret, files = 0, dirs = 0;
> +
> +	if (argc < 2)
> +		return CMD_RET_USAGE;
> +	if (argc > 4)
> +		return CMD_RET_USAGE;
> +
> +	while (1) {
> +		struct fs_dirent dent, dent2;
> +		char buf[256];
> +
> +		if (fs_set_blk_dev(ifname, dev_part_str, fstype))
> +			return 1;
> +
> +		ret = fs_readdir(filename, offset, &dent);
> +		if (ret == -ENOENT) {
> +			/* no more directory entries */
> +			break;
> +		} else if (ret) {
> +			printf("command failed at offset %lld (%d)\n",
> +			       offset, ret);
> +			return 1;
> +		}
> +
> +		/* figure out if the entry is a directory: */
> +		ret = snprintf(buf, sizeof(buf), "%s/%s", filename, dent.name);
> +		if (ret >= sizeof(buf))
> +			return 1;
> +
> +		fs_set_blk_dev(ifname, dev_part_str, fstype);
> +		ret = fs_readdir(buf, 0, &dent2);
> +
> +		if (ret == -ENOTDIR) {
> +			printf(" %8lld   %s\n", dent.size, dent.name);
> +			files++;
> +		} else {
> +			printf("            %s/\n", dent.name);
> +			dirs++;
> +		}
> +
> +		offset++;
> +	}
> +
> +	printf("\n%d file(s), %d dir(s)\n\n", files, dirs);
> +
> +	return 0;
> +}
> +
>  int file_exists(const char *dev_type, const char *dev_part, const char *file,
>  		int fstype)
>  {
> diff --git a/include/fs.h b/include/fs.h
> index 2f2aca8378..d8be5cc9a6 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.
>   */
> @@ -88,6 +109,8 @@ int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
>  		int fstype);
>  int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
>  		int fstype);
> +int do_ls2(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
> +		int fstype);
>  int file_exists(const char *dev_type, const char *dev_part, const char *file,
>  		int fstype);
>  int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
>

Patch

diff --git a/cmd/fs.c b/cmd/fs.c
index abfe5be172..58ddcec1a9 100644
--- a/cmd/fs.c
+++ b/cmd/fs.c
@@ -75,6 +75,20 @@  U_BOOT_CMD(
 	"      device type 'interface' instance 'dev'."
 )
 
+static int do_ls2_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
+				char * const argv[])
+{
+	return do_ls2(cmdtp, flag, argc, argv, FS_TYPE_ANY);
+}
+
+U_BOOT_CMD(
+	ls2,	4,	1,	do_ls2_wrapper,
+	"list files in a directory using fs_readdir (default /)",
+	"<interface> [<dev[:part]> [directory]]\n"
+	"    - List files in directory 'directory' of partition 'part' on\n"
+	"      device type 'interface' instance 'dev'."
+)
+
 static int do_fstype_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
 				char * const argv[])
 {
diff --git a/fs/fs.c b/fs/fs.c
index 595ff1fe69..5720ceec49 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 = fs_readdir_unsupported,
 	},
 #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)
 {
@@ -440,6 +465,61 @@  int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 	return 0;
 }
 
+int do_ls2(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+	int fstype)
+{
+	const char *filename = argc >= 4 ? argv[3] : "/";
+	const char *ifname = argv[1];
+	const char *dev_part_str = (argc >= 3) ? argv[2] : NULL;
+	loff_t offset = 0;
+	int ret, files = 0, dirs = 0;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+	if (argc > 4)
+		return CMD_RET_USAGE;
+
+	while (1) {
+		struct fs_dirent dent, dent2;
+		char buf[256];
+
+		if (fs_set_blk_dev(ifname, dev_part_str, fstype))
+			return 1;
+
+		ret = fs_readdir(filename, offset, &dent);
+		if (ret == -ENOENT) {
+			/* no more directory entries */
+			break;
+		} else if (ret) {
+			printf("command failed at offset %lld (%d)\n",
+			       offset, ret);
+			return 1;
+		}
+
+		/* figure out if the entry is a directory: */
+		ret = snprintf(buf, sizeof(buf), "%s/%s", filename, dent.name);
+		if (ret >= sizeof(buf))
+			return 1;
+
+		fs_set_blk_dev(ifname, dev_part_str, fstype);
+		ret = fs_readdir(buf, 0, &dent2);
+
+		if (ret == -ENOTDIR) {
+			printf(" %8lld   %s\n", dent.size, dent.name);
+			files++;
+		} else {
+			printf("            %s/\n", dent.name);
+			dirs++;
+		}
+
+		offset++;
+	}
+
+	printf("\n%d file(s), %d dir(s)\n\n", files, dirs);
+
+	return 0;
+}
+
 int file_exists(const char *dev_type, const char *dev_part, const char *file,
 		int fstype)
 {
diff --git a/include/fs.h b/include/fs.h
index 2f2aca8378..d8be5cc9a6 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.
  */
@@ -88,6 +109,8 @@  int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 		int fstype);
 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 		int fstype);
+int do_ls2(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+		int fstype);
 int file_exists(const char *dev_type, const char *dev_part, const char *file,
 		int fstype);
 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],