Skip to content

feat: NTFS full-volume capture, offline parity validation, and tooling#535

Merged
githubrobbi merged 39 commits into
mainfrom
feat/mft-metafile-capture
Jul 7, 2026
Merged

feat: NTFS full-volume capture, offline parity validation, and tooling#535
githubrobbi merged 39 commits into
mainfrom
feat/mft-metafile-capture

Conversation

@githubrobbi

Copy link
Copy Markdown
Collaborator

Builds the NTFS full-volume capture + offline reconstitution/validation system in uffs-mft, plus supporting CLI/tooling and a security dep bump. Validated end-to-end on real Windows captures replayed offline on macOS.

Capture (uffs-mft capture)

  • Full $MFT (compressed) + all 10 NTFS metafiles ($Boot, $Bitmap, $Secure:$SDS, $AttrDef, $MFTMirr, $Volume, $BadClus, $LogFile, $UsnJrnl:$J), hashed manifest.json + SHA256SUMS.
  • --all-drives, --zip/--split-gib (ustar+zstd, no PowerShell 2 GB limit).
  • $UsnJrnl:$J sparse-compact reader; $ATTRIBUTE_LIST following for named $DATA streams; sector-aligned data-run reads; NTFS version from extended volume data.
  • v3 .bin header carries reserved_allocated_bytes, restored on load so an offline parse reproduces the live root size-on-disk.
  • <DRIVE>_mft.bin naming for drop-in compatibility with the existing verify_parity flow.

Offline tooling (cross-platform)

  • metafile-info — decode a captured metafile ($Boot geometry, $Bitmap free space, $UsnJrnl summary).
  • verify — canonical MFT-CSV parity (column-name matched, multiset diff).
  • extract-mft — pull the byte-exact raw $MFT out of a .bin for analyzeMFT / MFT2CSV / ntfstool.
  • sysinfo — capture-host probe.

verify_parity.rs (parity harness)

  • --live --bundle (capture + zip transport), offline auto-expand of drive_<x>.tar.zst, daemon reset before --regenerate, dir size-on-disk skew tolerance, real mtimes in archives.

Fixes

  • uffs --status can no longer hang (bounded ps calls); just use-local stops daemon/MCP first.
  • crossbeam-epoch 0.9.18 → 0.9.20 (RUSTSEC-2026-0204) — delta-audited safe-to-deploy.

Validation

Offline replay on macOS: D/E/G/M/S clean SUPERSET/SORTED MATCH against the C++ golden (root reserved diff fixed by the v3 header); C/F are the inherently-churning drives. Docs: docs/architecture/mft-full-capture.md, docs/user-manual/mft-capture-verify-runbook.md.

🤖 Generated with Claude Code

githubrobbi and others added 30 commits July 5, 2026 10:58
Design for capturing a complete NTFS metafile set (MFT + $Secure/$UsnJrnl/
$Bitmap/$LogFile/$Boot/$UpCase/...) into a verifiable, transferable bundle:
two-phase live+VSS-frozen model (no read-only remount), a `capture`
subcommand as the home, a rust-script VSS/zip wrapper, and the `sysinfo`
host-probe that gates best-effort by OS class (client/server).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `uffs-mft sysinfo`: a cross-platform host + storage provenance probe that
runs before a capture and records the machine it ran on.

- Host: OS name/build/arch, client/server InstallationType (the VSS/shadow
  discriminator), elevation, VSS availability, CPU/RAM, timezone, tool version.
- NTFS drives (Windows): media type, geometry, $MFT stats, and per-drive
  capture-capability flags (iocp_capturable, vss_eligible).
- Volumes (all OS): every mounted filesystem with type / format / size / used%,
  collapsing shared-container volumes (e.g. synthetic APFS mounts).
- Derives the best-effort capture mode (full-server / best-effort-client /
  live-only / unsupported); also useful as a benchmark provenance stamp.

Text report + `--json` (Windows). Windows OS identity via a small read-only
RegGetValueW reader (new Win32_System_Registry feature); other probes reuse
existing safe wrappers. Split into capture_mode/report/windows/unix submodules.
Verified: host + cargo-xwin Windows clippy clean, 8 unit tests, macOS run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First frozen-metafile capture target. Adds a self-describing capture format
(`MetafileHeader`: magic/version/kind/drive/serial/timestamp/size) and a
`uffs-mft metafile --drive C --kind boot -o C_boot.bin` command that reads
$Boot (the 8 KiB volume boot region at offset 0) via the broker-safe
read_handle_at primitive and writes header + payload.

- New `platform::metafile` module (mirrors `platform::upcase`): MetafileKind,
  MetafileHeader (to_bytes/from_bytes), read_metafile (Windows) + non-Windows
  stub, save/load_metafile_to/from_file.
- `metafile` subcommand + MetafileKind CLI value-enum; dispatch on Windows,
  "requires Windows" elsewhere.
- 6 cross-platform header round-trip/validation tests.

Foundation for the remaining targets ($Bitmap, $Secure:$SDS, $AttrDef, ...),
which reuse the same header/format via data-run reads. Verified: host +
cargo-xwin Windows clippy clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…1.2)

Add the keystone data-run stream primitive and the first target that uses it.

- read_frs_record: read a raw MFT record (any FRS) with USA fixup.
- read_data_stream: resolve a metafile's non-resident $DATA attribute (unnamed,
  or a named stream like $SDS) and assemble its data runs.
- read_runs: read data runs into a data_size-truncated buffer; sparse runs stay
  zeroed. Reuses the broker-safe read_handle_at.
- $Bitmap (FRS 6): the volume cluster-allocation bitmap, captured via the
  unnamed non-resident $DATA stream. `metafile --kind bitmap`.

The named-stream support lands $Secure:$SDS next with no new I/O code.
Verified: host + cargo-xwin Windows clippy (pedantic/nursery) clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the NTFS security-descriptor store via the named-stream path added in
P1.2 (no new I/O code): $Secure (FRS 9), named $DATA stream $SDS. This is the
ACL / owner / DACL-SACL store that the $MFT namespace only references by
SecurityId. `metafile --kind secure`.

Verified: host + cargo-xwin Windows clippy (pedantic/nursery) clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (P1.4)

Complete the frozen-metafile target set:
- $AttrDef (FRS 4) and $MFTMirr (FRS 1): unnamed non-resident $DATA streams,
  via the P1.2 stream reader.
- $Volume (FRS 3) and $BadClus (FRS 8): their useful data lives in the MFT
  record itself ($VOLUME_NAME/$VOLUME_INFORMATION; the $Bad run list), so the
  fixed-up record is captured via read_frs_record.

`metafile --kind attr-def|mft-mirr|volume|bad-clus`. With $Boot/$Bitmap/$Secure
and the existing `save --upcase`, the complete metafile set is now capturable.
Verified: host + cargo-xwin Windows clippy (pedantic/nursery) clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `uffs-mft capture --drive C --out <dir>`: capture every NTFS metafile for a
drive into one hashed, manifested bundle under <out>/drive_<x>/.

- Writes each metafile ($Boot/$Bitmap/$Secure/$AttrDef/$MFTMirr/$Volume/
  $BadClus) via the P1.1-P1.4 metafile module, best-effort (a metafile that
  can't be read is skipped and noted, not fatal).
- manifest.json: schema, drive, captured_at, tool version, volume facts
  (serial/ntfs-version/cluster+record size), and per-artifact
  {file, kind, frs, bytes, sha256}.
- SHA256SUMS for transfer verification.

sha2 + hex added to the Windows dep set for the manifest hashing. Verified:
cargo-xwin Windows clippy + host pedantic clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the NTFS metadata transaction log: $LogFile (FRS 2), an unnamed
non-resident $DATA stream, via the P1.2 stream reader (no new I/O code).
Wired into `metafile --kind log-file` and the `capture` bundle.

This is the crash-consistency / replay artifact. The remaining temporal
artifact, $UsnJrnl:$J, needs $Extend directory-index traversal to resolve its
FRS and lands separately.

Verified: host + cargo-xwin Windows clippy (pedantic/nursery) clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(P2)

Capture the NTFS change journal, the one metafile not at a fixed FRS:

- resolve_extend_child: walk the $Extend (FRS 11) directory index to resolve a
  child's FRS by name — parses $INDEX_ROOT entries, and falls back to the
  $INDEX_ALLOCATION INDX blocks (with USA fixup via apply_usa_fixup) when the
  index has spilled.
- read_usn_journal: resolve $UsnJrnl's FRS, then read its named non-resident
  $DATA stream $J (sparse; the active tail) via the P1.2 stream reader.
- MetafileKind::UsnJrnl uses a reserved sentinel kind code (0xF5) since its FRS
  is dynamic; wired into `metafile --kind usn-jrnl` and the `capture` bundle.
- scan_index_entries is a pure parser with a cross-platform unit test
  (synthetic $INDEX_ROOT buffer → resolves a child FRS).

Completes the NTFS metafile capture set: $MFT + $Boot/$Bitmap/$Secure/$AttrDef/
$MFTMirr/$Volume/$BadClus/$LogFile/$UsnJrnl (+ existing $UpCase). Verified:
host pedantic + cargo-xwin Windows clippy clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`uffs-mft capture` now writes the primary artifact — the LZ4-compressed $MFT
(<x>_mft.compressed.bin, via MftReader::save_raw_to_file) — alongside the
metafiles, so the bundle is self-sufficient (MFT + all metafiles + manifest +
SHA256SUMS). Refactored the per-artifact loop into collect_artifacts/capture_mft
to keep cmd_capture simple.

Verified: host pedantic + cargo-xwin Windows clippy clean, tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update the full-capture plan status/phasing to reflect what landed: sysinfo,
all metafile save targets ($Boot..$UsnJrnl via $Extend traversal), and the
capture orchestrator/manifest incl. the compressed $MFT. Remaining: P3 (VSS
--volume-path), P5 (rust-script VSS/zip wrapper), P6 (full offline load).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ecode (P6)

The offline reconstitute/validate side of the capture flow — cross-platform, so
it runs on the transfer target (macOS/Linux) as well as Windows.

- platform::metafile::parse_boot: decode volume geometry (bytes/sector,
  sectors/cluster, cluster + MFT record size, total sectors, MFT LCN, serial)
  from a captured $Boot payload via NtfsBootSector.
- platform::metafile::summarize: human summary of a captured metafile (header +
  kind-specific detail).
- `uffs-mft metafile-info --input <file>`: load a captured metafile and print
  the summary. Dispatched on all platforms.
- Real cross-platform unit test: synthetic 512-byte boot sector → decoded
  geometry (runs on macOS). Verified end-to-end on macOS against a synthetic
  $Boot metafile.

This closes the loop: capture on Windows → transfer → `metafile-info` on the Mac
reproduces the same decode. Verified: host pedantic + cargo-xwin Windows clippy
clean, tests green, macOS e2e run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (P6)

- parse_bitmap: decode cluster-allocation stats (total/used/free clusters) from
  a captured $Bitmap payload by popcounting the allocation bitmap; folded into
  summarize / `metafile-info` for offline free-space validation (vs fsutil).
- Extract the pure offline decoders (BootGeometry/parse_boot, BitmapStats/
  parse_bitmap, summarize) into a new cross-platform `platform::metafile_decode`
  module — the $Bitmap addition pushed metafile.rs over the file-size limit, so
  this is the real fix (metafile.rs 826 → 661 LOC), no exception.

Cross-platform + unit-tested; verified end-to-end on macOS. host pedantic +
cargo-xwin Windows clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parse_usn decodes a captured $UsnJrnl:$J payload — skips the leading sparse
region, walks USN_RECORD_V2/V3 records (8-byte-aligned), and returns a record
count, USN range, and a small sample (usn / reason / filename). Folded into
summarize / `metafile-info` so the offline machine can inspect the change flow
(the temporal dimension) without the live volume.

Cross-platform + unit-tested (synthetic USN_RECORD_V2); verified end-to-end on
macOS. host pedantic + cargo-xwin Windows clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update the capture plan: metafile-info + parse_boot/parse_bitmap/parse_usn
offline decoders (cross-platform, Mac-verified) are in. Remaining: $Secure/
$Volume/$AttrDef parsers, verify_parity wiring, and the Windows-only P3
(VSS --volume-path) / P5 (rust-script VSS+zip wrapper).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`[super::volume::read_handle_at]` (volume is #[cfg(windows)], absent in the
macOS doc build) and `[MetafileHeader]` failed `cargo doc -D warnings` at
pre-push. Both were illustrative — demote to plain code spans.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Raw volume ReadFile requires sector-aligned length, but read_runs clamped the
final read to the attribute's exact data_size — which for $Bitmap on a 64 KB-
cluster volume is not sector-aligned (bitmap size = ceil(clusters/8)), so the
read failed with ERROR_INVALID_PARAMETER (os error 87). Now allocate the whole
cluster-aligned span the runs cover, read each run in full (aligned), and
truncate to data_size afterwards. $LogFile/$AttrDef worked before only because
their sizes happened to be aligned.

Found by the first real Windows e2e run (C: 64 KB clusters). Needs a re-run to
confirm $Bitmap now captures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
$Secure:$SDS and $UsnJrnl:$J live in extension records referenced by
$ATTRIBUTE_LIST when the base MFT record overflows, so the base-only
reader missed them. Add a pure, testable attribute_list_data_frs()
parser and fall back to reading the extension record(s) for the named
non-resident $DATA stream, merging runs in VCN order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… data

FSCTL_GET_NTFS_VOLUME_DATA only returns the NTFS version in the
NTFS_EXTENDED_VOLUME_DATA block that trails NTFS_VOLUME_DATA_BUFFER, so
ntfs_major_version/ntfs_minor_version were hardcoded to 0 and every
capture reported "ntfs:0.0". Query with a combined base+extended buffer
and read MajorVersion/MinorVersion when NTFS filled the extended block
(graceful 0.0 fallback on systems that don't).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AttributeRef::name() was a stub that decoded the UTF-16 name and then
unconditionally returned None (it could not safely return a borrowed
&[u16] from unaligned record bytes). Every named-stream match therefore
failed, so $Secure:$SDS and $UsnJrnl:$J were never captured — the real
root cause behind the earlier $ATTRIBUTE_LIST work, which relied on this
broken primitive. Return an owned Vec<u16> instead and lock it with a
decode test.

Also make read_runs' buffer allocation fallible: a sparse stream like
$UsnJrnl:$J can span a huge logical size, so surface a clean error
rather than aborting on an infallible vec![0; capacity].

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
$UsnJrnl:$J is a sparse file whose logical size can reach ~150 GB while
the live journal is a tiny allocated tail (the purged prefix is a
deallocated hole). The full-span reader hit the "too large to
materialize" guard and skipped it. Add read_runs_sparse_compact, which
reads only the non-sparse runs concatenated — each USN record is
self-describing, so dropping the leading hole loses no data. Share
run-resolution (base record + $ATTRIBUTE_LIST extensions) via
resolve_data_runs and the fallible allocation via alloc_zeroed.

Split the live-volume readers out of metafile.rs into a new
platform/metafile_read.rs (metafile.rs kept the on-disk format + save/
load); the growing reader set pushed metafile.rs to the 800-line gate.
read_metafile is re-exported so callers are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A USN is the record's byte offset in the journal, so it is always
positive and 8-byte aligned. The sparse-compact $J capture can leave
stale/padding bytes after the live tail that pass the RecordLength +
MajorVersion checks, producing a bogus record (observed last_usn
281479271678612, misaligned). Reject records whose USN is non-positive
or not 8-aligned, and bound RecordLength / require MinorVersion==0.
Locked with a misaligned-tail test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture every eligible NTFS volume in one run, each into its own
out/drive_<x>/ subfolder. --drive is now optional (required only for the
single-drive path); per-drive failures are reported and skipped so the
run continues, and the command errors at the end if any drive failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pack each captured drive directory into a single <dir>.tar.zst
(extractable with `tar --zstd -xf`), optionally split into --split-gib
GiB parts (<dir>.tar.zst.NNN) for transfer. No new dependency: add a
small, unit-tested ustar writer + byte splitter (src/archive.rs) and
compress with the existing zstd. Works per-drive, so it composes with
--all-drives (each volume archived independently, bounding memory).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compare two MFT CSV exports (from `load`) — Rust-on-Windows vs
Rust-on-macOS, or Rust vs a C++ golden — to tie down the capture flow.
Rows are projected onto key columns matched by header name (so column
order may differ), canonicalized as a multiset, and diffed; the command
exits non-zero on any divergence so it drops into scripts.

Adds a pure, unit-tested parity module (RFC 4180 field splitter,
name-based column projection, multiset diff) and the cross-platform
`verify --left A.csv --right B.csv [--columns ...]` command.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
End-to-end runbook for the capture flow: capture (single / --all-drives /
--zip --split-gib), transfer + SHA256SUMS verification, offline
metafile-info inspection, and the three-way parity check (CPP golden vs
Rust-on-Windows vs Rust-on-Mac) via load → verify. Plus a CLI cheat-sheet
and the sparse-$UsnJrnl / CSV-quoting caveats.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
capture wrote c_mft.compressed.bin, which verify_parity.rs --regenerate
(and test_runs.ps1) don't recognize — they look for <DRIVE>_mft.bin /
.iocp. Rename the captured MFT to <DRIVE>_mft.bin so new captures drop
straight into the existing offline parity harness alongside old ones.
Still zstd-compressed on disk; load_raw_mft auto-detects the flag and
decompresses, so the .bin name is correct. Runbook updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nsport

After each live per-drive compare, --bundle captures the MFT + metafiles
(uffs-mft capture) into the same drive dir as the cpp/rust outputs, then
zips it (PowerShell Compress-Archive) into drive_<x>.zip. The zip carries
the MFT, all metafiles, the manifest, and both tools' outputs, ready for
offline --regenerate on the Mac. uffs-mft is auto-detected (~/bin or
target/release) or set via --mft-bin. Bundling implies --keep.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PowerShell Compress-Archive silently fails past ~2 GB, so on large
drives (e.g. S:, whose <DRIVE>_mft.bin exceeds 2 GB) the bundle reported
success but wrote no zip. Replace the capture + Compress-Archive two-step
with a single `uffs-mft capture --zip` (ustar + zstd, no size limit),
which packs the whole drive dir into drive_<x>.tar.zst, and verify the
archive actually exists (never trust the exit code alone).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ustar writer hardcoded mtime=0, so extracting a bundle produced
1970-dated files — and the offline parity flow derives its --tz-offset
from the baseline file's mtime, which that broke. push_entry now takes
an mtime; capture reads each file's modified time so extraction restores
it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
githubrobbi and others added 9 commits July 6, 2026 15:27
Offline mode now discovers drive_<x>.tar.zst transport bundles in the
base dir, temp-expands each (tar --zstd -xf, or plain tar -xf which
libarchive auto-detects) into a drive_<x>/ dir, validates it via the
normal --regenerate path, and removes the expansion afterward — so a
dropped-in bundle is validated without keeping an uncompressed copy.
Skips expansion when a drive_<x>/ dir already exists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…drive load)

Offline --regenerate ran `uffs --mft-file <drive>` via autospawn, but a
daemon left resident from an earlier drive/session served its stale
in-memory index instead — so a --drive M run hit a daemon still holding
C: (327ms "scan", no verify_rust_m.txt, then FATAL not-found). --no-cache
only skips the cache file, not the hot daemon. Kill the daemon + purge
caches (cross-platform) before invoking uffs, mirroring the live mode's
cold-start, so only the requested drive's MFT is loaded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
classify_live_skew tolerated a directory's Size and Descendant-count
aggregates as live-read skew but not Size-on-Disk (col 4), which is
equally a subtree aggregate. So when Norton populated the S:\$AV_NLL
quarantine vault between the cold Rust scan and the warm C++ scan, the
vault dir's size/size-on-disk/descendants all moved; Size + Descendants
were tolerated but Size-on-Disk tripped a false "real diff", leaving 2
entries that flipped S: from SUPERSET MATCH to MISMATCH. Tolerate
Size-on-Disk for directories too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Offline --regenerate under-counted the root's size-on-disk by the
reserved-cluster bytes (total_reserved × cluster_size) because the
sequential .bin MFT format doesn't persist reserved_allocated_bytes
(only the IOCP format does), so it loads as 0. On drive M this was the
single 52 MB (13,327-cluster) root diff. Capture now writes the value
from volume data into reserved_allocated.txt, which verify_parity.rs
--regenerate already consumes via --reserved-allocated so the root
matches the live/C++ baseline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--status shelled out to `ps` twice (process list + parent-name lookup)
via Command::output() with no timeout, so a process with a huge argument
vector (or one stuck in uninterruptible I/O) made `ps` block and hung the
whole command. Route both through a shared capture_with_timeout helper
(2s watchdog on a helper thread; kills the child and reports "process
scan timed out — skipped" on timeout). Require the real `--mcp` flag when
matching sessions so build tooling (cargo/sccache compiling uffs-mcp) is
not listed. Split the MCP-stdio scan into a process_scan submodule to
stay under the file-size gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`just use-local` rebuilt the workspace and installed to ~/bin but left a
running daemon/MCP holding the old binaries — a stale in-memory index
could shadow the fresh build. Add a step 0 that runs `uffs --daemon kill`
+ `pkill -x uffsd uffsmcp` before building.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The offline root Size-on-Disk was short by the reserved-cluster bytes
(total_reserved × cluster_size) because the sequential .bin format never
carried the value (only IOCP did) and the --reserved-allocated flag is a
no-op stub. Bump RawMftHeader to v3 with a reserved_allocated_bytes
field, thread it through SaveRawOptions + the streaming writer, populate
it in capture from volume data, and restore it on load — including
load_raw_to_index_direct, the loader the daemon actually uses for
--mft-file. Validated on the Mac: G: offline flips MISMATCH → SUPERSET
MATCH (root only-in-baseline 1 → 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`extract-mft --input C_mft.bin --output C.mft` decompresses a captured
UFFS-MFT .bin and writes the byte-exact $MFT records — the format
analyzeMFT / MFT2CSV / ntfstool consume. Cross-platform, so a .bin moved
to a Mac yields a tool-ready $MFT with no re-capture. Validated: G_mft.bin
→ 20224 records × 1024 B, every record carrying the FILE magic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New advisory RUSTSEC-2026-0204: invalid-pointer dereference in
crossbeam-epoch's fmt::Pointer impl for Atomic/Shared (transitive via
crossbeam-deque). Bump to the patched 0.9.20. Delta audited safe-to-deploy:
a soundness fix that removes the unsafe deref (prints the raw address
instead), a benign sanitizer-cfg build.rs, no new runtime deps or ambient
capabilities, publisher taiki-e (crossbeam maintainer).

Vet-Reviewed-Diff: crossbeam-epoch@0.9.18->0.9.20
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@githubrobbi githubrobbi enabled auto-merge July 7, 2026 14:51
@githubrobbi githubrobbi added this pull request to the merge queue Jul 7, 2026
Merged via the queue into main with commit 4c5acaf Jul 7, 2026
22 checks passed
@githubrobbi githubrobbi deleted the feat/mft-metafile-capture branch July 7, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant