Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

/p/moul/x/plan9/ninep/v0

Directory · 4 Files
README.md Open

gno.land/p/moul/x/plan9/ninep/v0

A Plan 9 shaped file abstraction for gno: File, Mutable, Qid, Stat, Perm, the 9P error set, and lexical path handling.

1import ninep "gno.land/p/moul/x/plan9/ninep/v0"
2
3type File interface {
4	Stat() Stat
5	Walk(name string) (File, error)      // exactly one element
6	Read(off, count int64) (string, error)
7	ReadDir() ([]Stat, error)
8}

This implements the semantics of 9P2000, not its wire format. There is no socket on a chain: the VM call is the transport. What survives the translation is the part that made 9P useful, namely that every resource answers the same four questions, so a client written today can browse a file server deployed tomorrow.

One interface, not two. 9P reads a directory with the same Tread it uses for a file, so splitting File from Dir would be less faithful, and a single interface means no type assertion across a realm boundary.

File is read-only, on purpose. A crossing write method would mint the caller's realm frame for the callee, which is the confused-deputy shape that r/gov/dao's Executor relies on deliberately and p/nt/grc20's Teller refuses deliberately. So mutation lives in a separate Mutable, which is only safe on a tree your own realm owns. That is what makes it safe to hand a File to a stranger's namespace.

Deliberate divergences, each one forced:

  • Data is a string, not []byte. Every consumer on this chain is text and Render returns a string.
  • Mtime is a block height. It is the only clock every validating node agrees on.
  • There is no open/clunk. Without a session there are no fids, so Walk returns the file itself and nothing has to be released.
  • .. never reaches a server. Clean resolves it lexically first, per Lexical File Names in Plan 9, so .. undoes the name you typed rather than the directory you landed in.
  • MaxDepth caps a walk at 32 elements. Resolution can cost one cross-realm call per element, so depth is bounded rather than trusted.

Used by memfs (a RAM server), synfs (a computed server), ns (namespaces) and rc (the shell). Design and analysis: moul/gno-contracts#136.


Not affiliated with Plan 9. Plan 9 from Bell Labs is the work of the Computing Science Research Center at Bell Labs; the name and the marks are theirs, and the copyright is held by the Plan 9 Foundation. This package borrows the vocabulary and none of the code: it is an independent homage, asking what that ecosystem's spirit looks like on a chain. Full attribution: NOTICE.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.