9fans.net/go@v0.0.5/plan9/fcall.go (about) 1 package plan9 2 3 import ( 4 "fmt" 5 "io" 6 ) 7 8 const ( 9 IOHDRSIZE = 24 10 ) 11 12 type Fcall struct { 13 Type uint8 14 Fid uint32 15 Tag uint16 16 Msize uint32 17 Version string // Tversion, Rversion 18 Oldtag uint16 // Tflush 19 Ename string // Rerror 20 Qid Qid // Rattach, Ropen, Rcreate 21 Iounit uint32 // Ropen, Rcreate 22 Aqid Qid // Rauth 23 Afid uint32 // Tauth, Tattach 24 Uname string // Tauth, Tattach 25 Aname string // Tauth, Tattach 26 Perm Perm // Tcreate 27 Name string // Tcreate 28 Mode uint8 // Tcreate, Topen 29 Newfid uint32 // Twalk 30 Wname []string // Twalk 31 Wqid []Qid // Rwalk 32 Offset uint64 // Tread, Twrite 33 Count uint32 // Tread, Rwrite 34 Data []byte // Twrite, Rread 35 Stat []byte // Twstat, Rstat 36 37 // 9P2000.u extensions 38 Errno uint32 // Rerror 39 Uid uint32 // Tattach, Tauth 40 Extension string // Tcreate 41 } 42 43 const ( 44 Tversion = 100 + iota 45 Rversion 46 Tauth 47 Rauth 48 Tattach 49 Rattach 50 Terror // illegal 51 Rerror 52 Tflush 53 Rflush 54 Twalk 55 Rwalk 56 Topen 57 Ropen 58 Tcreate 59 Rcreate 60 Tread 61 Rread 62 Twrite 63 Rwrite 64 Tclunk 65 Rclunk 66 Tremove 67 Rremove 68 Tstat 69 Rstat 70 Twstat 71 Rwstat 72 Tmax 73 ) 74 75 func (f *Fcall) Bytes() ([]byte, error) { 76 b := pbit32(nil, 0) // length: fill in later 77 b = pbit8(b, f.Type) 78 b = pbit16(b, f.Tag) 79 switch f.Type { 80 default: 81 return nil, ProtocolError("invalid type") 82 83 case Tversion: 84 b = pbit32(b, f.Msize) 85 b = pstring(b, f.Version) 86 87 case Tflush: 88 b = pbit16(b, f.Oldtag) 89 90 case Tauth: 91 b = pbit32(b, f.Afid) 92 b = pstring(b, f.Uname) 93 b = pstring(b, f.Aname) 94 95 case Tattach: 96 b = pbit32(b, f.Fid) 97 b = pbit32(b, f.Afid) 98 b = pstring(b, f.Uname) 99 b = pstring(b, f.Aname) 100 101 case Twalk: 102 b = pbit32(b, f.Fid) 103 b = pbit32(b, f.Newfid) 104 if len(f.Wname) > MAXWELEM { 105 return nil, ProtocolError("too many names in walk") 106 } 107 b = pbit16(b, uint16(len(f.Wname))) 108 for i := range f.Wname { 109 b = pstring(b, f.Wname[i]) 110 } 111 112 case Topen: 113 b = pbit32(b, f.Fid) 114 b = pbit8(b, f.Mode) 115 116 case Tcreate: 117 b = pbit32(b, f.Fid) 118 b = pstring(b, f.Name) 119 b = pperm(b, f.Perm) 120 b = pbit8(b, f.Mode) 121 122 case Tread: 123 b = pbit32(b, f.Fid) 124 b = pbit64(b, f.Offset) 125 b = pbit32(b, f.Count) 126 127 case Twrite: 128 b = pbit32(b, f.Fid) 129 b = pbit64(b, f.Offset) 130 b = pbit32(b, uint32(len(f.Data))) 131 b = append(b, f.Data...) 132 133 case Tclunk, Tremove, Tstat: 134 b = pbit32(b, f.Fid) 135 136 case Twstat: 137 b = pbit32(b, f.Fid) 138 b = pbit16(b, uint16(len(f.Stat))) 139 b = append(b, f.Stat...) 140 141 case Rversion: 142 b = pbit32(b, f.Msize) 143 b = pstring(b, f.Version) 144 145 case Rerror: 146 b = pstring(b, f.Ename) 147 148 case Rflush, Rclunk, Rremove, Rwstat: 149 // nothing 150 151 case Rauth: 152 b = pqid(b, f.Aqid) 153 154 case Rattach: 155 b = pqid(b, f.Qid) 156 157 case Rwalk: 158 if len(f.Wqid) > MAXWELEM { 159 return nil, ProtocolError("too many qid in walk") 160 } 161 b = pbit16(b, uint16(len(f.Wqid))) 162 for i := range f.Wqid { 163 b = pqid(b, f.Wqid[i]) 164 } 165 166 case Ropen, Rcreate: 167 b = pqid(b, f.Qid) 168 b = pbit32(b, f.Iounit) 169 170 case Rread: 171 b = pbit32(b, uint32(len(f.Data))) 172 b = append(b, f.Data...) 173 174 case Rwrite: 175 b = pbit32(b, f.Count) 176 177 case Rstat: 178 b = pbit16(b, uint16(len(f.Stat))) 179 b = append(b, f.Stat...) 180 } 181 182 pbit32(b[0:0], uint32(len(b))) 183 return b, nil 184 } 185 186 func UnmarshalFcall(b []byte) (f *Fcall, err error) { 187 defer func() { 188 if recover() != nil { 189 println("bad fcall at ", b) 190 f = nil 191 err = ProtocolError("malformed Fcall") 192 } 193 }() 194 195 n, b := gbit32(b) 196 if len(b) != int(n)-4 { 197 panic(1) 198 } 199 200 f = new(Fcall) 201 f.Type, b = gbit8(b) 202 f.Tag, b = gbit16(b) 203 204 switch f.Type { 205 default: 206 panic(1) 207 208 case Tversion: 209 f.Msize, b = gbit32(b) 210 f.Version, b = gstring(b) 211 212 case Tflush: 213 f.Oldtag, b = gbit16(b) 214 215 case Tauth: 216 f.Afid, b = gbit32(b) 217 f.Uname, b = gstring(b) 218 f.Aname, b = gstring(b) 219 220 case Tattach: 221 f.Fid, b = gbit32(b) 222 f.Afid, b = gbit32(b) 223 f.Uname, b = gstring(b) 224 f.Aname, b = gstring(b) 225 226 case Twalk: 227 f.Fid, b = gbit32(b) 228 f.Newfid, b = gbit32(b) 229 var n uint16 230 n, b = gbit16(b) 231 if n > MAXWELEM { 232 panic(1) 233 } 234 f.Wname = make([]string, n) 235 for i := range f.Wname { 236 f.Wname[i], b = gstring(b) 237 } 238 239 case Topen: 240 f.Fid, b = gbit32(b) 241 f.Mode, b = gbit8(b) 242 243 case Tcreate: 244 f.Fid, b = gbit32(b) 245 f.Name, b = gstring(b) 246 f.Perm, b = gperm(b) 247 f.Mode, b = gbit8(b) 248 249 case Tread: 250 f.Fid, b = gbit32(b) 251 f.Offset, b = gbit64(b) 252 f.Count, b = gbit32(b) 253 254 case Twrite: 255 f.Fid, b = gbit32(b) 256 f.Offset, b = gbit64(b) 257 n, b = gbit32(b) 258 if len(b) != int(n) { 259 panic(1) 260 } 261 f.Data = b 262 b = nil 263 264 case Tclunk, Tremove, Tstat: 265 f.Fid, b = gbit32(b) 266 267 case Twstat: 268 f.Fid, b = gbit32(b) 269 var n uint16 270 n, b = gbit16(b) 271 if len(b) != int(n) { 272 panic(1) 273 } 274 f.Stat = b 275 b = nil 276 277 case Rversion: 278 f.Msize, b = gbit32(b) 279 f.Version, b = gstring(b) 280 281 case Rerror: 282 f.Ename, b = gstring(b) 283 284 case Rflush, Rclunk, Rremove, Rwstat: 285 // nothing 286 287 case Rauth: 288 f.Aqid, b = gqid(b) 289 290 case Rattach: 291 f.Qid, b = gqid(b) 292 293 case Rwalk: 294 var n uint16 295 n, b = gbit16(b) 296 if n > MAXWELEM { 297 panic(1) 298 } 299 f.Wqid = make([]Qid, n) 300 for i := range f.Wqid { 301 f.Wqid[i], b = gqid(b) 302 } 303 304 case Ropen, Rcreate: 305 f.Qid, b = gqid(b) 306 f.Iounit, b = gbit32(b) 307 308 case Rread: 309 n, b = gbit32(b) 310 if len(b) != int(n) { 311 panic(1) 312 } 313 f.Data = b 314 b = nil 315 316 case Rwrite: 317 f.Count, b = gbit32(b) 318 319 case Rstat: 320 var n uint16 321 n, b = gbit16(b) 322 if len(b) != int(n) { 323 panic(1) 324 } 325 f.Stat = b 326 b = nil 327 } 328 329 if len(b) != 0 { 330 panic(1) 331 } 332 333 return f, nil 334 } 335 336 func (f *Fcall) String() string { 337 if f == nil { 338 return "<nil>" 339 } 340 switch f.Type { 341 case Tversion: 342 return fmt.Sprintf("Tversion tag %d msize %d version '%s'", 343 f.Tag, f.Msize, f.Version) 344 case Rversion: 345 return fmt.Sprintf("Rversion tag %d msize %d version '%s'", 346 f.Tag, f.Msize, f.Version) 347 case Tauth: 348 return fmt.Sprintf("Tauth tag %d afid %d uname %s aname %s", 349 f.Tag, f.Afid, f.Uname, f.Aname) 350 case Rauth: 351 return fmt.Sprintf("Rauth tag %d qid %v", f.Tag, f.Qid) 352 case Tattach: 353 return fmt.Sprintf("Tattach tag %d fid %d afid %d uname %s aname %s", 354 f.Tag, f.Fid, f.Afid, f.Uname, f.Aname) 355 case Rattach: 356 return fmt.Sprintf("Rattach tag %d qid %v", f.Tag, f.Qid) 357 case Rerror: 358 return fmt.Sprintf("Rerror tag %d ename %s", f.Tag, f.Ename) 359 case Tflush: 360 return fmt.Sprintf("Tflush tag %d oldtag %d", f.Tag, f.Oldtag) 361 case Rflush: 362 return fmt.Sprintf("Rflush tag %d", f.Tag) 363 case Twalk: 364 return fmt.Sprintf("Twalk tag %d fid %d newfid %d wname %v", 365 f.Tag, f.Fid, f.Newfid, f.Wname) 366 case Rwalk: 367 return fmt.Sprintf("Rwalk tag %d wqid %v", f.Tag, f.Wqid) 368 case Topen: 369 return fmt.Sprintf("Topen tag %d fid %d mode %d", f.Tag, f.Fid, f.Mode) 370 case Ropen: 371 return fmt.Sprintf("Ropen tag %d qid %v iouint %d", f.Tag, f.Qid, f.Iounit) 372 case Tcreate: 373 return fmt.Sprintf("Tcreate tag %d fid %d name %s perm %v mode %d", 374 f.Tag, f.Fid, f.Name, f.Perm, f.Mode) 375 case Rcreate: 376 return fmt.Sprintf("Rcreate tag %d qid %v iouint %d", f.Tag, f.Qid, f.Iounit) 377 case Tread: 378 return fmt.Sprintf("Tread tag %d fid %d offset %d count %d", 379 f.Tag, f.Fid, f.Offset, f.Count) 380 case Rread: 381 return fmt.Sprintf("Rread tag %d count %d %s", 382 f.Tag, len(f.Data), dumpsome(f.Data)) 383 case Twrite: 384 return fmt.Sprintf("Twrite tag %d fid %d offset %d count %d %s", 385 f.Tag, f.Fid, f.Offset, len(f.Data), dumpsome(f.Data)) 386 case Rwrite: 387 return fmt.Sprintf("Rwrite tag %d count %d", f.Tag, f.Count) 388 case Tclunk: 389 return fmt.Sprintf("Tclunk tag %d fid %d", f.Tag, f.Fid) 390 case Rclunk: 391 return fmt.Sprintf("Rclunk tag %d", f.Tag) 392 case Tremove: 393 return fmt.Sprintf("Tremove tag %d fid %d", f.Tag, f.Fid) 394 case Rremove: 395 return fmt.Sprintf("Rremove tag %d", f.Tag) 396 case Tstat: 397 return fmt.Sprintf("Tstat tag %d fid %d", f.Tag, f.Fid) 398 case Rstat: 399 d, err := UnmarshalDir(f.Stat) 400 if err == nil { 401 return fmt.Sprintf("Rstat tag %d stat(%d bytes)", 402 f.Tag, len(f.Stat)) 403 } 404 return fmt.Sprintf("Rstat tag %d stat %v", f.Tag, d) 405 case Twstat: 406 d, err := UnmarshalDir(f.Stat) 407 if err == nil { 408 return fmt.Sprintf("Twstat tag %d fid %d stat(%d bytes)", 409 f.Tag, f.Fid, len(f.Stat)) 410 } 411 return fmt.Sprintf("Twstat tag %d fid %d stat %v", f.Tag, f.Fid, d) 412 case Rwstat: 413 return fmt.Sprintf("FidRwstat tag %d", f.Tag) 414 } 415 return fmt.Sprintf("unknown type %d", f.Type) 416 } 417 418 func ReadFcall(r io.Reader) (*Fcall, error) { 419 // 128 bytes should be enough for most messages 420 buf := make([]byte, 128) 421 _, err := io.ReadFull(r, buf[0:4]) 422 if err != nil { 423 return nil, err 424 } 425 426 // read 4-byte header, make room for remainder 427 n, _ := gbit32(buf) 428 if n < 4 { 429 return nil, ProtocolError("invalid length") 430 } 431 if int(n) <= len(buf) { 432 buf = buf[0:n] 433 } else { 434 buf = make([]byte, n) 435 pbit32(buf[0:0], n) 436 } 437 438 // read remainder and unpack 439 _, err = io.ReadFull(r, buf[4:]) 440 if err != nil { 441 return nil, err 442 } 443 return UnmarshalFcall(buf) 444 } 445 446 func WriteFcall(w io.Writer, f *Fcall) error { 447 b, err := f.Bytes() 448 if err != nil { 449 return err 450 } 451 _, err = w.Write(b) 452 return err 453 }