[PATCH v2] erofs-utils: fsck: support extracting subtrees
Inseob Kim
inseob at google.com
Thu Feb 26 15:00:24 AEDT 2026
Add --nid and --path options to fsck.erofs to allow users to check
or extract specific sub-directories or files instead of the entire
filesystem.
This is useful for targeted data recovery or verifying specific
image components without the overhead of a full traversal.
Signed-off-by: Inseob Kim <inseob at google.com>
---
v2: retrieve pnid correctly rather than pnid == nid hack
---
fsck/main.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 73 insertions(+), 9 deletions(-)
diff --git a/fsck/main.c b/fsck/main.c
index ab697be..16cc627 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -39,6 +39,8 @@ struct erofsfsck_cfg {
bool preserve_owner;
bool preserve_perms;
bool dump_xattrs;
+ erofs_nid_t nid;
+ const char *inode_path;
bool nosbcrc;
};
static struct erofsfsck_cfg fsckcfg;
@@ -59,6 +61,8 @@ static struct option long_options[] = {
{"offset", required_argument, 0, 12},
{"xattrs", no_argument, 0, 13},
{"no-xattrs", no_argument, 0, 14},
+ {"nid", required_argument, 0, 15},
+ {"path", required_argument, 0, 16},
{"no-sbcrc", no_argument, 0, 512},
{0, 0, 0, 0},
};
@@ -110,6 +114,8 @@ static void usage(int argc, char **argv)
" --extract[=X] check if all files are well encoded, optionally\n"
" extract to X\n"
" --offset=# skip # bytes at the beginning of IMAGE\n"
+ " --nid=# check or extract from the target inode of nid #\n"
+ " --path=X check or extract from the target inode of path X\n"
" --no-sbcrc bypass the superblock checksum verification\n"
" --[no-]xattrs whether to dump extended attributes (default off)\n"
"\n"
@@ -245,6 +251,12 @@ static int erofsfsck_parse_options_cfg(int argc, char **argv)
case 14:
fsckcfg.dump_xattrs = false;
break;
+ case 15:
+ fsckcfg.nid = (erofs_nid_t)atoll(optarg);
+ break;
+ case 16:
+ fsckcfg.inode_path = optarg;
+ break;
case 512:
fsckcfg.nosbcrc = true;
break;
@@ -862,6 +874,22 @@ again:
return ret;
}
+struct erofsfsck_get_parent_ctx {
+ struct erofs_dir_context ctx;
+ erofs_nid_t pnid;
+};
+
+static int erofsfsck_get_parent_cb(struct erofs_dir_context *ctx)
+{
+ struct erofsfsck_get_parent_ctx *pctx = (void *)ctx;
+
+ if (ctx->dot_dotdot && ctx->de_namelen == 2) {
+ pctx->pnid = ctx->de_nid;
+ return 1;
+ }
+ return 0;
+}
+
static int erofsfsck_dirent_iter(struct erofs_dir_context *ctx)
{
int ret;
@@ -1033,6 +1061,8 @@ int main(int argc, char *argv[])
fsckcfg.preserve_owner = fsckcfg.superuser;
fsckcfg.preserve_perms = fsckcfg.superuser;
fsckcfg.dump_xattrs = false;
+ fsckcfg.nid = 0;
+ fsckcfg.inode_path = NULL;
err = erofsfsck_parse_options_cfg(argc, argv);
if (err) {
@@ -1068,22 +1098,56 @@ int main(int argc, char *argv[])
if (fsckcfg.extract_path)
erofsfsck_hardlink_init();
- if (erofs_sb_has_fragments(&g_sbi) && g_sbi.packed_nid > 0) {
- err = erofs_packedfile_init(&g_sbi, false);
+ if (fsckcfg.inode_path) {
+ struct erofs_inode inode = { .sbi = &g_sbi };
+
+ err = erofs_ilookup(fsckcfg.inode_path, &inode);
if (err) {
- erofs_err("failed to initialize packedfile: %s",
- erofs_strerror(err));
+ erofs_err("failed to lookup %s", fsckcfg.inode_path);
goto exit_hardlink;
}
+ fsckcfg.nid = inode.nid;
+ } else if (!fsckcfg.nid) {
+ fsckcfg.nid = g_sbi.root_nid;
+ }
- err = erofsfsck_check_inode(g_sbi.packed_nid, g_sbi.packed_nid);
- if (err) {
- erofs_err("failed to verify packed file");
- goto exit_packedinode;
+ if (!fsckcfg.inode_path && fsckcfg.nid == g_sbi.root_nid) {
+ if (erofs_sb_has_fragments(&g_sbi) && g_sbi.packed_nid > 0) {
+ err = erofs_packedfile_init(&g_sbi, false);
+ if (err) {
+ erofs_err("failed to initialize packedfile: %s",
+ erofs_strerror(err));
+ goto exit_hardlink;
+ }
+
+ err = erofsfsck_check_inode(g_sbi.packed_nid, g_sbi.packed_nid);
+ if (err) {
+ erofs_err("failed to verify packed file");
+ goto exit_packedinode;
+ }
+ }
+ }
+
+ {
+ erofs_nid_t pnid = fsckcfg.nid;
+
+ if (fsckcfg.nid != g_sbi.root_nid) {
+ struct erofs_inode inode = { .sbi = &g_sbi, .nid = fsckcfg.nid };
+
+ if (!erofs_read_inode_from_disk(&inode) &&
+ S_ISDIR(inode.i_mode)) {
+ struct erofsfsck_get_parent_ctx ctx = {
+ .ctx.dir = &inode,
+ .ctx.cb = erofsfsck_get_parent_cb,
+ };
+
+ if (erofs_iterate_dir(&ctx.ctx, false) == 1)
+ pnid = ctx.pnid;
+ }
}
+ err = erofsfsck_check_inode(pnid, fsckcfg.nid);
}
- err = erofsfsck_check_inode(g_sbi.root_nid, g_sbi.root_nid);
if (fsckcfg.corrupted) {
if (!fsckcfg.extract_path)
erofs_err("Found some filesystem corruption");
--
2.53.0.414.gf7e9f6c205-goog
More information about the Linux-erofs
mailing list