commit 9eb89f2b634166824f52ccdd00f4b51c79792789
parent 10d2025ddb638345e7f6cbff1b6c783c2a7ff088
Author: Matsuda Kenji <info@mtkn.jp>
Date: Mon, 11 Sep 2023 12:42:54 +0900
implementing wstat (wip)
Diffstat:
5 files changed, 108 insertions(+), 2 deletions(-)
diff --git a/diskfs/file.go b/diskfs/file.go
@@ -164,3 +164,7 @@ 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/fcall.go b/fcall.go
@@ -1231,7 +1231,7 @@ func (msg *RStat) marshal() []byte {
}
func (msg *RStat) String() string {
- return fmt.Sprintf("Rstat tag %d Stat %s", msg.Tag(), msg.stat)
+ return fmt.Sprintf("Rstat tag %d stat %s", msg.Tag(), msg.stat)
}
type TWStat struct{
@@ -1253,6 +1253,7 @@ func (msg *TWStat) Size() uint32 {
func (msg *TWStat) Type() MsgType { return Twstat }
func (msg *TWStat) Tag() uint16 { return msg.tag }
func (msg *TWStat) Fid() uint32 { return msg.fid }
+func (msg *TWStat) Stat() *Stat { return msg.stat }
func (msg *TWStat) marshal() []byte {
buf := make([]byte, msg.Size())
pbit32(buf[0:4], msg.Size())
@@ -1269,7 +1270,7 @@ func (msg *TWStat) marshal() []byte {
}
func (msg *TWStat) String() string {
- return fmt.Sprintf("Twstat tag %d fid %d Stat %s", msg.Tag(), msg.Fid(), msg.stat)
+ return fmt.Sprintf("Twstat tag %d fid %d stat %s", msg.Tag(), msg.Fid(), msg.stat)
}
diff --git a/file.go b/file.go
@@ -3,6 +3,7 @@ package lib9p
import "fmt"
type File interface {
+ Parent() (File, error)
Child() ([]File, error) // Children
Stat() (*FileInfo, error)
@@ -10,6 +11,16 @@ type File interface {
Read(b []byte) (int, error)
}
+type WriterStatFile interface {
+ File
+
+ // WStat set file Stat to stat.
+ // After successful call, the file's Stat() method should return
+ // the same Stat as stat.
+ // If there is an error, file's status must remain the same as before.
+ WStat(stat *Stat) error
+}
+
// Walkfile walks file tree starting at f, following path specified by name.
// It returns the destination File and nil, or nil with non-nil error.
func walkfile(f File, name string) (File, error) {
diff --git a/server.go b/server.go
@@ -447,6 +447,90 @@ func sStat(s *Server, r *Req) {
func rStat(r *Req, err error) {}
+func sWStat(s *Server, r *Req) {
+ ifcall := r.ifcall.(*TWStat)
+ fidNum := ifcall.Fid()
+ fidStruct, ok := s.fPool.lookup(fidNum)
+ if !ok {
+ respond(r, fmt.Errorf("unknown fid %d", fidNum))
+ return
+ }
+
+ wsfile, ok := fidStruct.File.(WriterStatFile)
+ if !ok {
+ respond(r, fmt.Errorf("operation not supported"))
+ return
+ }
+
+ wstat := ifcall.Stat()
+ fi, err := fidStruct.File.Stat()
+ if err != nil {
+ respond(r, fmt.Errorf("stat: %v", err))
+ return
+ }
+ newStat := fi.Sys().(*Stat)
+
+ if wstat.Type != ^uint16(0) || wstat.Dev != ^uint32(0) ||
+ wstat.Qid.Type != QidType(^uint8(0)) || wstat.Qid.Vers != ^uint32(0) ||
+ wstat.Qid.Path != ^uint64(0) || wstat.Atime != ^uint32(0) ||
+ wstat.Uid != "" || wstat.Muid != "" {
+ respond(r, fmt.Errorf("operation not permitted"))
+ return
+ }
+
+ if wstat.Name != "" {
+ parent, err := fidStruct.File.Parent()
+ if err != nil {
+ 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)
+ }
+ respond(r, fmt.Errorf("permission denied"))
+ return
+ }
+ children, err := parent.Child()
+ if err != nil {
+ respond(r, fmt.Errorf("get children: %v", err))
+ return
+ }
+ for _, f := range children {
+ s, err := f.Stat()
+ if err != nil {
+ respond(r, fmt.Errorf("stat: %v", err))
+ return
+ }
+ if s.Name() == wstat.Name {
+ respond(r, fmt.Errorf("file already exists"))
+ return
+ }
+ }
+ 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 != "" {}
+
+ err = wsfile.WStat(newStat)
+ if err != nil {
+ respond(r, fmt.Errorf("wstat: %v", err))
+ return
+ }
+
+ ofcall := new(RWStat)
+ ofcall.tag = ifcall.Tag()
+ r.ofcall = ofcall
+
+ respond(r, nil)
+}
+
+func rWStat(r *Req, err error) {}
+
func (s *Server) Serve() {
for {
r, err := s.getReq()
@@ -483,6 +567,8 @@ func (s *Server) Serve() {
sClunk(s, r)
case *TStat:
sStat(s, r)
+ case *TWStat:
+ sWStat(s, r)
}
}
}
@@ -522,6 +608,8 @@ func respond(r *Req, err error) {
rClunk(r, err)
case *RStat:
rStat(r, err)
+ case *RWStat:
+ rWStat(r, err)
}
if chatty9P {
fmt.Fprintf(os.Stderr, "--> %s\n", r.ofcall)
diff --git a/stat.go b/stat.go
@@ -51,6 +51,7 @@ type Stat struct {
Mode FileMode
Atime uint32
Mtime uint32
+ //TODO: In 9P protocol Length is unsigned integer.
Length int64
Name string
Uid string