commit 029882122750da85f908f6159c8bbf7e27f60e6c
parent b1dc634e18ea7d53f3aa47c15ce925a4464296c3
Author: Matsuda Kenji <info@mtkn.jp>
Date: Sat, 28 Oct 2023 08:45:00 +0900
change test
Diffstat:
| A | auth_test.go | | | 13 | +++++++++++++ |
| A | export_test.go | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | server.go | | | 162 | ++++++++++++++++++++++++++++++++++++++++---------------------------------------- |
| M | server_test.go | | | 127 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| A | testfs/fs.go | | | 187 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
5 files changed, 418 insertions(+), 144 deletions(-)
diff --git a/auth_test.go b/auth_test.go
@@ -0,0 +1,12 @@
+package lib9p_test
+/*
+import (
+ "testing"
+
+ "git.mtkn.jp/lib9p"
+ "git.mtkn.jp/lib9p/client"
+)
+
+func TestAuth(t *testing.T) {
+ s := lib9p.NewServer()
+}*/
+\ No newline at end of file
diff --git a/export_test.go b/export_test.go
@@ -0,0 +1,72 @@
+package lib9p
+
+var (
+ SrvVersion = sVersion
+ RepVersion = rVersion
+ SrvAuth = sAuth
+ RepAuth = rAuth
+ SrvAttach = sAttach
+ RepAttach = rAttach
+ SrvFlush = sFlush
+ RepFlush = rFlush
+ SrvWalk = sWalk
+ RepWalk = rWalk
+ SrvOpen = sOpen
+ RepOpen = rOpen
+ SrvCreate = sCreate
+ RepCreate = rCreate
+ SrvRead = sRead
+ RepRead = rRead
+ SrvWrite = sWrite
+ RepWrite = rWrite
+ SrvClunk = sClunk
+ RepClunk = rClunk
+ SrvRemove = sRemove
+ RepRemove = rRemove
+ SrvStat = sStat
+ RepStat = rStat
+ SrvWStat = sWStat
+ RepWStat = rWStat
+)
+
+var (
+ NewTVersion = newTVersion
+ NewRVersion = newRVersion
+ NewTAuth = newTAuth
+ NewRAuth = newRAuth
+ NewTAttach = newTAttach
+ NewRAttach = newRAttach
+ NewTFlush = newTFlush
+ NewRFlush = newRFlush
+ NewTWalk = newTWalk
+ NewRWalk = newRWalk
+ NewTOpen = newTOpen
+ NewROpen = newROpen
+ NewTCreate = newTCreate
+ NewRCreate = newRCreate
+ NewTRead = newTRead
+ NewRRead = newRRead
+ NewTWrite = newTWrite
+ NewRWrite = newRWrite
+ NewTClunk = newTClunk
+ NewRClunk = newRClunk
+ NewTRemove = newTRemove
+ NewRRemove = newRRemove
+ NewTStat = newTStat
+ NewRStat = newRStat
+ NewTWStat = newTWStat
+ NewRWStat = newRWStat
+
+ NewStat = newStat
+)
+
+type BufMsg = bufMsg
+
+func (s *Server) RPool() *ReqPool { return s.rPool }
+func (s *Server) FPool() *FidPool { return s.fPool }
+
+func (rp *ReqPool) Add(tag uint16) (*Req, error) { return rp.add(tag) }
+
+func (fp *FidPool) Lookup(fid uint32) (*Fid, bool) { return fp.lookup(fid) }
+
+func (st *Stat) Size() uint16 { return st.size() }
+\ No newline at end of file
diff --git a/server.go b/server.go
@@ -204,7 +204,7 @@ func sVersion(ctx context.Context, s *Server, r *Req) {
Msize: msize,
Version: version,
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
// rVersion confirms that err is nil, and sets the server's msize to the
@@ -222,12 +222,12 @@ func sAuth(ctx context.Context, s *Server, r *Req) {
var err error
r.Afid, err = s.fPool.add(ifcall.Afid)
if err != nil {
- respond(ctx, r, ErrDupFid)
+ Respond(ctx, r, ErrDupFid)
}
if s.Auth != nil {
s.Auth(ctx, r)
} else {
- respond(ctx, r, fmt.Errorf("authentication not required"))
+ Respond(ctx, r, fmt.Errorf("authentication not required"))
return
}
}
@@ -245,49 +245,49 @@ func sAttach(ctx context.Context, s *Server, r *Req) {
ifcall := r.Ifcall.(*TAttach)
fid, err := s.fPool.add(ifcall.Fid)
if err != nil {
- respond(ctx, r, ErrDupFid)
+ Respond(ctx, r, ErrDupFid)
return
}
switch {
case s.Auth == nil && ifcall.Afid == NOFID:
case s.Auth == nil && ifcall.Afid != NOFID:
- respond(ctx, r, ErrBotch)
+ Respond(ctx, r, ErrBotch)
return
case s.Auth != nil && ifcall.Afid == NOFID:
- respond(ctx, r, fmt.Errorf("authentication required"))
+ Respond(ctx, r, fmt.Errorf("authentication required"))
return
case s.Auth != nil && ifcall.Afid != NOFID:
afid, ok := s.fPool.lookup(ifcall.Afid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
af, ok := afid.File.(*AuthFile)
if !ok {
- respond(ctx, r, fmt.Errorf("not auth file"))
+ Respond(ctx, r, fmt.Errorf("not auth file"))
return
}
if !af.AuthOK {
- respond(ctx, r, fmt.Errorf("not authenticated"))
+ Respond(ctx, r, fmt.Errorf("not authenticated"))
return
}
}
fid.File, err = s.fs.OpenFile(".", OREAD, 0)
if err != nil {
- respond(ctx, r, fmt.Errorf("open root: %v", err))
+ Respond(ctx, r, fmt.Errorf("open root: %v", err))
return
}
fid.Uid = ifcall.Uname
fid.OMode = -1 // TODO: right?
st, err := fid.File.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat root: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat root: %v", err))
return
}
r.Ofcall = &RAttach{
Qid: st.Sys().(*Stat).Qid,
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rAttach(r *Req, err error) {
@@ -298,7 +298,7 @@ func rAttach(r *Req, err error) {
}
func sFlush(ctx context.Context, s *Server, r *Req) {
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rFlush(r *Req, err error) {
@@ -315,20 +315,20 @@ func sWalk(ctx context.Context, s *Server, r *Req) {
ifcall := r.Ifcall.(*TWalk)
oldFid, ok := s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
if oldFid.OMode != -1 {
- respond(ctx, r, fmt.Errorf("cannot clone open fid"))
+ Respond(ctx, r, fmt.Errorf("cannot clone open fid"))
return
}
oldst, err := oldFid.File.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat: %v", err))
return
}
if len(ifcall.Wnames) > 0 && oldst.Sys().(*Stat).Qid.Type&QTDIR == 0 {
- respond(ctx, r, fmt.Errorf("walk on non-dir"))
+ Respond(ctx, r, fmt.Errorf("walk on non-dir"))
return
}
var newFid *Fid
@@ -339,7 +339,7 @@ func sWalk(ctx context.Context, s *Server, r *Req) {
newFid, err = s.fPool.add(ifcall.Newfid)
if err != nil {
log.Printf("alloc: %v", err)
- respond(ctx, r, fmt.Errorf("internal error"))
+ Respond(ctx, r, fmt.Errorf("internal error"))
return
}
}
@@ -369,7 +369,7 @@ func sWalk(ctx context.Context, s *Server, r *Req) {
r.Ofcall = &RWalk{
Qids: wqids[:n],
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rWalk(r *Req, err error) {
@@ -393,11 +393,11 @@ func sOpen(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
if r.Fid.OMode != -1 {
- respond(ctx, r, ErrBotch)
+ Respond(ctx, r, ErrBotch)
return
}
// Write attempt to a directory is prohibitted by the protocol.
@@ -406,12 +406,12 @@ func sOpen(ctx context.Context, s *Server, r *Req) {
// but ORCLOSE is also prohibitted by the protocol...
st, err := r.Fid.File.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat: %v", err))
return
}
qid := st.Sys().(*Stat).Qid
if qid.Type == QTDIR && ifcall.Mode != OREAD {
- respond(ctx, r, fmt.Errorf("is a directory"))
+ Respond(ctx, r, fmt.Errorf("is a directory"))
return
}
var p fs.FileMode
@@ -431,11 +431,11 @@ func sOpen(ctx context.Context, s *Server, r *Req) {
p |= AWRITE
}
if qid.Type&QTDIR != 0 && p != AREAD {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
if !hasPerm(r.Fid.File, r.Fid.Uid, p) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
if ifcall.Mode&ORCLOSE != 0 {
@@ -443,11 +443,11 @@ func sOpen(ctx context.Context, s *Server, r *Req) {
parent, err := s.fs.OpenFile(parentPath, OREAD, 0)
defer parent.Close()
if err != nil {
- respond(ctx, r, fmt.Errorf("open parent"))
+ Respond(ctx, r, fmt.Errorf("open parent"))
return
}
if !hasPerm(parent, r.Fid.Uid, AWRITE) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
}
@@ -455,7 +455,7 @@ func sOpen(ctx context.Context, s *Server, r *Req) {
Qid: qid,
Iounit: s.mSize() - IOHDRSZ,
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rOpen(r *Req, err error) {
@@ -477,26 +477,26 @@ func sCreate(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
dir := r.Fid.File
dirstat, err := dir.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat: %v", err))
return
}
if !dirstat.IsDir() {
- respond(ctx, r, fmt.Errorf("create in non-dir"))
+ Respond(ctx, r, fmt.Errorf("create in non-dir"))
return
}
if !hasPerm(dir, r.Fid.Uid, AWRITE) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
cfdir, ok := r.Fid.File.(CreaterFile)
if !ok {
- respond(ctx, r, ErrOperation)
+ Respond(ctx, r, ErrOperation)
return
}
perm := ifcall.Perm
@@ -508,25 +508,25 @@ func sCreate(ctx context.Context, s *Server, r *Req) {
}
file, err := cfdir.Create(ifcall.Name, r.Fid.Uid, ifcall.Mode, perm)
if err != nil {
- respond(ctx, r, fmt.Errorf("create: %v", err))
+ Respond(ctx, r, fmt.Errorf("create: %v", err))
return
}
if err := r.Fid.File.Close(); err != nil {
- respond(ctx, r, fmt.Errorf("close: %v", err))
+ Respond(ctx, r, fmt.Errorf("close: %v", err))
return
}
r.Fid.File = file
r.Fid.path = path.Join(r.Fid.path, ifcall.Name)
st, err := r.Fid.File.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat: %v", err))
return
}
r.Ofcall = &RCreate{
Qid: st.Sys().(*Stat).Qid,
Iounit: s.mSize() - IOHDRSZ,
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rCreate(r *Req, err error) {
if err != nil {
@@ -548,15 +548,15 @@ func sRead(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
if r.Fid.OMode == -1 {
- respond(ctx, r, fmt.Errorf("not open"))
+ Respond(ctx, r, fmt.Errorf("not open"))
return
}
if r.Fid.OMode != OREAD && r.Fid.OMode != ORDWR && r.Fid.OMode != OEXEC {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
data := make([]byte, ifcall.Count)
@@ -569,7 +569,7 @@ func sRead(ctx context.Context, s *Server, r *Req) {
fi, err := r.Fid.File.Stat()
if err != nil {
log.Printf("Stat: %v", err)
- respond(ctx, r, fmt.Errorf("internal error"))
+ Respond(ctx, r, fmt.Errorf("internal error"))
return
}
wg.Add(1)
@@ -586,7 +586,7 @@ func sRead(ctx context.Context, s *Server, r *Req) {
}
if ifcall.Offset != 0 && ifcall.Offset != r.Fid.dirOffset {
- respond(ctx, r, fmt.Errorf("invalid dir offset"))
+ Respond(ctx, r, fmt.Errorf("invalid dir offset"))
return
}
if ifcall.Offset == 0 {
@@ -623,7 +623,7 @@ func sRead(ctx context.Context, s *Server, r *Req) {
}
if err != io.EOF && err != nil {
log.Printf("sRead: %v\n", err)
- respond(ctx, r, err)
+ Respond(ctx, r, err)
return
}
}
@@ -636,7 +636,7 @@ func sRead(ctx context.Context, s *Server, r *Req) {
Count: uint32(n),
Data: data[:n],
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rRead(r *Req, err error) {
if err != nil {
@@ -649,19 +649,19 @@ func sWrite(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
if ifcall.Count > s.mSize()-IOHDRSZ {
ifcall.Count = s.mSize() - IOHDRSZ
}
if !hasPerm(r.Fid.File, r.Fid.Uid, AWRITE) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
omode := r.Fid.OMode & 3
if omode != OWRITE && omode != ORDWR {
- respond(ctx, r, fmt.Errorf("write on fid with open mode 0x%x", r.Fid.OMode))
+ Respond(ctx, r, fmt.Errorf("write on fid with open mode 0x%x", r.Fid.OMode))
return
}
ofcall := new(RWrite)
@@ -677,19 +677,19 @@ func sWrite(ctx context.Context, s *Server, r *Req) {
case io.WriterAt:
n, err := file.WriteAt(ifcall.Data, int64(ifcall.Offset))
if err != nil {
- respond(ctx, r, fmt.Errorf("write: %v", err))
+ Respond(ctx, r, fmt.Errorf("write: %v", err))
return
}
ofcall.Count = uint32(n)
case io.Writer:
n, err := file.Write(ifcall.Data)
if err != nil {
- respond(ctx, r, fmt.Errorf("write: %v", err))
+ Respond(ctx, r, fmt.Errorf("write: %v", err))
return
}
ofcall.Count = uint32(n)
default:
- respond(ctx, r, ErrOperation)
+ Respond(ctx, r, ErrOperation)
return
}
wg.Done()
@@ -699,7 +699,7 @@ func sWrite(ctx context.Context, s *Server, r *Req) {
case <-ctx.Done():
}
r.Ofcall = ofcall
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rWrite(r *Req, err error) {
@@ -714,12 +714,12 @@ func sClunk(ctx context.Context, s *Server, r *Req) {
ifcall := r.Ifcall.(*TClunk)
_, ok := s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
s.fPool.delete(ifcall.Fid)
r.Ofcall = &RClunk{}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rClunk(r *Req, err error) {
@@ -733,32 +733,32 @@ func sRemove(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
defer s.fPool.delete(ifcall.Fid)
parentPath := path.Dir(r.Fid.path)
parent, err := s.fs.OpenFile(parentPath, OREAD, 0)
if err != nil {
- respond(ctx, r, fmt.Errorf("open parent: %v", err))
+ Respond(ctx, r, fmt.Errorf("open parent: %v", err))
return
}
defer parent.Close()
if !hasPerm(parent, r.Fid.Uid, AWRITE) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
rfile, ok := r.Fid.File.(RemoverFile)
if !ok {
- respond(ctx, r, ErrOperation)
+ Respond(ctx, r, ErrOperation)
return
}
if err := rfile.Remove(); err != nil {
- respond(ctx, r, fmt.Errorf("remove: %v", err))
+ Respond(ctx, r, fmt.Errorf("remove: %v", err))
return
}
r.Ofcall = &RRemove{}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rRemove(r *Req, err error) {
if err != nil {
@@ -771,19 +771,19 @@ func sStat(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
fileInfo, err := r.Fid.File.Stat()
if err != nil {
log.Printf("stat %v: %v", r.Fid.File, err)
- respond(ctx, r, fmt.Errorf("internal error"))
+ Respond(ctx, r, fmt.Errorf("internal error"))
return
}
r.Ofcall = &RStat{
Stat: fileInfo.Sys().(*Stat),
}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rStat(r *Req, err error) {
@@ -797,18 +797,18 @@ func sWStat(ctx context.Context, s *Server, r *Req) {
var ok bool
r.Fid, ok = s.fPool.lookup(ifcall.Fid)
if !ok {
- respond(ctx, r, ErrUnknownFid)
+ Respond(ctx, r, ErrUnknownFid)
return
}
wsfile, ok := r.Fid.File.(WriterStatFile)
if !ok {
- respond(ctx, r, ErrOperation)
+ Respond(ctx, r, ErrOperation)
return
}
wstat := ifcall.Stat
fi, err := r.Fid.File.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat: %v", err))
return
}
newStat := fi.Sys().(*Stat)
@@ -816,33 +816,33 @@ func sWStat(ctx context.Context, s *Server, r *Req) {
wstat.Qid.Type != QidType(^uint8(0)) || wstat.Qid.Vers != ^uint32(0) ||
wstat.Qid.Path != ^uint64(0) || wstat.Atime != ^uint32(0) ||
wstat.Uid != "" || wstat.Muid != "" {
- respond(ctx, r, fmt.Errorf("operation not permitted"))
+ Respond(ctx, r, fmt.Errorf("operation not permitted"))
return
}
if wstat.Name != "" {
parentPath := path.Dir(r.Fid.path)
parent, err := s.fs.OpenFile(parentPath, OREAD, 0)
if err != nil {
- respond(ctx, r, fmt.Errorf("get parent: %v", err))
+ Respond(ctx, r, fmt.Errorf("get parent: %v", err))
return
}
if !hasPerm(parent, r.Fid.Uid, AWRITE) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
children, err := getChildren(s.fs, parentPath)
if err != nil {
- respond(ctx, r, fmt.Errorf("get children: %v", err))
+ Respond(ctx, r, fmt.Errorf("get children: %v", err))
return
}
for _, f := range children {
s, err := f.Stat()
if err != nil {
- respond(ctx, r, fmt.Errorf("stat: %v", err))
+ Respond(ctx, r, fmt.Errorf("stat: %v", err))
return
}
if s.Name() == wstat.Name {
- respond(ctx, r, fmt.Errorf("file already exists"))
+ Respond(ctx, r, fmt.Errorf("file already exists"))
return
}
}
@@ -850,7 +850,7 @@ func sWStat(ctx context.Context, s *Server, r *Req) {
}
if wstat.Length != ^int64(0) {
if fi.IsDir() || !hasPerm(r.Fid.File, r.Fid.Uid, AWRITE) {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
newStat.Length = wstat.Length
@@ -858,11 +858,11 @@ func sWStat(ctx context.Context, s *Server, r *Req) {
if wstat.Mode != FileMode(^uint32(0)) {
// 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 {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
if wstat.Mode&fs.ModeDir != newStat.Mode&fs.ModeDir {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
newStat.Mode = wstat.Mode
@@ -870,23 +870,23 @@ func sWStat(ctx context.Context, s *Server, r *Req) {
if wstat.Mtime != ^uint32(0) {
// 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 {
- respond(ctx, r, ErrPerm)
+ Respond(ctx, r, ErrPerm)
return
}
newStat.Mtime = wstat.Mtime
}
if wstat.Gid != "" {
// TODO implement
- respond(ctx, r, fmt.Errorf("not implemented"))
+ Respond(ctx, r, fmt.Errorf("not implemented"))
return
}
err = wsfile.WStat(newStat)
if err != nil {
- respond(ctx, r, fmt.Errorf("wstat: %v", err))
+ Respond(ctx, r, fmt.Errorf("wstat: %v", err))
return
}
r.Ofcall = &RWStat{}
- respond(ctx, r, nil)
+ Respond(ctx, r, nil)
}
func rWStat(r *Req, err error) {
@@ -916,7 +916,7 @@ L:
go func() {
switch r.Ifcall.(type) {
default:
- respond(ctx1, r, fmt.Errorf("unknown message type: %d", r.Ifcall.Type()))
+ Respond(ctx1, r, fmt.Errorf("unknown message type: %d", r.Ifcall.Type()))
case *TVersion:
sVersion(ctx1, s, r)
case *TAuth:
@@ -952,10 +952,10 @@ L:
}
}
-// Respond responds to the request r with the message r.Ofcall if err is nil,
+// Respond Responds to the request r with the message r.Ofcall if err is nil,
// or if err is not nil, with the Rerror with the error message.
// If r is nil, or both r.Ofcall and err are nil it panics.
-func respond(ctx context.Context, r *Req, err error) {
+func Respond(ctx context.Context, r *Req, err error) {
switch r.Ifcall.(type) {
default:
panic(fmt.Errorf("bug: r.Ifcall: %v", r.Ifcall))
diff --git a/server_test.go b/server_test.go
@@ -4,7 +4,8 @@ import (
"context"
"fmt"
"io"
- "path/filepath"
+ "path"
+ "strings"
"testing"
"git.mtkn.jp/lib9p"
@@ -16,55 +17,55 @@ func newReq(s *lib9p.Server, msg lib9p.Msg) (*lib9p.Req, error) {
if err != nil {
return nil, fmt.Errorf("lib9p.ReqPool.add(%d): %w", msg.GetTag(), err)
}
- r.srv = s
- r.tag = msg.GetTag()
- r.ifcall = msg
+ r.Srv = s
+ r.Tag = msg.GetTag()
+ r.Ifcall = msg
return r, nil
}
func handleReq(ctx context.Context, s *lib9p.Server, r *lib9p.Req) {
- switch r.ifcall.(type) {
+ switch r.Ifcall.(type) {
default:
- respond(ctx, r, fmt.Errorf("unknown message type: %d", r.ifcall.Type()))
- case *TVersion:
- sVersion(ctx, s, r)
- case *TAuth:
- sAuth(ctx, s, r)
- case *TAttach:
- sAttach(ctx, s, r)
- case *TWalk:
- sWalk(ctx, s, r)
- case *TOpen:
- sOpen(ctx, s, r)
- case *TCreate:
- sCreate(ctx, s, r)
- case *TRead:
- sRead(ctx, s, r)
- case *TWrite:
- sWrite(ctx, s, r)
- case *TClunk:
- sClunk(ctx, s, r)
- case *TRemove:
- sRemove(ctx, s, r)
- case *TStat:
- sStat(ctx, s, r)
- case *TWStat:
- sWStat(ctx, s, r)
+ lib9p.Respond(ctx, r, fmt.Errorf("unknown message type: %d", r.Ifcall.Type()))
+ case *lib9p.TVersion:
+ lib9p.SrvVersion(ctx, s, r)
+ case *lib9p.TAuth:
+ lib9p.SrvAuth(ctx, s, r)
+ case *lib9p.TAttach:
+ lib9p.SrvAttach(ctx, s, r)
+ case *lib9p.TWalk:
+ lib9p.SrvWalk(ctx, s, r)
+ case *lib9p.TOpen:
+ lib9p.SrvOpen(ctx, s, r)
+ case *lib9p.TCreate:
+ lib9p.SrvCreate(ctx, s, r)
+ case *lib9p.TRead:
+ lib9p.SrvRead(ctx, s, r)
+ case *lib9p.TWrite:
+ lib9p.SrvWrite(ctx, s, r)
+ case *lib9p.TClunk:
+ lib9p.SrvClunk(ctx, s, r)
+ case *lib9p.TRemove:
+ lib9p.SrvRemove(ctx, s, r)
+ case *lib9p.TStat:
+ lib9p.SrvStat(ctx, s, r)
+ case *lib9p.TWStat:
+ lib9p.SrvWStat(ctx, s, r)
}
}
// This function does the actual work for TestWalk().
-func testWalk(t *testing.T, fs *testfs.TestFS, path string, file *testfs.TestFile) {
- t.Logf("walk %s", path)
- f, err := fs.walk(split9path(path))
+func testWalk(t *testing.T, fs *testfs.TestFS, pathname string, file *testfs.TestFile) {
+ t.Logf("walk %s", pathname)
+ f, err := fs.Walk(strings.Split(pathname, "/"))
if err != nil {
- t.Errorf("open %s: %v", path, err)
+ t.Errorf("open %s: %v", pathname, err)
}
if f != file {
- t.Errorf("open %s: wrong file", path)
+ t.Errorf("open %s: wrong file", pathname)
}
for _, child := range file.Children {
- childpath := filepath.Join(path, child.St.Name)
+ childpath := path.Join(pathname, child.St.Name)
testWalk(t, fs, childpath, child)
}
}
@@ -73,7 +74,7 @@ func testWalk(t *testing.T, fs *testfs.TestFS, path string, file *testfs.TestFil
// checks if all files can be opened without error and if
// the opened file is the same as the file accessed via testFS.child
func TestWalk(t *testing.T) {
- testWalk(t, fsys, ".", fsys.Root)
+ testWalk(t, testfs.FS, ".", testfs.FS.Root)
}
func TestServer(t *testing.T) {
@@ -84,81 +85,81 @@ func TestServer(t *testing.T) {
defer cr.Close()
defer sw.Close()
msg := []lib9p.Msg{
- &TVersion{
- Tag: NOTAG,
+ &lib9p.TVersion{
+ Tag: lib9p.NOTAG,
Msize: 1024,
Version: "9P2000",
},
- &TAttach{
+ &lib9p.TAttach{
Tag: 0,
Fid: 0,
- Afid: NOFID,
+ Afid: lib9p.NOFID,
Uname: "glenda",
Aname: "",
},
- &TStat{
+ &lib9p.TStat{
Tag: 0,
Fid: 0,
},
- &TWalk{
+ &lib9p.TWalk{
Tag: 0,
Fid: 0,
Newfid: 1,
Wnames: []string{},
},
- &TOpen{
+ &lib9p.TOpen{
Tag: 0,
Fid: 1,
- Mode: OREAD,
+ Mode: lib9p.OREAD,
},
- &TRead{
+ &lib9p.TRead{
Tag: 0,
Fid: 1,
Offset: 0,
Count: 1024,
},
- &TClunk{
+ &lib9p.TClunk{
Fid: 1,
},
- &TWalk{
+ &lib9p.TWalk{
Tag: 0,
Fid: 0,
Newfid: 1,
Wnames: []string{"dir", "file"},
},
- &TOpen{
+ &lib9p.TOpen{
Tag: 0,
Fid: 1,
- Mode: ORDWR,
+ Mode: lib9p.ORDWR,
},
- &TRead{
+ &lib9p.TRead{
Tag: 0,
Fid: 1,
Offset: 0,
Count: 1024,
},
- &TWrite{
+ &lib9p.TWrite{
Tag: 0,
Fid: 1,
Offset: 2,
Count: 4,
Data: []byte("a"),
},
- &TRead{
+ &lib9p.TRead{
Tag: 0,
Fid: 1,
Offset: 0,
Count: 1024,
},
}
- s := NewServer(fsys, 1024, sr, sw)
+ s := lib9p.NewServer(testfs.FS, 1024, sr, sw)
for _, m := range msg {
r, err := newReq(s, m)
if err != nil {
t.Fatalf("newReq: %v", err)
return
}
- t.Logf("<-- %v\n", r.ifcall)
+ t.Logf("<-- %v\n", r.Ifcall)
go handleReq(context.Background(), s, r)
buf := make([]byte, 1024)
@@ -166,25 +167,25 @@ func TestServer(t *testing.T) {
if err != nil {
t.Fatalf("read: %v", err)
}
- t.Logf("--> %v\n", buflib9p.Msg(buf))
+ t.Logf("--> %v\n", lib9p.BufMsg(buf))
- if buflib9p.Msg(buf).Type() == Rread {
- rread := newRRead(buf)
+ if lib9p.BufMsg(buf).Type() == lib9p.Rread {
+ rread := lib9p.NewRRead(buf)
data := rread.Data
- fid, ok := s.fPool.lookup(m.(*TRead).Fid)
+ fid, ok := s.FPool().Lookup(m.(*lib9p.TRead).Fid)
if !ok {
- t.Fatalf("lookup fid %d", m.(*TRead).Fid)
+ t.Fatalf("lookup fid %d", m.(*lib9p.TRead).Fid)
}
st, err := fid.File.Stat()
if err != nil {
t.Errorf("stat: %v", err)
continue
}
- if st.Sys().(*Stat).Qid.Type&QTDIR != 0 {
+ if st.Sys().(*lib9p.Stat).Qid.Type&lib9p.QTDIR != 0 {
for i := 0; i < len(data); {
- stat := newStat(data[i:])
+ stat := lib9p.NewStat(data[i:])
t.Logf("stat: %v", stat)
- i += int(stat.size()) + 2
+ i += int(stat.Size()) + 2
}
} else {
t.Logf("content: %s", string(data))
diff --git a/testfs/fs.go b/testfs/fs.go
@@ -0,0 +1,187 @@
+package testfs
+
+import (
+ "bytes"
+ "fmt"
+ "io/fs"
+ "strings"
+ "time"
+
+ "git.mtkn.jp/lib9p"
+)
+
+const sleepTime = 1 * time.Second
+
+type TestFile struct {
+ Fsys *TestFS
+ Parent *TestFile
+ Children []*TestFile
+ Content []byte
+ Reader *bytes.Reader
+
+ St lib9p.Stat
+}
+
+func (f *TestFile) Stat() (*lib9p.FileInfo, error) {
+ return &lib9p.FileInfo{Stat: f.St}, nil
+}
+func (f *TestFile) Close() error {
+ f.Reader = nil
+ return nil
+}
+
+func (f *TestFile) Read(b []byte) (int, error) {
+ if f.Fsys.Slow {
+ time.Sleep(sleepTime)
+ }
+ return f.Reader.Read(b)
+}
+
+func (f *TestFile) ReadAt(b []byte, off int64) (n int, err error) {
+ if f.Fsys.Slow {
+ time.Sleep(sleepTime)
+ }
+ return f.Reader.ReadAt(b, off)
+}
+
+func (f *TestFile) ReadDir(n int) ([]*lib9p.DirEntry, error) {
+ de := make([]*lib9p.DirEntry, len(f.Children))
+ for i, c := range f.Children {
+ de[i], _ = c.Stat()
+ }
+ return de, nil
+}
+
+func (f *TestFile) WriteAt(p []byte, off int64) (int, error) {
+ if f.Fsys.Slow {
+ time.Sleep(sleepTime)
+ }
+ if f.Reader == nil {
+ return 0, fmt.Errorf("not open")
+ }
+ if off < 0 || off > int64(len(f.Content)) {
+ return 0, fmt.Errorf("bad offset")
+ }
+
+ if off+int64(len(p)) > int64(len(f.Content)) {
+ newcon := make([]byte, off+int64(len(p)))
+ copy(newcon, f.Content)
+ f.Content = newcon
+ }
+ copy(f.Content[off:], p)
+ f.Reader.Reset(f.Content)
+ return len(p), nil
+}
+
+type TestFS struct {
+ Root *TestFile
+ Slow bool
+}
+
+func (fs *TestFS) OpenFile(path string, omode lib9p.OpenMode, perm fs.FileMode) (lib9p.File, error) {
+ wnames := strings.Split(path, "/")
+ f, err := fs.Walk(wnames)
+ if err != nil {
+ return nil, fmt.Errorf("walk: %v", err)
+ }
+ f.Reader = bytes.NewReader(f.Content)
+ return f, nil
+}
+
+func (fs *TestFS) Walk(wnames []string) (*TestFile, error) {
+ if len(wnames) == 1 && (wnames[0] == "." || wnames[0] == "") {
+ return fs.Root, nil
+ }
+ cwd := fs.Root
+L:
+ for i, name := range wnames {
+ for _, child := range cwd.Children {
+ if child.St.Name == name {
+ cwd = child
+ continue L
+ }
+ }
+ return nil, fmt.Errorf("%s not found", strings.Join(wnames[:i+1], "/"))
+ }
+ return cwd, nil
+}
+
+var FS *TestFS
+
+func init() {
+ FS = &TestFS{
+ Root: &TestFile{
+ St: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 0, Type: lib9p.QTDIR},
+ Mode: lib9p.FileMode(fs.ModeDir | 0755),
+ Name: "root",
+ Uid: "glenda",
+ Gid: "glenda",
+ Muid: "glenda",
+ },
+ Children: []*TestFile{
+ &TestFile{
+ Content: []byte("a\n"),
+ St: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 1, Type: lib9p.QTFILE},
+ Mode: lib9p.FileMode(0644),
+ Name: "a",
+ Uid: "glenda",
+ Gid: "glenda",
+ Muid: "glenda",
+ },
+ },
+ &TestFile{
+ Content: []byte("b\n"),
+ St: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 2, Type: lib9p.QTFILE},
+ Mode: lib9p.FileMode(0400),
+ Name: "b",
+ Uid: "ken",
+ Gid: "ken",
+ Muid: "ken",
+ },
+ },
+ &TestFile{
+ St: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 3, Type: lib9p.QTDIR},
+ Mode: lib9p.FileMode(fs.ModeDir | 0755),
+ Name: "dir",
+ Uid: "rob",
+ Gid: "rob",
+ Muid: "rob",
+ },
+ Children: []*TestFile{
+ &TestFile{
+ Content: []byte("unko\n"),
+ St: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 4, Type: lib9p.QTFILE},
+ Mode: lib9p.FileMode(0666),
+ Name: "file",
+ Uid: "brian",
+ Gid: "brian",
+ Muid: "dennis",
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ SetFsysAndParent(FS, nil)
+}
+
+// SetFsysAndParent sets file.fsys and file.parent for every file in the fsys.
+// Pass nil as file to setup entire file system.
+func SetFsysAndParent(fsys *TestFS, file *TestFile) {
+ if file == nil {
+ file = fsys.Root
+ file.Parent = fsys.Root
+ file.Fsys = fsys
+ }
+ for _, child := range file.Children {
+ child.Parent = file
+ child.Fsys = fsys
+ SetFsysAndParent(fsys, child)
+ }
+}