Unified · Split
| @@ -1,3 +1,5 @@ | |||
| 1 | 20100220 | ||
| 2 | appl/cmd/keyfs.b wasn't clunking fids on error in remove [issue 225] | ||
| 1 | 20100213 | 3 | 20100213 |
| 2 | apply saoret.one's changes for thumb [issue 155] | 4 | apply saoret.one's changes for thumb [issue 155] |
| 3 | 20100205 | 5 | 20100205 |
| @@ -185,7 +185,7 @@ fileserve(rfd: ref Sys->FD, sync: chan of int) · 184 unmodified lines | |||
| 185 | error("bad R-message conversion"); | 185 | error("bad R-message conversion"); |
| 186 | if(showstyx) | 186 | if(showstyx) |
| 187 | chat(r.text()+"\n"); | 187 | chat(r.text()+"\n"); |
| 188 | if(styx->write(rfd, rbuf, len rbuf) != len rbuf) | 188 | if(sys->write(rfd, rbuf, len rbuf) != len rbuf) |
| 189 | error(sys->sprint("connection write error: %r")); | 189 | error(sys->sprint("connection write error: %r")); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| @@ -415,6 +415,7 @@ serveloop(tchan: chan of ref Tmsg, srv: ref Styxserver, pidc: chan of int, navop · 414 unmodified lines | |||
| 415 | } | 415 | } |
| 416 | case TYPE(c.path) { | 416 | case TYPE(c.path) { |
| 417 | Quser => | 417 | Quser => |
| 418 | srv.delfid(c); | ||
| 418 | u := finduserpath(c.path); | 419 | u := finduserpath(c.path); |
| 419 | if(u == nil){ | 420 | if(u == nil){ |
| 420 | srv.reply(ref Rmsg.Error(m.tag, Eremoved)); | 421 | srv.reply(ref Rmsg.Error(m.tag, Eremoved)); |
| @@ -422,9 +423,9 @@ serveloop(tchan: chan of ref Tmsg, srv: ref Styxserver, pidc: chan of int, navop · 1 unmodified line | |||
| 422 | } | 423 | } |
| 423 | removeuser(u); | 424 | removeuser(u); |
| 424 | writekeys(keyfile); | 425 | writekeys(keyfile); |
| 425 | srv.delfid(c); | ||
| 426 | srv.reply(ref Rmsg.Remove(m.tag)); | 426 | srv.reply(ref Rmsg.Remove(m.tag)); |
| 427 | Qsecret => | 427 | Qsecret => |
| 428 | srv.delfid(c); | ||
| 428 | u := finduserpath(c.path); | 429 | u := finduserpath(c.path); |
| 429 | if(u == nil){ | 430 | if(u == nil){ |
| 430 | srv.reply(ref Rmsg.Error(m.tag, Eremoved)); | 431 | srv.reply(ref Rmsg.Error(m.tag, Eremoved)); |
| @@ -432,7 +433,6 @@ serveloop(tchan: chan of ref Tmsg, srv: ref Styxserver, pidc: chan of int, navop · 1 unmodified line | |||
| 432 | } | 433 | } |
| 433 | u.secret = nil; | 434 | u.secret = nil; |
| 434 | writekeys(keyfile); | 435 | writekeys(keyfile); |
| 435 | srv.delfid(c); | ||
| 436 | srv.reply(ref Rmsg.Remove(m.tag)); | 436 | srv.reply(ref Rmsg.Remove(m.tag)); |
| 437 | * => | 437 | * => |
| 438 | srv.remove(m); # let it reject it | 438 | srv.remove(m); # let it reject it |
| @@ -195,7 +195,6 @@ dossrv(rfd: ref Sys->FD) · 194 unmodified lines | |||
| 195 | { | 195 | { |
| 196 | sys->pctl(Sys->NEWFD, rfd.fd :: 2 :: nil); | 196 | sys->pctl(Sys->NEWFD, rfd.fd :: 2 :: nil); |
| 197 | rfd = sys->fildes(rfd.fd); | 197 | rfd = sys->fildes(rfd.fd); |
| 198 | data := array[Styx->MAXRPC] of byte; | ||
| 199 | while((t := Tmsg.read(rfd, 0)) != nil){ | 198 | while((t := Tmsg.read(rfd, 0)) != nil){ |
| 200 | if(debug & STYX_MESS) | 199 | if(debug & STYX_MESS) |
| 201 | chat(sys->sprint("%s...", t.text())); | 200 | chat(sys->sprint("%s...", t.text())); |
| @@ -242,7 +241,7 @@ dossrv(rfd: ref Sys->FD) · 40 unmodified lines | |||
| 242 | panic("Rmsg.pack"); | 241 | panic("Rmsg.pack"); |
| 243 | if(debug & STYX_MESS) | 242 | if(debug & STYX_MESS) |
| 244 | chat(sys->sprint("%s\n", r.text())); | 243 | chat(sys->sprint("%s\n", r.text())); |
| 245 | if(styx->write(rfd, rbuf, len rbuf) != len rbuf) | 244 | if(sys->write(rfd, rbuf, len rbuf) != len rbuf) |
| 246 | panic("mount write"); | 245 | panic("mount write"); |
| 247 | } | 246 | } |
| 248 | 247 | ||
| @@ -967,7 +966,7 @@ rwstat(t: ref Tmsg.Wstat): ref Rmsg · 718 unmodified lines | |||
| 967 | oaddr := dp.addr; | 966 | oaddr := dp.addr; |
| 968 | ooffset := dp.offset; | 967 | ooffset := dp.offset; |
| 969 | d := dpd; | 968 | d := dpd; |
| 970 | od := *d; | 969 | # od := *d; |
| 971 | # start := getstart(f.xf, d); | 970 | # start := getstart(f.xf, d); |
| 972 | start := d.start; | 971 | start := d.start; |
| 973 | length := d.length; | 972 | length := d.length; |
| @@ -1395,7 +1394,7 @@ putstart(nil: ref Xfs, d: ref Dosdir, start: int) · 421 unmodified lines | |||
| 1395 | fileclust(f: ref Xfile, iclust: int, cflag: int): int | 1394 | fileclust(f: ref Xfile, iclust: int, cflag: int): int |
| 1396 | { | 1395 | { |
| 1397 | 1396 | ||
| 1398 | bp := f.xf.ptr; | 1397 | # bp := f.xf.ptr; |
| 1399 | dp := f.ptr; | 1398 | dp := f.ptr; |
| 1400 | if(isroot(dp.addr)) | 1399 | if(isroot(dp.addr)) |
| 1401 | return -1; # root directory for old FAT format does not start on a cluster boundary | 1400 | return -1; # root directory for old FAT format does not start on a cluster boundary |
| @@ -2067,7 +2066,7 @@ writefile(f: ref Xfile, buf: array of byte, offset,count: int): int · 665 unmodified lines | |||
| 2067 | truncfile(f: ref Xfile): int | 2066 | truncfile(f: ref Xfile): int |
| 2068 | { | 2067 | { |
| 2069 | xf := f.xf; | 2068 | xf := f.xf; |
| 2070 | bp := xf.ptr; | 2069 | # bp := xf.ptr; |
| 2071 | dp := f.ptr; | 2070 | dp := f.ptr; |
| 2072 | d := Dosdir.arr2Dd(dp.p.iobuf[dp.offset:dp.offset+DOSDIRSIZE]); | 2071 | d := Dosdir.arr2Dd(dp.p.iobuf[dp.offset:dp.offset+DOSDIRSIZE]); |
| 2073 | 2072 | ||
| @@ -280,7 +280,7 @@ sendreply(r: ref Rmsg) · 279 unmodified lines | |||
| 280 | if (debug) | 280 | if (debug) |
| 281 | sys->print("> %s\n", r.text()); | 281 | sys->print("> %s\n", r.text()); |
| 282 | a := r.pack(); | 282 | a := r.pack(); |
| 283 | if(styx->write(styxfd, a, len a) != len a) | 283 | if(sys->write(styxfd, a, len a) != len a) |
| 284 | sys->print("ftpfs: error replying: %r\n"); | 284 | sys->print("ftpfs: error replying: %r\n"); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| @@ -0,0 +1,914 @@ | |||
| 1 | implement Ninep; | ||
| 2 | |||
| 3 | include "sys.m"; | ||
| 4 | sys: Sys; | ||
| 5 | |||
| 6 | include "9p.m"; | ||
| 7 | |||
| 8 | STR: con BIT16SZ; # string length | ||
| 9 | TAG: con BIT16SZ; | ||
| 10 | FID: con BIT32SZ; | ||
| 11 | QID: con BIT8SZ+BIT32SZ+BIT64SZ; | ||
| 12 | LEN: con BIT16SZ; # stat and qid array lengths | ||
| 13 | COUNT: con BIT32SZ; | ||
| 14 | OFFSET: con BIT64SZ; | ||
| 15 | |||
| 16 | H: 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 | # | ||
| 21 | hdrlen := array[Tmax] of | ||
| 22 | { | ||
| 23 | Tversion => H+COUNT+STR, # size[4] Tversion tag[2] msize[4] version[s] | ||
| 24 | Rversion => H+COUNT+STR, # size[4] Rversion tag[2] msize[4] version[s] | ||
| 25 | |||
| 26 | Tauth => H+FID+STR+STR, # size[4] Tauth tag[2] afid[4] uname[s] aname[s] | ||
| 27 | Rauth => H+QID, # size[4] Rauth tag[2] aqid[13] | ||
| 28 | |||
| 29 | Rerror => H+STR, # size[4] Rerror tag[2] ename[s] | ||
| 30 | |||
| 31 | Tflush => H+TAG, # size[4] Tflush tag[2] oldtag[2] | ||
| 32 | Rflush => H, # size[4] Rflush tag[2] | ||
| 33 | |||
| 34 | Tattach => H+FID+FID+STR+STR, # size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] | ||
| 35 | Rattach => H+QID, # size[4] Rattach tag[2] qid[13] | ||
| 36 | |||
| 37 | Twalk => H+FID+FID+LEN, # size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) | ||
| 38 | Rwalk => H+LEN, # size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) | ||
| 39 | |||
| 40 | Topen => H+FID+BIT8SZ, # size[4] Topen tag[2] fid[4] mode[1] | ||
| 41 | Ropen => H+QID+COUNT, # size[4] Ropen tag[2] qid[13] iounit[4] | ||
| 42 | |||
| 43 | Tcreate => H+FID+STR+BIT32SZ+BIT8SZ, # size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1] | ||
| 44 | Rcreate => H+QID+COUNT, # size[4] Rcreate tag[2] qid[13] iounit[4] | ||
| 45 | |||
| 46 | Tread => H+FID+OFFSET+COUNT, # size[4] Tread tag[2] fid[4] offset[8] count[4] | ||
| 47 | Rread => H+COUNT, # size[4] Rread tag[2] count[4] data[count] | ||
| 48 | |||
| 49 | Twrite => H+FID+OFFSET+COUNT, # size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] | ||
| 50 | Rwrite => H+COUNT, # size[4] Rwrite tag[2] count[4] | ||
| 51 | |||
| 52 | Tclunk => H+FID, # size[4] Tclunk tag[2] fid[4] | ||
| 53 | Rclunk => H, # size[4] Rclunk tag[2] | ||
| 54 | |||
| 55 | Tremove => H+FID, # size[4] Tremove tag[2] fid[4] | ||
| 56 | Rremove => H, # size[4] Rremove tag[2] | ||
| 57 | |||
| 58 | Tstat => H+FID, # size[4] Tstat tag[2] fid[4] | ||
| 59 | Rstat => H+LEN, # size[4] Rstat tag[2] stat[n] | ||
| 60 | |||
| 61 | Twstat => H+FID+LEN, # size[4] Twstat tag[2] fid[4] stat[n] | ||
| 62 | Rwstat => H, # size[4] Rwstat tag[2] | ||
| 63 | }; | ||
| 64 | |||
| 65 | init() | ||
| 66 | { | ||
| 67 | sys = load Sys Sys->PATH; | ||
| 68 | } | ||
| 69 | |||
| 70 | utflen(s: string): int | ||
| 71 | { | ||
| 72 | # the domain is 16-bit unicode only, which is all that Inferno now implements | ||
| 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 | } | ||
| 80 | return n; | ||
| 81 | } | ||
| 82 | |||
| 83 | packdirsize(d: Sys->Dir): int | ||
| 84 | { | ||
| 85 | return STATFIXLEN+utflen(d.name)+utflen(d.uid)+utflen(d.gid)+utflen(d.muid); | ||
| 86 | } | ||
| 87 | |||
| 88 | packdir(f: Sys->Dir): array of byte | ||
| 89 | { | ||
| 90 | ds := packdirsize(f); | ||
| 91 | a := array[ds] of byte; | ||
| 92 | # size[2] | ||
| 93 | a[0] = byte (ds-LEN); | ||
| 94 | a[1] = byte ((ds-LEN)>>8); | ||
| 95 | # type[2] | ||
| 96 | a[2] = byte f.dtype; | ||
| 97 | a[3] = byte (f.dtype>>8); | ||
| 98 | # dev[4] | ||
| 99 | a[4] = byte f.dev; | ||
| 100 | a[5] = byte (f.dev>>8); | ||
| 101 | a[6] = byte (f.dev>>16); | ||
| 102 | a[7] = byte (f.dev>>24); | ||
| 103 | # qid.type[1] | ||
| 104 | # qid.vers[4] | ||
| 105 | # qid.path[8] | ||
| 106 | pqid(a, 8, f.qid); | ||
| 107 | # mode[4] | ||
| 108 | a[21] = byte f.mode; | ||
| 109 | a[22] = byte (f.mode>>8); | ||
| 110 | a[23] = byte (f.mode>>16); | ||
| 111 | a[24] = byte (f.mode>>24); | ||
| 112 | # atime[4] | ||
| 113 | a[25] = byte f.atime; | ||
| 114 | a[26] = byte (f.atime>>8); | ||
| 115 | a[27] = byte (f.atime>>16); | ||
| 116 | a[28] = byte (f.atime>>24); | ||
| 117 | # mtime[4] | ||
| 118 | a[29] = byte f.mtime; | ||
| 119 | a[30] = byte (f.mtime>>8); | ||
| 120 | a[31] = byte (f.mtime>>16); | ||
| 121 | a[32] = byte (f.mtime>>24); | ||
| 122 | # length[8] | ||
| 123 | p64(a, 33, big f.length); | ||
| 124 | # name[s] | ||
| 125 | i := pstring(a, 33+BIT64SZ, f.name); | ||
| 126 | i = pstring(a, i, f.uid); | ||
| 127 | i = pstring(a, i, f.gid); | ||
| 128 | i = pstring(a, i, f.muid); | ||
| 129 | if(i != len a) | ||
| 130 | raise "assertion: Ninep->packdir: bad count"; # can't happen unless packedsize is wrong | ||
| 131 | return a; | ||
| 132 | } | ||
| 133 | |||
| 134 | pqid(a: array of byte, o: int, q: Sys->Qid): int | ||
| 135 | { | ||
| 136 | a[o] = byte q.qtype; | ||
| 137 | v := q.vers; | ||
| 138 | a[o+1] = byte v; | ||
| 139 | a[o+2] = byte (v>>8); | ||
| 140 | a[o+3] = byte (v>>16); | ||
| 141 | a[o+4] = byte (v>>24); | ||
| 142 | v = int q.path; | ||
| 143 | a[o+5] = byte v; | ||
| 144 | a[o+6] = byte (v>>8); | ||
| 145 | a[o+7] = byte (v>>16); | ||
| 146 | a[o+8] = byte (v>>24); | ||
| 147 | v = int (q.path >> 32); | ||
| 148 | a[o+9] = byte v; | ||
| 149 | a[o+10] = byte (v>>8); | ||
| 150 | a[o+11] = byte (v>>16); | ||
| 151 | a[o+12] = byte (v>>24); | ||
| 152 | return o+QID; | ||
| 153 | } | ||
| 154 | |||
| 155 | pstring(a: array of byte, o: int, s: string): int | ||
| 156 | { | ||
| 157 | sa := array of byte s; # could do conversion ourselves | ||
| 158 | n := len sa; | ||
| 159 | a[o] = byte n; | ||
| 160 | a[o+1] = byte (n>>8); | ||
| 161 | a[o+2:] = sa; | ||
| 162 | return o+LEN+n; | ||
| 163 | } | ||
| 164 | |||
| 165 | p32(a: array of byte, o: int, v: int): int | ||
| 166 | { | ||
| 167 | a[o] = byte v; | ||
| 168 | a[o+1] = byte (v>>8); | ||
| 169 | a[o+2] = byte (v>>16); | ||
| 170 | a[o+3] = byte (v>>24); | ||
| 171 | return o+BIT32SZ; | ||
| 172 | } | ||
| 173 | |||
| 174 | p64(a: array of byte, o: int, b: big): int | ||
| 175 | { | ||
| 176 | i := int b; | ||
| 177 | a[o] = byte i; | ||
| 178 | a[o+1] = byte (i>>8); | ||
| 179 | a[o+2] = byte (i>>16); | ||
| 180 | a[o+3] = byte (i>>24); | ||
| 181 | i = int (b>>32); | ||
| 182 | a[o+4] = byte i; | ||
| 183 | a[o+5] = byte (i>>8); | ||
| 184 | a[o+6] = byte (i>>16); | ||
| 185 | a[o+7] = byte (i>>24); | ||
| 186 | return o+BIT64SZ; | ||
| 187 | } | ||
| 188 | |||
| 189 | unpackdir(a: array of byte): (int, Sys->Dir) | ||
| 190 | { | ||
| 191 | dir: Sys->Dir; | ||
| 192 | |||
| 193 | if(len a < STATFIXLEN) | ||
| 194 | return (0, dir); | ||
| 195 | # size[2] | ||
| 196 | sz := ((int a[1] << 8) | int a[0])+LEN; # bytes this packed dir should occupy | ||
| 197 | if(len a < sz) | ||
| 198 | return (0, dir); | ||
| 199 | # type[2] | ||
| 200 | dir.dtype = (int a[3]<<8) | int a[2]; | ||
| 201 | # dev[4] | ||
| 202 | dir.dev = (((((int a[7] << 8) | int a[6]) << 8) | int a[5]) << 8) | int a[4]; | ||
| 203 | # qid.type[1] | ||
| 204 | # qid.vers[4] | ||
| 205 | # qid.path[8] | ||
| 206 | dir.qid = gqid(a, 8); | ||
| 207 | # mode[4] | ||
| 208 | dir.mode = (((((int a[24] << 8) | int a[23]) << 8) | int a[22]) << 8) | int a[21]; | ||
| 209 | # atime[4] | ||
| 210 | dir.atime = (((((int a[28] << 8) | int a[27]) << 8) | int a[26]) << 8) | int a[25]; | ||
| 211 | # mtime[4] | ||
| 212 | dir.mtime = (((((int a[32] << 8) | int a[31]) << 8) | int a[30]) << 8) | int a[29]; | ||
| 213 | # length[8] | ||
| 214 | v0 := (((((int a[36] << 8) | int a[35]) << 8) | int a[34]) << 8) | int a[33]; | ||
| 215 | v1 := (((((int a[40] << 8) | int a[39]) << 8) | int a[38]) << 8) | int a[37]; | ||
| 216 | dir.length = (big v1 << 32) | (big v0 & 16rFFFFFFFF); | ||
| 217 | # name[s], uid[s], gid[s], muid[s] | ||
| 218 | i: int; | ||
| 219 | (dir.name, i) = gstring(a, 41); | ||
| 220 | (dir.uid, i) = gstring(a, i); | ||
| 221 | (dir.gid, i) = gstring(a, i); | ||
| 222 | (dir.muid, i) = gstring(a, i); | ||
| 223 | if(i != sz) | ||
| 224 | return (0, dir); | ||
| 225 | return (i, dir); | ||
| 226 | } | ||
| 227 | |||
| 228 | gqid(f: array of byte, i: int): Sys->Qid | ||
| 229 | { | ||
| 230 | qtype := int f[i]; | ||
| 231 | vers := (((((int f[i+4] << 8) | int f[i+3]) << 8) | int f[i+2]) << 8) | int f[i+1]; | ||
| 232 | i += BIT8SZ+BIT32SZ; | ||
| 233 | path0 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; | ||
| 234 | i += BIT32SZ; | ||
| 235 | path1 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; | ||
| 236 | path := (big path1 << 32) | (big path0 & 16rFFFFFFFF); | ||
| 237 | return (path, vers, qtype); | ||
| 238 | } | ||
| 239 | |||
| 240 | g32(f: array of byte, i: int): int | ||
| 241 | { | ||
| 242 | return (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; | ||
| 243 | } | ||
| 244 | |||
| 245 | g64(f: array of byte, i: int): big | ||
| 246 | { | ||
| 247 | b0 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i]; | ||
| 248 | b1 := (((((int f[i+7] << 8) | int f[i+6]) << 8) | int f[i+5]) << 8) | int f[i+4]; | ||
| 249 | return (big b1 << 32) | (big b0 & 16rFFFFFFFF); | ||
| 250 | } | ||
| 251 | |||
| 252 | gstring(a: array of byte, o: int): (string, int) | ||
| 253 | { | ||
| 254 | if(o < 0 || o+STR > len a) | ||
| 255 | return (nil, -1); | ||
| 256 | l := (int a[o+1] << 8) | int a[o]; | ||
| 257 | o += STR; | ||
| 258 | e := o+l; | ||
| 259 | if(e > len a) | ||
| 260 | return (nil, -1); | ||
| 261 | return (string a[o:e], e); | ||
| 262 | } | ||
| 263 | |||
| 264 | ttag2type := array[] of { | ||
| 265 | tagof Tmsg.Readerror => 0, | ||
| 266 | tagof Tmsg.Version => Tversion, | ||
| 267 | tagof Tmsg.Auth => Tauth, | ||
| 268 | tagof Tmsg.Attach => Tattach, | ||
| 269 | tagof Tmsg.Flush => Tflush, | ||
| 270 | tagof Tmsg.Walk => Twalk, | ||
| 271 | tagof Tmsg.Open => Topen, | ||
| 272 | tagof Tmsg.Create => Tcreate, | ||
| 273 | tagof Tmsg.Read => Tread, | ||
| 274 | tagof Tmsg.Write => Twrite, | ||
| 275 | tagof Tmsg.Clunk => Tclunk, | ||
| 276 | tagof Tmsg.Stat => Tstat, | ||
| 277 | tagof Tmsg.Remove => Tremove, | ||
| 278 | tagof Tmsg.Wstat => Twstat, | ||
| 279 | }; | ||
| 280 | |||
| 281 | Tmsg.mtype(t: self ref Tmsg): int | ||
| 282 | { | ||
| 283 | return ttag2type[tagof t]; | ||
| 284 | } | ||
| 285 | |||
| 286 | Tmsg.packedsize(t: self ref Tmsg): int | ||
| 287 | { | ||
| 288 | mtype := ttag2type[tagof t]; | ||
| 289 | if(mtype <= 0) | ||
| 290 | return 0; | ||
| 291 | ml := hdrlen[mtype]; | ||
| 292 | pick m := t { | ||
| 293 | Version => | ||
| 294 | ml += utflen(m.version); | ||
| 295 | Auth => | ||
| 296 | ml += utflen(m.uname)+utflen(m.aname); | ||
| 297 | Attach => | ||
| 298 | ml += utflen(m.uname)+utflen(m.aname); | ||
| 299 | Walk => | ||
| 300 | for(i:=0; i<len m.names; i++) | ||
| 301 | ml += STR+utflen(m.names[i]); | ||
| 302 | Create => | ||
| 303 | ml += utflen(m.name); | ||
| 304 | Write => | ||
| 305 | ml += len m.data; | ||
| 306 | Wstat => | ||
| 307 | ml += packdirsize(m.stat); | ||
| 308 | } | ||
| 309 | return ml; | ||
| 310 | } | ||
| 311 | |||
| 312 | Tmsg.pack(t: self ref Tmsg): array of byte | ||
| 313 | { | ||
| 314 | if(t == nil) | ||
| 315 | return nil; | ||
| 316 | ds := t.packedsize(); | ||
| 317 | if(ds <= 0) | ||
| 318 | return nil; | ||
| 319 | d := array[ds] of byte; | ||
| 320 | d[0] = byte ds; | ||
| 321 | d[1] = byte (ds>>8); | ||
| 322 | d[2] = byte (ds>>16); | ||
| 323 | d[3] = byte (ds>>24); | ||
| 324 | d[4] = byte ttag2type[tagof t]; | ||
| 325 | d[5] = byte t.tag; | ||
| 326 | d[6] = byte (t.tag >> 8); | ||
| 327 | pick m := t { | ||
| 328 | Version => | ||
| 329 | p32(d, H, m.msize); | ||
| 330 | pstring(d, H+COUNT, m.version); | ||
| 331 | Auth => | ||
| 332 | p32(d, H, m.afid); | ||
| 333 | o := pstring(d, H+FID, m.uname); | ||
| 334 | pstring(d, o, m.aname); | ||
| 335 | Flush => | ||
| 336 | v := m.oldtag; | ||
| 337 | d[H] = byte v; | ||
| 338 | d[H+1] = byte (v>>8); | ||
| 339 | Attach => | ||
| 340 | p32(d, H, m.fid); | ||
| 341 | p32(d, H+FID, m.afid); | ||
| 342 | o := pstring(d, H+2*FID, m.uname); | ||
| 343 | pstring(d, o, m.aname); | ||
| 344 | Walk => | ||
| 345 | d[H] = byte m.fid; | ||
| 346 | d[H+1] = byte (m.fid>>8); | ||
| 347 | d[H+2] = byte (m.fid>>16); | ||
| 348 | d[H+3] = byte (m.fid>>24); | ||
| 349 | d[H+FID] = byte m.newfid; | ||
| 350 | d[H+FID+1] = byte (m.newfid>>8); | ||
| 351 | d[H+FID+2] = byte (m.newfid>>16); | ||
| 352 | d[H+FID+3] = byte (m.newfid>>24); | ||
| 353 | n := len m.names; | ||
| 354 | d[H+2*FID] = byte n; | ||
| 355 | d[H+2*FID+1] = byte (n>>8); | ||
| 356 | o := H+2*FID+LEN; | ||
| 357 | for(i := 0; i < n; i++) | ||
| 358 | o = pstring(d, o, m.names[i]); | ||
| 359 | Open => | ||
| 360 | p32(d, H, m.fid); | ||
| 361 | d[H+FID] = byte m.mode; | ||
| 362 | Create => | ||
| 363 | p32(d, H, m.fid); | ||
| 364 | o := pstring(d, H+FID, m.name); | ||
| 365 | p32(d, o, m.perm); | ||
| 366 | d[o+BIT32SZ] = byte m.mode; | ||
| 367 | Read => | ||
| 368 | p32(d, H, m.fid); | ||
| 369 | p64(d, H+FID, m.offset); | ||
| 370 | p32(d, H+FID+OFFSET, m.count); | ||
| 371 | Write => | ||
| 372 | p32(d, H, m.fid); | ||
| 373 | p64(d, H+FID, m.offset); | ||
| 374 | n := len m.data; | ||
| 375 | p32(d, H+FID+OFFSET, n); | ||
| 376 | d[H+FID+OFFSET+COUNT:] = m.data; | ||
| 377 | Clunk or Remove or Stat => | ||
| 378 | p32(d, H, m.fid); | ||
| 379 | Wstat => | ||
| 380 | p32(d, H, m.fid); | ||
| 381 | stat := packdir(m.stat); | ||
| 382 | n := len stat; | ||
| 383 | d[H+FID] = byte n; | ||
| 384 | d[H+FID+1] = byte (n>>8); | ||
| 385 | d[H+FID+LEN:] = stat; | ||
| 386 | * => | ||
| 387 | raise sys->sprint("assertion: Ninep->Tmsg.pack: bad tag: %d", tagof t); | ||
| 388 | } | ||
| 389 | return d; | ||
| 390 | } | ||
| 391 | |||
| 392 | Tmsg.unpack(f: array of byte): (int, ref Tmsg) | ||
| 393 | { | ||
| 394 | if(len f < H) | ||
| 395 | return (0, nil); | ||
| 396 | size := (int f[1] << 8) | int f[0]; | ||
| 397 | size |= ((int f[3] << 8) | int f[2]) << 16; | ||
| 398 | if(len f != size){ | ||
| 399 | if(len f < size) | ||
| 400 | return (0, nil); # need more data | ||
| 401 | f = f[0:size]; # trim to exact length | ||
| 402 | } | ||
| 403 | mtype := int f[4]; | ||
| 404 | if(mtype >= len hdrlen || (mtype&1) != 0 || size < hdrlen[mtype]) | ||
| 405 | return (-1, nil); | ||
| 406 | |||
| 407 | tag := (int f[6] << 8) | int f[5]; | ||
| 408 | fid := 0; | ||
| 409 | if(hdrlen[mtype] >= H+FID) | ||
| 410 | fid = g32(f, H); # fid is always in same place: extract it once for all if there | ||
| 411 | |||
| 412 | # return out of each case body for a legal message; | ||
| 413 | # break out of the case for an illegal one | ||
| 414 | |||
| 415 | Decode: | ||
| 416 | case mtype { | ||
| 417 | * => | ||
| 418 | sys->print("styx: Tmsg.unpack: bad type %d\n", mtype); | ||
| 419 | Tversion => | ||
| 420 | msize := fid; | ||
| 421 | (version, o) := gstring(f, H+COUNT); | ||
| 422 | if(o <= 0) | ||
| 423 | break; | ||
| 424 | return (o, ref Tmsg.Version(tag, msize, version)); | ||
| 425 | Tauth => | ||
| 426 | (uname, o1) := gstring(f, H+FID); | ||
| 427 | (aname, o2) := gstring(f, o1); | ||
| 428 | if(o2 <= 0) | ||
| 429 | break; | ||
| 430 | return (o2, ref Tmsg.Auth(tag, fid, uname, aname)); | ||
| 431 | Tflush => | ||
| 432 | oldtag := (int f[H+1] << 8) | int f[H]; | ||
| 433 | return (H+TAG, ref Tmsg.Flush(tag, oldtag)); | ||
| 434 | Tattach => | ||
| 435 | afid := g32(f, H+FID); | ||
| 436 | (uname, o1) := gstring(f, H+2*FID); | ||
| 437 | (aname, o2) := gstring(f, o1); | ||
| 438 | if(o2 <= 0) | ||
| 439 | break; | ||
| 440 | return (o2, ref Tmsg.Attach(tag, fid, afid, uname, aname)); | ||
| 441 | Twalk => | ||
| 442 | newfid := g32(f, H+FID); | ||
| 443 | n := (int f[H+2*FID+1] << 8) | int f[H+2*FID]; | ||
| 444 | if(n > MAXWELEM) | ||
| 445 | break; | ||
| 446 | o := H+2*FID+LEN; | ||
| 447 | names: array of string = nil; | ||
| 448 | if(n > 0){ | ||
| 449 | names = array[n] of string; | ||
| 450 | for(i:=0; i<n; i++){ | ||
| 451 | (names[i], o) = gstring(f, o); | ||
| 452 | if(o <= 0) | ||
| 453 | break Decode; | ||
| 454 | } | ||
| 455 | } | ||
| 456 | return (o, ref Tmsg.Walk(tag, fid, newfid, names)); | ||
| 457 | Topen => | ||
| 458 | return (H+FID+BIT8SZ, ref Tmsg.Open(tag, fid, int f[H+FID])); | ||
| 459 | Tcreate => | ||
| 460 | (name, o) := gstring(f, H+FID); | ||
| 461 | if(o <= 0 || o+BIT32SZ+BIT8SZ > len f) | ||
| 462 | break; | ||
| 463 | perm := g32(f, o); | ||
| 464 | o += BIT32SZ; | ||
| 465 | mode := int f[o++]; | ||
| 466 | return (o, ref Tmsg.Create(tag, fid, name, perm, mode)); | ||
| 467 | Tread => | ||
| 468 | offset := g64(f, H+FID); | ||
| 469 | count := g32(f, H+FID+OFFSET); | ||
| 470 | return (H+FID+OFFSET+COUNT, ref Tmsg.Read(tag, fid, offset, count)); | ||
| 471 | Twrite => | ||
| 472 | offset := g64(f, H+FID); | ||
| 473 | count := g32(f, H+FID+OFFSET); | ||
| 474 | O: con H+FID+OFFSET+COUNT; | ||
| 475 | if(count > len f-O) | ||
| 476 | break; | ||
| 477 | data := f[O:O+count]; | ||
| 478 | return (O+count, ref Tmsg.Write(tag, fid, offset, data)); | ||
| 479 | Tclunk => | ||
| 480 | return (H+FID, ref Tmsg.Clunk(tag, fid)); | ||
| 481 | Tremove => | ||
| 482 | return (H+FID, ref Tmsg.Remove(tag, fid)); | ||
| 483 | Tstat => | ||
| 484 | return (H+FID, ref Tmsg.Stat(tag, fid)); | ||
| 485 | Twstat => | ||
| 486 | n := int (f[H+FID+1]<<8) | int f[H+FID]; | ||
| 487 | if(len f < H+FID+LEN+n) | ||
| 488 | break; | ||
| 489 | (ds, stat) := unpackdir(f[H+FID+LEN:]); | ||
| 490 | if(ds != n){ | ||
| 491 | sys->print("Ninep->Tmsg.unpack: wstat count: %d/%d\n", ds, n); # temporary | ||
| 492 | break; | ||
| 493 | } | ||
| 494 | return (H+FID+LEN+n, ref Tmsg.Wstat(tag, fid, stat)); | ||
| 495 | } | ||
| 496 | return (-1, nil); # illegal | ||
| 497 | } | ||
| 498 | |||
| 499 | tmsgname := array[] of { | ||
| 500 | tagof Tmsg.Readerror => "Readerror", | ||
| 501 | tagof Tmsg.Version => "Version", | ||
| 502 | tagof Tmsg.Auth => "Auth", | ||
| 503 | tagof Tmsg.Attach => "Attach", | ||
| 504 | tagof Tmsg.Flush => "Flush", | ||
| 505 | tagof Tmsg.Walk => "Walk", | ||
| 506 | tagof Tmsg.Open => "Open", | ||
| 507 | tagof Tmsg.Create => "Create", | ||
| 508 | tagof Tmsg.Read => "Read", | ||
| 509 | tagof Tmsg.Write => "Write", | ||
| 510 | tagof Tmsg.Clunk => "Clunk", | ||
| 511 | tagof Tmsg.Stat => "Stat", | ||
| 512 | tagof Tmsg.Remove => "Remove", | ||
| 513 | tagof Tmsg.Wstat => "Wstat", | ||
| 514 | }; | ||
| 515 | |||
| 516 | Tmsg.text(t: self ref Tmsg): string | ||
| 517 | { | ||
| 518 | if(t == nil) | ||
| 519 | return "nil"; | ||
| 520 | s := sys->sprint("Tmsg.%s(%ud", tmsgname[tagof t], t.tag); | ||
| 521 | pick m:= t { | ||
| 522 | * => | ||
| 523 | return s + ",ILLEGAL)"; | ||
| 524 | Readerror => | ||
| 525 | return s + sys->sprint(",\"%s\")", m.error); | ||
| 526 | Version => | ||
| 527 | return s + sys->sprint(",%d,\"%s\")", m.msize, m.version); | ||
| 528 | Auth => | ||
| 529 | return s + sys->sprint(",%ud,\"%s\",\"%s\")", m.afid, m.uname, m.aname); | ||
| 530 | Flush => | ||
| 531 | return s + sys->sprint(",%ud)", m.oldtag); | ||
| 532 | Attach => | ||
| 533 | return s + sys->sprint(",%ud,%ud,\"%s\",\"%s\")", m.fid, m.afid, m.uname, m.aname); | ||
| 534 | Walk => | ||
| 535 | s += sys->sprint(",%ud,%ud", m.fid, m.newfid); | ||
| 536 | if(len m.names != 0){ | ||
| 537 | s += ",array[] of {"; | ||
| 538 | for(i := 0; i < len m.names; i++){ | ||
| 539 | c := ","; | ||
| 540 | if(i == 0) | ||
| 541 | c = ""; | ||
| 542 | s += sys->sprint("%s\"%s\"", c, m.names[i]); | ||
| 543 | } | ||
| 544 | s += "}"; | ||
| 545 | }else | ||
| 546 | s += ",nil"; | ||
| 547 | return s + ")"; | ||
| 548 | Open => | ||
| 549 | return s + sys->sprint(",%ud,%d)", m.fid, m.mode); | ||
| 550 | Create => | ||
| 551 | return s + sys->sprint(",%ud,\"%s\",8r%uo,%d)", m.fid, m.name, m.perm, m.mode); | ||
| 552 | Read => | ||
| 553 | return s + sys->sprint(",%ud,%bd,%ud)", m.fid, m.offset, m.count); | ||
| 554 | Write => | ||
| 555 | return s + sys->sprint(",%ud,%bd,array[%d] of byte)", m.fid, m.offset, len m.data); | ||
| 556 | Clunk or | ||
| 557 | Remove or | ||
| 558 | Stat => | ||
| 559 | return s + sys->sprint(",%ud)", m.fid); | ||
| 560 | Wstat => | ||
| 561 | return s + sys->sprint(",%ud,%s)", m.fid, dir2text(m.stat)); | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 565 | Tmsg.read(fd: ref Sys->FD, msglim: int): ref Tmsg | ||
| 566 | { | ||
| 567 | (msg, err) := readmsg(fd, msglim); | ||
| 568 | if(err != nil) | ||
| 569 | return ref Tmsg.Readerror(0, err); | ||
| 570 | if(msg == nil) | ||
| 571 | return nil; | ||
| 572 | (nil, m) := Tmsg.unpack(msg); | ||
| 573 | if(m == nil) | ||
| 574 | return ref Tmsg.Readerror(0, "bad 9P T-message format"); | ||
| 575 | return m; | ||
| 576 | } | ||
| 577 | |||
| 578 | rtag2type := array[] of { | ||
| 579 | tagof Rmsg.Version => Rversion, | ||
| 580 | tagof Rmsg.Auth => Rauth, | ||
| 581 | tagof Rmsg.Error => Rerror, | ||
| 582 | tagof Rmsg.Flush => Rflush, | ||
| 583 | tagof Rmsg.Attach => Rattach, | ||
| 584 | tagof Rmsg.Walk => Rwalk, | ||
| 585 | tagof Rmsg.Open => Ropen, | ||
| 586 | tagof Rmsg.Create => Rcreate, | ||
| 587 | tagof Rmsg.Read => Rread, | ||
| 588 | tagof Rmsg.Write => Rwrite, | ||
| 589 | tagof Rmsg.Clunk => Rclunk, | ||
| 590 | tagof Rmsg.Remove => Rremove, | ||
| 591 | tagof Rmsg.Stat => Rstat, | ||
| 592 | tagof Rmsg.Wstat => Rwstat, | ||
| 593 | }; | ||
| 594 | |||
| 595 | Rmsg.mtype(r: self ref Rmsg): int | ||
| 596 | { | ||
| 597 | return rtag2type[tagof r]; | ||
| 598 | } | ||
| 599 | |||
| 600 | Rmsg.packedsize(r: self ref Rmsg): int | ||
| 601 | { | ||
| 602 | mtype := rtag2type[tagof r]; | ||
| 603 | if(mtype <= 0) | ||
| 604 | return 0; | ||
| 605 | ml := hdrlen[mtype]; | ||
| 606 | pick m := r { | ||
| 607 | Version => | ||
| 608 | ml += utflen(m.version); | ||
| 609 | Error => | ||
| 610 | ml += utflen(m.ename); | ||
| 611 | Walk => | ||
| 612 | ml += QID*len m.qids; | ||
| 613 | Read => | ||
| 614 | ml += len m.data; | ||
| 615 | Stat => | ||
| 616 | ml += packdirsize(m.stat); | ||
| 617 | } | ||
| 618 | return ml; | ||
| 619 | } | ||
| 620 | |||
| 621 | Rmsg.pack(r: self ref Rmsg): array of byte | ||
| 622 | { | ||
| 623 | if(r == nil) | ||
| 624 | return nil; | ||
| 625 | ps := r.packedsize(); | ||
| 626 | if(ps <= 0) | ||
| 627 | return nil; | ||
| 628 | d := array[ps] of byte; | ||
| 629 | d[0] = byte ps; | ||
| 630 | d[1] = byte (ps>>8); | ||
| 631 | d[2] = byte (ps>>16); | ||
| 632 | d[3] = byte (ps>>24); | ||
| 633 | d[4] = byte rtag2type[tagof r]; | ||
| 634 | d[5] = byte r.tag; | ||
| 635 | d[6] = byte (r.tag >> 8); | ||
| 636 | pick m := r { | ||
| 637 | Version => | ||
| 638 | p32(d, H, m.msize); | ||
| 639 | pstring(d, H+BIT32SZ, m.version); | ||
| 640 | Auth => | ||
| 641 | pqid(d, H, m.aqid); | ||
| 642 | Flush or | ||
| 643 | Clunk or | ||
| 644 | Remove or | ||
| 645 | Wstat => | ||
| 646 | ; # nothing more required | ||
| 647 | Error => | ||
| 648 | pstring(d, H, m.ename); | ||
| 649 | Attach => | ||
| 650 | pqid(d, H, m.qid); | ||
| 651 | Walk => | ||
| 652 | n := len m.qids; | ||
| 653 | d[H] = byte n; | ||
| 654 | d[H+1] = byte (n>>8); | ||
| 655 | o := H+LEN; | ||
| 656 | for(i:=0; i<n; i++){ | ||
| 657 | pqid(d, o, m.qids[i]); | ||
| 658 | o += QID; | ||
| 659 | } | ||
| 660 | Create or | ||
| 661 | Open => | ||
| 662 | pqid(d, H, m.qid); | ||
| 663 | p32(d, H+QID, m.iounit); | ||
| 664 | Read => | ||
| 665 | v := len m.data; | ||
| 666 | d[H] = byte v; | ||
| 667 | d[H+1] = byte (v>>8); | ||
| 668 | d[H+2] = byte (v>>16); | ||
| 669 | d[H+3] = byte (v>>24); | ||
| 670 | d[H+4:] = m.data; | ||
| 671 | Write => | ||
| 672 | v := m.count; | ||
| 673 | d[H] = byte v; | ||
| 674 | d[H+1] = byte (v>>8); | ||
| 675 | d[H+2] = byte (v>>16); | ||
| 676 | d[H+3] = byte (v>>24); | ||
| 677 | Stat => | ||
| 678 | stat := packdir(m.stat); | ||
| 679 | v := len stat; | ||
| 680 | d[H] = byte v; | ||
| 681 | d[H+1] = byte (v>>8); | ||
| 682 | d[H+2:] = stat; # should avoid copy? | ||
| 683 | * => | ||
| 684 | raise sys->sprint("assertion: Ninep->Rmsg.pack: missed case: tag %d", tagof r); | ||
| 685 | } | ||
| 686 | return d; | ||
| 687 | } | ||
| 688 | |||
| 689 | Rmsg.unpack(f: array of byte): (int, ref Rmsg) | ||
| 690 | { | ||
| 691 | if(len f < H) | ||
| 692 | return (0, nil); | ||
| 693 | size := (int f[1] << 8) | int f[0]; | ||
| 694 | size |= ((int f[3] << 8) | int f[2]) << 16; # size includes itself | ||
| 695 | if(len f != size){ | ||
| 696 | if(len f < size) | ||
| 697 | return (0, nil); # need more data | ||
| 698 | f = f[0:size]; # trim to exact length | ||
| 699 | } | ||
| 700 | mtype := int f[4]; | ||
| 701 | if(mtype >= len hdrlen || (mtype&1) == 0 || size < hdrlen[mtype]) | ||
| 702 | return (-1, nil); | ||
| 703 | |||
| 704 | tag := (int f[6] << 8) | int f[5]; | ||
| 705 | |||
| 706 | # return out of each case body for a legal message; | ||
| 707 | # break out of the case for an illegal one | ||
| 708 | |||
| 709 | case mtype { | ||
| 710 | * => | ||
| 711 | sys->print("Ninep->Rmsg.unpack: bad type %d\n", mtype); # temporary | ||
| 712 | Rversion => | ||
| 713 | msize := g32(f, H); | ||
| 714 | (version, o) := gstring(f, H+BIT32SZ); | ||
| 715 | if(o <= 0) | ||
| 716 | break; | ||
| 717 | return (o, ref Rmsg.Version(tag, msize, version)); | ||
| 718 | Rauth => | ||
| 719 | return (H+QID, ref Rmsg.Auth(tag, gqid(f, H))); | ||
| 720 | Rflush => | ||
| 721 | return (H, ref Rmsg.Flush(tag)); | ||
| 722 | Rerror => | ||
| 723 | (ename, o) := gstring(f, H); | ||
| 724 | if(o <= 0) | ||
| 725 | break; | ||
| 726 | return (o, ref Rmsg.Error(tag, ename)); | ||
| 727 | Rclunk => | ||
| 728 | return (H, ref Rmsg.Clunk(tag)); | ||
| 729 | Rremove => | ||
| 730 | return (H, ref Rmsg.Remove(tag)); | ||
| 731 | Rwstat=> | ||
| 732 | return (H, ref Rmsg.Wstat(tag)); | ||
| 733 | Rattach => | ||
| 734 | return (H+QID, ref Rmsg.Attach(tag, gqid(f, H))); | ||
| 735 | Rwalk => | ||
| 736 | nqid := (int f[H+1] << 8) | int f[H]; | ||
| 737 | if(len f < H+LEN+nqid*QID) | ||
| 738 | break; | ||
| 739 | o := H+LEN; | ||
| 740 | qids := array[nqid] of Sys->Qid; | ||
| 741 | for(i:=0; i<nqid; i++){ | ||
| 742 | qids[i] = gqid(f, o); | ||
| 743 | o += QID; | ||
| 744 | } | ||
| 745 | return (o, ref Rmsg.Walk(tag, qids)); | ||
| 746 | Ropen => | ||
| 747 | return (H+QID+COUNT, ref Rmsg.Open(tag, gqid(f, H), g32(f, H+QID))); | ||
| 748 | Rcreate=> | ||
| 749 | return (H+QID+COUNT, ref Rmsg.Create(tag, gqid(f, H), g32(f, H+QID))); | ||
| 750 | Rread => | ||
| 751 | count := g32(f, H); | ||
| 752 | if(len f < H+COUNT+count) | ||
| 753 | break; | ||
| 754 | data := f[H+COUNT:H+COUNT+count]; | ||
| 755 | return (H+COUNT+count, ref Rmsg.Read(tag, data)); | ||
| 756 | Rwrite => | ||
| 757 | return (H+COUNT, ref Rmsg.Write(tag, g32(f, H))); | ||
| 758 | Rstat => | ||
| 759 | n := (int f[H+1] << 8) | int f[H]; | ||
| 760 | if(len f < H+LEN+n) | ||
| 761 | break; | ||
| 762 | (ds, d) := unpackdir(f[H+LEN:]); | ||
| 763 | if(ds <= 0) | ||
| 764 | break; | ||
| 765 | if(ds != n){ | ||
| 766 | sys->print("Ninep->Rmsg.unpack: stat count: %d/%d\n", ds, n); # temporary | ||
| 767 | break; | ||
| 768 | } | ||
| 769 | return (H+LEN+n, ref Rmsg.Stat(tag, d)); | ||
| 770 | } | ||
| 771 | return (-1, nil); # illegal | ||
| 772 | } | ||
| 773 | |||
| 774 | rmsgname := array[] of { | ||
| 775 | tagof Rmsg.Version => "Version", | ||
| 776 | tagof Rmsg.Auth => "Auth", | ||
| 777 | tagof Rmsg.Attach => "Attach", | ||
| 778 | tagof Rmsg.Error => "Error", | ||
| 779 | tagof Rmsg.Flush => "Flush", | ||
| 780 | tagof Rmsg.Walk => "Walk", | ||
| 781 | tagof Rmsg.Create => "Create", | ||
| 782 | tagof Rmsg.Open => "Open", | ||
| 783 | tagof Rmsg.Read => "Read", | ||
| 784 | tagof Rmsg.Write => "Write", | ||
| 785 | tagof Rmsg.Clunk => "Clunk", | ||
| 786 | tagof Rmsg.Remove => "Remove", | ||
| 787 | tagof Rmsg.Stat => "Stat", | ||
| 788 | tagof Rmsg.Wstat => "Wstat", | ||
| 789 | }; | ||
| 790 | |||
| 791 | Rmsg.text(r: self ref Rmsg): string | ||
| 792 | { | ||
| 793 | if(sys == nil) | ||
| 794 | sys = load Sys Sys->PATH; | ||
| 795 | if(r == nil) | ||
| 796 | return "nil"; | ||
| 797 | s := sys->sprint("Rmsg.%s(%ud", rmsgname[tagof r], r.tag); | ||
| 798 | pick m := r { | ||
| 799 | * => | ||
| 800 | return s + "ERROR)"; | ||
| 801 | Readerror => | ||
| 802 | return s + sys->sprint(",\"%s\")", m.error); | ||
| 803 | Version => | ||
| 804 | return s + sys->sprint(",%d,\"%s\")", m.msize, m.version); | ||
| 805 | Auth => | ||
| 806 | return s+sys->sprint(",%s)", qid2text(m.aqid)); | ||
| 807 | Error => | ||
| 808 | return s+sys->sprint(",\"%s\")", m.ename); | ||
| 809 | Flush or | ||
| 810 | Clunk or | ||
| 811 | Remove or | ||
| 812 | Wstat => | ||
| 813 | return s+")"; | ||
| 814 | Attach => | ||
| 815 | return s+sys->sprint(",%s)", qid2text(m.qid)); | ||
| 816 | Walk => | ||
| 817 | s += ",array[] of {"; | ||
| 818 | for(i := 0; i < len m.qids; i++){ | ||
| 819 | c := ""; | ||
| 820 | if(i != 0) | ||
| 821 | c = ","; | ||
| 822 | s += sys->sprint("%s%s", c, qid2text(m.qids[i])); | ||
| 823 | } | ||
| 824 | return s+"})"; | ||
| 825 | Create or | ||
| 826 | Open => | ||
| 827 | return s+sys->sprint(",%s,%d)", qid2text(m.qid), m.iounit); | ||
| 828 | Read => | ||
| 829 | return s+sys->sprint(",array[%d] of byte)", len m.data); | ||
| 830 | Write => | ||
| 831 | return s+sys->sprint(",%d)", m.count); | ||
| 832 | Stat => | ||
| 833 | return s+sys->sprint(",%s)", dir2text(m.stat)); | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | Rmsg.read(fd: ref Sys->FD, msglim: int): ref Rmsg | ||
| 838 | { | ||
| 839 | (msg, err) := readmsg(fd, msglim); | ||
| 840 | if(err != nil) | ||
| 841 | return ref Rmsg.Readerror(0, err); | ||
| 842 | if(msg == nil) | ||
| 843 | return nil; | ||
| 844 | (nil, m) := Rmsg.unpack(msg); | ||
| 845 | if(m == nil) | ||
| 846 | return ref Rmsg.Readerror(0, "bad 9P R-message format"); | ||
| 847 | return m; | ||
| 848 | } | ||
| 849 | |||
| 850 | dir2text(d: Sys->Dir): string | ||
| 851 | { | ||
| 852 | return sys->sprint("Dir(\"%s\",\"%s\",\"%s\",%s,8r%uo,%d,%d,%bd,16r%ux,%d)", | ||
| 853 | d.name, d.uid, d.gid, qid2text(d.qid), d.mode, d.atime, d.mtime, d.length, d.dtype, d.dev); | ||
| 854 | } | ||
| 855 | |||
| 856 | qid2text(q: Sys->Qid): string | ||
| 857 | { | ||
| 858 | return sys->sprint("Qid(16r%ubx,%d,16r%.2ux)", q.path, q.vers, q.qtype); | ||
| 859 | } | ||
| 860 | |||
| 861 | readmsg(fd: ref Sys->FD, msglim: int): (array of byte, string) | ||
| 862 | { | ||
| 863 | if(msglim <= 0) | ||
| 864 | msglim = DEFMSIZE; | ||
| 865 | sbuf := array[BIT32SZ] of byte; | ||
| 866 | if((n := sys->readn(fd, sbuf, BIT32SZ)) != BIT32SZ){ | ||
| 867 | if(n == 0) | ||
| 868 | return (nil, nil); | ||
| 869 | return (nil, sys->sprint("%r")); | ||
| 870 | } | ||
| 871 | ml := (int sbuf[1] << 8) | int sbuf[0]; | ||
| 872 | ml |= ((int sbuf[3] << 8) | int sbuf[2]) << 16; | ||
| 873 | if(ml <= BIT32SZ) | ||
| 874 | return (nil, "invalid 9P message size"); | ||
| 875 | if(ml > msglim) | ||
| 876 | return (nil, "9P message longer than agreed"); | ||
| 877 | buf := array[ml] of byte; | ||
| 878 | buf[0:] = sbuf; | ||
| 879 | if((n = sys->readn(fd, buf[BIT32SZ:], ml-BIT32SZ)) != ml-BIT32SZ){ | ||
| 880 | if(n == 0) | ||
| 881 | return (nil, "9P message truncated"); | ||
| 882 | return (nil, sys->sprint("%r")); | ||
| 883 | } | ||
| 884 | return (buf, nil); | ||
| 885 | } | ||
| 886 | |||
| 887 | istmsg(f: array of byte): int | ||
| 888 | { | ||
| 889 | if(len f < H) | ||
| 890 | return -1; | ||
| 891 | return (int f[BIT32SZ] & 1) == 0; | ||
| 892 | } | ||
| 893 | |||
| 894 | compatible(t: ref Tmsg.Version, msize: int, version: string): (int, string) | ||
| 895 | { | ||
| 896 | if(version == nil) | ||
| 897 | version = VERSION; | ||
| 898 | if(t.msize < msize) | ||
| 899 | msize = t.msize; | ||
| 900 | v := t.version; | ||
| 901 | if(len v < 2 || v[0:2] != "9P") | ||
| 902 | return (msize, "unknown"); | ||
| 903 | for(i:=2; i<len v; i++) | ||
| 904 | if((c := v[i]) == '.'){ | ||
| 905 | v = v[0:i]; | ||
| 906 | break; | ||
| 907 | }else if(!(c >= '0' && c <= '9')) | ||
| 908 | return (msize, "unknown"); # fussier than Plan 9 | ||
| 909 | if(v < VERSION) | ||
| 910 | return (msize, "unknown"); | ||
| 911 | if(v < version) | ||
| 912 | version = v; | ||
| 913 | return (msize, version); | ||
| 914 | } | ||
| @@ -571,7 +571,7 @@ Tmsg.read(fd: ref Sys->FD, msglim: int): ref Tmsg · 570 unmodified lines | |||
| 571 | return nil; | 571 | return nil; |
| 572 | (nil, m) := Tmsg.unpack(msg); | 572 | (nil, m) := Tmsg.unpack(msg); |
| 573 | if(m == nil) | 573 | if(m == nil) |
| 574 | return ref Tmsg.Readerror(0, "bad Styx T-message format"); | 574 | return ref Tmsg.Readerror(0, "bad 9P T-message format"); |
| 575 | return m; | 575 | return m; |
| 576 | } | 576 | } |
| 577 | 577 | ||
| @@ -843,7 +843,7 @@ Rmsg.read(fd: ref Sys->FD, msglim: int): ref Rmsg · 265 unmodified lines | |||
| 843 | return nil; | 843 | return nil; |
| 844 | (nil, m) := Rmsg.unpack(msg); | 844 | (nil, m) := Rmsg.unpack(msg); |
| 845 | if(m == nil) | 845 | if(m == nil) |
| 846 | return ref Rmsg.Readerror(0, "bad Styx R-message format"); | 846 | return ref Rmsg.Readerror(0, "bad 9P R-message format"); |
| 847 | return m; | 847 | return m; |
| 848 | } | 848 | } |
| 849 | 849 | ||
| @@ -863,7 +863,7 @@ readmsg(fd: ref Sys->FD, msglim: int): (array of byte, string) · 13 unmodified lines | |||
| 863 | if(msglim <= 0) | 863 | if(msglim <= 0) |
| 864 | msglim = MAXRPC; | 864 | msglim = MAXRPC; |
| 865 | sbuf := array[BIT32SZ] of byte; | 865 | sbuf := array[BIT32SZ] of byte; |
| 866 | if((n := readn(fd, sbuf, BIT32SZ)) != BIT32SZ){ | 866 | if((n := sys->readn(fd, sbuf, BIT32SZ)) != BIT32SZ){ |
| 867 | if(n == 0) | 867 | if(n == 0) |
| 868 | return (nil, nil); | 868 | return (nil, nil); |
| 869 | return (nil, sys->sprint("%r")); | 869 | return (nil, sys->sprint("%r")); |
| @@ -871,33 +871,19 @@ readmsg(fd: ref Sys->FD, msglim: int): (array of byte, string) · 1 unmodified line | |||
| 871 | ml := (int sbuf[1] << 8) | int sbuf[0]; | 871 | ml := (int sbuf[1] << 8) | int sbuf[0]; |
| 872 | ml |= ((int sbuf[3] << 8) | int sbuf[2]) << 16; | 872 | ml |= ((int sbuf[3] << 8) | int sbuf[2]) << 16; |
| 873 | if(ml <= BIT32SZ) | 873 | if(ml <= BIT32SZ) |
| 874 | return (nil, "invalid Styx message size"); | 874 | return (nil, "invalid 9P message size"); |
| 875 | if(ml > msglim) | 875 | if(ml > msglim) |
| 876 | return (nil, "Styx message longer than agreed"); | 876 | return (nil, "9P message longer than agreed"); |
| 877 | buf := array[ml] of byte; | 877 | buf := array[ml] of byte; |
| 878 | buf[0:] = sbuf; | 878 | buf[0:] = sbuf; |
| 879 | if((n = readn(fd, buf[BIT32SZ:], ml-BIT32SZ)) != ml-BIT32SZ){ | 879 | if((n = sys->readn(fd, buf[BIT32SZ:], ml-BIT32SZ)) != ml-BIT32SZ){ |
| 880 | if(n == 0) | 880 | if(n == 0) |
| 881 | return (nil, "Styx message truncated"); | 881 | return (nil, "9P message truncated"); |
| 882 | return (nil, sys->sprint("%r")); | 882 | return (nil, sys->sprint("%r")); |
| 883 | } | 883 | } |
| 884 | return (buf, nil); | 884 | return (buf, nil); |
| 885 | } | 885 | } |
| 886 | 886 | ||
| 887 | readn(fd: ref Sys->FD, buf: array of byte, nb: int): int | ||
| 888 | { | ||
| 889 | for(nr := 0; nr < nb;){ | ||
| 890 | n := sys->read(fd, buf[nr:], nb-nr); | ||
| 891 | if(n <= 0){ | ||
| 892 | if(nr == 0) | ||
| 893 | return n; | ||
| 894 | break; | ||
| 895 | } | ||
| 896 | nr += n; | ||
| 897 | } | ||
| 898 | return nr; | ||
| 899 | } | ||
| 900 | |||
| 901 | istmsg(f: array of byte): int | 887 | istmsg(f: array of byte): int |
| 902 | { | 888 | { |
| 903 | if(len f < H) | 889 | if(len f < H) |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -1 +1 @@ | |||
| 1 | #define VERSION "Fourth Edition (20100213)" | 1 | #define VERSION "Fourth Edition (20100221)" |
| @@ -0,0 +1,416 @@ | |||
| 1 | .TH 9P-NINEP 2 | ||
| 2 | .SH NAME | ||
| 3 | Ninep: Rmsg, Tmsg, dir2text, istmsg, packdir, packdirsize, readmsg, qid2text, unpackdir \- interface to 9P file protocol | ||
| 4 | .SH SYNOPSIS | ||
| 5 | .EX | ||
| 6 | include "9p.m"; | ||
| 7 | ninep := load Ninep Ninep->PATH; | ||
| 8 | |||
| 9 | Tmsg: adt { | ||
| 10 | tag: int; | ||
| 11 | pick { | ||
| 12 | Readerror => | ||
| 13 | error: string; # tag is unused in this case | ||
| 14 | Version => | ||
| 15 | msize: int; | ||
| 16 | version: string; | ||
| 17 | Auth => | ||
| 18 | afid: int; | ||
| 19 | uname, aname: string; | ||
| 20 | Attach => | ||
| 21 | fid, afid: int; | ||
| 22 | uname, aname: string; | ||
| 23 | Flush => | ||
| 24 | oldtag: int; | ||
| 25 | Walk => | ||
| 26 | fid, newfid: int; | ||
| 27 | names: array of string; | ||
| 28 | Open => | ||
| 29 | fid, mode: int; | ||
| 30 | Create => | ||
| 31 | fid: int; | ||
| 32 | name: string; | ||
| 33 | perm, mode: int; | ||
| 34 | Read => | ||
| 35 | fid: int; | ||
| 36 | offset: big; | ||
| 37 | count: int; | ||
| 38 | Write => | ||
| 39 | fid: int; | ||
| 40 | offset: big; | ||
| 41 | data: array of byte; | ||
| 42 | Clunk or | ||
| 43 | Stat or | ||
| 44 | Remove => | ||
| 45 | fid: int; | ||
| 46 | Wstat => | ||
| 47 | fid: int; | ||
| 48 | stat: Sys->Dir; | ||
| 49 | } | ||
| 50 | |||
| 51 | read: fn(fd: ref Sys->FD, msize: int): ref Tmsg; | ||
| 52 | unpack: fn(a: array of byte): (int, ref Tmsg); | ||
| 53 | pack: fn(nil: self ref Tmsg): array of byte; | ||
| 54 | packedsize: fn(nil: self ref Tmsg): int; | ||
| 55 | text: fn(nil: self ref Tmsg): string; | ||
| 56 | mtype: fn(nil: self ref Tmsg): int; | ||
| 57 | }; | ||
| 58 | |||
| 59 | Rmsg: adt { | ||
| 60 | tag: int; | ||
| 61 | pick { | ||
| 62 | Readerror => | ||
| 63 | error: string; # tag is unused in this case | ||
| 64 | Version => | ||
| 65 | msize: int; | ||
| 66 | version: string; | ||
| 67 | Auth => | ||
| 68 | aqid: Sys->Qid; | ||
| 69 | Attach => | ||
| 70 | qid: Sys->Qid; | ||
| 71 | Flush => | ||
| 72 | Error => | ||
| 73 | ename: string; | ||
| 74 | Clunk or | ||
| 75 | Remove or | ||
| 76 | Wstat => | ||
| 77 | Walk => | ||
| 78 | qids: array of Sys->Qid; | ||
| 79 | Create or | ||
| 80 | Open => | ||
| 81 | qid: Sys->Qid; | ||
| 82 | iounit: int; | ||
| 83 | Read => | ||
| 84 | data: array of byte; | ||
| 85 | Write => | ||
| 86 | count: int; | ||
| 87 | Stat => | ||
| 88 | stat: Sys->Dir; | ||
| 89 | } | ||
| 90 | |||
| 91 | read: fn(fd: ref Sys->FD, msize: int): ref Rmsg; | ||
| 92 | unpack: fn(a: array of byte): (int, ref Rmsg); | ||
| 93 | pack: fn(nil: self ref Rmsg): array of byte; | ||
| 94 | packedsize: fn(nil: self ref Rmsg): int; | ||
| 95 | text: fn(nil: self ref Rmsg): string; | ||
| 96 | mtype: fn(nil: self ref Rmsg): int; | ||
| 97 | }; | ||
| 98 | |||
| 99 | init: fn(); | ||
| 100 | |||
| 101 | readmsg: fn(fd: ref Sys->FD, msize: int): (array of byte, string); | ||
| 102 | istmsg: fn(f: array of byte): int; | ||
| 103 | |||
| 104 | compatible: fn(t: ref Tmsg.Version, msize: int, version: string): (int, string); | ||
| 105 | |||
| 106 | packdirsize: fn(d: Sys->Dir): int; | ||
| 107 | packdir: fn(d: Sys->Dir): array of byte; | ||
| 108 | unpackdir: fn(f: array of byte): (int, Sys->Dir); | ||
| 109 | dir2text: fn(d: Sys->Dir): string; | ||
| 110 | qid2text: fn(q: Sys->Qid): string; | ||
| 111 | |||
| 112 | VERSION: con "9P2000"; | ||
| 113 | MAXWELEM: con 16; | ||
| 114 | NOTAG: con 16rFFFF; | ||
| 115 | NOFID: con ~0; | ||
| 116 | IOHDRSZ: con \fIimplementation-defined\f5; | ||
| 117 | DEFMSIZE: con \fIimplementation-defined\f5; | ||
| 118 | .EE | ||
| 119 | .SH DESCRIPTION | ||
| 120 | .B Ninep | ||
| 121 | provides a Limbo interface to send and receive messages of the 9P file service protocol, | ||
| 122 | described by Section 5 of this manual, a thorough reading of which | ||
| 123 | is advised before using this module. | ||
| 124 | .B Init | ||
| 125 | must be called before using any other function in the module. | ||
| 126 | .PP | ||
| 127 | A 9P client transmits requests to a server as `T-messages' | ||
| 128 | and receives replies in matching `R-messages'. | ||
| 129 | A T-message is here represented by values of the type | ||
| 130 | .BR Tmsg , | ||
| 131 | and an R-message by values of type | ||
| 132 | .BR Rmsg . | ||
| 133 | Every message has a | ||
| 134 | .B tag | ||
| 135 | value, and the alternatives of the pick adt represent the possible operation types of a T-message, | ||
| 136 | generally with parameter names and types corresponding to those described in section 5. | ||
| 137 | The exceptions are: | ||
| 138 | .B Tmsg.Write | ||
| 139 | and | ||
| 140 | .B Rmsg.Read | ||
| 141 | contain an array of byte, | ||
| 142 | .BR data , | ||
| 143 | to hold the data for the corresponding message, and the `count' parameter of the message is simply the length of that array; | ||
| 144 | and there is an alternative labelled | ||
| 145 | .B Readerror | ||
| 146 | that does not appear in the protocol but is used to represent input errors as described below. | ||
| 147 | Also note that values that are `unsigned' integers in the protocol are typically given signed integer | ||
| 148 | types in the Limbo representation (in particular, fids, qid paths, counts and offsets), and applications | ||
| 149 | should take appropriate care when manipulating them. | ||
| 150 | .PP | ||
| 151 | The following functions are provided by | ||
| 152 | .BR Tmsg: | ||
| 153 | .TP | ||
| 154 | .BI read( fd\fP,\fP\ msize ) | ||
| 155 | Read file descriptor | ||
| 156 | .I fd | ||
| 157 | to obtain exactly one T-message and return (a reference to) the corresponding | ||
| 158 | .BR Tmsg . | ||
| 159 | A nil value is returned on end of file. | ||
| 160 | Otherwise, if the read fails or the data read does not form a valid T-message, | ||
| 161 | the value returned will be a | ||
| 162 | .B Tmsg.Readerror | ||
| 163 | value in which the | ||
| 164 | .B error | ||
| 165 | member describes the error. | ||
| 166 | .I Msize | ||
| 167 | gives the maximum number of bytes in any acceptable T-message, | ||
| 168 | and should be the value negotiated in the exchange of | ||
| 169 | .B version | ||
| 170 | messages; | ||
| 171 | any incoming message larger than that will result in a diagnostic as a | ||
| 172 | .B Tmsg.Readerror | ||
| 173 | value. | ||
| 174 | An | ||
| 175 | .I msize | ||
| 176 | of 0 means `no limit negotiated' and should (only) be used until a message size | ||
| 177 | has been negotiated by exchange of | ||
| 178 | .IR version (5) | ||
| 179 | messages. | ||
| 180 | .TP | ||
| 181 | .IB t .pack() | ||
| 182 | Return an array of bytes containing the value of | ||
| 183 | .I t | ||
| 184 | in the machine-independent format described in Section 5. | ||
| 185 | It can return nil only if the message | ||
| 186 | .I t | ||
| 187 | is itself nil or has an invalid type. | ||
| 188 | .TP | ||
| 189 | .BI unpack( a ) | ||
| 190 | The array | ||
| 191 | .I a | ||
| 192 | is assumed to contain zero or more T-messages. | ||
| 193 | .B Unpack | ||
| 194 | attempts to unpack the first message, and returns a tuple of the form | ||
| 195 | .RI ( n , v ). | ||
| 196 | If successful, | ||
| 197 | .I n | ||
| 198 | is the number of bytes at the start of | ||
| 199 | .I a | ||
| 200 | used by the message, and | ||
| 201 | .I v | ||
| 202 | is the corresponding | ||
| 203 | .B Tmsg | ||
| 204 | value. | ||
| 205 | If | ||
| 206 | .I a | ||
| 207 | contains the prefix of a valid message but more data is required to complete it, | ||
| 208 | .I n | ||
| 209 | is zero (and | ||
| 210 | .I v | ||
| 211 | is nil); the caller will typically read more data, append it to | ||
| 212 | .IR a , | ||
| 213 | and try again. | ||
| 214 | If the message is invalid, | ||
| 215 | .I n | ||
| 216 | is -1 | ||
| 217 | and | ||
| 218 | .I v | ||
| 219 | is nil. | ||
| 220 | .TP | ||
| 221 | .IB t .packedsize() | ||
| 222 | Return the number of bytes required for the value of | ||
| 223 | .I t | ||
| 224 | when packed in its machine-independent format. | ||
| 225 | (Zero is returned if | ||
| 226 | .I t | ||
| 227 | is invalid.) | ||
| 228 | .TP | ||
| 229 | .IB t .text() | ||
| 230 | Return a printable string showing the contents of | ||
| 231 | .IR t , | ||
| 232 | for tracing or debugging. | ||
| 233 | .TP | ||
| 234 | .IB t .mtype() | ||
| 235 | Return the 9P message type of the message. | ||
| 236 | .PP | ||
| 237 | An R-message is represented by | ||
| 238 | .BR Rmsg . | ||
| 239 | Its member functions behave exactly as those for | ||
| 240 | .BR Tmsg , | ||
| 241 | except that they operate on R-messages not T-messages. | ||
| 242 | .PP | ||
| 243 | When a client reads a directory, the data returned in the reply must be formatted | ||
| 244 | as described in | ||
| 245 | .IR read (5): | ||
| 246 | an array of directory entries, one per file, with each entry formatted in | ||
| 247 | a machine-independent format. | ||
| 248 | An appropriate array value can be produced by | ||
| 249 | .B packdir | ||
| 250 | from a | ||
| 251 | .B Sys->Dir | ||
| 252 | structure, as used by | ||
| 253 | .IR sys-stat (2). | ||
| 254 | The space that packed representation will take can be calculated beforehand by | ||
| 255 | .BR packdirsize . | ||
| 256 | The server will usually fill the buffer for the reply to the read | ||
| 257 | with as many entries as will fit, | ||
| 258 | checking the space remaining against the result of | ||
| 259 | .B packdirsize | ||
| 260 | and if the value will fit, storing the result of | ||
| 261 | .BR packdir . | ||
| 262 | Given an array | ||
| 263 | .I a | ||
| 264 | containing at most one packed directory value (as produced by | ||
| 265 | .BR packdir ), | ||
| 266 | .B unpackdir | ||
| 267 | returns a tuple | ||
| 268 | .RI ( n,\ d ) | ||
| 269 | where | ||
| 270 | .I n | ||
| 271 | is \-1 if | ||
| 272 | .I a | ||
| 273 | is illegally formatted; | ||
| 274 | .I n | ||
| 275 | is zero if | ||
| 276 | .I a | ||
| 277 | does not contain a complete directory entry value; | ||
| 278 | and otherwise | ||
| 279 | .I n | ||
| 280 | is the number of bytes of | ||
| 281 | .I a | ||
| 282 | used to produce the unpacked | ||
| 283 | .B Dir | ||
| 284 | value | ||
| 285 | .I d . | ||
| 286 | .PP | ||
| 287 | The functions | ||
| 288 | .B dir2text | ||
| 289 | and | ||
| 290 | .B qid2text | ||
| 291 | produce printable strings showing the contents of the corresponding data structures, | ||
| 292 | for use when tracing or debugging. | ||
| 293 | .PP | ||
| 294 | Applications that acts as file servers will read T-messages and | ||
| 295 | reply with R-messages. | ||
| 296 | They can use | ||
| 297 | .B Tmsg.read | ||
| 298 | to read each T-message, build an | ||
| 299 | .B Rmsg | ||
| 300 | reply value | ||
| 301 | .IR r , | ||
| 302 | and use | ||
| 303 | .IB r .pack | ||
| 304 | to produce an array of bytes to be written in reply by | ||
| 305 | .B Sys->write | ||
| 306 | (see | ||
| 307 | .IR sys-read (2)). | ||
| 308 | .PP | ||
| 309 | A few specialised programs might need the lower-level function | ||
| 310 | .B readmsg | ||
| 311 | that underlies | ||
| 312 | .B Tmsg.read | ||
| 313 | and | ||
| 314 | .BR Rmsg.read . | ||
| 315 | It reads a single message, which can be either a T-message or R-message, | ||
| 316 | and returns it as an array of bytes, | ||
| 317 | which can then be unpacked using | ||
| 318 | .B Tmsg.unpack | ||
| 319 | or | ||
| 320 | .BR Rmsg.unpack . | ||
| 321 | .I Msize | ||
| 322 | is the negotiated message size, or 0 meaning `no limit'. | ||
| 323 | The predicate | ||
| 324 | .B istmsg | ||
| 325 | returns true if the contents of array | ||
| 326 | .I f | ||
| 327 | looks like a packed representation of a T-message, | ||
| 328 | judging only by its | ||
| 329 | .I type | ||
| 330 | byte. | ||
| 331 | .PP | ||
| 332 | When generating the | ||
| 333 | .B version | ||
| 334 | message (see | ||
| 335 | .IR version (5)), | ||
| 336 | the constant | ||
| 337 | .B NOTAG | ||
| 338 | can be used in | ||
| 339 | .B Tmsg.tag | ||
| 340 | and | ||
| 341 | .B Rmsg.tag | ||
| 342 | to represent `no tag value'. | ||
| 343 | The constant | ||
| 344 | .B VERSION | ||
| 345 | names the current version of the protocol, and can be | ||
| 346 | used as the value of | ||
| 347 | .BR Tmsg.version . | ||
| 348 | .PP | ||
| 349 | .B Compatible | ||
| 350 | can be used by a server to | ||
| 351 | compare its | ||
| 352 | .I msize | ||
| 353 | and | ||
| 354 | .I version | ||
| 355 | (which is typically | ||
| 356 | .BR VERSION ) | ||
| 357 | to those in the | ||
| 358 | .B Tmsg.Version | ||
| 359 | message received from a client, to decide its reply, | ||
| 360 | following the rules in | ||
| 361 | .IR version (5). | ||
| 362 | It returns a tuple | ||
| 363 | .RI ( m ", " v ) | ||
| 364 | with values for use in the | ||
| 365 | .B Rmsg.Version | ||
| 366 | reply. | ||
| 367 | .I M | ||
| 368 | is the lesser of | ||
| 369 | .I msize | ||
| 370 | and | ||
| 371 | .IB t .msize , | ||
| 372 | and | ||
| 373 | .I v | ||
| 374 | is the negotiated protocol version, or the value \f5"unknown"\f1 | ||
| 375 | if no version could be agreed. | ||
| 376 | The constant | ||
| 377 | .B DEFMSIZE | ||
| 378 | is a reasonable value for | ||
| 379 | .I msize | ||
| 380 | on current systems. | ||
| 381 | The resulting value | ||
| 382 | .I m | ||
| 383 | can subsequently be given to the various read functions as the limit | ||
| 384 | .IR msize . | ||
| 385 | The constant | ||
| 386 | .B IOHDRSZ | ||
| 387 | gives the amount to allow for protocol overhead, when limiting data size for | ||
| 388 | .B Tmsg.Write | ||
| 389 | and | ||
| 390 | .BR Rmsg.Read . | ||
| 391 | .PP | ||
| 392 | The constant | ||
| 393 | .B NOFID | ||
| 394 | can be used as the value of | ||
| 395 | .B afid | ||
| 396 | of the | ||
| 397 | .B attach | ||
| 398 | message when authentication is not required (see | ||
| 399 | .IR attach (5)). | ||
| 400 | .PP | ||
| 401 | The constant | ||
| 402 | .B MAXWELEM | ||
| 403 | gives the protocol-defined limit on the length of the arrays | ||
| 404 | .B Tmsg.names | ||
| 405 | and | ||
| 406 | .BR Rmsg.qids . | ||
| 407 | For specialised applications, the module defines constants | ||
| 408 | .BR Tversion , | ||
| 409 | .BR Rversion , | ||
| 410 | etc. for the message types of the protocol, and the | ||
| 411 | other constants mentioned in Section 5. | ||
| 412 | .SH SOURCE | ||
| 413 | .B /appl/lib/ninep.b | ||
| 414 | .SH SEE ALSO | ||
| 415 | .IR styxservers (2), | ||
| 416 | .IR intro (5) | ||
| @@ -0,0 +1,178 @@ | |||
| 1 | Ninep: module | ||
| 2 | { | ||
| 3 | PATH: con "/dis/lib/ninep.dis"; | ||
| 4 | |||
| 5 | VERSION: con "9P2000"; | ||
| 6 | MAXWELEM: con 16; | ||
| 7 | |||
| 8 | NOTAG: con 16rFFFF; | ||
| 9 | NOFID: con int ~0; # 32 bits in this version of 9P | ||
| 10 | |||
| 11 | BIT8SZ: con 1; | ||
| 12 | BIT16SZ: con 2; | ||
| 13 | BIT32SZ: con 4; | ||
| 14 | BIT64SZ: con 8; | ||
| 15 | QIDSZ: con BIT8SZ+BIT32SZ+BIT64SZ; | ||
| 16 | |||
| 17 | STATFIXLEN: con BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+BIT64SZ; # amount of fixed length data in a stat buffer | ||
| 18 | IOHDRSZ: con 24; # room for Twrite/Rread header | ||
| 19 | DEFIOUNIT: con 8192; # `reasonable' iounit | ||
| 20 | DEFMSIZE: con IOHDRSZ+DEFIOUNIT; # usable default for fversion and iounit | ||
| 21 | |||
| 22 | Tversion, # 100 | ||
| 23 | Rversion, | ||
| 24 | Tauth, # 102 | ||
| 25 | Rauth, | ||
| 26 | Tattach, # 104 | ||
| 27 | Rattach, | ||
| 28 | Terror, # 106, illegal | ||
| 29 | Rerror, | ||
| 30 | Tflush, #108 | ||
| 31 | Rflush, | ||
| 32 | Twalk, # 110 | ||
| 33 | Rwalk, | ||
| 34 | Topen, # 112 | ||
| 35 | Ropen, | ||
| 36 | Tcreate, # 114 | ||
| 37 | Rcreate, | ||
| 38 | Tread, # 116 | ||
| 39 | Rread, | ||
| 40 | Twrite, # 118 | ||
| 41 | Rwrite, | ||
| 42 | Tclunk, # 120 | ||
| 43 | Rclunk, | ||
| 44 | Tremove, # 122 | ||
| 45 | Rremove, | ||
| 46 | Tstat, # 124 | ||
| 47 | Rstat, | ||
| 48 | Twstat, #126 | ||
| 49 | Rwstat, | ||
| 50 | Tmax: con 100+iota; | ||
| 51 | |||
| 52 | ERRMAX: con 128; | ||
| 53 | |||
| 54 | OREAD: con 0; # open for read | ||
| 55 | OWRITE: con 1; # write | ||
| 56 | ORDWR: con 2; # read and write | ||
| 57 | OEXEC: con 3; # execute, == read but check execute permission | ||
| 58 | OTRUNC: con 16; # or'ed in (except for exec), truncate file first | ||
| 59 | ORCLOSE: con 64; # or'ed in, remove on close | ||
| 60 | |||
| 61 | # mode bits in Dir.mode used by the protocol | ||
| 62 | DMDIR: con int 1<<31; # mode bit for directory | ||
| 63 | DMAPPEND: con int 1<<30; # mode bit for append-only files | ||
| 64 | DMEXCL: con int 1<<29; # mode bit for exclusive use files | ||
| 65 | DMAUTH: con int 1<<27; # mode bit for authentication files | ||
| 66 | |||
| 67 | # Qid.qtype | ||
| 68 | QTDIR: con 16r80; | ||
| 69 | QTAPPEND: con 16r40; | ||
| 70 | QTEXCL: con 16r20; | ||
| 71 | QTAUTH: con 16r08; | ||
| 72 | QTFILE: con 16r00; | ||
| 73 | |||
| 74 | Tmsg: adt { | ||
| 75 | tag: int; | ||
| 76 | pick { | ||
| 77 | Readerror => | ||
| 78 | error: string; # tag is unused in this case | ||
| 79 | Version => | ||
| 80 | msize: int; | ||
| 81 | version: string; | ||
| 82 | Auth => | ||
| 83 | afid: int; | ||
| 84 | uname, aname: string; | ||
| 85 | Attach => | ||
| 86 | fid, afid: int; | ||
| 87 | uname, aname: string; | ||
| 88 | Flush => | ||
| 89 | oldtag: int; | ||
| 90 | Walk => | ||
| 91 | fid, newfid: int; | ||
| 92 | names: array of string; | ||
| 93 | Open => | ||
| 94 | fid, mode: int; | ||
| 95 | Create => | ||
| 96 | fid: int; | ||
| 97 | name: string; | ||
| 98 | perm, mode: int; | ||
| 99 | Read => | ||
| 100 | fid: int; | ||
| 101 | offset: big; | ||
| 102 | count: int; | ||
| 103 | Write => | ||
| 104 | fid: int; | ||
| 105 | offset: big; | ||
| 106 | data: array of byte; | ||
| 107 | Clunk or | ||
| 108 | Stat or | ||
| 109 | Remove => | ||
| 110 | fid: int; | ||
| 111 | Wstat => | ||
| 112 | fid: int; | ||
| 113 | stat: Sys->Dir; | ||
| 114 | } | ||
| 115 | |||
| 116 | read: fn(fd: ref Sys->FD, msize: int): ref Tmsg; | ||
| 117 | unpack: fn(a: array of byte): (int, ref Tmsg); | ||
| 118 | pack: fn(nil: self ref Tmsg): array of byte; | ||
| 119 | packedsize: fn(nil: self ref Tmsg): int; | ||
| 120 | text: fn(nil: self ref Tmsg): string; | ||
| 121 | mtype: fn(nil: self ref Tmsg): int; | ||
| 122 | }; | ||
| 123 | |||
| 124 | Rmsg: adt { | ||
| 125 | tag: int; | ||
| 126 | pick { | ||
| 127 | Readerror => | ||
| 128 | error: string; # tag is unused in this case | ||
| 129 | Version => | ||
| 130 | msize: int; | ||
| 131 | version: string; | ||
| 132 | Auth => | ||
| 133 | aqid: Sys->Qid; | ||
| 134 | Attach => | ||
| 135 | qid: Sys->Qid; | ||
| 136 | Flush => | ||
| 137 | Error => | ||
| 138 | ename: string; | ||
| 139 | Clunk or | ||
| 140 | Remove or | ||
| 141 | Wstat => | ||
| 142 | Walk => | ||
| 143 | qids: array of Sys->Qid; | ||
| 144 | Create or | ||
| 145 | Open => | ||
| 146 | qid: Sys->Qid; | ||
| 147 | iounit: int; | ||
| 148 | Read => | ||
| 149 | data: array of byte; | ||
| 150 | Write => | ||
| 151 | count: int; | ||
| 152 | Stat => | ||
| 153 | stat: Sys->Dir; | ||
| 154 | } | ||
| 155 | |||
| 156 | read: fn(fd: ref Sys->FD, msize: int): ref Rmsg; | ||
| 157 | unpack: fn(a: array of byte): (int, ref Rmsg); | ||
| 158 | pack: fn(nil: self ref Rmsg): array of byte; | ||
| 159 | packedsize: fn(nil: self ref Rmsg): int; | ||
| 160 | text: fn(nil: self ref Rmsg): string; | ||
| 161 | mtype: fn(nil: self ref Rmsg): int; | ||
| 162 | }; | ||
| 163 | |||
| 164 | init: fn(); | ||
| 165 | |||
| 166 | readmsg: fn(fd: ref Sys->FD, msize: int): (array of byte, string); | ||
| 167 | istmsg: fn(f: array of byte): int; | ||
| 168 | |||
| 169 | compatible: fn(t: ref Tmsg.Version, msize: int, version: string): (int, string); | ||
| 170 | |||
| 171 | packdirsize: fn(d: Sys->Dir): int; | ||
| 172 | packdir: fn(d: Sys->Dir): array of byte; | ||
| 173 | unpackdir: fn(f: array of byte): (int, Sys->Dir); | ||
| 174 | dir2text: fn(d: Sys->Dir): string; | ||
| 175 | qid2text: fn(q: Sys->Qid): string; | ||
| 176 | |||
| 177 | utflen: fn(s: string): int; | ||
| 178 | }; | ||