9fans.net/go@v0.0.5/plan9/client/fid_p9p.go (about) 1 //go:build !plan9 2 // +build !plan9 3 4 package client 5 6 import ( 7 "io" 8 "os" 9 "strings" 10 "sync" 11 12 "9fans.net/go/plan9" 13 ) 14 15 func getuser() string { return os.Getenv("USER") } 16 17 type Fid struct { 18 qid plan9.Qid 19 fid uint32 20 mode uint8 21 // f guards offset and c. 22 f sync.Mutex 23 // c holds the underlying connection. 24 // It's nil after the Fid has been closed. 25 _c *conn 26 offset int64 27 } 28 29 func (fid *Fid) conn() (*conn, error) { 30 fid.f.Lock() 31 c := fid._c 32 fid.f.Unlock() 33 if c == nil { 34 return nil, errClosed 35 } 36 return c, nil 37 } 38 39 func (fid *Fid) Close() error { 40 if fid == nil { 41 // TODO why is Close allowed on a nil fid but no other operations? 42 return nil 43 } 44 conn, err := fid.conn() 45 if err != nil { 46 return err 47 } 48 tx := &plan9.Fcall{Type: plan9.Tclunk, Fid: fid.fid} 49 _, err = conn.rpc(tx, fid) 50 return err 51 } 52 53 // clunked marks the fid as clunked and closes it. This is called 54 // just before sending a message that will clunk it. 55 func (fid *Fid) clunked() error { 56 fid.f.Lock() 57 defer fid.f.Unlock() 58 if fid._c == nil { 59 return errClosed 60 } 61 fid._c.putfidnum(fid.fid) 62 fid._c.release() 63 fid._c = nil 64 return nil 65 } 66 67 func (fid *Fid) Create(name string, mode uint8, perm plan9.Perm) error { 68 conn, err := fid.conn() 69 if err != nil { 70 return err 71 } 72 tx := &plan9.Fcall{Type: plan9.Tcreate, Fid: fid.fid, Name: name, Mode: mode, Perm: perm} 73 rx, err := conn.rpc(tx, nil) 74 if err != nil { 75 return err 76 } 77 fid.mode = mode 78 fid.qid = rx.Qid 79 return nil 80 } 81 82 func (fid *Fid) Open(mode uint8) error { 83 conn, err := fid.conn() 84 if err != nil { 85 return err 86 } 87 tx := &plan9.Fcall{Type: plan9.Topen, Fid: fid.fid, Mode: mode} 88 if _, err := conn.rpc(tx, nil); err != nil { 89 return err 90 } 91 fid.mode = mode 92 return nil 93 } 94 95 func (fid *Fid) Qid() plan9.Qid { 96 return fid.qid 97 } 98 99 func (fid *Fid) Read(b []byte) (n int, err error) { 100 return fid.ReadAt(b, -1) 101 } 102 103 func (fid *Fid) ReadAt(b []byte, offset int64) (n int, err error) { 104 for len(b) > 0 { 105 m, err := fid.readAt(b, offset) 106 if err != nil { 107 return n, err 108 } 109 n += m 110 b = b[m:] 111 if offset != -1 { 112 offset += int64(m) 113 } 114 } 115 return n, nil 116 } 117 118 func (fid *Fid) readAt(b []byte, offset int64) (n int, err error) { 119 conn, err := fid.conn() 120 if err != nil { 121 return 0, err 122 } 123 msize := conn.msize - plan9.IOHDRSZ 124 n = len(b) 125 if uint32(n) > msize { 126 n = int(msize) 127 } 128 o := offset 129 if o == -1 { 130 fid.f.Lock() 131 o = fid.offset 132 fid.f.Unlock() 133 } 134 tx := &plan9.Fcall{Type: plan9.Tread, Fid: fid.fid, Offset: uint64(o), Count: uint32(n)} 135 rx, err := conn.rpc(tx, nil) 136 if err != nil { 137 return 0, err 138 } 139 if len(rx.Data) == 0 { 140 return 0, io.EOF 141 } 142 copy(b, rx.Data) 143 if offset == -1 { 144 fid.f.Lock() 145 fid.offset += int64(len(rx.Data)) 146 fid.f.Unlock() 147 } 148 return len(rx.Data), nil 149 } 150 151 func (fid *Fid) Remove() error { 152 conn, err := fid.conn() 153 if err != nil { 154 return err 155 } 156 tx := &plan9.Fcall{Type: plan9.Tremove, Fid: fid.fid} 157 _, err = conn.rpc(tx, fid) 158 return err 159 } 160 161 func (fid *Fid) Seek(n int64, whence int) (int64, error) { 162 switch whence { 163 case 0: 164 fid.f.Lock() 165 fid.offset = n 166 fid.f.Unlock() 167 168 case 1: 169 fid.f.Lock() 170 n += fid.offset 171 if n < 0 { 172 fid.f.Unlock() 173 return 0, Error("negative offset") 174 } 175 fid.offset = n 176 fid.f.Unlock() 177 178 case 2: 179 d, err := fid.Stat() 180 if err != nil { 181 return 0, err 182 } 183 n += int64(d.Length) 184 if n < 0 { 185 return 0, Error("negative offset") 186 } 187 fid.f.Lock() 188 fid.offset = n 189 fid.f.Unlock() 190 191 default: 192 return 0, Error("bad whence in seek") 193 } 194 195 return n, nil 196 } 197 198 func (fid *Fid) Stat() (*plan9.Dir, error) { 199 conn, err := fid.conn() 200 if err != nil { 201 return nil, err 202 } 203 tx := &plan9.Fcall{Type: plan9.Tstat, Fid: fid.fid} 204 rx, err := conn.rpc(tx, nil) 205 if err != nil { 206 return nil, err 207 } 208 return plan9.UnmarshalDir(rx.Stat) 209 } 210 211 // TODO(rsc): Could use ...string instead? 212 func (fid *Fid) Walk(name string) (*Fid, error) { 213 conn, err := fid.conn() 214 if err != nil { 215 return nil, err 216 } 217 wfidnum, err := conn.newfidnum() 218 if err != nil { 219 return nil, err 220 } 221 222 // Split, delete empty strings and dot. 223 elem := strings.Split(name, "/") 224 j := 0 225 for _, e := range elem { 226 if e != "" && e != "." { 227 elem[j] = e 228 j++ 229 } 230 } 231 elem = elem[0:j] 232 233 var wfid *Fid 234 fromfidnum := fid.fid 235 for nwalk := 0; ; nwalk++ { 236 n := len(elem) 237 if n > plan9.MAXWELEM { 238 n = plan9.MAXWELEM 239 } 240 tx := &plan9.Fcall{Type: plan9.Twalk, Fid: fromfidnum, Newfid: wfidnum, Wname: elem[0:n]} 241 rx, err := conn.rpc(tx, nil) 242 if err == nil && len(rx.Wqid) != n { 243 err = Error("file '" + name + "' not found") 244 } 245 if err != nil { 246 if wfid != nil { 247 wfid.Close() 248 } 249 return nil, err 250 } 251 if n == 0 { 252 wfid = conn.newFid(wfidnum, fid.qid) 253 } else { 254 wfid = conn.newFid(wfidnum, rx.Wqid[n-1]) 255 } 256 elem = elem[n:] 257 if len(elem) == 0 { 258 break 259 } 260 fromfidnum = wfid.fid 261 } 262 return wfid, nil 263 } 264 265 func (fid *Fid) Write(b []byte) (n int, err error) { 266 return fid.WriteAt(b, -1) 267 } 268 269 func (fid *Fid) WriteAt(b []byte, offset int64) (n int, err error) { 270 conn, err := fid.conn() 271 if err != nil { 272 return 0, err 273 } 274 msize := conn.msize - plan9.IOHDRSIZE 275 tot := 0 276 n = len(b) 277 first := true 278 for tot < n || first { 279 want := n - tot 280 if uint32(want) > msize { 281 want = int(msize) 282 } 283 got, err := fid.writeAt(b[tot:tot+want], offset) 284 tot += got 285 if err != nil { 286 return tot, err 287 } 288 if offset != -1 { 289 offset += int64(got) 290 } 291 first = false 292 } 293 return tot, nil 294 } 295 296 func (fid *Fid) writeAt(b []byte, offset int64) (n int, err error) { 297 conn, err := fid.conn() 298 if err != nil { 299 return 0, err 300 } 301 o := offset 302 if o == -1 { 303 fid.f.Lock() 304 o = fid.offset 305 fid.f.Unlock() 306 } 307 tx := &plan9.Fcall{Type: plan9.Twrite, Fid: fid.fid, Offset: uint64(o), Data: b} 308 rx, err := conn.rpc(tx, nil) 309 if err != nil { 310 return 0, err 311 } 312 if offset == -1 && rx.Count > 0 { 313 fid.f.Lock() 314 fid.offset += int64(rx.Count) 315 fid.f.Unlock() 316 } 317 return int(rx.Count), nil 318 } 319 320 func (fid *Fid) Wstat(d *plan9.Dir) error { 321 conn, err := fid.conn() 322 if err != nil { 323 return err 324 } 325 b, err := d.Bytes() 326 if err != nil { 327 return err 328 } 329 tx := &plan9.Fcall{Type: plan9.Twstat, Fid: fid.fid, Stat: b} 330 _, err = conn.rpc(tx, nil) 331 return err 332 }