fs_ls_generic() displays file sizes but no timestamps. The FAT
filesystem stores a change date in every directory entry and already
populates fs_dirent::change_time in fat_readdir(). Print the date
alongside the file size for filesystems that provide it.

Add a u32 capability bitmap (caps) to struct fstype_info. Each bit
documents a property that the filesystem's readdir() implementation
guarantees:

  FS_CAP_DATE  BIT(0)  change_time in fs_dirent is valid

fs_ls_generic() tests FS_CAP_DATE once before the loop to select a
consistent output format for the entire listing:

  12345678  2024-03-15 09:30  filename.txt    (FAT)
  12345678   filename.txt                     (ext4, squashfs, ...)

Set FS_CAP_DATE for FAT. fat2rtc() loses the __maybe_unused annotation
since it is now called unconditionally outside XPL builds. The attr,
create_time, change_time, and access_time fields that were previously
only populated under CONFIG_EFI_LOADER are now populated whenever
CONFIG_XPL_BUILD is not set.

Extending the feature to another filesystem requires only adding
.caps = FS_CAP_DATE to its fstype_info entry and ensuring its readdir()
fills in fs_dirent::change_time.

Signed-off-by: Heinrich Schuchardt <[email protected]>
---
 fs/fat/fat.c |  2 +-
 fs/fs.c      | 38 +++++++++++++++++++++++++++++++++++---
 2 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index c1ccf30771a..7443f5952af 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -1539,7 +1539,7 @@ int fat_readdir(struct fs_dir_stream *dirs, struct 
fs_dirent **dentp)
 
        memset(dent, 0, sizeof(*dent));
        strcpy(dent->name, dir->itr.name);
-       if (CONFIG_IS_ENABLED(EFI_LOADER)) {
+       if (!IS_ENABLED(CONFIG_XPL_BUILD)) {
                dent->attr = dir->itr.dent->attr;
                fat2rtc(le16_to_cpu(dir->itr.dent->cdate),
                        le16_to_cpu(dir->itr.dent->ctime), &dent->create_time);
diff --git a/fs/fs.c b/fs/fs.c
index fe62b71c83c..f8e4794c10e 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -38,6 +38,11 @@ static int fs_dev_part;
 static struct disk_partition fs_partition;
 static int fs_type = FS_TYPE_ANY;
 
+/*
+ * define FS_CAP_DATE - readdir() populates fs_dirent::change_time
+ */
+#define FS_CAP_DATE    BIT(0)
+
 struct fstype_info {
        int fstype;
        char *name;
@@ -50,6 +55,10 @@ struct fstype_info {
         * filesystem.
         */
        bool null_dev_desc_ok;
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+       /* Capability flags (FS_CAP_*) */
+       u32 caps;
+#endif
        int (*probe)(struct blk_desc *fs_dev_desc,
                     struct disk_partition *fs_partition);
        int (*ls)(const char *dirname);
@@ -98,10 +107,19 @@ static inline int fs_ls_unsupported(const char *dirname)
        return -1;
 }
 
+/* Forward declaration - defined after fstypes[] */
+static struct fstype_info *fs_get_info(int fstype);
+
 /* generic implementation of ls in terms of opendir/readdir/closedir */
 __maybe_unused
 static int fs_ls_generic(const char *dirname)
 {
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+       struct fstype_info *info = fs_get_info(fs_type);
+       bool has_date = !!(info->caps & FS_CAP_DATE);
+#else
+       bool has_date = false;
+#endif
        struct fs_dir_stream *dirs;
        struct fs_dirent *dent;
        int nfiles = 0, ndirs = 0;
@@ -112,15 +130,26 @@ static int fs_ls_generic(const char *dirname)
 
        while ((dent = fs_readdir(dirs))) {
                if (dent->type == FS_DT_DIR) {
-                       printf("            %s/\n", dent->name);
+                       printf("          ");
                        ndirs++;
                } else if (dent->type == FS_DT_LNK) {
-                       printf("    <SYM>   %s\n", dent->name);
+                       printf("    <SYM> ");
                        nfiles++;
                } else {
-                       printf(" %8lld   %s\n", dent->size, dent->name);
+                       printf(" %8lld ", dent->size);
                        nfiles++;
                }
+               if (has_date)
+                       printf("%04d-%02d-%02d %02d:%02d ",
+                              dent->change_time.tm_year,
+                              dent->change_time.tm_mon,
+                              dent->change_time.tm_mday,
+                              dent->change_time.tm_hour,
+                              dent->change_time.tm_min);
+               if (dent->type == FS_DT_DIR)
+                       printf("%s/\n", dent->name);
+               else
+                       printf("%s\n", dent->name);
        }
 
        fs_closedir(dirs);
@@ -196,6 +225,9 @@ static struct fstype_info fstypes[] = {
                .fstype = FS_TYPE_FAT,
                .name = "fat",
                .null_dev_desc_ok = false,
+#if !IS_ENABLED(CONFIG_XPL_BUILD)
+               .caps = FS_CAP_DATE,
+#endif
                .probe = fat_set_blk_dev,
                .close = fat_close,
                .ls = fs_ls_generic,
-- 
2.53.0

Reply via email to