[Concept,12/34] vfs: Add ls support using dir open/read/close

Message ID 20260403140523.1998228-13-sjg@u-boot.org
State New
Headers
Series Add a virtual filesystem (VFS) layer to U-Boot |

Commit Message

Simon Glass April 3, 2026, 2:04 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add vfs_ls() which resolves a path through the mount table and lists
directory entries using the dir_open(), dir_read() and dir_close()
interface. At the root level, mount-point directories are shown.

Add an 'fs ls' subcommand and update the help text to include it along
with the mount -t syntax for block-device mounts.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 cmd/vfs.c     | 28 +++++++++++++++++++++++-----
 fs/vfs.c      | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 include/vfs.h | 11 +++++++++++
 test/dm/fs.c  | 10 ++++++++++
 4 files changed, 90 insertions(+), 5 deletions(-)
  

Patch

diff --git a/cmd/vfs.c b/cmd/vfs.c
index 23b8cabdcdb..5779f3f098d 100644
--- a/cmd/vfs.c
+++ b/cmd/vfs.c
@@ -1,6 +1,6 @@ 
 // SPDX-License-Identifier: GPL-2.0
 /*
- * VFS commands - 'fs mount', 'fs umount'
+ * VFS commands - 'fs mount', 'fs umount', 'fs ls'
  *
  * Provides a new 'fs' command with subcommands for the virtual filesystem
  * layer, co-existing with the legacy filesystem commands in cmd/fs.c.
@@ -87,10 +87,28 @@  static int do_fs_umount(struct cmd_tbl *cmdtp, int flag, int argc,
 	return CMD_RET_SUCCESS;
 }
 
+static int do_fs_ls(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[])
+{
+	const char *path = argc >= 2 ? argv[1] : "/";
+	int ret;
+
+	ret = vfs_ls(path);
+	if (ret) {
+		printf("fs ls failed: %dE\n", ret);
+		return CMD_RET_FAILURE;
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 U_BOOT_LONGHELP(fs,
-	"mount [<dev> <mountpoint>] - list or create mounts\n"
-	"fs umount <mountpoint>         - unmount a filesystem");
+	"mount [<dev> <mountpoint>]                   - list or create mounts\n"
+	"fs mount -t <type> <iface> <dev:part> <path>  - mount from block device\n"
+	"fs umount <mountpoint>                        - unmount a filesystem\n"
+	"fs ls [<path>]                                - list directory (default /)");
 
 U_BOOT_CMD_WITH_SUBCMDS(fs, "Filesystem operations", fs_help_text,
-	U_BOOT_SUBCMD_MKENT(mount, 3, 1, do_fs_mount),
-	U_BOOT_SUBCMD_MKENT(umount, 2, 1, do_fs_umount));
+	U_BOOT_SUBCMD_MKENT(mount, 6, 1, do_fs_mount),
+	U_BOOT_SUBCMD_MKENT(umount, 2, 1, do_fs_umount),
+	U_BOOT_SUBCMD_MKENT(ls, 2, 1, do_fs_ls));
diff --git a/fs/vfs.c b/fs/vfs.c
index db1aa84bfd6..e05a02ad5b0 100644
--- a/fs/vfs.c
+++ b/fs/vfs.c
@@ -331,6 +331,52 @@  void vfs_print_mounts(void)
 	}
 }
 
+int vfs_ls(const char *path)
+{
+	struct udevice *vfs, *mnt, *dir = NULL;
+	struct fs_dir_stream *strm;
+	struct fs_dirent dent;
+	const char *subpath;
+	bool empty = true;
+	int ret;
+
+	vfs = vfs_root();
+	if (!vfs)
+		return -ENXIO;
+
+	ret = vfs_find_mount(vfs, path, &mnt, &subpath);
+	if (!ret && mnt) {
+		struct vfsmount *m = dev_get_uclass_priv(mnt);
+
+		ret = fs_lookup_dir(m->target, subpath, &dir);
+		if (ret)
+			return ret;
+	} else if (!ret || !path[1]) {
+		/* Root "/" - list the VFS root dir */
+		ret = fs_lookup_dir(vfs, "", &dir);
+		if (ret)
+			return ret;
+	} else {
+		return ret;
+	}
+
+	ret = dir_open(dir, &strm);
+	if (ret)
+		return ret;
+
+	while (!dir_read(dir, strm, &dent)) {
+		if (dent.type == FS_DT_DIR)
+			printf("DIR %10u %s\n", 0, dent.name);
+		else
+			printf("    %10llu %s\n", dent.size, dent.name);
+		empty = false;
+	}
+
+	dir_close(dir, strm);
+
+	return 0;
+}
+
 struct udevice *vfs_root(void)
 {
 	struct udevice *dev;
diff --git a/include/vfs.h b/include/vfs.h
index 6673f9a5ef1..f85f45da4dd 100644
--- a/include/vfs.h
+++ b/include/vfs.h
@@ -125,4 +125,15 @@  bool vfs_is_mount_point(struct udevice *dir);
  */
 void vfs_print_mounts(void);
 
+/**
+ * vfs_ls() - List directory contents
+ *
+ * Resolves the path through the mount table and lists directory entries
+ * using dir_open(), dir_read() and dir_close().
+ *
+ * @path: Absolute path to list, or "/" for root
+ * Return: 0 if OK, -ve on error
+ */
+int vfs_ls(const char *path);
+
 #endif
diff --git a/test/dm/fs.c b/test/dm/fs.c
index f71ad361bcd..b14083590c6 100644
--- a/test/dm/fs.c
+++ b/test/dm/fs.c
@@ -262,6 +262,16 @@  static int dm_test_vfs_cmd(struct unit_test_state *uts)
 	ut_assert_nextlinen("/host");
 	ut_assert_console_end();
 
+	/* Root should show the "host" mount point */
+	ut_assertok(run_command("fs ls /", 0));
+	ut_assert_nextline("DIR %10u host", 0);
+	ut_assert_console_end();
+
+	/* Listing /host should show sandbox directory contents */
+	ut_assertok(run_command("fs ls /host", 0));
+	ut_assert_skip_to_linen("DIR ");
+	console_record_reset_enable();
+
 	/* Unmount */
 	ut_assertok(run_command("fs umount /host", 0));
 	ut_assert_console_end();