lib9p

Go 9P library.
Log | Files | Refs

commit e72454ff7e26e1c102d7532561154cd9c453787e
parent 825c0b5de9a56096a364e94ee499ed241fc21bd0
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Fri, 13 Oct 2023 16:50:50 +0900

add mount for client

Diffstat:
Mclient.go | 5+++--
Aclient2.go | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfid.go | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfile.go | 28+++++++++++++++++++++-------
Mfs.go | 1+
5 files changed, 151 insertions(+), 9 deletions(-)

diff --git a/client.go b/client.go @@ -11,11 +11,12 @@ type Client struct { msize uint32 mSizeLock *sync.Mutex uname string - fPool *FidPool + fPool *clientFidPool rPool *clientReqPool txc chan<- *clientReq errc chan error cancel context.CancelFunc + root *ClientFile } type LibErr string @@ -31,7 +32,7 @@ func NewClient(mSize uint32, uname string, r io.Reader, w io.Writer) *Client { msize: mSize, mSizeLock: new(sync.Mutex), uname: uname, - fPool: allocFidPool(), + fPool: allocClientFidPool(), rPool: newClientReqPool(), errc: make(chan error), cancel: cancel, diff --git a/client2.go b/client2.go @@ -0,0 +1,51 @@ +package lib9p + +import ( + "io" + "context" + "fmt" +) + +func (c *Client) Root() File { + return c.root +} + +func Mount(r io.Reader, w io.Writer, uname, aname string) (fs FS, err error) { + var ( + mSize uint32 = 8196 + version = "9P2000" + ctx = context.TODO() + ) + c := NewClient(mSize, uname, r, w) + defer func() { if err != nil { c.Stop() } }() + rmSize, rver, err := c.Version(ctx, mSize, version) + if err != nil { + return nil, fmt.Errorf("version: %v", err) + } + if rver != "version" { + return nil, fmt.Errorf("incompatible version %s", rver) + } + if rmSize < mSize { + c.setMSize(rmSize) + } + // TODO: auth + + fid, err := c.fPool.add(0) + if err != nil { + return nil, fmt.Errorf("add fid: %v", err) + } + qid, err := c.Attach(ctx, fid.fid, NOFID, uname, aname) + if err != nil { + return nil, fmt.Errorf("attach: %v", err) + } + c.root = &ClientFile{ + name: "/", + path: ".", + fid: fid, + qid: qid, + client: c, + } + c.root.parent = c.root + fid.file = c.root + return c, nil +} +\ No newline at end of file diff --git a/fid.go b/fid.go @@ -101,3 +101,76 @@ func (pool *FidPool) String() string { s += "}" return s } + +type clientFid struct { + fid uint32 + omode OpenMode // -1 for not open + offset uint64 + file *ClientFile +} + +func newClientFid(fid uint32) *clientFid { + return &clientFid{ + fid: fid, + omode: -1, + offset: 0, + } +} + +type clientFidPool struct { + m map[uint32]*clientFid + lock *sync.Mutex +} + +func allocClientFidPool() *clientFidPool { + return &clientFidPool{ + m: make(map[uint32]*clientFid), + lock: new(sync.Mutex), + } +} + +func (pool *clientFidPool) lookup(fid uint32) (*clientFid, bool) { + pool.lock.Lock() + defer pool.lock.Unlock() + + f, ok := pool.m[fid] + return f, ok +} + +func (pool *clientFidPool) add(fid uint32) (*clientFid, error) { + pool.lock.Lock() + defer pool.lock.Unlock() + + if _, ok := pool.m[fid]; ok { + return nil, fmt.Errorf("fid already in use.") + } + f := newClientFid(fid) + pool.m[fid] = f + return f, nil +} + +func (pool *clientFidPool) delete(fid uint32) { + pool.lock.Lock() + defer pool.lock.Unlock() + + delete(pool.m, fid) +} + +func (pool *clientFidPool) String() string { + pool.lock.Lock() // TODO: need? + defer pool.lock.Unlock() + s := "{" + for fnum, fstruct := range pool.m { + if fstruct.file == nil { + s += fmt.Sprintf(" [%d]<nil>", fnum) + continue + } + st, err := fstruct.file.Stat() + if err != nil { + panic(err) + } + s += fmt.Sprintf(" [%d]%v", fnum, st.Name()) + } + s += "}" + return s +} +\ No newline at end of file diff --git a/file.go b/file.go @@ -1,6 +1,7 @@ package lib9p import ( + "context" "fmt" "io" ) @@ -68,12 +69,14 @@ func walkfile(f File, name string) (File, error) { } type ClientFile struct { - stat Stat name string path string parent *ClientFile children []*ClientFile - fid *Fid + fid *clientFid + qid Qid + iounit uint32 + client *Client } func (cf *ClientFile) Parent() (File, error) { @@ -89,21 +92,32 @@ func (cf *ClientFile) Child() ([]File, error) { } func (cf *ClientFile) Stat() (*FileInfo, error) { - return &FileInfo{cf.stat}, nil + st, err := cf.client.Stat(context.TODO(), cf.fid.fid) + if err != nil { + return nil, err + } + return &FileInfo{*st}, nil } func (cf *ClientFile) Qid() Qid { - return cf.stat.Qid + return cf.qid } func (cf *ClientFile) Open(mode OpenMode) error { - cf.fid.OMode = mode + qid, iounit, err := cf.client.Open(context.TODO(), cf.fid.fid, mode) + if err != nil { + return err + } + cf.qid = qid + cf.iounit = iounit + cf.fid.omode = mode return nil } func (cf *ClientFile) Close() error { - cf.fid.OMode = -1 - return nil + err := cf.client.Clunk(context.TODO(), cf.fid.fid) + cf.fid = nil + return err } func (cf *ClientFile) Read(b []byte) (int, error) { diff --git a/fs.go b/fs.go @@ -10,6 +10,7 @@ type FS interface { type ClientFS struct { root *ClientFile + client *Client } func (cfs ClientFS) Root() File {