qid_unix.go (2937B)
1 //go:build unix 2 3 package diskfs 4 5 import ( 6 "fmt" 7 "io/fs" 8 "os" 9 "path/filepath" 10 "syscall" 11 "time" 12 13 "git.mtkn.jp/lib9p" 14 ) 15 16 // fileID is the identifier of a unix file. 17 // It is used to assosiate the file with Qid. 18 type fileID struct { 19 device uint64 20 inode uint64 21 } 22 23 // qidReq is used to update the Qid.Vers by checking the file's 24 // modified time. 25 type qidRec struct { 26 qid *lib9p.Qid 27 mtime time.Time 28 } 29 30 // QidPool is the list of Qids in the file system. 31 type QidPool struct { 32 m map[fileID]*qidRec 33 nextQid uint64 34 } 35 36 // id derives the fileID from the file. 37 func (f *File) id() (fileID, error) { 38 ospath := filepath.Join(f.fs.rootPath, f.path) 39 fi, err := os.Stat(ospath) 40 if err != nil { 41 return fileID{}, err 42 } 43 sys := fi.Sys().(*syscall.Stat_t) 44 id := fileID{ 45 device: uint64(sys.Dev), 46 inode: sys.Ino, 47 } 48 return id, nil 49 } 50 51 // idFromInfo derives the fileID from the fs.FileInfo. 52 func idFromInfo(path string, info fs.FileInfo) fileID { 53 stat := info.Sys().(*syscall.Stat_t) 54 return fileID{device: uint64(stat.Dev), inode: stat.Ino} 55 } 56 57 // newQidPool allocates a QidPool. 58 func newQidPool() *QidPool { 59 return &QidPool{ 60 m: make(map[fileID]*qidRec), 61 } 62 } 63 64 // lookup looks up the file in the QidPool. 65 // If found, it returns the corresponding Qid and true. 66 // If not found, it returns nil and false. 67 func (pool *QidPool) lookup(f *File) (lib9p.Qid, bool) { 68 id, err := f.id() 69 if err != nil { 70 return lib9p.Qid{}, false 71 } 72 ospath := filepath.Join(f.fs.rootPath, f.path) 73 fsfi, err := os.Stat(ospath) 74 if err != nil { 75 return lib9p.Qid{}, false 76 } 77 return pool.lookupID(id, fsfi.ModTime()) 78 } 79 80 // lookupID looksup the file in the QidPool by fileID. 81 // It also checks if the file is modified after the last access by 82 // comparing the qidReq.mtime and mtime, and update Qid.Vers if needed. 83 func (pool *QidPool) lookupID(id fileID, mtime time.Time) (lib9p.Qid, bool) { 84 qrec, ok := pool.m[id] 85 if !ok { 86 return lib9p.Qid{}, false 87 } 88 if qrec.mtime.Before(mtime) { 89 qrec.qid.Vers++ 90 qrec.mtime = mtime 91 } 92 return *qrec.qid, ok 93 } 94 95 // add adds the file's Qid to the QidPool and returns the newly added Qid. 96 func (pool *QidPool) add(f *File) (lib9p.Qid, error) { 97 id, err := f.id() 98 if err != nil { 99 return lib9p.Qid{}, fmt.Errorf("get id: %v", err) 100 } 101 ospath := filepath.Join(f.fs.rootPath, f.path) 102 fi, err := os.Stat(ospath) 103 if err != nil { 104 return lib9p.Qid{}, fmt.Errorf("stat %v: %v", f, err) 105 } 106 return pool.addID(id, fi) 107 } 108 109 // addID does the same as add, but by fileID. 110 func (pool *QidPool) addID(id fileID, info fs.FileInfo) (lib9p.Qid, error) { 111 qtype := lib9p.FSModeToQidType(info.Mode()) 112 qid := &lib9p.Qid{ 113 Path: pool.nextQid, 114 Type: qtype, 115 } 116 pool.m[id] = &qidRec{qid: qid, mtime: info.ModTime()} 117 pool.nextQid++ 118 return *qid, nil 119 } 120 121 // delete deletes Qid associated with f from the QidPool. 122 func (pool *QidPool) delete(f *File) { 123 id, err := f.id() 124 if err != nil { 125 return 126 } 127 delete(pool.m, id) 128 }