changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > ventivac / changeset: add venti lib and man page from inferno-os. to be modified slightly.

changeset 112: 994f59b44578
parent 111: 8fd6132b12be
child 113: 4a67185fe151
author: Mechiel Lukkien <mechiel@ueber.net>
date: Fri, 17 Aug 2007 21:38:38 +0200
files: appl/lib/venti.b man/2/venti
description: add venti lib and man page from inferno-os. to be modified slightly.
     1.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2+++ b/appl/lib/venti.b	Fri Aug 17 21:38:38 2007 +0200
     1.3@@ -0,0 +1,664 @@
     1.4+implement Venti;
     1.5+
     1.6+include "sys.m";
     1.7+	sys: Sys;
     1.8+include "venti.m";
     1.9+
    1.10+BIT8SZ:	con 1;
    1.11+BIT16SZ:	con 2;
    1.12+BIT32SZ:	con 4;
    1.13+BIT48SZ:	con 6;
    1.14+SCORE:	con 20;
    1.15+STR:		con BIT16SZ;
    1.16+H: con BIT16SZ+BIT8SZ+BIT8SZ;		# minimum header length: size[2] op[1] tid[1]
    1.17+Rootnamelen: con 128;
    1.18+
    1.19+versions := array[] of {"02"};
    1.20+
    1.21+blankroot: Root;
    1.22+blankentry: Entry;
    1.23+
    1.24+init()
    1.25+{
    1.26+	sys = load Sys Sys->PATH;
    1.27+}
    1.28+
    1.29+hdrlen := array[Tmax] of {
    1.30+Rerror =>	H+STR,							# size[2] Rerror tid[1] error[s]
    1.31+Tping =>	H,								# size[2] Tping tid[1]
    1.32+Rping => 	H,								# size[2] Rping tid[1]
    1.33+Thello =>	H+STR+STR+BIT8SZ+BIT8SZ+BIT8SZ,	# size[2] Thello tid[1] version[s] uid[s] crypto[1] cryptos[n] codecs[n]
    1.34+Rhello =>	H+STR+BIT8SZ+BIT8SZ,				# size[2] Rhello tid[1] sid[s] crypto[1] codec[1]
    1.35+Tgoodbye => H,							# size[2] Tgoodbye tid[1]
    1.36+Tread =>	H+SCORE+BIT8SZ+BIT8SZ+BIT16SZ,	# size[2] Tread tid[1] score[20] type[1] pad[1] n[2]
    1.37+Rread => H,								# size[2] Rread tid[1] data
    1.38+Twrite => H+BIT8SZ+3,						# size[2] Twrite tid[1] type[1] pad[3]
    1.39+Rwrite => H+SCORE,							# size[2] Rwrite tid[1] score[20
    1.40+Tsync => H,								# size[2] Tsync tid[1]
    1.41+Rsync => H,								# size[2] Rsync tid[1]
    1.42+};
    1.43+
    1.44+tag2type := array[] of {
    1.45+tagof Vmsg.Rerror => Rerror,
    1.46+tagof Vmsg.Tping => Tping,
    1.47+tagof Vmsg.Rping => Rping,
    1.48+tagof Vmsg.Thello => Thello,
    1.49+tagof Vmsg.Rhello => Rhello,
    1.50+tagof Vmsg.Tgoodbye => Tgoodbye,
    1.51+tagof Vmsg.Tread => Tread,
    1.52+tagof Vmsg.Rread => Rread,
    1.53+tagof Vmsg.Twrite => Twrite,
    1.54+tagof Vmsg.Rwrite => Rwrite,
    1.55+tagof Vmsg.Tsync => Tsync,
    1.56+tagof Vmsg.Rsync => Rsync,
    1.57+};
    1.58+
    1.59+msgname := array[] of {
    1.60+tagof Vmsg.Rerror => "Rerror",
    1.61+tagof Vmsg.Tping => "Tping",
    1.62+tagof Vmsg.Rping => "Rping",
    1.63+tagof Vmsg.Thello => "Thello",
    1.64+tagof Vmsg.Rhello => "Rhello",
    1.65+tagof Vmsg.Tgoodbye => "Tgoodbye",
    1.66+tagof Vmsg.Tread => "Tread",
    1.67+tagof Vmsg.Rread => "Rread",
    1.68+tagof Vmsg.Twrite => "Twrite",
    1.69+tagof Vmsg.Rwrite => "Rwrite",
    1.70+tagof Vmsg.Tsync => "Tsync",
    1.71+tagof Vmsg.Rsync => "Rsync",
    1.72+};
    1.73+
    1.74+zero := array[] of {
    1.75+	byte 16rda, byte 16r39, byte 16ra3, byte 16ree, byte 16r5e,
    1.76+	byte 16r6b, byte 16r4b, byte 16r0d, byte 16r32, byte 16r55,
    1.77+	byte 16rbf, byte 16ref, byte 16r95, byte 16r60, byte 16r18,
    1.78+	byte 16r90, byte 16raf, byte 16rd8, byte 16r07, byte 16r09
    1.79+};
    1.80+	
    1.81+
    1.82+Vmsg.read(fd: ref Sys->FD): (ref Vmsg, string)
    1.83+{
    1.84+	(msg, err) := readmsg(fd);
    1.85+	if(err != nil)
    1.86+		return (nil, err);
    1.87+	if(msg == nil)
    1.88+		return (nil, "eof reading message");
    1.89+	(nil, m) := Vmsg.unpack(msg);
    1.90+	if(m == nil)
    1.91+		return (nil, sys->sprint("bad venti message format: %r"));
    1.92+	return (m, nil);
    1.93+}
    1.94+
    1.95+Vmsg.unpack(f: array of byte): (int, ref Vmsg)
    1.96+{
    1.97+	if(len f < H) {
    1.98+		sys->werrstr("message too small");
    1.99+		return (0, nil);
   1.100+	}
   1.101+	size := (int f[0] << 8) | int f[1];		# size does not include self
   1.102+	size += BIT16SZ;
   1.103+	if(len f != size){
   1.104+		if(len f < size){
   1.105+			sys->werrstr("need more data");
   1.106+			return (0, nil);		# need more data
   1.107+		}
   1.108+		f = f[0:size];			# trim to exact length
   1.109+	}
   1.110+	mtype := int f[2];
   1.111+	if(mtype >= len hdrlen || size < hdrlen[mtype]){
   1.112+		sys->werrstr("mtype out of range");
   1.113+		return (-1, nil);
   1.114+	}
   1.115+	tid := int f[3];
   1.116+	m: ref Vmsg;
   1.117+	case mtype {
   1.118+	Thello =>
   1.119+		uid: string;
   1.120+		cryptos, codecs: array of byte;
   1.121+
   1.122+		(version, o) := gstring(f, H);
   1.123+		(uid, o) = gstring(f, o);
   1.124+		if(o < 0 || o >= len f)
   1.125+			break;
   1.126+		cryptostrength := int f[o++];
   1.127+		(cryptos, o) = gbytes(f, o);
   1.128+		(codecs, o) = gbytes(f, o);
   1.129+		if(o != len f)
   1.130+			break;
   1.131+		m = ref Vmsg.Thello(1, tid, version, uid, cryptostrength, cryptos, codecs);
   1.132+	Tping =>
   1.133+		m = ref Vmsg.Tping(1, tid);
   1.134+	Tgoodbye =>
   1.135+		m = ref Vmsg.Tgoodbye(1, tid);
   1.136+	Tread =>
   1.137+		score := Score(f[H:H+SCORE]);
   1.138+		etype := int f[H+SCORE];
   1.139+		n := (int f[H+SCORE+2] << 8) | int f[H+SCORE+3];
   1.140+		m = ref Vmsg.Tread(1, tid, score, etype, n);
   1.141+	Twrite =>
   1.142+		etype := int f[H];
   1.143+		m = ref Vmsg.Twrite(1, tid, etype, f[H+4:]);
   1.144+	Tsync =>
   1.145+		m = ref Vmsg.Tsync(1, tid);
   1.146+	Rhello =>
   1.147+		(sid, o) := gstring(f, H);
   1.148+		if(o+2 != len f)
   1.149+			break;
   1.150+		crypto := int f[o++];
   1.151+		codec := int f[o++];
   1.152+		m = ref Vmsg.Rhello(0, tid, sid, crypto, codec);
   1.153+	Rping =>
   1.154+		m = ref Vmsg.Rping(0, tid);
   1.155+	Rread =>
   1.156+		m = ref Vmsg.Rread(0, tid, f[H:]);
   1.157+	Rwrite =>
   1.158+		m = ref Vmsg.Rwrite(0, tid, Score(f[H:H+SCORE]));
   1.159+	Rsync =>
   1.160+		m = ref Vmsg.Rsync(0, tid);
   1.161+	Rerror =>
   1.162+		(err, o) := gstring(f, H);
   1.163+		if(o < 0)
   1.164+			break;
   1.165+		m = ref Vmsg.Rerror(0, tid, err);
   1.166+	* =>
   1.167+		sys->werrstr("unrecognised mtype " + string mtype);
   1.168+		return (-1, nil);
   1.169+	}
   1.170+	if(m == nil) {
   1.171+		sys->werrstr("bad message size");
   1.172+		return (-1, nil);
   1.173+	}
   1.174+	return (size, m);
   1.175+}
   1.176+
   1.177+Vmsg.pack(gm: self ref Vmsg): array of byte
   1.178+{
   1.179+	if(gm == nil)
   1.180+		return nil;
   1.181+	ds := gm.packedsize();
   1.182+	if(ds <= 0)
   1.183+		return nil;
   1.184+	d := array[ds] of byte;
   1.185+	d[0] = byte ((ds - 2) >> 8);
   1.186+	d[1] = byte (ds - 2);
   1.187+	d[2] = byte tag2type[tagof gm];
   1.188+	d[3] = byte gm.tid;
   1.189+	pick m := gm {
   1.190+	Thello =>
   1.191+		o := pstring(d, H, m.version);
   1.192+		o = pstring(d, o, m.uid);
   1.193+		d[o++] = byte m.cryptostrength;
   1.194+		d[o++] = byte len m.cryptos;
   1.195+		d[o:] = m.cryptos;
   1.196+		o += len m.cryptos;
   1.197+		d[o++] = byte len m.codecs;
   1.198+		d[o:] = m.codecs;
   1.199+		o += len m.codecs;
   1.200+	Tping =>
   1.201+		;
   1.202+	Tgoodbye =>
   1.203+		;
   1.204+	Tread =>
   1.205+		d[H:] = m.score.a;
   1.206+		d[H+SCORE] = byte m.etype;
   1.207+		d[H+SCORE+2] = byte (m.n >> 8);
   1.208+		d[H+SCORE+3] = byte m.n;
   1.209+	Twrite =>
   1.210+		d[H] = byte m.etype;
   1.211+		d[H+4:] = m.data;
   1.212+	Tsync =>
   1.213+		;
   1.214+	Rhello =>
   1.215+		o := pstring(d, H, m.sid);
   1.216+		d[o++] = byte m.crypto;
   1.217+		d[o++] = byte m.codec;
   1.218+	Rping =>
   1.219+		;
   1.220+	Rread =>
   1.221+		d[H:] = m.data;
   1.222+	Rwrite =>
   1.223+		d[H:] = m.score.a;
   1.224+	Rsync =>
   1.225+		;
   1.226+	Rerror =>
   1.227+		pstring(d, H, m.e);
   1.228+	* =>
   1.229+		return nil;
   1.230+	}
   1.231+	return d;
   1.232+}
   1.233+
   1.234+Vmsg.packedsize(gm: self ref Vmsg): int
   1.235+{
   1.236+	mtype := tag2type[tagof gm];
   1.237+	if(mtype <= 0)
   1.238+		return 0;
   1.239+	ml := hdrlen[mtype];
   1.240+	pick m := gm {
   1.241+	Thello =>
   1.242+		ml += utflen(m.version) + utflen(m.uid) + len m.cryptos + len m.codecs;
   1.243+	Rhello =>
   1.244+		ml += utflen(m.sid);
   1.245+	Rread =>
   1.246+		ml += len m.data;
   1.247+	Twrite =>
   1.248+		ml += len m.data;
   1.249+	Rerror =>
   1.250+		ml += utflen(m.e);
   1.251+	}
   1.252+	return ml;
   1.253+}
   1.254+
   1.255+Vmsg.text(gm: self ref Vmsg): string
   1.256+{
   1.257+	if(gm == nil)
   1.258+		return "(nil)";
   1.259+	s := sys->sprint("%s(%d", msgname[tagof gm], gm.tid);
   1.260+	pick m := gm {
   1.261+	* =>
   1.262+		s += ",ILLEGAL";
   1.263+	Thello =>
   1.264+		s += sys->sprint(", %#q, %#q, %d, [", m.version, m.uid, m.cryptostrength);
   1.265+		if(len m.cryptos > 0){
   1.266+			s += string int m.cryptos[0];
   1.267+			for(i := 1; i < len m.cryptos; i++)
   1.268+				s += "," + string int m.cryptos[i];
   1.269+		}
   1.270+		s += "], [";
   1.271+		if(len m.codecs > 0){
   1.272+			s += string int m.codecs[0];
   1.273+			for(i := 1; i < len m.codecs; i++)
   1.274+				s += "," + string int m.codecs[i];
   1.275+		}
   1.276+		s += "]";
   1.277+	Tping =>
   1.278+		;
   1.279+	Tgoodbye =>
   1.280+		;
   1.281+	Tread =>
   1.282+		s += sys->sprint(", %s, %d, %d", m.score.text(), m.etype, m.n);
   1.283+	Twrite =>
   1.284+		s += sys->sprint(", %d, data[%d]", m.etype, len m.data);
   1.285+	Tsync =>
   1.286+		;
   1.287+	Rhello =>
   1.288+		s += sys->sprint(", %#q, %d, %d", m.sid, m.crypto, m.codec);
   1.289+	Rping =>
   1.290+	Rread =>
   1.291+		s += sys->sprint(", data[%d]", len m.data);
   1.292+	Rwrite =>
   1.293+		s += ", " + m.score.text();
   1.294+	Rsync =>
   1.295+		;
   1.296+	Rerror =>
   1.297+		s += sys->sprint(", %#q", m.e);
   1.298+	}
   1.299+	return s + ")";
   1.300+}
   1.301+
   1.302+Session.new(fd: ref Sys->FD): ref Session
   1.303+{
   1.304+	s := "venti-";
   1.305+	for(i := 0; i < len versions; i++){
   1.306+		if(i != 0)
   1.307+			s[len s] = ':';
   1.308+		s += versions[i];
   1.309+	}
   1.310+	s += "-libventi\n";
   1.311+	d := array of byte s;
   1.312+	if(sys->write(fd, d, len d) != len d)
   1.313+		return nil;
   1.314+	version := readversion(fd, "venti-", versions);
   1.315+	if(version == nil)
   1.316+		return nil;
   1.317+	session := ref Session(fd, version);
   1.318+	(r, e) := session.rpc(ref Vmsg.Thello(1, 0, version, nil, 0, nil, nil));
   1.319+	if(r == nil){
   1.320+		sys->werrstr("hello failed: " + e);
   1.321+		return nil;
   1.322+	}
   1.323+	return ref Session(fd, version);
   1.324+}
   1.325+
   1.326+Session.read(s: self ref Session, score: Score, etype: int, maxn: int): array of byte
   1.327+{
   1.328+	(gm, err) := s.rpc(ref Vmsg.Tread(1, 0, score, etype, maxn));
   1.329+	if(gm == nil){
   1.330+		sys->werrstr(err);
   1.331+		return nil;
   1.332+	}
   1.333+	pick m := gm {
   1.334+	Rread =>
   1.335+		return m.data;
   1.336+	}
   1.337+	return nil;
   1.338+}
   1.339+
   1.340+Session.write(s: self ref Session, etype: int, data: array of byte): (int, Score)
   1.341+{
   1.342+	(gm, err) := s.rpc(ref Vmsg.Twrite(1, 0, etype, data));
   1.343+	if(gm == nil){
   1.344+		sys->werrstr(err);
   1.345+		return (-1, Score(nil));
   1.346+	}
   1.347+	pick m := gm {
   1.348+	Rwrite =>
   1.349+		return (0, m.score);
   1.350+	}
   1.351+	return (-1, Score(nil));
   1.352+}
   1.353+
   1.354+Session.sync(s: self ref Session): int
   1.355+{
   1.356+	(gm, err) := s.rpc(ref Vmsg.Tsync(1, 0));
   1.357+	if(gm == nil){
   1.358+		sys->werrstr(err);
   1.359+		return -1;
   1.360+	}
   1.361+	return 0;
   1.362+}
   1.363+
   1.364+Session.rpc(s: self ref Session, m: ref Vmsg): (ref Vmsg, string)
   1.365+{
   1.366+	d := m.pack();
   1.367+	if(sys->write(s.fd, d, len d) != len d)
   1.368+		return (nil, "write failed");
   1.369+	(grm, err) := Vmsg.read(s.fd);
   1.370+	if(grm == nil)
   1.371+		return (nil, err);
   1.372+	if(grm.tid != m.tid)
   1.373+		return (nil, "message tags don't match");
   1.374+	if(grm.istmsg)
   1.375+		return (nil, "reply message is a t-message");
   1.376+	pick rm := grm {
   1.377+	Rerror =>
   1.378+		return (nil, rm.e);
   1.379+	}
   1.380+	if(tagof(grm) != tagof(m) + 1)
   1.381+		return (nil, "reply message is of wrong type");
   1.382+	return (grm, nil);
   1.383+}
   1.384+
   1.385+readversion(fd: ref Sys->FD, prefix: string, versions: array of string): string
   1.386+{
   1.387+	buf := array[Maxstringsize] of byte;
   1.388+	i := 0;
   1.389+	for(;;){
   1.390+		if(i >= len buf){
   1.391+			sys->werrstr("initial version string too long");
   1.392+			return nil;
   1.393+		}
   1.394+		if(readn(fd, buf[i:], 1) != 1){
   1.395+			sys->werrstr("eof on version string");
   1.396+			return nil;
   1.397+		}
   1.398+		c := int buf[i];
   1.399+		if(c == '\n')
   1.400+			break;
   1.401+		if(c < ' ' || c > 16r7f || i < len prefix && prefix[i] != c){
   1.402+			sys->werrstr("bad version string");
   1.403+			return nil;
   1.404+		}
   1.405+		i++;
   1.406+	}
   1.407+	if(i < len prefix){
   1.408+		sys->werrstr("bad version string");
   1.409+		return nil;
   1.410+	}
   1.411+#sys->fprint(sys->fildes(2), "read version %#q\n", string buf[0:i]);
   1.412+	v := string buf[len prefix:i];
   1.413+	i = 0;
   1.414+	for(;;){
   1.415+		for(j := i; j < len v && v[j] != ':' && v[j] != '-'; j++)
   1.416+			;
   1.417+		vv := v[i:j];
   1.418+#sys->fprint(sys->fildes(2), "checking %#q\n", vv);
   1.419+		for(k := 0; k < len versions; k++)
   1.420+			if(versions[k] == vv)
   1.421+				return vv;
   1.422+		i = j;
   1.423+		if(i >= len v || v[i] != ':'){
   1.424+			sys->werrstr("unknown version");
   1.425+			return nil;
   1.426+		}
   1.427+		i++;
   1.428+	}
   1.429+	sys->werrstr("unknown version");
   1.430+	return nil;
   1.431+}
   1.432+
   1.433+
   1.434+Score.eq(a: self Score, b: Score): int
   1.435+{
   1.436+	for(i := 0; i < SCORE; i++)
   1.437+		if(a.a[i] != b.a[i])
   1.438+			return 0;
   1.439+	return 1;
   1.440+}
   1.441+
   1.442+Score.zero(): Score
   1.443+{
   1.444+	return Score(zero);
   1.445+}
   1.446+
   1.447+Score.parse(s: string): (int, Score)
   1.448+{
   1.449+	if(len s != Scoresize * 2)
   1.450+		return (-1, Score(nil));
   1.451+	score := array[Scoresize] of {* => byte 0};
   1.452+	for(i := 0; i < len s; i++){
   1.453+		c := s[i];
   1.454+		case s[i] {
   1.455+		'0' to '9' =>
   1.456+			c -= '0';
   1.457+		'a' to 'f' =>
   1.458+			c -= 'a' - 10;
   1.459+		'A' to 'F' =>
   1.460+			c -= 'A' - 10;
   1.461+		* =>
   1.462+			return (-1, Score(nil));
   1.463+		}
   1.464+		if((i & 1) == 0)
   1.465+			c <<= 4;
   1.466+		score[i>>1] |= byte c;
   1.467+	}
   1.468+	return (0, Score(score));
   1.469+}
   1.470+
   1.471+Score.text(a: self Score): string
   1.472+{
   1.473+	s := "";
   1.474+	for(i := 0; i < SCORE; i++)
   1.475+		s += sys->sprint("%.2ux", int a.a[i]);
   1.476+	return s;
   1.477+}
   1.478+
   1.479+readn(fd: ref Sys->FD, buf: array of byte, nb: int): int
   1.480+{
   1.481+	for(nr := 0; nr < nb;){
   1.482+		n := sys->read(fd, buf[nr:], nb-nr);
   1.483+		if(n <= 0){
   1.484+			if(nr == 0)
   1.485+				return n;
   1.486+			break;
   1.487+		}
   1.488+		nr += n;
   1.489+	}
   1.490+	return nr;
   1.491+}
   1.492+
   1.493+readmsg(fd: ref Sys->FD): (array of byte, string)
   1.494+{
   1.495+	sbuf := array[BIT16SZ] of byte;
   1.496+	if((n := readn(fd, sbuf, BIT16SZ)) != BIT16SZ){
   1.497+		if(n == 0)
   1.498+			return (nil, nil);
   1.499+		return (nil, sys->sprint("%r"));
   1.500+	}
   1.501+	ml := (int sbuf[0] << 8) | int sbuf[1];
   1.502+	if(ml < BIT16SZ)
   1.503+		return (nil, "invalid venti message size");
   1.504+	buf := array[ml + BIT16SZ] of byte;
   1.505+	buf[0:] = sbuf;
   1.506+	if((n = readn(fd, buf[BIT16SZ:], ml)) != ml){
   1.507+		if(n == 0)
   1.508+			return (nil, "venti message truncated");
   1.509+		return (nil, sys->sprint("%r"));
   1.510+	}
   1.511+	return (buf, nil);
   1.512+}
   1.513+
   1.514+pstring(a: array of byte, o: int, s: string): int
   1.515+{
   1.516+	sa := array of byte s;	# could do conversion ourselves
   1.517+	n := len sa;
   1.518+	a[o] = byte (n >> 8);
   1.519+	a[o+1] = byte n;
   1.520+	a[o+2:] = sa;
   1.521+	return o+STR+n;
   1.522+}
   1.523+
   1.524+gstring(a: array of byte, o: int): (string, int)
   1.525+{
   1.526+	if(o < 0 || o+STR > len a)
   1.527+		return (nil, -1);
   1.528+	l := (int a[o] << 8) | int a[o+1];
   1.529+	if(l > Maxstringsize)
   1.530+		return (nil, -1);
   1.531+	o += STR;
   1.532+	e := o+l;
   1.533+	if(e > len a)
   1.534+		return (nil, -1);
   1.535+	return (string a[o:e], e);
   1.536+}
   1.537+
   1.538+gbytes(a: array of byte, o: int): (array of byte, int)
   1.539+{
   1.540+	if(o < 0 || o+1 > len a)
   1.541+		return (nil, -1);
   1.542+	n := int a[o];
   1.543+	if(1+n > len a)
   1.544+		return (nil, -1);
   1.545+	no := o+1+n;
   1.546+	return (a[o+1:no], no);
   1.547+}
   1.548+
   1.549+utflen(s: string): int
   1.550+{
   1.551+	# the domain is 16-bit unicode only, which is all that Inferno now implements
   1.552+	n := l := len s;
   1.553+	for(i:=0; i<l; i++)
   1.554+		if((c := s[i]) > 16r7F){
   1.555+			n++;
   1.556+			if(c > 16r7FF)
   1.557+				n++;
   1.558+		}
   1.559+	return n;
   1.560+}
   1.561+
   1.562+gtstring(a: array of byte, o: int, n: int): string
   1.563+{
   1.564+	e := o + n;
   1.565+	if(e > len a)
   1.566+		return nil;
   1.567+	for(i := o; i < e; i++)
   1.568+		if(a[i] == byte 0)
   1.569+			break;
   1.570+	return string a[o:i];
   1.571+}
   1.572+unpackroot(d: array of byte): ref Root
   1.573+{
   1.574+	if(len d != Rootsize){
   1.575+		sys->werrstr("root entry is wrong length");
   1.576+		return nil;
   1.577+	}
   1.578+	r := ref blankroot;
   1.579+	r.version = g16(d, 0);
   1.580+	if(r.version != Rootversion){
   1.581+		sys->werrstr("unknown root version");
   1.582+		return nil;
   1.583+	}
   1.584+	o := BIT16SZ;
   1.585+	r.name = gtstring(d, o, Rootnamelen);
   1.586+	o += Rootnamelen;
   1.587+	r.rtype = gtstring(d, o, Rootnamelen);
   1.588+	o += Rootnamelen;
   1.589+	r.score = gscore(d, o);
   1.590+	o += Scoresize;
   1.591+	r.blocksize = g16(d, o);
   1.592+	o += BIT16SZ;
   1.593+	r.prev = gscore(d, o);
   1.594+	return r;
   1.595+}
   1.596+
   1.597+unpackentry(d: array of byte): ref Entry
   1.598+{
   1.599+	if(len d != Entrysize){
   1.600+		sys->werrstr("entry is wrong length");
   1.601+		return nil;
   1.602+	}
   1.603+	e := ref blankentry;
   1.604+	i := 0;
   1.605+	e.gen = g32(d, i);
   1.606+	i += BIT32SZ;
   1.607+	e.psize = g16(d, i);
   1.608+	i += BIT16SZ;
   1.609+	e.dsize = g16(d, i);
   1.610+	i += BIT16SZ;
   1.611+	e.flags = int d[i];
   1.612+	e.depth= (e.flags & Entrydepthmask) >> Entrydepthshift;
   1.613+	e.flags &= ~Entrydepthmask;
   1.614+	i += BIT8SZ;
   1.615+	i += 5;			# skip something...
   1.616+	e.size = g48(d, i);
   1.617+	i += BIT48SZ;
   1.618+	e.score = gscore(d, i);
   1.619+	i += Scoresize;
   1.620+	if((e.flags & Entryactive) == 0)
   1.621+		return e;
   1.622+	if(!checksize(e.psize) || !checksize(e.dsize)){
   1.623+		sys->werrstr(sys->sprint("bad blocksize (%d or %d)", e.psize, e.dsize));
   1.624+		return nil;
   1.625+	}
   1.626+	return e;
   1.627+}
   1.628+
   1.629+checksize(n: int): int
   1.630+{
   1.631+	if(n < 256 || n > Maxlumpsize) {
   1.632+		sys->werrstr("bad block size");
   1.633+		return 0;
   1.634+	}
   1.635+	return 1;
   1.636+}
   1.637+
   1.638+gscore(f: array of byte, i: int): Score
   1.639+{
   1.640+	s := Score(array[Scoresize] of byte);
   1.641+	s.a[0:] = f[i:i+Scoresize];
   1.642+	return s;
   1.643+}
   1.644+
   1.645+g16(f: array of byte, i: int): int
   1.646+{
   1.647+	return (int f[i] << 8) | int f[i+1];
   1.648+}
   1.649+
   1.650+g32(f: array of byte, i: int): int
   1.651+{
   1.652+	return (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
   1.653+}
   1.654+
   1.655+g48(f: array of byte, i: int): big
   1.656+{
   1.657+	b1 := (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
   1.658+	b0 := (int f[i+4] << 8) | int f[i+5];
   1.659+	return (big b1 << 16) | big b0;
   1.660+}
   1.661+
   1.662+g64(f: array of byte, i: int): big
   1.663+{
   1.664+	b0 := (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
   1.665+	b1 := (((((int f[i+4] << 8) | int f[i+5]) << 8) | int f[i+6]) << 8) | int f[i+7];
   1.666+	return (big b0 << 32) | (big b1 & 16rFFFFFFFF);
   1.667+}
     2.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2+++ b/man/2/venti	Fri Aug 17 21:38:38 2007 +0200
     2.3@@ -0,0 +1,107 @@
     2.4+.TH VENTI 2
     2.5+.SH NAME
     2.6+Venti \- access to Venti content-addressed filestore.
     2.7+.SH SYNOPSIS
     2.8+.EX
     2.9+include "venti.m";
    2.10+venti := load Venti Venti->PATH;
    2.11+Session: import venti;
    2.12+
    2.13+init:			fn();
    2.14+unpackentry:	fn(d: array of byte): ref Entry;
    2.15+unpackroot:	fn(d: array of byte): ref Root;
    2.16+
    2.17+Session: adt {
    2.18+	new:		fn(fd: ref Sys->FD): ref Session;
    2.19+	read:		fn(s: self ref Session, score: Venti->Score, etype: int, maxn: int): array of byte;
    2.20+	write:	fn(s: self ref Session, etype: int, buf: array of byte): (int, Venti->Score);
    2.21+	sync:	fn(s: self ref Session): int;
    2.22+};
    2.23+
    2.24+Score: adt {
    2.25+	a: array of byte;
    2.26+	eq:		fn(a: self Score, b: Score): int;
    2.27+	text:		fn(a: self Score): string;
    2.28+	parse:	fn(s: string): (int, Score);
    2.29+	zero:		fn(): Score;
    2.30+};
    2.31+
    2.32+.EE
    2.33+.SH DESCRIPTION
    2.34+.I Venti
    2.35+is a block storage server intended for archival applications.
    2.36+The
    2.37+.I Venti
    2.38+module provides low-level access to a Venti server.
    2.39+The module assumes that the physical connection
    2.40+to the server has already been established
    2.41+(for example, by
    2.42+.IR dial (2)).
    2.43+On a Venti server, a block is addressed by the SHA1 hash of
    2.44+the contents of that block, known as a
    2.45+.IR score ,
    2.46+and represented as a
    2.47+.B Score
    2.48+adt.
    2.49+Blocks are additionally tagged with a
    2.50+.IR type ,
    2.51+facilitating recovery in the event of corruption.
    2.52+A
    2.53+.B Session
    2.54+represents an session with a Venti server.
    2.55+.TP
    2.56+.IB s .new(\fIfd\fP)
    2.57+.B New
    2.58+performs the initial handshake with the Venti server,
    2.59+returning established
    2.60+.BR Session .
    2.61+.TP
    2.62+.IB s .read(\fIscore\fP,\ \fIetype\fP,\ \fImaxn\fP)
    2.63+.B Read
    2.64+tries to retrieve the block
    2.65+corresponding to
    2.66+.IR score ,
    2.67+and of type
    2.68+.IR etype .
    2.69+The block must be no longer than
    2.70+.I maxn
    2.71+bytes.
    2.72+.I Etype
    2.73+is conventionally one of the constants
    2.74+.BR Roottype ,
    2.75+.BR Dirtype ,
    2.76+.BR Datatype
    2.77+or
    2.78+.BR Pointertype [0-9],
    2.79+where the different
    2.80+.BR Pointertype s
    2.81+represent different depth levels within a Venti tree.
    2.82+.TP
    2.83+.IB s .write(\fIetype\fP,\ \fIbuf\fP)
    2.84+.B Write
    2.85+writes the data in
    2.86+.I buf
    2.87+to the Venti server.
    2.88+The block will be tagged with type
    2.89+.IR etype .
    2.90+It returns a tuple, say
    2.91+.RI ( ok ,\  score );
    2.92+on error,
    2.93+.I ok
    2.94+is -1, otherwise
    2.95+.I ok
    2.96+is 0 and
    2.97+.I score
    2.98+contains the Venti score for the block that has been written.
    2.99+.TP
   2.100+.IB s .sync()
   2.101+.B Sync
   2.102+tells the Venti server to make sure that all data is committed to
   2.103+active storage.
   2.104+.SH SOURCE
   2.105+.B /appl/lib/venti.b
   2.106+.SH BUGS
   2.107+to do: 
   2.108+Score adt
   2.109+entry packing/unpacking
   2.110+other Vmsgs, Session.rpc()?