* [PATCH v3 1/2] erofs-utils: lib: add API to iterate dirs in EROFS
@ 2021-12-16 1:24 Gao Xiang
2021-12-16 1:24 ` [PATCH v3 2/2] erofs-utils: fsck: convert to use erofs_iterate_dir() Gao Xiang
0 siblings, 1 reply; 2+ messages in thread
From: Gao Xiang @ 2021-12-16 1:24 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
This introduces erofs_iterate_dir() to iterate all dirents in
a directory inode and convert erofsfuse to use the API.
Note that it doesn't recursively walk into sub-directories.
If it's really needed, users should handle this in the callback.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
v3: https://lore.kernel.org/linux-erofs/20211215194200.61210-1-hsiangkao@linux.alibaba.com/
changes since v2:
- resolve nid endianless issue.
fuse/Makefile.am | 2 +-
fuse/dir.c | 100 -----------------------
fuse/main.c | 52 +++++++++++-
include/erofs/dir.h | 53 +++++++++++++
include/erofs/internal.h | 8 ++
lib/Makefile.am | 2 +-
lib/dir.c | 167 +++++++++++++++++++++++++++++++++++++++
7 files changed, 280 insertions(+), 104 deletions(-)
delete mode 100644 fuse/dir.c
create mode 100644 include/erofs/dir.h
create mode 100644 lib/dir.c
diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 8a2d4720d1b7..5aa5ac07be70 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,7 +3,7 @@
AUTOMAKE_OPTIONS = foreign
noinst_HEADERS = $(top_srcdir)/fuse/macosx.h
bin_PROGRAMS = erofsfuse
-erofsfuse_SOURCES = dir.c main.c
+erofsfuse_SOURCES = main.c
erofsfuse_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
erofsfuse_CFLAGS += -DFUSE_USE_VERSION=26 ${libfuse_CFLAGS} ${libselinux_CFLAGS}
erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la ${libfuse_LIBS} ${liblz4_LIBS} \
diff --git a/fuse/dir.c b/fuse/dir.c
deleted file mode 100644
index bc8735bedb6f..000000000000
--- a/fuse/dir.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#include <fuse.h>
-#include <fuse_opt.h>
-#include "macosx.h"
-#include "erofs/internal.h"
-#include "erofs/print.h"
-
-static int erofs_fill_dentries(struct erofs_inode *dir,
- fuse_fill_dir_t filler, void *buf,
- void *dblk, unsigned int nameoff,
- unsigned int maxsize)
-{
- struct erofs_dirent *de = dblk;
- const struct erofs_dirent *end = dblk + nameoff;
- char namebuf[EROFS_NAME_LEN + 1];
-
- while (de < end) {
- const char *de_name;
- unsigned int de_namelen;
-
- nameoff = le16_to_cpu(de->nameoff);
- de_name = (char *)dblk + nameoff;
-
- /* the last dirent in the block? */
- if (de + 1 >= end)
- de_namelen = strnlen(de_name, maxsize - nameoff);
- else
- de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
-
- /* a corrupted entry is found */
- if (nameoff + de_namelen > maxsize ||
- de_namelen > EROFS_NAME_LEN) {
- erofs_err("bogus dirent @ nid %llu", dir->nid | 0ULL);
- DBG_BUGON(1);
- return -EFSCORRUPTED;
- }
-
- memcpy(namebuf, de_name, de_namelen);
- namebuf[de_namelen] = '\0';
-
- filler(buf, namebuf, NULL, 0);
- ++de;
- }
- return 0;
-}
-
-int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
- off_t offset, struct fuse_file_info *fi)
-{
- int ret;
- struct erofs_inode dir;
- char dblk[EROFS_BLKSIZ];
- erofs_off_t pos;
-
- erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
-
- ret = erofs_ilookup(path, &dir);
- if (ret)
- return ret;
-
- erofs_dbg("path=%s nid = %llu", path, dir.nid | 0ULL);
-
- if (!S_ISDIR(dir.i_mode))
- return -ENOTDIR;
-
- if (!dir.i_size)
- return 0;
-
- pos = 0;
- while (pos < dir.i_size) {
- unsigned int nameoff, maxsize;
- struct erofs_dirent *de;
-
- maxsize = min_t(unsigned int, EROFS_BLKSIZ,
- dir.i_size - pos);
- ret = erofs_pread(&dir, dblk, maxsize, pos);
- if (ret)
- return ret;
-
- de = (struct erofs_dirent *)dblk;
- nameoff = le16_to_cpu(de->nameoff);
- if (nameoff < sizeof(struct erofs_dirent) ||
- nameoff >= PAGE_SIZE) {
- erofs_err("invalid de[0].nameoff %u @ nid %llu",
- nameoff, dir.nid | 0ULL);
- ret = -EFSCORRUPTED;
- break;
- }
-
- ret = erofs_fill_dentries(&dir, filler, buf,
- dblk, nameoff, maxsize);
- if (ret)
- break;
- pos += maxsize;
- }
- return 0;
-}
diff --git a/fuse/main.c b/fuse/main.c
index 255965e30969..2549d8a9b33a 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -12,9 +12,57 @@
#include "erofs/config.h"
#include "erofs/print.h"
#include "erofs/io.h"
+#include "erofs/dir.h"
-int erofsfuse_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
- off_t offset, struct fuse_file_info *fi);
+struct erofsfuse_dir_context {
+ struct erofs_dir_context ctx;
+ fuse_fill_dir_t filler;
+ struct fuse_file_info *fi;
+ void *buf;
+};
+
+static int erofsfuse_fill_dentries(struct erofs_dir_context *ctx)
+{
+ struct erofsfuse_dir_context *fusectx = (void *)ctx;
+ char dname[EROFS_NAME_LEN + 1];
+
+ strncpy(dname, ctx->dname, ctx->de_namelen);
+ dname[ctx->de_namelen] = '\0';
+ fusectx->filler(fusectx->buf, dname, NULL, 0);
+ return 0;
+}
+
+int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi)
+{
+ int ret;
+ struct erofs_inode dir;
+ struct erofsfuse_dir_context ctx = {
+ .ctx.dir = &dir,
+ .ctx.cb = erofsfuse_fill_dentries,
+ .filler = filler,
+ .fi = fi,
+ .buf = buf,
+ };
+ erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
+
+ ret = erofs_ilookup(path, &dir);
+ if (ret)
+ return ret;
+
+ erofs_dbg("path=%s nid = %llu", path, dir.nid | 0ULL);
+ if (!S_ISDIR(dir.i_mode))
+ return -ENOTDIR;
+
+ if (!dir.i_size)
+ return 0;
+#ifdef NDEBUG
+ return erofs_iterate_dir(&ctx.ctx, false);
+#else
+ return erofs_iterate_dir(&ctx.ctx, true);
+#endif
+
+}
static void *erofsfuse_init(struct fuse_conn_info *info)
{
diff --git a/include/erofs/dir.h b/include/erofs/dir.h
new file mode 100644
index 000000000000..25d6ce7ca072
--- /dev/null
+++ b/include/erofs/dir.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */
+#ifndef __EROFS_DIR_H
+#define __EROFS_DIR_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "internal.h"
+
+#define EROFS_READDIR_VALID_PNID 0x0001
+#define EROFS_READDIR_DOTDOT_FOUND 0x0002
+#define EROFS_READDIR_DOT_FOUND 0x0004
+
+#define EROFS_READDIR_ALL_SPECIAL_FOUND \
+ (EROFS_READDIR_DOTDOT_FOUND | EROFS_READDIR_DOT_FOUND)
+
+struct erofs_dir_context;
+
+/* callback function for iterating over inodes of EROFS */
+typedef int (*erofs_readdir_cb)(struct erofs_dir_context *);
+
+/*
+ * Callers could use a wrapper to contain extra information.
+ *
+ * Note that callback can reuse `struct erofs_dir_context' with care
+ * to avoid stack overflow due to deep recursion: dir, pnid, flags,
+ * (optional)cb SHOULD be saved to ensure the original state.
+ *
+ * Another way is to allocate `struct erofs_dir_context' on heap,
+ * and chain them together for multi-level traversal.
+ */
+struct erofs_dir_context {
+ struct erofs_inode *dir;
+ erofs_readdir_cb cb;
+ erofs_nid_t pnid; /* optional */
+
+ /* [out] the dirent which is under processing */
+ const char *dname;
+ erofs_nid_t de_nid;
+ u8 de_namelen, de_ftype, flags;
+ bool dot_dotdot;
+};
+
+/* iterate over inodes that are in directory */
+int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index e6beb8cb8528..d2adf57d8ae2 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -235,6 +235,14 @@ struct erofs_dentry {
};
};
+static inline bool is_dot_dotdot_len(const char *name, unsigned int len)
+{
+ if (len >= 1 && name[0] != '.')
+ return false;
+
+ return len == 1 || (len == 2 && name[1] == '.');
+}
+
static inline bool is_dot_dotdot(const char *name)
{
if (name[0] != '.')
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c745e493c391..4a2501342729 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -27,7 +27,7 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \
noinst_HEADERS += compressor.h
liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \
namei.c data.c compress.c compressor.c zmap.c decompress.c \
- compress_hints.c hashmap.c sha256.c blobchunk.c
+ compress_hints.c hashmap.c sha256.c blobchunk.c dir.c
liberofs_la_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
if ENABLE_LZ4
liberofs_la_CFLAGS += ${LZ4_CFLAGS}
diff --git a/lib/dir.c b/lib/dir.c
new file mode 100644
index 000000000000..63e35ba2318b
--- /dev/null
+++ b/lib/dir.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
+#include "erofs/print.h"
+#include "erofs/dir.h"
+#include <stdlib.h>
+
+static int traverse_dirents(struct erofs_dir_context *ctx,
+ void *dentry_blk, unsigned int lblk,
+ unsigned int next_nameoff, unsigned int maxsize,
+ bool fsck)
+{
+ struct erofs_dirent *de = dentry_blk;
+ const struct erofs_dirent *end = dentry_blk + next_nameoff;
+ const char *prev_name = NULL;
+ const char *errmsg;
+ unsigned int prev_namelen = 0;
+ int ret = 0;
+ bool silent = false;
+
+ while (de < end) {
+ const char *de_name;
+ unsigned int de_namelen;
+ unsigned int nameoff;
+
+ nameoff = le16_to_cpu(de->nameoff);
+ de_name = (char *)dentry_blk + nameoff;
+
+ /* the last dirent check */
+ if (de + 1 >= end)
+ de_namelen = strnlen(de_name, maxsize - nameoff);
+ else
+ de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+ ctx->de_nid = le64_to_cpu(de->nid);
+ erofs_dbg("traversed nid (%llu)", ctx->de_nid | 0ULL);
+
+ ret = -EFSCORRUPTED;
+ /* corrupted entry check */
+ if (nameoff != next_nameoff) {
+ errmsg = "bogus dirent nameoff";
+ break;
+ }
+
+ if (nameoff + de_namelen > maxsize ||
+ de_namelen > EROFS_NAME_LEN) {
+ errmsg = "bogus dirent namelen";
+ break;
+ }
+
+ if (fsck && prev_name) {
+ int cmp = strncmp(prev_name, de_name,
+ min(prev_namelen, de_namelen));
+
+ if (cmp > 0 || (cmp == 0 &&
+ prev_namelen >= de_namelen)) {
+ errmsg = "wrong dirent name order";
+ break;
+ }
+ }
+
+ if (fsck && de->file_type >= EROFS_FT_MAX) {
+ errmsg = "invalid file type %u";
+ break;
+ }
+
+ ctx->dname = de_name;
+ ctx->de_namelen = de_namelen;
+ ctx->dot_dotdot = is_dot_dotdot_len(de_name, de_namelen);
+ if (ctx->dot_dotdot) {
+ switch (de_namelen) {
+ case 2:
+ if (fsck &&
+ (ctx->flags & EROFS_READDIR_DOTDOT_FOUND)) {
+ errmsg = "duplicated `..' dirent";
+ goto out;
+ }
+ ctx->flags |= EROFS_READDIR_DOTDOT_FOUND;
+ if (sbi.root_nid == ctx->dir->nid) {
+ ctx->pnid = sbi.root_nid;
+ ctx->flags |= EROFS_READDIR_VALID_PNID;
+ }
+ if (fsck &&
+ (ctx->flags & EROFS_READDIR_VALID_PNID) &&
+ ctx->de_nid != ctx->pnid) {
+ errmsg = "corrupted `..' dirent";
+ goto out;
+ }
+ break;
+ case 1:
+ if (fsck &&
+ (ctx->flags & EROFS_READDIR_DOT_FOUND)) {
+ errmsg = "duplicated `.' dirent";
+ goto out;
+ }
+
+ ctx->flags |= EROFS_READDIR_DOT_FOUND;
+ if (fsck && ctx->de_nid != ctx->dir->nid) {
+ errmsg = "corrupted `.' dirent";
+ goto out;
+ }
+ break;
+ }
+ }
+ ret = ctx->cb(ctx);
+ if (ret) {
+ silent = true;
+ break;
+ }
+ prev_name = de_name;
+ prev_namelen = de_namelen;
+ next_nameoff += de_namelen;
+ ++de;
+ }
+out:
+ if (ret && !silent)
+ erofs_err("%s @ nid %llu, lblk %u, index %lu",
+ errmsg, ctx->dir->nid | 0ULL, lblk,
+ (de - (struct erofs_dirent *)dentry_blk) | 0UL);
+ return ret;
+}
+
+int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
+{
+ struct erofs_inode *dir = ctx->dir;
+ int err;
+ erofs_off_t pos;
+ char buf[EROFS_BLKSIZ];
+
+ if ((dir->i_mode & S_IFMT) != S_IFDIR)
+ return -ENOTDIR;
+
+ ctx->flags &= ~EROFS_READDIR_ALL_SPECIAL_FOUND;
+ pos = 0;
+ while (pos < dir->i_size) {
+ erofs_blk_t lblk = erofs_blknr(pos);
+ erofs_off_t maxsize = min_t(erofs_off_t,
+ dir->i_size - pos, EROFS_BLKSIZ);
+ const struct erofs_dirent *de = (const void *)buf;
+ unsigned int nameoff;
+
+ err = erofs_pread(dir, buf, maxsize, pos);
+ if (err) {
+ erofs_err("I/O error occurred when reading dirents @ nid %llu, lblk %u: %d",
+ dir->nid | 0ULL, lblk, err);
+ return err;
+ }
+
+ nameoff = le16_to_cpu(de->nameoff);
+ if (nameoff < sizeof(struct erofs_dirent) ||
+ nameoff >= PAGE_SIZE) {
+ erofs_err("invalid de[0].nameoff %u @ nid %llu, lblk %u",
+ nameoff, dir->nid | 0ULL, lblk);
+ return -EFSCORRUPTED;
+ }
+ err = traverse_dirents(ctx, buf, lblk, nameoff, maxsize, fsck);
+ if (err)
+ break;
+ pos += maxsize;
+ }
+
+ if (fsck && (ctx->flags & EROFS_READDIR_ALL_SPECIAL_FOUND) !=
+ EROFS_READDIR_ALL_SPECIAL_FOUND) {
+ erofs_err("`.' or `..' dirent is missing @ nid %llu",
+ dir->nid | 0ULL);
+ return -EFSCORRUPTED;
+ }
+ return 0;
+}
--
2.20.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH v3 2/2] erofs-utils: fsck: convert to use erofs_iterate_dir()
2021-12-16 1:24 [PATCH v3 1/2] erofs-utils: lib: add API to iterate dirs in EROFS Gao Xiang
@ 2021-12-16 1:24 ` Gao Xiang
0 siblings, 0 replies; 2+ messages in thread
From: Gao Xiang @ 2021-12-16 1:24 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
From: Gao Xiang <hsiangkao@linux.alibaba.com>
No need to open code after erofs_iterate_dir() is finalized in
liberofs.
However, there are still some TODOs for fsck:
- Avoid too deep recursive traversal, sceptically forming a loop;
- Check link counts at runtime to keep consistency;
- Check if any ftype / i_mode mismatches.
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
fsck/main.c | 178 +++++++---------------------------------------------
1 file changed, 23 insertions(+), 155 deletions(-)
diff --git a/fsck/main.c b/fsck/main.c
index ad48e35f587b..038f43badb8f 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -10,8 +10,9 @@
#include "erofs/print.h"
#include "erofs/io.h"
#include "erofs/decompress.h"
+#include "erofs/dir.h"
-static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid);
+static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid);
struct erofsfsck_cfg {
bool corrupted;
@@ -126,121 +127,6 @@ static int erofs_check_sb_chksum(void)
return 0;
}
-static bool check_special_dentry(struct erofs_dirent *de,
- unsigned int de_namelen, erofs_nid_t nid,
- erofs_nid_t pnid)
-{
- if (de_namelen == 2 && de->nid != pnid) {
- erofs_err("wrong parent dir nid(%llu): pnid(%llu) @ nid(%llu)",
- de->nid | 0ULL, pnid | 0ULL, nid | 0ULL);
- return false;
- }
-
- if (de_namelen == 1 && de->nid != nid) {
- erofs_err("wrong current dir nid(%llu) @ nid(%llu)",
- de->nid | 0ULL, nid | 0ULL);
- return false;
- }
- return true;
-}
-
-static int traverse_dirents(erofs_nid_t pnid, erofs_nid_t nid,
- void *dentry_blk, erofs_blk_t block,
- unsigned int next_nameoff, unsigned int maxsize)
-{
- struct erofs_dirent *de = dentry_blk;
- const struct erofs_dirent *end = dentry_blk + next_nameoff;
- unsigned int idx = 0;
- char *prev_name = NULL, *cur_name = NULL;
- int ret = 0;
-
- erofs_dbg("traversing pnid(%llu), nid(%llu)", pnid | 0ULL, nid | 0ULL);
-
- if (!block && (next_nameoff < 2 * sizeof(struct erofs_dirent))) {
- erofs_err("too small dirents of size(%d) in nid(%llu)",
- next_nameoff, nid | 0ULL);
- return -EFSCORRUPTED;
- }
-
- while (de < end) {
- const char *de_name;
- unsigned int de_namelen;
- unsigned int nameoff;
-
- nameoff = le16_to_cpu(de->nameoff);
- de_name = (char *)dentry_blk + nameoff;
-
- /* the last dirent check */
- if (de + 1 >= end)
- de_namelen = strnlen(de_name, maxsize - nameoff);
- else
- de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
-
- if (prev_name)
- free(prev_name);
- prev_name = cur_name;
- cur_name = strndup(de_name, de_namelen);
- if (!cur_name) {
- ret = -ENOMEM;
- goto out;
- }
-
- erofs_dbg("traversed filename(%s)", cur_name);
-
- /* corrupted entry check */
- if (nameoff != next_nameoff) {
- erofs_err("bogus dirent with nameoff(%u): expected(%d) @ nid %llu, block %u, idx %u",
- nameoff, next_nameoff, nid | 0ULL,
- block, idx);
- ret = -EFSCORRUPTED;
- goto out;
- }
-
- if (nameoff + de_namelen > maxsize ||
- de_namelen > EROFS_NAME_LEN) {
- erofs_err("bogus dirent with namelen(%u) @ nid %llu, block %u, idx %u",
- de_namelen, nid | 0ULL, block, idx);
- ret = -EFSCORRUPTED;
- goto out;
- }
-
- if (prev_name && (strcmp(prev_name, cur_name) >= 0)) {
- erofs_err("wrong dirent name order @ nid %llu block %u idx %u: prev(%s), cur(%s)",
- nid | 0ULL, block, idx,
- prev_name, cur_name);
- ret = -EFSCORRUPTED;
- goto out;
- }
-
- if (is_dot_dotdot(cur_name)) {
- if (!check_special_dentry(de, de_namelen, nid, pnid)) {
- ret = -EFSCORRUPTED;
- goto out;
- }
- } else {
- erofs_check_inode(nid, de->nid);
- }
-
- if (fsckcfg.corrupted) {
- ret = -EFSCORRUPTED;
- goto out;
- }
-
- next_nameoff += de_namelen;
- ++de;
- ++idx;
- }
-
-out:
- if (prev_name)
- free(prev_name);
- if (cur_name)
- free(cur_name);
-
- erofs_dbg("traversing ... done nid(%llu)", nid | 0ULL);
- return ret;
-}
-
static int verify_uncompressed_inode(struct erofs_inode *inode)
{
struct erofs_map_blocks map = {
@@ -479,12 +365,18 @@ static int erofs_verify_inode_data(struct erofs_inode *inode)
return ret;
}
-static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
+static int erofsfsck_chk_dirents(struct erofs_dir_context *ctx)
+{
+ if (ctx->dot_dotdot)
+ return 0;
+
+ return erofsfsck_check_inode(ctx->dir->nid, ctx->de_nid);
+}
+
+static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
{
int ret;
struct erofs_inode inode;
- char buf[EROFS_BLKSIZ];
- erofs_off_t offset;
erofs_dbg("check inode: nid(%llu)", nid | 0ULL);
@@ -507,44 +399,21 @@ static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
if (ret)
goto out;
- if ((inode.i_mode & S_IFMT) != S_IFDIR)
- goto out;
-
- offset = 0;
- while (offset < inode.i_size) {
- erofs_blk_t block = erofs_blknr(offset);
- erofs_off_t maxsize = min_t(erofs_off_t,
- inode.i_size - offset, EROFS_BLKSIZ);
- struct erofs_dirent *de = (void *)buf;
-
- unsigned int nameoff;
-
- ret = erofs_pread(&inode, buf, maxsize, offset);
- if (ret) {
- erofs_err("I/O error occurred when reading dirents @ nid %llu, block %u: %d",
- nid | 0ULL, block, ret);
- goto out;
- }
-
- nameoff = le16_to_cpu(de->nameoff);
- if (nameoff < sizeof(struct erofs_dirent) ||
- nameoff >= PAGE_SIZE) {
- erofs_err("invalid de[0].nameoff %u @ nid %llu block %u: %d",
- nameoff, nid | 0ULL, block, ret);
- ret = -EFSCORRUPTED;
- goto out;
- }
-
- ret = traverse_dirents(pnid, nid, buf, block,
- nameoff, maxsize);
- if (ret)
- goto out;
+ /* XXXX: the dir depth should be restricted in order to avoid loops */
+ if ((inode.i_mode & S_IFMT) == S_IFDIR) {
+ struct erofs_dir_context ctx = {
+ .flags = EROFS_READDIR_VALID_PNID,
+ .pnid = pnid,
+ .dir = &inode,
+ .cb = erofsfsck_chk_dirents,
+ };
- offset += maxsize;
+ ret = erofs_iterate_dir(&ctx, true);
}
out:
if (ret && ret != -EIO)
fsckcfg.corrupted = true;
+ return ret;
}
int main(int argc, char **argv)
@@ -583,12 +452,11 @@ int main(int argc, char **argv)
goto exit_dev_close;
}
- erofs_check_inode(sbi.root_nid, sbi.root_nid);
-
+ err = erofsfsck_check_inode(sbi.root_nid, sbi.root_nid);
if (fsckcfg.corrupted) {
erofs_err("Found some filesystem corruption");
err = -EFSCORRUPTED;
- } else {
+ } else if (!err) {
erofs_info("No error found");
if (fsckcfg.print_comp_ratio) {
double comp_ratio =
--
2.20.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-12-16 1:29 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-16 1:24 [PATCH v3 1/2] erofs-utils: lib: add API to iterate dirs in EROFS Gao Xiang
2021-12-16 1:24 ` [PATCH v3 2/2] erofs-utils: fsck: convert to use erofs_iterate_dir() Gao Xiang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox