commit 9a378c874e3eab72b585a8d67c738ec60babb95b
parent c9d25ef21910519cd1efa5baa16a0be4e4d6ba88
Author: Matsuda Kenji <info@mtkn.jp>
Date: Mon, 14 Aug 2023 12:00:11 +0900
add walk
Diffstat:
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