Friendly ping On Wed, Dec 8, 2021 at 5:21 PM Kelvin Zhang <[email protected]> wrote:
> Change-Id: Ia35708080a72ee204eaaddfc670d3cb8023a078c > Signed-off-by: Kelvin Zhang <[email protected]> > --- > 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
