Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.E?? filter=lfs diff=lfs merge=lfs -text
*.e?? filter=lfs diff=lfs merge=lfs -text
*.aff filter=lfs diff=lfs merge=lfs -text
*.AFF filter=lfs diff=lfs merge=lfs -text
*.dd filter=lfs diff=lfs merge=lfs -text
*.DD filter=lfs diff=lfs merge=lfs -text
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ jobs:
- windows-latest
env:
CARGO_TERM_COLOR: always
NTFS_TESTDATA_REQUIRED: 1
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
lfs: true

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
Expand Down
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,15 @@
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
*.rmeta
*.rmeta

# Vendored third-party code lives in `external/`.
# Keep heavyweight deps ignored, but track `external/refs/` (specs/docs we cite from code).
external/*
# !external/refs/
!external/refs/**/*.md
!external/refs/**/*.pdf
# Temporary scratch space for downloaded artifacts / experiments.
external/refs/tmp/
.DS_Store
.cursor/debug.log
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
repos:
- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt --all --check
entry: cargo fmt --all --check
language: system
pass_filenames: false
files: '\.rs$'
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The crate root lives in `src/lib.rs` with supporting modules in `src/attribute`,

## Build, Test, and Development Commands
Run `cargo build --all-targets` for a full local compile, and `cargo test --all-features` before pushing to mirror CI. Use `cargo bench --bench benchmark` when touching performance-critical code paths. `cargo fmt` and `cargo clippy --all-targets --all-features` should produce a clean workspace; address new lints or explain why they cannot be resolved.
To catch formatting issues before CI, install the repo's pre-commit hook (`pre-commit install`) after installing `pre-commit`.

## Coding Style & Naming Conventions
Follow Rust 2024 idioms and let `rustfmt` enforce four-space indentation and line wrapping. Favour descriptive snake_case for modules, functions, and test names, and PascalCase for types and enums. Prefer early returns with `?`, explicit error types via `thiserror`, and structured logging through the `log` macros. Keep public API additions documented with concise doc comments.
Expand Down
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ authors = ["Omer Ben-Amram <omerbenamram@gmail.com>"]
edition = "2024"
rust-version = "1.90"

[workspace]
members = [
".",
"crates/forensic-image",
"crates/aff",
"crates/ntfs",
"crates/ntfs-explorer-gui",
]

[dependencies]
log = { version = "0.4", features = ["release_max_level_debug"] }
encoding = "0.2"
Expand Down
39 changes: 39 additions & 0 deletions crates/aff/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[package]
name = "aff"
version = "0.1.0"
edition = "2024"
rust-version = "1.90"
license = "MIT/Apache-2.0"
description = "AFF (Advanced Forensic Format) reader with optional crypto/signature verification"
repository = "https://github.com/omerbenamram/mft"
readme = "README.md"

[dependencies]
forensic-image = { path = "../forensic-image" }
thiserror = "2"
log = { version = "0.4", features = ["release_max_level_debug"] }
lru = "0.16.1"
flate2 = { version = "1", default-features = false, features = ["rust_backend"] }

# Optional: decrypt `/aes256` segments + verify `/sha256` signatures (AFFLIB semantics).
openssl = { version = "0.10", features = ["vendored"], optional = true }

# Optional: LZMA page decompression (AFFLIB uses LZMA-Alone framing).
lzma-rs = { version = "0.3", optional = true }

# CLI tools
clap = { version = "4", features = ["derive"] }
anyhow = "1"

[dev-dependencies]
tempfile = "3.23"
assert_cmd = "2.1.1"
predicates = "3.1"

[features]
default = ["crypto", "lzma"]

crypto = ["dep:openssl"]
lzma = ["dep:lzma-rs"]


35 changes: 35 additions & 0 deletions crates/aff/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# `aff` — Advanced Forensic Format (AFF) reader

This crate provides **read-only** access to AFF containers with behavior closely aligned to
**AFFLIBv3**.

## Supported containers

- **AFF1** single-file (`.aff`)
- **AFM** (`.afm`) metadata + split-raw payload (`.000`, `.001`, …)
- **AFD** directory container (`file_000.aff`, `file_001.aff`, …)

## Quick start

```rust
use aff::AffOpenOptions;
use forensic_image::ReadAt;

let img = AffOpenOptions::new().open("image.aff")?;
let mut buf = [0u8; 512];
img.read_exact_at(0, &mut buf)?;
# Ok::<(), aff::Error>(())
```

## Features

- **`crypto`** (default): decrypt `/aes256` segments (read-side) + verify `/sha256` signatures (read-side)
- **`lzma`** (default): LZMA page decompression (`AF_PAGE_COMP_ALG_LZMA`)

## Reference materials

This repo vendors reference materials under `external/refs/` (AFFLIBv3 snapshot + public specs).
These are used for **correctness** and **parity testing**; the `aff` crate itself does not link to
AFFLIB.


Loading