Skip to main content

Filesystem

Struct Filesystem 

Source
pub struct Filesystem<R: Read + Seek + Send + 'static> { /* private fields */ }
Expand description

High-level read-only btrfs filesystem.

Filesystem is a cheap-to-clone handle (Arc internally) and all operations are async fn, so multiple tokio tasks can drive the same filesystem concurrently. I/O still serialises on a single internal mutex (held only inside spawn_blocking); a future phase can swap that for a reader pool without changing the public API.

Implementations§

Source§

impl<R: Read + Seek + Send + 'static> Filesystem<R>

Source

pub fn open(reader: R) -> Result<Self>

Bootstrap the filesystem from a reader over an image or block device, with default cache sizes.

This is sync because the heavy work happens during the bootstrap (chunk tree walk, root tree walk) and only runs once. Embedders that want non-blocking open can wrap the call in tokio::task::spawn_blocking themselves.

Source

pub fn open_subvol(reader: R, subvol: SubvolId) -> Result<Self>

Bootstrap the filesystem and select a non-default subvolume as the Filesystem::root, with default cache sizes.

subvol must be the tree id of an existing subvolume — pass the value from a previously-listed SubvolInfo::id, or use SubvolId(5) to get the default. Errors with NotFound if the id is unknown, InvalidInput if it’s outside the subvolume id range.

Source

pub fn open_with_caches(reader: R, cache_config: CacheConfig) -> Result<Self>

Like Filesystem::open but with caller-chosen cache sizes. Use CacheConfig::no_cache for benchmarking the cold path or memory-constrained embedders; otherwise tune the individual entries to match your workload.

Source

pub fn open_subvol_with_caches( reader: R, subvol: SubvolId, cache_config: CacheConfig, ) -> Result<Self>

Like Filesystem::open_subvol but with caller-chosen cache sizes.

Source

pub fn tree_block_cache_stats(&self) -> CacheStats

Snapshot of the tree-block cache hit/miss counters. Useful for tests, benchmarks, and embedders surfacing cache metrics.

Source

pub fn root(&self) -> Inode

Inode of the default subvolume’s root directory (objectid 256).

Source

pub fn default_subvol(&self) -> SubvolId

The subvolume Filesystem was opened against (the default FS_TREE unless Filesystem::open_subvol was used).

Source

pub async fn list_subvolumes(&self) -> Result<Vec<SubvolInfo>>

Enumerate every subvolume on the filesystem.

Walks the root tree, parsing ROOT_ITEM and ROOT_BACKREF entries to build a SubvolInfo per subvolume. The default FS_TREE (SubvolId(5)) is included with parent: None and an empty name.

Source

pub async fn get_subvol_info(&self, id: SubvolId) -> Result<Option<SubvolInfo>>

Fetch metadata for a single subvolume.

Currently implemented as a filtered Filesystem::list_subvolumes call — the root-tree walk dominates either way, so a one-shot lookup wouldn’t be faster than the cached/single-pass list. Returns Ok(None) for an unknown id.

Source

pub fn superblock(&self) -> &Superblock

Read-only access to the parsed primary-device superblock. Used by ioctl handlers (FS_INFO, GET_FEATURES, etc.) and by embedders that need to inspect format-level fields without re-parsing.

Source

pub fn dev_info(&self, devid: u64) -> Option<DeviceItem>

Return the DeviceItem for devid, or None if no such device exists on this filesystem.

Currently single-device-only: returns the primary device’s embedded dev_item from the superblock when devid == 1, None otherwise. Multi-device support would walk the dev tree; landing alongside multi-device write support.

Run a tree search matching the kernel’s BTRFS_IOC_TREE_SEARCH_V2 semantics. Returns at most filter.max_items items, stopping early if max_buf_size (the userspace buffer cap, including per-item 32-byte headers) would be exceeded by adding the next item.

Note: the kernel runs the search against any tree by id; we only resolve subvolume trees and the root tree (tree_id == 1). Searches against the chunk/extent/csum/etc. trees would need additional plumbing — they’re not exposed today.

Source

pub async fn ino_lookup( &self, subvol: SubvolId, objectid: u64, ) -> Result<Option<Vec<u8>>>

Resolve objectid in subvol to its slash-separated path from the subvolume root.

Walks the INODE_REF chain upwards from objectid until it reaches the subvolume root (objectid 256). For directories the kernel INO_LOOKUP ioctl returns the path with a trailing /; this helper does NOT add one — the caller can append if it needs to mimic that exactly.

Returns Ok(None) if any step in the chain has no INODE_REF (orphaned inode, or wrong subvol).

Source

pub async fn ino_paths( &self, subvol: SubvolId, objectid: u64, ) -> Result<Vec<Vec<u8>>>

Resolve every path in subvol that names objectid. A regular inode has a single path; hard-linked files have one entry per link, in unspecified order. Returns an empty vector for an orphan inode (no INODE_REF / INODE_EXTREF).

Each returned path is relative to the subvolume root, with no leading slash.

Source

pub fn blksize(&self) -> u32

Filesystem sectorsize.

Source

pub fn forget(&self, ino: Inode)

Drop cached state for ino from both the inode and extent-map caches. Embedders that observe inode-level invalidation events (FUSE forget, manual cache pressure) can call this to release memory ahead of LRU eviction. Safe to call for an inode that’s never been cached: it’s a no-op in that case.

Source

pub async fn lookup( &self, parent: Inode, name: &[u8], ) -> Result<Option<(Inode, InodeItem)>>

Look up a child of parent by name.

Source

pub async fn read_inode_item(&self, ino: Inode) -> Result<Option<InodeItem>>

Read the inode item for ino.

Source

pub async fn getattr(&self, ino: Inode) -> Result<Option<Stat>>

Read inode metadata as a Stat.

Source

pub async fn readdir(&self, dir_ino: Inode, offset: u64) -> Result<Vec<Entry>>

List the entries of a directory inode, starting strictly after offset. . and .. are synthesised at offsets 0 and 1.

Source

pub async fn readdirplus( &self, dir_ino: Inode, offset: u64, ) -> Result<Vec<(Entry, Stat)>>

Like Filesystem::readdir but pairs each Entry with its Stat so callers don’t need a separate getattr per entry. The FUSE driver feeds this into the kernel’s READDIRPLUS path, which collapses ls -l-style listings into one round trip.

Entries that vanish between the directory walk and the stat (effectively impossible on a read-only mount, but defended for robustness) are dropped from the result rather than erroring.

Read the target of a symbolic link.

Source

pub async fn read(&self, ino: Inode, offset: u64, size: u32) -> Result<Vec<u8>>

Read size bytes from ino starting at offset. Sparse holes and prealloc extents return zeros; compressed extents are decompressed.

Source

pub async fn resolve_subvol_path(&self, path: &str) -> Result<Option<SubvolId>>

Resolve a slash-separated subvolume path (relative to the filesystem root) to its SubvolId. Empty path / "/" resolves to the default FS_TREE (SubvolId(5)).

Walks the same list_subvolumes graph that btrfs subvolume list uses, so any path the user could see in that listing is resolvable here. Returns Ok(None) if the path doesn’t match any subvolume.

Source

pub async fn send<W: Write + Send + 'static>( &self, snapshot: SubvolId, output: W, ) -> Result<W>

Generate a v1 send stream describing snapshot and write it to output. Tier 1 of the send roadmap: full sends only (no parent), no clone sources, no encoded-write passthrough.

The stream begins with a SUBVOL command, then walks the subvolume tree path-first emitting per-inode creation commands (Mkfile / Mkdir / Symlink / Mknod / Mkfifo / Mksock), SetXattr for each xattr, Write chunks for regular file contents, and Truncate / Chmod / Chown / Utimes to finalise. Terminates with End.

Hardlinks beyond the first reference become Link commands rather than re-creating the inode. Subvolume crossings (DirItem whose location.key_type == ROOT_ITEM) are skipped — caller must run send again per subvolume.

Encodes paths as UTF-8 (lossy on invalid byte sequences). Real btrfs filenames are arbitrary bytes; full-fidelity non-UTF-8 support can come later if a real workload needs it.

§Errors

Returns an error if the subvolume isn’t found, any tree read fails, or the underlying writer fails.

Source

pub async fn seek_hole_data( &self, ino: Inode, offset: u64, whence: SeekHoleData, ) -> Result<u64>

Find the next hole or data region in ino at or after offset. Mirrors lseek(fd, offset, SEEK_HOLE) / lseek(fd, offset, SEEK_DATA) semantics.

SEEK_DATA returns the offset of the next byte that is part of a data region. Returns Err(ENXIO) if no data exists at or after offset (e.g. offset >= file_size).

SEEK_HOLE returns the offset of the next hole. EOF is always considered a virtual hole, so this succeeds for any offset < file_size. Returns Err(ENXIO) only when offset >= file_size.

Holes include both implicit (gaps with no EXTENT_DATA item) and explicit (regular extent with disk_bytenr == 0) representations. Inline and prealloc extents are treated as data — matching kernel btrfs and POSIX convention.

Source

pub async fn xattr_list(&self, ino: Inode) -> Result<Vec<Vec<u8>>>

List all xattr names for an inode.

Source

pub async fn xattr_get( &self, ino: Inode, name: &[u8], ) -> Result<Option<Vec<u8>>>

Look up the value of a single xattr by exact name.

Source

pub fn statfs(&self) -> StatFs

Filesystem-wide statistics pulled straight from the superblock. No I/O — sync.

Trait Implementations§

Source§

impl<R: Read + Seek + Send + 'static> Clone for Filesystem<R>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl<R> Freeze for Filesystem<R>

§

impl<R> RefUnwindSafe for Filesystem<R>

§

impl<R> Send for Filesystem<R>

§

impl<R> Sync for Filesystem<R>

§

impl<R> Unpin for Filesystem<R>

§

impl<R> UnsafeUnpin for Filesystem<R>

§

impl<R> UnwindSafe for Filesystem<R>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.