[U-Boot] [PATCH v2 4/8] fs: add fs_readdir()

Łukasz Majewski lukma at denx.de
Sun Sep 3 15:16:07 UTC 2017


On 09/02/2017 06:37 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.
> 
> Modelled after POSIX opendir()/readdir()/closedir().  Unlike the other
> fs APIs, this is stateful (ie. state is held in the FS_DIR "directory
> stream"), to avoid re-traversing of the directory structure at each
> step.  The directory stream must be released with closedir() when it
> is no longer needed.
> 

Reviewed-by: Łukasz Majewski <lukma at denx.de>

> Signed-off-by: Rob Clark <robdclark at gmail.com>
> ---
>   disk/part.c    | 31 ++++++++++++--------
>   fs/fs.c        | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   include/fs.h   | 55 +++++++++++++++++++++++++++++++++++
>   include/part.h |  4 +++
>   4 files changed, 169 insertions(+), 12 deletions(-)
> 
> diff --git a/disk/part.c b/disk/part.c
> index c67fdacc79..aa9183d696 100644
> --- a/disk/part.c
> +++ b/disk/part.c
> @@ -331,6 +331,24 @@ int part_get_info(struct blk_desc *dev_desc, int part,
>   	return -1;
>   }
>   
> +int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info)
> +{
> +	info->start = 0;
> +	info->size = dev_desc->lba;
> +	info->blksz = dev_desc->blksz;
> +	info->bootable = 0;
> +	strcpy((char *)info->type, BOOT_PART_TYPE);
> +	strcpy((char *)info->name, "Whole Disk");
> +#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
> +	info->uuid[0] = 0;
> +#endif
> +#ifdef CONFIG_PARTITION_TYPE_GUID
> +	info->type_guid[0] = 0;
> +#endif
> +
> +	return 0;
> +}
> +
>   int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
>   			  struct blk_desc **dev_desc)
>   {
> @@ -523,18 +541,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
>   
>   		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
>   
> -		info->start = 0;
> -		info->size = (*dev_desc)->lba;
> -		info->blksz = (*dev_desc)->blksz;
> -		info->bootable = 0;
> -		strcpy((char *)info->type, BOOT_PART_TYPE);
> -		strcpy((char *)info->name, "Whole Disk");
> -#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
> -		info->uuid[0] = 0;
> -#endif
> -#ifdef CONFIG_PARTITION_TYPE_GUID
> -		info->type_guid[0] = 0;
> -#endif
> +		part_get_info_whole_disk(*dev_desc, info);
>   
>   		ret = 0;
>   		goto cleanup;
> diff --git a/fs/fs.c b/fs/fs.c
> index 13cd3626c6..441c880654 100644
> --- a/fs/fs.c
> +++ b/fs/fs.c
> @@ -21,6 +21,7 @@
>   DECLARE_GLOBAL_DATA_PTR;
>   
>   static struct blk_desc *fs_dev_desc;
> +static int fs_dev_part;
>   static disk_partition_t fs_partition;
>   static int fs_type = FS_TYPE_ANY;
>   
> @@ -69,6 +70,11 @@ static inline int fs_uuid_unsupported(char *uuid_str)
>   	return -1;
>   }
>   
> +static inline int fs_opendir_unsupported(const char *filename, FS_DIR **dirp)
> +{
> +	return -EACCES;
> +}
> +
>   struct fstype_info {
>   	int fstype;
>   	char *name;
> @@ -92,6 +98,9 @@ struct fstype_info {
>   		     loff_t len, loff_t *actwrite);
>   	void (*close)(void);
>   	int (*uuid)(char *uuid_str);
> +	int (*opendir)(const char *filename, FS_DIR **dirp);
> +	int (*readdir)(FS_DIR *dirp);
> +	void (*closedir)(FS_DIR *dirp);
>   };
>   
>   static struct fstype_info fstypes[] = {
> @@ -112,6 +121,7 @@ static struct fstype_info fstypes[] = {
>   		.write = fs_write_unsupported,
>   #endif
>   		.uuid = fs_uuid_unsupported,
> +		.opendir = fs_opendir_unsupported,
>   	},
>   #endif
>   #ifdef CONFIG_FS_EXT4
> @@ -131,6 +141,7 @@ static struct fstype_info fstypes[] = {
>   		.write = fs_write_unsupported,
>   #endif
>   		.uuid = ext4fs_uuid,
> +		.opendir = fs_opendir_unsupported,
>   	},
>   #endif
>   #ifdef CONFIG_SANDBOX
> @@ -146,6 +157,7 @@ static struct fstype_info fstypes[] = {
>   		.read = fs_read_sandbox,
>   		.write = fs_write_sandbox,
>   		.uuid = fs_uuid_unsupported,
> +		.opendir = fs_opendir_unsupported,
>   	},
>   #endif
>   #ifdef CONFIG_CMD_UBIFS
> @@ -161,6 +173,7 @@ static struct fstype_info fstypes[] = {
>   		.read = ubifs_read,
>   		.write = fs_write_unsupported,
>   		.uuid = fs_uuid_unsupported,
> +		.opendir = fs_opendir_unsupported,
>   	},
>   #endif
>   	{
> @@ -175,6 +188,7 @@ static struct fstype_info fstypes[] = {
>   		.read = fs_read_unsupported,
>   		.write = fs_write_unsupported,
>   		.uuid = fs_uuid_unsupported,
> +		.opendir = fs_opendir_unsupported,
>   	},
>   };
>   
> @@ -228,6 +242,31 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
>   
>   		if (!info->probe(fs_dev_desc, &fs_partition)) {
>   			fs_type = info->fstype;
> +			fs_dev_part = part;
> +			return 0;
> +		}
> +	}
> +
> +	return -1;
> +}
> +
> +/* set current blk device w/ blk_desc + partition # */
> +int fs_set_blk_dev2(struct blk_desc *desc, int part)
> +{
> +	struct fstype_info *info;
> +	int ret, i;
> +
> +	if (part >= 1)
> +		ret = part_get_info(desc, part, &fs_partition);
> +	else
> +		ret = part_get_info_whole_disk(desc, &fs_partition);
> +	if (ret)
> +		return ret;
> +	fs_dev_desc = desc;
> +
> +	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
> +		if (!info->probe(fs_dev_desc, &fs_partition)) {
> +			fs_type = info->fstype;
>   			return 0;
>   		}
>   	}
> @@ -334,6 +373,58 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
>   	return ret;
>   }
>   
> +FS_DIR *fs_opendir(const char *filename)
> +{
> +	struct fstype_info *info = fs_get_info(fs_type);
> +	FS_DIR *dirp = NULL;
> +	int ret;
> +
> +	ret = info->opendir(filename, &dirp);
> +	fs_close();
> +	if (ret) {
> +		errno = -ret;
> +		return NULL;
> +	}
> +
> +	dirp->desc = fs_dev_desc;
> +	dirp->part = fs_dev_part;
> +
> +	return dirp;
> +}
> +
> +struct fs_dirent *fs_readdir(FS_DIR *dirp)
> +{
> +	struct fstype_info *info;
> +	int ret;
> +
> +	fs_set_blk_dev2(dirp->desc, dirp->part);
> +	info = fs_get_info(fs_type);
> +
> +	memset(&dirp->dirent, 0, sizeof(dirp->dirent));
> +
> +	ret = info->readdir(dirp);
> +	fs_close();
> +	if (ret)
> +		return NULL;
> +
> +	return &dirp->dirent;;
> +}
> +
> +void fs_closedir(FS_DIR *dirp)
> +{
> +	struct fstype_info *info;
> +
> +	if (!dirp)
> +		return;
> +
> +	fs_set_blk_dev2(dirp->desc, dirp->part);
> +	info = fs_get_info(fs_type);
> +
> +	info->closedir(dirp);
> +	fs_close();
> +}
> +
> +
>   int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
>   		int fstype)
>   {
> diff --git a/include/fs.h b/include/fs.h
> index 2f2aca8378..0a6a366078 100644
> --- a/include/fs.h
> +++ b/include/fs.h
> @@ -26,6 +26,8 @@
>    */
>   int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype);
>   
> +int fs_set_blk_dev2(struct blk_desc *desc, int part);
> +
>   /*
>    * Print the list of files on the partition previously set by fs_set_blk_dev(),
>    * in directory "dirname".
> @@ -78,6 +80,59 @@ int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
>   int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
>   	     loff_t *actwrite);
>   
> +/* Add additional FS_DT_* as supported by additional filesystems:*/
> +#define FS_DT_DIR  0x4       /* directory */
> +#define FS_DT_REG  0x8       /* regular file */
> +
> +/*
> + * A directory entry.
> + */
> +struct fs_dirent {
> +	unsigned type;       /* one of FS_DT_* */
> +	loff_t size;
> +	char name[256];
> +};
> +
> +typedef struct _FS_DIR FS_DIR;
> +
> +/*
> + * fs_opendir - Open a directory
> + *
> + * @filename: the path to directory to open
> + * @return a pointer to the directory stream or NULL on error and errno
> + *    set appropriately
> + */
> +FS_DIR *fs_opendir(const char *filename);
> +
> +/*
> + * fs_readdir - Read the next directory entry in the directory stream.
> + *
> + * @dirp: the directory stream
> + * @return the next directory entry (only valid until next fs_readdir() or
> + *    fs_closedir() call, do not attempt to free()) or NULL if the end of
> + *    the directory is reached.
> + */
> +struct fs_dirent *fs_readdir(FS_DIR *dirp);
> +
> +/*
> + * fs_closedir - close a directory stream
> + *
> + * @dirp: the directory stream
> + */
> +void fs_closedir(FS_DIR *dirp);
> +
> +/*
> + * private to fs implementations, would be in fs.c but we need to let
> + * implementations subclass:
> + */
> +
> +struct _FS_DIR {
> +	struct fs_dirent dirent;
> +	/* private to fs layer: */
> +	struct blk_desc *desc;
> +	int part;
> +};
> +
>   /*
>    * Common implementation for various filesystem commands, optionally limited
>    * to a specific filesystem type via the fstype parameter.
> diff --git a/include/part.h b/include/part.h
> index 0cd803a933..48e8ff6d8a 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -98,6 +98,7 @@ int host_get_dev_err(int dev, struct blk_desc **blk_devp);
>   
>   /* disk/part.c */
>   int part_get_info(struct blk_desc *dev_desc, int part, disk_partition_t *info);
> +int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info);
>   void part_print(struct blk_desc *dev_desc);
>   void part_init(struct blk_desc *dev_desc);
>   void dev_print(struct blk_desc *dev_desc);
> @@ -203,6 +204,9 @@ static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; }
>   
>   static inline int part_get_info(struct blk_desc *dev_desc, int part,
>   				disk_partition_t *info) { return -1; }
> +static inline int part_get_info_whole_disk(struct blk_desc *dev_desc,
> +					   disk_partition_t *info)
> +{ return -1; }
>   static inline void part_print(struct blk_desc *dev_desc) {}
>   static inline void part_init(struct blk_desc *dev_desc) {}
>   static inline void dev_print(struct blk_desc *dev_desc) {}
> 


-- 
Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de


More information about the U-Boot mailing list