On Thu, Feb 26, 2026 at 11:37 AM Gao Xiang <[email protected]> wrote:
>
>
>
> On 2026/2/26 10:18, Inseob Kim wrote:
> > On Thu, Feb 26, 2026 at 10:50 AM Gao Xiang <[email protected]>
> > wrote:
> >>
> >> Hi Inseob,
> >>
> >> On 2026/2/26 08:59, Inseob Kim wrote:
> >>> 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.
> >>
> >> Thanks for the patch!
> >
> > Thank *you* for quick response!
> >
> >>
> >>>
> >>> Signed-off-by: Inseob Kim <[email protected]>
> >>> ---
> >>> fsck/main.c | 50 ++++++++++++++++++++++++++++++++++++++++----------
> >>> 1 file changed, 40 insertions(+), 10 deletions(-)
> >>>
> >>> diff --git a/fsck/main.c b/fsck/main.c
> >>> index ab697be..a7d9f46 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;
> >>> @@ -981,7 +993,8 @@ static int erofsfsck_check_inode(erofs_nid_t pnid,
> >>> erofs_nid_t nid)
> >>>
> >>> if (S_ISDIR(inode.i_mode)) {
> >>> struct erofs_dir_context ctx = {
> >>> - .flags = EROFS_READDIR_VALID_PNID,
> >>> + .flags = (pnid == nid && nid != g_sbi.root_nid) ?
> >>
> >> Does it relax the validatation check?
> >>
> >> and does (nid == pnid && nid == fsckcfg.nid) work?
> >
> > It shouldn't relax the existing validation check.
> > `erofsfsck_check_inode` is called with `err =
> > erofsfsck_check_inode(fsckcfg.nid, fsckcfg.nid);`.
> >
> > * If a given path is not the root, `nid`'s parent `..` will differ
> > from `pnid`, causing failure. This condition only relaxes the starting
> > directory.
>
> I just have a wild thought, if there is a directory which have
>
> foo/
> | - .. -> pointing to `foo` itself
> - a/ -> pointing to `foo` directory too
>
> will (pnid == nid && nid != g_sbi.root_nid) relaxs
> the check for a/ ?
>
> I'm not sure but you could double check.
Thank you for pointing that out. I'll try retrieving the parent before
calling `erofsfsck_check_inode` and then pass it correctly.
>
> > * In the case of the root, `nid`'s parent `..` should indeed be
> > itself. So we can still validate.
> >
> > If you have any better suggestions, I'll follow them.
> >
> >>
> >>> + 0 : EROFS_READDIR_VALID_PNID,
> >>> .pnid = pnid,
> >>> .dir = &inode,
> >>> .cb = erofsfsck_dirent_iter,
> >>> @@ -1033,6 +1046,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 +1083,37 @@ 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;
> >>> }
> >>
> >> It would be better to check if it's a directory.
> >
> > My intention was that we support both directories and files. Or should
> > I create a separate flag like `--cat` in dump.erofs?
>
> Ok, make sense.
>
> Thanks,
> Gao Xiang
--
Inseob Kim | Software Engineer | [email protected]