lib9p

Go 9P library.
Log | Files | Refs

commit 7464c340f8010cecdeafff2b5aa1fe44d5233f57
parent 0020dcd0a0e379bad363ac2aee9a8535fdde00f5
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Mon, 17 Jul 2023 15:25:08 +0900

add fidpool and sAttach

Diffstat:
Mcmd/disk.go | 10+++++-----
Mfcall.go | 32+++++++++++++++++++++++++-------
Mfid.go | 59++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mserver.go | 59+++++++++++++++++++++++++++++++++++++++++++++++------------
4 files changed, 125 insertions(+), 35 deletions(-)

diff --git a/cmd/disk.go b/cmd/disk.go @@ -36,17 +36,17 @@ func main() { log.Printf("accept connection: %v", err) continue } - disk := os.DirFS(os.Args[1]) + disk := os.DirFS(flag.Arg(0)) go handle(conn, disk) } } func handle(conn net.Conn, disk fs.FS) { srv := &lib9p.Srv{ - disk, - 8 * 1024, - conn, - conn, + FS: disk, + MSize: 8 * 1024, + Reader: conn, + Writer: conn, } lib9p.Serve(srv) diff --git a/fcall.go b/fcall.go @@ -76,6 +76,12 @@ type Msg interface { String() string } +type Req struct { + srv *Srv + ifcall Msg + ofcall Msg +} + // bufMsg is Msg with just an array of bytes. type bufMsg []byte @@ -130,7 +136,7 @@ type TAuth []byte func (msg TAuth) Size() uint32 { return gbit32(msg[0:4]) } func (msg TAuth) Type() MsgType { return MsgType(msg[4]) } func (msg TAuth) Tag() uint16 { return gbit16(msg[5:7]) } -func (msg TAuth) AFid() Fid { return Fid(msg[7:11]) } +func (msg TAuth) AFid() uint32 { return gbit32(msg[7:11]) } func (msg TAuth) UName() string { size := gbit16(msg[11:13]) return string(msg[13 : 13+size]) @@ -142,8 +148,12 @@ func (msg TAuth) AName() string { } func (msg TAuth) conv2M() []byte { return []byte(msg)[:msg.Size()] } func (msg TAuth) String() string { - return fmt.Sprintf("Tauth tag %d afid %v uname %s aname %s", - msg.Tag(), msg.AFid(), msg.UName(), msg.AName()) + afid := int64(msg.AFid()) + if afid == int64(NOFID) { + afid = -1 + } + return fmt.Sprintf("Tauth tag %d afid %d uname %s aname %s", + msg.Tag(), afid, msg.UName(), msg.AName()) } type RAuth []byte @@ -163,8 +173,8 @@ type TAttach []byte func (msg TAttach) Size() uint32 { return gbit32(msg[0:4]) } func (msg TAttach) Type() MsgType { return MsgType(msg[4]) } func (msg TAttach) Tag() uint16 { return gbit16(msg[5:7]) } -func (msg TAttach) Fid() Fid { return Fid(msg[7:11]) } -func (msg TAttach) AFid() Fid { return Fid(msg[11:15]) } +func (msg TAttach) Fid() uint32 { return gbit32(msg[7:11]) } +func (msg TAttach) AFid() uint32 { return gbit32(msg[11:15]) } func (msg TAttach) UName() string { usize := gbit16(msg[15:17]) return string(msg[17 : 17+usize]) @@ -176,8 +186,16 @@ func (msg TAttach) AName() string { } func (msg TAttach) conv2M() []byte { return []byte(msg)[:msg.Size()] } func (msg TAttach) String() string { - return fmt.Sprintf("Tattach tag %d fid %v afid %v uname %s aname %s", - msg.Tag(), msg.Fid(), msg.AFid(), msg.UName(), msg.AName()) + fid := int64(msg.Fid()) + if fid == int64(NOFID) { + fid = -1 + } + afid := int64(msg.AFid()) + if afid == int64(NOFID) { + afid = -1 + } + return fmt.Sprintf("Tattach tag %d fid %d afid %d uname %s aname %s", + msg.Tag(), fid, afid, msg.UName(), msg.AName()) } type RAttach []byte diff --git a/fid.go b/fid.go @@ -2,6 +2,7 @@ package lib9p import ( "fmt" + "io/fs" ) // QidType represents the type of Qid. the 'QT' prefix may be redundant. @@ -18,22 +19,29 @@ const ( QTFILE = 0x00 /* type bits for plain file */ ) -type Req struct { - srv *Srv - ifcall Msg - ofcall Msg +type Fid struct { + Fid uint32 + OMode int32 /* -1 = not open */ + File fs.File + Uid string + Qid Qid } -type Fid []byte - const NOFID = ^uint32(0) -func (f Fid) String() string { - fn := int64(gbit32(f)) - if uint32(fn) == NOFID { - fn = -1 +func newFid(fid uint32) *Fid { + f := new(Fid) + f.Fid = fid + f.OMode = -1 + return f +} + +func (f *Fid) String() string { + fid := int64(f.Fid) + if uint32(fid) == NOFID { + fid = -1 } - return fmt.Sprintf("%d", fn) + return fmt.Sprintf("%d", fid) } type Qid []byte @@ -66,3 +74,32 @@ func (q Qid) typeStr() string { } return s } + +type FidPool struct { + m map[uint32]*Fid +} + +func allocFidPool() *FidPool { + f := new(FidPool) + f.m = make(map[uint32]*Fid) + return f +} + +func (pool *FidPool) lookupFid(fid uint32) *Fid { + return pool.m[fid] +} + +func (pool *FidPool) allocFid(fid uint32) (*Fid, error) { + if _, ok := pool.m[fid]; ok { + return nil, fmt.Errorf("fid already in use.") + } + f := newFid(fid) + pool.m[fid] = f + return f, nil +} + +func (pool *FidPool) removeFid(fid uint32) *Fid { + f := pool.lookupFid(fid) + delete(pool.m, fid) + return f +} diff --git a/server.go b/server.go @@ -16,18 +16,20 @@ func Chatty() { } type Srv struct { - FS fs.FS - MSize uint32 - io.Reader - io.Writer + FS fs.FS + MSize uint32 + fPool *FidPool + Reader io.Reader + Writer io.Writer } func getReq(s *Srv) (*Req, error) { var r Req + r.srv = s - buf, err := read9PMsg(s) + buf, err := read9PMsg(s.Reader) if err != nil { - return nil, fmt.Errorf("read message: %v", err) + return &r, fmt.Errorf("read message: %v", err) } switch t := bufMsg(buf).Type(); t { @@ -35,7 +37,7 @@ func getReq(s *Srv) (*Req, error) { if chatty9P { fmt.Fprintf(os.Stderr, "<-- %v\n", bufMsg(buf)) } - return nil, fmt.Errorf("unknown message type %d", t) + return &r, fmt.Errorf("unknown message type %d", t) case Tversion: r.ifcall = TVersion(buf) case Tattach: @@ -43,7 +45,6 @@ func getReq(s *Srv) (*Req, error) { case Tauth: r.ifcall = TAuth(buf) } - r.srv = s if chatty9P { fmt.Fprintf(os.Stderr, "<-- %v\n", r.ifcall) } @@ -98,6 +99,40 @@ func rAuth(r *Req, err error) { } func sAttach(s *Srv, r *Req) { + ifcall, ok := r.ifcall.(TAttach) + if !ok { + panic("not TAttach") + } + if s.fPool == nil { + s.fPool = allocFidPool() + } + fid, err := s.fPool.allocFid(ifcall.Fid()) + if err != nil { + respond(r, fmt.Errorf("duplicate fid")) + return + } + + fid.File, err = s.FS.Open(".") // TODO: use aname + if err != nil { + respond(r, fmt.Errorf("unable to open file tree")) + return + } + + fid.Uid = ifcall.UName() + + qid := Qid(make([]byte, 13)) + qid.SetType(QTDIR) + qid.SetVers(0) + qid.SetPath(0) + fid.Qid = qid + + ofcall := RAttach(make([]byte, 4+1+2+13)) + ofcall.SetSize(uint32(len(ofcall))) + ofcall.SetType(Rattach) + ofcall.SetTag(ifcall.Tag()) + ofcall.SetQid(qid) + r.ofcall = ofcall + respond(r, nil) } @@ -118,7 +153,8 @@ func Serve(s *Srv) { r, err := getReq(s) if err != nil { log.Printf("get req: %v\n", err) - break + respond(r, fmt.Errorf("internal error")) + continue } switch r.ifcall.(type) { default: @@ -142,7 +178,7 @@ func respond(r *Req, err error) { } rError(r, err) } else { - rError(r, fmt.Errorf("unknown message type: %s", r.ofcall.Type())) + rError(r, fmt.Errorf("unknown message type: %d", r.ofcall.Type())) } case RVersion: rVersion(r, err) @@ -155,6 +191,5 @@ func respond(r *Req, err error) { if chatty9P { fmt.Fprintf(os.Stderr, "--> %s\n", r.ofcall) } - r.srv.Write(r.ofcall.conv2M()) - + r.srv.Writer.Write(r.ofcall.conv2M()) }