commit 7946abf959f1d81ec0181079ad705971cbdd551c
parent 0c30f8deceab890728459eb52601f676467393c4
Author: Matsuda Kenji <info@mtkn.jp>
Date: Tue, 9 Jan 2024 12:01:21 +0900
support aname in attach
Diffstat:
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) {