Modify a FAT filesystem safely
Open writable media with both read and write access, operate through the
filesystem handle, and call sync before the backing device is removed.
[dependencies.hadris]
version = "3.0.0-rc.2"
default-features = false
features = ["std", "sync", "fat"]
use std::io::Write;
use hadris::fat::sync::FatFs;
use hadris::fs::sync::{FileSystem, Volume};
use hadris::fs::{MountOptions, OpenOptions, SystemClock};
use hadris::storage::host::FileDevice;
use hadris::storage::sync::Cache;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let image = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open("disk.img")?;
let device = Cache::new(FileDevice::new(image)?, 64);
let fs = FatFs::mount(device, MountOptions::new().with_clock(&SystemClock))?;
let vol = Volume::new(fs);
let mut file = vol.open("/hello.txt", OpenOptions::new().write().create().truncate())?;
file.write_all(b"Hello from Hadris\n")?;
file.close()?;
vol.lock().sync()?;
Ok(())
}
sync writes the sizes and modification times still held for open files,
the FAT32 free count, and flushes the device, so the Cache writes back its
dirty blocks. Cache<D> from hadris-storage replaces the old FAT sector
cache: it caches any block device and costs nothing unless constructed.
Writes are ordered so that an interrupted operation leaves a volume that
fsck repairs: at worst lost clusters, a chain longer than its file, or a
renamed node under both names. hadris::fat::sync::check reports exactly those
leftovers without changing the volume.
Mutation checklist
- Close
Filehandles (or callcloseon the node) so sizes reach the directory entry;syncwrites all of them. Closing does not flush the device: callFile::sync_all(fsync) orsyncfor durability. - Removing a file that is still open fails with
ErrorKind::Busy; close it first. A node you only looked up does not block removal; its id answersErrorKind::NotFoundafterwards until youforgetit. - Call
syncafter writes and before ejecting or closing removable media. - Do not mutate an image concurrently through another handle. To share one
volume between threads, clone the
hadris::fs::sync::Volume. FatFs::unmountsyncs and gives the device back.- Validate important generated images with
checkand an independent implementation.
For deterministic images, keep the default NoClock (which stamps
1980-01-01) or supply your own hadris::fs::Clock through
MountOptions::with_clock instead of relying on the host clock.