commit a095dbd85e5794b0d0ed508312aeaaf4fc7cc4af
parent 7464c340f8010cecdeafff2b5aa1fe44d5233f57
Author: Matsuda Kenji <info@mtkn.jp>
Date: Thu, 27 Jul 2023 17:54:37 +0900
add stat message
Diffstat:
| M | cmd/disk.go | | | 10 | ++-------- |
| M | fcall.go | | | 107 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- |
| M | fid.go | | | 69 | +++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
| M | file.go | | | 201 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
| M | parse.go | | | 3 | +++ |
| M | server.go | | | 94 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
6 files changed, 383 insertions(+), 101 deletions(-)
diff --git a/cmd/disk.go b/cmd/disk.go
@@ -42,12 +42,6 @@ func main() {
}
func handle(conn net.Conn, disk fs.FS) {
- srv := &lib9p.Srv{
- FS: disk,
- MSize: 8 * 1024,
- Reader: conn,
- Writer: conn,
- }
-
- lib9p.Serve(srv)
+ srv := lib9p.NewServer(disk, 8*1024, conn, conn)
+ srv.Serve()
}
diff --git a/fcall.go b/fcall.go
@@ -77,7 +77,7 @@ type Msg interface {
}
type Req struct {
- srv *Srv
+ srv *Server
ifcall Msg
ofcall Msg
}
@@ -92,15 +92,41 @@ func (msg bufMsg) conv2M() []byte { return []byte(msg)[:msg.Size()] }
func (msg bufMsg) String() string { return fmt.Sprint([]byte(msg[:msg.Size()])) }
// TVersion represents Tversion message of 9P.
-type TVersion []byte
-
-func (msg TVersion) Size() uint32 { return gbit32(msg[0:4]) }
-func (msg TVersion) Type() MsgType { return MsgType(msg[4]) }
-func (msg TVersion) Tag() uint16 { return gbit16(msg[5:7]) }
-func (msg TVersion) MSize() uint32 { return gbit32(msg[7:11]) }
-func (msg TVersion) Version() string { return string(msg[13:msg.Size()]) }
-func (msg TVersion) conv2M() []byte { return []byte(msg)[:msg.Size()] }
-func (msg TVersion) String() string {
+type TVersion struct {
+ size uint32
+ tag uint16
+ mSize uint32
+ version string
+}
+
+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) Type() MsgType { return Tversion }
+func (msg *TVersion) Tag() uint16 { return msg.tag }
+func (msg *TVersion) MSize() uint32 { return msg.mSize }
+func (msg *TVersion) Version() string { return msg.version }
+func (msg *TVersion) conv2M() []byte {
+ m := make([]byte, msg.Size())
+ pbit32(m[0:4], msg.Size())
+ m[4] = uint8(Tversion)
+ pbit16(m[5:7], msg.Tag())
+ pbit32(m[7:11], msg.MSize())
+ v := msg.Version()
+ pbit16(m[11:13], uint16(len(v)))
+ for i := 0; i < len(v); i++ {
+ m[13+i] = v[i]
+ }
+ return m
+}
+func (msg *TVersion) String() string {
return fmt.Sprintf("Tversion tag %d msize %d version '%s'",
msg.Tag(), msg.MSize(), msg.Version())
}
@@ -161,7 +187,7 @@ type RAuth []byte
func (msg RAuth) Size() uint32 { return gbit32(msg[0:4]) }
func (msg RAuth) Type() MsgType { return MsgType(msg[4]) }
func (msg RAuth) Tag() uint16 { return gbit16(msg[5:7]) }
-func (msg RAuth) AQid() Qid { return Qid(msg[7:20]) }
+func (msg RAuth) AQid() *Qid { return newQid(msg[7:20]) }
func (msg RAuth) conv2M() []byte { return []byte(msg)[:msg.Size()] }
func (msg RAuth) String() string {
return fmt.Sprintf("Tauth tag %d aqid %v",
@@ -173,7 +199,7 @@ type TAttach []byte
func (msg TAttach) Size() uint32 { return gbit32(msg[0:4]) }
func (msg TAttach) Type() MsgType { return MsgType(msg[4]) }
func (msg TAttach) Tag() uint16 { return gbit16(msg[5:7]) }
-func (msg TAttach) Fid() uint32 { return gbit32(msg[7:11]) }
+func (msg TAttach) Fid() uint32 { return gbit32(msg[7:11]) }
func (msg TAttach) AFid() uint32 { return gbit32(msg[11:15]) }
func (msg TAttach) UName() string {
usize := gbit16(msg[15:17])
@@ -206,8 +232,8 @@ func (msg RAttach) Type() MsgType { return MsgType(msg[4]) }
func (msg RAttach) SetType(t MsgType) { msg[4] = byte(t) }
func (msg RAttach) Tag() uint16 { return gbit16(msg[5:7]) }
func (msg RAttach) SetTag(t uint16) { pbit16(msg[5:7], t) }
-func (msg RAttach) Qid() Qid { return Qid(msg[7:20]) }
-func (msg RAttach) SetQid(q Qid) {
+func (msg RAttach) Qid() *Qid { return newQid(msg[7:20]) }
+func (msg RAttach) SetQid(q *Qid) {
msg[7] = uint8(q.Type())
pbit32(msg[8:12], q.Vers())
pbit64(msg[12:20], q.Path())
@@ -245,3 +271,56 @@ func (msg RError) SetEName(err error) {
func (msg RError) String() string {
return fmt.Sprintf("Rerror tag %d ename %v", msg.Tag(), msg.EName())
}
+
+type TStat struct {
+ size uint32
+ tag uint16
+ fid uint32
+}
+
+func newTStat(buf []byte) *TStat {
+ msg := new(TStat)
+ msg.size = gbit32(buf[0:4])
+ msg.tag = gbit16(buf[5:7])
+ 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) Fid() uint32 { return msg.fid }
+func (msg *TStat) conv2M() []byte {
+ m := make([]byte, msg.Size())
+ pbit32(m[0:4], msg.Size())
+ m[4] = uint8(Tstat)
+ pbit16(m[5:7], msg.Tag())
+ pbit32(m[7:11], msg.Fid())
+ return m
+}
+func (msg *TStat) String() string {
+ return fmt.Sprintf("Tstat tag %d fid %d",
+ msg.Tag(), msg.Fid())
+}
+
+type RStat struct {
+ tag uint16
+ stat *stat
+}
+
+func (msg *RStat) Size() uint32 { return uint32(4 + 1 + 2 + 2 + 2 + msg.stat.size()) } // TODO: collect ?
+func (msg *RStat) Type() MsgType { return Rstat }
+func (msg *RStat) Tag() uint16 { return msg.tag }
+func (msg *RStat) conv2M() []byte {
+ buf := make([]byte, msg.Size())
+ pbit32(buf[0:4], msg.Size())
+ buf[4] = uint8(Rstat)
+ pbit16(buf[5:7], msg.Tag())
+ statBuf := msg.stat.conv2M()
+ pbit16(buf[7:9], uint16(len(statBuf)))
+ for i := 0; i < len(statBuf); i++ {
+ buf[9+i] = statBuf[i]
+ }
+ return buf
+}
+
+func (msg *RStat) String() string { return fmt.Sprintf("Rstat tag %d %s", msg.Tag(), msg.stat) }
diff --git a/fid.go b/fid.go
@@ -2,7 +2,6 @@ package lib9p
import (
"fmt"
- "io/fs"
)
// QidType represents the type of Qid. the 'QT' prefix may be redundant.
@@ -19,12 +18,26 @@ const (
QTFILE = 0x00 /* type bits for plain file */
)
+type OpenMode int32
+
+const (
+ OREAD OpenMode = 0
+ OWRITE = 1
+ ORDWR = 2
+ OEXEC = 3
+
+ OTRUNC = 16
+ OCEXEC = 32
+ ORCLOSE = 64
+ ORDIRECT = 128
+)
+
type Fid struct {
Fid uint32
- OMode int32 /* -1 = not open */
- File fs.File
+ OMode OpenMode /* -1 = not open */
+ File *File
Uid string
- Qid Qid
+ Qid *Qid
}
const NOFID = ^uint32(0)
@@ -44,20 +57,31 @@ func (f *Fid) String() string {
return fmt.Sprintf("%d", fid)
}
-type Qid []byte
+type Qid struct {
+ t QidType
+ vers uint32
+ path uint64
+}
-func (q Qid) Type() QidType { return QidType(q[0]) }
-func (q Qid) SetType(t QidType) { q[0] = uint8(t) }
-func (q Qid) Vers() uint32 { return gbit32(q[1:5]) }
-func (q Qid) SetVers(v uint32) { pbit32(q[1:5], v) }
-func (q Qid) Path() uint64 { return gbit64(q[5:13]) }
-func (q Qid) SetPath(p uint64) { pbit64(q[5:13], p) }
-func (q Qid) String() string {
+func newQid(b []byte) *Qid {
+ return &Qid{
+ t: QidType(b[0]),
+ vers: gbit32(b[1:5]),
+ path: gbit64(b[5:13]),
+ }
+}
+func (q *Qid) Type() QidType { return q.t }
+func (q *Qid) SetType(t QidType) { q.t = t }
+func (q *Qid) Vers() uint32 { return q.vers }
+func (q *Qid) SetVers(v uint32) { q.vers = v }
+func (q *Qid) Path() uint64 { return q.path }
+func (q *Qid) SetPath(p uint64) { q.path = p }
+func (q *Qid) String() string {
return fmt.Sprintf("(%016d %d %s)", q.Path(), q.Vers(), q.typeStr())
}
// TypeStr returns the q.Type() as string for debugging information.
-func (q Qid) typeStr() string {
+func (q *Qid) typeStr() string {
var s string
t := q.Type()
if t&QTDIR != 0 {
@@ -85,8 +109,9 @@ func allocFidPool() *FidPool {
return f
}
-func (pool *FidPool) lookupFid(fid uint32) *Fid {
- return pool.m[fid]
+func (pool *FidPool) lookupFid(fid uint32) (*Fid, bool) {
+ f, ok := pool.m[fid]
+ return f, ok
}
func (pool *FidPool) allocFid(fid uint32) (*Fid, error) {
@@ -99,7 +124,19 @@ func (pool *FidPool) allocFid(fid uint32) (*Fid, error) {
}
func (pool *FidPool) removeFid(fid uint32) *Fid {
- f := pool.lookupFid(fid)
+ f, ok := pool.lookupFid(fid)
+ if !ok {
+ return nil
+ }
delete(pool.m, fid)
return f
}
+
+func (pool *FidPool) String() string {
+ s := "{"
+ for fnum, fstruct := range pool.m {
+ s += fmt.Sprintf(" [%d]%v", fnum, fstruct)
+ }
+ s += "}"
+ return s
+}
diff --git a/file.go b/file.go
@@ -1,6 +1,7 @@
package lib9p
import (
+ "fmt"
"io/fs"
"time"
)
@@ -12,46 +13,77 @@ const (
DMTMP = 0x04000000
)
-type Stat []byte
-
-func (s Stat) Size() uint16 { return gbit16(s[0:2]) }
-func (s Stat) Type() uint16 { return gbit16(s[2:4]) }
-func (s Stat) Dev() uint32 { return gbit32(s[4:8]) }
-func (s Stat) Qid() Qid { return Qid(s[8:21]) }
-func (s Stat) Mode() uint32 { return gbit32(s[21:25]) }
-func (s Stat) ATime() uint32 { return gbit32(s[25:29]) }
-func (s Stat) MTime() uint32 { return gbit32(s[29:33]) }
-func (s Stat) Length() uint64 { return gbit64(s[33:41]) }
-func (s Stat) Name() string {
- nlen := gbit16(s[41:43])
- return string(s[43 : 43+nlen])
+type stat struct {
+ // size uint16
+ t uint16
+ dev uint32
+ qid *Qid
+ mode fs.FileMode
+ aTime time.Time
+ mTime time.Time
+ length int64
+ name string
+ uid string
+ gid string
+ muid string
}
-func (s Stat) Uid() string {
- nlen := gbit16(s[41:43])
- ulen := gbit16(s[43+nlen : 43+nlen+2])
- return string(s[43+nlen+2 : 43+nlen+2+ulen])
-}
-func (s Stat) Gid() string {
- nlen := gbit16(s[41:43])
- ulen := gbit16(s[43+nlen : 43+nlen+2])
- glen := gbit16(s[43+nlen+2+ulen : 43+nlen+2+ulen+2])
- return string(s[43+nlen+2+ulen+2 : 43+nlen+2+ulen+2+glen])
+
+func (s *stat) size() uint16 {
+ return uint16(2 + 4 + 13 + 4 + 4 + 4 + 8 +
+ // type + dev + qid + mode + atime + mtime + length
+ 2 + len(s.name) +
+ 2 + len(s.uid) +
+ 2 + len(s.gid) +
+ 2 + len(s.muid))
}
-func (s Stat) MUid() string {
- nlen := gbit16(s[41:43])
- ulen := gbit16(s[43+nlen : 43+nlen+2])
- glen := gbit16(s[43+nlen+2+ulen : 43+nlen+2+ulen+2])
- mlen := gbit16(s[43+nlen+2+ulen+2+glen : 43+nlen+2+ulen+2+glen+2])
- return string(s[43+nlen+2+ulen+2+glen+2 : 43+nlen+2+ulen+2+glen+2+mlen])
+
+func (s *stat) conv2M() []byte {
+ size := s.size()
+ msg := make([]byte, 2+size)
+ pbit16(msg[:2], size)
+ pbit16(msg[2:4], s.t)
+ pbit32(msg[4:8], s.dev)
+ msg[8] = uint8(s.qid.Type())
+ pbit32(msg[9:13], s.qid.Vers())
+ pbit64(msg[13:21], s.qid.Path())
+ pbit32(msg[21:25], uint32(s.mode))
+ pbit32(msg[25:29], uint32(s.aTime.Unix()))
+ pbit32(msg[29:33], uint32(s.mTime.Unix()))
+ pbit64(msg[33:41], uint64(s.length))
+ pbit16(msg[41:43], uint16(len(s.name)))
+ for i := 0; i < len(s.name); i++ {
+ msg[43+i] = s.name[i]
+ }
+ uidOffset := 43 + len(s.name)
+ pbit16(msg[uidOffset:uidOffset+2], uint16(len(s.uid)))
+ for i := 0; i < len(s.uid); i++ {
+ msg[uidOffset+2+i] = s.uid[i]
+ }
+ gidOffset := uidOffset + 2 + len(s.uid)
+ pbit16(msg[gidOffset:gidOffset+2], uint16(len(s.gid)))
+ for i := 0; i < len(s.gid); i++ {
+ msg[gidOffset+2+i] = s.gid[i]
+ }
+ muidOffset := gidOffset + 2 + len(s.gid)
+ pbit16(msg[muidOffset:muidOffset+2], uint16(len(s.muid)))
+ for i := 0; i < len(s.muid); i++ {
+ msg[muidOffset+2+i] = s.muid[i]
+ }
+
+ if len(msg) != muidOffset+2+len(s.muid) {
+ panic(fmt.Errorf("stat offset %d and msg length %d not match",
+ muidOffset+2+len(s.muid), len(msg)))
+ }
+ return msg
}
-type FileInfo Stat
+type FileInfo stat
-func (fi FileInfo) Name() string { return Stat(fi).Name() }
-func (fi FileInfo) Size() int64 { return int64(Stat(fi).Length()) }
-func (fi FileInfo) Mode() fs.FileMode {
+func (fi *FileInfo) Name() string { return (*stat)(fi).name }
+func (fi *FileInfo) Size() int64 { return int64((*stat)(fi).length) }
+func (fi *FileInfo) Mode() fs.FileMode {
var mode fs.FileMode
- smode := Stat(fi).Mode()
+ smode := (*stat)(fi).mode
if smode&DMDIR != 0 {
mode |= fs.ModeDir
}
@@ -65,9 +97,102 @@ func (fi FileInfo) Mode() fs.FileMode {
mode |= fs.ModeTemporary
}
// Permission bits are fixed according to godoc of fs.FileMode
- mode |= fs.FileMode(smode&0777)
+ mode |= fs.FileMode(smode & 0777)
return mode
}
-func (fi FileInfo) ModTime() time.Time { return time.Unix(int64(Stat(fi).MTime()), 0) }
-func (fi FileInfo) IsDir() bool { return Stat(fi).Mode()&DMDIR != 0 }
-func (fi FileInfo) Sys() any { return Stat(fi) }
+func (fi *FileInfo) ModTime() time.Time { return (*stat)(fi).mTime }
+func (fi *FileInfo) IsDir() bool { return (*stat)(fi).mode&DMDIR != 0 }
+func (fi *FileInfo) Sys() any { return (*stat)(fi) }
+
+type File struct {
+ file fs.File // underlying file
+ qid *Qid
+}
+
+func (f *File) Stat() (*FileInfo, error) {
+ fi, err := f.file.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("stat file: %v, %v", f, err)
+ }
+ st := &stat{
+ qid: f.qid,
+ mode: fi.Mode(), // TODO: convert mode from fs to 9p
+ aTime: fi.ModTime(),
+ mTime: fi.ModTime(),
+ length: fi.Size(),
+ name: fi.Name(),
+ // TODO: size, t, dev, uid, gid, muid
+ }
+ return (*FileInfo)(st), nil
+}
+
+func (f *File) Read(b []byte) (int, error) {
+ return f.file.Read(b)
+}
+
+func (f *File) Close() error {
+ return f.file.Close()
+}
+
+type FS struct {
+ nextQid uint64 // next qid to be used
+ fs fs.FS // underlying file system
+}
+
+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)
+ }
+ qid := newQid(make([]byte, 13))
+ qid.SetPath(fsys.nextQid)
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("stat file %v: %v", f, err)
+ }
+ mode := fi.Mode()
+ var qtype QidType
+ if mode&fs.ModeDir != 0 {
+ qtype |= QTDIR
+ }
+ if mode&fs.ModeAppend != 0 {
+ qtype |= QTAPPEND
+ }
+ if mode&fs.ModeExclusive != 0 {
+ qtype |= QTEXCL
+ }
+ if mode&fs.ModeTemporary != 0 {
+ qtype |= QTTMP
+ }
+ if mode&fs.ModeSymlink != 0 {
+ qtype |= QTSYMLINK
+ }
+ // TODO: QTAUTH
+ qid.SetType(qtype)
+ fsys.nextQid++
+
+ file := &File{
+ file: f,
+ qid: qid,
+ }
+
+ 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/parse.go b/parse.go
@@ -11,6 +11,9 @@ func read9PMsg(r io.Reader) ([]byte, error) {
buf := make([]byte, 4)
read, err := r.Read(buf)
if err != nil {
+ if err == io.EOF {
+ return nil, err
+ }
return nil, fmt.Errorf("read size: %v", err)
}
if read != len(buf) {
diff --git a/server.go b/server.go
@@ -15,20 +15,33 @@ func Chatty() {
chatty9P = true
}
-type Srv struct {
- FS fs.FS
+type Server struct {
+ FS *FS
MSize uint32
fPool *FidPool
Reader io.Reader
Writer io.Writer
}
-func getReq(s *Srv) (*Req, error) {
+func NewServer(fs fs.FS, mSize uint32, r io.Reader, w io.Writer) *Server {
+ s := new(Server)
+ s.FS = &FS{fs: fs}
+ s.MSize = mSize
+ s.fPool = allocFidPool()
+ s.Reader = r
+ s.Writer = w
+ return s
+}
+
+func (s *Server) getReq() (*Req, error) {
var r Req
r.srv = s
buf, err := read9PMsg(s.Reader)
if err != nil {
+ if err == io.EOF {
+ return &r, err
+ }
return &r, fmt.Errorf("read message: %v", err)
}
@@ -39,11 +52,13 @@ func getReq(s *Srv) (*Req, error) {
}
return &r, fmt.Errorf("unknown message type %d", t)
case Tversion:
- r.ifcall = TVersion(buf)
+ r.ifcall = newTVersion(buf)
case Tattach:
r.ifcall = TAttach(buf)
case Tauth:
r.ifcall = TAuth(buf)
+ case Tstat:
+ r.ifcall = newTStat(buf)
}
if chatty9P {
fmt.Fprintf(os.Stderr, "<-- %v\n", r.ifcall)
@@ -51,8 +66,8 @@ func getReq(s *Srv) (*Req, error) {
return &r, nil
}
-func sVersion(s *Srv, r *Req) {
- ifcall, ok := r.ifcall.(TVersion)
+func sVersion(s *Server, r *Req) {
+ ifcall, ok := r.ifcall.(*TVersion)
if !ok {
panic("not TVersion")
}
@@ -83,7 +98,7 @@ func sVersion(s *Srv, r *Req) {
func rVersion(r *Req, err error) {}
-func sAuth(s *Srv, r *Req) {
+func sAuth(s *Server, r *Req) {
respond(r, fmt.Errorf("authentication not implemented"))
}
@@ -98,14 +113,11 @@ func rAuth(r *Req, err error) {
}
}
-func sAttach(s *Srv, r *Req) {
+func sAttach(s *Server, r *Req) {
ifcall, ok := r.ifcall.(TAttach)
if !ok {
panic("not TAttach")
}
- if s.fPool == nil {
- s.fPool = allocFidPool()
- }
fid, err := s.fPool.allocFid(ifcall.Fid())
if err != nil {
respond(r, fmt.Errorf("duplicate fid"))
@@ -119,26 +131,50 @@ func sAttach(s *Srv, r *Req) {
}
fid.Uid = ifcall.UName()
-
- qid := Qid(make([]byte, 13))
- qid.SetType(QTDIR)
- qid.SetVers(0)
- qid.SetPath(0)
- fid.Qid = qid
+ fid.OMode = OREAD
+ fid.Qid = fid.File.qid
ofcall := RAttach(make([]byte, 4+1+2+13))
ofcall.SetSize(uint32(len(ofcall)))
ofcall.SetType(Rattach)
ofcall.SetTag(ifcall.Tag())
- ofcall.SetQid(qid)
+ ofcall.SetQid(fid.Qid)
r.ofcall = ofcall
respond(r, nil)
}
-func rAttach(r *Req, err error) {
+func rAttach(r *Req, err error) {}
+
+func sStat(s *Server, r *Req) {
+ ifcall, ok := r.ifcall.(*TStat)
+ if !ok {
+ panic("not TStat")
+ }
+ fidNum := ifcall.Fid()
+ fidStruct, ok := s.fPool.lookupFid(fidNum)
+ if !ok {
+ respond(r, fmt.Errorf("unknown fid %d", fidNum))
+ return
+ }
+ fileInfo, err := fidStruct.File.Stat()
+ if err != nil {
+ log.Printf("stat file %v: %v", fidStruct.File, err)
+ respond(r, fmt.Errorf("internal error"))
+ return
+ }
+
+ ofcall := &RStat{
+ tag: ifcall.Tag(),
+ stat: (*stat)(fileInfo),
+ }
+
+ r.ofcall = ofcall
+ respond(r, nil)
}
+func rStat(r *Req, err error) {}
+
func rError(r *Req, err error) {
size := uint32(4 + 1 + 2 + 2 + len(err.Error()))
ofcall := RError(make([]byte, size))
@@ -148,23 +184,29 @@ func rError(r *Req, err error) {
r.ofcall = ofcall
}
-func Serve(s *Srv) {
+func (s *Server) Serve() {
for {
- r, err := getReq(s)
- if err != nil {
- log.Printf("get req: %v\n", err)
+ r, err := s.getReq()
+ // TODO: check tag duplicate
+ if err == io.EOF {
+ log.Printf("getReq: %v\n", err)
+ break
+ } else if err != nil {
+ log.Printf("getReq: %v\n", err)
respond(r, fmt.Errorf("internal error"))
continue
}
switch r.ifcall.(type) {
default:
respond(r, fmt.Errorf("unknown message type: %d", r.ifcall.Type()))
- case TVersion:
+ case *TVersion:
sVersion(s, r)
case TAuth:
sAuth(s, r)
case TAttach:
sAttach(s, r)
+ case *TStat:
+ sStat(s, r)
}
}
}
@@ -186,10 +228,12 @@ func respond(r *Req, err error) {
rAuth(r, err)
case RAttach:
rAttach(r, err)
+ case *RStat:
+ rStat(r, err)
}
-
if chatty9P {
fmt.Fprintf(os.Stderr, "--> %s\n", r.ofcall)
}
r.srv.Writer.Write(r.ofcall.conv2M())
+ // TODO: free tag.
}