fid.go (3657B)
1 package lib9p 2 3 import ( 4 "fmt" 5 "io/fs" 6 "sync" 7 ) 8 9 // An OpenMode is the mode of an open file. 10 // This is used by fid structure. 11 // If the file is not open, the mode must be -1. 12 type OpenMode int8 13 14 const ( 15 OREAD OpenMode = 0 16 OWRITE = 1 17 ORDWR = 2 18 OEXEC = 3 19 20 OTRUNC = 16 21 ORCLOSE = 64 22 ) 23 24 // ModeToFlag converts OpenMode (OREAD etc.) to open flag (O_RDONLY etc.). 25 // ORCLOSE is not implemented and ignored silently. 26 // O_APPEND, O_CREATE, O_EXCL, O_SYNC can't be specified. 27 func ModeToFlag(m OpenMode) int { 28 var flag int 29 switch m & 3 { 30 case OREAD, OEXEC: 31 flag = O_RDONLY 32 case OWRITE: 33 flag = O_WRONLY 34 case ORDWR: 35 flag = O_RDWR 36 } 37 if m&OTRUNC != 0 { 38 flag |= O_TRUNC 39 } 40 // ORCLOSE is delt by the library in sClunk. 41 return flag 42 } 43 44 // FlugToMode converts open flag (O_RDONLY etc.) to OpenMode (OREAD etc.). 45 // O_APPEND, O_CREATE, O_EXCL, O_SYNC are not implemented and ignored silently. 46 // ORCLOSE can't be specified. 47 func FlagToMode(f int) OpenMode { 48 var m OpenMode 49 switch { 50 case f&O_RDONLY != 0: 51 m = OREAD 52 case f&O_WRONLY != 0: 53 m = OWRITE 54 case f&O_RDWR != 0: 55 m = ORDWR 56 } 57 if f&O_TRUNC != 0 { 58 m |= OTRUNC 59 } 60 return m 61 } 62 63 // An fid represents an fid defined by 9P. 64 // It is used as the identifier of a file in 9P session. 65 // It is specified by the client and the server connects it to a file in the 66 // file system. 67 // Multiple fids can be connected to a single file. 68 // On the other hand, a Qid is the Identifier in the file system itself, 69 // and does not change between 9P sessions. 70 type fid struct { 71 fid uint32 72 omode OpenMode /* -1 = not open */ 73 path string // The path from the root of the FS. 74 qidpath uint64 75 fs FS // The associated FS. 76 file File // The associated File. 77 uid string // The user id derived from the attach message. 78 dirOffset uint64 // Used when reading directory. 79 dirIndex int // Used when reading directory. 80 dirEnts []fs.DirEntry // DirEntry cache. 81 } 82 83 // NOFID is used in afid field of Tattach message when no authentication 84 // is required. 85 const NOFID = ^uint32(0) 86 87 // NewFid returns an fid with fid set to id and omode set to -1. 88 // Other fields should be set propperly after aquiring the fid. 89 func newFid(id uint32) *fid { 90 return &fid{ 91 fid: id, 92 omode: -1, 93 } 94 } 95 96 func (f *fid) String() string { 97 fid := int64(f.fid) 98 if uint32(fid) == NOFID { 99 fid = -1 100 } 101 return fmt.Sprintf("%d", fid) 102 } 103 104 // An fidPool is a pool of fid. 105 // It is used to track the fids of each 9P connection (not of each session). 106 // It is safe for concurrent use by multiple goroutines except the String method. 107 type fidPool struct { 108 m map[uint32]*fid 109 *sync.Mutex 110 } 111 112 // newFidPool allocates an fidPool. 113 func newFidPool() *fidPool { 114 return &fidPool{ 115 make(map[uint32]*fid), 116 new(sync.Mutex), 117 } 118 } 119 120 func (pool *fidPool) lookup(id uint32) (*fid, bool) { 121 pool.Lock() 122 defer pool.Unlock() 123 f, ok := pool.m[id] 124 return f, ok 125 } 126 127 func (pool *fidPool) add(id uint32) (*fid, error) { 128 pool.Lock() 129 defer pool.Unlock() 130 if _, ok := pool.m[id]; ok { 131 return nil, fmt.Errorf("fid already in use.") 132 } 133 f := newFid(id) 134 pool.m[id] = f 135 return f, nil 136 } 137 138 func (pool *fidPool) delete(id uint32) { 139 pool.Lock() 140 defer pool.Unlock() 141 delete(pool.m, id) 142 } 143 144 // not safe for concurrent use. 145 func (pool *fidPool) String() string { 146 s := "&fidPool{\n" 147 for fnum, fstruct := range pool.m { 148 if fstruct.file == nil { 149 s += fmt.Sprintf(" %d: <nil>\n", fnum) 150 continue 151 } 152 st, err := fstruct.file.Stat() 153 if err != nil { 154 panic(err) 155 } 156 s += fmt.Sprintf(" %d: %v\n", fnum, st.Sys().(*Stat)) 157 } 158 s += "}" 159 return s 160 }