feat(vfs): surface NTFS reparse-point and ntfs-3g symlinks - #10
Open
frankmanzhu wants to merge 3 commits into
Open
feat(vfs): surface NTFS reparse-point and ntfs-3g symlinks#10frankmanzhu wants to merge 3 commits into
frankmanzhu wants to merge 3 commits into
Conversation
The vfs adapter now classifies symlinks as NodeKind::Symlink and implements FileSystem::read_link for both on-disk forms: - Windows: $REPARSE_POINT attribute (0xC0), tags 0xA000000C (symlink) and 0xA0000003 (mount point/junction) — the substitute name is decoded from the SymbolicLinkReparseBuffer/MountPointReparseBuffer layout. - Linux (ntfs-3g): a resident unnamed $DATA starting with the 'IntxLNK' magic (7 bytes + version) carries the UTF-16LE target — the format ntfs-3g 2022.10.3 writes when creating symlinks on a mounted volume. A read/parse miss degrades to a regular-file classification rather than failing a directory listing. Verified against an ntfs-3g-authored image: the symlink resolves to '../README.txt', matching ntfs-3g's own mount.
- Committed tiny.zip (8 MiB NTFS volume with an ntfs-3g-authored IntxLNK symlink; provenance in tests/data/README.md). - vfs_ntfs.rs integration test walks the volume: Symlink classification and read_link == '../README.txt' (ntfs-3g's own resolution), regular files stay File with an empty target. - vfs.rs unit tests build crafted MFT records + attributes to cover the Windows $REPARSE_POINT branch (symlink + mount-point tags, substitute name decode), the IntxLNK branch, plain-file/unknown-tag negatives, and bounds-safety of both decoders. - llvm-cov --workspace --all-features: 98.68% lines; vfs.rs 96.16% (was 94.18% pre-patch).
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.
feat(vfs): surface NTFS reparse-point and ntfs-3g symlinks
What this does
The
vfsadapter now classifies NTFS symlinks asNodeKind::Symlinkand implementsFileSystem::read_linkfor both on-disk forms:$REPARSE_POINTattribute (0xC0): tags0xA000000C(symbolic link) and0xA0000003(mount point/junction), substitute name decoded from theSymbolicLinkReparseBuffer/MountPointReparseBufferlayout.$DATAstarting with theIntxLNKmagic (7 bytes + version byte) carries the UTF-16LE target. This is what ntfs-3g actually writes when creating symlinks on a mounted volume: no$REPARSE_POINTattribute exists at all (verified empirically — the record contains only$STANDARD_INFORMATION/$FILE_NAME/$SECURITY_DESCRIPTOR/$DATA).Why it currently fails
read_linkwas unimplemented and reparse/IntxLNKnodes were surfaced asNodeKind::Filewith the raw target record as file content. A consumer extracting an NTFS volume with symlinks silently writes the reparse data (or theIntxLNKrecord) as a regular file — wrong data with no error. Verified against a real ntfs-3g-authored symlink: the image's own author (ntfs-3g mount) resolves it to../README.txt, 7-Zip lists it as a symlink, while the unpatched adapter read the 34-byte record as a file.Why it needs fixing
Same contract gap as the other adapters:
forensic-vfs::FileSystempromisesNodeKind::Symlink+read_link. NTFS volumes routinely contain symlinks/junctions (Windows junctions,%LOCALAPPDATA%links, ntfs-3g-created links), and the silent-junk failure mode is the worst kind for a forensic/extraction consumer.Implementation notes
Noneon malformed input — never a fabricated target).is_symlink_recordis conservative by design).IntxLNKversion byte is intentionally not validated (matching ntfs-3g and 7-Zip, which accept any version); documented.build_metaclassifies directories first, so reparse checks never misfire on directories.Test coverage
tests/data/tiny.zip(provenance intests/data/README.md): an 8 MiB NTFS volume with an ntfs-3g-authoredIntxLNKsymlink; thevfs_ntfs.rsintegration test assertsNodeKind::Symlink+read_link == b"../README.txt"— ntfs-3g's own resolution as ground truth — and that regular files read an empty target.$REPARSE_POINTform end-to-end at the classifier level (symlink + mount-point tags, substitute-name decode, unrelated-tag and truncation negatives) — Windows symlinks cannot be produced on macOS, so this form is unit-tested rather than integration-tested; the layout follows the documentedREPARSE_DATA_BUFFERstructure.cargo llvm-cov --workspace --all-features: 98.68% workspace-wide; vfs.rs 96.16% (up from a 94.18% pre-patch baseline).Code quality
cargo clippy --workspace --all-targets --all-features: clean.cargo test --workspace --all-features: all green.unsafe; nounwrap/expectin production code; failures map to typedVfsErrorwith context.Known limitations (documented, not addressed here)