commit c2a30f351932ac96a20217c786e699fe1d89e070
parent 5b2a845a3d4ac65006109f36f9ef38108ddfe379
Author: Matsuda Kenji <info@mtkn.jp>
Date: Fri, 8 Sep 2023 08:04:07 +0900
found probrem
fs.ReadDirFile.ReadDir() returns []fs.DirEntry once, and
subsequent call returns nothing.
Diffstat:
4 files changed, 67 insertions(+), 17 deletions(-)
diff --git a/diskfs/file.go b/diskfs/file.go
@@ -5,6 +5,7 @@ import (
"io/fs"
"os"
"os/user"
+ "path"
"strconv"
"syscall"
@@ -77,6 +78,32 @@ func (f *File) Read(b []byte) (int, error) {
return f.file.Read(b)
}
+func (f *File) Parent() (lib9p.File, error) {
+ parentPath := path.Dir(f.path)
+ parent, err := f.fs.Open(parentPath)
+ if err != nil {
+ return nil, fmt.Errorf("open parent: %v", err)
+ }
+ return parent, nil
+}
+
+func (f *File) Child() ([]lib9p.File, error) {
+ de, err := f.ReadDir(-1)
+ if err != nil {
+ return nil, fmt.Errorf("read dir: %v", err)
+ }
+ children := make([]lib9p.File, len(de))
+ for i := 0; i < len(de); i++ {
+ childPath := path.Join(f.PathName(), de[i].Name())
+ file, err := f.fs.Open(childPath)
+ if err != nil {
+ return children, fmt.Errorf("open child: %v", err)
+ }
+ children[i] = file
+ }
+ return children, nil
+}
+
func (f *File) ReadAt(p []byte, off int64) (int, error) {
return f.file.ReadAt(p, off)
}
diff --git a/file.go b/file.go
@@ -6,9 +6,13 @@ import (
type File interface {
fs.File
+
// I think Files should be identified by Qid.Path, but os.Files
// are indexed by path.
PathName() string // path from the root of the fs which this file belongs to.
+
+ Parent() (File, error)
+ Child() ([]File, error)
}
type ReadDirFile interface {
diff --git a/fs.go b/fs.go
@@ -1,6 +1,7 @@
package lib9p
import (
+ "fmt"
"io/fs"
"path"
)
@@ -28,6 +29,23 @@ func walk(fsys FS, root string, wnames []string) ([]Qid, error) {
return wqids, nil
}
+func walkfile(f File, name string) (File, error) {
+ children, err := f.Child()
+ if err != nil {
+ return nil, fmt.Errorf("get children: %v", err)
+ }
+ for _, child := range children {
+ s, err := child.Stat()
+ if err != nil {
+ return nil, fmt.Errorf("stat: %v", err)
+ }
+ if s.Name() == name {
+ return child, nil
+ }
+ }
+ return nil, fmt.Errorf("not found")
+}
+
func FSModeToQidType(fm fs.FileMode) QidType {
var qt QidType
if fm&fs.ModeDir != 0 {
diff --git a/server.go b/server.go
@@ -6,7 +6,6 @@ import (
"io/fs"
"log"
"os"
- "path"
"strings"
)
@@ -174,24 +173,26 @@ func sWalk(s *Server, r *Req) {
return
}
- wqids, err := walk(s.fs, oldFid.File.PathName(), ifcall.WName())
- if err != nil {
- s.fPool.delete(ifcall.NewFid())
- log.Printf("walk fs: %v", err)
- respond(r, fmt.Errorf("walk error"))
- return
- }
-
- relPath := path.Join(ifcall.WName()...)
- absPath := path.Join(oldFid.File.PathName(), relPath)
- f, err := s.fs.Open(absPath)
- if err != nil {
- log.Printf("open root dir: %v", err)
- respond(r, fmt.Errorf("internal error"))
- return
+ wqids := make([]Qid, ifcall.NWName())
+ cwd := oldFid.File
+ for i, name := range ifcall.WName() {
+ child, err := walkfile(cwd, name)
+ if err != nil {
+ s.fPool.delete(ifcall.NewFid())
+ respond(r, fmt.Errorf("walk: %v", err))
+ return
+ }
+ stat, err := child.Stat()
+ if err != nil {
+ s.fPool.delete(ifcall.NewFid())
+ respond(r, fmt.Errorf("stat: %v", err))
+ return
+ }
+ wqids[i] = stat.(*FileInfo).Qid()
+ cwd = child
}
- newFid.File = f.(File)
+ newFid.File = cwd
newFid.Uid = oldFid.Uid
info, err := newFid.File.Stat()
if err != nil {