forsyth20121205-174063a80cc13 years agoHistory
1012 lines · 21.0 KB · Brainfuck
RawDownload
implement Vac; include "sys.m";	sys: Sys;	sprint: import sys;include "venti.m";	venti: Venti;	Entrysize, Scoresize, Roottype, Dirtype, Pointertype0, Datatype: import venti;	Root, Entry, Score, Session: import venti;include "vac.m";  dflag = 0; BIT8SZ:	con 1;BIT16SZ:        con 2;BIT32SZ:        con 4;BIT48SZ:        con 6;BIT64SZ:	con 8; Rootnamelen:	con 128;Rootversion:	con 2;Direntrymagic:	con 16r1c4d9072;Metablockmagic:	con 16r5656fc79;Maxstringsize: con 1000; blankroot: Root;blankentry: Entry;blankdirentry: Direntry;blankmetablock: Metablock;blankmetaentry: Metaentry; init(){	sys = load Sys Sys->PATH;	venti = load Venti Venti->PATH;	venti->init();} Direntry.new(): ref Direntry{	return ref Direntry(9, "", 0, 0, 0, 0, big 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, big 0, big 0);} Direntry.mk(d: Sys->Dir): ref Direntry{	atime := 0; # d.atime;	mode := d.mode&Modeperm;	if(d.mode&sys->DMAPPEND)		mode |= Modeappend;	if(d.mode&sys->DMEXCL)		mode |= Modeexcl;	if(d.mode&sys->DMDIR)		mode |= Modedir;	if(d.mode&sys->DMTMP)		mode |= Modetemp;	return ref Direntry(9, d.name, 0, 0, 0, 0, d.qid.path, d.uid, d.gid, d.muid, d.mtime, 0, 0, atime, mode, d.mode, 0, big 0, big 0);} Direntry.mkdir(de: self ref Direntry): ref Sys->Dir{        d := ref sys->nulldir;        d.name = de.elem;        d.uid = de.uid;        d.gid = de.gid;        d.muid = de.mid;        d.qid.path = de.qid;        d.qid.vers = 0;        d.qid.qtype = de.emode>>24;        d.mode = de.emode;        d.atime = de.atime;        d.mtime = de.mtime;        d.length = big 0;        return d;} strlen(s: string): int{	return 2+len array of byte s;} Direntry.pack(de: self ref Direntry): array of byte{	if(de.version != 9) {		sys->werrstr("only version 9 supported");		return nil;	}			length := 4+2+strlen(de.elem)+4+4+4+4+8+strlen(de.uid)+strlen(de.gid)+strlen(de.mid)+4+4+4+4+4;	if(de.qidspace)		length += 1+2+8+8; 	d := array[length] of byte;	i := 0;	i = p32(d, i, Direntrymagic);	i = p16(d, i, de.version);	i = pstring(d, i, de.elem);	i = p32(d, i, de.entry);	if(de.version == 9) {		i = p32(d, i, de.gen);		i = p32(d, i, de.mentry);		i = p32(d, i, de.mgen);	}	i = p64(d, i, de.qid);	i = pstring(d, i, de.uid);	i = pstring(d, i, de.gid);	i = pstring(d, i, de.mid);	i = p32(d, i, de.mtime);	i = p32(d, i, de.mcount);	i = p32(d, i, de.ctime);	i = p32(d, i, de.atime);	i = p32(d, i, de.mode);	if(de.qidspace) {		d[i++] = byte DirQidspace;		i = p16(d, i, 16);		i = p64(d, i, de.qidoff);		i = p64(d, i, de.qidmax);	}	if(i != len d) {		sys->werrstr(sprint("bad length for direntry (expected %d, have %d)", len d, i));		return nil;	}	return d;} Direntry.unpack(d: array of byte): ref Direntry{	{		de := ref blankdirentry;		i := 0;		magic: int;		(magic, i) = eg32(d, i);		if(magic != Direntrymagic) {			sys->werrstr(sprint("bad magic (%x, want %x)", magic, Direntrymagic));			return nil;		}		(de.version, i) = eg16(d, i);		if(de.version != 8 && de.version != 9) {			sys->werrstr(sprint("bad version (%d)", de.version));			return nil;		}		(de.elem, i) = egstring(d, i);		(de.entry, i) = eg32(d, i);		case de.version {		8 =>			de.gen = 0;			de.mentry = de.entry+1;			de.mgen = 0;		9 =>			(de.gen, i) = eg32(d, i);			(de.mentry, i) = eg32(d, i);			(de.mgen, i) = eg32(d, i);		}		(de.qid, i) = eg64(d, i);		(de.uid, i) = egstring(d, i);		(de.gid, i) = egstring(d, i);		(de.mid, i) = egstring(d, i);		(de.mtime, i) = eg32(d, i);		(de.mcount, i) = eg32(d, i);		(de.ctime, i) = eg32(d, i);		(de.atime, i) = eg32(d, i);		(de.mode, i) = eg32(d, i);		de.emode = de.mode&Modeperm;		if(de.mode&Modeappend)			de.emode |= sys->DMAPPEND;		if(de.mode&Modeexcl)			de.emode |= sys->DMEXCL;		if(de.mode&Modedir)			de.emode |= sys->DMDIR;		if(de.mode&Modetemp)			de.emode |= sys->DMTMP;		while(i < len d) {			t := int d[i++];			n: int;			(n, i) = eg16(d, i);			case t {			DirQidspace =>				if(n != 16) {					sys->werrstr(sprint("invalid qidspace length %d", n));					return nil;				}				de.qidspace = 1;				(de.qidoff, i) = eg64(d, i);				(de.qidmax, i) = eg64(d, i);			* =>				# ignore other optional fields				i += n;			}		}		return de;	} exception e {	"too small:*" =>		sys->werrstr("direntry "+e);		return nil;	* =>		raise e;	}}  Metablock.new(): ref Metablock{	return ref Metablock(0, 0, 0, 0);} Metablock.pack(mb: self ref Metablock, d: array of byte){	i := 0;	i = p32(d, i, Metablockmagic);	i = p16(d, i, mb.size);	i = p16(d, i, mb.free);	i = p16(d, i, mb.maxindex);	i = p16(d, i, mb.nindex);} Metablock.unpack(d: array of byte): ref Metablock{	if(len d < Metablocksize) {		sys->werrstr(sprint("bad length for metablock (%d, want %d)", len d, Metablocksize));		return nil;	}	i := 0;	magic := g32(d, i);	if(magic != Metablockmagic && magic != Metablockmagic+1) {		sys->werrstr(sprint("bad magic for metablock (%x, need %x)", magic, Metablockmagic));		return nil;	}	i += BIT32SZ; 	mb := ref blankmetablock;	mb.size = g16(d, i);	i += BIT16SZ;	mb.free = g16(d, i);	i += BIT16SZ;	mb.maxindex = g16(d, i);	i += BIT16SZ;	mb.nindex = g16(d, i);	i += BIT16SZ;	if(mb.nindex == 0) {		sys->werrstr("bad metablock, nindex=0");		return nil;	}	return mb;} Metaentry.pack(me: self ref Metaentry, d: array of byte){	i := 0;	i = p16(d, i, me.offset);	i = p16(d, i, me.size);} Metaentry.unpack(d: array of byte, i: int): ref Metaentry{	o := Metablocksize+i*Metaentrysize;	if(o+Metaentrysize > len d) {		sys->werrstr(sprint("meta entry lies outside meta block, i=%d", i));		return nil;	} 	me := ref blankmetaentry;	me.offset = g16(d, o);	o += BIT16SZ;	me.size = g16(d, o);	o += BIT16SZ;	if(me.offset+me.size > len d) {		sys->werrstr(sprint("meta entry points outside meta block, i=%d", i));		return nil;	}	return me;}  Page.new(dsize: int): ref Page{	psize := (dsize/Scoresize)*Scoresize;	return ref Page(array[psize] of byte, 0);} Page.add(p: self ref Page, s: Score){	for(i := 0; i < Scoresize; i++)		p.d[p.o+i] = s.a[i];	p.o += Scoresize;} Page.full(p: self ref Page): int{	return p.o+Scoresize > len p.d;} Page.data(p: self ref Page): array of byte{	for(i := p.o; i >= Scoresize; i -= Scoresize)		if(!Score(p.d[i-Scoresize:i]).eq(Score.zero()))			break;	return p.d[:i];}  File.new(s: ref Session, dtype, dsize: int): ref File{	p := array[1] of ref Page;	p[0] = Page.new(dsize);	return ref File(p, dtype, dsize, big 0, s);} fflush(f: ref File, last: int): (int, ref Entry){	for(i := 0; i < len f.p; i++) {		if(!last && !f.p[i].full())			return (0, nil);		if(last && f.p[i].o == Scoresize) {			flags := venti->Entryactive;			if(f.dtype == Dirtype)				flags |= venti->Entrydir;			flags |= i<<venti->Entrydepthshift;			score := Score(f.p[i].data());			if(len score.a == 0)				score = Score.zero();			return (0, ref Entry(0, len f.p[i].d, f.dsize, i, flags, f.size, score));		}		(ok, score) := f.s.write(Pointertype0+i, f.p[i].data());		if(ok < 0)			return (-1, nil);		f.p[i] = Page.new(f.dsize);		if(i+1 == len f.p) {			newp := array[len f.p+1] of ref Page;			newp[:] = f.p;			newp[len newp-1] = Page.new(f.dsize);			f.p = newp;		}		f.p[i+1].add(score);	}	sys->werrstr("internal error in fflush");	return (-1, nil);} File.write(f: self ref File, d: array of byte): int{	(fok, nil) := fflush(f, 0);	if(fok < 0)		return -1;	length := len d;	for(i := len d; i > 0; i--)		if(d[i-1] != byte 0)			break;	d = d[:i];	(ok, score) := f.s.write(f.dtype, d);	if(ok < 0)		return -1;	f.size += big length;	f.p[0].add(score);	return 0;} File.finish(f: self ref File): ref Entry{	(ok, e) := fflush(f, 1);	if(ok < 0)		return nil;	return e;}  Sink.new(s: ref Venti->Session, dsize: int): ref Sink{	dirdsize := (dsize/Entrysize)*Entrysize;	return ref Sink(File.new(s, Dirtype, dsize), array[dirdsize] of byte, 0, 0);} Sink.add(m: self ref Sink, e: ref Entry): int{	ed := e.pack();	if(ed == nil)		return -1;	n := len m.d - m.nd;	if(n > len ed)		n = len ed;	m.d[m.nd:] = ed[:n];	m.nd += n;	if(n < len ed) {		if(m.f.write(m.d) < 0)			return -1;		m.nd = len ed - n;		m.d[:] = ed[n:];	}	return m.ne++;} Sink.finish(m: self ref Sink): ref Entry{	if(m.nd > 0)		if(m.f.write(m.d[:m.nd]) < 0)			return nil;	e := m.f.finish();	e.dsize = len m.d;	return e;}  elemcmp(a, b: array of byte, fossil: int): int{	for(i := 0; i < len a && i < len b; i++)		if(a[i] != b[i])			return (int a[i] - int b[i]);	if(fossil)		return len a - len b;	return len b - len a;} Mentry.cmp(a, b: ref Mentry): int{	return elemcmp(array of byte a.elem, array of byte b.elem, 0);} MSink.new(s: ref Venti->Session, dsize: int): ref MSink{	return ref MSink(File.new(s, Datatype, dsize), array[dsize] of byte, 0, nil);} l2a[T](l: list of T): array of T{	a := array[len l] of T;	i := 0;	for(; l != nil; l = tl l)		a[i++] = hd l;	return a;} insertsort[T](a: array of T)	for { T =>	cmp:	fn(a, b: T): int; }{	for(i := 1; i < len a; i++) {		tmp := a[i];		for(j := i; j > 0 && T.cmp(a[j-1], tmp) > 0; j--)			a[j] = a[j-1];		a[j] = tmp;	}} mflush(m: ref MSink, last: int): int{	d := array[len m.de] of byte; 	me := l2a(m.l);	insertsort(me);	o := Metablocksize;	deo := o+len m.l*Metaentrysize;	for(i := 0; i < len me; i++) {		me[i].me.offset += deo;		me[i].me.pack(d[o:]);		o += Metaentrysize;	}	d[o:] = m.de[:m.nde];	o += m.nde;	if(!last)		while(o < len d)			d[o++] = byte 0; 	mb := Metablock.new();	mb.nindex = len m.l;	mb.maxindex = mb.nindex;	mb.free = 0;	mb.size = o;	mb.pack(d); 	if(m.f.write(d[:o]) < 0)		return -1;	m.nde = 0;	m.l = nil;	return 0;} MSink.add(m: self ref MSink, de: ref Direntry): int{	d := de.pack();	if(d == nil)		return -1;if(dflag) say(sprint("msink: adding direntry, length %d", len d));	if(Metablocksize+len m.l*Metaentrysize+m.nde + Metaentrysize+len d > len m.de)		if(mflush(m, 0) < 0)			return -1;	m.de[m.nde:] = d;	m.l = ref Mentry(de.elem, ref Metaentry(m.nde, len d))::m.l;	m.nde += len d;	return 0;} MSink.finish(m: self ref MSink): ref Entry{	if(m.nde > 0)		mflush(m, 1);	return m.f.finish();} Source.new(s: ref Session, e: ref Entry): ref Source{	dsize := e.dsize;	if(e.flags&venti->Entrydir)

Lines 1–500 of 1012.