[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