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 @@
1+20100220
2+ appl/cmd/keyfs.b wasn't clunking fids on error in remove [issue 225]
13 20100213
24 apply saoret.one's changes for thumb [issue 155]
35 20100205
appl/cmd/9660srv.b+1−1
@@ -185,7 +185,7 @@ fileserve(rfd: ref Sys->FD, sync: chan of int) · 184 unmodified lines
185185 error("bad R-message conversion");
186186 if(showstyx)
187187 chat(r.text()+"\n");
188− if(styx->write(rfd, rbuf, len rbuf) != len rbuf)
188+ if(sys->write(rfd, rbuf, len rbuf) != len rbuf)
189189 error(sys->sprint("connection write error: %r"));
190190 }
191191
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
415415 }
416416 case TYPE(c.path) {
417417 Quser =>
418+ srv.delfid(c);
418419 u := finduserpath(c.path);
419420 if(u == nil){
420421 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
422423 }
423424 removeuser(u);
424425 writekeys(keyfile);
425− srv.delfid(c);
426426 srv.reply(ref Rmsg.Remove(m.tag));
427427 Qsecret =>
428+ srv.delfid(c);
428429 u := finduserpath(c.path);
429430 if(u == nil){
430431 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
432433 }
433434 u.secret = nil;
434435 writekeys(keyfile);
435− srv.delfid(c);
436436 srv.reply(ref Rmsg.Remove(m.tag));
437437 * =>
438438 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
195195 {
196196 sys->pctl(Sys->NEWFD, rfd.fd :: 2 :: nil);
197197 rfd = sys->fildes(rfd.fd);
198− data := array[Styx->MAXRPC] of byte;
199198 while((t := Tmsg.read(rfd, 0)) != nil){
200199 if(debug & STYX_MESS)
201200 chat(sys->sprint("%s...", t.text()));
@@ -242,7 +241,7 @@ dossrv(rfd: ref Sys->FD) · 40 unmodified lines
242241 panic("Rmsg.pack");
243242 if(debug & STYX_MESS)
244243 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)
246245 panic("mount write");
247246 }
248247
@@ -967,7 +966,7 @@ rwstat(t: ref Tmsg.Wstat): ref Rmsg · 718 unmodified lines
967966 oaddr := dp.addr;
968967 ooffset := dp.offset;
969968 d := dpd;
970− od := *d;
969+# od := *d;
971970 # start := getstart(f.xf, d);
972971 start := d.start;
973972 length := d.length;
@@ -1395,7 +1394,7 @@ putstart(nil: ref Xfs, d: ref Dosdir, start: int) · 421 unmodified lines
13951394 fileclust(f: ref Xfile, iclust: int, cflag: int): int
13961395 {
13971396
1398− bp := f.xf.ptr;
1397+# bp := f.xf.ptr;
13991398 dp := f.ptr;
14001399 if(isroot(dp.addr))
14011400 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
20672066 truncfile(f: ref Xfile): int
20682067 {
20692068 xf := f.xf;
2070− bp := xf.ptr;
2069+# bp := xf.ptr;
20712070 dp := f.ptr;
20722071 d := Dosdir.arr2Dd(dp.p.iobuf[dp.offset:dp.offset+DOSDIRSIZE]);
20732072
appl/cmd/ftpfs.b+1−1
@@ -280,7 +280,7 @@ sendreply(r: ref Rmsg) · 279 unmodified lines
280280 if (debug)
281281 sys->print("> %s\n", r.text());
282282 a := r.pack();
283− if(styx->write(styxfd, a, len a) != len a)
283+ if(sys->write(styxfd, a, len a) != len a)
284284 sys->print("ftpfs: error replying: %r\n");
285285 }
286286
appl/lib/ninep.b+914−0
@@ -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+}
appl/lib/styx.b+7−21
@@ -571,7 +571,7 @@ Tmsg.read(fd: ref Sys->FD, msglim: int): ref Tmsg · 570 unmodified lines
571571 return nil;
572572 (nil, m) := Tmsg.unpack(msg);
573573 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");
575575 return m;
576576 }
577577
@@ -843,7 +843,7 @@ Rmsg.read(fd: ref Sys->FD, msglim: int): ref Rmsg · 265 unmodified lines
843843 return nil;
844844 (nil, m) := Rmsg.unpack(msg);
845845 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");
847847 return m;
848848 }
849849
@@ -863,7 +863,7 @@ readmsg(fd: ref Sys->FD, msglim: int): (array of byte, string) · 13 unmodified lines
863863 if(msglim <= 0)
864864 msglim = MAXRPC;
865865 sbuf := array[BIT32SZ] of byte;
866− if((n := readn(fd, sbuf, BIT32SZ)) != BIT32SZ){
866+ if((n := sys->readn(fd, sbuf, BIT32SZ)) != BIT32SZ){
867867 if(n == 0)
868868 return (nil, nil);
869869 return (nil, sys->sprint("%r"));
@@ -871,33 +871,19 @@ readmsg(fd: ref Sys->FD, msglim: int): (array of byte, string) · 1 unmodified line
871871 ml := (int sbuf[1] << 8) | int sbuf[0];
872872 ml |= ((int sbuf[3] << 8) | int sbuf[2]) << 16;
873873 if(ml <= BIT32SZ)
874− return (nil, "invalid Styx message size");
874+ return (nil, "invalid 9P message size");
875875 if(ml > msglim)
876− return (nil, "Styx message longer than agreed");
876+ return (nil, "9P message longer than agreed");
877877 buf := array[ml] of byte;
878878 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){
880880 if(n == 0)
881− return (nil, "Styx message truncated");
881+ return (nil, "9P message truncated");
882882 return (nil, sys->sprint("%r"));
883883 }
884884 return (buf, nil);
885885 }
886886
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−
901887 istmsg(f: array of byte): int
902888 {
903889 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
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)
module/9p.m+178−0
@@ -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+};