12 breaking releases
Uses new Rust 2024
| 0.13.0 | Oct 29, 2025 |
|---|---|
| 0.11.0 | Oct 28, 2025 |
#322 in Filesystem
Used in 2 crates
110KB
2K
SLoC
rs9p
Tokio-based asynchronous filesystems library using 9P2000.L protocol, an extended variant of 9P from Plan 9.
Features
- 🚀 Async/Await: Built on tokio for high-performance async I/O
- 🔒 Memory Safe:
#![forbid(unsafe_code)]- no unsafe code - 🔌 Multiple Transports: TCP and Unix domain sockets
- 📦 9P2000.L Protocol: Full support for Linux-extended 9P
- 🛠️ Easy to Use: Simple trait-based API for building custom filesystems
Documentation
- API Documentation - Full API reference on docs.rs
- Filesystem Trait Guide - Complete guide to implementing custom filesystems
- Documentation Index - All available documentation
Quick Start
Using as a Library
Add to your Cargo.toml:
[dependencies]
rs9p = "0.5"
async-trait = "0.1"
tokio = { version = "1", features = ["full"] }
Implement the Filesystem trait:
use rs9p::{srv::{Filesystem, FId, srv_async}, Result, FCall, QId, QIdType};
use async_trait::async_trait;
#[derive(Clone)]
struct MyFs;
#[derive(Default)]
struct MyFId;
#[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> {
Ok(FCall::RAttach {
qid: QId {
typ: QIdType::DIR,
version: 0,
path: 0,
}
})
}
// Implement other methods...
}
#[tokio::main]
async fn main() -> Result<()> {
srv_async(MyFs, "tcp!127.0.0.1!564").await
}
See the Filesystem Trait Guide for complete examples.
unpfs - Reference Implementation
unpfs
unpfs is the reference implementation of a file server which exports your filesystem.
You can install unpfs from crates.io:
cargo install unpfs
or build it from source with the following commands:
git clone https://github.com/rs9p/rs9p
cd rs9p
cargo install crates/unpfs
and run unpfs with the following command to export ./testdir:
# Unix domain socket:
# port number is a suffix to the unix domain socket
# 'unix!/tmp/unpfs-socket!n' creates `/tmp/unpfs-socket:n`
unpfs 'unix!/tmp/unpfs-socket!0' testdir
You are now ready to import/mount the remote filesystem.
Let's mount it at ./mount:
# Unix domain socket
sudo mount -t 9p -o version=9p2000.L,trans=unix,uname=$USER /tmp/unpfs-socket:0 ./mount
The default transport is normally TCP, but the port its listening on is in the restricted range, which requires root permissions. That's why we started with the unix domain socket, because it's more likely to just work.
But TCP is obviously supported as well. Here's the same commands as above, but using TCP this time:
sudo unpfs 'tcp!0.0.0.0!564' testdir
# TCP
sudo mount -t 9p -o version=9p2000.L,trans=tcp,port=564,uname=$USER 127.0.0.1 ./mount
| Mount option | Value |
|---|---|
| version | must be "9p2000.L" |
| trans | an alternative v9fs transport. "tcp" or "unix" |
| port | port to connect to on the remote server |
| uname | user name to attempt mount as on the remote server |
See v9fs documentation for more details.
Protocol Reference
Contributing
Contributions are welcome! Please:
- Check existing issues or create a new one
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure
cargo test,cargo clippy, andcargo fmt --checkpass - Submit a pull request
Safety and Security
- Memory Safe: No unsafe code - all operations use safe Rust
- Error Handling: Comprehensive error handling prevents panics
- Path Validation: Implement proper validation to prevent directory traversal
- Authentication: Default auth returns
EOPNOTSUPP- implement for production use
See the Filesystem Trait Guide for security best practices.
License
rs9p is distributed under the BSD 3-Clause License. See LICENSE for details.
Dependencies
~10–14MB
~172K SLoC