Skip to main content
Read, write, list, and manipulate files inside a running sandbox. Obtained via sb.fs(). Every op dispatches through the same host-guest channel as command execution, so there is no SSH and no network involved. Path-style helpers are the usual choice; handle-style helpers are available for callers that need POSIX-like file descriptor reuse. For bulk file movement, prefer a volume that gives the guest direct filesystem access. See Filesystem for conceptual usage.

Typical flow

use microsandbox::Sandbox;

let sb = Sandbox::builder("api").image("python").create().await?;
let fs = sb.fs();

fs.write("/tmp/config.json", r#"{"debug": true}"#).await?;
let text = fs.read_to_string("/tmp/config.json").await?;
println!("{text}");

for entry in fs.list("/tmp").await? {
    println!("{} ({} bytes)", entry.path, entry.size);
}
sb.fs() is synchronous and just borrows the sandbox’s backend and name; the work happens on the awaited methods below, every one of which is async.

Read operations

fs.read()

async fn read(&self, path: &str) -> MicrosandboxResult<Bytes>
let bytes = sb.fs().read("/app/logo.png").await?;
println!("{} bytes", bytes.len());
Read an entire file from the guest filesystem into memory as raw bytes.

Parameters

path&str
Absolute path inside the guest, e.g. “/app/config.json”.

Returns

Bytes
File contents as raw bytes.

fs.read_to_string()

async fn read_to_string(&self, path: &str) -> MicrosandboxResult<String>
let text = sb.fs().read_to_string("/etc/hostname").await?;
println!("{}", text.trim());
Read an entire file and decode it as UTF-8. Errors if the contents are not valid UTF-8.

Parameters

path&str
Absolute path inside the guest.

Returns

String
File contents as a UTF-8 string.

fs.read_stream()

async fn read_stream(&self, path: &str) -> MicrosandboxResult<FsReadStream>
let mut stream = sb.fs().read_stream("/var/log/big.log").await?;
let mut total = 0;
while let Some(chunk) = stream.recv().await? {
    total += chunk.len();
}
println!("read {total} bytes");
Open a streaming reader that yields chunks of file data as they arrive. Use this for files too large to hold in memory, or to process data incrementally.

Parameters

path&str
Absolute path inside the guest.

Returns

Reader that yields chunks until the file is exhausted.

Write operations

fs.write()

async fn write(&self, path: &str, data: impl AsRef<[u8]>) -> MicrosandboxResult<()>
sb.fs().write("/tmp/hello.txt", "hi there").await?;
Write data to a file in the guest, creating it if it doesn’t exist and truncating it if it does. Parent directories must already exist.

Parameters

path&str
Absolute path inside the guest.
dataimpl AsRef<[u8]>
File content (bytes or a string).

fs.write_stream()

async fn write_stream(&self, path: &str) -> MicrosandboxResult<FsWriteSink>
let sink = sb.fs().write_stream("/tmp/out.bin").await?;
sink.write(&[0u8; 4096]).await?;
sink.write(&[1u8; 4096]).await?;
sink.close().await?;
Open a streaming writer for large files. Write chunks incrementally, then call FsWriteSink::close() to flush and finalize. The file is created if missing and truncated if it exists.

Parameters

path&str
Absolute path inside the guest.

Returns

Writer for sending chunks; must be closed to finalize.

Handle operations

Handle operations expose agentd-side file and directory handles. Use them when you need repeated reads/writes against the same open file, directory iteration state, or handle-based metadata updates. They require Sandbox::fs() on a live local sandbox because agentd scopes handles to the relay client; SandboxFsOps::with_backend() can run path-style methods but returns Unsupported for handle methods.
use microsandbox::sandbox::FsOpenOptions;

let fs = sb.fs();
let handle = fs.open_file("/tmp/data.txt", FsOpenOptions {
    read: true,
    write: true,
    create: true,
    ..Default::default()
}).await?;

fs.write_handle(handle, 0, "hello").await?;
let bytes = fs.read_handle(handle, 0, None).await?;
fs.close_handle(handle).await?;

fs.open_file()

async fn open_file(&self, path: &str, options: FsOpenOptions) -> MicrosandboxResult<FsHandle>
Open a file inside the guest and return an agentd-side handle. Configure read/write/create/truncate behavior with FsOpenOptions.

fs.open_dir()

async fn open_dir(&self, path: &str) -> MicrosandboxResult<FsHandle>
Open a directory inside the guest and return an agentd-side handle that can be consumed with read_dir_handle().

fs.close_handle()

async fn close_handle(&self, handle: FsHandle) -> MicrosandboxResult<()>
Close an open file or directory handle. Always close handles you opened directly once you are done with them.

fs.read_handle()

async fn read_handle(&self, handle: FsHandle, offset: u64, len: Option<u64>) -> MicrosandboxResult<Bytes>
Read from an open file handle at offset. Passing None for len reads through EOF.

fs.read_handle_stream()

async fn read_handle_stream(&self, handle: FsHandle, offset: u64, len: Option<u64>) -> MicrosandboxResult<FsReadStream>
Stream bytes from an open file handle. Use this for large reads while preserving the same open-handle semantics as read_handle().

fs.write_handle()

async fn write_handle(&self, handle: FsHandle, offset: u64, data: impl AsRef<[u8]>) -> MicrosandboxResult<()>
Write bytes to an open file handle at offset.

fs.write_handle_stream()

async fn write_handle_stream(&self, handle: FsHandle, offset: u64, len: Option<u64>) -> MicrosandboxResult<FsWriteSink>
Stream writes to an open file handle at offset. Call FsWriteSink::close() to send EOF and wait for the guest to confirm the write.

fs.read_dir_handle()

async fn read_dir_handle(&self, handle: FsHandle, limit: Option<u32>) -> MicrosandboxResult<Vec<FsEntry>>
Read the next batch of entries from an open directory handle. limit caps the batch size when set.

fs.read_dir()

async fn read_dir(&self, handle: FsHandle, limit: Option<u32>) -> MicrosandboxResult<Vec<FsEntry>>
Compatibility alias for read_dir_handle().

fs.stat_handle()

async fn stat_handle(&self, handle: FsHandle) -> MicrosandboxResult<FsMetadata>
Return metadata for an open file or directory handle.

fs.fstat()

async fn fstat(&self, handle: FsHandle) -> MicrosandboxResult<FsMetadata>
Unix-style compatibility alias for stat_handle().

fs.set_stat_handle()

async fn set_stat_handle(&self, handle: FsHandle, attrs: FsSetAttrs) -> MicrosandboxResult<()>
Update metadata for an open file handle. Only the fields set on FsSetAttrs are changed.

fs.fset_stat()

async fn fset_stat(&self, handle: FsHandle, attrs: FsSetAttrs) -> MicrosandboxResult<()>
Unix-style compatibility alias for set_stat_handle().

Directory operations

fs.list()

async fn list(&self, path: &str) -> MicrosandboxResult<Vec<FsEntry>>
for entry in sb.fs().list("/app").await? {
    println!("{:?} {}", entry.kind, entry.path);
}
List the immediate children of a directory (non-recursive). Each entry carries its path, kind, size, mode, and modification time.

Parameters

path&str
Absolute directory path inside the guest.

Returns

Directory entries.

fs.mkdir()

async fn mkdir(&self, path: &str) -> MicrosandboxResult<()>
sb.fs().mkdir("/app/data/cache").await?;
Create a directory, including any missing parent directories.

Parameters

path&str
Absolute directory path inside the guest.

fs.remove_dir()

async fn remove_dir(&self, path: &str) -> MicrosandboxResult<()>
sb.fs().remove_dir("/app/data/cache").await?;
Remove a directory and everything under it, recursively. For a single file use remove().

Parameters

path&str
Absolute directory path inside the guest.

fs.remove_empty_dir()

async fn remove_empty_dir(&self, path: &str) -> MicrosandboxResult<()>
sb.fs().remove_empty_dir("/app/data/empty").await?;
Remove an empty directory. Unlike remove_dir(), this does not remove child entries and fails when the directory is not empty.

Parameters

path&str
Absolute directory path inside the guest.

File operations

fs.remove()

async fn remove(&self, path: &str) -> MicrosandboxResult<()>
sb.fs().remove("/tmp/hello.txt").await?;
Delete a single file. Use remove_dir() for directories.

Parameters

path&str
Absolute file path inside the guest.

fs.copy()

async fn copy(&self, from: &str, to: &str) -> MicrosandboxResult<()>
sb.fs().copy("/app/config.json", "/app/config.bak.json").await?;
Copy a file from one path to another within the sandbox.

Parameters

from&str
Source path inside the guest.
to&str
Destination path inside the guest.

fs.rename()

async fn rename(&self, from: &str, to: &str) -> MicrosandboxResult<()>
sb.fs().rename("/tmp/draft.txt", "/tmp/final.txt").await?;
Rename or move a file or directory within the sandbox.

Parameters

from&str
Current path inside the guest.
to&str
New path inside the guest.

Metadata

fs.stat()

async fn stat(&self, path: &str) -> MicrosandboxResult<FsMetadata>
let meta = sb.fs().stat("/app/config.json").await?;
println!("{} bytes, mode {:o}", meta.size, meta.mode);
Get metadata for a file or directory: kind, size, mode, read-only flag, and timestamps. A final symlink is followed (equivalent to stat_with_follow(path, true)); use stat_with_follow() to control that.

Parameters

path&str
Absolute path inside the guest.

Returns

File metadata.

fs.stat_with_follow()

async fn stat_with_follow(&self, path: &str, follow_symlink: bool) -> MicrosandboxResult<FsMetadata>
let link_meta = sb.fs().stat_with_follow("/app/current", false).await?;
println!("{:?}", link_meta.kind);
Get metadata, choosing whether to follow a final symlink. With follow_symlink = false you stat the link itself rather than its target. Local backend only; cloud returns Unsupported.

Parameters

path&str
Absolute path inside the guest.
follow_symlinkbool
When false, stat the symlink itself instead of its target.

Returns

File metadata.

fs.set_stat()

async fn set_stat(&self, path: &str, follow_symlink: bool, attrs: FsSetAttrs) -> MicrosandboxResult<()>
use microsandbox::sandbox::FsSetAttrs;

sb.fs().set_stat("/app/run.sh", true, FsSetAttrs {
    mode: Some(0o755),
    ..Default::default()
}).await?;
Update metadata on a file or directory: mode, owner uid/gid, size, and access/modification times. Only the fields you set on FsSetAttrs are applied. Local backend only; cloud returns Unsupported.

Parameters

path&str
Absolute path inside the guest.
follow_symlinkbool
When false, target the symlink itself instead of its target.
Attributes to change; unset fields are left untouched.
async fn read_link(&self, path: &str) -> MicrosandboxResult<String>
let target = sb.fs().read_link("/app/current").await?;
println!("-> {target}");
Read the target of a symbolic link, returning the literal target text. Local backend only; cloud returns Unsupported.

Parameters

path&str
Absolute path of the symlink inside the guest.

Returns

String
The link’s target path.
async fn symlink(&self, target: &str, link_path: &str) -> MicrosandboxResult<()>
sb.fs().symlink("/app/releases/v2", "/app/current").await?;
Create a symbolic link at link_path that points to target. Local backend only; cloud returns Unsupported.

Parameters

target&str
What the link points to (literal target text).
link_path&str
Absolute path of the symlink to create.

fs.real_path()

async fn real_path(&self, path: &str) -> MicrosandboxResult<String>
let canonical = sb.fs().real_path("/app/../app/config.json").await?;
println!("{canonical}");
Resolve a path to its canonical absolute path inside the guest.

Parameters

path&str
Path inside the guest.

Returns

String
Canonical absolute path.

fs.exists()

async fn exists(&self, path: &str) -> MicrosandboxResult<bool>
if sb.fs().exists("/app/config.json").await? {
    println!("config present");
}
Check whether a file or directory exists at the given path in the guest. Implemented as a stat() probe: a successful stat yields true, a filesystem-op error yields false, and transport errors still propagate.

Parameters

path&str
Absolute path inside the guest.

Returns

bool
true if the path exists.

Host transfer

fs.copy_from_host()

async fn copy_from_host(&self, host_path: impl AsRef<Path>, guest_path: &str) -> MicrosandboxResult<()>
sb.fs().copy_from_host("./local/model.bin", "/app/model.bin").await?;
Copy a file from the host machine into the sandbox, streaming it in chunks. For transferring many files, consider a bind-mounted volume instead.

Parameters

host_pathimpl AsRef<Path>
Path on the host filesystem.
guest_path&str
Destination path inside the sandbox.

fs.copy_to_host()

async fn copy_to_host(&self, guest_path: &str, host_path: impl AsRef<Path>) -> MicrosandboxResult<()>
sb.fs().copy_to_host("/app/out/report.pdf", "./report.pdf").await?;
Copy a file from the sandbox to the host machine.

Parameters

guest_path&str
Path inside the sandbox.
host_pathimpl AsRef<Path>
Destination path on the host.

Types

SandboxFsOps

Returned by sb.fs()

Filesystem operations handle for a running sandbox, borrowing the parent sandbox’s backend and name (it is generic over a lifetime, SandboxFsOps<'a>). Every method dispatches through the same host-guest channel as command execution. Local routes to core.fs.* agent messages; cloud returns Unsupported per method until cloud guest-fs lands. All operations are listed in the sections above. with_backend(backend, name) is a public constructor for FFI shims that re-assemble a SandboxFsOps per call; most callers obtain one via sb.fs().

FsEntry

Returned by list()

Metadata for a single entry returned from a directory listing.
FieldTypeDescription
pathStringPath of the entry
kindFsEntryKindKind of entry
sizeu64Size in bytes
modeu32Unix permission bits (e.g. 0o644)
uidu32Owner user ID
gidu32Owner group ID
accessedOption<DateTime<Utc>>Last access time
modifiedOption<DateTime<Utc>>Last modification time

FsEntryKind

Used by FsEntry.kind · FsMetadata.kind

The kind of a filesystem entry. Derives Copy, PartialEq, and Eq.
VariantDescription
FileRegular file
DirectoryDirectory
SymlinkSymbolic link
OtherOther entry type (device, socket, etc.)

FsMetadata

Returned by stat() · stat_with_follow()

Detailed metadata for a file or directory.
FieldTypeDescription
kindFsEntryKindKind of entry
sizeu64Size in bytes
modeu32Unix permission bits
uidu32Owner user ID
gidu32Owner group ID
readonlyboolWhether the entry is read-only (no owner write bit)
accessedOption<DateTime<Utc>>Last access time
modifiedOption<DateTime<Utc>>Last modification time
createdOption<DateTime<Utc>>Creation time (not populated by guest stat, currently always None)

FsOpenOptions

Used by open_file()

Options accepted by open_file(). Re-exported from microsandbox_protocol::fs. Derives Default, so set only the flags you need.
FieldTypeDescription
readboolOpen for reading
writeboolOpen for writing
appendboolAppend writes to the end
createboolCreate the file if it is missing
truncateboolTruncate the file after opening
create_newboolCreate a new file and fail if it already exists
modeOption<u32>Permission bits to set on creation

FsSetAttrs

Used by set_stat() · set_stat_handle() · fset_stat()

Attributes accepted by set_stat(). Re-exported from microsandbox_protocol::fs. Derives Default, so set only the fields you want to change and spread the rest with ..Default::default(). Each field is Option: None leaves that attribute unchanged.
FieldTypeDescription
modeOption<u32>Unix permission bits
uidOption<u32>Owner user ID
gidOption<u32>Owner group ID
sizeOption<u64>File size (truncate or extend)
atimeOption<i64>Access time as Unix timestamp seconds
mtimeOption<i64>Modification time as Unix timestamp seconds

FsReadStream

Returned by read_stream() · read_handle_stream()

Streaming reader for file data from the sandbox. Obtained via read_stream() or read_handle_stream().
MethodSignatureDescription
recv()recv(&mut self) -> MicrosandboxResult<Option<Bytes>>Receive the next chunk; None once the file is fully read. Errors if the guest reports a failure.
collect()collect(self) -> MicrosandboxResult<Bytes>Consume the stream and collect all remaining chunks into a single buffer.

FsWriteSink

Returned by write_stream() · write_handle_stream()

Streaming writer for file data to the sandbox. Obtained via write_stream() or write_handle_stream().
MethodSignatureDescription
write()write(&self, data: impl AsRef<[u8]>) -> MicrosandboxResult<()>Write a chunk of data.
close()close(self) -> MicrosandboxResult<()>Send EOF and wait for confirmation. Must be called to finalize the write; errors if the guest reports a write failure.

FsHandle

Returned by open_file() · open_dir()

Type alias for an agentd-side filesystem handle. Handles are valid only for the live relay client that opened them; close directly opened handles with close_handle().
pub type FsHandle = u64;