[PATCH v2 2/2] Add API to iterate over inodes in EROFS
Kelvin Zhang
zhangkelvin at google.com
Tue Dec 14 09:42:19 AEDT 2021
Friendly ping
On Wed, Dec 8, 2021 at 5:21 PM Kelvin Zhang <zhangkelvin at google.com> wrote:
> Change-Id: Ia35708080a72ee204eaaddfc670d3cb8023a078c
> Signed-off-by: Kelvin Zhang <zhangkelvin at google.com>
> ---
> include/erofs/iterate.h | 57 +++++++++++++
> lib/Makefile.am | 2 +-
> lib/iterate.c | 173 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 231 insertions(+), 1 deletion(-)
> create mode 100644 include/erofs/iterate.h
> create mode 100644 lib/iterate.c
>
> diff --git a/include/erofs/iterate.h b/include/erofs/iterate.h
> new file mode 100644
> index 0000000..96171a7
> --- /dev/null
> +++ b/include/erofs/iterate.h
> @@ -0,0 +1,57 @@
> +//
> +// Copyright (C) 2021 The Android Open Source Project
> +//
> +// Licensed under the Apache License, Version 2.0 (the "License");
> +// you may not use this file except in compliance with the License.
> +// You may obtain a copy of the License at
> +//
> +// http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing, software
> +// distributed under the License is distributed on an "AS IS" BASIS,
> +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> +// See the License for the specific language governing permissions and
> +// limitations under the License.
> +//
> +
> +#ifndef ITERATE_ITERATE
> +#define ITERATE_ITERATE
> +
> +#ifdef __cplusplus
> +extern "C"
> +{
> +#endif
> +
> +
> +#include "erofs/io.h"
> +#include "erofs/print.h"
> +
> +
> +struct erofs_inode_info {
> + uint64_t inode_id;
> + const char* name;
> + bool is_reg_file;
> + u64 compressed_size;
> + u64 uncompressed_size;
> + struct erofs_inode* inode;
> + void* arg;
> +};
> +// Callback function for iterating over inodes of EROFS
> +
> +typedef bool (*ErofsIterCallback)(struct erofs_inode_info);
> +
> +int erofs_iterate_dir(const struct erofs_sb_info* sbi,
> + erofs_nid_t nid,
> + erofs_nid_t parent_nid,
> + ErofsIterCallback cb,
> + void* arg);
> +int erofs_iterate_root_dir(const struct erofs_sb_info* sbi,
> + ErofsIterCallback cbg,
> + void* arg);
> +int erofs_get_occupied_size(struct erofs_inode* inode, erofs_off_t* size);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif // ITERATE_ITERATE
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index 67ba798..20c0e4f 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -27,7 +27,7 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \
> noinst_HEADERS += compressor.h
> liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c
> exclude.c \
> namei.c data.c compress.c compressor.c zmap.c
> decompress.c \
> - compress_hints.c hashmap.c sha256.c blobchunk.c
> + compress_hints.c hashmap.c sha256.c blobchunk.c
> iterate.c
> liberofs_la_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
> if ENABLE_LZ4
> liberofs_la_CFLAGS += ${LZ4_CFLAGS}
> diff --git a/lib/iterate.c b/lib/iterate.c
> new file mode 100644
> index 0000000..1a10ec1
> --- /dev/null
> +++ b/lib/iterate.c
> @@ -0,0 +1,173 @@
> +//
> +// Copyright (C) 2021 The Android Open Source Project
> +//
> +// Licensed under the Apache License, Version 2.0 (the "License");
> +// you may not use this file except in compliance with the License.
> +// You may obtain a copy of the License at
> +//
> +// http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing, software
> +// distributed under the License is distributed on an "AS IS" BASIS,
> +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> +// See the License for the specific language governing permissions and
> +// limitations under the License.
> +//
> +
> +#include "erofs/internal.h"
> +#include "erofs_fs.h"
> +#include "erofs/print.h"
> +#include "erofs/iterate.h"
> +
> +static int erofs_read_dirent(const struct erofs_sb_info* sbi,
> + const struct erofs_dirent* de,
> + erofs_nid_t nid,
> + erofs_nid_t parent_nid,
> + const char* dname,
> + ErofsIterCallback cb,
> + void* arg) {
> + int err;
> + erofs_off_t occupied_size = 0;
> + struct erofs_inode inode = {.nid = de->nid};
> + err = erofs_read_inode_from_disk(&inode);
> + if (err) {
> + erofs_err("read file inode from disk failed!");
> + return err;
> + }
> + err = erofs_get_occupied_size(&inode, &occupied_size);
> + if (err) {
> + erofs_err("get file size failed\n");
> + return err;
> + }
> + char buf[PATH_MAX + 1];
> + erofs_get_inode_name(sbi, de->nid, buf, PATH_MAX + 1);
> + struct erofs_inode_info info = {
> + .inode_id = de->nid,
> + .name = buf,
> + .is_reg_file = de->file_type == EROFS_FT_REG_FILE,
> + .compressed_size = occupied_size,
> + .uncompressed_size = inode.i_size,
> + .inode = &inode,
> + .arg = arg};
> + cb(info);
> + if ((de->file_type == EROFS_FT_DIR) && de->nid != nid &&
> + de->nid != parent_nid) {
> + err = erofs_iterate_dir(sbi, de->nid, nid, cb, arg);
> + if (err) {
> + erofs_err("parse dir nid %u error occurred\n",
> + (unsigned int)(de->nid));
> + return err;
> + }
> + }
> + return 0;
> +}
> +
> +static inline int erofs_checkdirent(const struct erofs_dirent* de,
> + const struct erofs_dirent* last_de,
> + u32 maxsize,
> + const char* dname) {
> + int dname_len;
> + unsigned int nameoff = le16_to_cpu(de->nameoff);
> + if (nameoff < sizeof(struct erofs_dirent) || nameoff >= PAGE_SIZE) {
> + erofs_err("invalid de[0].nameoff %u @ nid %llu", nameoff, de->nid |
> 0ULL);
> + return -EFSCORRUPTED;
> + }
> + dname_len = (de + 1 >= last_de) ? strnlen(dname, maxsize - nameoff)
> + : le16_to_cpu(de[1].nameoff) - nameoff;
> + /* a corrupted entry is found */
> + if (nameoff + dname_len > maxsize || dname_len > EROFS_NAME_LEN) {
> + erofs_err("bogus dirent @ nid %llu", le64_to_cpu(de->nid) | 0ULL);
> + DBG_BUGON(1);
> + return -EFSCORRUPTED;
> + }
> + if (de->file_type >= EROFS_FT_MAX) {
> + erofs_err("invalid file type %u", (unsigned int)(de->nid));
> + return -EFSCORRUPTED;
> + }
> + return dname_len;
> +}
> +
> +int erofs_iterate_dir(const struct erofs_sb_info* sbi,
> + erofs_nid_t nid,
> + erofs_nid_t parent_nid,
> + ErofsIterCallback cb,
> + void* arg) {
> + int err;
> + erofs_off_t offset;
> + char buf[EROFS_BLKSIZ];
> + struct erofs_inode vi = {.nid = nid};
> + err = erofs_read_inode_from_disk(&vi);
> + if (err)
> + return err;
> + struct erofs_inode_info inode_info = {
> + .inode_id = nid,
> + .name = buf,
> + .is_reg_file = false,
> + .compressed_size = vi.i_size,
> + .uncompressed_size = vi.i_size,
> + .inode = &vi,
> + .arg = arg,
> + };
> + err = erofs_get_inode_name(sbi, nid, buf, EROFS_BLKSIZ);
> + cb(inode_info);
> + if (err) {
> + return err;
> + }
> + offset = 0;
> + while (offset < vi.i_size) {
> + erofs_off_t maxsize = min_t(erofs_off_t, vi.i_size - offset,
> EROFS_BLKSIZ);
> + const struct erofs_dirent* de = (const struct erofs_dirent*)(buf);
> + struct erofs_dirent* end;
> + unsigned int nameoff;
> + err = erofs_pread(&vi, buf, maxsize, offset);
> + if (err)
> + return err;
> + nameoff = le16_to_cpu(de->nameoff);
> + end = (struct erofs_dirent*)(buf + nameoff);
> + while (de < end) {
> + const char* dname;
> + int ret;
> + /* skip "." and ".." dentry */
> + if (de->nid == nid || de->nid == parent_nid) {
> + de++;
> + continue;
> + }
> + dname = (char*)buf + nameoff;
> + ret = erofs_checkdirent(de, end, maxsize, dname);
> + if (ret < 0)
> + return ret;
> + ret = erofs_read_dirent(sbi, de, nid, parent_nid, dname, cb, arg);
> + if (ret < 0)
> + return ret;
> + ++de;
> + }
> + offset += maxsize;
> + }
> + return 0;
> +}
> +
> +int erofs_get_occupied_size(struct erofs_inode* inode, erofs_off_t* size)
> {
> + *size = 0;
> + switch (inode->datalayout) {
> + case EROFS_INODE_FLAT_INLINE:
> + case EROFS_INODE_FLAT_PLAIN:
> + case EROFS_INODE_CHUNK_BASED:
> + *size = inode->i_size;
> + break;
> + case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
> + case EROFS_INODE_FLAT_COMPRESSION:
> + *size = inode->u.i_blocks * EROFS_BLKSIZ;
> + break;
> + default:
> + erofs_err("unknown datalayout");
> + return -1;
> + }
> + return 0;
> +}
> +
> +int erofs_iterate_root_dir(const struct erofs_sb_info* sbi,
> + ErofsIterCallback cb,
> + void* arg) {
> + return erofs_iterate_dir(sbi, sbi->root_nid, sbi->root_nid, cb, arg);
> +}
> +
> --
> 2.34.1.173.g76aa8bc2d0-goog
>
>
--
Sincerely,
Kelvin Zhang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/linux-erofs/attachments/20211213/1a24aa66/attachment.htm>
More information about the Linux-erofs
mailing list