1implement Styx; 2 3include "sys.m"; 4 sys: Sys; 5 6include "styx.m"; 7 8STR: con BIT16SZ; # string length 9TAG: con BIT16SZ; 10FID: con BIT32SZ; 11QID: con BIT8SZ+BIT32SZ+BIT64SZ; 12LEN: con BIT16SZ; # stat and qid array lengths 13COUNT: con BIT32SZ; 14OFFSET: con BIT64SZ; 15 16H: con BIT32SZ+BIT8SZ+BIT16SZ; # minimum header length: size[4] type tag[2] 17 18# 19# the following array could be shorter if it were indexed by (type-Tversion) 20# 21hdrlen := array[Tmax] of 22{ 23Tversion => H+COUNT+STR, # size[4] Tversion tag[2] msize[4] version[s] 24Rversion => H+COUNT+STR, # size[4] Rversion tag[2] msize[4] version[s] 25 26Tauth => H+FID+STR+STR, # size[4] Tauth tag[2] afid[4] uname[s] aname[s] 27Rauth => H+QID, # size[4] Rauth tag[2] aqid[13] 28 29Rerror => H+STR, # size[4] Rerror tag[2] ename[s] 30 31Tflush => H+TAG, # size[4] Tflush tag[2] oldtag[2] 32Rflush => H, # size[4] Rflush tag[2] 33 34Tattach => H+FID+FID+STR+STR, # size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] 35Rattach => H+QID, # size[4] Rattach tag[2] qid[13] 36 37Twalk => H+FID+FID+LEN, # size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) 38Rwalk => H+LEN, # size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) 39 40Topen => H+FID+BIT8SZ, # size[4] Topen tag[2] fid[4] mode[1] 41Ropen => H+QID+COUNT, # size[4] Ropen tag[2] qid[13] iounit[4] 42 43Tcreate => H+FID+STR+BIT32SZ+BIT8SZ, # size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1] 44Rcreate => H+QID+COUNT, # size[4] Rcreate tag[2] qid[13] iounit[4] 45 46Tread => H+FID+OFFSET+COUNT, # size[4] Tread tag[2] fid[4] offset[8] count[4] 47Rread => H+COUNT, # size[4] Rread tag[2] count[4] data[count] 48 49Twrite => H+FID+OFFSET+COUNT, # size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] 50Rwrite => H+COUNT, # size[4] Rwrite tag[2] count[4] 51 52Tclunk => H+FID, # size[4] Tclunk tag[2] fid[4] 53Rclunk => H, # size[4] Rclunk tag[2] 54 55Tremove => H+FID, # size[4] Tremove tag[2] fid[4] 56Rremove => H, # size[4] Rremove tag[2] 57 58Tstat => H+FID, # size[4] Tstat tag[2] fid[4] 59Rstat => H+LEN, # size[4] Rstat tag[2] stat[n] 60 61Twstat => H+FID+LEN, # size[4] Twstat tag[2] fid[4] stat[n] 62Rwstat => H, # size[4] Rwstat tag[2] 63}; 64 65init() 66{ 67 sys = load Sys Sys->PATH; 68} 69 70utflen(s: string): int 71{ 72 # the domain is 21-bit unicode 73 n := l := len s; 74 for(i:=0; i<l; i++) 75 if((c := s[i]) > 16r7F){ 76 n++; 77 if(c > 16r7FF){ 78 n++; 79 if(c > 16rFFFF) 80 n++; 81 } 82 } 83 return n; 84} 85 86packdirsize(d: Sys->Dir): int 87{ 88 return STATFIXLEN+utflen(d.name)+utflen(d.uid)+utflen(d.gid)+utflen(d.muid); 89} 90 91packdir(f: Sys->Dir): array of byte 92{ 93 ds := packdirsize(f); 94 a := array[ds] of byte; 95 # size[2] 96 a[0] = byte (ds-LEN); 97 a[1] = byte ((ds-LEN)>>8); 98 # type[2] 99 a[2] = byte f.dtype; 100 a[3] = byte (f.dtype>>8); 101 # dev[4] 102 a[4] = byte f.dev; 103 a[5] = byte (f.dev>>8); 104 a[6] = byte (f.dev>>16); 105 a[7] = byte (f.dev>>24); 106 # qid.type[1] 107 # qid.vers[4] 108 # qid.path[8] 109 pqid(a, 8, f.qid); 110 # mode[4] 111 a[21] = byte f.mode; 112 a[22] = byte (f.mode>>8); 113 a[23] = byte (f.mode>>16); 114 a[24] = byte (f.mode>>24); 115 # atime[4] 116 a[25] = byte f.atime; 117 a[26] = byte (f.atime>>8); 118 a[27] = byte (f.atime>>16); 119 a[28] = byte (f.atime>>24); 120 # mtime[4] 121 a[29] = byte f.mtime; 122 a[30] = byte (f.mtime>>8); 123 a[31] = byte (f.mtime>>16); 124 a[32] = byte (f.mtime>>24); 125 # length[8] 126 p64(a, 33, big f.length); 127 # name[s] 128 i := pstring(a, 33+BIT64SZ, f.name); 129 i = pstring(a, i, f.uid); 130 i = pstring(a, i, f.gid); 131 i = pstring(a, i, f.muid); 132 if(i != len a) 133 raise "assertion: Styx->packdir: bad count"; # can't happen unless packedsize is wrong 134 return a; 135} 136 137pqid(a: array of byte, o: int, q: Sys->Qid): int 138{ 139 a[o] = byte q.qtype; 140 v := q.vers; 141 a[o+1] = byte v; 142 a[o+2] = byte (v>>8); 143 a[o+3] = byte (v>>16); 144 a[o+4] = byte (v>>24); 145 v = int q.path; 146 a[o+5] = byte v; 147 a[o+6] = byte (v>>8); 148 a[o+7] = byte (v>>16); 149 a[o+8] = byte (v>>24); 150 v = int (q.path >> 32); 151 a[o+9] = byte v; 152 a[o+10] = byte (v>>8); 153 a[o+11] = byte (v>>16); 154 a[o+12] = byte (v>>24); 155 return o+QID; 156} 157 158pstring(a: array of byte, o: int, s: string): int 159{ 160 sa := array of byte s; # could do conversion ourselves 161 n := len sa; 162 a[o] = byte n; 163 a[o+1] = byte (n>>8); 164 a[o+2:] = sa; 165 return o+LEN+n; 166} 167 168p32(a: array of byte, o: int, v: int): int 169{ 170 a[o] = byte v; 171 a[o+1] = byte (v>>8); 172 a[o+2] = byte (v>>16); 173 a[o+3] = byte (v>>24); 174 return o+BIT32SZ; 175} 176 177p64(a: array of byte, o: int, b: big): int 178{ 179 i := int b; 180 a[o] = byte i; 181 a[o+1] = byte (i>>8); 182 a[o+2] = byte (i>>16); 183 a[o+3] = byte (i>>24); 184 i = int (b>>32); 185 a[o+4] = byte i; 186 a[o+5] = byte (i>>8); 187 a[o+6] = byte (i>>16); 188 a[o+7] = byte (i>>24); 189 return o+BIT64SZ; 190} 191 192unpackdir(a: array of byte): (int, Sys->Dir) 193{ 194 dir: Sys->Dir; 195 196 if(len a < STATFIXLEN) 197 return (0, dir); 198 # size[2] 199 sz := ((int a[1] << 8) | int a[0])+LEN; # bytes this packed dir should occupy 200 if(len a < sz) 201 return (0, dir); 202 # type[2] 203 dir.dtype = (int a[3]<<8) | int a[2]; 204 # dev[4] 205 dir.dev = (((((int a[7] << 8) | int a[6]) << 8) | int a[5]) << 8) | int a[4]; 206 # qid.type[1] 207 # qid.vers[4] 208 # qid.path[8] 209 dir.qid = gqid(a, 8); 210 # mode[4] 211 dir.mode = (((((int a[24] << 8) | int a[23]) << 8) | int a[22]) << 8) | int a[21]; 212 # atime[4] 213 dir.atime = (((((int a[28] << 8) | int a[27]) << 8) | int a[26]) << 8) | int a[25]; 214 # mtime[4] 215 dir.mtime = (((((int a[32] << 8) | int a[31]) << 8) | int a[30]) << 8) | int a[29]; 216 # length[8] 217 v0 := (((((int a[36] << 8) | int a[35]) << 8) | int a[34]) << 8) | int a[33]; 218 v1 := (((((int a[40] << 8) | int a[39]) << 8) | int a[38]) << 8) | int a[37]; 219 dir.length = (big v1 << 32) | (big v0 & 16rFFFFFFFF); 220 # name[s], uid[s], gid[s], muid[s] 221 i: int; 222 (dir.name, i) = gstring(a, 41); 223 (dir.uid, i) = gstring(a, i); 224 (dir.gid, i) = gstring(a, i); 225 (dir.muid, i) = gstring(a, i); 226 if(i != sz) 227 return (0, dir); 228 return (i, dir); 229} 230 231gqid(f: array of byte, i: int): Sys->Qid 232{ 233 qtype := int f[i]; 234 vers := (((((int f[i+4] << 8) | int f[i+3]) << 8) | int f[i+2]) << 8) | int f[i+1]; 235 i += BIT8SZ+BIT32SZ; 236 path0 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; 237 i += BIT32SZ; 238 path1 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; 239 path := (big path1 << 32) | (big path0 & 16rFFFFFFFF); 240 return (path, vers, qtype); 241} 242 243g32(f: array of byte, i: int): int 244{ 245 return (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; 246} 247 248g64(f: array of byte, i: int): big 249{ 250 b0 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; 251 b1 := (((((int f[i+7] << 8) | int f[i+6]) << 8) | int f[i+5]) << 8) | int f[i+4]; 252 return (big b1 << 32) | (big b0 & 16rFFFFFFFF); 253} 254 255gstring(a: array of byte, o: int): (string, int) 256{ 257 if(o < 0 || o+STR > len a) 258 return (nil, -1); 259 l := (int a[o+1] << 8) | int a[o]; 260 o += STR; 261 e := o+l; 262 if(e > len a) 263 return (nil, -1); 264 return (string a[o:e], e); 265} 266 267ttag2type := array[] of { 268tagof Tmsg.Readerror => 0, 269tagof Tmsg.Version => Tversion, 270tagof Tmsg.Auth => Tauth, 271tagof Tmsg.Attach => Tattach, 272tagof Tmsg.Flush => Tflush, 273tagof Tmsg.Walk => Twalk, 274tagof Tmsg.Open => Topen, 275tagof Tmsg.Create => Tcreate, 276tagof Tmsg.Read => Tread, 277tagof Tmsg.Write => Twrite, 278tagof Tmsg.Clunk => Tclunk, 279tagof Tmsg.Stat => Tstat, 280tagof Tmsg.Remove => Tremove, 281tagof Tmsg.Wstat => Twstat, 282}; 283 284Tmsg.mtype(t: self ref Tmsg): int 285{ 286 return ttag2type[tagof t]; 287} 288 289Tmsg.packedsize(t: self ref Tmsg): int 290{ 291 mtype := ttag2type[tagof t]; 292 if(mtype <= 0) 293 return 0; 294 ml := hdrlen[mtype]; 295 pick m := t { 296 Version => 297 ml += utflen(m.version); 298 Auth => 299 ml += utflen(m.uname)+utflen(m.aname); 300 Attach => 301 ml += utflen(m.uname)+utflen(m.aname); 302 Walk => 303 for(i:=0; i<len m.names; i++) 304 ml += STR+utflen(m.names[i]); 305 Create => 306 ml += utflen(m.name); 307 Write => 308 ml += len m.data; 309 Wstat => 310 ml += packdirsize(m.stat); 311 } 312 return ml; 313} 314 315Tmsg.pack(t: self ref Tmsg): array of byte 316{ 317 if(t == nil) 318 return nil; 319 ds := t.packedsize(); 320 if(ds <= 0) 321 return nil; 322 d := array[ds] of byte; 323 d[0] = byte ds; 324 d[1] = byte (ds>>8); 325 d[2] = byte (ds>>16); 326 d[3] = byte (ds>>24); 327 d[4] = byte ttag2type[tagof t]; 328 d[5] = byte t.tag; 329 d[6] = byte (t.tag >> 8); 330 pick m := t { 331 Version => 332 p32(d, H, m.msize); 333 pstring(d, H+COUNT, m.version); 334 Auth => 335 p32(d, H, m.afid); 336 o := pstring(d, H+FID, m.uname); 337 pstring(d, o, m.aname); 338 Flush => 339 v := m.oldtag; 340 d[H] = byte v; 341 d[H+1] = byte (v>>8); 342 Attach => 343 p32(d, H, m.fid); 344 p32(d, H+FID, m.afid); 345 o := pstring(d, H+2*FID, m.uname); 346 pstring(d, o, m.aname); 347 Walk => 348 d[H] = byte m.fid; 349 d[H+1] = byte (m.fid>>8); 350 d[H+2] = byte (m.fid>>16); 351 d[H+3] = byte (m.fid>>24); 352 d[H+FID] = byte m.newfid; 353 d[H+FID+1] = byte (m.newfid>>8); 354 d[H+FID+2] = byte (m.newfid>>16); 355 d[H+FID+3] = byte (m.newfid>>24); 356 n := len m.names; 357 d[H+2*FID] = byte n; 358 d[H+2*FID+1] = byte (n>>8); 359 o := H+2*FID+LEN; 360 for(i := 0; i < n; i++) 361 o = pstring(d, o, m.names[i]); 362 Open => 363 p32(d, H, m.fid); 364 d[H+FID] = byte m.mode; 365 Create => 366 p32(d, H, m.fid); 367 o := pstring(d, H+FID, m.name); 368 p32(d, o, m.perm); 369 d[o+BIT32SZ] = byte m.mode; 370 Read => 371 p32(d, H, m.fid); 372 p64(d, H+FID, m.offset); 373 p32(d, H+FID+OFFSET, m.count); 374 Write => 375 p32(d, H, m.fid); 376 p64(d, H+FID, m.offset); 377 n := len m.data; 378 p32(d, H+FID+OFFSET, n); 379 d[H+FID+OFFSET+COUNT:] = m.data; 380 Clunk or Remove or Stat => 381 p32(d, H, m.fid); 382 Wstat => 383 p32(d, H, m.fid); 384 stat := packdir(m.stat); 385 n := len stat; 386 d[H+FID] = byte n; 387 d[H+FID+1] = byte (n>>8); 388 d[H+FID+LEN:] = stat; 389 * => 390 raise sys->sprint("assertion: Styx->Tmsg.pack: bad tag: %d", tagof t); 391 } 392 return d; 393} 394 395Tmsg.unpack(f: array of byte): (int, ref Tmsg) 396{ 397 if(len f < H) 398 return (0, nil); 399 size := (int f[1] << 8) | int f[0]; 400 size |= ((int f[3] << 8) | int f[2]) << 16; 401 if(len f != size){ 402 if(len f < size) 403 return (0, nil); # need more data 404 f = f[0:size]; # trim to exact length 405 } 406 mtype := int f[4]; 407 if(mtype >= len hdrlen || (mtype&1) != 0 || size < hdrlen[mtype]) 408 return (-1, nil); 409 410 tag := (int f[6] << 8) | int f[5]; 411 fid := 0; 412 if(hdrlen[mtype] >= H+FID) 413 fid = g32(f, H); # fid is always in same place: extract it once for all if there 414 415 # return out of each case body for a legal message; 416 # break out of the case for an illegal one 417 418Decode: 419 case mtype { 420 * => 421 sys->print("styx: Tmsg.unpack: bad type %d\n", mtype); 422 Tversion => 423 msize := fid; 424 (version, o) := gstring(f, H+COUNT); 425 if(o <= 0) 426 break; 427 return (o, ref Tmsg.Version(tag, msize, version)); 428 Tauth => 429 (uname, o1) := gstring(f, H+FID); 430 (aname, o2) := gstring(f, o1); 431 if(o2 <= 0) 432 break; 433 return (o2, ref Tmsg.Auth(tag, fid, uname, aname)); 434 Tflush => 435 oldtag := (int f[H+1] << 8) | int f[H]; 436 return (H+TAG, ref Tmsg.Flush(tag, oldtag)); 437 Tattach => 438 afid := g32(f, H+FID); 439 (uname, o1) := gstring(f, H+2*FID); 440 (aname, o2) := gstring(f, o1); 441 if(o2 <= 0) 442 break; 443 return (o2, ref Tmsg.Attach(tag, fid, afid, uname, aname)); 444 Twalk => 445 newfid := g32(f, H+FID); 446 n := (int f[H+2*FID+1] << 8) | int f[H+2*FID]; 447 if(n > MAXWELEM) 448 break; 449 o := H+2*FID+LEN; 450 names: array of string = nil; 451 if(n > 0){ 452 names = array[n] of string; 453 for(i:=0; i<n; i++){ 454 (names[i], o) = gstring(f, o); 455 if(o <= 0) 456 break Decode; 457 } 458 } 459 return (o, ref Tmsg.Walk(tag, fid, newfid, names)); 460 Topen => 461 return (H+FID+BIT8SZ, ref Tmsg.Open(tag, fid, int f[H+FID])); 462 Tcreate => 463 (name, o) := gstring(f, H+FID); 464 if(o <= 0 || o+BIT32SZ+BIT8SZ > len f) 465 break; 466 perm := g32(f, o); 467 o += BIT32SZ; 468 mode := int f[o++]; 469 return (o, ref Tmsg.Create(tag, fid, name, perm, mode)); 470 Tread => 471 offset := g64(f, H+FID); 472 count := g32(f, H+FID+OFFSET); 473 return (H+FID+OFFSET+COUNT, ref Tmsg.Read(tag, fid, offset, count)); 474 Twrite => 475 offset := g64(f, H+FID); 476 count := g32(f, H+FID+OFFSET); 477 O: con H+FID+OFFSET+COUNT; 478 if(count > len f-O) 479 break; 480 data := f[O:O+count]; 481 return (O+count, ref Tmsg.Write(tag, fid, offset, data)); 482 Tclunk => 483 return (H+FID, ref Tmsg.Clunk(tag, fid)); 484 Tremove => 485 return (H+FID, ref Tmsg.Remove(tag, fid)); 486 Tstat => 487 return (H+FID, ref Tmsg.Stat(tag, fid)); 488 Twstat => 489 n := int (f[H+FID+1]<<8) | int f[H+FID]; 490 if(len f < H+FID+LEN+n) 491 break; 492 (ds, stat) := unpackdir(f[H+FID+LEN:]); 493 if(ds != n){ 494 sys->print("Styx->Tmsg.unpack: wstat count: %d/%d\n", ds, n); # temporary 495 break; 496 } 497 return (H+FID+LEN+n, ref Tmsg.Wstat(tag, fid, stat)); 498 } 499 return (-1, nil); # illegal 500} 501 502tmsgname := array[] of { 503tagof Tmsg.Readerror => "Readerror", 504tagof Tmsg.Version => "Version", 505tagof Tmsg.Auth => "Auth", 506tagof Tmsg.Attach => "Attach", 507tagof Tmsg.Flush => "Flush", 508tagof Tmsg.Walk => "Walk", 509tagof Tmsg.Open => "Open", 510tagof Tmsg.Create => "Create", 511tagof Tmsg.Read => "Read", 512tagof Tmsg.Write => "Write", 513tagof Tmsg.Clunk => "Clunk", 514tagof Tmsg.Stat => "Stat", 515tagof Tmsg.Remove => "Remove", 516tagof Tmsg.Wstat => "Wstat", 517}; 518 519Tmsg.text(t: self ref Tmsg): string 520{ 521 if(t == nil) 522 return "nil"; 523 s := sys->sprint("Tmsg.%s(%ud", tmsgname[tagof t], t.tag); 524 pick m:= t { 525 * => 526 return s + ",ILLEGAL)"; 527 Readerror => 528 return s + sys->sprint(",\"%s\")", m.error); 529 Version => 530 return s + sys->sprint(",%d,\"%s\")", m.msize, m.version); 531 Auth => 532 return s + sys->sprint(",%ud,\"%s\",\"%s\")", m.afid, m.uname, m.aname); 533 Flush => 534 return s + sys->sprint(",%ud)", m.oldtag); 535 Attach => 536 return s + sys->sprint(",%ud,%ud,\"%s\",\"%s\")", m.fid, m.afid, m.uname, m.aname); 537 Walk => 538 s += sys->sprint(",%ud,%ud", m.fid, m.newfid); 539 if(len m.names != 0){ 540 s += ",array[] of {"; 541 for(i := 0; i < len m.names; i++){ 542 c := ","; 543 if(i == 0) 544 c = ""; 545 s += sys->sprint("%s\"%s\"", c, m.names[i]); 546 } 547 s += "}"; 548 }else 549 s += ",nil"; 550 return s + ")"; 551 Open => 552 return s + sys->sprint(",%ud,%d)", m.fid, m.mode); 553 Create => 554 return s + sys->sprint(",%ud,\"%s\",8r%uo,%d)", m.fid, m.name, m.perm, m.mode); 555 Read => 556 return s + sys->sprint(",%ud,%bd,%ud)", m.fid, m.offset, m.count); 557 Write => 558 return s + sys->sprint(",%ud,%bd,array[%d] of byte)", m.fid, m.offset, len m.data); 559 Clunk or 560 Remove or 561 Stat => 562 return s + sys->sprint(",%ud)", m.fid); 563 Wstat => 564 return s + sys->sprint(",%ud,%s)", m.fid, dir2text(m.stat)); 565 } 566} 567 568Tmsg.read(fd: ref Sys->FD, msglim: int): ref Tmsg 569{ 570 (msg, err) := readmsg(fd, msglim); 571 if(err != nil) 572 return ref Tmsg.Readerror(0, err); 573 if(msg == nil) 574 return nil; 575 (nil, m) := Tmsg.unpack(msg); 576 if(m == nil) 577 return ref Tmsg.Readerror(0, "bad 9P T-message format"); 578 return m; 579} 580 581rtag2type := array[] of { 582tagof Rmsg.Version => Rversion, 583tagof Rmsg.Auth => Rauth, 584tagof Rmsg.Error => Rerror, 585tagof Rmsg.Flush => Rflush, 586tagof Rmsg.Attach => Rattach, 587tagof Rmsg.Walk => Rwalk, 588tagof Rmsg.Open => Ropen, 589tagof Rmsg.Create => Rcreate, 590tagof Rmsg.Read => Rread, 591tagof Rmsg.Write => Rwrite, 592tagof Rmsg.Clunk => Rclunk, 593tagof Rmsg.Remove => Rremove, 594tagof Rmsg.Stat => Rstat, 595tagof Rmsg.Wstat => Rwstat, 596}; 597 598Rmsg.mtype(r: self ref Rmsg): int 599{ 600 return rtag2type[tagof r]; 601} 602 603Rmsg.packedsize(r: self ref Rmsg): int 604{ 605 mtype := rtag2type[tagof r]; 606 if(mtype <= 0) 607 return 0; 608 ml := hdrlen[mtype]; 609 pick m := r { 610 Version => 611 ml += utflen(m.version); 612 Error => 613 ml += utflen(m.ename); 614 Walk => 615 ml += QID*len m.qids; 616 Read => 617 ml += len m.data; 618 Stat => 619 ml += packdirsize(m.stat); 620 } 621 return ml; 622} 623 624Rmsg.pack(r: self ref Rmsg): array of byte 625{ 626 if(r == nil) 627 return nil; 628 ps := r.packedsize(); 629 if(ps <= 0) 630 return nil; 631 d := array[ps] of byte; 632 d[0] = byte ps; 633 d[1] = byte (ps>>8); 634 d[2] = byte (ps>>16); 635 d[3] = byte (ps>>24); 636 d[4] = byte rtag2type[tagof r]; 637 d[5] = byte r.tag; 638 d[6] = byte (r.tag >> 8); 639 pick m := r { 640 Version => 641 p32(d, H, m.msize); 642 pstring(d, H+BIT32SZ, m.version); 643 Auth => 644 pqid(d, H, m.aqid); 645 Flush or 646 Clunk or 647 Remove or 648 Wstat => 649 ; # nothing more required 650 Error => 651 pstring(d, H, m.ename); 652 Attach => 653 pqid(d, H, m.qid); 654 Walk => 655 n := len m.qids; 656 d[H] = byte n; 657 d[H+1] = byte (n>>8); 658 o := H+LEN; 659 for(i:=0; i<n; i++){ 660 pqid(d, o, m.qids[i]); 661 o += QID; 662 } 663 Create or 664 Open => 665 pqid(d, H, m.qid); 666 p32(d, H+QID, m.iounit); 667 Read => 668 v := len m.data; 669 d[H] = byte v; 670 d[H+1] = byte (v>>8); 671 d[H+2] = byte (v>>16); 672 d[H+3] = byte (v>>24); 673 d[H+4:] = m.data; 674 Write => 675 v := m.count; 676 d[H] = byte v; 677 d[H+1] = byte (v>>8); 678 d[H+2] = byte (v>>16); 679 d[H+3] = byte (v>>24); 680 Stat => 681 stat := packdir(m.stat); 682 v := len stat; 683 d[H] = byte v; 684 d[H+1] = byte (v>>8); 685 d[H+2:] = stat; # should avoid copy? 686 * => 687 raise sys->sprint("assertion: Styx->Rmsg.pack: missed case: tag %d", tagof r); 688 } 689 return d; 690} 691 692Rmsg.unpack(f: array of byte): (int, ref Rmsg) 693{ 694 if(len f < H) 695 return (0, nil); 696 size := (int f[1] << 8) | int f[0]; 697 size |= ((int f[3] << 8) | int f[2]) << 16; # size includes itself 698 if(len f != size){ 699 if(len f < size) 700 return (0, nil); # need more data 701 f = f[0:size]; # trim to exact length 702 } 703 mtype := int f[4]; 704 if(mtype >= len hdrlen || (mtype&1) == 0 || size < hdrlen[mtype]) 705 return (-1, nil); 706 707 tag := (int f[6] << 8) | int f[5]; 708 709 # return out of each case body for a legal message; 710 # break out of the case for an illegal one 711 712 case mtype { 713 * => 714 sys->print("Styx->Rmsg.unpack: bad type %d\n", mtype); # temporary 715 Rversion => 716 msize := g32(f, H); 717 (version, o) := gstring(f, H+BIT32SZ); 718 if(o <= 0) 719 break; 720 return (o, ref Rmsg.Version(tag, msize, version)); 721 Rauth => 722 return (H+QID, ref Rmsg.Auth(tag, gqid(f, H))); 723 Rflush => 724 return (H, ref Rmsg.Flush(tag)); 725 Rerror => 726 (ename, o) := gstring(f, H); 727 if(o <= 0) 728 break; 729 return (o, ref Rmsg.Error(tag, ename)); 730 Rclunk => 731 return (H, ref Rmsg.Clunk(tag)); 732 Rremove => 733 return (H, ref Rmsg.Remove(tag)); 734 Rwstat=> 735 return (H, ref Rmsg.Wstat(tag)); 736 Rattach => 737 return (H+QID, ref Rmsg.Attach(tag, gqid(f, H))); 738 Rwalk => 739 nqid := (int f[H+1] << 8) | int f[H]; 740 if(len f < H+LEN+nqid*QID) 741 break; 742 o := H+LEN; 743 qids := array[nqid] of Sys->Qid; 744 for(i:=0; i<nqid; i++){ 745 qids[i] = gqid(f, o); 746 o += QID; 747 } 748 return (o, ref Rmsg.Walk(tag, qids)); 749 Ropen => 750 return (H+QID+COUNT, ref Rmsg.Open(tag, gqid(f, H), g32(f, H+QID))); 751 Rcreate=> 752 return (H+QID+COUNT, ref Rmsg.Create(tag, gqid(f, H), g32(f, H+QID))); 753 Rread => 754 count := g32(f, H); 755 if(len f < H+COUNT+count) 756 break; 757 data := f[H+COUNT:H+COUNT+count]; 758 return (H+COUNT+count, ref Rmsg.Read(tag, data)); 759 Rwrite => 760 return (H+COUNT, ref Rmsg.Write(tag, g32(f, H))); 761 Rstat => 762 n := (int f[H+1] << 8) | int f[H]; 763 if(len f < H+LEN+n) 764 break; 765 (ds, d) := unpackdir(f[H+LEN:]); 766 if(ds <= 0) 767 break; 768 if(ds != n){ 769 sys->print("Styx->Rmsg.unpack: stat count: %d/%d\n", ds, n); # temporary 770 break; 771 } 772 return (H+LEN+n, ref Rmsg.Stat(tag, d)); 773 } 774 return (-1, nil); # illegal 775} 776 777rmsgname := array[] of { 778tagof Rmsg.Version => "Version", 779tagof Rmsg.Auth => "Auth", 780tagof Rmsg.Attach => "Attach", 781tagof Rmsg.Error => "Error", 782tagof Rmsg.Flush => "Flush", 783tagof Rmsg.Walk => "Walk", 784tagof Rmsg.Create => "Create", 785tagof Rmsg.Open => "Open", 786tagof Rmsg.Read => "Read", 787tagof Rmsg.Write => "Write", 788tagof Rmsg.Clunk => "Clunk", 789tagof Rmsg.Remove => "Remove", 790tagof Rmsg.Stat => "Stat", 791tagof Rmsg.Wstat => "Wstat", 792}; 793 794Rmsg.text(r: self ref Rmsg): string 795{ 796 if(sys == nil) 797 sys = load Sys Sys->PATH; 798 if(r == nil) 799 return "nil"; 800 s := sys->sprint("Rmsg.%s(%ud", rmsgname[tagof r], r.tag); 801 pick m := r { 802 * => 803 return s + "ERROR)"; 804 Readerror => 805 return s + sys->sprint(",\"%s\")", m.error); 806 Version => 807 return s + sys->sprint(",%d,\"%s\")", m.msize, m.version); 808 Auth => 809 return s+sys->sprint(",%s)", qid2text(m.aqid)); 810 Error => 811 return s+sys->sprint(",\"%s\")", m.ename); 812 Flush or 813 Clunk or 814 Remove or 815 Wstat => 816 return s+")"; 817 Attach => 818 return s+sys->sprint(",%s)", qid2text(m.qid)); 819 Walk => 820 s += ",array[] of {"; 821 for(i := 0; i < len m.qids; i++){ 822 c := ""; 823 if(i != 0) 824 c = ","; 825 s += sys->sprint("%s%s", c, qid2text(m.qids[i])); 826 } 827 return s+"})"; 828 Create or 829 Open => 830 return s+sys->sprint(",%s,%d)", qid2text(m.qid), m.iounit); 831 Read => 832 return s+sys->sprint(",array[%d] of byte)", len m.data); 833 Write => 834 return s+sys->sprint(",%d)", m.count); 835 Stat => 836 return s+sys->sprint(",%s)", dir2text(m.stat)); 837 } 838} 839 840Rmsg.read(fd: ref Sys->FD, msglim: int): ref Rmsg 841{ 842 (msg, err) := readmsg(fd, msglim); 843 if(err != nil) 844 return ref Rmsg.Readerror(0, err); 845 if(msg == nil) 846 return nil; 847 (nil, m) := Rmsg.unpack(msg); 848 if(m == nil) 849 return ref Rmsg.Readerror(0, "bad 9P R-message format"); 850 return m; 851} 852 853dir2text(d: Sys->Dir): string 854{ 855 return sys->sprint("Dir(\"%s\",\"%s\",\"%s\",%s,8r%uo,%d,%d,%bd,16r%ux,%d)", 856 d.name, d.uid, d.gid, qid2text(d.qid), d.mode, d.atime, d.mtime, d.length, d.dtype, d.dev); 857} 858 859qid2text(q: Sys->Qid): string 860{ 861 return sys->sprint("Qid(16r%ubx,%d,16r%.2ux)", q.path, q.vers, q.qtype); 862} 863 864readmsg(fd: ref Sys->FD, msglim: int): (array of byte, string) 865{ 866 if(msglim <= 0) 867 msglim = MAXRPC; 868 sbuf := array[BIT32SZ] of byte; 869 if((n := sys->readn(fd, sbuf, BIT32SZ)) != BIT32SZ){ 870 if(n == 0) 871 return (nil, nil); 872 return (nil, sys->sprint("%r")); 873 } 874 ml := (int sbuf[1] << 8) | int sbuf[0]; 875 ml |= ((int sbuf[3] << 8) | int sbuf[2]) << 16; 876 if(ml <= BIT32SZ) 877 return (nil, "invalid 9P message size"); 878 if(ml > msglim) 879 return (nil, "9P message longer than agreed"); 880 buf := array[ml] of byte; 881 buf[0:] = sbuf; 882 if((n = sys->readn(fd, buf[BIT32SZ:], ml-BIT32SZ)) != ml-BIT32SZ){ 883 if(n == 0) 884 return (nil, "9P message truncated"); 885 return (nil, sys->sprint("%r")); 886 } 887 return (buf, nil); 888} 889 890istmsg(f: array of byte): int 891{ 892 if(len f < H) 893 return -1; 894 return (int f[BIT32SZ] & 1) == 0; 895} 896 897compatible(t: ref Tmsg.Version, msize: int, version: string): (int, string) 898{ 899 if(version == nil) 900 version = VERSION; 901 if(t.msize < msize) 902 msize = t.msize; 903 v := t.version; 904 if(len v < 2 || v[0:2] != "9P") 905 return (msize, "unknown"); 906 for(i:=2; i<len v; i++) 907 if((c := v[i]) == '.'){ 908 v = v[0:i]; 909 break; 910 }else if(!(c >= '0' && c <= '9')) 911 return (msize, "unknown"); # fussier than Plan 9 912 if(v < VERSION) 913 return (msize, "unknown"); 914 if(v < version) 915 version = v; 916 return (msize, version); 917} 918 919# only here to support an implementation of this module that talks the previous version of Styx 920write(fd: ref Sys->FD, buf: array of byte, nb: int): int 921{ 922 return sys->write(fd, buf, nb); 923} 924