fat-core 0.1.4

Pure-Rust, panic-free forensic reader for FAT12, FAT16, FAT32 and exFAT: one reader auto-detects the variant, walks directory trees and cluster chains, reassembles VFAT long names and exFAT name entry sets, and exposes deleted directory entries.
Documentation

fat-forensic

Crates.io: fat-core Crates.io: fat-forensic Docs.rs Rust 1.85+ License: Apache-2.0 Sponsor

CI Docs unsafe forbidden Fuzzed

Audit a FAT12/FAT16/FAT32/exFAT volume for tampering, and read every file — one pure-Rust reader, no C-FFI.

// Surface structural anomalies a happy-path reader silently trusts:
// invalid BPBs, FAT1/FAT2 disagreements, exFAT boot-checksum mismatches,
// bad/cross-linked/orphaned chains, deleted directory entries.
for anomaly in fat_forensic::audit_path("evidence.img".as_ref())? {
    println!("[{:?}] {}: {}", anomaly.severity(), anomaly.code(), anomaly.note());
}
// [High] FAT-MIRROR-MISMATCH: FAT1 and FAT2 disagree at entry 42
//   (0x0003 vs 0x0000) — consistent with post-hoc edit of one copy

Each anomaly is an observation ("consistent with"), never a verdict, and converts to a forensicnomicon Finding.

Read any FAT variant with one reader

fat-core (imported as fat) auto-detects FAT12, FAT16, FAT32 or exFAT from the boot sector — the caller does not choose:

use fat::FatFs;
let fs = FatFs::open(std::fs::File::open("evidence.img")?)?;
println!("variant: {:?}", fs.variant());          // Fat12 | Fat16 | Fat32 | ExFat

let root = fs.root();
let hello = fs.lookup(root, b"HELLO.TXT")?.expect("present");
let meta = fs.meta(hello)?;                        // size, times, attributes
let mut buf = vec![0u8; meta.size as usize];
fs.read_at(hello, 0, &mut buf)?;                   // cluster chain (or exFAT contiguous)

VFAT long names and exFAT File-Name entry sets are reassembled; deleted directory entries (first byte 0xE5) are exposed for recovery.

Mount it into the forensic-vfs unified filesystem layer with the vfs feature:

fat-core = { version = "0.1", features = ["vfs"] }

Install

[dependencies]
fat-core = "0.1"        # the reader (import: `fat`)
fat-forensic = "0.1"    # the auditor

Safety

#![forbid(unsafe_code)], panic-free on untrusted input (bounds-checked reads, range-checked cluster/offset/count fields, allocation caps), and cargo-fuzz targets per parsed structure assert the parser and audit pipeline never panic. Correctness is established against The Sleuth Kit on self-minted FAT12/16/32/exFAT images — see the validation notes.


Privacy Policy · Terms of Service · © 2026 Security Ronin Ltd