lib9p

Go 9P library.
Log | Files | Refs

commit d90eb452034a44596173aec28deca11a49199ebb
parent 9eb89f2b634166824f52ccdd00f4b51c79792789
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue, 12 Sep 2023 07:08:43 +0900

implement wstat
chgroup is not yet

Diffstat:
Mdiskfs/file.go | 6------
Mdiskfs/stat.go | 39+++++++++++++++++++++++++++++++++++++++
Mfcall.go | 2+-
Mserver.go | 58++++++++++++++++++++++++++++++++++++++--------------------
Mtestdir/a | 2+-
Mtestdir/b | 2+-
Muid.go | 15++++++++-------
7 files changed, 88 insertions(+), 36 deletions(-)

diff --git a/diskfs/file.go b/diskfs/file.go @@ -151,7 +151,6 @@ func (f *File) ReadAt(p []byte, off int64) (int, error) { func (f *File) WriteAt(p []byte, off int64) (int, error) { n, err := f.file.WriteAt(p, off) - fmt.Printf("n, err: %d, %v\n", n, err) return n, err } @@ -164,7 +163,3 @@ func (f *File) ReadDir(n int) ([]*lib9p.DirEntry, error) { f.diroff += n return childEntry[:n], nil } - -func (f *File) WStat(s *lib9p.Stat) error { - return fmt.Errorf("unimplemented") -} -\ No newline at end of file diff --git a/diskfs/stat.go b/diskfs/stat.go @@ -3,9 +3,11 @@ package diskfs import ( "fmt" "io/fs" + "os" "os/user" "strconv" "syscall" + "time" "lib9p" ) @@ -44,3 +46,39 @@ func fiStat(pool *QidPool, id fileID, info fs.FileInfo) *lib9p.Stat { Muid: "", } } + +func (f *File) WStat(s *lib9p.Stat) error { + fi, err := f.Stat() + if err != nil { + return fmt.Errorf("stat: %v", err) + } + + oldStat := fi.Sys().(*lib9p.Stat) + + if s.Name != oldStat.Name { + if err := os.Rename(oldStat.Name, s.Name); err != nil { + return fmt.Errorf("rename: %v", err) + } + } + if s.Length != oldStat.Length { + if err := f.file.Truncate(s.Length); err != nil { + return fmt.Errorf("truncate: %v", err) + } + } + if s.Mode != oldStat.Mode { + if err := f.file.Chmod(lib9p.Mode9ToFSMode(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("chgroup unimplemented") + } + + return nil +} +\ No newline at end of file diff --git a/fcall.go b/fcall.go @@ -1024,7 +1024,7 @@ func (msg *TWrite) marshal() []byte { return buf } func (msg *TWrite) String() string { - return fmt.Sprintf("Tread tag %d fid %d offset %d count %d '%s'", + return fmt.Sprintf("Twrite tag %d fid %d offset %d count %d '%s'", msg.Tag(), msg.Fid(), msg.Offset(), msg.Count(), msg.Data()) } diff --git a/server.go b/server.go @@ -255,13 +255,7 @@ func sOpen(s *Server, r *Req) { return } - ok, err := hasPerm(fidStruct.File, fidStruct.Uid, p) - if err != nil { - log.Printf("hasPerm: %v", err) - respond(r, fmt.Errorf("internal error")) - return - } - if !ok { + if !hasPerm(fidStruct.File, fidStruct.Uid, p) { respond(r, fmt.Errorf("permission denied")) return } @@ -362,10 +356,7 @@ func sWrite(s *Server, r *Req) { } file := fid.File - if ok, err := hasPerm(file, fid.Uid, AWRITE); !ok || err != nil { - if err != nil { - log.Printf("hasPerm: %v", err) - } + if !hasPerm(file, fid.Uid, AWRITE) { respond(r, fmt.Errorf("permission denied")) return } @@ -484,10 +475,7 @@ func sWStat(s *Server, r *Req) { respond(r, fmt.Errorf("get parent: %v", err)) return } - if ok, err := hasPerm(parent, fidStruct.Uid, AWRITE); !ok || err != nil { - if err != nil { - log.Printf("hasPerm: %v", err) - } + if !hasPerm(parent, fidStruct.Uid, AWRITE) { respond(r, fmt.Errorf("permission denied")) return } @@ -510,11 +498,41 @@ func sWStat(s *Server, r *Req) { newStat.Name = wstat.Name } - // TODO: WIP - if wstat.Length != ^int64(0) { log.Printf("length: %T, %d", wstat.Length, wstat.Length) } - if wstat.Mode != FileMode(^uint32(0)) {} - if wstat.Mtime != ^uint32(0) {} - if wstat.Gid != "" {} + if wstat.Length != ^int64(0) { + log.Printf("length: %T, %d", wstat.Length, wstat.Length) + if fi.IsDir() || !hasPerm(fidStruct.File, fidStruct.Uid, AWRITE) { + respond(r, fmt.Errorf("permission denied")) + return + } + newStat.Length = wstat.Length + } + + if wstat.Mode != FileMode(^uint32(0)) { + // the owner of the file or the group leader of the file's group. + if wstat.Uid != newStat.Uid && wstat.Gid != newStat.Uid { + respond(r, fmt.Errorf("permission denied")) + return + } + if (wstat.Mode^newStat.Mode)&DMDIR != 0 { + respond(r, fmt.Errorf("permission denied")) + return + } + newStat.Mode = wstat.Mode + } + + if wstat.Mtime != ^uint32(0) { + // the owner of the file or the group leader of the file's group. + if wstat.Uid != newStat.Uid && wstat.Gid != newStat.Uid { + respond(r, fmt.Errorf("permission denied")) + return + } + newStat.Mtime = wstat.Mtime + } + if wstat.Gid != "" { + // TODO implement + respond(r, fmt.Errorf("not implemented")) + return + } err = wsfile.WStat(newStat) if err != nil { diff --git a/testdir/a b/testdir/a @@ -1,2 +1,2 @@ a -aa +unko diff --git a/testdir/b b/testdir/b @@ -1 +1 @@ -update +yatta diff --git a/uid.go b/uid.go @@ -1,34 +1,35 @@ package lib9p import ( - "fmt" "io/fs" + "log" ) // p is logical OR of AREAD, AWRITE, AEXEC. // TODO: user is assumed to be the leader of the group -func hasPerm(f File, uid string, p fs.FileMode) (bool, error) { +func hasPerm(f File, uid string, p fs.FileMode) bool { fi, err := f.Stat() if err != nil { - return false, fmt.Errorf("Stat: %v", err) + log.Printf("stat: %v", err) + return false } fp := fi.Mode().Perm() Stat := fi.Sys().(*Stat) m := fp & 7 // other if (p & m) == p { - return true, nil + return true } if Stat.Uid == uid { m |= (fp >> 6) & 7 if (p & m) == p { - return true, nil + return true } } if Stat.Gid == uid { m |= (fp >> 3) & 7 if (p & m) == p { - return true, nil + return true } } - return false, nil + return false }