commit be1c9672cc596e2445a629ff209e7bacaeee84e9
parent ce0b99eea7036da62c69bb2c845f00d673004454
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sat, 19 Oct 2024 16:07:44 +0900
Merge branch 'master' of git.mtkn.jp:lib9p
Diffstat:
2 files changed, 47 insertions(+), 11 deletions(-)
diff --git a/diskfs/stat_unix.go b/diskfs/stat_unix.go
@@ -116,10 +116,18 @@ func (f *File) wstat(s *lib9p.Stat) error {
 			return fmt.Errorf("chmod: %v", err)
 		}
 	}
+	// TODO: changing atime is not permitted by the protocol, but some unix
+	// utilities try to change it (e.g. mv, touch, git).
+	if s.Atime != oldStat.Atime {
+		err := os.Chtimes(path.Join(f.fs.rootPath, f.path), time.Unix(int64(s.Mtime), 0), time.Time{})
+		if err != nil {
+			return fmt.Errorf("change atime: %v", err)
+		}
+	}
 	if s.Mtime != oldStat.Mtime {
-		err := os.Chtimes(f.path, time.Time{}, time.Unix(int64(s.Mtime), 0))
+		err := os.Chtimes(path.Join(f.fs.rootPath, f.path), time.Time{}, time.Unix(int64(s.Mtime), 0))
 		if err != nil {
-			return fmt.Errorf("chtimes: %v", err)
+			return fmt.Errorf("change mtime: %v", err)
 		}
 	}
 	if s.Gid != oldStat.Gid {
diff --git a/server.go b/server.go
@@ -1117,15 +1117,43 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) {
 				r.err = fmt.Errorf("qid mismatch")
 				goto resp
 			}
-			if wstat.Type != ^uint16(0) && wstat.Type != newStat.Type ||
-				wstat.Dev != ^uint32(0) && wstat.Dev != newStat.Dev ||
-				wstat.Qid.Type != QidType(^uint8(0)) && wstat.Qid.Type != newStat.Qid.Type ||
-				wstat.Qid.Vers != ^uint32(0) && wstat.Qid.Vers != newStat.Qid.Vers ||
-				wstat.Qid.Path != ^uint64(0) && wstat.Qid.Path != newStat.Qid.Path ||
-				wstat.Atime != ^uint32(0) && wstat.Atime != newStat.Atime ||
-				wstat.Uid != "" && wstat.Uid != newStat.Uid ||
-				wstat.Muid != "" && wstat.Muid != newStat.Muid {
-				r.err = fmt.Errorf("operation not permitted")
+			if wstat.Type != ^uint16(0) && wstat.Type != newStat.Type {
+				r.err = fmt.Errorf("changing type is not permitted")
+				goto resp
+			}
+			if wstat.Dev != ^uint32(0) && wstat.Dev != newStat.Dev {
+				r.err = fmt.Errorf("changing dev is not permitted")
+				goto resp
+			}
+			if wstat.Qid.Type != QidType(^uint8(0)) && wstat.Qid.Type != newStat.Qid.Type {
+				r.err = fmt.Errorf("changing qid type is not permitted")
+				goto resp
+			}
+			if wstat.Qid.Vers != ^uint32(0) && wstat.Qid.Vers != newStat.Qid.Vers {
+				r.err = fmt.Errorf("changing qid vers is not permitted")
+				goto resp
+			}
+			if wstat.Qid.Path != ^uint64(0) && wstat.Qid.Path != newStat.Qid.Path {
+				r.err = fmt.Errorf("changing qid path is not permitted")
+				goto resp
+			}
+			// TODO: some unix utilities (e.g. touch, mv, git) tries to change atime.
+			// But changing atime is prohibited by the protocol.
+			if wstat.Atime != ^uint32(0) && wstat.Atime != newStat.Atime {
+				if r.fid.uid != newStat.Uid && !isGroupLeader(r.fid.fs, newStat.Gid, r.fid.uid) {
+					r.err = ErrPerm
+					goto resp
+				}
+				newStat.Atime = wstat.Atime
+				//r.err = fmt.Errorf("changing atime is not permitted")
+				//goto resp
+			}
+			if wstat.Uid != "" && wstat.Uid != newStat.Uid {
+				r.err = fmt.Errorf("changing uid is not permitted")
+				goto resp
+			}
+			if wstat.Muid != "" && wstat.Muid != newStat.Muid {
+				r.err = fmt.Errorf("changing muid is not permitted")
 				goto resp
 			}
 			if wstat.Name != "" && newStat.Name != wstat.Name {