forsyth20121205-174063a80cc13 years agoHistory
914 lines · 21.5 KB · Brainfuck
RawDownload
implement Ninep; include "sys.m";	sys: Sys; include "9p.m"; STR: con BIT16SZ;	# string lengthTAG: con BIT16SZ;FID: con BIT32SZ;QID: con BIT8SZ+BIT32SZ+BIT64SZ;LEN: con BIT16SZ;	# stat and qid array lengthsCOUNT: con BIT32SZ;OFFSET: con BIT64SZ; H: con BIT32SZ+BIT8SZ+BIT16SZ;	# minimum header length: size[4] type tag[2] ## the following array could be shorter if it were indexed by (type-Tversion)#hdrlen := array[Tmax] of{Tversion =>	H+COUNT+STR,	# size[4] Tversion tag[2] msize[4] version[s]Rversion =>	H+COUNT+STR,	# size[4] Rversion tag[2] msize[4] version[s] Tauth =>	H+FID+STR+STR,		# size[4] Tauth tag[2] afid[4] uname[s] aname[s]Rauth =>	H+QID,			# size[4] Rauth tag[2] aqid[13] Rerror =>	H+STR,		# size[4] Rerror tag[2] ename[s] Tflush =>	H+TAG,		# size[4] Tflush tag[2] oldtag[2]Rflush =>	H,			# size[4] Rflush tag[2] Tattach =>	H+FID+FID+STR+STR,	# size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s]Rattach =>	H+QID,		# size[4] Rattach tag[2] qid[13] Twalk =>	H+FID+FID+LEN,	# size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])Rwalk =>	H+LEN,		# size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) Topen =>	H+FID+BIT8SZ,		# size[4] Topen tag[2] fid[4] mode[1]Ropen =>	H+QID+COUNT,	# size[4] Ropen tag[2] qid[13] iounit[4] Tcreate =>	H+FID+STR+BIT32SZ+BIT8SZ,	# size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1]Rcreate =>	H+QID+COUNT,	# size[4] Rcreate tag[2] qid[13] iounit[4] Tread =>	H+FID+OFFSET+COUNT,	# size[4] Tread tag[2] fid[4] offset[8] count[4]Rread =>	H+COUNT,		# size[4] Rread tag[2] count[4] data[count] Twrite =>	H+FID+OFFSET+COUNT,	# size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]Rwrite =>	H+COUNT,	# size[4] Rwrite tag[2] count[4] Tclunk =>	H+FID,	# size[4] Tclunk tag[2] fid[4]Rclunk =>	H,		# size[4] Rclunk tag[2] Tremove =>	H+FID,	# size[4] Tremove tag[2] fid[4]Rremove =>	H,	# size[4] Rremove tag[2] Tstat =>	H+FID,	# size[4] Tstat tag[2] fid[4]Rstat =>	H+LEN,	# size[4] Rstat tag[2] stat[n] Twstat =>	H+FID+LEN,	# size[4] Twstat tag[2] fid[4] stat[n]Rwstat =>	H,	# size[4] Rwstat tag[2]}; init(){	sys = load Sys Sys->PATH;} utflen(s: string): int{	# the domain is 16-bit unicode only, which is all that Inferno now implements	n := l := len s;	for(i:=0; i<l; i++)		if((c := s[i]) > 16r7F){			n++;			if(c > 16r7FF)				n++;		}	return n;} packdirsize(d: Sys->Dir): int{	return STATFIXLEN+utflen(d.name)+utflen(d.uid)+utflen(d.gid)+utflen(d.muid);} packdir(f: Sys->Dir): array of byte{	ds := packdirsize(f);	a := array[ds] of byte;	# size[2]	a[0] = byte (ds-LEN);	a[1] = byte ((ds-LEN)>>8);	# type[2]	a[2] = byte f.dtype;	a[3] = byte (f.dtype>>8);	# dev[4]	a[4] = byte f.dev;	a[5] = byte (f.dev>>8);	a[6] = byte (f.dev>>16);	a[7] = byte (f.dev>>24);	# qid.type[1]	# qid.vers[4]	# qid.path[8]	pqid(a, 8, f.qid);	# mode[4]	a[21] = byte f.mode;	a[22] = byte (f.mode>>8);	a[23] = byte (f.mode>>16);	a[24] = byte (f.mode>>24);	# atime[4]	a[25] = byte f.atime;	a[26] = byte (f.atime>>8);	a[27] = byte (f.atime>>16);	a[28] = byte (f.atime>>24);	# mtime[4]	a[29] = byte f.mtime;	a[30] = byte (f.mtime>>8);	a[31] = byte (f.mtime>>16);	a[32] = byte (f.mtime>>24);	# length[8]	p64(a, 33, big f.length);	# name[s]	i := pstring(a, 33+BIT64SZ, f.name);	i = pstring(a, i, f.uid);	i = pstring(a, i, f.gid);	i = pstring(a, i, f.muid);	if(i != len a)		raise "assertion: Ninep->packdir: bad count";	# can't happen unless packedsize is wrong	return a;} pqid(a: array of byte, o: int, q: Sys->Qid): int{	a[o] = byte q.qtype;	v := q.vers;	a[o+1] = byte v;	a[o+2] = byte (v>>8);	a[o+3] = byte (v>>16);	a[o+4] = byte (v>>24);	v = int q.path;	a[o+5] = byte v;	a[o+6] = byte (v>>8);	a[o+7] = byte (v>>16);	a[o+8] = byte (v>>24);	v = int (q.path >> 32);	a[o+9] = byte v;	a[o+10] = byte (v>>8);	a[o+11] = byte (v>>16);	a[o+12] = byte (v>>24);	return o+QID;} pstring(a: array of byte, o: int, s: string): int{	sa := array of byte s;	# could do conversion ourselves	n := len sa;	a[o] = byte n;	a[o+1] = byte (n>>8);	a[o+2:] = sa;	return o+LEN+n;} p32(a: array of byte, o: int, v: int): int{	a[o] = byte v;	a[o+1] = byte (v>>8);	a[o+2] = byte (v>>16);	a[o+3] = byte (v>>24);	return o+BIT32SZ;} p64(a: array of byte, o: int, b: big): int{	i := int b;	a[o] = byte i;	a[o+1] = byte (i>>8);	a[o+2] = byte (i>>16);	a[o+3] = byte (i>>24);	i = int (b>>32);	a[o+4] = byte i;	a[o+5] = byte (i>>8);	a[o+6] = byte (i>>16);	a[o+7] = byte (i>>24);	return o+BIT64SZ;} unpackdir(a: array of byte): (int, Sys->Dir){	dir: Sys->Dir; 	if(len a < STATFIXLEN)		return (0, dir);	# size[2]	sz := ((int a[1] << 8) | int a[0])+LEN;	# bytes this packed dir should occupy	if(len a < sz)		return (0, dir);	# type[2]	dir.dtype = (int a[3]<<8) | int a[2];	# dev[4]	dir.dev = (((((int a[7] << 8) | int a[6]) << 8) | int a[5]) << 8) | int a[4];	# qid.type[1]	# qid.vers[4]	# qid.path[8]	dir.qid = gqid(a, 8);	# mode[4]	dir.mode = (((((int a[24] << 8) | int a[23]) << 8) | int a[22]) << 8) | int a[21];	# atime[4]	dir.atime = (((((int a[28] << 8) | int a[27]) << 8) | int a[26]) << 8) | int a[25];	# mtime[4]	dir.mtime = (((((int a[32] << 8) | int a[31]) << 8) | int a[30]) << 8) | int a[29];	# length[8]	v0 := (((((int a[36] << 8) | int a[35]) << 8) | int a[34]) << 8) | int a[33];	v1 := (((((int a[40] << 8) | int a[39]) << 8) | int a[38]) << 8) | int a[37];	dir.length = (big v1 << 32) | (big v0 & 16rFFFFFFFF);	# name[s], uid[s], gid[s], muid[s]	i: int;	(dir.name, i) = gstring(a, 41);	(dir.uid, i) = gstring(a, i);	(dir.gid, i) = gstring(a, i);	(dir.muid, i) = gstring(a, i);	if(i != sz)		return (0, dir);	return (i, dir);} gqid(f: array of byte, i: int): Sys->Qid{	qtype := int f[i];	vers := (((((int f[i+4] << 8) | int f[i+3]) << 8) | int f[i+2]) << 8) | int f[i+1];	i += BIT8SZ+BIT32SZ;	path0 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i];	i += BIT32SZ;	path1 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i];	path := (big path1 << 32) | (big path0 & 16rFFFFFFFF);	return (path, vers, qtype);} g32(f: array of byte, i: int): int{	return (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i];} g64(f: array of byte, i: int): big{	b0 := (((((int f[i+3] << 8) | int f[i+2]) << 8) | int f[i+1]) << 8) | int f[i];	b1 := (((((int f[i+7] << 8) | int f[i+6]) << 8) | int f[i+5]) << 8) | int f[i+4];	return (big b1 << 32) | (big b0 & 16rFFFFFFFF);} gstring(a: array of byte, o: int): (string, int){	if(o < 0 || o+STR > len a)		return (nil, -1);	l := (int a[o+1] << 8) | int a[o];	o += STR;	e := o+l;	if(e > len a)		return (nil, -1);	return (string a[o:e], e);} ttag2type := array[] of {tagof Tmsg.Readerror => 0,tagof Tmsg.Version => Tversion,tagof Tmsg.Auth => Tauth,tagof Tmsg.Attach => Tattach,tagof Tmsg.Flush => Tflush,tagof Tmsg.Walk => Twalk,tagof Tmsg.Open => Topen,tagof Tmsg.Create => Tcreate,tagof Tmsg.Read => Tread,tagof Tmsg.Write => Twrite,tagof Tmsg.Clunk => Tclunk,tagof Tmsg.Stat => Tstat,tagof Tmsg.Remove => Tremove,tagof Tmsg.Wstat => Twstat,}; Tmsg.mtype(t: self ref Tmsg): int{	return ttag2type[tagof t];} Tmsg.packedsize(t: self ref Tmsg): int{	mtype := ttag2type[tagof t];	if(mtype <= 0)		return 0;	ml := hdrlen[mtype];	pick m := t {	Version =>		ml += utflen(m.version);	Auth =>		ml += utflen(m.uname)+utflen(m.aname);	Attach =>		ml += utflen(m.uname)+utflen(m.aname);	Walk =>		for(i:=0; i<len m.names; i++)			ml += STR+utflen(m.names[i]);	Create =>		ml += utflen(m.name);	Write =>		ml += len m.data;	Wstat =>		ml += packdirsize(m.stat);	}	return ml;} Tmsg.pack(t: self ref Tmsg): array of byte{	if(t == nil)		return nil;	ds := t.packedsize();	if(ds <= 0)		return nil;	d := array[ds] of byte;	d[0] = byte ds;	d[1] = byte (ds>>8);	d[2] = byte (ds>>16);	d[3] = byte (ds>>24);	d[4] = byte ttag2type[tagof t];	d[5] = byte t.tag;	d[6] = byte (t.tag >> 8);	pick m := t {	Version =>		p32(d, H, m.msize);		pstring(d, H+COUNT, m.version);	Auth =>		p32(d, H, m.afid);		o := pstring(d, H+FID, m.uname);		pstring(d, o, m.aname);	Flush =>		v := m.oldtag;		d[H] = byte v;		d[H+1] = byte (v>>8);	Attach =>		p32(d, H, m.fid);		p32(d, H+FID, m.afid);		o := pstring(d, H+2*FID, m.uname);		pstring(d, o, m.aname);	Walk =>		d[H] = byte m.fid;		d[H+1] = byte (m.fid>>8);		d[H+2] = byte (m.fid>>16);		d[H+3] = byte (m.fid>>24);		d[H+FID] = byte m.newfid;		d[H+FID+1] = byte (m.newfid>>8);		d[H+FID+2] = byte (m.newfid>>16);		d[H+FID+3] = byte (m.newfid>>24);		n := len m.names;		d[H+2*FID] = byte n;		d[H+2*FID+1] = byte (n>>8);		o := H+2*FID+LEN;		for(i := 0; i < n; i++)			o = pstring(d, o, m.names[i]);	Open =>		p32(d, H, m.fid);		d[H+FID] = byte m.mode;	Create =>		p32(d, H, m.fid);		o := pstring(d, H+FID, m.name);		p32(d, o, m.perm);		d[o+BIT32SZ] = byte m.mode;	Read =>		p32(d, H, m.fid);		p64(d, H+FID, m.offset);		p32(d, H+FID+OFFSET, m.count);	Write =>		p32(d, H, m.fid);		p64(d, H+FID, m.offset);		n := len m.data;		p32(d, H+FID+OFFSET, n);		d[H+FID+OFFSET+COUNT:] = m.data;	Clunk or Remove or Stat =>		p32(d, H, m.fid);	Wstat =>		p32(d, H, m.fid);		stat := packdir(m.stat);		n := len stat;		d[H+FID] = byte n;		d[H+FID+1] = byte (n>>8);		d[H+FID+LEN:] = stat;	* =>		raise sys->sprint("assertion: Ninep->Tmsg.pack: bad tag: %d", tagof t);	}	return d;} Tmsg.unpack(f: array of byte): (int, ref Tmsg){	if(len f < H)		return (0, nil);	size := (int f[1] << 8) | int f[0];	size |= ((int f[3] << 8) | int f[2]) << 16;	if(len f != size){		if(len f < size)			return (0, nil);	# need more data		f = f[0:size];	# trim to exact length	}	mtype := int f[4];	if(mtype >= len hdrlen || (mtype&1) != 0 || size < hdrlen[mtype])		return (-1, nil); 	tag := (int f[6] << 8) | int f[5];	fid := 0;	if(hdrlen[mtype] >= H+FID)		fid = g32(f, H);	# fid is always in same place: extract it once for all if there 	# return out of each case body for a legal message;	# break out of the case for an illegal one Decode:	case mtype {	* =>		sys->print("styx: Tmsg.unpack: bad type %d\n", mtype);	Tversion =>		msize := fid;		(version, o) := gstring(f, H+COUNT);		if(o <= 0)			break;		return (o, ref Tmsg.Version(tag, msize, version));	Tauth =>		(uname, o1) := gstring(f, H+FID);		(aname, o2) := gstring(f, o1);		if(o2 <= 0)			break;		return (o2, ref Tmsg.Auth(tag, fid, uname, aname));	Tflush =>		oldtag := (int f[H+1] << 8) | int f[H];		return (H+TAG, ref Tmsg.Flush(tag, oldtag));	Tattach =>		afid := g32(f, H+FID);		(uname, o1) := gstring(f, H+2*FID);		(aname, o2) := gstring(f, o1);		if(o2 <= 0)			break;		return (o2, ref Tmsg.Attach(tag, fid, afid, uname, aname));	Twalk =>		newfid := g32(f, H+FID);		n := (int f[H+2*FID+1] << 8) | int f[H+2*FID];		if(n > MAXWELEM)			break;		o := H+2*FID+LEN;		names: array of string = nil;		if(n > 0){			names = array[n] of string;			for(i:=0; i<n; i++){				(names[i], o) = gstring(f, o);				if(o <= 0)					break Decode;			}		}		return (o, ref Tmsg.Walk(tag, fid, newfid, names));	Topen =>		return (H+FID+BIT8SZ, ref Tmsg.Open(tag, fid, int f[H+FID]));	Tcreate =>		(name, o) := gstring(f, H+FID);		if(o <= 0 || o+BIT32SZ+BIT8SZ > len f)			break;		perm := g32(f, o);		o += BIT32SZ;		mode := int f[o++];		return (o, ref Tmsg.Create(tag, fid, name, perm, mode));	Tread =>		offset := g64(f, H+FID);		count := g32(f, H+FID+OFFSET);		return (H+FID+OFFSET+COUNT, ref Tmsg.Read(tag, fid, offset, count));	Twrite =>		offset := g64(f, H+FID);		count := g32(f, H+FID+OFFSET);		O: con H+FID+OFFSET+COUNT;		if(count > len f-O)			break;		data := f[O:O+count];		return (O+count, ref Tmsg.Write(tag, fid, offset, data));	Tclunk =>		return (H+FID, ref Tmsg.Clunk(tag, fid));	Tremove =>		return (H+FID, ref Tmsg.Remove(tag, fid));	Tstat =>		return (H+FID, ref Tmsg.Stat(tag, fid));	Twstat =>		n := int (f[H+FID+1]<<8) | int f[H+FID];		if(len f < H+FID+LEN+n)			break;		(ds, stat) := unpackdir(f[H+FID+LEN:]);		if(ds != n){			sys->print("Ninep->Tmsg.unpack: wstat count: %d/%d\n", ds, n);	# temporary			break;		}		return (H+FID+LEN+n, ref Tmsg.Wstat(tag, fid, stat));	}	return (-1, nil);		# illegal} tmsgname := array[] of {tagof Tmsg.Readerror => "Readerror",

Lines 1–500 of 914.