crates/filesystem/README.md
Filesystem backends for microsandbox virtual machines. This crate now exposes the three backends the runtime still uses: PassthroughFs, MemFs, and DualFs.
DynFileSystem and can be nested freelyExposes a single host directory to the guest VM. The guest sees standard Linux ownership, permissions, and file types even when the host runs macOS.
let fs = PassthroughFs::builder()
.root_dir("/path/to/host/dir")
.build()?;
Metadata like uid, gid, and mode are stored in an extended attribute on the host, so the actual host file permissions stay untouched. Special files (devices, sockets, FIFOs) are stored as regular files with their type bits in the xattr. Path confinement prevents the guest from escaping the root directory.
A pure in-memory filesystem — no host I/O at all. Good for scratch space and ephemeral workloads.
use microsandbox_filesystem::SizeExt;
let fs = MemFs::builder()
.capacity(64.mib())
.max_inodes(10_000)
.build()?;
Combines two backends under a single mount point with a dispatch policy that routes each operation to the right backend.
let fs = DualFs::builder()
.backend_a(mem_fs)
.backend_b(passthrough_fs)
.policy(ReadBackendBWriteBackendA)
.build()?;
Built-in policies:
| Policy | Behavior |
|---|---|
ReadBackendBWriteBackendA | Reads from B, writes to A (default) |
BackendAOnly | Everything goes to A |
BackendAFallbackToBackendBRead | Reads try A first, fall back to B |
MergeReadsBackendAPrecedence | Merge directory listings, A wins on conflicts |
When a write targets a file that lives on the other backend, DualFs copies it over automatically.
All backends support configurable kernel caching:
| Policy | Behavior |
|---|---|
Never | No caching — every read hits the backend (DIRECT_IO) |
Auto | Kernel decides (default for PassthroughFs and DualFs) |
Always | Aggressive caching (default for MemFs, since memory is authoritative) |
let fs = PassthroughFs::builder()
.root_dir("/path/to/dir")
.cache_policy(CachePolicy::Always)
.build()?;