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:
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
}