High-level 9P client library for Zig
|
|
||
|---|---|---|
| src | release: v0.1.1 | |
| .gitignore | release: v0.1.0 | |
| build.zig | release: v0.1.0 | |
| build.zig.zon | release: v0.1.1 | |
| LICENSE | release: v0.1.0 | |
| README.md | release: v0.1.0 | |
ninepea
High-level 9P client library for Zig following the Plan 9 syscall interface.
Overview
ninepea provides a complete Plan 9-style namespace abstraction for 9P clients,
with support for:
- All three 9P dialects: 9P2000, 9P2000.u, 9P2000.L
- Plan 9 namespace semantics: union directories, bind mounts, mount points
- Async I/O: Full
std.Iointegration for cancelable, concurrent operations - RAII resource management: Automatic fid lifecycle with defer-safe cleanup
- Dialect-aware routing: Automatically uses the best available protocol operation
Quick Start
conststd=@import("std");constninepea=@import("ninepea");pubfnmain(opts:std.Options)!void{vargpa:std.heap.DebugAllocator(.{})=.init;defer_=gpa.deinit();constio=opts.io;// Create a namespacevarns=tryninepea.Ns.init(gpa.allocator(),io);deferns.deinit();// Connect and mount a 9P serverconstaddr=trystd.Io.net.IpAddress.parseIp4("127.0.0.1",564);constconn=tryaddr.connect(io,.{});deferconn.close(io);tryns.mount(conn,"","/mnt",.{},"");// Open and read a filevarfile=tryns.openFile("/mnt/data.txt",.{.access=.read});deferfile.close()catch{};varbuf:[4096]u8=undefined;constn=tryfile.read(&buf);std.debug.print("Read {d} bytes\n",.{n});}Features
Transport Support
- Wire transport: Network connections (TCP, Unix sockets) and file descriptors
- DirectPipe: In-process synchronous IPC for testing and embedded servers
- AsyncDirectPipe: In-process async IPC with concurrent request handling
Namespace Management
// Mount a 9P connection (replaces any existing mount by default)tryns.mount(conn,"","/mnt",.{},"");// Create a union directory (multiple mount points)// First mount establishes the directorytryns.mount(conn1,"","/data",.{},"server1");// Second mount adds to the union, searched after conn1tryns.mount(conn2,"","/data",.{.after=true},"server2");// Mount a DirectPipe (in-process IPC)varpipe:nine_p.proto.DirectPipe(.{})=undefined;nine_p.proto.DirectPipe(.{}).initOwned(&pipe,8192);tryns.mountDirectPipe(&pipe,"","/local",.{},"");// Bind one path to anothertryns.bind("/remote/bin","/bin",.{});// Unmounttryns.unmount("/mnt",null);File Operations
// Open and readvarfile=tryns.openFile("/path/to/file",.{.access=.read});deferfile.close()catch{};varbuf:[4096]u8=undefined;constn=tryfile.read(&buf);// Create and writevarfile=tryns.createFile("/path/to/new",0o644,.{.access=.write});deferfile.close()catch{};constwritten=tryfile.write("hello world");// Positioned I/Oconstn=tryfile.pread(&buf,1024);constw=tryfile.pwrite("data",2048);// Seekconstoffset=tryfile.seek(-100,.end);Directory Operations
// Iterate directory entriesvardir=tryninepea.Dir.open(&ns,"/path");deferdir.close()catch{};while(trydir.next())|entry|{std.debug.print("{s}\n",.{entry.name});}// Create files and directoriestrydir.createFile("newfile.txt",0o644,.{.access=.write});trydir.mkdir("subdir",0o755);// Symlinks (9P2000.u / 9P2000.L)trydir.symlink("link","/target/path");9P2000.L Extended Operations
// File lockingtryfile.lock(.write,0,1024,.{.block=true});deferfile.lock(.unlock,0,1024,.{})catch{};// Extended attributesvarxattr_buf:[256]u8=undefined;constn=tryfile.getxattr("user.comment",&xattr_buf);tryfile.setxattr("user.comment","my note",0);// Fsynctryfile.sync();Plan 9 Syscall Compatibility
constsys=ninepea.syscalls;constfd=trysys.open(&ns,"/data/file.txt",.{.access=.read});defersys.close(&ns,fd)catch{};varbuf:[256]u8=undefined;constn=trysys.read(&ns,fd,&buf);constn2=trysys.pread(&ns,fd,&buf,1024);Async Operations
vargroup:std.Io.Group=.init;group.async(io,readFile,.{io,&ns,"/data/file1.txt"});group.async(io,readFile,.{io,&ns,"/data/file2.txt"});group.async(io,readFile,.{io,&ns,"/data/file3.txt"});trygroup.await(io);DirectPipe In-Process IPC
constnine_p=@import("nine_p");// Create an in-process pipevarpipe:nine_p.proto.DirectPipe(.{})=undefined;nine_p.proto.DirectPipe(.{}).initOwned(&pipe,8192);deferpipe.deinit();// Mount the client sidetryns.mountDirectPipe(&pipe,"","/proc",.{},"");// Run a server handler on pipe.server() in another taskvargroup:std.Io.Group=.init;group.async(io,runServer,.{io,&pipe});// Use files in /proc like any other mountvarfile=tryns.openFile("/proc/status",.{.access=.read});deferfile.close()catch{};Architecture
See DESIGN.md for the complete design document.
Key Components
- Ns: Namespace management (mount, bind, unmount, path resolution)
- File: Open file handle (read, write, seek, stat, close)
- Dir: Directory iteration and operations
- MountPoint: 9P connection state (session, fid pool, cache)
- NamespaceTree: Union mount table and path resolution
- FidCache: Fid reuse optimization
- DialectRouter: Automatic dialect-specific operation dispatch
Building
zig build
Testing
zig build test
zig build test --summary all
Dependencies
nine_p: Low-level 9P protocol librarystd.Io: Standard library async I/O
Project Status
This is a design document and initial structure. Implementation is in progress.
See DESIGN.md for detailed architecture, API specifications, and implementation roadmap.
License
Same license as the parent 9p repository.