Expand description
Asynchronous 9P2000.L filesystem server library for Rust.
This crate provides a tokio-based async implementation of the 9P2000.L protocol, allowing you to build virtual filesystem servers that can be mounted using the Linux kernel’s v9fs module.
§Overview
The 9P protocol was originally developed for the Plan 9 distributed operating system. 9P2000.L is an extended variant that adds Linux-specific features like proper permission handling, symbolic links, and other POSIX semantics.
§Getting Started
To create a 9P filesystem server, you need to:
- Define a type to represent your per-fid state (or use
()for stateless fids) - Implement the
srv::Filesystemtrait for your filesystem type - Start the server with
srv::srv_asyncor related functions
§Example
use rs9p::{srv::{Filesystem, FId, srv_async}, Result, FCall};
use async_trait::async_trait;
// Define your filesystem
#[derive(Clone)]
struct MyFs;
// Define per-fid state (or use () if you don't need state)
#[derive(Default)]
struct MyFId {
// Your per-fid data here
}
#[async_trait]
impl Filesystem for MyFs {
type FId = MyFId;
async fn rattach(
&self,
fid: &FId<Self::FId>,
_afid: Option<&FId<Self::FId>>,
_uname: &str,
_aname: &str,
_n_uname: u32,
) -> Result<FCall> {
// Initialize the root fid and return its qid
Ok(FCall::RAttach {
qid: rs9p::QId {
typ: rs9p::QIdType::DIR,
version: 0,
path: 0,
}
})
}
// Implement other required methods...
}
#[tokio::main]
async fn main() -> Result<()> {
let fs = MyFs;
srv_async(fs, "tcp!127.0.0.1!564").await
}§Protocol Details
§Message Flow
- Version Negotiation: Client sends
TVersion, server responds withRVersion - Authentication (optional):
TAuth/RAuthexchange - Attach: Client attaches to the filesystem root with
TAttach - Operations: Client performs file operations (
walk,open,read,write, etc.) - Cleanup: Client clunks fids with
TClunkto release resources
§FId Management
A “fid” (file identifier) is a 32-bit handle used by the client to reference a file or directory. The server must track the mapping between fids and filesystem objects.
Important invariants:
- Each fid is unique per connection
- FIds persist across operations until explicitly clunked
- Walking to a new fid creates a new fid (the old one remains valid)
- After
TClunk, the fid is invalid and will be removed
§Error Handling
Return errors using the error::Error type. The server will automatically
convert these to RlError messages with appropriate error codes (errno).
Common error codes:
ENOENT- File not foundEACCES/EPERM- Permission deniedEISDIR- Is a directory (when file expected)ENOTDIR- Not a directory (when directory expected)EBADF- Bad file descriptor (invalid fid)ELOOP- Too many levels of symbolic links
§Transport
The library supports multiple transports:
- TCP:
"tcp!host!port"(e.g.,"tcp!0.0.0.0!564") - Unix Domain Sockets:
"unix!path!suffix"(e.g.,"unix!/tmp/socket!0")
§Feature Flags
This crate uses workspace dependencies and requires:
tokiowithfullfeatures for async runtimeasync-traitfor trait async methods
§Safety
This crate forbids unsafe code (#![forbid(unsafe_code)]) and relies on Rust’s
type system for memory safety. All filesystem operations are async and designed
to be cancellation-safe.
Re-exports§
pub use crate::error::Error;pub use crate::error::errno;pub use crate::error::string as errstr;pub use crate::utils::Result;pub use crate::fcall::*;
Modules§
- error
- 9P error representations.
- fcall
- 9P protocol data types and constants.
- serialize
- Serialize/deserialize 9P messages into/from binary.
- srv
- Asynchronous server side 9P library.
- utils