History

20100221-1211

forsyth committed 16 years ago

Commit bea10701 parent 591b8a316 files · +1520 −25Browse files

Unified · Split

16 files
  1. CHANGES +2 −0
  2. appl/cmd/9660srv.b +1 −1
  3. appl/cmd/auth/keyfs.b +2 −2
  4. appl/cmd/dossrv.b +4 −5
  5. appl/cmd/ftpfs.b +1 −1
  6. appl/lib/ninep.b +914 −0
  7. appl/lib/styx.b +7 −21
  8. dis/9660srv.dis +0 −0
  9. dis/auth/keyfs.dis +0 −0
  10. dis/dossrv.dis +0 −0
  11. dis/ftpfs.dis +0 −0
  12. dis/lib/ninep.dis +0 −0
  13. dis/lib/styx.dis +0 −0
  14. include/version.h +1 −1
  15. man/2/9p-ninep +416 −0
  16. module/9p.m +178 −0
CHANGES+2−0
@@ -1,3 +1,5 @@
120100220
2 appl/cmd/keyfs.b wasn't clunking fids on error in remove [issue 225]
120100213320100213
2 apply saoret.one's changes for thumb [issue 155]4 apply saoret.one's changes for thumb [issue 155]
320100205520100205
appl/cmd/9660srv.b+1−1
@@ -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
appl/cmd/auth/keyfs.b+2−2
@@ -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 it438 srv.remove(m); # let it reject it
appl/cmd/dossrv.b+4−5
@@ -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
1395fileclust(f: ref Xfile, iclust: int, cflag: int): int1394fileclust(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 boundary1400 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
2067truncfile(f: ref Xfile): int2066truncfile(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
appl/cmd/ftpfs.b+1−1
@@ -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
appl/lib/ninep.b+914−0
@@ -0,0 +1,914 @@
1implement Ninep;
2
3include "sys.m";
4 sys: Sys;
5
6include "9p.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 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
83packdirsize(d: Sys->Dir): int
84{
85 return STATFIXLEN+utflen(d.name)+utflen(d.uid)+utflen(d.gid)+utflen(d.muid);
86}
87
88packdir(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
134pqid(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
155pstring(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
165p32(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
174p64(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
189unpackdir(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
228gqid(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
240g32(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
245g64(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
252gstring(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
264ttag2type := array[] of {
265tagof Tmsg.Readerror => 0,
266tagof Tmsg.Version => Tversion,
267tagof Tmsg.Auth => Tauth,
268tagof Tmsg.Attach => Tattach,
269tagof Tmsg.Flush => Tflush,
270tagof Tmsg.Walk => Twalk,
271tagof Tmsg.Open => Topen,
272tagof Tmsg.Create => Tcreate,
273tagof Tmsg.Read => Tread,
274tagof Tmsg.Write => Twrite,
275tagof Tmsg.Clunk => Tclunk,
276tagof Tmsg.Stat => Tstat,
277tagof Tmsg.Remove => Tremove,
278tagof Tmsg.Wstat => Twstat,
279};
280
281Tmsg.mtype(t: self ref Tmsg): int
282{
283 return ttag2type[tagof t];
284}
285
286Tmsg.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
312Tmsg.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
392Tmsg.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
415Decode:
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
499tmsgname := array[] of {
500tagof Tmsg.Readerror => "Readerror",
501tagof Tmsg.Version => "Version",
502tagof Tmsg.Auth => "Auth",
503tagof Tmsg.Attach => "Attach",
504tagof Tmsg.Flush => "Flush",
505tagof Tmsg.Walk => "Walk",
506tagof Tmsg.Open => "Open",
507tagof Tmsg.Create => "Create",
508tagof Tmsg.Read => "Read",
509tagof Tmsg.Write => "Write",
510tagof Tmsg.Clunk => "Clunk",
511tagof Tmsg.Stat => "Stat",
512tagof Tmsg.Remove => "Remove",
513tagof Tmsg.Wstat => "Wstat",
514};
515
516Tmsg.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
565Tmsg.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
578rtag2type := array[] of {
579tagof Rmsg.Version => Rversion,
580tagof Rmsg.Auth => Rauth,
581tagof Rmsg.Error => Rerror,
582tagof Rmsg.Flush => Rflush,
583tagof Rmsg.Attach => Rattach,
584tagof Rmsg.Walk => Rwalk,
585tagof Rmsg.Open => Ropen,
586tagof Rmsg.Create => Rcreate,
587tagof Rmsg.Read => Rread,
588tagof Rmsg.Write => Rwrite,
589tagof Rmsg.Clunk => Rclunk,
590tagof Rmsg.Remove => Rremove,
591tagof Rmsg.Stat => Rstat,
592tagof Rmsg.Wstat => Rwstat,
593};
594
595Rmsg.mtype(r: self ref Rmsg): int
596{
597 return rtag2type[tagof r];
598}
599
600Rmsg.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
621Rmsg.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
689Rmsg.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
774rmsgname := array[] of {
775tagof Rmsg.Version => "Version",
776tagof Rmsg.Auth => "Auth",
777tagof Rmsg.Attach => "Attach",
778tagof Rmsg.Error => "Error",
779tagof Rmsg.Flush => "Flush",
780tagof Rmsg.Walk => "Walk",
781tagof Rmsg.Create => "Create",
782tagof Rmsg.Open => "Open",
783tagof Rmsg.Read => "Read",
784tagof Rmsg.Write => "Write",
785tagof Rmsg.Clunk => "Clunk",
786tagof Rmsg.Remove => "Remove",
787tagof Rmsg.Stat => "Stat",
788tagof Rmsg.Wstat => "Wstat",
789};
790
791Rmsg.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
837Rmsg.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
850dir2text(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
856qid2text(q: Sys->Qid): string
857{
858 return sys->sprint("Qid(16r%ubx,%d,16r%.2ux)", q.path, q.vers, q.qtype);
859}
860
861readmsg(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
887istmsg(f: array of byte): int
888{
889 if(len f < H)
890 return -1;
891 return (int f[BIT32SZ] & 1) == 0;
892}
893
894compatible(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}
appl/lib/styx.b+7−21
@@ -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
887readn(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
901istmsg(f: array of byte): int887istmsg(f: array of byte): int
902{888{
903 if(len f < H)889 if(len f < H)
dis/9660srv.dis+0−0

Binary file not shown.

dis/auth/keyfs.dis+0−0

Binary file not shown.

dis/dossrv.dis+0−0

Binary file not shown.

dis/ftpfs.dis+0−0

Binary file not shown.

dis/lib/ninep.dis+0−0

Binary file not shown.

dis/lib/styx.dis+0−0

Binary file not shown.

include/version.h+1−1
@@ -1 +1 @@
1#define VERSION "Fourth Edition (20100213)"1#define VERSION "Fourth Edition (20100221)"
man/2/9p-ninep+416−0
@@ -0,0 +1,416 @@
1.TH 9P-NINEP 2
2.SH NAME
3Ninep: Rmsg, Tmsg, dir2text, istmsg, packdir, packdirsize, readmsg, qid2text, unpackdir \- interface to 9P file protocol
4.SH SYNOPSIS
5.EX
6include "9p.m";
7ninep := load Ninep Ninep->PATH;
8
9Tmsg: 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
59Rmsg: 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
99init: fn();
100
101readmsg: fn(fd: ref Sys->FD, msize: int): (array of byte, string);
102istmsg: fn(f: array of byte): int;
103
104compatible: fn(t: ref Tmsg.Version, msize: int, version: string): (int, string);
105
106packdirsize: fn(d: Sys->Dir): int;
107packdir: fn(d: Sys->Dir): array of byte;
108unpackdir: fn(f: array of byte): (int, Sys->Dir);
109dir2text: fn(d: Sys->Dir): string;
110qid2text: fn(q: Sys->Qid): string;
111
112VERSION: con "9P2000";
113MAXWELEM: con 16;
114NOTAG: con 16rFFFF;
115NOFID: con ~0;
116IOHDRSZ: con \fIimplementation-defined\f5;
117DEFMSIZE: con \fIimplementation-defined\f5;
118.EE
119.SH DESCRIPTION
120.B Ninep
121provides a Limbo interface to send and receive messages of the 9P file service protocol,
122described by Section 5 of this manual, a thorough reading of which
123is advised before using this module.
124.B Init
125must be called before using any other function in the module.
126.PP
127A 9P client transmits requests to a server as `T-messages'
128and receives replies in matching `R-messages'.
129A T-message is here represented by values of the type
130.BR Tmsg ,
131and an R-message by values of type
132.BR Rmsg .
133Every message has a
134.B tag
135value, and the alternatives of the pick adt represent the possible operation types of a T-message,
136generally with parameter names and types corresponding to those described in section 5.
137The exceptions are:
138.B Tmsg.Write
139and
140.B Rmsg.Read
141contain an array of byte,
142.BR data ,
143to hold the data for the corresponding message, and the `count' parameter of the message is simply the length of that array;
144and there is an alternative labelled
145.B Readerror
146that does not appear in the protocol but is used to represent input errors as described below.
147Also note that values that are `unsigned' integers in the protocol are typically given signed integer
148types in the Limbo representation (in particular, fids, qid paths, counts and offsets), and applications
149should take appropriate care when manipulating them.
150.PP
151The following functions are provided by
152.BR Tmsg:
153.TP
154.BI read( fd\fP,\fP\ msize )
155Read file descriptor
156.I fd
157to obtain exactly one T-message and return (a reference to) the corresponding
158.BR Tmsg .
159A nil value is returned on end of file.
160Otherwise, if the read fails or the data read does not form a valid T-message,
161the value returned will be a
162.B Tmsg.Readerror
163value in which the
164.B error
165member describes the error.
166.I Msize
167gives the maximum number of bytes in any acceptable T-message,
168and should be the value negotiated in the exchange of
169.B version
170messages;
171any incoming message larger than that will result in a diagnostic as a
172.B Tmsg.Readerror
173value.
174An
175.I msize
176of 0 means `no limit negotiated' and should (only) be used until a message size
177has been negotiated by exchange of
178.IR version (5)
179messages.
180.TP
181.IB t .pack()
182Return an array of bytes containing the value of
183.I t
184in the machine-independent format described in Section 5.
185It can return nil only if the message
186.I t
187is itself nil or has an invalid type.
188.TP
189.BI unpack( a )
190The array
191.I a
192is assumed to contain zero or more T-messages.
193.B Unpack
194attempts to unpack the first message, and returns a tuple of the form
195.RI ( n , v ).
196If successful,
197.I n
198is the number of bytes at the start of
199.I a
200used by the message, and
201.I v
202is the corresponding
203.B Tmsg
204value.
205If
206.I a
207contains the prefix of a valid message but more data is required to complete it,
208.I n
209is zero (and
210.I v
211is nil); the caller will typically read more data, append it to
212.IR a ,
213and try again.
214If the message is invalid,
215.I n
216is -1
217and
218.I v
219is nil.
220.TP
221.IB t .packedsize()
222Return the number of bytes required for the value of
223.I t
224when packed in its machine-independent format.
225(Zero is returned if
226.I t
227is invalid.)
228.TP
229.IB t .text()
230Return a printable string showing the contents of
231.IR t ,
232for tracing or debugging.
233.TP
234.IB t .mtype()
235Return the 9P message type of the message.
236.PP
237An R-message is represented by
238.BR Rmsg .
239Its member functions behave exactly as those for
240.BR Tmsg ,
241except that they operate on R-messages not T-messages.
242.PP
243When a client reads a directory, the data returned in the reply must be formatted
244as described in
245.IR read (5):
246an array of directory entries, one per file, with each entry formatted in
247a machine-independent format.
248An appropriate array value can be produced by
249.B packdir
250from a
251.B Sys->Dir
252structure, as used by
253.IR sys-stat (2).
254The space that packed representation will take can be calculated beforehand by
255.BR packdirsize .
256The server will usually fill the buffer for the reply to the read
257with as many entries as will fit,
258checking the space remaining against the result of
259.B packdirsize
260and if the value will fit, storing the result of
261.BR packdir .
262Given an array
263.I a
264containing at most one packed directory value (as produced by
265.BR packdir ),
266.B unpackdir
267returns a tuple
268.RI ( n,\ d )
269where
270.I n
271is \-1 if
272.I a
273is illegally formatted;
274.I n
275is zero if
276.I a
277does not contain a complete directory entry value;
278and otherwise
279.I n
280is the number of bytes of
281.I a
282used to produce the unpacked
283.B Dir
284value
285.I d .
286.PP
287The functions
288.B dir2text
289and
290.B qid2text
291produce printable strings showing the contents of the corresponding data structures,
292for use when tracing or debugging.
293.PP
294Applications that acts as file servers will read T-messages and
295reply with R-messages.
296They can use
297.B Tmsg.read
298to read each T-message, build an
299.B Rmsg
300reply value
301.IR r ,
302and use
303.IB r .pack
304to produce an array of bytes to be written in reply by
305.B Sys->write
306(see
307.IR sys-read (2)).
308.PP
309A few specialised programs might need the lower-level function
310.B readmsg
311that underlies
312.B Tmsg.read
313and
314.BR Rmsg.read .
315It reads a single message, which can be either a T-message or R-message,
316and returns it as an array of bytes,
317which can then be unpacked using
318.B Tmsg.unpack
319or
320.BR Rmsg.unpack .
321.I Msize
322is the negotiated message size, or 0 meaning `no limit'.
323The predicate
324.B istmsg
325returns true if the contents of array
326.I f
327looks like a packed representation of a T-message,
328judging only by its
329.I type
330byte.
331.PP
332When generating the
333.B version
334message (see
335.IR version (5)),
336the constant
337.B NOTAG
338can be used in
339.B Tmsg.tag
340and
341.B Rmsg.tag
342to represent `no tag value'.
343The constant
344.B VERSION
345names the current version of the protocol, and can be
346used as the value of
347.BR Tmsg.version .
348.PP
349.B Compatible
350can be used by a server to
351compare its
352.I msize
353and
354.I version
355(which is typically
356.BR VERSION )
357to those in the
358.B Tmsg.Version
359message received from a client, to decide its reply,
360following the rules in
361.IR version (5).
362It returns a tuple
363.RI ( m ", " v )
364with values for use in the
365.B Rmsg.Version
366reply.
367.I M
368is the lesser of
369.I msize
370and
371.IB t .msize ,
372and
373.I v
374is the negotiated protocol version, or the value \f5"unknown"\f1
375if no version could be agreed.
376The constant
377.B DEFMSIZE
378is a reasonable value for
379.I msize
380on current systems.
381The resulting value
382.I m
383can subsequently be given to the various read functions as the limit
384.IR msize .
385The constant
386.B IOHDRSZ
387gives the amount to allow for protocol overhead, when limiting data size for
388.B Tmsg.Write
389and
390.BR Rmsg.Read .
391.PP
392The constant
393.B NOFID
394can be used as the value of
395.B afid
396of the
397.B attach
398message when authentication is not required (see
399.IR attach (5)).
400.PP
401The constant
402.B MAXWELEM
403gives the protocol-defined limit on the length of the arrays
404.B Tmsg.names
405and
406.BR Rmsg.qids .
407For specialised applications, the module defines constants
408.BR Tversion ,
409.BR Rversion ,
410etc. for the message types of the protocol, and the
411other 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)
module/9p.m+178−0
@@ -0,0 +1,178 @@
1Ninep: 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};