All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gao Xiang <xiang@kernel.org>
To: linux-erofs@lists.ozlabs.org
Subject: [PATCH] erofs-utils: dump: convert readdir to use erofs_iterate_dir()
Date: Fri, 17 Dec 2021 00:02:54 +0800	[thread overview]
Message-ID: <20211216160254.28166-1-xiang@kernel.org> (raw)

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@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@outlook.com>
  *            Guo Xuenan <guoxuenan@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


                 reply	other threads:[~2021-12-16 16:03 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211216160254.28166-1-xiang@kernel.org \
    --to=xiang@kernel.org \
    --cc=linux-erofs@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.