commit c9d25ef21910519cd1efa5baa16a0be4e4d6ba88
parent 5ebffe30824b8f1148066c185df189339db089ba
Author: Matsuda Kenji <info@mtkn.jp>
Date: Mon, 31 Jul 2023 15:35:21 +0900
change data structure
Diffstat:
| A | disk.go | | | 2 | ++ |
| M | fcall.go | | | 61 | +++++++++++++++++++++++++++++++++++-------------------------- |
| M | fid.go | | | 38 | +++++++++++++++++++++++++++++++++++++- |
| M | file.go | | | 206 | +++++++++++++++++++++---------------------------------------------------------- |
| A | fs.go | | | 30 | ++++++++++++++++++++++++++++++ |
| M | server.go | | | 56 | ++++++++++++++++++++++++++++++++++++++++++++++++++------ |
6 files changed, 208 insertions(+), 185 deletions(-)
diff --git a/disk.go b/disk.go
@@ -0,0 +1,2 @@
+package lib9p
+
diff --git a/fcall.go b/fcall.go
@@ -70,9 +70,8 @@ type Msg interface {
// Tag returns the tag of msg.
Tag() uint16
- // Conv2M convert Msg to byte array to be transmitted.
- // This name is derived from plan9port's lib9p: convS2M.
- conv2M() []byte
+ // Marshal convert Msg to byte array to be transmitted.
+ marshal() []byte
String() string
}
@@ -82,7 +81,7 @@ 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) conv2M() []byte { return []byte(msg)[:msg.Size()] }
+func (msg bufMsg) marshal() []byte { return []byte(msg)[:msg.Size()] }
func (msg bufMsg) String() string { return fmt.Sprint([]byte(msg[:msg.Size()])) }
// TVersion represents Tversion message of 9P.
@@ -107,7 +106,7 @@ 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 {
+func (msg *TVersion) marshal() []byte {
m := make([]byte, msg.Size())
pbit32(m[0:4], msg.Size())
m[4] = uint8(Tversion)
@@ -140,7 +139,7 @@ func (msg *RVersion) MSize() uint32 { return msg.mSize }
func (msg *RVersion) SetMSize(s uint32) { msg.mSize = s }
func (msg *RVersion) Version() string { return msg.version }
func (msg *RVersion) SetVersion(v string) { msg.version = v }
-func (msg *RVersion) conv2M() []byte {
+func (msg *RVersion) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -204,7 +203,7 @@ func (msg TAuth) Tag() uint16 { return msg.tag }
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) conv2M() []byte {
+func (msg TAuth) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -253,7 +252,7 @@ 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) AQid() *Qid { return msg.aqid }
-func (msg RAuth) conv2M() []byte {
+func (msg RAuth) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -262,7 +261,7 @@ func (msg RAuth) conv2M() []byte {
cur += 1
pbit16(buf[cur:cur+2], msg.Tag())
cur += 2
- qid := msg.AQid().conv2M()
+ qid := msg.AQid().marshal()
for i := 0; i < len(qid); i++ {
buf[cur+i] = qid[i]
}
@@ -318,7 +317,7 @@ 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) conv2M() []byte {
+func (msg TAttach) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -373,7 +372,7 @@ 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) Qid() *Qid { return msg.qid }
-func (msg RAttach) conv2M() []byte {
+func (msg RAttach) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -382,7 +381,7 @@ func (msg RAttach) conv2M() []byte {
cur += 1
pbit16(buf[cur:cur+2], msg.Tag())
cur += 2
- qid := msg.Qid().conv2M()
+ qid := msg.Qid().marshal()
for i := 0; i < len(qid); i++ {
buf[cur+i] = qid[i]
}
@@ -407,7 +406,7 @@ 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) EName() string { return msg.ename.Error() }
-func (msg *RError) conv2M() []byte {
+func (msg *RError) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -466,7 +465,7 @@ func (msg *TWalk) Fid() uint32 { return msg.fid }
func (msg *TWalk) NewFid() uint32 { return msg.newFid }
func (msg *TWalk) NWName() uint16 { return uint16(len(msg.wname)) }
func (msg *TWalk) WName() []string { return msg.wname }
-func (msg *TWalk) conv2M() []byte {
+func (msg *TWalk) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -514,7 +513,7 @@ func (msg *RWalk) Size() uint32 {
func (msg *RWalk) Type() MsgType { return Rwalk }
func (msg *RWalk) Tag() uint16 { return msg.tag }
func (msg *RWalk) Qid() []*Qid { return msg.qid }
-func (msg *RWalk) conv2M() []byte {
+func (msg *RWalk) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -526,7 +525,7 @@ func (msg *RWalk) conv2M() []byte {
pbit16(buf[cur:cur+2], uint16(len(msg.Qid())))
cur += 2
for _, qid := range msg.Qid() {
- for i, bit := range qid.conv2M() {
+ for i, bit := range qid.marshal() {
buf[cur+i] = bit
}
cur += 13
@@ -573,7 +572,7 @@ func (msg *TOpen) Type() MsgType { return Topen }
func (msg *TOpen) Tag() uint16 { return msg.tag }
func (msg *TOpen) Fid() uint32 { return msg.fid }
func (msg *TOpen) Mode() OpenMode { return msg.mode }
-func (msg *TOpen) conv2M() []byte {
+func (msg *TOpen) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -611,7 +610,7 @@ func (msg *ROpen) Type() MsgType { return Ropen }
func (msg *ROpen) Tag() uint16 { return msg.tag }
func (msg *ROpen) Qid() *Qid { return msg.qid }
func (msg *ROpen) IoUnit() uint32 { return msg.iounit }
-func (msg *ROpen) conv2M() []byte {
+func (msg *ROpen) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -620,7 +619,7 @@ func (msg *ROpen) conv2M() []byte {
cur += 1
pbit16(buf[cur:cur+2], msg.Tag())
cur += 2
- for i, bit := range msg.Qid().conv2M() {
+ for i, bit := range msg.Qid().marshal() {
buf[cur+i] = bit
}
cur += 13
@@ -670,7 +669,7 @@ func (msg *TRead) Tag() uint16 { return msg.tag }
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) conv2M() []byte {
+func (msg *TRead) marshal() []byte {
cur := 0
buf := make([]byte, msg.Size())
pbit32(buf[cur:cur+4], msg.Size())
@@ -709,7 +708,7 @@ func (msg *RRead) Type() MsgType { return Rread }
func (msg *RRead) Tag() uint16 { return msg.tag }
func (msg *RRead) Count() uint32 { return msg.count }
func (msg *RRead) Data() []byte { return msg.data }
-func (msg *RRead) conv2M() []byte {
+func (msg *RRead) marshal() []byte {
if uint32(len(msg.Data())) != msg.Count() {
panic(fmt.Errorf("data size %d and count %d don't match",
len(msg.Data()), msg.Count()))
@@ -756,7 +755,7 @@ 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 {
+func (msg *TStat) marshal() []byte {
m := make([]byte, msg.Size())
pbit32(m[0:4], msg.Size())
m[4] = uint8(Tstat)
@@ -775,15 +774,25 @@ type RStat struct {
}
func newRStat(buf []byte) *RStat { panic("not implemented") }
-func (msg *RStat) Size() uint32 { return uint32(4 + 1 + 2 + 2 + 2 + msg.info.statSize()) } // TODO: collect ?
+func (msg *RStat) Size() uint32 {
+ stat, ok := msg.info.Sys().(*stat)
+ if !ok {
+ panic("not stat")
+ }
+ return uint32(4 + 1 + 2 + 2 + 2 + stat.size())
+}
func (msg *RStat) Type() MsgType { return Rstat }
func (msg *RStat) Tag() uint16 { return msg.tag }
-func (msg *RStat) conv2M() []byte {
+func (msg *RStat) marshal() []byte {
buf := make([]byte, msg.Size())
pbit32(buf[0:4], msg.Size())
buf[4] = uint8(Rstat)
pbit16(buf[5:7], msg.Tag())
- fiBuf := msg.info.conv2M()
+ stat, ok := msg.info.Sys().(*stat)
+ if !ok {
+ panic("not stat")
+ }
+ fiBuf := stat.marshal()
pbit16(buf[7:9], uint16(len(fiBuf)))
for i := 0; i < len(fiBuf); i++ {
buf[9+i] = fiBuf[i]
@@ -791,4 +800,4 @@ func (msg *RStat) conv2M() []byte {
return buf
}
-func (msg *RStat) String() string { return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.info) }
+func (msg *RStat) String() string { return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.info.stat) }
diff --git a/fid.go b/fid.go
@@ -89,7 +89,7 @@ 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) conv2M() []byte {
+func (q *Qid) marshal() []byte {
buf := make([]byte, 13)
buf[0] = uint8(q.t)
pbit32(buf[1:5], q.vers)
@@ -119,6 +119,42 @@ func (q *Qid) typeStr() string {
return s
}
+type QidPool struct {
+ m map[*File]*Qid
+ nextQid uint64
+}
+
+func allocQidPool() *QidPool {
+ q := new(QidPool)
+ q.m = make(map[*File]*Qid)
+ return q
+}
+
+func (pool *QidPool) lookup(f *File) (*Qid, bool) {
+ q, ok := pool.m[f]
+ return q, ok
+}
+
+func (pool *QidPool) alloc(f *File) (*Qid, error) {
+ _, ok := pool.m[f]
+ if ok {
+ return nil, fmt.Errorf("qid already exist for file %v", f)
+ }
+
+ s, err := f.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("stat %v: %v", f, err)
+ }
+ t := fsModeToQidType(s.Mode())
+ q := &Qid{t: t, path:pool.nextQid}
+ pool.nextQid++
+ if q.path > pool.nextQid {
+ panic("qid overflow")
+ }
+ pool.m[f] = q
+ return q, nil
+}
+
type FidPool struct {
m map[uint32]*Fid
}
diff --git a/file.go b/file.go
@@ -5,6 +5,7 @@ import (
"io"
"io/fs"
"time"
+ "path"
)
const (
@@ -26,17 +27,21 @@ func hasPerm(f *File, uid string, p fs.FileMode) (bool, error) {
return false, fmt.Errorf("stat: %v", err)
}
fp := fi.Mode().Perm()
+ stat, ok := fi.Sys().(*stat)
+ if !ok {
+ panic("not stat")
+ }
m := fp & 7 // other
if (p & m) == p {
return true, nil
}
- if fi.statUid() == uid {
+ if stat.uid == uid {
m |= (fp >> 6) & 7
if (p & m) == p {
return true, nil
}
}
- if fi.statGid() == uid {
+ if stat.gid == uid {
m |= (fp >> 3) & 7
if (p & m) == p {
return true, nil
@@ -45,14 +50,13 @@ func hasPerm(f *File, uid string, p fs.FileMode) (bool, error) {
return false, nil
}
-/*
type stat struct {
t uint16
dev uint32
qid *Qid
- mode fs.FileMode
- aTime time.Time
- mTime time.Time
+ mode uint32
+ aTime uint32
+ mTime uint32
length int64
name string
uid string
@@ -69,7 +73,7 @@ func (s *stat) size() uint16 {
2 + len(s.muid))
}
-func (s *stat) conv2M() []byte {
+func (s *stat) marshal() []byte {
cur := 0
size := s.size()
msg := make([]byte, 2+size)
@@ -85,11 +89,11 @@ func (s *stat) conv2M() []byte {
cur += 4
pbit64(msg[cur:cur+8], s.qid.Path())
cur += 8
- pbit32(msg[cur:cur+4], uint32(s.mode))
+ pbit32(msg[cur:cur+4], s.mode)
cur += 4
- pbit32(msg[cur:cur+4], uint32(s.aTime.Unix()))
+ pbit32(msg[cur:cur+4], s.aTime)
cur += 4
- pbit32(msg[cur:cur+4], uint32(s.mTime.Unix()))
+ pbit32(msg[cur:cur+4], s.mTime)
cur += 4
pbit64(msg[cur:cur+8], uint64(s.length))
cur += 8
@@ -127,27 +131,13 @@ func (s *stat) conv2M() []byte {
func (s *stat) String() string {
return fmt.Sprintf("'%s' '%s' '%s' '%s' q %v m %#o at %d mt %d l %d t %d d %d",
- s.name, s.uid, s.gid, s.muid, s.qid, uint32(s.mode),
- s.aTime.Unix(), s.mTime.Unix(), s.length, s.t, s.dev)
+ s.name, s.uid, s.gid, s.muid, s.qid, s.mode,
+ s.aTime, s.mTime, s.length, s.t, s.dev)
}
-*/
type FileInfo struct {
info fs.FileInfo
- qid *Qid
- /*
- 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
- */
+ stat *stat
}
func (fi *FileInfo) Name() string { return fi.info.Name() }
@@ -155,97 +145,26 @@ func (fi *FileInfo) Size() int64 { return fi.info.Size() }
func (fi *FileInfo) Mode() fs.FileMode { return fi.info.Mode() }
func (fi *FileInfo) ModTime() time.Time { return fi.info.ModTime() }
func (fi *FileInfo) IsDir() bool { return fi.info.IsDir() }
-func (fi *FileInfo) Sys() any { return fi }
-
-func (fi *FileInfo) statSize() uint16 {
- return uint16(2 + 4 + 13 + 4 + 4 + 4 + 8 +
- 2 + len(fi.statName()) + 2 + len(fi.statUid()) +
- 2 + len(fi.statGid()) + 2 + len(fi.statMuid()))
-}
-func (fi *FileInfo) statType() uint16 { return 0 }
-func (fi *FileInfo) statDev() uint32 { return 0 }
-func (fi *FileInfo) statQid() *Qid { return fi.qid }
-func (fi *FileInfo) statMode() uint32 { return DMDIR|0777 }
-func (fi *FileInfo) statATime() uint32 { return uint32(fi.ModTime().Unix()) }
-func (fi *FileInfo) statMTime() uint32 { return uint32(fi.ModTime().Unix()) }
-func (fi *FileInfo) statLength() uint64 {
- if fi.IsDir() {
- return 0
- } else {
- return uint64(fi.Size())
- }
-}
-func (fi *FileInfo) statName() string { return fi.Name() } // TODO: "/" for root
-func (fi *FileInfo) statUid() string { return "" }
-func (fi *FileInfo) statGid() string { return "" }
-func (fi *FileInfo) statMuid() string { return "" }
-func (fi *FileInfo) conv2M() []byte {
- cur := 0
- buf := make([]byte, 2 + fi.statSize())
- pbit16(buf[cur:cur+2], fi.statSize())
- cur += 2
- pbit16(buf[cur:cur+2], fi.statType())
- cur += 2
- pbit32(buf[cur:cur+4], fi.statDev())
- cur += 4
- qidBuf := fi.statQid().conv2M()
- for i := 0; i < len(qidBuf); i++ {
- buf[cur+i] = qidBuf[i]
- }
- cur += len(qidBuf)
- pbit32(buf[cur:cur+4], fi.statMode())
- cur += 4
- pbit32(buf[cur:cur+4], fi.statATime())
- cur += 4
- pbit32(buf[cur:cur+4], fi.statMTime())
- cur += 4
- pbit64(buf[cur:cur+8], fi.statLength())
- cur += 8
- name := fi.statName()
- pbit16(buf[cur:cur+2], uint16(len(name)))
- cur += 2
- for i := 0; i < len(name); i++ {
- buf[cur+i] = name[i]
- }
- cur += len(name)
- uid := fi.statUid()
- pbit16(buf[cur:cur+2], uint16(len(uid)))
- cur += 2
- for i := 0; i < len(uid); i++ {
- buf[cur+i] = uid[i]
- }
- cur += len(uid)
- gid := fi.statGid()
- pbit16(buf[cur:cur+2], uint16(len(gid)))
- cur += 2
- for i := 0; i < len(gid); i++ {
- buf[cur+i] = gid[i]
- }
- cur += len(gid)
- muid := fi.statMuid()
- pbit16(buf[cur:cur+2], uint16(len(muid)))
- cur += 2
- for i := 0; i < len(muid); i++ {
- buf[cur+i] = muid[i]
- }
- cur += len(muid)
- if len(buf) != cur {
- panic(fmt.Errorf("cursor position %d and buf length %d don't match",
- cur, len(buf)))
- }
- return buf
-}
-func (fi *FileInfo) String() string {
- return fmt.Sprintf("'%s' '%s' '%s' '%s' q %v m %#o at %d mt %d l %d t %d d %d",
- fi.statName(), fi.statUid(), fi.statGid(), fi.statMuid(),
- fi.statQid(), fi.statMode(), fi.statATime(), fi.statMTime(),
- fi.statLength(), fi.statType(), fi.statDev())
-}
+func (fi *FileInfo) Sys() any { return fi.stat }
type File struct {
fs *FS // file system to which this file belongs
file fs.File // underlying file
qid *Qid
+ path string // absolute path from the root of the fs.
+}
+
+func newFile(fsys *FS, file fs.File) (*File, error) {
+ f := &File{
+ fs: fsys,
+ file: file,
+ }
+ q, err := fsys.qidPool.alloc(f)
+ if err != nil {
+ return nil, fmt.Errorf("alloc qid for file %v: %v", file, err)
+ }
+ f.qid = q
+ return f, nil
}
func (f *File) Stat() (*FileInfo, error) {
@@ -254,9 +173,13 @@ func (f *File) Stat() (*FileInfo, error) {
return nil, fmt.Errorf("stat file: %v, %v", f, err)
}
fi := &FileInfo{
- info: fsfi,
- qid: f.qid,
- // TODO: t, dev, uid, gid, muid
+ info: fsfi,
+ stat: &stat{
+ qid: f.qid,
+ name: path.Base(f.path),
+ mode: uint32(fsfi.Mode()), // TODO: convert
+ },
+ // TODO: ..., uid, gid, muid
}
return fi, nil
}
@@ -306,15 +229,21 @@ func (f *File) ReadDir(n int) ([]*DirEntry, error) {
}
de := make([]*DirEntry, len(fsde))
for i := 0; i < len(de); i++ {
- fsinfo, err := fsde[i].Info()
+ fpath := path.Join(f.path, fsde[i].Name())
+ file, err := f.fs.Open(fpath)
+ 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)
}
de[i] = &DirEntry{
dirEnt: fsde[i],
- info: &FileInfo{fsinfo, &Qid{path:f.fs.nextQid}}, // TODO: need mutex?
+ info: info,
+ file: file,
}
- f.fs.nextQid++
}
return de, nil
}
@@ -322,6 +251,7 @@ func (f *File) ReadDir(n int) ([]*DirEntry, error) {
type DirEntry struct {
dirEnt fs.DirEntry // underlying fs.DirEntry
info *FileInfo
+ file *File
}
func (e *DirEntry) Name() string { return e.dirEnt.Name() }
@@ -334,8 +264,8 @@ func (f *File) Close() error {
}
type FS struct {
- nextQid uint64 // next qid to be used
- fs fs.FS // underlying file system
+ fs fs.FS // underlying file system
+ qidPool *QidPool
}
func (fsys *FS) Open(name string) (*File, error) {
@@ -343,39 +273,11 @@ func (fsys *FS) Open(name string) (*File, error) {
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()
+ file, err := newFile(fsys, f)
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
+ return nil, fmt.Errorf("newFile(%v): %v", file, err)
}
- if mode&fs.ModeTemporary != 0 {
- qtype |= QTTMP
- }
- if mode&fs.ModeSymlink != 0 {
- qtype |= QTSYMLINK
- }
- // TODO: QTAUTH
- qid.SetType(qtype)
- fsys.nextQid++
-
- file := &File{
- fs: fsys,
- file: f,
- qid: qid,
- }
-
+ file.path = name
return file, nil
}
diff --git a/fs.go b/fs.go
@@ -0,0 +1,29 @@
+package lib9p
+
+import (
+ "io/fs"
+)
+
+func fsModeToQidType(fm fs.FileMode) QidType {
+ var qt QidType
+ if fm | fs.ModeDir != 0 {
+ qt |= QTDIR
+ }
+ if fm | fs.ModeAppend != 0 {
+ qt |= QTAPPEND
+ }
+ if fm | fs.ModeExclusive != 0 {
+ qt |= QTEXCL
+ }
+ if fm | fs.ModeTemporary != 0 {
+ qt |= QTTMP
+ }
+ if fm | fs.ModeSymlink != 0 {
+ qt |= QTSYMLINK
+ }
+ // QTMOUNT is not in fs.FileMode.
+ // ModeDevice, ModeNamedPope, ModeSocket, ModeSetuid,
+ // ModeSetgid, ModeCharDevice, ModeSticky, ModeIrregular
+ // are not in QidType.
+ return qt
+}
+\ No newline at end of file
diff --git a/server.go b/server.go
@@ -28,7 +28,10 @@ type Server struct {
func NewServer(fs fs.FS, mSize uint32, r io.Reader, w io.Writer) *Server {
s := new(Server)
- s.FS = &FS{fs: fs}
+ s.FS = &FS{
+ fs: fs,
+ qidPool: allocQidPool(),
+ }
s.MSize = mSize
s.fPool = allocFidPool()
s.rPool = allocReqPool()
@@ -139,7 +142,17 @@ func sAttach(s *Server, r *Req) {
fid.Uid = ifcall.UName()
fid.OMode = OREAD
- fid.Qid = fid.File.qid
+ info, err := fid.File.Stat()
+ if err != nil {
+ log.Printf("stat %s, %v", fid.File, err)
+ respond(r, fmt.Errorf("internal error"))
+ return
+ }
+ stat, ok := info.Sys().(*stat)
+ if !ok {
+ panic("not stat")
+ }
+ fid.Qid = stat.qid
ofcall := &RAttach{
tag: ifcall.Tag(),
@@ -184,7 +197,17 @@ func sWalk(s *Server, r *Req) {
return
}
newFid.Uid = oldFid.Uid
- newFid.Qid = newFid.File.qid
+ info, err := newFid.File.Stat()
+ if err != nil {
+ log.Printf("stat %v, %v", newFid.File, err)
+ respond(r, fmt.Errorf("internal error"))
+ return
+ }
+ stat, ok := info.Sys().(*stat)
+ if !ok {
+ panic("not stat")
+ }
+ newFid.Qid = stat.qid
ofcall := &RWalk{
tag: r.ifcall.Tag(),
@@ -244,10 +267,12 @@ func sOpen(s *Server, r *Req) {
respond(r, fmt.Errorf("internal error"))
return
}
+ /*
if !ok {
respond(r, fmt.Errorf("permission denied"))
return
}
+ */
if ifcall.Mode()&ORCLOSE != 0 {
panic("ORCLOSE not implemented")
@@ -294,7 +319,27 @@ func sRead(s *Server, r *Req) {
return
}
if fi.IsDir() {
-
+ de, err := fid.File.ReadDir(-1)
+ if err != nil {
+ respond(r, err)
+ return
+ }
+ for _, e := range de {
+ info, err := e.Info()
+ if err != nil {
+ respond(r, err)
+ return
+ }
+ st, ok := info.Sys().(*stat)
+ if !ok {
+ panic("not stat")
+ }
+ buf := st.marshal()
+ for i := 0; i < len(buf); i++ {
+ data[n+i] = buf[i]
+ }
+ n += len(buf)
+ }
} else {
n, err = fid.File.ReadAt(data, int64(ifcall.Offset()))
if err != nil {
@@ -302,7 +347,6 @@ func sRead(s *Server, r *Req) {
return
}
}
-
ofcall := &RRead{
tag: ifcall.Tag(),
count: uint32(n),
@@ -421,7 +465,7 @@ func respond(r *Req, err error) {
if chatty9P {
fmt.Fprintf(os.Stderr, "--> %s\n", r.ofcall)
}
- r.srv.Writer.Write(r.ofcall.conv2M())
+ r.srv.Writer.Write(r.ofcall.marshal())
// free tag.
if r.pool == nil && err != EDupTag {