pub trait VfsiExt: Vfsi {
Show 47 methods
// Provided methods
fn open_options(&self) -> OpenOptions<'_, Self> { ... }
fn statfs<P>(&self, target: P) -> Result<FilesystemStats, VfError>
where P: AsTarget<Self::File> { ... }
fn open(&self, path: impl AsRef<Path>) -> Result<Self::File, VfError> { ... }
fn create(&self, path: impl AsRef<Path>) -> Result<Self::File, VfError> { ... }
fn open_with(&self, request: OpenOp<'_>) -> Result<Self::File, VfError> { ... }
fn close_files(&self, files: Vec<Self::File>) -> Result<(), VfError> { ... }
fn read(&self, path: impl AsRef<Path>) -> Result<Vec<u8>, VfError> { ... }
fn read_with_options(
&self,
path: impl AsRef<Path>,
options: ReadOptions,
) -> Result<Vec<u8>, VfError> { ... }
fn read_files<P>(&self, paths: &[P]) -> Result<Vec<Vec<u8>>, VfError>
where P: AsRef<Path> { ... }
fn read_files_with_options<P>(
&self,
paths: &[P],
options: ReadOptions,
) -> Result<Vec<Vec<u8>>, VfError>
where P: AsRef<Path> { ... }
fn read_to_string(&self, path: impl AsRef<Path>) -> Result<String, VfError> { ... }
fn read_to_string_with_options(
&self,
path: impl AsRef<Path>,
options: ReadOptions,
) -> Result<String, VfError> { ... }
fn read_stream(
&self,
path: impl AsRef<Path>,
callback: impl FnMut(u64, &[u8]) -> Result<ControlFlow<()>, VfError>,
) -> Result<StreamCompletion, VfError> { ... }
fn read_stream_with_options(
&self,
path: impl AsRef<Path>,
options: StreamOptions,
callback: impl FnMut(u64, &[u8]) -> Result<ControlFlow<()>, VfError>,
) -> Result<StreamCompletion, VfError> { ... }
fn write(&self, path: impl AsRef<Path>, data: &[u8]) -> Result<(), VfError> { ... }
fn write_files<P, B>(&self, entries: &[(P, B)]) -> Result<(), VfError>
where P: AsRef<Path>,
B: AsRef<[u8]> { ... }
fn std_io<'a>(
&'a self,
file: &'a Self::File,
) -> impl Read + Write + Seek + 'a { ... }
fn sync_data(&self, file: &Self::File) -> Result<(), VfError> { ... }
fn sync_all(&self, file: &Self::File) -> Result<(), VfError> { ... }
fn attrs<T>(&self, path: T) -> Result<Attrs, VfError>
where T: AsTarget<Self::File> { ... }
fn attrs_with_options<T>(
&self,
path: T,
options: AttrsOptions,
) -> Result<Attrs, VfError>
where T: AsTarget<Self::File> { ... }
fn symlink_attrs(&self, path: impl AsRef<Path>) -> Result<Attrs, VfError> { ... }
fn read_dir(&self, path: impl AsRef<Path>) -> Result<Vec<DirEntry>, VfError> { ... }
fn read_dir_with_options(
&self,
path: impl AsRef<Path>,
options: ListDirOptions,
) -> Result<Vec<DirEntry>, VfError> { ... }
fn read_dirs<P>(
&self,
paths: &[P],
) -> Result<Vec<DirectoryListing>, VfError>
where P: AsRef<Path> { ... }
fn read_dirs_with_options<P>(
&self,
paths: &[P],
options: ListDirOptions,
) -> Result<Vec<Vec<DirectoryListing>>, VfError>
where P: AsRef<Path> { ... }
fn listdir(
&self,
root: impl AsRef<Path>,
options: impl Into<WalkOptions>,
visitor: impl FnMut(&WalkEvent) -> Result<WalkControl, VfError>,
) -> Result<TraversalCompletion, VfError> { ... }
fn visit_entries_with_options<P>(
&self,
paths: &[P],
options: ListDirOptions,
callback: impl FnMut(usize, &DirEntry) -> Result<ControlFlow<()>, VfError>,
) -> Result<Vec<TraversalCompletion>, VfError>
where P: AsRef<Path> { ... }
fn visit_dirs_ordered(
&self,
root: impl AsRef<Path>,
options: ListDirOptions,
order: impl FnMut(&DirEntry, &DirEntry) -> Ordering,
descend: impl FnMut(&DirEntry) -> bool,
visitor: impl FnMut(DirectoryListing, usize) -> Result<WalkControl, VfError>,
) -> Result<TraversalCompletion, VfError> { ... }
fn create_dir(&self, path: impl AsRef<Path>) -> Result<(), VfError> { ... }
fn truncate<T>(&self, target: T, len: u64) -> Result<(), VfError>
where T: AsTarget<Self::File> { ... }
fn chmod<T>(
&self,
target: T,
permissions: Permissions,
) -> Result<(), VfError>
where T: AsTarget<Self::File> { ... }
fn chown<T>(
&self,
target: T,
uid: Option<u32>,
gid: Option<u32>,
) -> Result<(), VfError>
where T: AsTarget<Self::File> { ... }
fn create_dir_with_mode(
&self,
path: impl AsRef<Path>,
mode: u32,
) -> Result<(), VfError> { ... }
fn symlink(
&self,
target: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<(), VfError> { ... }
fn read_link(&self, path: impl AsRef<Path>) -> Result<PathBuf, VfError> { ... }
fn hard_link(
&self,
source: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<(), VfError> { ... }
fn create_dir_all(&self, path: impl AsRef<Path>) -> Result<(), VfError> { ... }
fn rename(
&self,
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
) -> Result<(), VfError> { ... }
fn copy(
&self,
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
) -> Result<(), VfError> { ... }
fn copy_with_options(
&self,
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
options: CopyOptions,
) -> Result<(), VfError> { ... }
fn remove_file(&self, path: impl AsRef<Path>) -> Result<(), VfError> { ... }
fn remove_dir(&self, path: impl AsRef<Path>) -> Result<(), VfError> { ... }
fn remove_dir_all(&self, path: impl AsRef<Path>) -> Result<(), VfError> { ... }
fn remove_dir_all_with_options(
&self,
path: impl AsRef<Path>,
options: RemoveOptions,
) -> Result<(), VfError> { ... }
fn remove_dir_contents(&self, path: impl AsRef<Path>) -> Result<(), VfError> { ... }
fn remove_dir_contents_with_options(
&self,
path: impl AsRef<Path>,
options: RemoveOptions,
) -> Result<(), VfError> { ... }
}Expand description
Scalar operations and convenience workflows alongside the Vfsi vectors.
Blanket-implemented for every filesystem implementing Vfsi. Import VfsiExt (or
crate::api::prelude) to use these helpers; generic code needs only an
Vfsi bound. Helpers preserve batching, resource limits, and non-atomic
failure semantics. All helpers compose vectorized Vfsi primitives; native execution belongs in Vfsi.
Single-target helpers use conventional names such as open, attrs,
and read_dir. Prefer vector APIs for independent work on many files or
directories so the backend can batch requests.
§Method groups
- Open and close:
open,create. - Read files:
read_files,read_files_with_options. - Write files:
write,write_files. - Attrs:
attrs,attrs_with_options. - Collect directories:
read_dir,read_dir_with_options. - Visit directories:
listdir,visit_dirs_ordered. - Create, move, copy, and remove:
create_dir,create_dir_all.
§Boundary
| Contract | Responsibility | Examples |
|---|---|---|
Vfsi | Native vector execution, paging, and policy inspection | vopen, vread, vlistdirs, limits |
VfsiExt | Scalar adapters and composed workflows | open, read_files, create_dir_all |
Implement only Vfsi; this extension is blanket implemented. A helper belongs
here only when it can compose Vfsi primitives without losing native batching,
bounded paging, or recovery semantics. Singular convenience is not a promise
of one RPC, and vector execution is not a promise of atomicity.
Provided Methods§
Sourcefn open_options(&self) -> OpenOptions<'_, Self>
fn open_options(&self) -> OpenOptions<'_, Self>
Build reusable open options for this client.
Sourcefn statfs<P>(&self, target: P) -> Result<FilesystemStats, VfError>
fn statfs<P>(&self, target: P) -> Result<FilesystemStats, VfError>
Query one target through the vector filesystem-statistics engine.
Sourcefn open(&self, path: impl AsRef<Path>) -> Result<Self::File, VfError>
fn open(&self, path: impl AsRef<Path>) -> Result<Self::File, VfError>
Single-target convenience. For multiple files, prefer Vfsi::vopen to expose batching opportunities.
Open read-only. Paths are relative to this client’s configured namespace.
Use open_with for write/create flags, or
vopen to batch many opens. The returned handle owns
lifecycle only; use vectors or std_io for I/O.
use vfsi_core::api::{Vfsi, VfsiExt, FileHandle, WriteOp};
let file = fs.open("/config")?;
let mut header = [0_u8; 128];
let result = fs.vread([vfsi_core::api::ReadOp::into(&file, 0, &mut header)], Default::default());
let close = file.close();
let bytes = result?[0].bytes_read();
close?;
println!("read {bytes} bytes");Sourcefn create(&self, path: impl AsRef<Path>) -> Result<Self::File, VfError>
fn create(&self, path: impl AsRef<Path>) -> Result<Self::File, VfError>
Single-target convenience. For multiple creations, prefer Vfsi::vopen with CREATE/TRUNCATE flags.
Create or truncate a file and open for writing; does not create parents.
Existing contents are discarded immediately. For exclusive creation,
use open_with with WRITE | CREATE_NEW instead.
use vfsi_core::api::{Vfsi, VfsiExt, FileHandle, WriteOp};
let file = fs.create("/output")?;
let result = fs.vwrite(&[WriteOp::at(&file, 0, b"complete contents")], vfsi_core::api::WriteOptions::new().with_write_all(true));
let close = file.close();
result?;
close?;Sourcefn open_with(&self, request: OpenOp<'_>) -> Result<Self::File, VfError>
fn open_with(&self, request: OpenOp<'_>) -> Result<Self::File, VfError>
Single-target convenience. For multiple requests, prefer Vfsi::vopen with per-file flags and modes.
Open with an explicit access/create/truncate request; effects are eager.
Creation/truncation occurs at open, not on the first write. CREATE_NEW
rejects an existing path. This does not create missing parents.
Delegates to singleton Vfsi::vopen. Backends must preserve scalar final-
symlink resolution and independently opened handles for singleton vectors.
use vfsi_core::api::{Vfsi, VfsiExt, FileHandle, OpenFlags, OpenOp, WriteOp};
let file = fs.open_with(OpenOp::new(
"/new-file", OpenFlags::WRITE | OpenFlags::CREATE_NEW,
).mode(0o600))?;
file.close()?;Sourcefn close_files(&self, files: Vec<Self::File>) -> Result<(), VfError>
fn close_files(&self, files: Vec<Self::File>) -> Result<(), VfError>
Consume all handles. Errors cannot return cleanup ownership; Drop is
best-effort. Prefer vclose when close errors require reconciliation.
This releases all local handles even on failure; it does not promise every remote CLOSE succeeded. Closing alone is not a durability barrier.
use vfsi_core::api::{Vfsi, VfsiExt, OpenFlags, OpenOp, WriteOp};
let files = fs.vopen(&[OpenOp::new("/config", OpenFlags::READ)])?;
fs.close_files(files)?; // Observe a close error instead of discarding it in Drop.Sourcefn read(&self, path: impl AsRef<Path>) -> Result<Vec<u8>, VfError>
fn read(&self, path: impl AsRef<Path>) -> Result<Vec<u8>, VfError>
Read one complete file within the client’s aggregate read budget.
For multiple files, prefer Self::read_files. This is a convenience
over the vector read operation and retains its allocation limits.
Sourcefn read_with_options(
&self,
path: impl AsRef<Path>,
options: ReadOptions,
) -> Result<Vec<u8>, VfError>
fn read_with_options( &self, path: impl AsRef<Path>, options: ReadOptions, ) -> Result<Vec<u8>, VfError>
Read one complete file with an explicit read policy.
Sourcefn read_files<P>(&self, paths: &[P]) -> Result<Vec<Vec<u8>>, VfError>
fn read_files<P>(&self, paths: &[P]) -> Result<Vec<Vec<u8>>, VfError>
Read complete files in input order using vectorized whole-file reads.
The aggregate payload is bounded by limits().max_read_bytes().
Use Self::read_files_with_options to override it, or stream large files.
A failure returns an error, not a successful partial collection.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
let contents = fs.read_files(&["/file-1", "/file-2"])?;
for bytes in contents { println!("{} bytes", bytes.len()); }Sourcefn read_files_with_options<P>(
&self,
paths: &[P],
options: ReadOptions,
) -> Result<Vec<Vec<u8>>, VfError>
fn read_files_with_options<P>( &self, paths: &[P], options: ReadOptions, ) -> Result<Vec<Vec<u8>>, VfError>
Whole-file convenience reads with an explicit aggregate payload budget.
use vfsi_core::api::{Vfsi, VfsiExt, ReadOptions, WriteOp};
let files = fs.read_files_with_options(&["/config"],
ReadOptions::new().with_max_total_bytes(std::num::NonZeroUsize::new(1024 * 1024).unwrap()))?;Sourcefn read_to_string(&self, path: impl AsRef<Path>) -> Result<String, VfError>
fn read_to_string(&self, path: impl AsRef<Path>) -> Result<String, VfError>
Single-target convenience. For multiple files, prefer Vfsi::vread with whole-file operations and decode each result as UTF-8.
Read a complete UTF-8 file within this client’s aggregate read budget.
Invalid UTF-8 is an invalid-input error; use read_files for arbitrary bytes.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
let text = fs.read_to_string("/config")?;
println!("{text}");Sourcefn read_to_string_with_options(
&self,
path: impl AsRef<Path>,
options: ReadOptions,
) -> Result<String, VfError>
fn read_to_string_with_options( &self, path: impl AsRef<Path>, options: ReadOptions, ) -> Result<String, VfError>
Single-target convenience. For multiple files, prefer Vfsi::vread with an aggregate byte budget, then decode UTF-8.
Read a complete UTF-8 file with the same budget policy as Vfsi::vread.
ReadOptions::default() inherits the client limit; explicit overrides are nonzero.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
let text = fs.read_to_string_with_options("/config", vfsi_core::api::ReadOptions::new()
.with_max_total_bytes(std::num::NonZeroUsize::new(4096).unwrap()))?;
println!("{text}");Sourcefn read_stream(
&self,
path: impl AsRef<Path>,
callback: impl FnMut(u64, &[u8]) -> Result<ControlFlow<()>, VfError>,
) -> Result<StreamCompletion, VfError>
fn read_stream( &self, path: impl AsRef<Path>, callback: impl FnMut(u64, &[u8]) -> Result<ControlFlow<()>, VfError>, ) -> Result<StreamCompletion, VfError>
Single-target convenience. For multiple files, prefer Vfsi::vstream. Backends may process streams sequentially.
Stream a file using the client’s bounded chunk size instead of collecting it.
Return Ok(ControlFlow::Break(())) to stop successfully; the callback runs outside the lock.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.read_stream("/large", |offset, bytes| {
println!("{} bytes at {offset}", bytes.len());
Ok(std::ops::ControlFlow::Continue(()))
})?;Sourcefn read_stream_with_options(
&self,
path: impl AsRef<Path>,
options: StreamOptions,
callback: impl FnMut(u64, &[u8]) -> Result<ControlFlow<()>, VfError>,
) -> Result<StreamCompletion, VfError>
fn read_stream_with_options( &self, path: impl AsRef<Path>, options: StreamOptions, callback: impl FnMut(u64, &[u8]) -> Result<ControlFlow<()>, VfError>, ) -> Result<StreamCompletion, VfError>
Single-target convenience. For multiple files, prefer Vfsi::vstream. Backends may process streams sequentially.
Stream from offset zero outside the backend lock. ControlFlow::Break(()) stops after
the delivered chunk; completion reports the next offset. Not a snapshot.
The callback borrows each chunk only for its invocation. Consume it
without collecting chunks to keep memory bounded. chunk_size is a
maximum; negotiated protocol limits and short reads can produce smaller
chunks. The internally opened file is closed on completion, stopping,
callback error, or read failure. Stopping successfully does not mean EOF.
This simple stream does not promise RTT-hiding parallelism; direct NFS
applications can use NfsBuilder::connect_read_pool for pipelined reads.
use vfsi_core::api::{Vfsi, VfsiExt, StreamOptions, StreamCompletion, WriteOp};
let mut processed = 0_u64;
let completion = fs.read_stream_with_options(
"/large.bin", StreamOptions::new().with_chunk_size(std::num::NonZeroUsize::new(1024 * 1024).unwrap()),
|_offset, chunk| {
processed += chunk.len() as u64; // Process the borrowed bytes here.
Ok(if processed < 8 * 1024 * 1024 {
std::ops::ControlFlow::Continue(())
} else {
std::ops::ControlFlow::Break(())
}) // Stop after a bounded sample.
},
)?;
match completion {
StreamCompletion::Complete => println!("reached EOF after {processed} bytes"),
StreamCompletion::Stopped { next_offset } => println!("stopped at {next_offset}"),
}Sourcefn write(&self, path: impl AsRef<Path>, data: &[u8]) -> Result<(), VfError>
fn write(&self, path: impl AsRef<Path>, data: &[u8]) -> Result<(), VfError>
Single-target convenience. For multiple complete files, prefer VfsiExt::write_files; for opened handles, prefer Vfsi::vwrite.
Replace a file completely, creating/truncating eagerly; not atomic replace.
The parent must exist. Success writes all bytes and closes the internal handle; failure may leave a created, truncated, or partially written file. For exclusive creation or durability control use an explicit open handle.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.write("/output", b"replacement contents")?;Sourcefn write_files<P, B>(&self, entries: &[(P, B)]) -> Result<(), VfError>
fn write_files<P, B>(&self, entries: &[(P, B)]) -> Result<(), VfError>
Replace files in vector phases. Success completes payloads; errors may follow create/truncate/write effects and never authorize blind replay.
Parents must exist. Payloads are completed via vector open/write/close phases, not a scalar write loop or necessarily a single RPC. No atomic replacement, cross-file transaction, or durability guarantee is provided.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.write_files(&[
("/file-1", b"hello".as_slice()),
("/file-2", b"world".as_slice()),
])?;Sourcefn std_io<'a>(&'a self, file: &'a Self::File) -> impl Read + Write + Seek + 'a
fn std_io<'a>(&'a self, file: &'a Self::File) -> impl Read + Write + Seek + 'a
Borrow a standard-I/O adapter with an independent cursor, initially zero. Reads/writes use this client’s vectors; collecting reads enforce its payload budget. The adapter does not own or close the file.
Sourcefn sync_data(&self, file: &Self::File) -> Result<(), VfError>
fn sync_data(&self, file: &Self::File) -> Result<(), VfError>
Synchronize one retained handle through Vfsi::vfsync.
Sourcefn sync_all(&self, file: &Self::File) -> Result<(), VfError>
fn sync_all(&self, file: &Self::File) -> Result<(), VfError>
Synchronize one retained handle’s data and metadata through Vfsi::vfsync.
Sourcefn attrs<T>(&self, path: T) -> Result<Attrs, VfError>
fn attrs<T>(&self, path: T) -> Result<Attrs, VfError>
Single-target convenience. For multiple paths, prefer Vfsi::vgetattrs.
Query a path following its final symlink; unavailable fields remain None.
To inspect the symlink itself use symlink_attrs.
To query an opened object after rename, pass crate::api::Target::file.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
let attrs = fs.attrs("/file-1")?;
println!("{:?} bytes; directory={}", attrs.len(), attrs.is_dir());Sourcefn attrs_with_options<T>(
&self,
path: T,
options: AttrsOptions,
) -> Result<Attrs, VfError>
fn attrs_with_options<T>( &self, path: T, options: AttrsOptions, ) -> Result<Attrs, VfError>
Single-target convenience. For multiple paths, prefer Vfsi::vgetattrs with selected fields and follow_final_symlink(false).
Query one path with selected fields and final-symlink behavior; absent fields remain None.
This avoids requesting every optional attribute. Type/size can be
requested internally even when not selected; missing optional attributes
must still be handled via their Option accessors.
use vfsi_core::api::{Vfsi, VfsiExt, Attributes, WriteOp};
let attrs = fs.attrs_with_options(
"/file-1", vfsi_core::api::AttrsOptions::new()
.with_fields(Attributes::MODE | Attributes::BLOCKS).with_follow_final_symlink(false),
)?;
if let Some(blocks) = attrs.blocks() {
println!("allocated blocks: {blocks}");
}Sourcefn symlink_attrs(&self, path: impl AsRef<Path>) -> Result<Attrs, VfError>
fn symlink_attrs(&self, path: impl AsRef<Path>) -> Result<Attrs, VfError>
Single-target convenience. For multiple paths, prefer Vfsi::vgetattrs with follow_final_symlink(false).
Query the final symlink itself instead of following it.
This does not prevent following symlinks in ancestor components and is not a race-free namespace confinement primitive.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
let attrs = fs.symlink_attrs("/link-or-file")?;
println!("symlink={}", attrs.is_symlink());Sourcefn read_dir(&self, path: impl AsRef<Path>) -> Result<Vec<DirEntry>, VfError>
fn read_dir(&self, path: impl AsRef<Path>) -> Result<Vec<DirEntry>, VfError>
Single-target convenience. For multiple directories, prefer VfsiExt::read_dirs_with_options or VfsiExt::read_dirs.
Collect one directory using the client’s entry and path-byte limits.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
for entry in fs.read_dir("/input")? {
println!("{}", entry.path().display());
}Sourcefn read_dir_with_options(
&self,
path: impl AsRef<Path>,
options: ListDirOptions,
) -> Result<Vec<DirEntry>, VfError>
fn read_dir_with_options( &self, path: impl AsRef<Path>, options: ListDirOptions, ) -> Result<Vec<DirEntry>, VfError>
Single-target convenience. For multiple directories, prefer VfsiExt::read_dirs_with_options with one aggregate budget.
Collect one shallow directory with selected metadata and entry/path-byte limits.
Recursive options are rejected; use read_dirs_with_options with
ListDirOptions::with_recursive(true) to collect a tree.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
let entries = fs.read_dir_with_options("/input",
vfsi_core::api::ListDirOptions::new().with_max_entries(100))?;
println!("{} entries", entries.len());Sourcefn read_dirs<P>(&self, paths: &[P]) -> Result<Vec<DirectoryListing>, VfError>
fn read_dirs<P>(&self, paths: &[P]) -> Result<Vec<DirectoryListing>, VfError>
Collect directory listings under one aggregate entry/path-byte policy.
There is one listing per input directory, in input order; entry order is
backend-defined. Entries include metadata, avoiding a separate scalar
stat per child. The default policy comes from this client’s limits.
Use read_dirs_with_options to select
attributes, or a visitor instead of collecting large listings.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
for listing in fs.read_dirs(&["/input", "/output"])? {
for entry in listing.entries {
println!("{}: {:?} bytes", entry.path().display(), entry.attrs().len());
}
}Sourcefn read_dirs_with_options<P>(
&self,
paths: &[P],
options: ListDirOptions,
) -> Result<Vec<Vec<DirectoryListing>>, VfError>
fn read_dirs_with_options<P>( &self, paths: &[P], options: ListDirOptions, ) -> Result<Vec<Vec<DirectoryListing>>, VfError>
Collect shallow directories or recursive trees, grouped by input root.
results[i] contains the listings for paths[i]. Shallow mode
returns exactly one listing per root; recursive mode includes the root
and descendants. Entries and path-byte budgets are shared across roots;
recursive collection also charges retained directory paths.
Collection builds on the batched directory-page visitor.
Explicit limits override client defaults. Errors discard collected results;
this is not a snapshot. Symlink entries are not recursively followed.
use vfsi_core::api::{Vfsi, VfsiExt, Attributes, ListDirOptions};
let trees = fs.read_dirs_with_options(&["/input", "/output"],
ListDirOptions::new().with_recursive(true).with_fields(Attributes::MODE)
.with_max_entries(10_000).with_max_path_bytes(1024 * 1024))?;
for tree in trees {
for listing in tree {
println!("{}: {} entries", listing.path.display(), listing.entries.len());
}
}Sourcefn listdir(
&self,
root: impl AsRef<Path>,
options: impl Into<WalkOptions>,
visitor: impl FnMut(&WalkEvent) -> Result<WalkControl, VfError>,
) -> Result<TraversalCompletion, VfError>
fn listdir( &self, root: impl AsRef<Path>, options: impl Into<WalkOptions>, visitor: impl FnMut(&WalkEvent) -> Result<WalkControl, VfError>, ) -> Result<TraversalCompletion, VfError>
List one directory through callbacks, optionally recursively.
For independent roots and owned pages, prefer Vfsi::vlistdirs.
By default, only child Entry events are delivered, with no extra root
attribute request or full-listing allocation on paging backends. Set
recursive(true) to descend without following entry symlinks. Entry-only
traversal retains native anchored child cursors and sibling batching;
its order is backend-defined.
enter_leave(true) includes the root and emits depth-first Enter and
Leave events for traversed directories, including pruned directories.
In shallow lifecycle mode, children are Entry events. Symlinks are
always Entry events. A non-directory lifecycle root produces one Entry.
Lifecycle traversal currently retains bounded directory buffers because
the vector page primitive does not expose resumable cursors.
sort_by_name(true) also buffers a bounded directory before sorting.
Unsorted entry-only visiting remains paged. This is not a snapshot.
Buffered recursive/lifecycle visiting rejects symlinks in reopened
directory paths, including ancestors. Backends unable to guarantee that
return Unsupported instead of checking and then following the path.
Ordinary shallow listing retains the backend’s path resolution; use
allow_symlink_components(false) to require no-follow directory opens explicitly.
The root is depth zero and its children have depth one. Directory depth limits control descent; shallow mode ignores them. Lifecycle mode charges the root against the entry/path budgets; recursive entry-only mode charges retained directory paths. All unspecified budgets inherit client limits.
SkipSubtree on Enter prevents reading that directory’s children;
it does nothing on files or Leave. Pruning a recursive directory Entry
without lifecycle events is rejected: enable enter_leave(true).
Stop returns Stopped immediately,
without synthesizing pending Leave events. Callback errors propagate
without replay. Callbacks run outside backend locks and may reenter.
use vfsi_core::api::{ListDirOptions, Vfsi, VfsiExt, WalkControl};
fs.listdir("/input", ListDirOptions::new(), |event| {
println!("{}", event.entry.path().display());
Ok(WalkControl::Continue)
})?;Recursive lifecycle events allow pruning before listing children:
use vfsi_core::api::{ListDirOptions, Vfsi, VfsiExt, WalkControl, WalkEventKind};
fs.listdir("/project",
vfsi_core::api::WalkOptions::new(ListDirOptions::new().with_recursive(true))
.with_enter_leave(true).with_sort_by_name(true),
|event| {
if event.kind == WalkEventKind::Enter
&& event.entry.file_name() == Some(std::ffi::OsStr::new(".git")) {
return Ok(WalkControl::SkipSubtree);
}
println!("{:?}: {}", event.kind, event.entry.path().display());
Ok(WalkControl::Continue)
})?;Sourcefn visit_entries_with_options<P>(
&self,
paths: &[P],
options: ListDirOptions,
callback: impl FnMut(usize, &DirEntry) -> Result<ControlFlow<()>, VfError>,
) -> Result<Vec<TraversalCompletion>, VfError>
fn visit_entries_with_options<P>( &self, paths: &[P], options: ListDirOptions, callback: impl FnMut(usize, &DirEntry) -> Result<ControlFlow<()>, VfError>, ) -> Result<Vec<TraversalCompletion>, VfError>
Visit individual entries using the directory-page primitive. Empty directories produce pages but no entry callbacks.
Sourcefn visit_dirs_ordered(
&self,
root: impl AsRef<Path>,
options: ListDirOptions,
order: impl FnMut(&DirEntry, &DirEntry) -> Ordering,
descend: impl FnMut(&DirEntry) -> bool,
visitor: impl FnMut(DirectoryListing, usize) -> Result<WalkControl, VfError>,
) -> Result<TraversalCompletion, VfError>
fn visit_dirs_ordered( &self, root: impl AsRef<Path>, options: ListDirOptions, order: impl FnMut(&DirEntry, &DirEntry) -> Ordering, descend: impl FnMut(&DirEntry) -> bool, visitor: impl FnMut(DirectoryListing, usize) -> Result<WalkControl, VfError>, ) -> Result<TraversalCompletion, VfError>
Visit complete shallow listings in depth-first order with application policy.
order compares immutable siblings (for example, locale-aware ls ordering).
The shared workflow sorts them; callbacks cannot replace validated entries.
descend selects directories before their contents are read; it does not
filter entries delivered in their parent’s listing. Symlinks are never
traversed. Descendant opens reject symlinks in every component; backends
unable to guarantee that return Unsupported. The root uses the supplied
path-resolution policy. visitor runs outside backend locks and may stop immediately
or skip all children of the current directory. Errors after delivered
listings must not trigger replay through another backend.
Storage is bounded by one complete listing and the pending directory
frontier. Entry/path budgets charge all fetched children, including those
rejected by descend. This ordered workflow deliberately does not
speculatively list children before admission; use vlistdirs to batch
already-approved independent directories.
use vfsi_core::api::{Attributes, Result, Vfsi, VfsiExt, WalkControl};
fs.visit_dirs_ordered("/input",
fs.limits().walk_options().with_fields(Attributes::MODE | Attributes::SIZE),
|a, b| a.path().cmp(b.path()),
|entry| entry.file_name() != Some(std::ffi::OsStr::new(".git")),
|listing, depth| {
println!("{}: {} entries at depth {depth}", listing.path.display(), listing.entries.len());
Ok(WalkControl::Continue)
})?;Sourcefn create_dir(&self, path: impl AsRef<Path>) -> Result<(), VfError>
fn create_dir(&self, path: impl AsRef<Path>) -> Result<(), VfError>
Single-target convenience. For multiple independent directories, prefer Vfsi::vmkdir.
Create one directory; its parent must exist.
An existing entry is an error, even if already a directory. Use
create_dir_all for missing parents/idempotent
directory setup, or vmkdir for independent siblings.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.create_dir("/fresh-directory")?;Sourcefn truncate<T>(&self, target: T, len: u64) -> Result<(), VfError>
fn truncate<T>(&self, target: T, len: u64) -> Result<(), VfError>
Truncate or extend one path or opened object using Vfsi::vsetattrs.
Sourcefn chmod<T>(&self, target: T, permissions: Permissions) -> Result<(), VfError>
fn chmod<T>(&self, target: T, permissions: Permissions) -> Result<(), VfError>
Change permissions on one path or opened object using Vfsi::vsetattrs.
Sourcefn chown<T>(
&self,
target: T,
uid: Option<u32>,
gid: Option<u32>,
) -> Result<(), VfError>
fn chown<T>( &self, target: T, uid: Option<u32>, gid: Option<u32>, ) -> Result<(), VfError>
Change ownership of one path or opened object through Vfsi::vsetattrs.
None leaves the corresponding owner/group unchanged. Use the vector
with SetAttrsOp::with_follow_final_symlink(false)
to change a symlink itself.
Sourcefn create_dir_with_mode(
&self,
path: impl AsRef<Path>,
mode: u32,
) -> Result<(), VfError>
fn create_dir_with_mode( &self, path: impl AsRef<Path>, mode: u32, ) -> Result<(), VfError>
Create one directory with explicit Unix permission bits.
Sourcefn symlink(
&self,
target: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<(), VfError>
fn symlink( &self, target: impl AsRef<Path>, link: impl AsRef<Path>, ) -> Result<(), VfError>
Create one symbolic link; submit multiple pairs with Vfsi::vsymlink.
Sourcefn read_link(&self, path: impl AsRef<Path>) -> Result<PathBuf, VfError>
fn read_link(&self, path: impl AsRef<Path>) -> Result<PathBuf, VfError>
Read one symlink target; submit multiple paths with Vfsi::vreadlink.
Sourcefn hard_link(
&self,
source: impl AsRef<Path>,
link: impl AsRef<Path>,
) -> Result<(), VfError>
fn hard_link( &self, source: impl AsRef<Path>, link: impl AsRef<Path>, ) -> Result<(), VfError>
Create one hard link; submit multiple pairs with Vfsi::vhardlink.
Sourcefn create_dir_all(&self, path: impl AsRef<Path>) -> Result<(), VfError>
fn create_dir_all(&self, path: impl AsRef<Path>) -> Result<(), VfError>
Single-target convenience. For multiple directory creations, prefer Vfsi::vmkdir; plan missing parents before their children.
Create missing parents; an error can leave some directories created.
Existing directories are accepted; an existing non-directory component is an error. This is not atomic and is not protected against concurrent changes to ancestor paths.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.create_dir_all("/workspace/results/2026")?;Sourcefn rename(
&self,
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
) -> Result<(), VfError>
fn rename( &self, source: impl AsRef<Path>, destination: impl AsRef<Path>, ) -> Result<(), VfError>
Single-target convenience. For multiple source/destination pairs, prefer Vfsi::vrename.
Rename within supported namespaces; cross-filesystem moves can fail.
Both paths use this client’s namespace. Replacement semantics follow the backend/filesystem; this is not a cross-file vector transaction or a guarantee of durable directory updates. No copy fallback is implied.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.rename("/old-name", "/new-name")?;Sourcefn copy(
&self,
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
) -> Result<(), VfError>
fn copy( &self, source: impl AsRef<Path>, destination: impl AsRef<Path>, ) -> Result<(), VfError>
Single-target convenience. For multiple file pairs, prefer Vfsi::vcopy.
Copy a file’s contents; this is not recursive tree copying.
Destination creation/replacement and failures follow backend semantics. A failure can leave a partial destination. Do not assume metadata, sparse layout, or durability is preserved. Server-side copy is used only where supported; callers need not build protocol COPY requests.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.copy("/source", "/destination")?;Sourcefn copy_with_options(
&self,
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
options: CopyOptions,
) -> Result<(), VfError>
fn copy_with_options( &self, source: impl AsRef<Path>, destination: impl AsRef<Path>, options: CopyOptions, ) -> Result<(), VfError>
Single-target copy with explicit operation semantics; prefer Vfsi::vcopy
when submitting multiple pairs.
Sourcefn remove_file(&self, path: impl AsRef<Path>) -> Result<(), VfError>
fn remove_file(&self, path: impl AsRef<Path>) -> Result<(), VfError>
Single-target convenience. For multiple paths, prefer Vfsi::vremove. That vector API accepts both files and directories.
Remove one file or symlink, not the symlink target.
Missing paths are errors. To remove a directory use
remove_dir or remove_dir_all.
use vfsi_core::api::{Vfsi, VfsiExt, ErrorKind, WriteOp};
match fs.remove_file("/temporary-file") {
Ok(()) => (),
Err(error) if error.kind() == ErrorKind::NotFound => (),
Err(error) => return Err(error),
}Sourcefn remove_dir(&self, path: impl AsRef<Path>) -> Result<(), VfError>
fn remove_dir(&self, path: impl AsRef<Path>) -> Result<(), VfError>
Single-target convenience. For multiple paths, prefer Vfsi::vremove. That vector API does not enforce directory-only inputs.
Remove one empty directory; not a recursive operation.
Nonempty directories fail. Use remove_dir_contents
to empty a directory while retaining it, or remove_dir_all
to remove its tree. Only operate on paths whose removal you intend.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.remove_dir("/empty-temporary-directory")?;Sourcefn remove_dir_all(&self, path: impl AsRef<Path>) -> Result<(), VfError>
fn remove_dir_all(&self, path: impl AsRef<Path>) -> Result<(), VfError>
Single-target convenience. For multiple trees, prefer Vfsi::vremove with RemoveMode::Tree.
Recursively remove a tree without following directory symlinks. Path-based removal is not a security sandbox or an atomic transaction.
A failure can leave a partly removed tree. Use trusted ancestor paths; concurrent namespace substitutions are not a confinement guarantee. This is destructive: do not use it to prepare an arbitrary existing directory for an example or benchmark.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
// Remove only the tree that this application intentionally owns.
fs.remove_dir_all("/owned-temporary-tree")?;Sourcefn remove_dir_all_with_options(
&self,
path: impl AsRef<Path>,
options: RemoveOptions,
) -> Result<(), VfError>
fn remove_dir_all_with_options( &self, path: impl AsRef<Path>, options: RemoveOptions, ) -> Result<(), VfError>
Recursively remove one directory using explicit batching and failure
policy. The directory is validated before mutation; symlink roots are
not followed. Prefer Vfsi::vremove when removing several trees.
Sourcefn remove_dir_contents(&self, path: impl AsRef<Path>) -> Result<(), VfError>
fn remove_dir_contents(&self, path: impl AsRef<Path>) -> Result<(), VfError>
Single-target convenience. For multiple directory roots, prefer Vfsi::vremove.
Recursively empty a directory while keeping its root.
The root must be a directory, not a symlink. Child symlinks are removed without following their targets. Errors can leave partially removed contents; retaining the root does not make the operation transactional. The path is resolved for this call, not pinned across calls or renames. Use trusted ancestors; this is not a path-confinement guarantee.
use vfsi_core::api::{Vfsi, VfsiExt, WriteOp};
fs.remove_dir_contents("/owned-scratch-directory")?;
// The scratch directory remains available for subsequent work.Sourcefn remove_dir_contents_with_options(
&self,
path: impl AsRef<Path>,
options: RemoveOptions,
) -> Result<(), VfError>
fn remove_dir_contents_with_options( &self, path: impl AsRef<Path>, options: RemoveOptions, ) -> Result<(), VfError>
Recursively empty one directory while retaining its root, using
explicit batching and failure policy. The root is validated without
following a symlink. Prefer Vfsi::vremove for several roots.
Like Self::remove_dir_contents, this resolves the current pathname;
it does not retain a previously opened directory’s identity.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".