You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pure-managed filesystem handling for .NET, without mounting anything through the host OS. The
package claims the WHOLE domain — every filesystem and disk-image container, modern, legacy,
virtual-machine, optical, forensic and retro-computing alike — not a selection of it. Where a
format is read-only, create-only or a deliberate subset, that is a tracked gap recorded in the
support matrix below, which is generated from the descriptors and checked by
the test suite.
The package bundles every FileSystem.* assembly and the disk-image FileFormat.* assemblies, with Hawkynt.Compression.Core as its one NuGet dependency.
✨ Features
Inspect filesystems in-process without libguestfs, loop mounts, kernel drivers or elevated privileges — NTFS from Linux, ext4 from Windows, HFS+ from either.
Create fresh images for every format marked WORM or R/W below, with real nested directory trees where the format has them.
Edit existing images for every format marked R/W: add, replace, remove, purge. Some formats edit blocks in place, some lay the volume out again; the matrix says which.
Defragment, wipe unused space, shrink and re-lay volumes at a chosen geometry on the formats whose descriptors offer it.
Open disk-image containers (VHD, VHDX, VMDK, VDI, QCOW2, DMG, EWF, optical and tape images, firmware volumes) and reach the filesystem inside.
Every writer is held against the format's own tools where one exists: a real kernel under QEMU, its fsck, or its canonical third-party utility.
🧩 Support matrix
State
Meaning
N/A
Registered filesystem domain that is not represented by a standalone image/container descriptor; specialized multi-source drivers may expose mounted capabilities separately.
R
Open, list and extract only. For network, distributed and encrypted formats this may be signature/metadata detection; deliberately unverified descriptors can instead require explicit format selection and expose an opaque object.
WORM
Read plus create a fresh image; no supported edit of an existing image.
R/W
Read plus add / replace / remove / purge on an existing image. The edit may update blocks in place or lay the volume out again — the Notes column says when it is the latter.
The six verb columns are the maintenance operations the CLI and the UI gate on, defined once in docs/ARCHIVE-MODEL.md:
Defrag lays a volume out again, and says how: moving relocates only the runs that are out of place through a block mover of the format's own, rebuild writes the volume out afresh.
Wipe zeroes what no file holds — free space, cluster-tip slack, deleted directory entries — without touching a live byte.
Shrink reduces a volume to what it needs, keeping its geometry. It is absent wherever the geometry is fixed: for most read-only filesystems and for optical images there is no smaller canonical size to step to, so nothing could be reclaimed.
Layout re-lays a volume at a chosen cluster or block geometry. This needs a creator to write the new volume with, so a format that can only analyse its geometry is marked absent here however thoroughly it reads it.
Purge erases every live entry and leaves a valid empty image.
Compact is the composite the UI offers as one click: defrag, then layout, then shrink, so it is available wherever any of those three is.
Proof is how the format is held against something outside this repository, and every tool it names links to that tool's own source, so the thing doing the checking can be reached from here. "own reader + struct-parity tests" means nothing outside this repository currently checks the format — either no such tool exists, or none is wired into the suite — so the on-disk structures are checked field by field instead. That cell is the honest gap, and it is deliberately preferred over naming a tool nobody runs: a cell that cites a checker which never executes stops anyone from going looking for one.
The Id, State and verb columns are read off the descriptors by FilesystemReadmeIsCurrentTests, and cross-checked against the registry's own filesystem list by CapabilityDocumentationTests; a row that disagrees with the code fails the build. FilesystemVerbsAreBackedTests then runs each ticked verb, so a cell cannot be earned by declaring an interface that refuses when called.
Intel HEX and Motorola S-record, normalised to firmware.bin + metadata; the writer takes one payload and the base and start addresses from metadata.ini
Writes NTFS 1.2, 3.0 or 3.1 as the NtfsVersion create option selects, and reads all three: the version drives the FILE record header layout (3.1 names the record at 44 with the USA at 48; 3.0 and 1.2 have no record number and put the USA at 42), the metadata set ($Secure+$Extend from 3.0, $Quota and no $Extend before it), the $AttrDef table and the $STANDARD_INFORMATION size (72 from 3.0, 48 on 1.2). No security descriptors are stored at any version. Edits relayout the volume; ntfs3 mounts it but lists an empty root (root $I30 index pending)
ReFS 3.x; mutation is offline-quiescent only (see limitations). Its geometry analysis is real, but there is no creator to write a re-laid volume with, so Layout stays absent
V3/V6 decoder + RAID0 stripe arithmetic against documented layout, over real ext/XFS backing images and their native user.fhgfs xattrs — no BeeGFS-produced target set serves as an oracle
Read-only mounting of offline metadata/storage target sets through FilesystemStreamSet; V3 dentries + V6 inline/separate regular-file inodes; non-mirrored non-sparse RAID0. Nothing is created or modified: BeeGFS-level mutation would be a transaction across every target plus management state
No normative on-disk specification, reference implementation or genuine sample was located; the historical TFS\x01 magic and .tfs extension are unsourced and no longer detect, so the image is exposed opaquely and only when the caller names the format; see the format notes
Every public and protected member of all 868 types, generated from the built assembly and its XML documentation, is in REFERENCE.md.
🧪 How the proofs run
The Proof column is produced by these suites, all in Compression.Tests. External tools that are absent make the corresponding test skip rather than fail, so the matrix records what has been shown, not what a particular runner had installed. A tool too old to read the format at all counts as absent for this purpose and skips with the version it reported — it never examined the image, so it has not judged it. A tool that does read the image and then objects has judged it, and that is a failure, never a skip.
Suite
What it shows
Support/ThirdPartyFsCheck
Mounts the written image with the host kernel's own driver, or extracts it with 7-Zip, and compares every payload. A driver that is present and refuses the volume fails the test; only a driver that is absent lets it skip.
Support/QemuRunner (BSD guests)
A headless FreeBSD guest runs fsck_ffs over the written UFS volume; a DragonFly guest runs hammer over the HAMMER and HAMMER2 volumes. There is no Linux guest — Linux drivers are reached through the host kernel, not through QEMU.
KernelMount/InPlaceRwKernelMountTests
On a Linux host whose kernel carries the module, the host loop-mounts the package's image directly and reads the in-place-added file (MinixV1, MinixV2, NILFS2). Skips without sudo, losetup or the module.
e2fsck, xfs_repair, btrfs check, fsck.f2fs, fsck.jfs, reiserfsck, fsck.minix, fsck.hfsplus, hfsutils, ntfs-3g, mkudffs, unsquashfs, mtools, qemu-img accept what the package writes, and the package reads what they write.
DOS-era drivers under QEMU / dmsdos
MS-DOS 6.22 DRVSPACE mounts the DoubleSpace / DriveSpace CVFs; the dmsdos driver mounts the DriveSpace 3 and Stacker volumes.
Struct-parity unit tests
For formats with no reachable external tool, each on-disk structure the writer emits is compared field by field against the specification and read back by the package's own reader.
Disk-image containers follow the same rule with qemu-img: forward check, raw round-trip via convert -O raw, and reverse — an image qemu-img create made is opened by the package reader. A forensic-style path builds an inner filesystem with known files, wraps it in a container, validates the container externally, then walks it back and compares bytes.
🧯 Filesystem-aware recovery
FilesystemCarver in Compression.Analysis scans raw images for known superblock signatures at canonical offsets, asks the matching reader to validate each candidate, and can then extract readable entries — useful when a partition table is lost but an inner superblock survives.
Compression, checksums, bit I/O, partition helpers and the shared registry primitives
Host filesystem drivers / libguestfs
Not required at runtime.
External fsck / mkfs / qemu tools
Optional, used by the test suite only
⚠️ Limitations
This is an image-manipulation toolkit, not a kernel filesystem driver. R/W does not imply concurrent mount semantics, crash-consistent journaling under arbitrary interruption, or a drop-in replacement for the OS driver.
Where Notes says a format's edits rebuild the volume, an add or remove costs the whole image rather than the bytes that changed, and the block placement of untouched files may move.
bcachefs mutation is profile-gated: the in-place writer owns single-device regular pointer extents as emitted by this package. Bucket generations are carried through a mutation: emptying a bucket advances its generation, and the alloc key, the bucket_gens slot, the extent pointer and its backpointer are written from one source and checked against each other before the commit is published. Foreign volumes with extra live b-trees, non-canonical bucket_gens or alloc_v4 keys, inline / reflink / compressed extent keys, or unsupported inode and dirent types are refused for mutation rather than rewritten speculatively; read support is broader. How the accounting, backpointer and LRU keys were established is written up in BCACHEFS-ACCOUNTING.md.
ReFS edits are offline-quiescent: the image must not be mounted, and RefsMutationMode.NativeCow stays fail-closed. The reader walks ReFS 3.x containers, MSB+ trees, allocators, Block Refcount rows and MLog framing; the offline editor relocates data and metadata pages, replaces and removes regular files and empty directories through CoW B+ replacement and alternate-checkpoint publication. Block Refcount row creation and whole-file clone semantics are implemented and tested: RefsOfflineBlockCloner.CloneWholeFile repoints an existing destination stream at an existing, equal-sized, cluster-aligned source stream, materialises the shared-cluster reference counts — including the first clone of a slot the sparse table does not yet track — and publishes Object Table root #0 and Block Refcount root #6 through one alternate checkpoint, reclaiming the destination's former allocation only once that checkpoint is durable. Writing to a clone afterwards reallocates rather than overwriting the shared clusters. No public verb reaches this primitive: it is a library entry point, not something cwb can be asked to do, and the profile is deliberately narrower than FSCTL_DUPLICATE_EXTENTS_TO_FILE — resident, sparse, integrity, zero-length, already-shared and partial-range clones are all refused. Still open before a mounted driver could use the same core: redo-payload codecs and replay for every opcode, every Schema Table key rule, the allocation-zone policies of the three allocators, container create / delete / move, partial-range and EOF-extending clones, hard links, sparse and integrity-stream mutation beyond 4 KiB clusters, snapshots, ADS, security descriptors, reparse points, USN, rename, truncate, a format path, locking and a Windows chkdsk corpus.
Reiser4 remains WORM: the current writer captures the empty native tree but stores added files in a payload area the reiser4 driver does not see. It must not be promoted until the native tree writer owns those files.
GFS2 R/W is the standalone lock_nolock profile with regular files in the root directory; small files are stuffed and larger files use the indirect tree. Existing-image edits rebuild the volume while preserving its size floor and lock-table value. ExHash/nested-directory writing, journal replay, cluster-lock-manager state and extended attributes remain out of scope.
NSS native read support is intentionally narrow and quiescent: the reader reconstructs validated DirH/LEAF namespace relationships and ordinary contiguous file extents using the OES-derived clean-room profile in NSS-ON-DISK.md, while retaining anchor diagnostics for unsupported images. Native allocation trees, journals, trustee metadata, ZLBH history, compressed/sparse/fragmented data profiles and writable NSS pools remain out of scope; the existing writer still emits a private Workbench container rather than a pool NetWare/OES would mount.
Network and distributed formats generally carry no self-contained image. eCryptfs is the encrypted exception handled here: a lower file is structurally self-contained, and the passphrase profile is supported for AES-128/192/256; private-key authentication and xattr-only metadata remain unsupported.
Disk-image container support and inner-filesystem support are separate capabilities; a container marked R/W edits the filesystem inside it through that filesystem's own descriptor.
❤️ Support
If this project saves you time or money, consider supporting its development:
📜 License
Licensed under LGPL-3.0-or-later — see the repository LICENSE.