lib9p

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

commit 50f4afc20fb2da188312238ae02e0219bde7d4cc
parent 7b859127166c4c370fb721ac8d88d81b22486bc9
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Wed,  8 Nov 2023 09:55:04 +0900

add plan9 files

Diffstat:
Adiskfs/qid_plan9.go | 18++++++++++++++++++
Adiskfs/stat_plan9.go | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 138 insertions(+), 0 deletions(-)

diff --git a/diskfs/qid_plan9.go b/diskfs/qid_plan9.go @@ -0,0 +1,18 @@ +//go:build plan9 +package diskfs + +import ( + "io/fs" +) + +type fileID struct{} + +func idFromInfo(fi fs.FileInfo) fileID { return fileID{} } + +// QidPool is the list of Qids in the file system. +type QidPool struct {} + +// newQidPool allocates a QidPool. +func newQidPool() *QidPool { + return &QidPool{} +} diff --git a/diskfs/stat_plan9.go b/diskfs/stat_plan9.go @@ -0,0 +1,120 @@ +//go:build plan9 +package diskfs + +import ( + "fmt" + "io/fs" + "os" + "os/user" + "path" + "strconv" + "syscall" + "time" + + "git.mtkn.jp/lib9p" +) + +// fiStat generates lib9p.Stat from the FileInfo. +// It requires QidPool and fileID to fill the Qid field of Stat. +func fiStat(pool *QidPool, id fileID, info fs.FileInfo) *lib9p.Stat { + dir := info.Sys().(*syscall.Dir) + qid := lib9p.Qid{ + Type: lib9p.QidType(dir.Qid.Type), + Vers: dir.Qid.Vers, + Path: dir.Qid.Path, + } + return &lib9p.Stat{ + Type: dir.Type, + Dev: dir.Dev, + Qid: qid, + Mode: info.Mode(), + Atime: dir.Atime, + Mtime: dir.Mtime, + Length: dir.Length, + Name: dir.Name, + Uid: dir.Uid, + Gid: dir.Gid, + Muid: dir.Muid, + } +} + +// Stat is real implementation of File.Stat. +func (f *File) stat() (*lib9p.FileInfo, error) { + fi, err := f.file.Stat() + if err != nil { + return nil, fmt.Errorf("stat: %v", err) + } + return &lib9p.FileInfo{Stat: *fiStat(nil, fileID{}, fi)}, nil +} + +// wstat is the real implementation of File.WStat. +// TODO: when error occurs, file stat should be restored. +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 + } + defer file.Close() + + fi, err := f.Stat() + if err != nil { + return fmt.Errorf("stat: %v", err) + } + + oldStat := fi.Sys().(*lib9p.Stat) + + if s.Name != oldStat.Name { + // TODO: check neither Names contains "/" + oldpath := path.Join(f.fs.rootPath, path.Dir(f.path), oldStat.Name) + newpath := path.Join(f.fs.rootPath, path.Dir(f.path), s.Name) + if err := os.Rename(oldpath, newpath); err != nil { + return fmt.Errorf("rename: %v", err) + } + } + if s.Length != oldStat.Length { + if err := file.Truncate(s.Length); err != nil { + return fmt.Errorf("truncate: %v", err) + } + ret, err := file.Seek(0, 0) + if err != nil { + return fmt.Errorf("seek 0: %d, %w", ret, err) + } + } + if s.Mode != oldStat.Mode { + if err := file.Chmod(s.Mode); err != nil { + return fmt.Errorf("chmod: %v", err) + } + } + if s.Mtime != oldStat.Mtime { + err := os.Chtimes(f.path, time.Time{}, time.Unix(int64(s.Mtime), 0)) + if err != nil { + return fmt.Errorf("chtimes: %v", err) + } + } + + if s.Gid != oldStat.Gid { + return fmt.Errorf("not implemented in plan9") + group, err := user.LookupGroup(s.Gid) + if err != nil { + return fmt.Errorf("lookupgroup: %v", err) + } + usr, err := user.Lookup(oldStat.Uid) + if err != nil { + return fmt.Errorf("lookup user: %v", err) + } + u, err := strconv.Atoi(usr.Uid) + if err != nil { + return fmt.Errorf("convert uid: %v", err) + } + g, err := strconv.Atoi(group.Gid) + if err != nil { + return fmt.Errorf("convert gid: %v", err) + } + + if err := file.Chown(u, g); err != nil { + return fmt.Errorf("chown: %v", err) + } + } + + return nil +}