Skip to content

Commit bf8fbfc

Browse files
gregordinaryclaude
andcommitted
Document the 0.4.0 surface
The front page, the crate page, and the guide all described a crate with one filesystem in it. They now describe the one that ships: two filesystems, each a feature a build takes or leaves, reached through a root that belongs to neither. The guide's formatting and command-line pages carry FAT beside ext rather than after it, since a reader arrives wanting one of them and should not have to read the other first. The changelog states what 0.4.0 adds, what moved to the root and what that means for a caller who named it under `ext`, and the defects fixed since. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 4335a9d commit bf8fbfc

7 files changed

Lines changed: 1546 additions & 166 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 588 additions & 0 deletions
Large diffs are not rendered by default.

‎README.md‎

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
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

67
This 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

1314
Both 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

4148
The [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
6677
cargo build
6778
cargo test
6879
cargo 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

Comments
 (0)