lib9p

Go 9P library.
Log | Files | Refs | LICENSE

commit 7af35432538fdae5ad2f6b3d4a469e37ea877a65
parent 2d9142feb469878243bedcff010c1003415e0550
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Wed, 25 Oct 2023 06:37:48 +0900

add comment

Diffstat:
Ddiskfs/diskfs.go | 61-------------------------------------------------------------
Mdiskfs/file.go | 89++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mdiskfs/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