FSYS (fsys-rs) is a low-level file and directory IO crate for Rust.
It is aimed at systems code that needs explicit control over durability,
predictable cross-platform behavior, and an API surface that stays close to
how storage software actually thinks about IO.
The crate sits between std::fs and a fully bespoke platform layer. It keeps
the operational model explicit: you choose a durability method, build a
long-lived Handle, and issue file or directory operations through that
handle. On supported platforms, fsys uses the best available primitive for
the selected method while keeping fallback behavior visible rather than
implicit.
That makes it a good fit for storage engines, embedded databases, local-first
applications, durable caches, append-heavy services, background workers, and
other programs where write semantics matter as much as raw throughput. It is
not trying to replace std::fs for ordinary application code.
⚠️ Status: Early development.
The crate is usable and tested, but the API is not stable yet. Expect breaking changes before1.0.0.
FEATURES
- Five real durability methods —
Sync,Data,Mmap,Direct, and hardware-awareAuto. Every method is platform-honest: the actual primitive in use is observable viaHandle::active_method()andHandle::active_durability_primitive(). - Cross-platform IO semantics — one API surface across Linux, macOS, and Windows, with platform-specific fallbacks documented rather than hidden.
- NVMe passthrough flush — on Linux (
NVME_IOCTL_IO_CMD) and Windows (IOCTL_STORAGE_PROTOCOL_COMMAND) when the hardware supports it and the process has the privilege. Transparent fallback tofdatasync/WRITE_THROUGHotherwise. - Linux io_uring path —
Method::Directon Linux routes throughio_uringwhen available (kernel ≥ 5.1, no SECCOMP/AppArmor block), falling back toO_DIRECT+pwrite+fdatasynccleanly. - Atomic replace-style writes — every public write API (
write,write_copy,write_batch,Batch::commit) uses a temp-file + atomic rename pattern. The target file is either entirely the old payload or entirely the new payload — never torn. - Crash-safety verified — per-method crash tests with three kill points (pre-syscall, mid-syscall, post-syscall) and the 100× pre-merge stability protocol.
write_copywith metadata preservation — atomic-swap that preserves the target's existing mode (Unix), owner/group (Unix, when permitted), ACLs (Windows), and timestamps (all platforms).- Root-scoped handles — bind a
Handleto a base directory and reject paths that escape it. - Full file and directory CRUD — write, read, append, positioned writes, range reads, truncate, rename, copy, metadata, sync, directory creation/removal, listing, recursive scan, glob find, and recursive count.
- Batch operations — grouped writes, deletes, and copies through
write_batch,delete_batch,copy_batch, and the chainableBatchbuilder. - Async layer — gated behind the
asyncCargo feature. Every sync method gets an_asyncsibling backed bytokio::task::spawn_blocking; async batch ops route through the per-handle dispatcher viatokio::sync::oneshot. - Configurable group lane — tune batch window, batch size, queue depth, io_uring queue depth, and aligned-buffer-pool size per handle.
- Quick one-shot API — convenience helpers backed by a lazily initialized default handle for simple cases.
- Structured error reporting — 18 explicit error variants with stable
FS-XXXXXcodes for unsupported methods, alignment failures, atomic-replace failures, NVMe passthrough denial, async-runtime requirements, glob-pattern errors, and batch failure position.
What fsys provides today
- A
Handle+Buildermodel for configuring IO once and reusing it across operations. - Five durability methods:
Sync,Data,Mmap,Direct(with NVMe passthrough on capable hardware), andAuto. - Cross-platform file CRUD: atomic replace-style writes,
write_copy(atomic-swap with metadata preservation), reads, appends, deletes, copies, range reads, truncate, rename, metadata, and sync operations. - Cross-platform directory CRUD: create, remove, recursive variants, existence checks, listing, recursive scan, glob find, and recursive count.
- A root-scoped path model so a handle can enforce that all resolved paths stay under a chosen base directory.
- A convenience
quickmodule for one-shot operations when you do not want to manage a handle directly. - A batch API for grouped writes, deletes, and copies via
Handle::write_batch,Handle::delete_batch,Handle::copy_batch, and theBatchbuilder. - A per-handle group lane with bounded queueing and configurable batch thresholds for workloads that benefit from grouped dispatch.
- An optional async layer (feature
async) covering every sync method. - The
fsys::primitivemodule of canonical durability-primitive strings for runtime observation of the active code path.
Design principles
- Explicit semantics first. The API should make durability and routing choices visible.
- Portable without pretending platforms are identical. Linux, macOS, and Windows have different primitives;
fsysexposes one model while documenting where fallbacks occur. - Low ceremony for the common path. A single
Handleshould cover most workloads; thequickmodule exists for one-off use. - Predictable failure behavior. Atomic write/replace and batch operations report where failure happened instead of silently smoothing over it.
- Room to grow. Reserved methods and pipeline internals make it possible to expand into more advanced IO paths without replacing the public model.
When to use fsys
Use fsys when you need one or more of the following:
- Explicit control over full sync, data-only sync, direct IO, or automatic method selection.
- Cross-platform file IO behavior that is stricter and more deliberate than
std::fsdefaults. - Atomic replace-style writes for file updates.
- A handle-scoped root for keeping file activity inside a known subtree.
- Grouped write/delete/copy submission for higher-throughput batch-style work.
Non-goals
- High-level filesystem tooling such as watchers, lock orchestration, virtual filesystems, or rich path-manipulation utilities.
- Replacing
std::fsfor everyday scripting or application scaffolding. - Hiding platform-specific tradeoffs behind vague “fast mode” abstractions.
- Full async-runtime integration in the core crate.
Status & roadmap
Current state: the public API is feature-complete for everything that will
ship at 1.0 — with the single exception of Method::Journal, which is
deliberately reserved for 0.7.x. The current release line is 0.6.x.
0.6.0 finished the public surface: the async layer, NVMe passthrough flush
on Linux and Windows, completion CRUD methods (write_copy, scan, find,
count), Handle::active_durability_primitive() plus the fsys::primitive
constants module, and a publication-quality documentation pass across the
crate. The 0.5.x line consolidated real hardware probing, the real
Method::Mmap implementation, the io_uring path on Linux, and the per-method
crash-test harness. Everything from earlier phases (handle/builder, full
file/dir CRUD, batch + group lane) is unchanged.
What remains before 1.0:
Method::Journal(intent-log durability) —0.7.xwork.- A native io_uring async substrate (using io_uring as a true
Future-driven primitive instead ofspawn_blocking) —0.7.x. - Deep audit, performance certification on real NVMe, full alpha → beta → RC progression.
The roadmap below shows where each phase landed.
0.1.x— [DONE]: Initial setup.0.2.x— [DONE]: Scaffolding and foundation modules.0.3.x— [DONE]: Handle, CRUD, metadata, and cross-platform IO core.0.4.x— [DONE]: Group-lane batching and dispatcher pipeline.0.5.x— [DONE]: Real hardware probe,Method::Mmap,Method::Directwith io_uring on Linux, per-method crash tests.0.6.x— [CURRENT]: Async layer, NVMe passthrough, completion CRUD, publication-quality docs.0.7.x— [NEXT]:Method::Journal, native async io_uring, observability, deep audit.0.8.x— [BETA]: Public testing and compatibility validation.0.9.x— [RC]: Release candidate.1.0.0— Stable API release.
The roadmap is aspirational, not a schedule. Versions ship when they're right, not when the calendar agrees.
Installation
[]
= "0.6.0"
To opt into the async layer:
[]
= { = "0.6.0", = ["async"] }
⚠️ The crate is published and usable, but it should still be treated as pre-stable software. Use it in production only if you are comfortable tracking breaking changes before
1.0.0.
Cargo features
| Feature | Default | Pulls in | Purpose |
|---|---|---|---|
async |
off | tokio (rt, rt-multi-thread, sync, macros) |
_async siblings for every sync method; async batch via tokio::sync::oneshot. |
stress |
off | (none) | Switches the soak tests in tests/stress.rs from a 60-second validation run to the full 1-hour soak duration. CI nightly enables this; dev iteration leaves it off. |
fuzz |
off | (none) | Compile-only flag for fuzz instrumentation. The actual fuzz targets live in fuzz/ (separate cargo-fuzz workspace). |
Minimum supported Rust version
1.75. The MSRV may be raised in any minor version before 1.0.0. After 1.0.0, MSRV bumps require a minor version bump.
Documentation
- API reference: https://docs.rs/fsys
- Architecture overview:
docs/ARCHITECTURE.md - Method matrix and
Autodecision ladder:docs/METHODS.md - Performance targets and tuning:
docs/PERFORMANCE.md - Crash-safety contract per method:
docs/CRASH-SAFETY.md - Per-platform behavior + capability requirements:
docs/PLATFORM-NOTES.md - Migration policy:
docs/MIGRATION.md
Coming Soon
LICENSE
Licensed under the Apache License version 2.0 [ LICENSE-APACHE ], or the MIT License [ LICENSE-MIT ]; otherwise known as the ("License Agreement"); you are permitted to use this software, its source code, documentation, concepts, and any of the associated contents, within the limitations defined by the "License Agreement".