[PATCH] erofs-utils: fsck: support extracting subtrees
Gao Xiang
hsiangkao at linux.alibaba.com
Thu Feb 26 13:37:41 AEDT 2026
On 2026/2/26 10:18, Inseob Kim wrote:
> On Thu, Feb 26, 2026 at 10:50 AM Gao Xiang <hsiangkao at linux.alibaba.com> 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 <inseob at google.com>
>>> ---
>>> 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
More information about the Linux-erofs
mailing list