commit 598384d1cc8241a26b999fc63e0e0c608eec3171
parent eb6c4499cd33ac8cbb06bc8af2f1467259e13414
Author: Matsuda Kenji <info@mtkn.jp>
Date: Thu, 9 Nov 2023 08:48:19 +0900
implement *clientFile.ReadDir
Diffstat:
7 files changed, 46 insertions(+), 21 deletions(-)
diff --git a/client/file.go b/client/file.go
@@ -2,7 +2,7 @@ package client
import (
"context"
- "fmt"
+ "errors"
"io"
"io/fs"
@@ -46,12 +46,12 @@ func (cf *ClientFile) Close() error {
}
func (cf *ClientFile) Read(b []byte) (int, error) {
+ if cf.fid.omode == -1 {
+ return 0, errors.New("not open")
+ }
if len(b) == 0 {
return 0, nil
}
- if cf.fid.omode == -1 {
- return 0, fmt.Errorf("not open")
- }
if cf.fid.omode&3 != lib9p.OREAD && cf.fid.omode&3 != lib9p.ORDWR {
return 0, lib9p.ErrPerm
}
@@ -87,3 +87,30 @@ func (cf *ClientFile) Read(b []byte) (int, error) {
return cur, nil
}
}
+
+// TODO: support n
+func (cf *ClientFile) ReadDir(n int) ([]fs.DirEntry, error) {
+ if cf.qid.Type&lib9p.QTDIR == 0 {
+ return nil, errors.New("not a directory")
+ }
+ if cf.fid.omode == -1 {
+ return nil, errors.New("not open")
+ }
+ tag, err := cf.fs.tPool.add()
+ if err != nil {
+ return nil, err
+ }
+ data, err := cf.fs.c.Read(context.TODO(), tag, cf.fid.fid, cf.fid.offset, cf.iounit)
+ cf.fs.tPool.delete(tag)
+ if err != nil {
+ return nil, err
+ }
+ cf.fid.offset += uint64(len(data))
+ var de []fs.DirEntry
+ for len(data) > 0 {
+ st := lib9p.NewStat(data)
+ data = data[2+st.Size():]
+ de = append(de, &lib9p.FileInfo{Stat: *st})
+ }
+ return de, nil
+}
diff --git a/client/fs.go b/client/fs.go
@@ -9,6 +9,7 @@ import (
"strings"
"git.mtkn.jp/lib9p"
+ "log"
)
// ClientFS represents the file system the client imports.
@@ -19,12 +20,14 @@ type ClientFS struct {
// Open opens the file named name in fsys.
func (fsys *ClientFS) Open(name string) (lib9p.File, error) {
+ log.Println("open:", name)
return fsys.OpenFile(name, lib9p.OREAD, 0)
}
// OpenFile opens the file named name in fsys with omode.
// If the file does not exist, it create it with perm.
func (fsys *ClientFS) OpenFile(name string, omode lib9p.OpenMode, perm fs.FileMode) (lib9p.File, error) {
+ log.Println("openfile:", name)
var (
qid lib9p.Qid
iounit uint32
diff --git a/export_fs_test.go b/export_fs_test.go
@@ -6,5 +6,5 @@ import (
)
func TestInterface(t *testing.T) {
- var _ fs.FS = exportFS{}
+ var _ fs.FS = ExportFS{}
}
\ No newline at end of file
diff --git a/export_test.go b/export_test.go
@@ -58,8 +58,6 @@ var (
NewRStat = newRStat
NewTWStat = newTWStat
NewRWStat = newRWStat
-
- NewStat = newStat
)
type BufMsg = bufMsg
@@ -76,5 +74,3 @@ func (s *Server) RunSpeaker(ctx context.Context) {
func (rp *ReqPool) Add(tag uint16) (*Req, error) { return rp.add(tag) }
func (fp *FidPool) Lookup(fid uint32) (*Fid, bool) { return fp.lookup(fid) }
-
-func (st *Stat) Size() uint16 { return st.size() }
-\ No newline at end of file
diff --git a/fcall.go b/fcall.go
@@ -1260,11 +1260,11 @@ func newRStat(buf []byte) *RStat {
msg := new(RStat)
size := gbit32(buf[:4])
msg.Tag = gbit16(buf[5:7])
- msg.Stat = newStat(buf[9:size])
+ msg.Stat = NewStat(buf[9:size])
return msg
}
func (msg *RStat) Size() uint32 {
- return uint32(4 + 1 + 2 + 2 + 2 + msg.Stat.size())
+ return uint32(4 + 1 + 2 + 2 + 2 + msg.Stat.Size())
}
func (msg *RStat) Type() MsgType { return Rstat }
func (msg *RStat) GetTag() uint16 { return msg.Tag }
@@ -1296,11 +1296,11 @@ func newTWStat(buf []byte) *TWStat {
msg := new(TWStat)
msg.Tag = gbit16(buf[5:7])
msg.Fid = gbit32(buf[7:11])
- msg.Stat = newStat(buf[13:])
+ msg.Stat = NewStat(buf[13:])
return msg
}
func (msg *TWStat) Size() uint32 {
- return uint32(4 + 1 + 2 + 4 + 2 + 2 + msg.Stat.size())
+ return uint32(4 + 1 + 2 + 4 + 2 + 2 + msg.Stat.Size())
}
func (msg *TWStat) Type() MsgType { return Twstat }
func (msg *TWStat) GetTag() uint16 { return msg.Tag }
diff --git a/stat.go b/stat.go
@@ -55,8 +55,8 @@ type Stat struct {
Muid string
}
-// newStat converts a byte array of stat from a 9P message into Stat struct.
-func newStat(b []byte) *Stat {
+// NewStat converts a byte array of stat from a 9P message into Stat struct.
+func NewStat(b []byte) *Stat {
stat := new(Stat)
size := gbit16(b[:2]) + 2
cur := 2 // ignore size field
@@ -93,12 +93,12 @@ func newStat(b []byte) *Stat {
if cur != int(size) {
panic(fmt.Errorf("size %d != cursor position %d", size, cur))
}
-
return stat
}
-// size returns the size of marshaled stat in bytes.
-func (s *Stat) size() uint16 {
+// size returns the size of marshaled stat in bytes excluding the
+// size field itself.
+func (s *Stat) Size() uint16 {
// type + dev + qid + mode + atime + mtime + length
return uint16(2 + 4 + 13 + 4 + 4 + 4 + 8 +
2 + len(s.Name) +
@@ -111,7 +111,7 @@ func (s *Stat) size() uint16 {
// in 9P conversatino.
func (s *Stat) marshal() []byte {
cur := 0
- size := s.size()
+ size := s.Size()
msg := make([]byte, 2+size)
pbit16(msg[cur:cur+2], size)
cur += 2
diff --git a/stat_test.go b/stat_test.go
@@ -17,7 +17,7 @@ func TestStatMarshal(t *testing.T) {
Uid: "10", Gid: "11", Muid: "12"}},
}
for _, test := range tests {
- got := newStat(test.stat.marshal())
+ got := NewStat(test.stat.marshal())
if !reflect.DeepEqual(got, test.stat) {
t.Errorf("%s: got: %v, want: %v", test.name, got, test.stat)
}