lib9p

Go 9P library.
Log | Files | Refs

commit 9a378c874e3eab72b585a8d67c738ec60babb95b
parent c9d25ef21910519cd1efa5baa16a0be4e4d6ba88
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Mon, 14 Aug 2023 12:00:11 +0900

add walk

Diffstat:
Mfcall.go | 51+++++++++++++++++++++++++++++++++++----------------
Mfile.go | 43++++---------------------------------------
Mfs.go | 62+++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mparse.go | 1+
Mserver.go | 44++++++++++++++++++++------------------------
Atestdir/a | 0
Atestdir/b | 0
Atestdir/c | 0
Atestdir/d/unko | 1+
9 files changed, 116 insertions(+), 86 deletions(-)

diff --git a/fcall.go b/fcall.go @@ -78,11 +78,11 @@ type Msg interface { // bufMsg is Msg with just an array of bytes. type bufMsg []byte -func (msg bufMsg) Size() uint32 { return gbit32(msg[0:4]) } -func (msg bufMsg) Type() MsgType { return MsgType(msg[4]) } -func (msg bufMsg) Tag() uint16 { return gbit16(msg[5:7]) } +func (msg bufMsg) Size() uint32 { return gbit32(msg[0:4]) } +func (msg bufMsg) Type() MsgType { return MsgType(msg[4]) } +func (msg bufMsg) Tag() uint16 { return gbit16(msg[5:7]) } func (msg bufMsg) marshal() []byte { return []byte(msg)[:msg.Size()] } -func (msg bufMsg) String() string { return fmt.Sprint([]byte(msg[:msg.Size()])) } +func (msg bufMsg) String() string { return fmt.Sprint([]byte(msg[:msg.Size()])) } // TVersion represents Tversion message of 9P. type TVersion struct { @@ -441,20 +441,30 @@ type TWalk struct { } func newTWalk(buf []byte) *TWalk { + cur := 0 msg := new(TWalk) - msg.size = gbit32(buf[0:4]) - msg.tag = gbit16(buf[5:7]) - msg.fid = gbit32(buf[7:11]) - msg.newFid = gbit32(buf[11:15]) - nwname := gbit16(buf[15:17]) + msg.size = gbit32(buf[cur : cur+4]) + cur += 4 + cur += 1 // msgType + msg.tag = gbit16(buf[cur : cur+2]) + cur += 2 + msg.fid = gbit32(buf[cur : cur+4]) + cur += 4 + msg.newFid = gbit32(buf[cur : cur+4]) + cur += 4 + nwname := gbit16(buf[cur : cur+2]) + cur += 2 msg.wname = make([]string, nwname) - cur := 17 + fmt.Printf("nwname: %d\n", nwname) for i := 0; i < int(nwname); i++ { size := int(gbit16(buf[cur : cur+2])) cur += 2 - msg.wname = append(msg.wname, string(buf[cur:cur+size])) + msg.wname[i] = string(buf[cur:cur+size]) cur += size } + if cur != int(msg.size) { + panic("length of buf and cursor position not match") + } return msg } @@ -734,8 +744,15 @@ func (msg *RRead) marshal() []byte { return buf } func (msg *RRead) String() string { - return fmt.Sprintf("Rread tag %d count %d data %v", - msg.Tag(), msg.Count(), msg.Data()) + s := fmt.Sprintf("Rread tag %d count %d '", + msg.Tag(), msg.Count()) + data := msg.Data() + for i := 0; i < len(data) && i < 64; i += 4 { + s += fmt.Sprintf(" %02x%02x%02x%02x", uint8(data[i]), uint8(data[i+1]), + uint8(data[i+2]), uint8(data[i+3])) + } + s += "'" + return s } type TStat struct { @@ -770,11 +787,11 @@ func (msg *TStat) String() string { type RStat struct { tag uint16 - info *FileInfo + info *FileInfo } func newRStat(buf []byte) *RStat { panic("not implemented") } -func (msg *RStat) Size() uint32 { +func (msg *RStat) Size() uint32 { stat, ok := msg.info.Sys().(*stat) if !ok { panic("not stat") @@ -800,4 +817,6 @@ func (msg *RStat) marshal() []byte { return buf } -func (msg *RStat) String() string { return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.info.stat) } +func (msg *RStat) String() string { + return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.info.stat) +} diff --git a/file.go b/file.go @@ -184,6 +184,10 @@ func (f *File) Stat() (*FileInfo, error) { return fi, nil } +func (f *File) Close() error { + return f.file.Close() +} + func (f *File) Read(b []byte) (int, error) { return f.file.Read(b) } @@ -234,7 +238,6 @@ func (f *File) ReadDir(n int) ([]*DirEntry, error) { if err != nil { return nil, fmt.Errorf("open file: %v", err) } - file.path = fpath info, err := file.Stat() if err != nil { return nil, fmt.Errorf("stat: %v", err) @@ -259,42 +262,4 @@ func (e *DirEntry) IsDir() bool { return e.dirEnt.IsDir() } func (e *DirEntry) Type() fs.FileMode { return e.dirEnt.Type() } func (e *DirEntry) Info() (*FileInfo, error) { return e.info, nil } -func (f *File) Close() error { - return f.file.Close() -} - -type FS struct { - fs fs.FS // underlying file system - qidPool *QidPool -} - -func (fsys *FS) Open(name string) (*File, error) { - f, err := fsys.fs.Open(name) // fs.File - if err != nil { - return nil, fmt.Errorf("open file %s: %v", name, err) - } - file, err := newFile(fsys, f) - if err != nil { - return nil, fmt.Errorf("newFile(%v): %v", file, err) - } - file.path = name - return file, nil -} - -/* -func (fs *FS) walkFile1(d fs.DirEntry, wname string) (*Qid, error) { - -} - -func (fs *FS) walkFile(d fs.DirEntry, wnames []string) ([]*Qid, error) { - wqids := make([]*Qid, len(wnames)) - for i, wname := range wnames { - wqids[i] = fs.walkFile1(wname) - } -} - -func walkDirFunc(path string, d fs.DirEntry, err error) error { - -} -*/ diff --git a/fs.go b/fs.go @@ -1,24 +1,73 @@ package lib9p import ( + "fmt" "io/fs" + "path" + "log" ) +type FS struct { + fs fs.FS // underlying file system + qidPool *QidPool +} + +func (fsys *FS) Open(name string) (*File, error) { + f, err := fsys.fs.Open(name) // fs.File + if err != nil { + return nil, fmt.Errorf("open file %s: %v", name, err) + } + file, err := newFile(fsys, f) + if err != nil { + return nil, fmt.Errorf("newFile(%v): %v", file, err) + } + file.path = name + fi, err := f.Stat() + if err != nil { + return nil, fmt.Errorf("stat file %s: %v", name, err) + } + file.qid.SetType(fsModeToQidType(fi.Mode())) + return file, nil +} + +func (fsys *FS) walk(root string, wnames []string) ([]*Qid, error) { + log.Printf("wnames: %v\n", wnames) + wqids := make([]*Qid, len(wnames)) + curName := root + for i, name := range wnames { + curName = path.Join(curName, name) + log.Printf("curName: %s\n", curName) + f, err := fsys.Open(curName) + if err != nil { + return wqids, err + } + qid, ok := fsys.qidPool.lookup(f) + if !ok { + qid, err = fsys.qidPool.alloc(f) + if err != nil { + return wqids, err + } + } + wqids[i] = qid + } + return wqids, nil +} + func fsModeToQidType(fm fs.FileMode) QidType { var qt QidType - if fm | fs.ModeDir != 0 { + if fm|fs.ModeDir != 0 { qt |= QTDIR } - if fm | fs.ModeAppend != 0 { + if fm|fs.ModeAppend != 0 { qt |= QTAPPEND } - if fm | fs.ModeExclusive != 0 { + if fm|fs.ModeExclusive != 0 { qt |= QTEXCL } - if fm | fs.ModeTemporary != 0 { + if fm|fs.ModeTemporary != 0 { qt |= QTTMP } - if fm | fs.ModeSymlink != 0 { + if fm|fs.ModeSymlink != 0 { qt |= QTSYMLINK } // QTMOUNT is not in fs.FileMode. @@ -26,4 +75,4 @@ func fsModeToQidType(fm fs.FileMode) QidType { // ModeSetgid, ModeCharDevice, ModeSticky, ModeIrregular // are not in QidType. return qt -} -\ No newline at end of file +} diff --git a/parse.go b/parse.go @@ -49,6 +49,7 @@ func unmarshal(buf []byte) (Msg, error) { case Rerror: return newRError(buf), nil case Twalk: + fmt.Printf("Twalk: %v\n", buf) return newTWalk(buf), nil case Rwalk: return newRWalk(buf), nil diff --git a/server.go b/server.go @@ -7,6 +7,7 @@ import ( "log" "os" "strings" + "path" ) var chatty9P = false @@ -18,7 +19,7 @@ func Chatty() { var EDupTag = fmt.Errorf("duplicate tag") type Server struct { - FS *FS + fs *FS MSize uint32 fPool *FidPool rPool *ReqPool @@ -26,10 +27,10 @@ type Server struct { Writer io.Writer } -func NewServer(fs fs.FS, mSize uint32, r io.Reader, w io.Writer) *Server { +func NewServer(fsys fs.FS, mSize uint32, r io.Reader, w io.Writer) *Server { s := new(Server) - s.FS = &FS{ - fs: fs, + s.fs = &FS{ + fs: fsys, qidPool: allocQidPool(), } s.MSize = mSize @@ -124,17 +125,14 @@ func rAuth(r *Req, err error) { } func sAttach(s *Server, r *Req) { - ifcall, ok := r.ifcall.(*TAttach) - if !ok { - panic("not TAttach") - } + ifcall := r.ifcall.(*TAttach) fid, err := s.fPool.allocFid(ifcall.Fid()) if err != nil { respond(r, fmt.Errorf("duplicate fid")) return } - fid.File, err = s.FS.Open(".") // TODO: use aname + fid.File, err = s.fs.Open(".") // TODO: use aname? if err != nil { respond(r, fmt.Errorf("unable to open file tree")) return @@ -148,10 +146,7 @@ func sAttach(s *Server, r *Req) { respond(r, fmt.Errorf("internal error")) return } - stat, ok := info.Sys().(*stat) - if !ok { - panic("not stat") - } + stat := info.Sys().(*stat) fid.Qid = stat.qid ofcall := &RAttach{ @@ -166,10 +161,7 @@ func sAttach(s *Server, r *Req) { func rAttach(r *Req, err error) {} func sWalk(s *Server, r *Req) { - ifcall, ok := r.ifcall.(*TWalk) - if !ok { - panic("not TWalk") - } + ifcall := r.ifcall.(*TWalk) oldFid, ok := s.fPool.lookupFid(ifcall.Fid()) if !ok { respond(r, fmt.Errorf("unknown fid")) @@ -187,10 +179,16 @@ func sWalk(s *Server, r *Req) { return } - for i := 0; i < int(ifcall.NWName()); i++ { - // s.FS.walk() TODO: implement + wqids, err := s.fs.walk(oldFid.File.path, ifcall.WName()) + if err != nil { + log.Printf("walk fs: %v", err) + respond(r, fmt.Errorf("walk error")) + return } - newFid.File, err = s.FS.Open(".") + + relPath := path.Join(ifcall.WName()...) + absPath := path.Join(oldFid.File.path, relPath) + newFid.File, err = s.fs.Open(absPath) if err != nil { log.Printf("open root dir: %v", err) respond(r, fmt.Errorf("internal error")) @@ -203,14 +201,12 @@ func sWalk(s *Server, r *Req) { respond(r, fmt.Errorf("internal error")) return } - stat, ok := info.Sys().(*stat) - if !ok { - panic("not stat") - } + stat := info.Sys().(*stat) newFid.Qid = stat.qid ofcall := &RWalk{ tag: r.ifcall.Tag(), + qid: wqids, } r.ofcall = ofcall respond(r, nil) diff --git a/testdir/a b/testdir/a diff --git a/testdir/b b/testdir/b diff --git a/testdir/c b/testdir/c diff --git a/testdir/d/unko b/testdir/d/unko @@ -0,0 +1 @@ +unko