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.

* 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

Reply via email to