lib9p

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

commit 7a7f18f9bc9ba240e32963b4507c39d23ac3e78c
parent 8a84f2d965a87e77b329f5ee8fc36bb770396eff
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Mon, 25 Dec 2023 18:39:53 +0900

delete r... functions

Diffstat:
Mauth_test.go | 15+++++++++------
Mserver.go | 359+++++++++++++++++++++++++++----------------------------------------------------
2 files changed, 132 insertions(+), 242 deletions(-)

diff --git a/auth_test.go b/auth_test.go @@ -9,6 +9,9 @@ import ( "git.mtkn.jp/lib9p/testfs" ) +// TODO: this test sometimes fails. +// err: unknown fid, or err: not authenticated. +// maybe there is some race condition or something. func TestAuth(t *testing.T) { conn := testfs.SetupConn() defer conn.Close() @@ -55,27 +58,27 @@ func TestAuth(t *testing.T) { } _, err = conn.C.Auth(ctx, 0, 0, "kenji", "") if err != nil { - t.Error(err) + t.Fatal(err) } _, err = conn.C.Attach(ctx, 0, 1, 0, "kenji", "") if err == nil { - t.Error("authentication skipped") + t.Fatal("authentication skipped") } _, _, err = conn.C.Open(ctx, 0, 0, lib9p.ORDWR) if err != nil { - t.Error(err) + t.Fatal(err) } _, err = conn.C.Write(ctx, 0, 0, 0, 5, []byte("kenji")) if err != nil { - t.Error(err) + t.Fatal(err) } _, err = conn.C.Write(ctx, 0, 0, 0, 8, []byte("password")) if err != nil { - t.Error(err) + t.Fatal(err) } _, err = conn.C.Attach(ctx, 0, 1, 0, "kenji", "") if err != nil { - t.Error(err) + t.Fatal(err) } } diff --git a/server.go b/server.go @@ -445,7 +445,7 @@ func sOpen(ctx context.Context, s *Server, c <-chan *Req) { return } var ( - p fs.FileMode + p fs.FileMode err error qid Qid st fs.FileInfo @@ -548,9 +548,6 @@ func sOpen(ctx context.Context, s *Server, c <-chan *Req) { } func sCreate(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rCreate(ctx, rc) for { select { case <-ctx.Done(): @@ -559,80 +556,70 @@ func sCreate(ctx context.Context, s *Server, c <-chan *Req) { if !ok { return } + var ( + st fs.FileInfo + dirstat fs.FileInfo + err error + file File + cfs CreaterFS + cpath string + perm FileMode + dirperm FileMode + ) ifcall := r.Ifcall.(*TCreate) r.Fid, ok = s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } - dirstat, err := fs.Stat(ExportFS{s.fs}, r.Fid.path) + dirstat, err = fs.Stat(ExportFS{s.fs}, r.Fid.path) if err != nil { r.err = fmt.Errorf("stat: %v", err) - rc <- r - continue + goto resp } if !dirstat.IsDir() { r.err = fmt.Errorf("create in non-dir") - rc <- r - continue + goto resp } if !hasPerm(s.fs, dirstat, r.Fid.Uid, AWRITE) { r.err = ErrPerm - rc <- r - continue + goto resp } - cfs, ok := s.fs.(CreaterFS) + cfs, ok = s.fs.(CreaterFS) if !ok { r.err = ErrOperation - rc <- r - continue + goto resp } - perm := ifcall.Perm - dirperm := dirstat.Mode() + perm = ifcall.Perm + dirperm = dirstat.Mode() if perm&fs.ModeDir == 0 { perm &= ^FileMode(0666) | (dirperm & FileMode(0666)) } else { perm &= ^FileMode(0777) | (dirperm & FileMode(0777)) } - cpath := path.Join(r.Fid.path, ifcall.Name) - file, err := cfs.Create(cpath, r.Fid.Uid, ifcall.Mode, perm) + cpath = path.Join(r.Fid.path, ifcall.Name) + file, err = cfs.Create(cpath, r.Fid.Uid, ifcall.Mode, perm) if err != nil { r.err = fmt.Errorf("create: %v", err) - rc <- r - continue + goto resp } r.Fid.File = file r.Fid.path = cpath r.Fid.OMode = ifcall.Mode - st, err := r.Fid.File.Stat() + st, err = r.Fid.File.Stat() if err != nil { r.err = fmt.Errorf("stat: %v", err) - rc <- r - continue + goto resp } r.Ofcall = &RCreate{ Qid: st.Sys().(*Stat).Qid, Iounit: s.mSize() - IOHDRSZ, } - rc <- r - } - } -} - -func rCreate(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { setError(r, r.err) } - r.Srv.respChan <- r + s.respChan <- r } } } @@ -640,14 +627,18 @@ func rCreate(ctx context.Context, c <-chan *Req) { // TODO: I think the file should be locked while reading. // or should the undeterminism left for the client side? func sRead(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rRead(ctx, rc) for { select { case <-ctx.Done(): return case r, ok := <-c: + var ( + fi fs.FileInfo + err error + data []byte + errc chan error + n int + ) if !ok { return } @@ -655,28 +646,23 @@ func sRead(ctx context.Context, s *Server, c <-chan *Req) { r.Fid, ok = s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } if r.Fid.OMode == -1 { r.err = fmt.Errorf("not open") - rc <- r - continue + goto resp } if r.Fid.OMode != OREAD && r.Fid.OMode != ORDWR && r.Fid.OMode != OEXEC { r.err = ErrPerm - rc <- r - continue + goto resp } - fi, err := r.Fid.File.Stat() + fi, err = r.Fid.File.Stat() if err != nil { r.err = fmt.Errorf("stat: %v", err) - rc <- r - continue + goto resp } - data := make([]byte, ifcall.Count) - errc := make(chan error) - var n int + data = make([]byte, ifcall.Count) + errc = make(chan error) go func() { defer close(errc) if fi.IsDir() { @@ -729,8 +715,7 @@ func sRead(ctx context.Context, s *Server, c <-chan *Req) { case err := <-errc: if err != nil { r.err = err - rc <- r - continue + goto resp } case <-r.Done: continue @@ -739,33 +724,17 @@ func sRead(ctx context.Context, s *Server, c <-chan *Req) { Count: uint32(n), Data: data[:n], } - rc <- r - } - } -} - -func rRead(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { setError(r, r.err) } - r.Srv.respChan <- r + s.respChan <- r } } } // TODO: I think the file should be locked while reading. func sWrite(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rWrite(ctx, rc) for { select { case <-ctx.Done(): @@ -774,24 +743,27 @@ func sWrite(ctx context.Context, s *Server, c <-chan *Req) { if !ok { return } + var ( + ofcall *RWrite + errc chan error + omode OpenMode + ) ifcall := r.Ifcall.(*TWrite) r.Fid, ok = s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } if ifcall.Count > s.mSize()-IOHDRSZ { ifcall.Count = s.mSize() - IOHDRSZ } - omode := r.Fid.OMode & 3 + omode = r.Fid.OMode & 3 if omode != OWRITE && omode != ORDWR { r.err = fmt.Errorf("write on fid with open mode 0x%x", r.Fid.OMode) - rc <- r - continue + goto resp } - ofcall := new(RWrite) - errc := make(chan error) + ofcall = new(RWrite) + errc = make(chan error) go func() { defer close(errc) switch file := r.Fid.File.(type) { @@ -818,39 +790,22 @@ func sWrite(ctx context.Context, s *Server, c <-chan *Req) { case err := <-errc: if err != nil { r.err = err - rc <- r - continue + goto resp } case <-r.Done: continue } r.Ofcall = ofcall - rc <- r - } - } -} - -func rWrite(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { setError(r, r.err) } - r.Srv.respChan <- r + s.respChan <- r } } } func sClunk(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rClunk(ctx, rc) for { select { case <-ctx.Done(): @@ -863,45 +818,27 @@ func sClunk(ctx context.Context, s *Server, c <-chan *Req) { fid, ok := s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } s.fPool.delete(ifcall.Fid) if fid.OMode != -1 { if err := fid.File.Close(); err != nil { r.err = fmt.Errorf("close: %v", err) - rc <- r - continue + goto resp } } r.Ofcall = &RClunk{} - rc <- r - } - } -} - -func rClunk(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { log.Printf("clunk: %v", r.err) r.Ofcall = &RClunk{} } - r.Srv.respChan <- r + s.respChan <- r } } } func sRemove(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rRemove(ctx, rc) for { select { case <-ctx.Done(): @@ -910,67 +847,52 @@ func sRemove(ctx context.Context, s *Server, c <-chan *Req) { if !ok { return } + var ( + parentPath string + pstat fs.FileInfo + err error + rfs RemoverFS + ) ifcall := r.Ifcall.(*TRemove) r.Fid, ok = s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } s.fPool.delete(ifcall.Fid) if r.Fid.OMode != -1 { r.Fid.File.Close() } - parentPath := path.Dir(r.Fid.path) - pstat, err := fs.Stat(ExportFS{s.fs}, parentPath) + parentPath = path.Dir(r.Fid.path) + pstat, err = fs.Stat(ExportFS{s.fs}, parentPath) if err != nil { r.err = fmt.Errorf("stat parent: %v", err) - rc <- r - continue + goto resp } if !hasPerm(s.fs, pstat, r.Fid.Uid, AWRITE) { r.err = ErrPerm - rc <- r - continue + goto resp } - rfs, ok := s.fs.(RemoverFS) + rfs, ok = s.fs.(RemoverFS) if !ok { r.err = ErrOperation - rc <- r - continue + goto resp } - if err := rfs.Remove(r.Fid.path); err != nil { + if err = rfs.Remove(r.Fid.path); err != nil { r.err = fmt.Errorf("remove: %v", err) - rc <- r - continue + goto resp } r.Ofcall = &RRemove{} - rc <- r - } - } -} - -func rRemove(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { setError(r, r.err) } - r.Srv.respChan <- r + s.respChan <- r } } } func sStat(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rStat(ctx, rc) for { select { case <-ctx.Done(): @@ -979,48 +901,34 @@ func sStat(ctx context.Context, s *Server, c <-chan *Req) { if !ok { return } + var ( + fi fs.FileInfo + err error + ) ifcall := r.Ifcall.(*TStat) r.Fid, ok = s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } - fi, err := fs.Stat(ExportFS{s.fs}, r.Fid.path) + fi, err = fs.Stat(ExportFS{s.fs}, r.Fid.path) if err != nil { r.err = fmt.Errorf("stat: %v", err) - rc <- r - continue + goto resp } r.Ofcall = &RStat{ Stat: fi.Sys().(*Stat), } - rc <- r - } - } -} - -func rStat(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { setError(r, r.err) } - r.Srv.respChan <- r + s.respChan <- r } } } func sWStat(ctx context.Context, s *Server, c <-chan *Req) { - rc := make(chan *Req) - defer close(rc) - go rWStat(ctx, rc) for { select { case <-ctx.Done(): @@ -1029,37 +937,40 @@ func sWStat(ctx context.Context, s *Server, c <-chan *Req) { if !ok { return } + var ( + wsfile WriterStatFile + wstat *Stat + newStat *Stat + fi fs.FileInfo + err error + ) ifcall := r.Ifcall.(*TWStat) r.Fid, ok = s.fPool.lookup(ifcall.Fid) if !ok { r.err = ErrUnknownFid - rc <- r - continue + goto resp } if r.Fid.OMode == -1 { var err error r.Fid.File, err = s.fs.OpenFile(r.Fid.path, OREAD) if err != nil { r.err = fmt.Errorf("open: %v", err) - rc <- r - continue + goto resp } defer r.Fid.File.Close() } - wsfile, ok := r.Fid.File.(WriterStatFile) + wsfile, ok = r.Fid.File.(WriterStatFile) if !ok { r.err = ErrOperation - rc <- r - continue + goto resp } - wstat := ifcall.Stat - fi, err := r.Fid.File.Stat() + wstat = ifcall.Stat + fi, err = r.Fid.File.Stat() if err != nil { r.err = fmt.Errorf("stat: %v", err) - rc <- r - continue + goto resp } - newStat := fi.Sys().(*Stat) + newStat = fi.Sys().(*Stat) if wstat.Type != ^uint16(0) && wstat.Type != newStat.Type || wstat.Dev != ^uint32(0) && wstat.Dev != newStat.Dev || wstat.Qid.Type != QidType(^uint8(0)) && wstat.Qid.Type != newStat.Qid.Type || @@ -1069,21 +980,18 @@ func sWStat(ctx context.Context, s *Server, c <-chan *Req) { wstat.Uid != "" && wstat.Uid != newStat.Uid || wstat.Muid != "" && wstat.Muid != newStat.Muid { r.err = fmt.Errorf("operation not permitted") - rc <- r - continue + goto resp } if wstat.Name != "" && newStat.Name != wstat.Name { parentPath := path.Dir(r.Fid.path) pstat, err := fs.Stat(ExportFS{s.fs}, parentPath) if err != nil { r.err = fmt.Errorf("stat parent: %v", err) - rc <- r - continue + goto resp } if !hasPerm(s.fs, pstat, r.Fid.Uid, AWRITE) { r.err = ErrPerm - rc <- r - continue + goto resp } // TODO: I think 9P protocol prohibits renaming to existent file. // Wstat(9P) in p9p says: @@ -1091,27 +999,24 @@ func sWStat(ctx context.Context, s *Server, c <-chan *Req) { // an existing file. // but 9pfs, 9pfuse does the rename when used with `git init`. /* - children, err := fs.Glob(ExportFS{s.fs}, path.Join(parentPath, "*")) - if err != nil { - r.err = fmt.Errorf("glob children: %v", err) - rc <- r - continue - } - for _, f := range children { - if path.Base(f) == wstat.Name { - r.err = fmt.Errorf("file already exists") - rc <- r - continue - } + children, err := fs.Glob(ExportFS{s.fs}, path.Join(parentPath, "*")) + if err != nil { + r.err = fmt.Errorf("glob children: %v", err) + goto resp + } + for _, f := range children { + if path.Base(f) == wstat.Name { + r.err = fmt.Errorf("file already exists") + goto resp } + } */ newStat.Name = wstat.Name } if wstat.Length != ^int64(0) && wstat.Length != newStat.Length { if fi.IsDir() || !hasPerm(s.fs, fi, r.Fid.Uid, AWRITE) { r.err = ErrPerm - rc <- r - continue + goto resp } newStat.Length = wstat.Length } @@ -1119,13 +1024,11 @@ func sWStat(ctx context.Context, s *Server, c <-chan *Req) { // the owner of the file or the group leader of the file's group. if r.Fid.Uid != newStat.Uid && r.Fid.Uid != newStat.Gid { r.err = ErrPerm - rc <- r - continue + goto resp } if wstat.Mode&fs.ModeDir != newStat.Mode&fs.ModeDir { r.err = ErrPerm - rc <- r - continue + goto resp } newStat.Mode = wstat.Mode } @@ -1133,8 +1036,7 @@ func sWStat(ctx context.Context, s *Server, c <-chan *Req) { // the owner of the file or the group leader of the file's group. if r.Fid.Uid != newStat.Uid && r.Fid.Uid != newStat.Gid { r.err = ErrPerm - rc <- r - continue + goto resp } newStat.Mtime = wstat.Mtime } @@ -1150,35 +1052,20 @@ func sWStat(ctx context.Context, s *Server, c <-chan *Req) { newStat.Gid = wstat.Gid } else { r.err = ErrPerm - rc <- r - continue + goto resp } } err = wsfile.WStat(newStat) if err != nil { r.err = fmt.Errorf("wstat: %v", err) - rc <- r - continue + goto resp } r.Ofcall = &RWStat{} - rc <- r - } - } -} - -func rWStat(ctx context.Context, c <-chan *Req) { - for { - select { - case <-ctx.Done(): - return - case r, ok := <-c: - if !ok { - return - } + resp: if r.err != nil { setError(r, r.err) } - r.Srv.respChan <- r + s.respChan <- r } } }