lib9p

Go 9P library.
Log | Files | Refs | LICENSE

commit 7946abf959f1d81ec0181079ad705971cbdd551c
parent 0c30f8deceab890728459eb52601f676467393c4
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue,  9 Jan 2024 12:01:21 +0900

support aname in attach

Diffstat:
Mfid.go | 1+
Mserver.go | 68++++++++++++++++++++++++++++++++++++++------------------------------
Mserver_test.go | 6++++++
3 files changed, 45 insertions(+), 30 deletions(-)

diff --git a/fid.go b/fid.go @@ -31,6 +31,7 @@ type fid struct { fid uint32 omode OpenMode /* -1 = not open */ path string // The path from the root of the FS. + fs FS // The associated FS. file File // The associated File. uid string // The user id derived from the attach message. dirOffset uint64 // Used when reading directory. diff --git a/server.go b/server.go @@ -13,7 +13,7 @@ import ( ) var ( - ErrBotch = fmt.Errorf("bocchi") + ErrBotch = fmt.Errorf("botch") ErrPerm = fmt.Errorf("permission denied") ErrOperation = fmt.Errorf("operation not supported") ErrDupTag = fmt.Errorf("duplicate tag") @@ -35,7 +35,7 @@ type Server struct { chatty9P bool // The file system to export via 9P. - fs FS + fs map[string]FS // Auth function is passed an auth request when a TAuth message arrives // If authentication is desired, Auth should @@ -50,7 +50,7 @@ type Server struct { // It reads incoming messages from r and writes responses to w. func NewServer(fsys FS) *Server { s := &Server{ - fs: fsys, + fs: map[string]FS{"": fsys}, } return s } @@ -288,6 +288,7 @@ func sAttach(ctx context.Context, c *conn, rc <-chan *request) { return case r, ok := <-rc: var ( + fsys FS st fs.FileInfo err error ) @@ -327,7 +328,13 @@ func sAttach(ctx context.Context, c *conn, rc <-chan *request) { r.fid.omode = -1 r.fid.path = "." r.fid.uid = ifcall.Uname - st, err = fs.Stat(ExportFS{c.s.fs}, ".") + fsys, ok = c.s.fs[ifcall.Aname] + if !ok { + r.err = fmt.Errorf("no such file system") + goto resp + } + r.fid.fs = fsys + st, err = fs.Stat(ExportFS{c.s.fs[ifcall.Aname]}, ".") if err != nil { r.err = fmt.Errorf("stat root: %v", err) goto resp @@ -401,7 +408,7 @@ func sWalk(ctx context.Context, c *conn, rc <-chan *request) { r.err = fmt.Errorf("cannot clone open fid") goto resp } - oldst, err = fs.Stat(ExportFS{c.s.fs}, oldFid.path) + oldst, err = fs.Stat(ExportFS{oldFid.fs}, oldFid.path) if err != nil { r.err = fmt.Errorf("stat: %v", err) goto resp @@ -427,7 +434,7 @@ func sWalk(ctx context.Context, c *conn, rc <-chan *request) { if cwdp == ".." { cwdp = "." // parent of the root is itself. } - stat, err := fs.Stat(ExportFS{c.s.fs}, cwdp) + stat, err := fs.Stat(ExportFS{oldFid.fs}, cwdp) if err != nil { break } @@ -437,6 +444,7 @@ func sWalk(ctx context.Context, c *conn, rc <-chan *request) { newFid.omode = -1 newFid.path = cwdp newFid.uid = oldFid.uid + newFid.fs = oldFid.fs r.ofcall = &RWalk{ Qids: wqids[:n], } @@ -508,7 +516,7 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { // See open(5). // In plan9 implementation, ifcall.Mode() is ANDed with ^ORCLOSE, // but ORCLOSE is also prohibitted by the protocol... - st, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path) + st, err = fs.Stat(ExportFS{r.fid.fs}, r.fid.path) if err != nil { r.err = fmt.Errorf("stat: %v", err) goto resp @@ -538,18 +546,18 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { r.err = ErrPerm goto resp } - if !hasPerm(c.s.fs, st, r.fid.uid, p) { + if !hasPerm(r.fid.fs, st, r.fid.uid, p) { r.err = ErrPerm goto resp } if ifcall.Mode&ORCLOSE != 0 { parentPath := path.Dir(r.fid.path) - st, err := fs.Stat(ExportFS{c.s.fs}, parentPath) + st, err := fs.Stat(ExportFS{r.fid.fs}, parentPath) if err != nil { r.err = fmt.Errorf("stat parent: %v", err) goto resp } - if !hasPerm(c.s.fs, st, r.fid.uid, AWRITE) { + if !hasPerm(r.fid.fs, st, r.fid.uid, AWRITE) { r.err = ErrPerm goto resp } @@ -577,7 +585,7 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { } continue } - f, err := c.s.fs.OpenFile(r.fid.path, r.fid.omode) + f, err := r.fid.fs.OpenFile(r.fid.path, r.fid.omode) if err != nil { setError(r, err) select { @@ -626,7 +634,7 @@ func sCreate(ctx context.Context, c *conn, rc <-chan *request) { r.err = ErrBotch goto resp } - dirstat, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path) + dirstat, err = fs.Stat(ExportFS{r.fid.fs}, r.fid.path) if err != nil { r.err = fmt.Errorf("stat: %v", err) goto resp @@ -635,11 +643,11 @@ func sCreate(ctx context.Context, c *conn, rc <-chan *request) { r.err = fmt.Errorf("create in non-dir") goto resp } - if !hasPerm(c.s.fs, dirstat, r.fid.uid, AWRITE) { + if !hasPerm(r.fid.fs, dirstat, r.fid.uid, AWRITE) { r.err = ErrPerm goto resp } - cfs, ok = c.s.fs.(CreaterFS) + cfs, ok = r.fid.fs.(CreaterFS) if !ok { r.err = ErrOperation goto resp @@ -728,7 +736,7 @@ func sRead(ctx context.Context, c *conn, rc <-chan *request) { errc <- fmt.Errorf("invalid dir offset") return } - children, err := fs.Glob(ExportFS{c.s.fs}, path.Join(r.fid.path, "*")) + children, err := fs.Glob(ExportFS{r.fid.fs}, path.Join(r.fid.path, "*")) if err != nil { errc <- fmt.Errorf("glob children: %v", err) return @@ -739,7 +747,7 @@ func sRead(ctx context.Context, c *conn, rc <-chan *request) { } k := r.fid.dirIndex for ; k < len(children); k++ { - fi, err := fs.Stat(ExportFS{c.s.fs}, children[k]) + fi, err := fs.Stat(ExportFS{r.fid.fs}, children[k]) if err != nil { log.Printf("stat: %v", err) continue @@ -937,16 +945,16 @@ func sRemove(ctx context.Context, c *conn, rc <-chan *request) { r.fid.file.Close() } parentPath = path.Dir(r.fid.path) - pstat, err = fs.Stat(ExportFS{c.s.fs}, parentPath) + pstat, err = fs.Stat(ExportFS{r.fid.fs}, parentPath) if err != nil { r.err = fmt.Errorf("stat parent: %v", err) goto resp } - if !hasPerm(c.s.fs, pstat, r.fid.uid, AWRITE) { + if !hasPerm(r.fid.fs, pstat, r.fid.uid, AWRITE) { r.err = ErrPerm goto resp } - rfs, ok = c.s.fs.(RemoverFS) + rfs, ok = r.fid.fs.(RemoverFS) if !ok { r.err = ErrOperation goto resp @@ -990,7 +998,7 @@ func sStat(ctx context.Context, c *conn, rc <-chan *request) { r.err = ErrUnknownFid goto resp } - fi, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path) + fi, err = fs.Stat(ExportFS{r.fid.fs}, r.fid.path) if err != nil { r.err = fmt.Errorf("stat: %v", err) goto resp @@ -1035,7 +1043,7 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { } if r.fid.omode == -1 { var err error - r.fid.file, err = c.s.fs.OpenFile(r.fid.path, OREAD) + r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, OREAD) if err != nil { r.err = fmt.Errorf("open: %v", err) goto resp @@ -1067,12 +1075,12 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { } if wstat.Name != "" && newStat.Name != wstat.Name { parentPath := path.Dir(r.fid.path) - pstat, err := fs.Stat(ExportFS{c.s.fs}, parentPath) + pstat, err := fs.Stat(ExportFS{r.fid.fs}, parentPath) if err != nil { r.err = fmt.Errorf("stat parent: %v", err) goto resp } - if !hasPerm(c.s.fs, pstat, r.fid.uid, AWRITE) { + if !hasPerm(r.fid.fs, pstat, r.fid.uid, AWRITE) { r.err = ErrPerm goto resp } @@ -1082,7 +1090,7 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { // an existing file. // but 9pfs, 9pfuse does the rename when used with `git init`. /* - children, err := fs.Glob(ExportFS{c.s.fs}, path.Join(parentPath, "*")) + children, err := fs.Glob(ExportFS{r.fid.fs}, path.Join(parentPath, "*")) if err != nil { r.err = fmt.Errorf("glob children: %v", err) goto resp @@ -1098,7 +1106,7 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { } if wstat.Length != ^int64(0) && wstat.Length != newStat.Length { // TODO: deal with wstat which changes directory length to 0 - if fi.IsDir() || !hasPerm(c.s.fs, fi, r.fid.uid, AWRITE) { + if fi.IsDir() || !hasPerm(r.fid.fs, fi, r.fid.uid, AWRITE) { r.err = ErrPerm goto resp } @@ -1106,7 +1114,7 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { } if wstat.Mode != FileMode(^uint32(0)) && wstat.Mode != newStat.Mode { // the owner of the file or the group leader of the file'c group. - if r.fid.uid != newStat.Uid && !isGroupLeader(c.s.fs, newStat.Gid, r.fid.uid) { + if r.fid.uid != newStat.Uid && !isGroupLeader(r.fid.fs, newStat.Gid, r.fid.uid) { r.err = ErrPerm goto resp } @@ -1118,7 +1126,7 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { } if wstat.Mtime != ^uint32(0) && wstat.Mtime != newStat.Mtime { // the owner of the file or the group leader of the file'c group. - if r.fid.uid != newStat.Uid && !isGroupLeader(c.s.fs, newStat.Gid, r.fid.uid) { + if r.fid.uid != newStat.Uid && !isGroupLeader(r.fid.fs, newStat.Gid, r.fid.uid) { r.err = ErrPerm goto resp } @@ -1128,9 +1136,9 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { // by the owner if also a member of the new group; // or by the group leader of the file'c current group if // also the leader of the new group. - if r.fid.uid == newStat.Uid && isGroupMember(c.s.fs, wstat.Gid, r.fid.uid) || - isGroupLeader(c.s.fs, newStat.Gid, r.fid.uid) && - isGroupLeader(c.s.fs, wstat.Gid, r.fid.uid) { + if r.fid.uid == newStat.Uid && isGroupMember(r.fid.fs, wstat.Gid, r.fid.uid) || + isGroupLeader(r.fid.fs, newStat.Gid, r.fid.uid) && + isGroupLeader(r.fid.fs, wstat.Gid, r.fid.uid) { newStat.Gid = wstat.Gid } else { r.err = ErrPerm diff --git a/server_test.go b/server_test.go @@ -349,6 +349,7 @@ func TestSWalk(t *testing.T) { } fid.omode = -1 fid.path = "." + fid.fs = testfs ctx, cancel := context.WithCancel(context.Background()) defer cancel() go sWalk(ctx, c, tc) @@ -411,6 +412,7 @@ func TestSOpen(t *testing.T) { fid.omode = -1 fid.path = test.filePath fid.uid = test.uid + fid.fs = testfs f, err := testfs.walkPath(test.filePath) if err != nil { t.Error(i, err) @@ -472,6 +474,7 @@ func TestSCreate(t *testing.T) { fid.omode = -1 fid.path = test.dir fid.uid = test.uid + fid.fs = testfs tc <- &request{ifcall: test.ifcall} ofcall := (<-rc).ofcall var qid Qid @@ -712,6 +715,7 @@ func TestSRemove(t *testing.T) { defer f.Close() fid.file = f fid.uid = test.ruid + fid.fs = testfs tc <- &request{ifcall: test.ifcall} ofcall := (<-rc).ofcall switch ofcall := ofcall.(type) { @@ -762,6 +766,7 @@ func testSStat(t *testing.T, pathname string, c *conn, tc, rc chan *request) { fid.omode = -1 fid.path = pathname fid.file = f + fid.fs = testfs tc <- &request{ifcall: &TStat{Fid: 0}} ofcall := (<-rc).ofcall c.fPool.delete(0) @@ -931,6 +936,7 @@ func TestSWstat(t *testing.T) { fid.file = f fid.uid = test.uid fid.path = test.path + fid.fs = testfs tc <- &request{ifcall: test.ifcall} ofcall := (<-rc).ofcall switch ofcall := ofcall.(type) {