fs: add fs_readdir()
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. Signed-off-by: Rob Clark <robdclark@gmail.com> Reviewed-by: Łukasz Majewski <lukma@denx.de> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
8eafae209c
commit
4bbcc965f9
31
disk/part.c
31
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;
|
||||
|
104
fs/fs.c
104
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,12 @@ static inline int fs_uuid_unsupported(char *uuid_str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int fs_opendir_unsupported(const char *filename,
|
||||
struct fs_dir_stream **dirs)
|
||||
{
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
struct fstype_info {
|
||||
int fstype;
|
||||
char *name;
|
||||
@ -92,6 +99,20 @@ struct fstype_info {
|
||||
loff_t len, loff_t *actwrite);
|
||||
void (*close)(void);
|
||||
int (*uuid)(char *uuid_str);
|
||||
/*
|
||||
* Open a directory stream. On success return 0 and directory
|
||||
* stream pointer via 'dirsp'. On error, return -errno. See
|
||||
* fs_opendir().
|
||||
*/
|
||||
int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
|
||||
/*
|
||||
* Read next entry from directory stream. On success return 0
|
||||
* and directory entry pointer via 'dentp'. On error return
|
||||
* -errno. See fs_readdir().
|
||||
*/
|
||||
int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
|
||||
/* see fs_closedir() */
|
||||
void (*closedir)(struct fs_dir_stream *dirs);
|
||||
};
|
||||
|
||||
static struct fstype_info fstypes[] = {
|
||||
@ -112,6 +133,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 +153,7 @@ static struct fstype_info fstypes[] = {
|
||||
.write = fs_write_unsupported,
|
||||
#endif
|
||||
.uuid = ext4fs_uuid,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_SANDBOX
|
||||
@ -146,6 +169,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 +185,7 @@ static struct fstype_info fstypes[] = {
|
||||
.read = ubifs_read,
|
||||
.write = fs_write_unsupported,
|
||||
.uuid = fs_uuid_unsupported,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
@ -175,6 +200,7 @@ static struct fstype_info fstypes[] = {
|
||||
.read = fs_read_unsupported,
|
||||
.write = fs_write_unsupported,
|
||||
.uuid = fs_uuid_unsupported,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
},
|
||||
};
|
||||
|
||||
@ -226,6 +252,31 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
|
||||
if (!fs_dev_desc && !info->null_dev_desc_ok)
|
||||
continue;
|
||||
|
||||
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_dev_with_part(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 +385,59 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct fs_dir_stream *fs_opendir(const char *filename)
|
||||
{
|
||||
struct fstype_info *info = fs_get_info(fs_type);
|
||||
struct fs_dir_stream *dirs = NULL;
|
||||
int ret;
|
||||
|
||||
ret = info->opendir(filename, &dirs);
|
||||
fs_close();
|
||||
if (ret) {
|
||||
errno = -ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dirs->desc = fs_dev_desc;
|
||||
dirs->part = fs_dev_part;
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
||||
struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
|
||||
{
|
||||
struct fstype_info *info;
|
||||
struct fs_dirent *dirent;
|
||||
int ret;
|
||||
|
||||
fs_set_blk_dev_with_part(dirs->desc, dirs->part);
|
||||
info = fs_get_info(fs_type);
|
||||
|
||||
ret = info->readdir(dirs, &dirent);
|
||||
fs_close();
|
||||
if (ret) {
|
||||
errno = -ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dirent;
|
||||
}
|
||||
|
||||
void fs_closedir(struct fs_dir_stream *dirs)
|
||||
{
|
||||
struct fstype_info *info;
|
||||
|
||||
if (!dirs)
|
||||
return;
|
||||
|
||||
fs_set_blk_dev_with_part(dirs->desc, dirs->part);
|
||||
info = fs_get_info(fs_type);
|
||||
|
||||
info->closedir(dirs);
|
||||
fs_close();
|
||||
}
|
||||
|
||||
|
||||
int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype)
|
||||
{
|
||||
|
67
include/fs.h
67
include/fs.h
@ -26,6 +26,17 @@
|
||||
*/
|
||||
int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype);
|
||||
|
||||
/*
|
||||
* fs_set_blk_dev_with_part - Set current block device + partition
|
||||
*
|
||||
* Similar to fs_set_blk_dev(), but useful for cases where you already
|
||||
* know the blk_desc and part number.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns non-zero if invalid partition or error accessing the disk.
|
||||
*/
|
||||
int fs_set_blk_dev_with_part(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 +89,62 @@ 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);
|
||||
|
||||
/*
|
||||
* Directory entry types, matches the subset of DT_x in posix readdir()
|
||||
* which apply to u-boot.
|
||||
*/
|
||||
#define FS_DT_DIR 4 /* directory */
|
||||
#define FS_DT_REG 8 /* regular file */
|
||||
#define FS_DT_LNK 10 /* symbolic link */
|
||||
|
||||
/*
|
||||
* A directory entry, returned by fs_readdir(). Returns information
|
||||
* about the file/directory at the current directory entry position.
|
||||
*/
|
||||
struct fs_dirent {
|
||||
unsigned type; /* one of FS_DT_x (not a mask) */
|
||||
loff_t size; /* size in bytes */
|
||||
char name[256];
|
||||
};
|
||||
|
||||
/* Note: fs_dir_stream should be treated as opaque to the user of fs layer */
|
||||
struct fs_dir_stream {
|
||||
/* private to fs. layer: */
|
||||
struct blk_desc *desc;
|
||||
int part;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
struct fs_dir_stream *fs_opendir(const char *filename);
|
||||
|
||||
/*
|
||||
* fs_readdir - Read the next directory entry in the directory stream.
|
||||
*
|
||||
* Works in an analogous way to posix readdir(). The previously returned
|
||||
* directory entry is no longer valid after calling fs_readdir() again.
|
||||
* After fs_closedir() is called, the returned directory entry is no
|
||||
* longer valid.
|
||||
*
|
||||
* @dirs: 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(struct fs_dir_stream *dirs);
|
||||
|
||||
/*
|
||||
* fs_closedir - close a directory stream
|
||||
*
|
||||
* @dirs: the directory stream
|
||||
*/
|
||||
void fs_closedir(struct fs_dir_stream *dirs);
|
||||
|
||||
/*
|
||||
* Common implementation for various filesystem commands, optionally limited
|
||||
* to a specific filesystem type via the fstype parameter.
|
||||
|
@ -98,6 +98,12 @@ 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);
|
||||
/**
|
||||
* part_get_info_whole_disk() - get partition info for the special case of
|
||||
* a partition occupying the entire disk.
|
||||
*/
|
||||
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 +209,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) {}
|
||||
|
Loading…
Reference in New Issue
Block a user