No need to open code after erofs_iterate_dir() is finalized in
liberofs.

Note that `erofs_get_pathname' isn't touched in this commit.

Signed-off-by: Gao Xiang <[email protected]>
---
 configure.ac           |   5 ++
 dump/main.c            | 182 +++++++++++++++++------------------------
 lib/liberofs_private.h |  12 +++
 3 files changed, 93 insertions(+), 106 deletions(-)

diff --git a/configure.ac b/configure.ac
index 6fdb0e4ce63c..a5de291c69d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -167,6 +167,11 @@ AC_CHECK_DECL(lseek64,[AC_DEFINE(HAVE_LSEEK64_PROTOTYPE, 1,
    #define _LARGEFILE64_SOURCE
    #include <unistd.h>])
 
+AC_CHECK_DECL(memrchr,[AC_DEFINE(HAVE_MEMRCHR, 1,
+  [Define to 1 if memrchr declared in string.h])],,
+  [#define _GNU_SOURCE
+   #include <string.h>])
+
 # Checks for library functions.
 AC_CHECK_FUNCS(m4_flatten([
        backtrace
diff --git a/dump/main.c b/dump/main.c
index 072d726da71b..7f3f74368332 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -5,12 +5,16 @@
  * Created by Wang Qi <[email protected]>
  *            Guo Xuenan <[email protected]>
  */
+#define _GNU_SOURCE
 #include <stdlib.h>
 #include <getopt.h>
 #include <time.h>
+#include <sys/stat.h>
 #include "erofs/print.h"
 #include "erofs/inode.h"
 #include "erofs/io.h"
+#include "erofs/dir.h"
+#include "../lib/liberofs_private.h"
 
 #ifdef HAVE_LIBUUID
 #include <uuid.h>
@@ -90,10 +94,7 @@ static struct erofsdump_feature feature_lists[] = {
        { false, EROFS_FEATURE_INCOMPAT_DEVICE_TABLE, "device_table" },
 };
 
-static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid);
-static inline int erofs_checkdirent(struct erofs_dirent *de,
-               struct erofs_dirent *last_de,
-               u32 maxsize, const char *dname);
+static int erofsdump_readdir(struct erofs_dir_context *ctx);
 
 static void usage(void)
 {
@@ -198,18 +199,20 @@ static int erofs_get_occupied_size(struct erofs_inode 
*inode,
        return 0;
 }
 
-static int erofs_getfile_extension(const char *filename)
+static void inc_file_extension_count(const char *dname, unsigned int len)
 {
-       char *postfix = strrchr(filename, '.');
-       int type = 0;
+       char *postfix = memrchr(dname, '.', len);
+       int type;
 
-       if (!postfix)
-               return OTHERFILETYPE - 1;
-       for (type = 0; type < OTHERFILETYPE - 1; ++type) {
-               if (strcmp(postfix, file_types[type]) == 0)
-                       break;
+       if (!postfix) {
+               type = OTHERFILETYPE - 1;
+       } else {
+               for (type = 0; type < OTHERFILETYPE - 1; ++type)
+                       if (!strncmp(postfix, file_types[type],
+                                    len - (postfix - dname)))
+                               break;
        }
-       return type;
+       ++stats.file_type_stat[type];
 }
 
 static void update_file_size_statatics(erofs_off_t occupied_size,
@@ -244,6 +247,56 @@ static void update_file_size_statatics(erofs_off_t 
occupied_size,
                stats.file_comp_size[occupied_size_mark]++;
 }
 
+static int erofsdump_dirent_iter(struct erofs_dir_context *ctx)
+{
+       /* skip "." and ".." dentry */
+       if (ctx->dot_dotdot)
+               return 0;
+
+       return erofsdump_readdir(ctx);
+}
+
+static int erofsdump_readdir(struct erofs_dir_context *ctx)
+{
+       int err;
+       erofs_off_t occupied_size = 0;
+       struct erofs_inode vi = { .nid = ctx->de_nid };
+
+       err = erofs_read_inode_from_disk(&vi);
+       if (err) {
+               erofs_err("failed to read file inode from disk");
+               return err;
+       }
+       stats.files++;
+       stats.file_category_stat[erofs_mode_to_ftype(vi.i_mode)]++;
+
+       err = erofs_get_occupied_size(&vi, &occupied_size);
+       if (err) {
+               erofs_err("get file size failed");
+               return err;
+       }
+
+       if (S_ISREG(vi.i_mode)) {
+               stats.files_total_origin_size += vi.i_size;
+               inc_file_extension_count(ctx->dname, ctx->de_namelen);
+               stats.files_total_size += occupied_size;
+               update_file_size_statatics(occupied_size, vi.i_size);
+       }
+
+       /* XXXX: the dir depth should be restricted in order to avoid loops */
+       if (S_ISDIR(vi.i_mode)) {
+               struct erofs_dir_context nctx = {
+                       .flags = ctx->dir ? EROFS_READDIR_VALID_PNID : 0,
+                       .pnid = ctx->dir ? ctx->dir->nid : 0,
+                       .dir = &vi,
+                       .cb = erofsdump_dirent_iter,
+               };
+
+               return erofs_iterate_dir(&nctx, false);
+       }
+       return 0;
+}
+
 static inline int erofs_checkdirent(struct erofs_dirent *de,
                struct erofs_dirent *last_de,
                u32 maxsize, const char *dname)
@@ -275,97 +328,6 @@ static inline int erofs_checkdirent(struct erofs_dirent 
*de,
        return dname_len;
 }
 
-static int erofs_read_dirent(struct erofs_dirent *de,
-               erofs_nid_t nid, erofs_nid_t parent_nid,
-               const char *dname)
-{
-       int err;
-       erofs_off_t occupied_size = 0;
-       struct erofs_inode inode = { .nid = le64_to_cpu(de->nid) };
-
-       stats.files++;
-       stats.file_category_stat[de->file_type]++;
-       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;
-       }
-
-       if (de->file_type == EROFS_FT_REG_FILE) {
-               stats.files_total_origin_size += inode.i_size;
-               stats.file_type_stat[erofs_getfile_extension(dname)]++;
-               stats.files_total_size += occupied_size;
-               update_file_size_statatics(occupied_size, inode.i_size);
-       }
-
-       if (de->file_type == EROFS_FT_DIR && inode.nid != nid &&
-           inode.nid != parent_nid) {
-               err = erofs_read_dir(inode.nid, nid);
-               if (err) {
-                       erofs_err("parse dir nid %llu error occurred\n",
-                                 inode.nid | 0ULL);
-                       return err;
-               }
-       }
-       return 0;
-}
-
-static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid)
-{
-       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;
-
-       offset = 0;
-       while (offset < vi.i_size) {
-               erofs_off_t maxsize = min_t(erofs_off_t,
-                                               vi.i_size - offset, 
EROFS_BLKSIZ);
-               struct erofs_dirent *de = (void *)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 = (void *)buf + nameoff;
-               while (de < end) {
-                       const char *dname;
-                       int ret;
-
-                       /* skip "." and ".." dentry */
-                       if (le64_to_cpu(de->nid) == nid ||
-                           le64_to_cpu(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(de, nid, parent_nid, dname);
-                       if (ret < 0)
-                               return ret;
-                       ++de;
-               }
-               offset += maxsize;
-       }
-       return 0;
-}
-
 static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
                erofs_nid_t target, char *path, unsigned int pos)
 {
@@ -629,13 +591,21 @@ static void erofsdump_file_statistic(void)
 static void erofsdump_print_statistic(void)
 {
        int err;
+       struct erofs_dir_context ctx = {
+               .flags = 0,
+               .pnid = 0,
+               .dir = NULL,
+               .cb = erofsdump_dirent_iter,
+               .de_nid = sbi.root_nid,
+               .dname = "",
+               .de_namelen = 0
+       };
 
-       err = erofs_read_dir(sbi.root_nid, sbi.root_nid);
+       err = erofsdump_readdir(&ctx);
        if (err) {
                erofs_err("read dir failed");
                return;
        }
-
        erofsdump_file_statistic();
        erofsdump_filesize_distribution("Original",
                        stats.file_original_size,
diff --git a/lib/liberofs_private.h b/lib/liberofs_private.h
index c2312e8e7a31..0eeca3c1d601 100644
--- a/lib/liberofs_private.h
+++ b/lib/liberofs_private.h
@@ -11,3 +11,15 @@
 #include <private/canned_fs_config.h>
 #include <private/fs_config.h>
 #endif
+
+#ifndef HAVE_MEMRCHR
+static inline void *memrchr(const void *s, int c, size_t n)
+{
+       const unsigned char *p = (const unsigned char *)s;
+
+       for (p += n; n > 0; n--)
+               if (*--p == c)
+                       return (void*)p;
+       return NULL;
+}
+#endif
-- 
2.20.1

Reply via email to