lib9p

Go 9P library.
Log | Files | Refs

commit 0b14ec5ecaa1c3bf35928a5ca78f6e67cd273272
parent 02e91e7befd7522bc0b1c0aab79b90525e1e05f4
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sat, 23 Sep 2023 08:38:37 +0900

update cmd

Diffstat:
Mcmd/disk.go | 5++++-
Mdiskfs/diskfs.go | 30++++++++++++++++++------------
Mdiskfs/file.go | 226+++++++++++++++++++++++++++++++++++++------------------------------------------
Mdiskfs/qid_unix.go | 26++++++++------------------
4 files changed, 137 insertions(+), 150 deletions(-)

diff --git a/cmd/disk.go b/cmd/disk.go @@ -36,7 +36,10 @@ func main() { log.Printf("accept connection: %v", err) continue } - disk := diskfs.Open(flag.Arg(0)) + disk, err := diskfs.Open(flag.Arg(0)) + if err != nil { + log.Fatalf("open file tree.") + } go handle(conn, disk) } } diff --git a/diskfs/diskfs.go b/diskfs/diskfs.go @@ -1,7 +1,6 @@ package diskfs import ( - "io/fs" "os" "lib9p" @@ -11,24 +10,31 @@ import ( DiskFS is a file system opened by OpenDiskFS */ type FS struct { - fs fs.FS rootPath string + root *File qidPool *QidPool } -func Open(name string) *FS { - fsys := os.DirFS(name) - return &FS{ - fs: fsys, +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{ + root: root, rootPath: name, qidPool: allocQidPool(), } + root.fs = fsys + return fsys, nil } -func (fsys *FS) Open(name string) (lib9p.File, error) { - file, err := openFile(fsys, name, lib9p.ORDWR) - if err != nil { - return nil, err - } - return file, nil +func (fsys *FS) Root() lib9p.File { + return fsys.root } diff --git a/diskfs/file.go b/diskfs/file.go @@ -4,7 +4,7 @@ import ( "fmt" "os" "os/user" - "path" + "path/filepath" "strconv" "syscall" @@ -13,56 +13,8 @@ import ( type File struct { fs *FS // file system to which this file belongs - path string // absolute path from the root of the fs. -} - -func getChildEntry(fsys *FS, dir *os.File) ([]*lib9p.DirEntry, error) { - fi, err := dir.Stat() - if err != nil { - return nil, fmt.Errorf("stat: %v", err) - } - var childEntry []*lib9p.DirEntry - if !fi.IsDir() { - return nil, fmt.Errorf("not a directory") - } - - de, err := dir.ReadDir(-1) - if err != nil { - return nil, fmt.Errorf("read dir: %v", err) - } - childEntry = make([]*lib9p.DirEntry, len(de)) - for i := 0; i < len(de); i++ { - info, err := de[i].Info() - if err != nil { - return nil, fmt.Errorf("info: %v", err) - } - // TODO: unix specific - sys := info.Sys().(*syscall.Stat_t) - id := fileID{ - device: sys.Dev, - inode: sys.Ino, - } - stat := fiStat(fsys.qidPool, id, info) - childEntry[i] = &lib9p.DirEntry{Stat: *stat} - } - return childEntry, nil -} - -func openFile(fsys *FS, fpath string, mode lib9p.OpenMode) (*File, error) { - // TODO: check if path exists. -/* - fsfile, err := fsys.fs.Open(fpath) - if err != nil { - return nil, fmt.Errorf("fs open: %v", err) - } - fsfile.Close() -*/ - - f := &File{ - fs: fsys, - path: fpath, - } - return f, nil + path string // relative path from the root of the fs. + file *os.File // underlying file. nil if not open. } func (f *File) Fsys() lib9p.FS { @@ -70,13 +22,8 @@ func (f *File) Fsys() lib9p.FS { } func (f *File) Stat() (*lib9p.FileInfo, error) { - file, err := f.fs.fs.Open(f.path) - if err != nil { - return nil, fmt.Errorf("open: %v", err) - } - defer file.Close() - - fsfi, err := file.Stat() + ospath := filepath.Join(f.fs.rootPath, f.path) + fsfi, err := os.Stat(ospath) if err != nil { return nil, fmt.Errorf("stat: %v", err) } @@ -112,70 +59,42 @@ func (f *File) Stat() (*lib9p.FileInfo, error) { return &lib9p.FileInfo{stat}, nil } -func (f *File) Close() error { - return nil -} - -func (f *File) Read(b []byte) (int, error) { - file, err := f.fs.fs.Open(f.path) - if err != nil { - return 0, fmt.Errorf("open: %v", err) - } - defer file.Close() - return 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) +func (f *File) Qid() lib9p.Qid { + qid, ok := f.fs.qidPool.lookup(f) + if !ok { + var err error + qid, err = f.fs.qidPool.alloc(f) + if err != nil { + panic(fmt.Errorf("alloc qid: %v", err)) + } } - return parent, nil + return qid } -func (f *File) Child() ([]lib9p.File, error) { - var err error - dir, err := f.fs.fs.Open(f.path) - if err != nil { - return nil, err +func (f *File) Open(mode lib9p.OpenMode) error { + var flag int + switch mode&3 { + case lib9p.OREAD, lib9p.OEXEC: + flag = os.O_RDONLY + case lib9p.OWRITE: + flag = os.O_WRONLY + case lib9p.ORDWR: + flag = os.O_RDWR } - file := dir.(*os.File) - childEntry, err := getChildEntry(f.fs, file) - if err != nil { - return nil, err + if mode&lib9p.OTRUNC != 0 { + flag |= os.O_TRUNC } - - files := make([]lib9p.File, 0, len(childEntry)) - for i := 0; i < len(childEntry); i++ { - cpath := path.Join(f.path, childEntry[i].Name()) - child, e := f.fs.Open(cpath) - if e != nil { - err = e - continue - } - files = append(files, child) + if mode&lib9p.ORCLOSE != 0 { + return fmt.Errorf("not implemented") } - return files, err -} -func (f *File) ReadAt(p []byte, off int64) (int, error) { - file, err := f.fs.fs.Open(f.path) - if err != nil { - return 0, fmt.Errorf("open: %v", err) - } - defer file.Close() - return file.(*os.File).ReadAt(p, off) -} - -func (f *File) WriteAt(p []byte, off int64) (int, error) { - file, err := os.OpenFile(path.Join(f.fs.rootPath, f.path), os.O_WRONLY , 0) + ospath := filepath.Join(f.fs.rootPath, f.path) + file, err := os.OpenFile(ospath, flag, 0) if err != nil { - return 0, fmt.Errorf("open: %v", err) + return fmt.Errorf("open: %v", err) } - defer file.Close() - n, err := file.WriteAt(p, off) - return n, err + f.file = file + return nil } func (f *File) Create(name string, uid string, @@ -188,7 +107,7 @@ func (f *File) Create(name string, uid string, return nil, fmt.Errorf("not a directory") } - ospath := path.Join(f.fs.rootPath, f.path, name) + ospath := filepath.Join(f.fs.rootPath, f.path, name) if perm&lib9p.DMDIR != 0 { if err := os.Mkdir(ospath, lib9p.Mode9ToFSMode(perm)); err != nil { return nil, fmt.Errorf("mkdir: %v", err) @@ -225,15 +144,84 @@ func (f *File) Create(name string, uid string, return nil, fmt.Errorf("set file mode: %v", err) } - file, err := openFile(f.fs, path.Join(f.path, name), mode) - if err != nil { + file := &File{path: filepath.Join(f.path, name), fs: f.fs} + if err := file.Open(mode); err != nil { return nil, fmt.Errorf("open new file: %v", err) } - return file, nil } + +func (f *File) Close() error { + if f.file == nil { + return fmt.Errorf("not open") + } + if err := f.file.Close(); err != nil { + return err + } + f.file = nil + return nil +} + +func (f *File) Read(b []byte) (int, error) { + if f.file == nil { + return 0, fmt.Errorf("not open") + } + return f.file.Read(b) +} + +func (f *File) Parent() (lib9p.File, error) { + parentPath := filepath.Dir(f.path) + parent, err := os.Open(filepath.Join(f.fs.rootPath, parentPath)) + if err != nil { + return nil, fmt.Errorf("open parent: %v", err) + } + parent.Close() + return &File{path: parentPath, fs: f.fs}, nil +} + +func (f *File) Child() ([]lib9p.File, error) { + ospath := filepath.Join(f.fs.rootPath, f.path) + osde, err := os.ReadDir(ospath) + if err != nil { + return nil, fmt.Errorf("readdir: %v", err) + } + + files := make([]lib9p.File, 0, len(osde)) + for _, de := range osde { + cpath := filepath.Join(f.path, de.Name()) + child := &File{ + path: cpath, + fs: f.fs, + } + files = append(files, child) + } + return files, nil +} + +func (f *File) ReadAt(p []byte, off int64) (int, error) { + if f.file == nil { + return 0, fmt.Errorf("not open") + } + return f.file.ReadAt(p, off) +} + +func (f *File) WriteAt(p []byte, off int64) (int, error) { + if f.file == nil { + return 0, fmt.Errorf("not open") + } + return f.file.WriteAt(p, off) +} + func (f *File) Remove() error { - ospath := path.Join(f.fs.rootPath, f.path) - return os.Remove(ospath) + ospath := filepath.Join(f.fs.rootPath, f.path) + if f.file != nil { + if err := f.file.Close(); err != nil { + return fmt.Errorf("close: %v", err) + } + } + if err := os.Remove(ospath); err != nil { + return fmt.Errorf("remove: %v", err) + } + return nil } \ No newline at end of file diff --git a/diskfs/qid_unix.go b/diskfs/qid_unix.go @@ -5,6 +5,8 @@ import ( "io/fs" "syscall" "time" + "path/filepath" + "os" "lib9p" ) @@ -25,12 +27,8 @@ type QidPool struct { } func (f *File) id() (fileID, error) { - file, err := f.fs.fs.Open(f.path) - if err != nil { - return fileID{}, fmt.Errorf("open: %v", err) - } - defer file.Close() - fi, err := file.Stat() + ospath := filepath.Join(f.fs.rootPath, f.path) + fi, err := os.Stat(ospath) if err != nil { return fileID{}, err } @@ -58,12 +56,8 @@ func (pool *QidPool) lookup(f *File) (lib9p.Qid, bool) { if err != nil { return lib9p.Qid{}, false } - file, err := f.fs.fs.Open(f.path) - if err != nil { - return lib9p.Qid{}, false - } - defer file.Close() - fsfi, err := file.Stat() + ospath := filepath.Join(f.fs.rootPath, f.path) + fsfi, err := os.Stat(ospath) if err != nil { return lib9p.Qid{}, false } @@ -87,12 +81,8 @@ func (pool *QidPool) alloc(f *File) (lib9p.Qid, error) { if err != nil { return lib9p.Qid{}, fmt.Errorf("get id: %v", err) } - file, err := f.fs.fs.Open(f.path) - if err != nil { - return lib9p.Qid{}, fmt.Errorf("open: %v", err) - } - defer file.Close() - fi, err := file.Stat() + ospath := filepath.Join(f.fs.rootPath, f.path) + fi, err := os.Stat(ospath) if err != nil { return lib9p.Qid{}, fmt.Errorf("stat %v: %v", f, err) }