[PATCH] erofs-utils: dump: convert readdir to use erofs_iterate_dir()

Gao Xiang xiang at kernel.org
Fri Dec 17 03:02:54 AEDT 2021


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 <xiang at kernel.org>
---
 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 <mpiglet at outlook.com>
  *            Guo Xuenan <guoxuenan at huawei.com>
  */
+#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



More information about the Linux-erofs mailing list