Skip to main content

Filesystem

Trait Filesystem 

Source
pub trait Filesystem {
Show 30 methods // Required methods fn create_file( &mut self, dev: &mut dyn BlockDevice, path: &Path, src: FileSource, meta: FileMeta, ) -> Result<()>; fn create_dir( &mut self, dev: &mut dyn BlockDevice, path: &Path, meta: FileMeta, ) -> Result<()>; fn create_symlink( &mut self, dev: &mut dyn BlockDevice, path: &Path, target: &Path, meta: FileMeta, ) -> Result<()>; fn create_device( &mut self, dev: &mut dyn BlockDevice, path: &Path, kind: DeviceKind, major: u32, minor: u32, meta: FileMeta, ) -> Result<()>; fn remove(&mut self, dev: &mut dyn BlockDevice, path: &Path) -> Result<()>; fn list( &mut self, dev: &mut dyn BlockDevice, path: &Path, ) -> Result<Vec<DirEntry>>; fn read_file<'a>( &'a mut self, dev: &'a mut dyn BlockDevice, path: &Path, ) -> Result<Box<dyn Read + 'a>>; fn flush(&mut self, dev: &mut dyn BlockDevice) -> Result<()>; // Provided methods fn streams_immediately(&self) -> bool { ... } fn create_file_streaming( &mut self, dev: &mut dyn BlockDevice, path: &Path, body: &mut dyn Read, len: u64, meta: FileMeta, ) -> Result<()> { ... } fn open_file_ro<'a>( &'a mut self, _dev: &'a mut dyn BlockDevice, _path: &Path, ) -> Result<Box<dyn FileReadHandle + 'a>> { ... } fn open_file_rw<'a>( &'a mut self, _dev: &'a mut dyn BlockDevice, _path: &Path, _flags: OpenFlags, _meta: Option<FileMeta>, ) -> Result<Box<dyn FileHandle + 'a>> { ... } fn image_len(&self) -> Option<u64> { ... } fn mutation_capability(&self) -> MutationCapability { ... } fn supports_mutation(&self) -> bool { ... } fn clone_capability(&self) -> CloneCapability { ... } fn clone_file( &mut self, dev: &mut dyn BlockDevice, src: &Path, dst: &Path, ) -> Result<()> { ... } fn clone_range( &mut self, _dev: &mut dyn BlockDevice, _src: &Path, _src_off: u64, _dst: &Path, _dst_off: u64, _len: u64, ) -> Result<()> { ... } fn read_symlink( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, ) -> Result<PathBuf> { ... } fn getattr( &mut self, dev: &mut dyn BlockDevice, path: &Path, ) -> Result<FileAttrs> { ... } fn set_attrs( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _attrs: SetAttrs, ) -> Result<()> { ... } fn truncate( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _new_size: u64, ) -> Result<()> { ... } fn rename( &mut self, _dev: &mut dyn BlockDevice, _old_path: &Path, _new_path: &Path, ) -> Result<()> { ... } fn hardlink( &mut self, _dev: &mut dyn BlockDevice, _target_path: &Path, _new_path: &Path, ) -> Result<()> { ... } fn list_xattrs( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, ) -> Result<Vec<XattrPair>> { ... } fn set_xattr( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _name: &str, _value: &[u8], ) -> Result<()> { ... } fn set_xattrs( &mut self, dev: &mut dyn BlockDevice, path: &Path, xattrs: &[XattrPair], ) -> Result<()> { ... } fn remove_xattr( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _name: &str, ) -> Result<()> { ... } fn statfs(&mut self, _dev: &mut dyn BlockDevice) -> Result<StatFs> { ... } fn total_file_bytes(&mut self, dev: &mut dyn BlockDevice) -> Result<u64> { ... }
}
Expand description

Top-level dyn-compatible API every filesystem implements. The format / open factory methods live on the sibling FilesystemFactory trait so this one stays object-safe — the generic walker in crate::repack can hold a &mut dyn Filesystem and drive any of Ext / Fat32 / HfsPlus / Ntfs / F2fs / Squashfs / Xfs through the same create_* / remove / list / read_file / flush entry points.

Required Methods§

Source

fn create_file( &mut self, dev: &mut dyn BlockDevice, path: &Path, src: FileSource, meta: FileMeta, ) -> Result<()>

Create a regular file at path populated from src with metadata meta.

Source

fn create_dir( &mut self, dev: &mut dyn BlockDevice, path: &Path, meta: FileMeta, ) -> Result<()>

Create a directory at path.

Create a symbolic link at path pointing at target.

Source

fn create_device( &mut self, dev: &mut dyn BlockDevice, path: &Path, kind: DeviceKind, major: u32, minor: u32, meta: FileMeta, ) -> Result<()>

Create a device node / FIFO / socket.

Source

fn remove(&mut self, dev: &mut dyn BlockDevice, path: &Path) -> Result<()>

Remove a file, directory, or special entry. Returns Error::InvalidArgument for a non-empty directory.

Source

fn list( &mut self, dev: &mut dyn BlockDevice, path: &Path, ) -> Result<Vec<DirEntry>>

List the entries of a directory.

Source

fn read_file<'a>( &'a mut self, dev: &'a mut dyn BlockDevice, path: &Path, ) -> Result<Box<dyn Read + 'a>>

Open a regular file for reading. Returns a boxed streaming reader that borrows both self (for filesystem metadata) and dev (for actual block reads), so it must outlive both.

Source

fn flush(&mut self, dev: &mut dyn BlockDevice) -> Result<()>

Persist outstanding dirty state to the device.

Provided Methods§

Source

fn streams_immediately(&self) -> bool

Create a regular file at path streaming exactly len bytes from body. Unlike create_file’s FileSource::Reader (which needs an owned ReadSeek + Send), body is a plain borrowed Read — so a body borrowed from another open filesystem can be piped straight through without an intermediate tempfile or a Seek/Send bound. Implementations MUST NOT retain body past the call.

Default: spool body into a tempfile and delegate to create_file(FileSource::HostPath(..)) — correct everywhere, so no backend regresses. Backends whose writer already consumes a &mut dyn Read (ext, FAT32, the archive core, …) override this for true zero-copy streaming. Whether create_file consumes its FileSource synchronously (true) rather than storing it to read later at flush (false — e.g. SquashFS / ISO 9660 / GRF, which keep every source until they serialise). Immediate backends let create_file_streaming buffer small files in memory instead of spilling each one to a temp file.

Source

fn create_file_streaming( &mut self, dev: &mut dyn BlockDevice, path: &Path, body: &mut dyn Read, len: u64, meta: FileMeta, ) -> Result<()>

Source

fn open_file_ro<'a>( &'a mut self, _dev: &'a mut dyn BlockDevice, _path: &Path, ) -> Result<Box<dyn FileReadHandle + 'a>>

Open a regular file for random-access reads with no writes. The returned handle is Read + Seek and reports the file’s total length via len(). Every backend that can surface file contents should implement this — including the immutable formats (ISO 9660 / SquashFS / tar / GRF) where open_file_rw is unsupported but seeking inside a file is still meaningful.

Default: returns Unsupported. Implementations override — most can do so by reusing the same extent / runlist walker that powers Self::read_file.

Source

fn open_file_rw<'a>( &'a mut self, _dev: &'a mut dyn BlockDevice, _path: &Path, _flags: OpenFlags, _meta: Option<FileMeta>, ) -> Result<Box<dyn FileHandle + 'a>>

Open a regular file for in-place reads + writes at byte granularity. The returned handle is Read + Write + Seek; dropping it persists any pending bytes (each implementation chooses whether Write::write is eager or buffered).

Filesystems whose on-disk format requires journaling to be safe across crash boundaries should refuse this method until their journal is wired — partial writes that bypass a journal leave the FS in a “needs fsck” state on next mount, which is a worse default than a clear Unsupported error.

Default: returns Unsupported. Implementations override only when they can produce a result that survives a clean unmount without external repair.

Source

fn image_len(&self) -> Option<u64>

For archive / streaming writers backed by a pre-sized device: the exact number of bytes the output occupies after flush. The backing file is provisioned generously (and sparsely), so the caller truncates it to this length — an archive must be exactly its own size, not padded with a zero tail.

Default None: filesystem images keep their provisioned size. Only the archive backends (zip/cpio/ar) override this.

Source

fn mutation_capability(&self) -> MutationCapability

Capability of this filesystem with respect to mutating an already-flushed image. Three cases:

Default: Mutable. Override on backends that aren’t.

Source

fn supports_mutation(&self) -> bool

Convenience shortcut: can this filesystem satisfy create_file / remove? Equivalent to mutation_capability().supports_add_remove(). Returns true for both MutationCapability::Mutable and MutationCapability::WholeFileOnly — callers that need finer detail (e.g. “can I patch byte N?”) should query Self::mutation_capability directly.

Source

fn clone_capability(&self) -> CloneCapability

Reflink / clone capability of this filesystem — does it natively share extents, and at what granularity?

Default: CloneCapability::Noneclone_file will byte-copy and clone_range will return Unsupported. Reflink-capable backends (XFS once the REFLINK feature is on, APFS clones, Btrfs) override to surface the right variant.

Source

fn clone_file( &mut self, dev: &mut dyn BlockDevice, src: &Path, dst: &Path, ) -> Result<()>

Clone the file at src into a new file at dst. Reflink-capable backends share extents (zero data copy, refcount-btree updates); everything else falls back to the default byte-copy.

Default behaviour. Spools src to a host tempfile so the read-borrow on self is dropped, then runs create_file(dst, FileSource::TempFile, ...). Best-effort metadata via Self::getattr (mode / uid / gid / mtime); falls back to FileMeta::default when the source backend has no getattr implementation.

Contracts.

  • src must exist; dst must not already exist.
  • dst’s parent directory must exist.
  • The result is observable through read_file / getattr regardless of whether extents were shared — callers needn’t inspect clone_capability to use this method.

Returns Err(Unsupported) only when neither sharing nor the default fallback can satisfy the call (e.g. an immutable backend can’t create files at all).

Source

fn clone_range( &mut self, _dev: &mut dyn BlockDevice, _src: &Path, _src_off: u64, _dst: &Path, _dst_off: u64, _len: u64, ) -> Result<()>

Clone an arbitrary byte range src[src_off..src_off+len] into dst[dst_off..dst_off+len]. Reflink-capable backends share the underlying extents (BTRFS_IOC_CLONE_RANGE / FICLONERANGE semantics: writes through either side trigger COW).

Default: crate::Error::Unsupported. Sub-file extent sharing is fundamentally a refcount-btree operation; backends without that machinery cannot satisfy it (a byte-copy would have different semantics — writes through src after the “clone” would NOT propagate, defeating the point).

Contracts (when supported):

  • src and dst must both exist (dst may equal src).
  • src_off + len must not exceed src’s size; dst_off may extend dst (the backend grows it).
  • Offsets and length must be aligned to the backend’s allocation unit (typically the cluster / block size); the backend’s docs specify the exact rule.

Read a symbolic link’s target. Default returns Unsupported — filesystems that have symlinks (ext, tar, xfs, hfs+, ntfs, squashfs, iso 9660 via Rock Ridge) override.

Source

fn getattr( &mut self, dev: &mut dyn BlockDevice, path: &Path, ) -> Result<FileAttrs>

Full attributes for path. Used by the FUSE adapter to populate getattr and lookup replies; also handy for any consumer that wants a complete stat-like result without juggling Self::list + the file handle.

Default: best-effort. We list the parent and find the entry — that gives kind, size, and inode. The rest (mode, uid, gid, times) are defaulted by FileAttrs::defaults_for (mode 0o755 for dirs, 0o644 for files, 0o777 for symlinks; all times 0). Backends with per-file metadata (ext, hfs+, ntfs, xfs, …) should override.

Source

fn set_attrs( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _attrs: SetAttrs, ) -> Result<()>

Update attributes on path. Fields set to None in attrs are left unchanged. Backends that can’t change a given field silently ignore it (FAT, for example, has no uid/gid concept).

Default: returns Unsupported. Read-only and metadata-poor backends keep this default; mutable backends override.

Source

fn truncate( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _new_size: u64, ) -> Result<()>

Resize path to new_size bytes. Equivalent to FileHandle::set_len reached through a path. Growing fills with zeros; shrinking discards trailing bytes and frees blocks.

Default: returns Unsupported. Mutable backends override.

Source

fn rename( &mut self, _dev: &mut dyn BlockDevice, _old_path: &Path, _new_path: &Path, ) -> Result<()>

Rename old_path to new_path. Cross-directory moves and directory renames are both in scope — the operation must preserve the target inode (so hardlinks survive).

Default: returns Unsupported. Mutable backends override.

Add a new directory entry at new_path that points at the existing inode at target_path — a POSIX hard link.

Default: returns Unsupported. Only ext implements this today.

Source

fn list_xattrs( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, ) -> Result<Vec<XattrPair>>

List the extended attributes attached to path, with both names and values. The FUSE adapter splits this into listxattr / getxattr itself; we surface both at once so backends don’t need two parallel walkers.

Default: empty vec. Backends with xattr storage (ext, ntfs, hfs+) override.

Source

fn set_xattr( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _name: &str, _value: &[u8], ) -> Result<()>

Write or replace the xattr name on path. Returns Unsupported when the backend can’t store xattrs.

Source

fn set_xattrs( &mut self, dev: &mut dyn BlockDevice, path: &Path, xattrs: &[XattrPair], ) -> Result<()>

Write a whole set of xattrs onto path at once, replacing any existing set. Backends that store xattrs in a single on-disk structure (ext’s external attribute block) override this to write them atomically — applying them one at a time via set_xattr would orphan the previous block on each call. The default applies them individually.

Source

fn remove_xattr( &mut self, _dev: &mut dyn BlockDevice, _path: &Path, _name: &str, ) -> Result<()>

Remove the xattr name from path. Returns Unsupported when the backend can’t store xattrs.

Source

fn statfs(&mut self, _dev: &mut dyn BlockDevice) -> Result<StatFs>

Filesystem-level capacity stats. The FUSE adapter calls this to answer statfs; the CLI’s info command could too.

Default: StatFs::default — 4 KiB block size, zero counts, name_max = 255. Backends with real superblock data override.

Source

fn total_file_bytes(&mut self, dev: &mut dyn BlockDevice) -> Result<u64>

Recursive sum of all regular-file sizes in the filesystem. Uses the size field on DirEntry returned by Self::list — filesystems that don’t surface size from a listing return 0 for those entries, in which case the total is best-effort.

Skips the special names ".", "..", and "lost+found" so the walk doesn’t loop / double-count ext’s reserved tree.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl Filesystem for Affs

Source§

impl Filesystem for Apfs

Filesystem adapter for APFS. An Apfs opened via Apfs::open is read-only — mutation calls return Unsupported. An Apfs returned by Apfs::format is in pending-write mode: create_file / create_dir / create_symlink buffer operations in memory and flush drains them into a fresh image through write::ApfsWriter. After flush the Apfs is in read mode and behaves like a freshly-opened image.

Source§

impl Filesystem for ArFs

Source§

impl Filesystem for ArcFs

Source§

impl Filesystem for ArchiveFs

Source§

impl Filesystem for CabFs

Source§

impl Filesystem for CpioFs

Source§

impl Filesystem for Exfat

Filesystem adapter so inspect::open(dev) can return a Box<dyn Filesystem> that walks and mutates an exFAT image. Symlinks and device nodes have no representation in exFAT and return Unsupported. The caller must call flush to persist FAT + bitmap changes before dropping the volume.

Source§

impl Filesystem for Ext

Source§

impl Filesystem for F2fs

Source§

impl Filesystem for Fat32

Source§

impl Filesystem for Grf

Source§

impl Filesystem for Hfs

Source§

impl Filesystem for HfsPlus

Source§

impl Filesystem for Iso9660

Source§

impl Filesystem for LhaFs

Source§

impl Filesystem for LzxFs

Source§

impl Filesystem for Ntfs

Source§

impl Filesystem for Ramfs

Source§

impl Filesystem for RarFs

Source§

impl Filesystem for SevenZFs

Source§

impl Filesystem for SitFs

Source§

impl Filesystem for Squashfs

Source§

impl Filesystem for Tar

Read-only Filesystem adapter so inspect::open(dev) can return a Box<dyn Filesystem> that walks a tar archive. Writes return Unsupported — tar archives are sequential and repack is the only way to produce a new one.

Source§

impl Filesystem for Xfs

Source§

impl Filesystem for ZipFs