Documentation ¶
Overview ¶
Example ¶
package main import ( "errors" "fmt" "log" "git.sr.ht/~moody/ninep" ) // Embed NopFS to cover message types we dont plan // to support. type myfs struct { ninep.NopFS i int msg []byte rootD ninep.Dir fileD ninep.Dir } func (e *myfs) Attach(t *ninep.Tattach) { e.msg = []byte(fmt.Sprintf("You are lucky number %d\n", e.i)) e.fileD = ninep.Dir{ Qid: ninep.Qid{1, 0, 0}, Mode: 0x4, Len: uint64(len(e.msg)), Name: "test", Uid: "moody", Gid: "moody", Muid: "moody", } e.rootD = ninep.Dir{ Qid: ninep.Qid{0, 0, ninep.QTDir}, Name: "/", Mode: ninep.DMDir | 0777, Uid: "moody", Gid: "moody", Muid: "moody", } t.Respond(&e.rootD.Qid) } func (e *myfs) Walk(cur *ninep.Qid, next string) *ninep.Qid { if cur.Path == 0 && next == "test" { return &e.fileD.Qid } return nil } func (e *myfs) Open(t *ninep.Topen, q *ninep.Qid) { t.Respond(q, 8192) } var errNoFile = errors.New("no such file or directory") func (e *myfs) Read(t *ninep.Tread, q *ninep.Qid) { switch q.Path { case 0: ninep.ReadDir(t, []ninep.Dir{e.fileD}) case 1: ninep.ReadBuf(t, e.msg) default: t.Err(errNoFile) } } func (e *myfs) Stat(t *ninep.Tstat, q *ninep.Qid) { switch q.Path { case 0: t.Respond(&e.rootD) case 1: t.Respond(&e.fileD) default: t.Err(errNoFile) } } func main() { i := 0 //Create a new srv, where each new session is given an instance //of myfs. For each session i will be incremented. srv := ninep.NewSrv(func() ninep.FS { i++; return &myfs{i: i} }) srv.Chatty9P = true log.Fatal(srv.ListenAndServe(":9999")) }
Output:
Index ¶
- Constants
- func ReadBuf(t *Tread, b []byte)
- func ReadDir(t *Tread, dirs []Dir)
- type Dir
- type FS
- type FSMaker
- type NopFS
- func (n *NopFS) Attach(t *Tattach)
- func (n *NopFS) Clunk(t *Tclunk, q *Qid)
- func (n *NopFS) Create(t *Tcreate, q *Qid)
- func (n *NopFS) Open(t *Topen, q *Qid)
- func (n *NopFS) Read(t *Tread, q *Qid)
- func (n *NopFS) Remove(t *Tremove, q *Qid)
- func (n *NopFS) Stat(t *Tstat, q *Qid)
- func (n *NopFS) Walk(cur *Qid, next string) *Qid
- func (n *NopFS) Write(t *Twrite, q *Qid)
- func (n *NopFS) Wstat(t *Twstat, q *Qid)
- type Qid
- type Srv
- type Tattach
- type Tauth
- type Tclunk
- type Tcreate
- type Topen
- type Tread
- type Tremove
- type Tstat
- type Twrite
- type Twstat
Examples ¶
Constants ¶
const ( //Bits for Qid.Type QTDir = 0x80 //Directory QTAppend = 0x40 //Append only QTExcl = 0x20 //Exclusive use QTMount = 0x10 //Mounted channel QTAuth = 0x08 //Auth file QTTemp = 0x04 //Non WORM backed file QTFile = 0 //Regular file )
const ( //Special bits for Dir.Mode DMDir = 0x80000000 //Directory DMAppend = 0x40000000 //Append only DMExcl = 0x20000000 //Exclusive use DMMount = 0x10000000 //Mounted channel DMAuth = 0x08000000 //Auth file DMTmp = 0x04000000 //Non WORM backed file //Unix permissions in Dir.Mode, 3 sets for user, group and other. DMRead = 0x4 DMWrite = 0x2 DMExec = 0x1 )
const Ninep2000 = "9P2000"
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Dir ¶
type Dir struct { Qid Mode uint32 //Unix permissions Atime uint32 //Unix time of last access Mtime uint32 //Unix time of last modification Len uint64 //Length of file, directories set this to 0 Name string //Filename Uid string //User Owner Gid string //Group owner Muid string //User that last modified this file }
Dir contains all of the meta information for a file or directory.
type FS ¶
type FS interface { //Attach is the first message sent on a session, for which //the root Qid should be returned. Attach(t *Tattach) //Walk is called multiple times for a single Twalk request, //once for each walk elemenent within the message. For each //call cur is set to the directory from which the walk is //starting, with next being the path element that the client //wishes to walk to within the directory. The return value //should represent the Qid for the file identified by next //or nil if the file does not exist. Walk(cur *Qid, next string) *Qid //The Qid passed to create is the directory for which //the new file is to be created in. Create(t *Tcreate, q *Qid) //For Open, Read, Write, Stat, Wstat, and Remove. The Qid passed //represents the specific file the client wishes to operate on. //Read is also the message called for listing files within //a directory, a helper function ReadDir is included for //this case. Open(t *Topen, q *Qid) Read(t *Tread, q *Qid) Write(t *Twrite, q *Qid) Stat(t *Tstat, q *Qid) Wstat(t *Twstat, q *Qid) Remove(t *Tremove, q *Qid) //Clunk is sent when the client no longer has any refrences //open to a specific file to allow the server to perform //clenup. Clunk(t *Tclunk, q *Qid) }
FS is the interface that 9p servers must satisfy to be used with Srv. Each function that accepts a T* message is expected to call T*'s Respond method. Respond takes the corespdonding R* message and err string. If the err string is non empty then a Rerror is sent to the client with the string included as the error message instead.
type NopFS ¶
type NopFS struct{}
NopFS is a filesystem that simply errors on each request message. NopFS can be embedded to respond to request types the server does not plan to support.
type Qid ¶
type Qid struct { Path uint64 //Unique ID of specific file to a specific server. Vers uint32 //The version of the file, incremented for each change. Type byte //The type of the file. }
Qid is the unique identification for a file.
type Srv ¶
type Srv struct { Chatty9P bool // contains filtered or unexported fields }
Srv handles the marshalling and session management for a FS. Setting Chatty9P to true will cause message string representations to be printed to stderr.
func NewSrv ¶
NewSrv allocates a new Srv struct. For each new session a new FS is substantiated through the fsf function, this allows the FS to store session specific state like attached usernames.
func (*Srv) ListenAndServe ¶
ListenAndServe is a helper function that wraps Serve that listens on the specific port before calling Serve.