11# ferrosys
22
3- A pure-Rust ext2/ext3/ext4 filesystem: it builds and reads filesystem images in
4- userspace, over ordinary byte streams, in safe Rust.
3+ Pure-Rust filesystem tooling: it builds and reads filesystem images in userspace, over
4+ ordinary byte streams, in safe Rust. Two families — ext2/ext3/ext4 and FAT12/FAT16/FAT32 —
5+ and a build takes the ones it names.
56
67This Cargo workspace holds two crates:
78
8- - [ ` ferrosys ` ] ( crates/ferrosys ) — the library: a formatter and reader with resize-safe,
9- byte-reproducible on-disk geometry.
9+ - [ ` ferrosys ` ] ( crates/ferrosys ) — the library: a formatter and reader per family, each
10+ behind a feature of its own, with byte-reproducible on-disk geometry.
1011- [ ` ferrosys-cli ` ] ( crates/ferrosys-cli ) — the ` ferrosys ` binary, which puts the library
11- on the command line.
12+ on the command line and carries every family .
1213
1314Both build on Rust 1.88 or newer.
1415
@@ -18,25 +19,31 @@ Both build on Rust 1.88 or newer.
1819
1920## Highlights
2021
21- - ** ext2, ext3, and ext4** — one formatter and one reader across the lineage, from the
22- classic direct/indirect block map to extent trees of any depth.
23- - ** Resize-safe geometry** — descriptor backups and reserved GDT blocks, sized by a grow
24- reservation, let the image grow in place without relocating its descriptor table.
25- - ** Byte-reproducible** — the UUID, hash seed, and timestamps are inputs, so the same
26- inputs write the same image every time.
27- - ** Full fidelity** — every file type, ownership and mode bits, nanosecond timestamps,
28- extended attributes, POSIX ACLs, metadata checksums, a jbd2 journal, and an orphan file.
29- - ** A robust reader** — bounds-checks every field into typed errors, reads foreign images
30- other tools wrote, and scans a whole image into typed anomalies rendered as JSON, SARIF,
31- or a table, allocating in proportion to the bytes an image holds rather than to what it
32- claims.
22+ - ** Two families, one at a time or both** — ext2, ext3, and ext4 across one lineage, from
23+ the classic direct/indirect block map to extent trees of any depth; FAT12, FAT16, and
24+ FAT32 across another, where the type is derived from the cluster count rather than
25+ chosen. Each is a feature, so a consumer wanting one filesystem compiles one.
26+ - ** Resize-safe ext geometry** — descriptor backups and reserved GDT blocks, sized by a
27+ grow reservation, let the image grow in place without relocating its descriptor table.
28+ - ** Byte-reproducible** — the identifiers and timestamps an image carries are inputs, so
29+ the same inputs write the same image every time and nothing about the machine that wrote
30+ one reaches it.
31+ - ** Full fidelity, and a report where a format cannot hold it** — ext records every file
32+ type, ownership and mode bits, nanosecond timestamps, extended attributes, POSIX ACLs,
33+ metadata checksums, a jbd2 journal, and an orphan file. Where a format holds less than
34+ the tree it is given, what it could not keep is named rather than dropped in silence.
35+ - ** A robust reader per family** — bounds-checks every field into typed errors, reads
36+ foreign images other tools wrote, and scans a whole image into typed findings rendered as
37+ JSON, SARIF, or a table, allocating in proportion to the bytes an image holds rather than
38+ to what it claims.
3339- ** Built for scale** — streaming in both directions: a format writes only the blocks the
3440 filesystem uses, so an image stays sparse and may be larger than memory, and a read
3541 windows its way through a file rather than holding it, so pulling a multi-gigabyte file
36- out of an image costs a working set. 64-bit block addressing reaches past 16 TiB.
37- - ** Sources** — a programmatic tree, a tar archive, or a directory on this machine, each
38- handing a file's bytes over as a handle so a format's peak memory is the largest single
39- file rather than the sum of them all.
42+ out of an image costs a working set. ext's 64-bit block addressing reaches past 16 TiB.
43+ - ** Sources and sinks, belonging to no family** — a programmatic tree, a tar archive, or a
44+ directory on this machine feeds whichever family is being written, and an archive or a
45+ directory drains whichever one was opened. Each hands a file's bytes over as a handle, so
46+ a format's peak memory is the largest single file rather than the sum of them all.
4047
4148The [ crate README] ( crates/ferrosys/README.md ) and the
4249[ guide] ( https://gregordinary.github.io/ferrosys/ ) carry the complete feature list.
@@ -50,14 +57,18 @@ $ ferrosys format --size 512M --uuid "$(uuidgen)" --time 1700000000 \
5057 --from-tar rootfs.tar rootfs.img
5158$ ferrosys inspect rootfs.img
5259$ ferrosys extract rootfs.img --to-tar - | tar -tv
60+
61+ $ ferrosys format --type fat32 --size auto --from-dir seed/ seed.img
5362```
5463
55- ` format ` writes a filesystem — from a tar archive, a directory tree, or empty, at a size
56- you name or one ` --size auto ` finds from the contents — ` inspect ` reports on one and says
57- whether it is sound, ` extract ` reads the contents back out as a tar archive, a directory
58- tree, one file's bytes, one path's metadata, or a listing, ` detect ` says which filesystem
59- an image holds, and ` identity ` changes what one is known by. The identifiers and timestamps are inputs, so the same inputs
60- write the same image every time. The exit codes mirror ` e2fsck ` 's. See the guide's
64+ ` format ` writes a filesystem — of the type ` --type ` names, from a tar archive, a directory
65+ tree, or empty, at a size you name or one ` --size auto ` finds from the contents —
66+ ` inspect ` reports on one and says whether it is sound, ` extract ` reads the contents back
67+ out as a tar archive, a directory tree, one file's bytes, one path's metadata, or a
68+ listing, ` detect ` says which filesystem an image holds, and ` identity ` changes what one is
69+ known by. Every command takes any family the binary carries. The identifiers and
70+ timestamps are inputs, so the same inputs write the same image every time. The exit codes
71+ mirror ` e2fsck ` 's. See the guide's
6172[ command-line chapter] ( https://gregordinary.github.io/ferrosys/cli.html ) .
6273
6374## Build and test
@@ -66,6 +77,7 @@ write the same image every time. The exit codes mirror `e2fsck`'s. See the guide
6677cargo build
6778cargo test
6879cargo doc --no-deps # clean under RUSTDOCFLAGS="-D warnings"
80+ ci/lint-features.sh # and clean in every feature configuration on offer
6981```
7082
7183## Documentation
0 commit comments