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>
impl<R: Read + Seek + Send + 'static> Filesystem<R>
Sourcepub fn open(reader: R) -> Result<Self>
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.
Sourcepub fn open_subvol(reader: R, subvol: SubvolId) -> Result<Self>
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.
Sourcepub fn open_with_caches(reader: R, cache_config: CacheConfig) -> Result<Self>
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.
Sourcepub fn open_subvol_with_caches(
reader: R,
subvol: SubvolId,
cache_config: CacheConfig,
) -> Result<Self>
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.
Sourcepub fn tree_block_cache_stats(&self) -> CacheStats
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.
Sourcepub fn default_subvol(&self) -> SubvolId
pub fn default_subvol(&self) -> SubvolId
The subvolume Filesystem was opened against (the default
FS_TREE unless Filesystem::open_subvol was used).
Sourcepub async fn list_subvolumes(&self) -> Result<Vec<SubvolInfo>>
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.
Sourcepub async fn get_subvol_info(&self, id: SubvolId) -> Result<Option<SubvolInfo>>
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.
Sourcepub fn superblock(&self) -> &Superblock
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.
Sourcepub fn dev_info(&self, devid: u64) -> Option<DeviceItem>
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.
Sourcepub async fn tree_search(
&self,
filter: SearchFilter,
max_buf_size: usize,
) -> Result<Vec<SearchItem>>
pub async fn tree_search( &self, filter: SearchFilter, max_buf_size: usize, ) -> Result<Vec<SearchItem>>
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.
Sourcepub async fn ino_lookup(
&self,
subvol: SubvolId,
objectid: u64,
) -> Result<Option<Vec<u8>>>
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).
Sourcepub async fn ino_paths(
&self,
subvol: SubvolId,
objectid: u64,
) -> Result<Vec<Vec<u8>>>
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.
Sourcepub fn forget(&self, ino: Inode)
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.
Sourcepub async fn lookup(
&self,
parent: Inode,
name: &[u8],
) -> Result<Option<(Inode, InodeItem)>>
pub async fn lookup( &self, parent: Inode, name: &[u8], ) -> Result<Option<(Inode, InodeItem)>>
Look up a child of parent by name.
Sourcepub async fn read_inode_item(&self, ino: Inode) -> Result<Option<InodeItem>>
pub async fn read_inode_item(&self, ino: Inode) -> Result<Option<InodeItem>>
Read the inode item for ino.
Sourcepub async fn readdir(&self, dir_ino: Inode, offset: u64) -> Result<Vec<Entry>>
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.
Sourcepub async fn readdirplus(
&self,
dir_ino: Inode,
offset: u64,
) -> Result<Vec<(Entry, Stat)>>
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.
Sourcepub async fn readlink(&self, ino: Inode) -> Result<Option<Vec<u8>>>
pub async fn readlink(&self, ino: Inode) -> Result<Option<Vec<u8>>>
Read the target of a symbolic link.
Sourcepub async fn read(&self, ino: Inode, offset: u64, size: u32) -> Result<Vec<u8>>
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.
Sourcepub async fn resolve_subvol_path(&self, path: &str) -> Result<Option<SubvolId>>
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.
Sourcepub async fn send<W: Write + Send + 'static>(
&self,
snapshot: SubvolId,
output: W,
) -> Result<W>
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.
Sourcepub async fn seek_hole_data(
&self,
ino: Inode,
offset: u64,
whence: SeekHoleData,
) -> Result<u64>
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.
Sourcepub async fn xattr_list(&self, ino: Inode) -> Result<Vec<Vec<u8>>>
pub async fn xattr_list(&self, ino: Inode) -> Result<Vec<Vec<u8>>>
List all xattr names for an inode.