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

