Skip to content

feat: AD1 (AccessData logical image) lazy mount + doc lifecycle#3

Merged
h4x0r merged 8 commits into
mainfrom
feat/ad1-mount
Jul 1, 2026
Merged

feat: AD1 (AccessData logical image) lazy mount + doc lifecycle#3
h4x0r merged 8 commits into
mainfrom
feat/ad1-mount

Conversation

@h4x0r

@h4x0r h4x0r commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Mount AccessData AD1 logical images (4n6mount evidence.ad1 /mnt) lazily via the pure-Rust ad1-core crate — no full extraction of a potentially multi-GiB image. Implemented with strict TDD.

AD1 support

  • Detection (RED→GREEN): ADSEGMENTEDFILE / ADCRYPT magic → FsType::Ad1.
  • Backend fs_ad1 (RED→GREEN): Ad1ForensicFs builds the ForensicFs tree directly from the path (AD1 is a logical tree opened by path, so it bypasses build_filesystem), reading bytes lazily via ad1::read_at (inflates only overlapping zlib chunks). Encrypted (ADCRYPT) images are refused loudly.
  • Validation: 4 unit tests against ad1-core's testfix independent oracle (spec-faithful writer, flate2 + RustCrypto) — byte-identical reads incl. a mid-file range across a zlib-chunk boundary. Plus a committed 1150-byte fixture added to the mount-smoke matrix (14th format, FUSE + Dokan).
  • ad1 is a default feature.

Doc lifecycle (per CLAUDE.md standard)

  • Reverse-wrote ADR 0001 (docs/decisions/) capturing the why; retired the implemented HANDOFF-ad1.md.
  • .gitignore: added .claude/ + cargo-fuzz output (fuzz/target/, fuzz/corpus/, fuzz/artifacts/); untracked 3706 fuzz build-output/corpus files committed by mistake (files kept on disk; history retains them).

Test

Local: 202 lib + 10 integration tests green; clippy -D warnings + fmt clean; cargo deny green with ad1-core in the graph.

🤖 Generated with Claude Code

h4x0r and others added 8 commits July 1, 2026 13:16
Add the FsType::Ad1 variant + Display + FromStr so the tests compile, and
two failing detection tests asserting the AccessData AD1 magic bytes map
to FsType::Ad1. The magic check itself follows in GREEN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the magic-byte checks to detect_filesystem so AccessData AD1 images
(and their ADCRYPT encrypted variant) resolve to FsType::Ad1. Both
detection tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the ad1 feature (default) + ad1-core dep, and dev-deps (ad1-core
testfix + tempfile). New fs_ad1 module with the Ad1ForensicFs skeleton
(stubbed) and four tests driven by ad1-core's testfix fixture builder:
list the tree, read every file byte-identical to testfix's independently
hashed ground truth, a mid-file range read across a zlib-chunk boundary,
and fs_info. All four fail (unimplemented); implementation follows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ad1ForensicFs::open enumerates the AD1 logical tree into an ArchiveTree
(file entries carry their reader index as payload); reads go through
read_range, which resolves the entry and loops ad1::read_at (handling
short reads) to inflate only the overlapping zlib chunks — no full
extraction. ForensicFs methods delegate to the tree; encrypted (ADCRYPT)
images surface as NotSupported via map_err. All four testfix-oracle tests
pass; clippy -D warnings and fmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the FsType::Ad1 arm to the mount dispatch. Unlike seekable-stream
formats, AD1 opens by path (to find sibling segments) and exposes a
logical tree, so it constructs Ad1ForensicFs directly rather than
funnelling through build_filesystem. It inherits the DiskOverlay layout
(ro/ rw/ deleted/) like the archive backends. ADCRYPT images fail open
with a clear message and are refused. Binary builds; clippy/fmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Commit a 1150-byte AD1 fixture (built by ad1-core's spec-faithful testfix
writer, verified to read back through Ad1ForensicFs), copied by
gen-fixtures.sh and asserted by the `ad1` manifest row (root/hello.txt =
"hello from ad1"). Provenance + md5 documented in tests/data/README.md.
This mounts AD1 end-to-end through FUSE (Linux) and Dokan (Windows)
alongside the other 13 formats.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reverse-write ADR 0001 capturing why AD1 mounts as a logical tree built
directly from the path (bypassing build_filesystem), reads lazily via
ad1-core, refuses ADCRYPT, and uses the DiskOverlay layout. The planning
handoff (HANDOFF-ad1.md) is retired now that the work is built and its
rationale lives here — per the plan/doc lifecycle standard, the working
tree holds the conclusion, git history holds the archaeology.

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

Apply the .gitignore standard: cover local agent state (.claude/) and
cargo-fuzz's regenerated output (fuzz/target/, fuzz/corpus/,
fuzz/artifacts/) plus a couple more editor cruft globs. Untrack the 3706
fuzz/target + fuzz/corpus files that had been committed by mistake — the
files stay on disk and git history retains them, so nothing is lost; the
working tree just stops carrying regenerated build output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedad1-core@​0.1.09910093100100

View full report

@h4x0r h4x0r merged commit 3787db0 into main Jul 1, 2026
12 checks passed
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