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