commit 8fb09c72847ef13ab02fafb2c266684f36ae0bc2
parent 0992cc760c2083abc929711d1a53891f96d0c41f
Author: Matsuda Kenji <info@mtkn.jp>
Date: Thu, 21 Sep 2023 09:59:29 +0900
implementing file system for testing
Diffstat:
| A | client_test.go | | | 139 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | fcall.go | | | 293 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
| A | fs_test.go | | | 92 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 406 insertions(+), 118 deletions(-)
diff --git a/client_test.go b/client_test.go
@@ -0,0 +1,139 @@
+package lib9p
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+func newReq(s *Server, msg Msg) (*Req, error) {
+ r, err := s.rPool.add(msg.Tag())
+ if err != nil {
+ return nil, fmt.Errorf("ReqPool.add(%d): %w", msg.Tag(), err)
+ }
+ r.srv = s
+ r.tag = msg.Tag()
+ r.ifcall = msg
+ return r, nil
+}
+
+func handleReq(s *Server, r *Req) {
+ switch r.ifcall.(type) {
+ default:
+ respond(r, fmt.Errorf("unknown message type: %d", r.ifcall.Type()))
+ case *TVersion:
+ sVersion(s, r)
+ case *TAuth:
+ sAuth(s, r)
+ case *TAttach:
+ sAttach(s, r)
+ case *TWalk:
+ sWalk(s, r)
+ case *TOpen:
+ sOpen(s, r)
+ case *TCreate:
+ sCreate(s, r)
+ case *TRead:
+ sRead(s, r)
+ case *TWrite:
+ sWrite(s, r)
+ case *TClunk:
+ sClunk(s, r)
+ case *TRemove:
+ sRemove(s, r)
+ case *TStat:
+ sStat(s, r)
+ case *TWStat:
+ sWStat(s, r)
+ }
+}
+
+func TestWalk(t *testing.T) {
+ fsys := &testFS{
+ root: &testFile{
+ name: "root",
+ omode: -1,
+ isDir: true,
+ children: []*testFile{
+ &testFile{
+ name: "unko",
+ omode: -1,
+ isDir: false,
+ content: []byte("unko\n"),
+ },
+ },
+ },
+ }
+ fsys.root.fsys = fsys
+ fsys.root.parent = fsys.root
+ fsys.root.children[0].fsys = fsys
+ fsys.root.children[0].parent = fsys.root
+
+ f, err := fsys.Open(".")
+ if err != nil {
+ t.Errorf("open: %v", err)
+ } else {
+ t.Logf("file: %s", f.(*testFile).name)
+ }
+ f, err = fsys.Open("unko")
+ if err != nil {
+ t.Errorf("open: %v", err)
+ } else {
+ t.Logf("file: %s", f.(*testFile).name)
+ }
+ f, err = fsys.Open("chinko")
+ if err != nil {
+ t.Logf("open: %v", err)
+ } else {
+ t.Errorf("file: %s", f.(*testFile).name)
+ }
+
+}
+
+func TestSVersion(t *testing.T) {
+ sr, _ := io.Pipe()
+ cr, sw := io.Pipe()
+ msg := []Msg{
+ &TVersion{
+ tag: ^uint16(0),
+ mSize: 1024,
+ version: "9P2000",
+ },
+ &TAttach{
+ tag: 0,
+ fid: 0,
+ afid: NOFID,
+ uname: "glenda",
+ aname: "",
+ },
+ }
+ fsys := &testFS{
+ root: &testFile{
+ omode: -1,
+ name: "root",
+ children: nil,
+ content: nil,
+ },
+ }
+ fsys.root.fsys = fsys
+ fsys.root.parent = fsys.root
+
+ s := NewServer(fsys, 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)
+
+ go handleReq(s, r)
+ buf := make([]byte, 1024)
+ _, err = cr.Read(buf)
+ if err != nil {
+ t.Fatalf("read: %v", err)
+ }
+ t.Logf("--> %v\n", bufMsg(buf))
+ }
+}
diff --git a/fcall.go b/fcall.go
@@ -68,11 +68,69 @@ func (msg bufMsg) Type() MsgType { return MsgType(msg[4]) }
func (msg bufMsg) Tag() uint16 { return gbit16(msg[5:7]) }
func (msg bufMsg) SetTag(t uint16) { pbit16(msg[5:7], t) }
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 {
+ switch msg.Type() {
+ case Tversion:
+ return newTVersion(msg).String()
+ case Rversion:
+ return newRVersion(msg).String()
+ case Tauth:
+ return newTAuth(msg).String()
+ case Rauth:
+ return newRAuth(msg).String()
+ case Tattach:
+ return newTAttach(msg).String()
+ case Rattach:
+ return newRAttach(msg).String()
+ case Rerror:
+ return newRError(msg).String()
+ case Tflush:
+ return newTFlush(msg).String()
+ case Rflush:
+ return newRFlush(msg).String()
+ case Twalk:
+ return newTWalk(msg).String()
+ case Rwalk:
+ return newRWalk(msg).String()
+ case Topen:
+ return newTOpen(msg).String()
+ case Ropen:
+ return newROpen(msg).String()
+ case Tcreate:
+ return newTCreate(msg).String()
+ case Rcreate:
+ return newRCreate(msg).String()
+ case Tread:
+ return newTRead(msg).String()
+ case Rread:
+ return newRRead(msg).String()
+ case Twrite:
+ return newTWrite(msg).String()
+ case Rwrite:
+ return newRWrite(msg).String()
+ case Tclunk:
+ return newTClunk(msg).String()
+ case Rclunk:
+ return newRClunk(msg).String()
+ case Tremove:
+ return newTRemove(msg).String()
+ case Rremove:
+ return newRRemove(msg).String()
+ case Tstat:
+ return newTStat(msg).String()
+ case Rstat:
+ return newRStat(msg).String()
+ case Twstat:
+ return newTWStat(msg).String()
+ case Rwstat:
+ return newRWStat(msg).String()
+ default:
+ return fmt.Sprint([]byte(msg[:msg.Size()]))
+ }
+}
// TVersion represents Tversion message of 9P.
type TVersion struct {
- size uint32
tag uint16
mSize uint32
version string
@@ -80,14 +138,13 @@ type TVersion struct {
func newTVersion(buf []byte) *TVersion {
msg := new(TVersion)
- msg.size = gbit32(buf[0:4])
msg.tag = gbit16(buf[5:7])
msg.mSize = gbit32(buf[7:11])
vs := gbit16(buf[11:13])
msg.version = string(buf[13 : 13+vs])
return msg
}
-func (msg *TVersion) Size() uint32 { return msg.size }
+func (msg *TVersion) Size() uint32 { return uint32(4 + 1 + 2 + 4 + 2 + len(msg.version)) }
func (msg *TVersion) Type() MsgType { return Tversion }
func (msg *TVersion) Tag() uint16 { return msg.tag }
func (msg *TVersion) SetTag(t uint16) { msg.tag = t }
@@ -161,7 +218,6 @@ func (msg *RVersion) String() string {
}
type TAuth struct {
- size uint32
tag uint16
afid uint32
uname string
@@ -171,7 +227,6 @@ type TAuth struct {
func newTAuth(buf []byte) *TAuth {
cur := 0
msg := new(TAuth)
- msg.size = gbit32(buf[cur : cur+4])
cur += 4
cur += 1 // message type
msg.tag = gbit16(buf[cur : cur+2])
@@ -186,18 +241,20 @@ func newTAuth(buf []byte) *TAuth {
cur += 2
msg.aname = string(buf[cur : cur+l])
cur += l
- if cur != int(msg.size) {
+ if cur != int(gbit32(buf[0:4])) {
panic("length of buf and cursor position not match")
}
return msg
}
-func (msg *TAuth) Size() uint32 { return msg.size }
-func (msg *TAuth) Type() MsgType { return Tauth }
-func (msg *TAuth) Tag() uint16 { return msg.tag }
+func (msg *TAuth) Size() uint32 {
+ return uint32(4 + 1 + 2 + 4 + 2 + len(msg.uname) + 2 + len(msg.aname))
+}
+func (msg *TAuth) Type() MsgType { return Tauth }
+func (msg *TAuth) Tag() uint16 { return msg.tag }
func (msg *TAuth) SetTag(t uint16) { msg.tag = t }
-func (msg *TAuth) AFid() uint32 { return msg.afid }
-func (msg *TAuth) UName() string { return msg.uname }
-func (msg *TAuth) AName() string { return msg.aname }
+func (msg *TAuth) AFid() uint32 { return msg.afid }
+func (msg *TAuth) UName() string { return msg.uname }
+func (msg *TAuth) AName() string { return msg.aname }
func (msg *TAuth) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -248,11 +305,11 @@ func newRAuth(buf []byte) *RAuth {
msg.aqid = unmarshalQid(buf[7:])
return msg
}
-func (msg *RAuth) Size() uint32 { return 4 + 1 + 2 + 13 }
-func (msg *RAuth) Type() MsgType { return Rauth }
-func (msg *RAuth) Tag() uint16 { return msg.tag }
+func (msg *RAuth) Size() uint32 { return 4 + 1 + 2 + 13 }
+func (msg *RAuth) Type() MsgType { return Rauth }
+func (msg *RAuth) Tag() uint16 { return msg.tag }
func (msg *RAuth) SetTag(t uint16) { msg.tag = t }
-func (msg *RAuth) AQid() Qid { return msg.aqid }
+func (msg *RAuth) AQid() Qid { return msg.aqid }
func (msg *RAuth) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -278,7 +335,6 @@ func (msg *RAuth) String() string {
}
type TAttach struct {
- size uint32
tag uint16
fid uint32
afid uint32
@@ -289,7 +345,6 @@ type TAttach struct {
func newTAttach(buf []byte) *TAttach {
cur := 0
msg := new(TAttach)
- msg.size = gbit32(buf[cur : cur+4])
cur += 4
cur += 1 // message type
msg.tag = gbit16(buf[cur : cur+2])
@@ -306,19 +361,21 @@ func newTAttach(buf []byte) *TAttach {
cur += 2
msg.aname = string(buf[cur : cur+l])
cur += l
- if cur != int(msg.size) {
+ if cur != int(gbit32(buf[0:4])) {
panic("length of buf and cursor position not match")
}
return msg
}
-func (msg *TAttach) Size() uint32 { return msg.size }
-func (msg *TAttach) Type() MsgType { return Tattach }
-func (msg *TAttach) Tag() uint16 { return msg.tag }
+func (msg *TAttach) Size() uint32 {
+ return uint32(4 + 1 + 2 + 4 + 4 + 2 + len(msg.uname) + 2 + len(msg.aname))
+}
+func (msg *TAttach) Type() MsgType { return Tattach }
+func (msg *TAttach) Tag() uint16 { return msg.tag }
func (msg *TAttach) SetTag(t uint16) { msg.tag = t }
-func (msg *TAttach) Fid() uint32 { return msg.fid }
-func (msg *TAttach) AFid() uint32 { return msg.afid }
-func (msg *TAttach) UName() string { return msg.uname }
-func (msg *TAttach) AName() string { return msg.aname }
+func (msg *TAttach) Fid() uint32 { return msg.fid }
+func (msg *TAttach) AFid() uint32 { return msg.afid }
+func (msg *TAttach) UName() string { return msg.uname }
+func (msg *TAttach) AName() string { return msg.aname }
func (msg *TAttach) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -375,11 +432,11 @@ func newRAttach(buf []byte) *RAttach {
msg.qid = unmarshalQid(buf[7:])
return msg
}
-func (msg *RAttach) Size() uint32 { return 4 + 1 + 2 + 13 }
-func (msg *RAttach) Type() MsgType { return Rattach }
-func (msg *RAttach) Tag() uint16 { return msg.tag }
+func (msg *RAttach) Size() uint32 { return 4 + 1 + 2 + 13 }
+func (msg *RAttach) Type() MsgType { return Rattach }
+func (msg *RAttach) Tag() uint16 { return msg.tag }
func (msg *RAttach) SetTag(t uint16) { msg.tag = t }
-func (msg *RAttach) Qid() Qid { return msg.qid }
+func (msg *RAttach) Qid() Qid { return msg.qid }
func (msg *RAttach) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -416,11 +473,11 @@ func newRError(buf []byte) *RError {
msg.ename = fmt.Errorf("%s", string(buf[9:9+es]))
return msg
}
-func (msg *RError) Size() uint32 { return uint32(4 + 1 + 2 + 2 + len(msg.EName())) }
-func (msg *RError) Type() MsgType { return Rerror }
-func (msg *RError) Tag() uint16 { return msg.tag }
+func (msg *RError) Size() uint32 { return uint32(4 + 1 + 2 + 2 + len(msg.EName())) }
+func (msg *RError) Type() MsgType { return Rerror }
+func (msg *RError) Tag() uint16 { return msg.tag }
func (msg *RError) SetTag(t uint16) { msg.tag = t }
-func (msg *RError) EName() string { return msg.ename.Error() }
+func (msg *RError) EName() string { return msg.ename.Error() }
func (msg *RError) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -459,11 +516,11 @@ func newTFlush(buf []byte) *TFlush {
return msg
}
-func (msg *TFlush) Size() uint32 { return 9 }
-func (msg *TFlush) Type() MsgType { return Tflush }
-func (msg *TFlush) Tag() uint16 { return msg.tag }
+func (msg *TFlush) Size() uint32 { return 9 }
+func (msg *TFlush) Type() MsgType { return Tflush }
+func (msg *TFlush) Tag() uint16 { return msg.tag }
func (msg *TFlush) SetTag(t uint16) { msg.tag = t }
-func (msg *TFlush) OldTag() uint16 { return msg.oldtag }
+func (msg *TFlush) OldTag() uint16 { return msg.oldtag }
func (msg *TFlush) marshal() []byte {
buf := make([]byte, msg.Size())
pbit32(buf[0:4], msg.Size())
@@ -486,9 +543,9 @@ func newRFlush(buf []byte) *RFlush {
return msg
}
-func (msg *RFlush) Size() uint32 { return 7 }
-func (msg *RFlush) Type() MsgType { return Rflush }
-func (msg *RFlush) Tag() uint16 { return msg.tag }
+func (msg *RFlush) Size() uint32 { return 7 }
+func (msg *RFlush) Type() MsgType { return Rflush }
+func (msg *RFlush) Tag() uint16 { return msg.tag }
func (msg *RFlush) SetTag(t uint16) { msg.tag = t }
func (msg *RFlush) marshal() []byte {
buf := make([]byte, msg.Size())
@@ -603,10 +660,10 @@ func newRWalk(buf []byte) *RWalk {
func (msg *RWalk) Size() uint32 {
return uint32(4 + 1 + 2 + 2 + len(msg.Qid())*13)
}
-func (msg *RWalk) Type() MsgType { return Rwalk }
-func (msg *RWalk) Tag() uint16 { return msg.tag }
+func (msg *RWalk) Type() MsgType { return Rwalk }
+func (msg *RWalk) Tag() uint16 { return msg.tag }
func (msg *RWalk) SetTag(t uint16) { msg.tag = t }
-func (msg *RWalk) Qid() []Qid { return msg.qid }
+func (msg *RWalk) Qid() []Qid { return msg.qid }
func (msg *RWalk) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -661,12 +718,12 @@ func newTOpen(buf []byte) *TOpen {
}
return msg
}
-func (msg *TOpen) Size() uint32 { return msg.size }
-func (msg *TOpen) Type() MsgType { return Topen }
-func (msg *TOpen) Tag() uint16 { return msg.tag }
+func (msg *TOpen) Size() uint32 { return msg.size }
+func (msg *TOpen) Type() MsgType { return Topen }
+func (msg *TOpen) Tag() uint16 { return msg.tag }
func (msg *TOpen) SetTag(t uint16) { msg.tag = t }
-func (msg *TOpen) Fid() uint32 { return msg.fid }
-func (msg *TOpen) Mode() OpenMode { return msg.mode }
+func (msg *TOpen) Fid() uint32 { return msg.fid }
+func (msg *TOpen) Mode() OpenMode { return msg.mode }
func (msg *TOpen) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -707,11 +764,11 @@ func newROpen(buf []byte) *ROpen {
func (msg *ROpen) Size() uint32 {
return uint32(4 + 1 + 2 + 13 + 4)
}
-func (msg *ROpen) Type() MsgType { return Ropen }
-func (msg *ROpen) Tag() uint16 { return msg.tag }
+func (msg *ROpen) Type() MsgType { return Ropen }
+func (msg *ROpen) Tag() uint16 { return msg.tag }
func (msg *ROpen) SetTag(t uint16) { msg.tag = t }
-func (msg *ROpen) Qid() Qid { return msg.qid }
-func (msg *ROpen) IoUnit() uint32 { return msg.iounit }
+func (msg *ROpen) Qid() Qid { return msg.qid }
+func (msg *ROpen) IoUnit() uint32 { return msg.iounit }
func (msg *ROpen) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -770,13 +827,13 @@ func newTCreate(buf []byte) *TCreate {
func (msg *TCreate) Size() uint32 {
return uint32(4 + 1 + 2 + 4 + 2 + len(msg.name) + 4 + 1)
}
-func (msg *TCreate) Type() MsgType { return Tcreate }
-func (msg *TCreate) Tag() uint16 { return msg.tag }
+func (msg *TCreate) Type() MsgType { return Tcreate }
+func (msg *TCreate) Tag() uint16 { return msg.tag }
func (msg *TCreate) SetTag(t uint16) { msg.tag = t }
-func (msg *TCreate) Fid() uint32 { return msg.fid }
-func (msg *TCreate) Name() string { return msg.name }
-func (msg *TCreate) Perm() FileMode { return msg.perm }
-func (msg *TCreate) Mode() OpenMode { return msg.mode }
+func (msg *TCreate) Fid() uint32 { return msg.fid }
+func (msg *TCreate) Name() string { return msg.name }
+func (msg *TCreate) Perm() FileMode { return msg.perm }
+func (msg *TCreate) Mode() OpenMode { return msg.mode }
func (msg *TCreate) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -827,11 +884,11 @@ func newRCreate(buf []byte) *RCreate {
func (msg *RCreate) Size() uint32 {
return uint32(4 + 1 + 2 + 13 + 4)
}
-func (msg *RCreate) Type() MsgType { return Rcreate }
-func (msg *RCreate) Tag() uint16 { return msg.tag }
+func (msg *RCreate) Type() MsgType { return Rcreate }
+func (msg *RCreate) Tag() uint16 { return msg.tag }
func (msg *RCreate) SetTag(t uint16) { msg.tag = t }
-func (msg *RCreate) Qid() Qid { return msg.qid }
-func (msg *RCreate) IoUnit() uint32 { return msg.iounit }
+func (msg *RCreate) Qid() Qid { return msg.qid }
+func (msg *RCreate) IoUnit() uint32 { return msg.iounit }
func (msg *RCreate) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -885,13 +942,13 @@ func newTRead(buf []byte) *TRead {
}
return msg
}
-func (msg *TRead) Size() uint32 { return msg.size }
-func (msg *TRead) Type() MsgType { return Tread }
-func (msg *TRead) Tag() uint16 { return msg.tag }
+func (msg *TRead) Size() uint32 { return msg.size }
+func (msg *TRead) Type() MsgType { return Tread }
+func (msg *TRead) Tag() uint16 { return msg.tag }
func (msg *TRead) SetTag(t uint16) { msg.tag = t }
-func (msg *TRead) Fid() uint32 { return msg.fid }
-func (msg *TRead) Offset() uint64 { return msg.offset }
-func (msg *TRead) Count() uint32 { return msg.count }
+func (msg *TRead) Fid() uint32 { return msg.fid }
+func (msg *TRead) Offset() uint64 { return msg.offset }
+func (msg *TRead) Count() uint32 { return msg.count }
func (msg *TRead) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -936,11 +993,11 @@ func newRRead(buf []byte) *RRead {
func (msg *RRead) Size() uint32 {
return uint32(4 + 1 + 2 + 4 + msg.Count())
}
-func (msg *RRead) Type() MsgType { return Rread }
-func (msg *RRead) Tag() uint16 { return msg.tag }
+func (msg *RRead) Type() MsgType { return Rread }
+func (msg *RRead) Tag() uint16 { return msg.tag }
func (msg *RRead) SetTag(t uint16) { msg.tag = t }
-func (msg *RRead) Count() uint32 { return msg.count }
-func (msg *RRead) Data() []byte { return msg.data }
+func (msg *RRead) Count() uint32 { return msg.count }
+func (msg *RRead) Data() []byte { return msg.data }
func (msg *RRead) marshal() []byte {
if uint32(len(msg.Data())) != msg.Count() {
panic(fmt.Errorf("data size %d and count %d don't match",
@@ -1014,16 +1071,16 @@ func newTWrite(buf []byte) *TWrite {
}
return msg
}
-func (msg *TWrite) Size() uint32 {
+func (msg *TWrite) Size() uint32 {
return uint32(4 + 1 + 2 + 4 + 8 + 4 + len(msg.Data()))
}
-func (msg *TWrite) Type() MsgType { return Twrite }
-func (msg *TWrite) Tag() uint16 { return msg.tag }
+func (msg *TWrite) Type() MsgType { return Twrite }
+func (msg *TWrite) Tag() uint16 { return msg.tag }
func (msg *TWrite) SetTag(t uint16) { msg.tag = t }
-func (msg *TWrite) Fid() uint32 { return msg.fid }
-func (msg *TWrite) Offset() uint64 { return msg.offset }
-func (msg *TWrite) Count() uint32 { return msg.count }
-func (msg *TWrite) Data() []byte { return msg.data }
+func (msg *TWrite) Fid() uint32 { return msg.fid }
+func (msg *TWrite) Offset() uint64 { return msg.offset }
+func (msg *TWrite) Count() uint32 { return msg.count }
+func (msg *TWrite) Data() []byte { return msg.data }
func (msg *TWrite) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -1067,10 +1124,10 @@ func newRWrite(buf []byte) *RWrite {
func (msg *RWrite) Size() uint32 {
return uint32(4 + 1 + 2 + 4)
}
-func (msg *RWrite) Type() MsgType { return Rwrite }
-func (msg *RWrite) Tag() uint16 { return msg.tag }
+func (msg *RWrite) Type() MsgType { return Rwrite }
+func (msg *RWrite) Tag() uint16 { return msg.tag }
func (msg *RWrite) SetTag(t uint16) { msg.tag = t }
-func (msg *RWrite) Count() uint32 { return msg.count }
+func (msg *RWrite) Count() uint32 { return msg.count }
func (msg *RWrite) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
@@ -1106,11 +1163,11 @@ func newTClunk(buf []byte) *TClunk {
return msg
}
-func (msg *TClunk) Size() uint32 { return msg.size }
-func (msg *TClunk) Type() MsgType { return Tclunk }
-func (msg *TClunk) Tag() uint16 { return msg.tag }
+func (msg *TClunk) Size() uint32 { return msg.size }
+func (msg *TClunk) Type() MsgType { return Tclunk }
+func (msg *TClunk) Tag() uint16 { return msg.tag }
func (msg *TClunk) SetTag(t uint16) { msg.tag = t }
-func (msg *TClunk) Fid() uint32 { return msg.fid }
+func (msg *TClunk) Fid() uint32 { return msg.fid }
func (msg *TClunk) marshal() []byte {
m := make([]byte, msg.Size())
pbit32(m[0:4], msg.Size())
@@ -1133,9 +1190,9 @@ func newRClunk(buf []byte) *RClunk {
msg.tag = gbit16(buf[5:7])
return msg
}
-func (msg *RClunk) Size() uint32 { return 7 }
-func (msg *RClunk) Type() MsgType { return Rclunk }
-func (msg *RClunk) Tag() uint16 { return msg.tag }
+func (msg *RClunk) Size() uint32 { return 7 }
+func (msg *RClunk) Type() MsgType { return Rclunk }
+func (msg *RClunk) Tag() uint16 { return msg.tag }
func (msg *RClunk) SetTag(t uint16) { msg.tag = t }
func (msg *RClunk) marshal() []byte {
m := make([]byte, msg.Size())
@@ -1148,10 +1205,11 @@ func (msg *RClunk) String() string {
return fmt.Sprintf("Rclunk tag %d", msg.Tag())
}
-type TRemove struct{
+type TRemove struct {
tag uint16
fid uint32
}
+
func newTRemove(buf []byte) *TRemove {
msg := new(TRemove)
msg.tag = gbit16(buf[5:7])
@@ -1159,11 +1217,11 @@ func newTRemove(buf []byte) *TRemove {
return msg
}
-func (msg *TRemove) Size() uint32 { return 4 + 1 + 2 + 4 }
-func (msg *TRemove) Type() MsgType { return Tremove }
-func (msg *TRemove) Tag() uint16 { return msg.tag }
+func (msg *TRemove) Size() uint32 { return 4 + 1 + 2 + 4 }
+func (msg *TRemove) Type() MsgType { return Tremove }
+func (msg *TRemove) Tag() uint16 { return msg.tag }
func (msg *TRemove) SetTag(t uint16) { msg.tag = t }
-func (msg *TRemove) Fid() uint32 { return msg.fid }
+func (msg *TRemove) Fid() uint32 { return msg.fid }
func (msg *TRemove) marshal() []byte {
m := make([]byte, msg.Size())
pbit32(m[0:4], msg.Size())
@@ -1176,7 +1234,7 @@ func (msg *TRemove) String() string {
return fmt.Sprintf("Tremove tag %d fid %d", msg.Tag(), msg.Fid())
}
-type RRemove struct{
+type RRemove struct {
tag uint16
}
@@ -1185,9 +1243,9 @@ func newRRemove(buf []byte) *RRemove {
msg.tag = gbit16(buf[5:7])
return msg
}
-func (msg *RRemove) Size() uint32 { return 4 + 1 + 2 }
-func (msg *RRemove) Type() MsgType { return Rremove }
-func (msg *RRemove) Tag() uint16 { return msg.tag }
+func (msg *RRemove) Size() uint32 { return 4 + 1 + 2 }
+func (msg *RRemove) Type() MsgType { return Rremove }
+func (msg *RRemove) Tag() uint16 { return msg.tag }
func (msg *RRemove) SetTag(t uint16) { msg.tag = t }
func (msg *RRemove) marshal() []byte {
m := make([]byte, msg.Size())
@@ -1213,11 +1271,11 @@ func newTStat(buf []byte) *TStat {
msg.fid = gbit32(buf[7:11])
return msg
}
-func (msg *TStat) Size() uint32 { return msg.size }
-func (msg *TStat) Type() MsgType { return Tstat }
-func (msg *TStat) Tag() uint16 { return msg.tag }
+func (msg *TStat) Size() uint32 { return msg.size }
+func (msg *TStat) Type() MsgType { return Tstat }
+func (msg *TStat) Tag() uint16 { return msg.tag }
func (msg *TStat) SetTag(t uint16) { msg.tag = t }
-func (msg *TStat) Fid() uint32 { return msg.fid }
+func (msg *TStat) Fid() uint32 { return msg.fid }
func (msg *TStat) marshal() []byte {
m := make([]byte, msg.Size())
pbit32(m[0:4], msg.Size())
@@ -1245,8 +1303,8 @@ func newRStat(buf []byte) *RStat {
func (msg *RStat) Size() uint32 {
return uint32(4 + 1 + 2 + 2 + 2 + msg.stat.size())
}
-func (msg *RStat) Type() MsgType { return Rstat }
-func (msg *RStat) Tag() uint16 { return msg.tag }
+func (msg *RStat) Type() MsgType { return Rstat }
+func (msg *RStat) Tag() uint16 { return msg.tag }
func (msg *RStat) SetTag(t uint16) { msg.tag = t }
func (msg *RStat) marshal() []byte {
buf := make([]byte, msg.Size())
@@ -1266,9 +1324,9 @@ func (msg *RStat) String() string {
return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.stat)
}
-type TWStat struct{
- tag uint16
- fid uint32
+type TWStat struct {
+ tag uint16
+ fid uint32
stat *Stat
}
@@ -1282,11 +1340,11 @@ func newTWStat(buf []byte) *TWStat {
func (msg *TWStat) Size() uint32 {
return uint32(4 + 1 + 2 + 4 + 2 + 2 + msg.stat.size())
}
-func (msg *TWStat) Type() MsgType { return Twstat }
-func (msg *TWStat) Tag() uint16 { return msg.tag }
+func (msg *TWStat) Type() MsgType { return Twstat }
+func (msg *TWStat) Tag() uint16 { return msg.tag }
func (msg *TWStat) SetTag(t uint16) { msg.tag = t }
-func (msg *TWStat) Fid() uint32 { return msg.fid }
-func (msg *TWStat) Stat() *Stat { return msg.stat }
+func (msg *TWStat) Fid() uint32 { return msg.fid }
+func (msg *TWStat) Stat() *Stat { return msg.stat }
func (msg *TWStat) marshal() []byte {
buf := make([]byte, msg.Size())
pbit32(buf[0:4], msg.Size())
@@ -1306,8 +1364,7 @@ func (msg *TWStat) String() string {
return fmt.Sprintf("Twstat tag %d fid %d stat %s", msg.Tag(), msg.Fid(), msg.stat)
}
-
-type RWStat struct{
+type RWStat struct {
tag uint16
}
@@ -1316,9 +1373,9 @@ func newRWStat(buf []byte) *RWStat {
msg.tag = gbit16(buf[5:7])
return msg
}
-func (msg *RWStat) Size() uint32 { return 4 + 1 + 2 }
-func (msg *RWStat) Type() MsgType { return Rwstat }
-func (msg *RWStat) Tag() uint16 { return msg.tag }
+func (msg *RWStat) Size() uint32 { return 4 + 1 + 2 }
+func (msg *RWStat) Type() MsgType { return Rwstat }
+func (msg *RWStat) Tag() uint16 { return msg.tag }
func (msg *RWStat) SetTag(t uint16) { msg.tag = t }
func (msg *RWStat) marshal() []byte {
m := make([]byte, msg.Size())
diff --git a/fs_test.go b/fs_test.go
@@ -0,0 +1,92 @@
+package lib9p
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+type testFile struct {
+ name string
+ omode OpenMode
+ isDir bool
+ fsys *testFS
+ parent *testFile
+ children []*testFile
+ content []byte
+ reader *bytes.Reader
+ stat Stat
+}
+
+func (f *testFile) Parent() (File, error) { return f.parent, nil }
+func (f *testFile) Child() ([]File, error) {
+ child := make([]File, len(f.children))
+ for i, c := range f.children {
+ child[i] = c
+ }
+ return child, nil
+}
+func (f *testFile) Stat() (*FileInfo, error) { return &FileInfo{Stat: f.stat}, nil }
+func (f *testFile) Open(omode OpenMode) error {
+ if f.omode != -1 {
+ return fmt.Errorf("already open")
+ }
+ if omode == -1 {
+ return fmt.Errorf("invalid mode: %d", omode)
+ }
+ f.omode = omode
+ f.reader = bytes.NewReader(f.content)
+ return nil
+}
+
+func (f *testFile) Close() error {
+ f.omode = -1
+ f.reader = nil
+ return nil
+}
+
+func (f *testFile) Read(b []byte) (int, error) {
+ if f.omode != OREAD && f.omode != ORDWR {
+ return 0, fmt.Errorf("permission denied")
+ }
+ return f.reader.Read(b)
+}
+
+type testFS struct {
+ root *testFile
+}
+
+func (fs *testFS) Open(path string) (File, error) {
+ path = clean9path(path)
+ wnames := split9path(path)
+ return fs.walk(wnames)
+}
+
+func (fs *testFS) walk(wnames []string) (*testFile, error) {
+ cwd := fs.root
+L:
+ for i, name := range wnames {
+ for _, child := range cwd.children {
+ if child.name == name {
+ cwd = child
+ continue L
+ }
+ }
+ return nil, fmt.Errorf("%s not found", strings.Join(wnames[:i+1], "/"))
+ }
+ return cwd, nil
+}
+
+func clean9path(path string) string {
+ if path[len(path)-1] == '/' {
+ path = path[:len(path)-1]
+ }
+ return path
+}
+
+func split9path(path string) []string {
+ if path == "." || path == "/" {
+ return []string{}
+ }
+ return strings.Split(path, "/")
+}