commit 7af35432538fdae5ad2f6b3d4a469e37ea877a65
parent 2d9142feb469878243bedcff010c1003415e0550
Author: Matsuda Kenji <info@mtkn.jp>
Date: Wed, 25 Oct 2023 06:37:48 +0900
add comment
Diffstat:
| D | diskfs/diskfs.go | | | 61 | ------------------------------------------------------------- |
| M | diskfs/file.go | | | 89 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | diskfs/stat_unix.go | | | 44 | +++++++++++++++++++++++++++++++++++++++++++- |
3 files changed, 88 insertions(+), 106 deletions(-)
diff --git a/diskfs/diskfs.go b/diskfs/diskfs.go
@@ -1,61 +0,0 @@
-package diskfs
-
-import (
- "fmt"
- "io/fs"
- "os"
- "path/filepath"
-
- "git.mtkn.jp/lib9p"
-)
-
-/*
-DiskFS is a file system opened by OpenDiskFS
-*/
-type FS struct {
- rootPath string
- qidPool *QidPool
-}
-
-func Open(name string) (*FS, error) {
- f, err := os.Open(name)
- if err != nil {
- return nil, err
- }
- if err := f.Close(); err != nil {
- panic(err)
- }
- root := &File{
- path: ".",
- }
- fsys := &FS{
- rootPath: name,
- qidPool: allocQidPool(),
- }
- root.fs = fsys
- return fsys, nil
-}
-
-func (fsys *FS) OpenFile(name string, omode lib9p.OpenMode, perm fs.FileMode) (lib9p.File, error) {
- fp := filepath.Join(fsys.rootPath, name)
- var m int
- switch omode & 3 {
- case lib9p.OREAD:
- m = os.O_RDONLY
- case lib9p.OWRITE:
- m = os.O_WRONLY
- case lib9p.ORDWR:
- m = os.O_RDWR
- }
- if omode&lib9p.OTRUNC != 0 {
- m |= os.O_TRUNC
- }
- if omode&lib9p.ORCLOSE != 0 {
- return nil, fmt.Errorf("orclose not implemented")
- }
- osf, err := os.OpenFile(fp, m, perm)
- if err != nil {
- return nil, err
- }
- return &File{fs: fsys, path: name, file: osf}, nil
-}
diff --git a/diskfs/file.go b/diskfs/file.go
@@ -2,12 +2,12 @@ package diskfs
import (
"fmt"
+ "io"
"io/fs"
"os"
"os/user"
"path/filepath"
"strconv"
- "syscall"
"git.mtkn.jp/lib9p"
)
@@ -17,46 +17,21 @@ type File struct {
fs *FS // file system to which this file belongs
path string // relative path from the root of the fs.
file *os.File // underlying file. nil if not open.
+ dirIndex int // index for ReadDir
}
+// Stat returns the *lib9p.FileInfo structure describing file.
func (f *File) Stat() (*lib9p.FileInfo, error) {
- ospath := filepath.Join(f.fs.rootPath, f.path)
- fsfi, err := os.Stat(ospath)
- if err != nil {
- return nil, fmt.Errorf("stat: %v", err)
- }
- var stat lib9p.Stat
- stat.Type = 0
- stat.Dev = 0
- qid, ok := f.fs.qidPool.lookup(f)
- if !ok {
- qid, err = f.fs.qidPool.alloc(f)
- if err != nil {
- panic(fmt.Errorf("alloc qid: %v", err))
- }
- }
- stat.Qid = qid
- stat.Length = fsfi.Size()
- stat.Mode = fsfi.Mode()
- stat.Name = fsfi.Name()
- stat.Atime = uint32(fsfi.Sys().(*syscall.Stat_t).Atim.Sec)
- stat.Mtime = uint32(fsfi.Sys().(*syscall.Stat_t).Mtim.Sec)
- uid := fsfi.Sys().(*syscall.Stat_t).Uid
- usr, err := user.LookupId(strconv.Itoa(int(uid)))
- if err != nil {
- return nil, fmt.Errorf("LookupId(%d): %v", uid, err)
- }
- stat.Uid = usr.Username
- gid := fsfi.Sys().(*syscall.Stat_t).Gid
- group, err := user.LookupGroupId(strconv.Itoa(int(gid)))
- if err != nil {
- return nil, fmt.Errorf("LookupGroupId(%d): %v", gid, err)
- }
- stat.Gid = group.Name
- stat.Muid = ""
- return &lib9p.FileInfo{stat}, nil
+ return f.stat()
+}
+
+// WStat updates the stat of the file.
+func (f *File) WStat(s *lib9p.Stat) error {
+ return f.wstat(s)
}
+// Create creates file named name in the directory f, and returns the
+// newly created file.
func (f *File) Create(name string, uid string,
mode lib9p.OpenMode, perm lib9p.FileMode) (lib9p.File, error) {
dirinfo, err := f.Stat()
@@ -66,7 +41,6 @@ func (f *File) Create(name string, uid string,
if !dirinfo.IsDir() {
return nil, fmt.Errorf("not a directory")
}
-
ospath := filepath.Join(f.fs.rootPath, f.path, name)
if perm&fs.ModeDir != 0 {
if err := os.Mkdir(ospath, perm); err != nil {
@@ -79,7 +53,6 @@ func (f *File) Create(name string, uid string,
}
osfile.Close()
}
-
usr, err := user.Lookup(uid)
if err != nil {
return nil, fmt.Errorf("lookup user: %v", err)
@@ -99,11 +72,9 @@ func (f *File) Create(name string, uid string,
if err := os.Chown(ospath, u, g); err != nil {
return nil, fmt.Errorf("set owner and group: %v", err)
}
-
if err := os.Chmod(ospath, perm); err != nil {
return nil, fmt.Errorf("set file mode: %v", err)
}
-
file, err := f.fs.OpenFile(filepath.Join(f.path, name), mode, 0)
if err != nil {
return nil, fmt.Errorf("open new file: %v", err)
@@ -111,6 +82,7 @@ func (f *File) Create(name string, uid string,
return file, nil
}
+// Close closes the file.
func (f *File) Close() error {
if f.file == nil {
return fmt.Errorf("not open")
@@ -122,6 +94,9 @@ func (f *File) Close() error {
return nil
}
+// Read reads up to len(b) bytes from the File and stores them in b.
+// It returns the number of bytes read and any error encountered.
+// At end of file. Read returns 0, io.EOF.
func (f *File) Read(b []byte) (int, error) {
if f.file == nil {
return 0, fmt.Errorf("not open")
@@ -129,20 +104,46 @@ func (f *File) Read(b []byte) (int, error) {
return f.file.Read(b)
}
+// ReadDir reads the contents of the directory and returns
+// a slice of up to n *lib9p.DirEntry values in directory order.
+// Subsequent calls on the same file will yield further DirEntry values.
+//
+// If n > 0, ReadDir returns at most n DirEntry structures.
+// In this case, if ReadDir returns an empty slice, it will return
+// a non-nil error explaining why.
+// At the end of a directory, the error is io.EOF.
+// (ReadDir must return io.EOF itself, not an error wrapping io.EOF.)
+//
+// If n <= 0, ReadDir returns all the DirEntry values from the directory
+// in a single slice. In this case, if ReadDir succeeds (reads all the way
+// to the end of the directory), it returns the slice and a nil error.
+// If it encounters an error before the end of the directory,
+// ReadDir returns the DirEntry list read until that point and a non-nil error.
func (f *File) ReadDir(n int) ([]*lib9p.DirEntry, error) {
ospath := filepath.Join(f.fs.rootPath, f.path)
osde, err := os.ReadDir(ospath)
if err != nil {
return nil, fmt.Errorf("readdir: %v", err)
}
- de := make([]*lib9p.DirEntry, len(osde))
- for i, e := range osde {
- fi, err := e.Info()
+ if len(osde) <= f.dirIndex {
+ return nil, io.EOF
+ }
+ de := make([]*lib9p.DirEntry, len(osde) - f.dirIndex)
+ var m int
+ if n <= 0 {
+ m = len(osde)
+ } else if len(osde) - f.dirIndex > n {
+ m = f.dirIndex + n
+ } else {
+ m = len(osde)
+ }
+ for i := f.dirIndex; i < m; i++ {
+ fi, err := osde[i].Info()
if err != nil {
return nil, fmt.Errorf("info: %v", err)
}
id := idFromInfo(fi)
- de[i] = &lib9p.DirEntry{Stat: *fiStat(f.fs.qidPool, id, fi)}
+ de[i - f.dirIndex] = &lib9p.DirEntry{Stat: *fiStat(f.fs.qidPool, id, fi)}
}
return de, nil
}
diff --git a/diskfs/stat_unix.go b/diskfs/stat_unix.go
@@ -6,6 +6,7 @@ import (
"os"
"os/user"
"path"
+ "path/filepath"
"strconv"
"syscall"
"time"
@@ -48,8 +49,49 @@ func fiStat(pool *QidPool, id fileID, info fs.FileInfo) *lib9p.Stat {
}
}
+// Stat is real implementation of Stat.
+func (f *File) stat() (*lib9p.FileInfo, error) {
+ ospath := filepath.Join(f.fs.rootPath, f.path)
+ fsfi, err := os.Stat(ospath)
+ if err != nil {
+ return nil, fmt.Errorf("stat: %v", err)
+ }
+ var stat lib9p.Stat
+ stat.Type = 0
+ stat.Dev = 0
+ qid, ok := f.fs.qidPool.lookup(f)
+ if !ok {
+ qid, err = f.fs.qidPool.alloc(f)
+ if err != nil {
+ panic(fmt.Errorf("alloc qid: %v", err))
+ }
+ }
+ stat.Qid = qid
+ stat.Length = fsfi.Size()
+ stat.Mode = fsfi.Mode()
+ stat.Name = fsfi.Name()
+ // TODO: Unix specific.
+ stat.Atime = uint32(fsfi.Sys().(*syscall.Stat_t).Atim.Sec)
+ stat.Mtime = uint32(fsfi.Sys().(*syscall.Stat_t).Mtim.Sec)
+ uid := fsfi.Sys().(*syscall.Stat_t).Uid
+ usr, err := user.LookupId(strconv.Itoa(int(uid)))
+ if err != nil {
+ return nil, fmt.Errorf("LookupId(%d): %v", uid, err)
+ }
+ stat.Uid = usr.Username
+ gid := fsfi.Sys().(*syscall.Stat_t).Gid
+ group, err := user.LookupGroupId(strconv.Itoa(int(gid)))
+ if err != nil {
+ return nil, fmt.Errorf("LookupGroupId(%d): %v", gid, err)
+ }
+ stat.Gid = group.Name
+ stat.Muid = ""
+ return &lib9p.FileInfo{stat}, nil
+}
+
+
// TODO: when error occurs, file stat should be restored.
-func (f *File) WStat(s *lib9p.Stat) error {
+func (f *File) wstat(s *lib9p.Stat) error {
file, err := os.OpenFile(path.Join(f.fs.rootPath, f.path), os.O_RDWR, 0)
if err != nil {
return err