stat_plan9.go (2952B)
1 //go:build plan9 2 3 package diskfs 4 5 import ( 6 "fmt" 7 "io/fs" 8 "os" 9 "os/user" 10 "path" 11 "strconv" 12 "syscall" 13 "time" 14 15 "git.mtkn.jp/lib9p" 16 ) 17 18 // fiStat generates lib9p.Stat from the FileInfo. 19 // It requires QidPool and fileID to fill the Qid field of Stat. 20 func fiStat(pool *QidPool, id fileID, info fs.FileInfo) (*lib9p.Stat, error) { 21 dir := info.Sys().(*syscall.Dir) 22 qid := lib9p.Qid{ 23 Type: lib9p.QidType(dir.Qid.Type), 24 Vers: dir.Qid.Vers, 25 Path: dir.Qid.Path, 26 } 27 return &lib9p.Stat{ 28 Type: dir.Type, 29 Dev: dir.Dev, 30 Qid: qid, 31 Mode: info.Mode(), 32 Atime: dir.Atime, 33 Mtime: dir.Mtime, 34 Length: dir.Length, 35 Name: dir.Name, 36 Uid: dir.Uid, 37 Gid: dir.Gid, 38 Muid: dir.Muid, 39 }, nil 40 } 41 42 // Stat is real implementation of File.Stat. 43 func (f *File) stat() (*lib9p.FileInfo, error) { 44 fi, err := f.file.Stat() 45 if err != nil { 46 return nil, fmt.Errorf("stat: %v", err) 47 } 48 stat, err := fiStat(nil, fileID{}, fi) 49 if err != nil { 50 return nil, fmt.Errorf("fiStat: %v", err) 51 } 52 return &lib9p.FileInfo{Stat: *stat}, nil 53 } 54 55 // wstat is the real implementation of File.WStat. 56 // TODO: when error occurs, file stat should be restored. 57 func (f *File) wstat(s *lib9p.Stat) error { 58 file, err := os.OpenFile(path.Join(f.fs.rootPath, f.path), os.O_RDWR, 0) 59 if err != nil { 60 return err 61 } 62 defer file.Close() 63 64 fi, err := f.Stat() 65 if err != nil { 66 return fmt.Errorf("stat: %v", err) 67 } 68 69 oldStat := fi.Sys().(*lib9p.Stat) 70 71 if s.Name != oldStat.Name { 72 // TODO: check neither Names contains "/" 73 oldpath := path.Join(f.fs.rootPath, path.Dir(f.path), oldStat.Name) 74 newpath := path.Join(f.fs.rootPath, path.Dir(f.path), s.Name) 75 if err := os.Rename(oldpath, newpath); err != nil { 76 return fmt.Errorf("rename: %v", err) 77 } 78 } 79 if s.Length != oldStat.Length { 80 if err := file.Truncate(s.Length); err != nil { 81 return fmt.Errorf("truncate: %v", err) 82 } 83 ret, err := file.Seek(0, 0) 84 if err != nil { 85 return fmt.Errorf("seek 0: %d, %w", ret, err) 86 } 87 } 88 if s.Mode != oldStat.Mode { 89 if err := file.Chmod(s.Mode); err != nil { 90 return fmt.Errorf("chmod: %v", err) 91 } 92 } 93 if s.Mtime != oldStat.Mtime { 94 err := os.Chtimes(f.path, time.Time{}, time.Unix(int64(s.Mtime), 0)) 95 if err != nil { 96 return fmt.Errorf("chtimes: %v", err) 97 } 98 } 99 100 if s.Gid != oldStat.Gid { 101 return fmt.Errorf("not implemented in plan9") 102 group, err := user.LookupGroup(s.Gid) 103 if err != nil { 104 return fmt.Errorf("lookupgroup: %v", err) 105 } 106 usr, err := user.Lookup(oldStat.Uid) 107 if err != nil { 108 return fmt.Errorf("lookup user: %v", err) 109 } 110 u, err := strconv.Atoi(usr.Uid) 111 if err != nil { 112 return fmt.Errorf("convert uid: %v", err) 113 } 114 g, err := strconv.Atoi(group.Gid) 115 if err != nil { 116 return fmt.Errorf("convert gid: %v", err) 117 } 118 119 if err := file.Chown(u, g); err != nil { 120 return fmt.Errorf("chown: %v", err) 121 } 122 } 123 124 return nil 125 } 126 127 // TODO: implement 128 func chown(ospath, uid, gid string) error { return nil }