From patchwork Sun Sep 10 11:21:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 812114 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="nGXvdYuq"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3xqpt05QMRz9sDB for ; Sun, 10 Sep 2017 21:36:24 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 8E4E5C21F21; Sun, 10 Sep 2017 11:26:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id EFAEDC21F47; Sun, 10 Sep 2017 11:24:22 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 6E5E8C21F58; Sun, 10 Sep 2017 11:22:38 +0000 (UTC) Received: from mail-qt0-f194.google.com (mail-qt0-f194.google.com [209.85.216.194]) by lists.denx.de (Postfix) with ESMTPS id 036B1C21DEF for ; Sun, 10 Sep 2017 11:22:32 +0000 (UTC) Received: by mail-qt0-f194.google.com with SMTP id k2so4080027qte.5 for ; Sun, 10 Sep 2017 04:22:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=H/PHz9M1Onapa4r2mUlmZrc6JQMTaIbCS4SXtWVnBXA=; b=nGXvdYuqqbYx7uM5WTUxpJjYYismaZh4RLfQ4qePtNhumBzIIslza0n5fJcsn2w7kC 4VwWWSfZw3i+sslbyIiczNzHpOKv3wQg8JSSigtl4wFuxQQdZecItZxK5T2mRXxP9iQT jzmmaD7Xa7xGGmc5WCOyhT+yujpjSdbQOrsB1AymqPhp0HYvph8332M8o5BhfA7Ix2wL tGKsHLjLK/R/OhoPfMste0sRVpRLwh6gb6K7zEnrSYhCGZhZ/1+1mX5MhV/DOw72ZRj5 gAACjXX8JYMud2LJa6iKgqfxh6e/RFcfRk8clctWi/qHGXNRDSA3c5JEsF+vzydH54sT 8tvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=H/PHz9M1Onapa4r2mUlmZrc6JQMTaIbCS4SXtWVnBXA=; b=eNsWEDlQ9PDfi8O589jA2zoYw4rw0ZNDnySAhAoC7T73CjbaN2WX4fbpIhq7XwxC1e EpbtPotHKpCOkszV7ufKTpkCT3Y1lYtoBuMIvmvMlX/dm6kTAw4M7kkfDinPd5bzfNDr 5hwaq3CH4m2KQMKKZtD+7TvKBCak1e162/moV5TCqvx2gZMh+51czeO/Uz1UdyGyoe1O rcTjhAVoeTCvWXR+LYfHHzUaksK6+MoF5v9jf2cgrse53O/bj7erGwFUh8cwJ+Oby7ec mhCv4nMxTJnyEAGGCQOt2Z+0/DroZXwoM5amHJxlWn2cId6YoRTHngpdAlBCTSpEkBpi zZIQ== X-Gm-Message-State: AHPjjUjBcynwIyl9HqYA892Xgu69p/edPgW+GdxRJJyCm9FcUQCvaeni 7kCS2PbyYIiOX5r1jEw= X-Google-Smtp-Source: AOwi7QAxWcHtDDez3TnGqvBttZs2angcyNuW+avx5NabZ6N9xYKjT/FpAMTHrkALz9UF7+TmmRXSPw== X-Received: by 10.200.13.8 with SMTP id q8mr10975837qti.99.1505042550591; Sun, 10 Sep 2017 04:22:30 -0700 (PDT) Received: from localhost ([2601:184:4780:aac0:25f8:dd96:a084:785a]) by smtp.gmail.com with ESMTPSA id 25sm4399980qtv.14.2017.09.10.04.22.29 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 10 Sep 2017 04:22:29 -0700 (PDT) From: Rob Clark To: U-Boot Mailing List Date: Sun, 10 Sep 2017 07:21:25 -0400 Message-Id: <20170910112149.21358-9-robdclark@gmail.com> X-Mailer: git-send-email 2.13.5 In-Reply-To: <20170910112149.21358-1-robdclark@gmail.com> References: <20170910112149.21358-1-robdclark@gmail.com> MIME-Version: 1.0 Cc: Alison Chaiken , Petr Kulhavy , Heinrich Schuchardt , Zhikang Zhang , Steve Rae , Maxime Ripard Subject: [U-Boot] [PATCH v3 4/9] fs: add fs_readdir() X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 Reviewed-by: Ɓukasz Majewski --- disk/part.c | 31 ++++++++++------- fs/fs.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 67 +++++++++++++++++++++++++++++++++++++ include/part.h | 9 +++++ 4 files changed, 199 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..fc0c953fcb 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,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, }, }; @@ -228,6 +254,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_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) { diff --git a/include/fs.h b/include/fs.h index 2f2aca8378..0869ad6e80 100644 --- a/include/fs.h +++ b/include/fs.h @@ -27,6 +27,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". * @@ -79,6 +90,62 @@ 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. */ diff --git a/include/part.h b/include/part.h index 0d5c99836b..86117a7ce5 100644 --- a/include/part.h +++ b/include/part.h @@ -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) {}