[PATCH 3/5] fs: ext4: implement opendir, readdir, closedir

Simon Glass sjg at chromium.org
Sun Oct 27 18:16:02 CET 2024


Hi Heinrich,

On Sat, 26 Oct 2024 at 08:41, Heinrich Schuchardt
<heinrich.schuchardt at canonical.com> wrote:
>
> For accessing directories from the EFI sub-system a file system must
> implement opendir, readdir, closedir. Provide the missing implementation.
>
> With this patch the eficonfig command can be used to define load options
> for the ext4 file system.
>
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt at canonical.com>
> ---
>  fs/ext4/ext4fs.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++-
>  fs/fs.c          |   4 +-
>  include/ext4fs.h |   4 ++
>  3 files changed, 166 insertions(+), 3 deletions(-)
>

with nits/questions below

Reviewed-by: Simon Glass <sjg at chromium.org>

> diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
> index 21714149ef5..32693198aeb 100644
> --- a/fs/ext4/ext4fs.c
> +++ b/fs/ext4/ext4fs.c
> @@ -21,17 +21,36 @@
>   */
>
>  #include <blk.h>
> +#include <div64.h>
> +#include <errno.h>
>  #include <ext_common.h>
>  #include <ext4fs.h>
> -#include "ext4_common.h"
> -#include <div64.h>
>  #include <malloc.h>
>  #include <part.h>
>  #include <u-boot/uuid.h>
> +#include "ext4_common.h"
>
>  int ext4fs_symlinknest;
>  struct ext_filesystem ext_fs;
>
> +/**
> + * struct ext4_dir_stream - ext4 directory stream
> + *
> + * @parent: partition data used by fs layer.
> + * This field must be at the beginning of the structure.
> + * All other fields are private to the ext4 driver.
> + * @root:      root directory node
> + * @dir:       directory node
> + * @dirent:    directory stream entry
> + * @fpos:      file position in directory
> + */
> +struct ext4_dir_stream {
> +       struct fs_dir_stream parent;
> +       char *dirname;
> +       struct fs_dirent dirent;
> +       unsigned int fpos;
> +};
> +
>  struct ext_filesystem *get_fs(void)
>  {
>         return &ext_fs;
> @@ -205,6 +224,144 @@ int ext4fs_ls(const char *dirname)
>         return 0;
>  }
>
> +int ext4fs_opendir(const char *dirname, struct fs_dir_stream **dirsp)
> +{
> +       struct ext4_dir_stream *dirs;
> +       struct ext2fs_node *dir = NULL;
> +       int ret;
> +
> +       *dirsp = NULL;
> +
> +       dirs = calloc(1, sizeof(struct ext4_dir_stream));
> +       if (!dirs)
> +               return -ENOMEM;
> +       dirs->dirname = strdup(dirname);
> +       if (!dirs) {
> +               free(dirs);
> +               return -ENOMEM;
> +       }
> +
> +       ret = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dir,
> +                              FILETYPE_DIRECTORY);
> +       if (ret == 1) {
> +               ret = 0;
> +               *dirsp = (struct fs_dir_stream *)dirs;
> +       } else {
> +               ret = -ENOENT;
> +       }
> +
> +       if (dir)
> +               ext4fs_free_node(dir, &ext4fs_root->diropen);
> +
> +       return ret;
> +}
> +
> +int ext4fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
> +{
> +       struct ext4_dir_stream *dirs = (struct ext4_dir_stream *)fs_dirs;
> +       struct fs_dirent *dent = &dirs->dirent;
> +       struct ext2fs_node *dir = NULL;
> +       int ret;
> +       loff_t actread;
> +       struct ext2fs_node fdiro;
> +       int len;
> +       struct ext2_dirent dirent;
> +
> +       *dentp = NULL;
> +
> +       ret = ext4fs_find_file(dirs->dirname, &ext4fs_root->diropen, &dir,
> +                              FILETYPE_DIRECTORY);
> +       if (ret != 1) {
> +               ret = -ENOENT;
> +               goto out;
> +       }
> +       if (!dir->inode_read) {
> +               ret = ext4fs_read_inode(dir->data, dir->ino, &dir->inode);
> +               if (!ret) {
> +                       ret = -EIO;
> +                       goto out;
> +               }
> +       }
> +
> +       if (dirs->fpos >= le32_to_cpu(dir->inode.size))
> +               return -ENOENT;
> +
> +       memset(dent, 0, sizeof(struct fs_dirent));
> +
> +       while (dirs->fpos < le32_to_cpu(dir->inode.size)) {
> +               ret = ext4fs_read_file(dir, dirs->fpos,
> +                                      sizeof(struct ext2_dirent),
> +                                      (char *)&dirent, &actread);
> +               if (ret < 0)
> +                       return -ret;
> +
> +               if (!dirent.direntlen)
> +                       return -EIO;

Should this (and the return immediately above) free call ext4fs_free_node() ?

> +
> +               if (dirent.namelen)
> +                       break;
> +
> +               dirs->fpos += le16_to_cpu(dirent.direntlen);
> +       }
> +
> +       len = min(FS_DIRENT_NAME_LEN - 1, (int)dirent.namelen);
> +
> +       ret = ext4fs_read_file(dir, dirs->fpos + sizeof(struct ext2_dirent),
> +                              len, dent->name, &actread);
> +       if (ret < 0)
> +               goto out;
> +       dent->name[len] = '\0';
> +
> +       fdiro.data = dir->data;
> +       fdiro.ino = le32_to_cpu(dirent.inode);
> +
> +       ret = ext4fs_read_inode(dir->data, fdiro.ino, &fdiro.inode);
> +       if (!ret) {
> +               ret = -EIO;
> +               goto out;
> +       }
> +
> +       switch (le16_to_cpu(fdiro.inode.mode) & FILETYPE_INO_MASK) {
> +       case FILETYPE_INO_DIRECTORY:
> +               dent->type = FS_DT_DIR;
> +               break;
> +       case FILETYPE_INO_SYMLINK:
> +               dent->type = FS_DT_LNK;
> +               break;
> +       case FILETYPE_INO_REG:
> +               dent->type = FS_DT_REG;
> +               break;
> +       default:
> +               dent->type = FILETYPE_UNKNOWN;
> +       }
> +
> +       rtc_to_tm(fdiro.inode.atime, &dent->access_time);
> +       rtc_to_tm(fdiro.inode.ctime, &dent->create_time);
> +       rtc_to_tm(fdiro.inode.mtime, &dent->change_time);
> +
> +       dirs->fpos += le16_to_cpu(dirent.direntlen);
> +       dent->size = fdiro.inode.size;
> +       *dentp = dent;
> +       ret = 0;
> +
> +out:
> +       if (dir)
> +               ext4fs_free_node(dir, &ext4fs_root->diropen);
> +
> +       return ret;
> +}
> +
> +void ext4fs_closedir(struct fs_dir_stream *fs_dirs)
> +{
> +       struct ext4_dir_stream *dirs = (struct ext4_dir_stream *)fs_dirs;
> +
> +       if (!dirs)
> +               return;
> +
> +       free(dirs->dirname);
> +       free(dirs);
> +}
> +
>  int ext4fs_exists(const char *filename)
>  {
>         struct ext2fs_node *dirnode = NULL;
> diff --git a/fs/fs.c b/fs/fs.c
> index e2915e7cf79..a515905c4c9 100644
> --- a/fs/fs.c
> +++ b/fs/fs.c
> @@ -232,7 +232,9 @@ static struct fstype_info fstypes[] = {
>                 .ln = fs_ln_unsupported,
>  #endif
>                 .uuid = ext4fs_uuid,
> -               .opendir = fs_opendir_unsupported,
> +               .opendir = ext4fs_opendir,
> +               .readdir = ext4fs_readdir,
> +               .closedir = ext4fs_closedir,
>                 .unlink = fs_unlink_unsupported,
>                 .mkdir = fs_mkdir_unsupported,
>         },
> diff --git a/include/ext4fs.h b/include/ext4fs.h
> index 41f9eb8bd33..fe3fb301ec8 100644
> --- a/include/ext4fs.h
> +++ b/include/ext4fs.h
> @@ -27,6 +27,7 @@
>  #ifndef __EXT4__
>  #define __EXT4__
>  #include <ext_common.h>
> +#include <fs.h>
>
>  struct disk_partition;
>
> @@ -218,4 +219,7 @@ int ext4fs_uuid(char *uuid_str);
>  void ext_cache_init(struct ext_block_cache *cache);
>  void ext_cache_fini(struct ext_block_cache *cache);
>  int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size);
> +int ext4fs_opendir(const char *dirname, struct fs_dir_stream **dirsp);
> +int ext4fs_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
> +void ext4fs_closedir(struct fs_dir_stream *dirs);

Please add function comments

>  #endif
> --
> 2.45.2
>

Regards,
Simon


More information about the U-Boot mailing list