Repository navigation
nilfs2: extract 3.x volumes (closes #64) - #67
Merged
Merged
Conversation
moria identified NILFS2 (issue #24) but had no extractor, so -e wrote nothing. Add src/extract/nilfs2.{cpp,hpp} and register it in extractor_for(). NILFS2 is log-structured: the live tree is reached through the latest checkpoint, not a fixed inode table. The extractor: - picks the valid superblock (primary at 1024, secondary near EOF) with the greater write time, since NILFS2 updates them lazily and the primary can lag the newest log; - follows its last partial segment to the super root (the last block of that segment), which embeds the DAT, cpfile and sufile inodes; - reads the DAT (disk address translation), a palloc file whose own block map uses physical pointers, to translate the virtual block numbers that every other inode's pointers carry; - reads the cpfile checkpoint for the last checkpoint number to get the ifile inode, reads the root inode from the ifile (also a palloc file), and walks the directory tree, rebuilding regular files, directories and symlinks. Block maps are NILFS2 bmaps: an inline "direct" map (up to 6 pointers) or a B-tree whose non-root nodes carry an 8-byte pad between header and keys. All reads go through the bounds-checked Reader, so a truncated or corrupt image yields a partial result rather than a crash, and a declared file size larger than the image is clamped to bound the allocation. Tests (tests/test_nilfs2_extract.py): a real empty mkfs.nilfs2 image is identified and extracted cleanly (always-on, no privilege), exercising the whole metadata chain against genuine bytes; a populated round-trip builds a known tree, mounts and copies it in, extracts and compares byte-for-byte (self-skips without the kernel module and mount privilege, since mkfs.nilfs2 has no populate mode); and mangled superblock/metadata inputs must not crash. Adds fuzz/fuzz_nilfs2.cpp over the parse-only read chain.
nmatt0
force-pushed
the
feat/nilfs2-extract
branch
from
October 17, 2026 21:57
e88342d to
c16a86c
Compare
# Conflicts: # CMakeLists.txt # tests/run.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds read-only extraction for NILFS2. Identification landed with the legacy-block-filesystem batch (#24); until now
-eon a NILFS2 image printed the summary table and wrote nothing, becauseextractor_for()had nonilfs2case. Closes #64.What it does
NILFS2 is log-structured, so the live filesystem is reached through the latest checkpoint rather than a fixed inode table.
src/extract/nilfs2.{cpp,hpp}, registered inextractor_for():s_wtime. NILFS2 writes the superblocks lazily, so the primary can lag the newest committed log; selecting the newer one is what makes a cleanly-unmounted image read back its latest state.Block maps are NILFS2 bmaps: an inline "direct" map (header + up to 6 pointers for file blocks 0..5) or a B-tree. A detail that matters on real images: B-tree non-root nodes carry an 8-byte pad between the node header and the keys (root nodes do not), and only the DAT inode's pointers are physical; all others are virtual and resolved through the DAT.
Safety
Reader; a truncated or corrupt image yields apartial/error:status, never an out-of-bounds access.Tests
tests/test_nilfs2_extract.py(wired intorun.shand ctest):mkfs.nilfs2builds an empty filesystem and moria must identify and extract it cleanly. This drives the entire metadata chain (superblock selection, super root, DAT translation, cpfile lookup, ifile read, root-directory walk) against genuine on-disk bytes. Self-skips ifnilfs-utilsis absent.mkfs.nilfs2has no populate-from-directory mode and the kernel driver is required to write, so this layer needs the nilfs2 module and mount privilege.fuzz/fuzz_nilfs2.cppfuzzes the parse-only read chain (superblock selection through directory walk and block maps), plus the scan pipeline on the raw bytes.Docs
NILFS2 added to the extractable-filesystem lists in
README.mdandmoria.1.