Commit Diff


commit - 01cea2ecb8c0b101a22e7883d87fbf1d28a03043
commit + 64f9764ea9f958a1abc7a32424f43019723e9e53
blob - c8d68bd7921096c568240c7a58e9fd94efd144d5 (mode 644)
blob + /dev/null
--- src/cmd/vac/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This is somewhat untested but is believed to work.
-
blob - 5f177d65e2a0a1f3d07dda7a1718c13fbe9614ac
blob + 5e51c84ab7a3581fa1b2fe44e3ae1ccfd06ffdbc
--- src/cmd/vac/file.c
+++ src/cmd/vac/file.c
@@ -563,8 +563,6 @@ vacfileread(VacFile *f, void *buf, int cnt, vlong offs
 	int off, dsize, n, nn;
 	VtBlock *b;
 	uchar *p;
-
-if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);
 
 	if(filerlock(f) < 0)
 		return -1;
@@ -617,66 +615,8 @@ Err:
 	vtfileunlock(s);
 Err1:
 	filerunlock(f);
-	return -1;
-}
-
-#if 0
-/* 
- * Changes the file block bn to be the given block score.
- * Very sneaky.  Only used by flfmt.
- */
-int
-filemapblock(VacFile *f, ulong bn, uchar score[VtScoreSize], ulong tag)
-{
-	VtBlock *b;
-	VtEntry e;
-	VtFile *s;
-
-	if(filelock(f) < 0)
-		return -1;
-
-	s = nil;
-	if(f->dir.mode & ModeDir){
-		werrstr(ENotFile);
-		goto Err;
-	}
-
-	if(f->source->mode != VtORDWR){
-		werrstr(EReadOnly);
-		goto Err;
-	}
-
-	if(vtfilelock(f->source, -1) < 0)
-		goto Err;
-
-	s = f->source;
-	b = _vtfileblock(s, bn, VtORDWR, 1, tag);
-	if(b == nil)
-		goto Err;
-
-	if(vtfilegetentry(s, &e) < 0)
-		goto Err;
-	if(b->l.type == BtDir){
-		memmove(e.score, score, VtScoreSize);
-		assert(e.tag == tag || e.tag == 0);
-		e.tag = tag;
-		e.flags |= VtEntryLocal;
-		vtentrypack(&e, b->data, f->source->offset % f->source->epb);
-	}else
-		memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize);
-	/* vtblockdirty(b); */
-	vtblockput(b);
-	vtfileunlock(s);
-	fileunlock(f);
-	return 0;
-
-Err:
-	if(s)
-		vtfileunlock(s);
-	fileunlock(f);
 	return -1;
 }
-#endif
 
 int
 vacfilesetsize(VacFile *f, uvlong size)
@@ -713,8 +653,6 @@ filewrite(VacFile *f, void *buf, int cnt, vlong offset
 	uchar *p;
 	vlong eof;
 
-if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);
-
 	if(filelock(f) < 0)
 		return -1;
 
@@ -1064,7 +1002,7 @@ vacfilemetaflush(VacFile *f, int rec)
 	vtfree(kids);
 }
 
-/* assumes metaLock is held */
+/* assumes metalock is held */
 static int
 filemetaflush2(VacFile *f, char *oelem)
 {
@@ -1097,15 +1035,14 @@ filemetaflush2(VacFile *f, char *oelem)
 	if(mbsearch(&mb, oelem, &i, &me) < 0)
 		goto Err;
 
-	n = vdsize(&f->dir);
-if(0)fprint(2, "old size %d new size %d\n", me.size, n);
+	n = vdsize(&f->dir, VacDirVersion);
 
 	if(mbresize(&mb, &me, n) >= 0){
 		/* fits in the block */
 		mbdelete(&mb, i, &me);
 		if(strcmp(f->dir.elem, oelem) != 0)
 			mbsearch(&mb, f->dir.elem, &i, &me2);
-		vdpack(&f->dir, &me);
+		vdpack(&f->dir, &me, VacDirVersion);
 		mbinsert(&mb, i, &me);
 		mbpack(&mb);
 		/* vtblockdirty(b); */
@@ -1126,19 +1063,17 @@ if(0)fprint(2, "old size %d new size %d\n", me.size, n
 	 */
 	boff = filemetaalloc(fp, &f->dir, f->boff+1);
 	if(boff == NilBlock){
-		/* mbResize might have modified block */
+		/* mbresize might have modified block */
 		mbpack(&mb);
 		/* vtblockdirty(b); */
 		goto Err;
 	}
-fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
 	f->boff = boff;
 
 	/* make sure deletion goes to disk after new entry */
 	bb = vtfileblock(fp->msource, f->boff, VtORDWR);
 	mbdelete(&mb, i, &me);
 	mbpack(&mb);
-/*	blockDependency(b, bb, -1, nil, nil); */
 	vtblockput(bb);
 	/* vtblockdirty(b); */
 	vtblockput(b);
@@ -1520,6 +1455,16 @@ Return:
 	if(didread)
 		fileraccess(f);
 	return ret;
+}
+
+int
+vdeunread(VacDirEnum *vde)
+{
+	if(vde->i > 0){
+		vde->i--;
+		return 0;
+	}
+	return -1;
 }
 
 void
@@ -1555,7 +1500,7 @@ filemetaalloc(VacFile *f, VacDir *dir, u32int start)
 	s = f->source;
 	ms = f->msource;
 
-	n = vdsize(dir);
+	n = vdsize(dir, VacDirVersion);
 	nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
 	b = nil;
 	if(start > nb)
@@ -1584,9 +1529,8 @@ filemetaalloc(VacFile *f, VacDir *dir, u32int start)
 
 	p = mballoc(&mb, n);
 	if(p == nil){
-		/* mbAlloc might have changed block */
+		/* mballoc might have changed block */
 		mbpack(&mb);
-		/* vtblockdirty(b); */
 		werrstr(EBadMeta);
 		goto Err;
 	}
@@ -1595,29 +1539,10 @@ filemetaalloc(VacFile *f, VacDir *dir, u32int start)
 	assert(me.p == nil);
 	me.p = p;
 	me.size = n;
-	vdpack(dir, &me);
+	vdpack(dir, &me, VacDirVersion);
 	mbinsert(&mb, i, &me);
 	mbpack(&mb);
 
-#ifdef notdef /* XXX */
-	/* meta block depends on super block for qid ... */
-	bb = cacheLocal(b->c, PartSuper, 0, VtOREAD);
-	blockDependency(b, bb, -1, nil, nil);
-	vtblockput(bb);
-
-	/* ... and one or two dir entries */
-	epb = s->dsize/VtEntrySize;
-	bb = vtfileblock(s, dir->entry/epb, VtOREAD);
-	blockDependency(b, bb, -1, nil, nil);
-	vtblockput(bb);
-	if(dir->mode & ModeDir){
-		bb = sourceBlock(s, dir->mentry/epb, VtOREAD);
-		blockDependency(b, bb, -1, nil, nil);
-		vtblockput(bb);
-	}
-#endif
-
-	/* vtblockdirty(b); */
 	vtblockput(b);
 	return bo;
 Err:
@@ -1676,7 +1601,7 @@ fileunlock(VacFile *f)
 
 /*
  * f->source and f->msource must NOT be locked.
- * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
+ * vacfilemetaflush locks the filemeta and then the source (in filemetaflush2).
  * We have to respect that ordering.
  */
 static void
@@ -1734,132 +1659,5 @@ filewaccess(VacFile* f, char *mid)
 	if(f->up)
 		filewaccess(f->up, mid);
 */
-}
-
-#if 0
-static void
-markCopied(Block *b)
-{
-	VtBlock *lb;
-	Label l;
-
-	if(globalToLocal(b->score) == NilBlock)
-		return;
-
-	if(!(b->l.state & BsCopied)){
-		/*
-		 * We need to record that there are now pointers in
-		 * b that are not unique to b.  We do this by marking
-		 * b as copied.  Since we don't return the label block,
-		 * the caller can't get the dependencies right.  So we have
-		 * to flush the block ourselves.  This is a rare occurrence.
-		 */
-		l = b->l;
-		l.state |= BsCopied;
-		lb = _blockSetLabel(b, &l);
-	WriteAgain:
-		while(!blockWrite(lb)){
-			fprint(2, "getEntry: could not write label block\n");
-			sleep(10*1000);
-		}
-		while(lb->iostate != BioClean && lb->iostate != BioDirty){
-			assert(lb->iostate == BioWriting);
-			vtSleep(lb->ioready);
-		}
-		if(lb->iostate == BioDirty)
-			goto WriteAgain;
-		vtblockput(lb);
-	}
 }
 
-static int
-getEntry(VtFile *r, Entry *e, int mark)
-{
-	Block *b;
-
-	if(r == nil){
-		memset(&e, 0, sizeof e);
-		return 1;
-	}
-
-	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtOREAD);
-	if(b == nil)
-		return 0;
-	if(!entryUnpack(e, b->data, r->offset % r->epb)){
-		vtblockput(b);
-		return 0;
-	}
-
-	if(mark)
-		markCopied(b);
-	vtblockput(b);
-	return 1;
-}
-
-static int
-setEntry(Source *r, Entry *e)
-{
-	Block *b;
-	Entry oe;
-
-	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtORDWR);
-	if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
-	if(b == nil)
-		return 0;
-	if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
-		vtblockput(b);
-		return 0;
-	}
-	e->gen = oe.gen;
-	entryPack(e, b->data, r->offset % r->epb);
-
-	/* BUG b should depend on the entry pointer */
-
-	markCopied(b);
-	/* vtblockdirty(b); */
-	vtblockput(b);
-	return 1;
-}
-
-/* assumes hold elk */
-int
-fileSnapshot(VacFile *dst, VacFile *src, u32int epoch, int doarchive)
-{
-	Entry e, ee;
-
-	/* add link to snapshot */
-	if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
-		return 0;
-
-	e.snap = epoch;
-	e.archive = doarchive;
-	ee.snap = epoch;
-	ee.archive = doarchive;
-
-	if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
-		return 0;
-	return 1;
-}
-
-int
-fileGetSources(VacFile *f, Entry *e, Entry *ee, int mark)
-{
-	if(!getEntry(f->source, e, mark)
-	|| !getEntry(f->msource, ee, mark))
-		return 0;
-	return 1;
-}	
-
-int
-fileWalkSources(VacFile *f)
-{
-	if(f->mode == VtOREAD)
-		return 1;
-	if(!sourceLock2(f->source, f->msource, VtORDWR))
-		return 0;
-	vtfileunlock(f->source);
-	vtfileunlock(f->msource);
-	return 1;
-}
-
-#endif
blob - 335d85c96322a06dc0e0c17b04bb4b5e6f9e15a4
blob + afcb7f7b9e2eb4aa7618617b55d674996cddb274
--- src/cmd/vac/fns.h
+++ src/cmd/vac/fns.h
@@ -8,9 +8,13 @@ int	meunpack(MetaEntry*, MetaBlock *mb, int i);
 int	mecmp(MetaEntry*, char *s);
 int	mecmpnew(MetaEntry*, char *s);
 
-int	vdsize(VacDir *dir);
+enum {
+	VacDirVersion = 8,
+	FossilDirVersion = 9,
+};
+int	vdsize(VacDir *dir, int);
 int	vdunpack(VacDir *dir, MetaEntry*);
-void	vdpack(VacDir *dir, MetaEntry*);
+void	vdpack(VacDir *dir, MetaEntry*, int);
 
 VacFile *_vacfileroot(VacFs *fs, VtFile *file);
 
blob - 1f8d99958612cb60b242510aa39e3603cb9879a1
blob + 02f437e0ab0992fe99960f8feca4bd761c19f80b
--- src/cmd/vac/mkfile
+++ src/cmd/vac/mkfile
@@ -16,7 +16,7 @@ HFILES=\
 	dat.h\
 	fns.h\
 
-TARG=vac vacfs # vtdump
+TARG=vac vacfs unvac # vtdump
 
 default:V: all
 
blob - 319cb4636104edeb6686b241f7abc3d94690c2a1
blob + 79811dfe60ba9cc6763851b96758f4174bbc05b2
--- src/cmd/vac/pack.c
+++ src/cmd/vac/pack.c
@@ -200,7 +200,7 @@ if(0)print("eo = %d en = %d\n", eo, en);
 	return 0;
 }
 
-/* assumes a small amount of checking has been done in mbEntry */
+/* assumes a small amount of checking has been done in mbentry */
 int
 mecmp(MetaEntry *me, char *s)
 {
@@ -372,18 +372,17 @@ mballoc(MetaBlock *mb, int n)
 }
 
 int
-vdsize(VacDir *dir)
+vdsize(VacDir *dir, int version)
 {
 	int n;
 	
-	/* constant part */
+	if(version < 8 || version > 9)
+		sysfatal("bad version %d in vdpack", version);
 
+	/* constant part */
 	n = 	4 +	/* magic */
 		2 + 	/* version */
 		4 +	/* entry */
-		4 + 	/* guid */
-		4 + 	/* mentry */
-		4 + 	/* mgen */
 		8 +	/* qid */
 		4 + 	/* mtime */
 		4 + 	/* mcount */
@@ -392,6 +391,13 @@ vdsize(VacDir *dir)
 		4 +	/* mode */
 		0;
 
+	if(version == 9){
+		n += 	4 +	/* gen */
+			4 + 	/* mentry */
+			4 + 	/* mgen */
+			0;
+	}
+
 	/* strings */
 	n += 2 + strlen(dir->elem);
 	n += 2 + strlen(dir->uid);
@@ -399,36 +405,54 @@ vdsize(VacDir *dir)
 	n += 2 + strlen(dir->mid);
 
 	/* optional sections */
+	if(version < 9 && dir->plan9) {
+		n += 	3 + 	/* option header */
+			8 + 	/* path */
+			4;	/* version */
+	}
 	if(dir->qidspace) {
 		n += 	3 + 	/* option header */
 			8 + 	/* qid offset */
 			8;	/* qid max */
 	}
+	if(version < 9 && dir->gen) {
+		n += 	3 + 	/* option header */
+			4;	/* gen */
+	}
 
 	return n;
 }
 
 void
-vdpack(VacDir *dir, MetaEntry *me)
+vdpack(VacDir *dir, MetaEntry *me, int version)
 {
 	uchar *p;
 	ulong t32;
 
+	if(version < 8 || version > 9)
+		sysfatal("bad version %d in vdpack", version);
+
 	p = me->p;
 	
 	U32PUT(p, DirMagic);
-	U16PUT(p+4, 9);		/* version */
+	U16PUT(p+4, version);		/* version */
 	p += 6;
 
 	p += stringpack(dir->elem, p);
 
 	U32PUT(p, dir->entry);
-	U32PUT(p+4, dir->gen);
-	U32PUT(p+8, dir->mentry);
-	U32PUT(p+12, dir->mgen);
-	U64PUT(p+16, dir->qid, t32);
-	p += 24;
+	p += 4;
+	
+	if(version == 9){
+		U32PUT(p, dir->gen);
+		U32PUT(p+4, dir->mentry);
+		U32PUT(p+8, dir->mgen);
+		p += 12;
+	}
 
+	U64PUT(p, dir->qid, t32);
+	p += 8;
+
 	p += stringpack(dir->uid, p);
 	p += stringpack(dir->gid, p);
 	p += stringpack(dir->mid, p);
@@ -439,6 +463,15 @@ vdpack(VacDir *dir, MetaEntry *me)
 	U32PUT(p+12, dir->atime);
 	U32PUT(p+16, dir->mode);
 	p += 5*4;
+	
+	if(dir->plan9 && version < 9) {
+		U8PUT(p, DirPlan9Entry);
+		U16PUT(p+1, 8+4);
+		p += 3;
+		U64PUT(p, dir->p9path, t32);
+		U32PUT(p+8, dir->p9version);
+		p += 12;
+	}
 
 	if(dir->qidspace) {
 		U8PUT(p, DirQidSpaceEntry);
@@ -446,12 +479,20 @@ vdpack(VacDir *dir, MetaEntry *me)
 		p += 3;
 		U64PUT(p, dir->qidoffset, t32);
 		U64PUT(p+8, dir->qidmax, t32);
+		p += 16;
+	}
+	
+	if(dir->gen && version < 9) {
+		U8PUT(p, DirGenEntry);
+		U16PUT(p+1, 4);
+		p += 3;
+		U32PUT(p, dir->gen);
+		p += 4;
 	}
 
 	assert(p == me->p + me->size);
 }
 
-
 int
 vdunpack(VacDir *dir, MetaEntry *me)
 {
@@ -463,14 +504,12 @@ vdunpack(VacDir *dir, MetaEntry *me)
 
 	memset(dir, 0, sizeof(VacDir));
 
-if(0)print("vdUnpack\n");
 	/* magic */
 	if(n < 4 || U32GET(p) != DirMagic)
 		goto Err;
 	p += 4;
 	n -= 4;
 
-if(0)print("vdUnpack: got magic\n");
 	/* version */
 	if(n < 2)
 		goto Err;
@@ -480,13 +519,9 @@ if(0)print("vdUnpack: got magic\n");
 	p += 2;
 	n -= 2;	
 
-if(0)print("vdUnpack: got version\n");
-
 	/* elem */
 	if(stringunpack(&dir->elem, &p, &n) < 0)
 		goto Err;
-
-if(0)print("vdUnpack: got elem\n");
 
 	/* entry  */
 	if(n < 4)
@@ -495,8 +530,6 @@ if(0)print("vdUnpack: got elem\n");
 	p += 4;
 	n -= 4;
 
-if(0)print("vdUnpack: got entry\n");
-
 	if(version < 9) {
 		dir->gen = 0;
 		dir->mentry = dir->entry+1;
@@ -511,8 +544,6 @@ if(0)print("vdUnpack: got entry\n");
 		n -= 3*4;
 	}
 
-if(0)print("vdUnpack: got gen etc\n");
-
 	/* size is gotten from DirEntry */
 
 	/* qid */
@@ -522,7 +553,6 @@ if(0)print("vdUnpack: got gen etc\n");
 	p += 8;
 	n -= 8;
 
-if(0)print("vdUnpack: got qid\n");
 	/* skip replacement */
 	if(version == 7) {
 		if(n < VtScoreSize)
@@ -543,7 +573,6 @@ if(0)print("vdUnpack: got qid\n");
 	if(stringunpack(&dir->mid, &p, &n) < 0)
 		goto Err;
 
-if(0)print("vdUnpack: got ids\n");
 	if(n < 5*4)
 		goto Err;
 	dir->mtime = U32GET(p);
@@ -554,7 +583,6 @@ if(0)print("vdUnpack: got ids\n");
 	p += 5*4;
 	n -= 5*4;
 
-if(0)print("vdUnpack: got times\n");
 	/* optional meta data */
 	while(n > 0) {
 		if(n < 3)
@@ -594,15 +622,12 @@ if(0)print("vdUnpack: got times\n");
 		p += nn;
 		n -= nn;
 	}
-if(0)print("vdUnpack: got options\n");
 
 	if(p != me->p + me->size)
 		goto Err;
 
-if(0)print("vdUnpack: correct size\n");
 	return 0;
 Err:
-if(0)print("vdUnpack: XXXXXXXXXXXX EbadMeta\n");
 	werrstr(EBadMeta);
 	vdcleanup(dir);
 	return -1;
blob - 81143337d5789f40d7edd60762f2970ea7a4294b (mode 644)
blob + /dev/null
--- src/cmd/vac/rtest.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "stdinc.h"
-
-enum {
-	Nblock = 300000,
-	BlockSize = 8*1024
-};
-
-uchar data[Nblock*VtScoreSize];
-int rflag;
-int nblock = 10000;
-int perm[Nblock];
-
-void
-main(int argc, char *argv[])
-{
-	VtSession *z;
-	int i, j, t;
-	int start;
-	uchar buf[BlockSize];
-
-	srand(time(0));
-
-	ARGBEGIN{
-	case 'r':
-		rflag++;
-		break;
-	case 'n':
-		nblock = atoi(ARGF());
-		break;
-	}ARGEND
-
-	for(i=0; i<nblock; i++)
-		perm[i] = i;
-
-	if(rflag) {
-		for(i=0; i<nblock; i++) {
-			j = nrand(nblock);
-			t = perm[j];
-			perm[j] = perm[i];
-			perm[i] = t;
-		}
-	}
-
-	if(readn(0, data, VtScoreSize*nblock) < VtScoreSize*nblock)
-		sysfatal("read failed: %r");
-
-	vtAttach();
-
-	z = vtDial("iolaire2");
-	if(z == nil)
-		sysfatal("cound not connect to venti");
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-
-	print("starting\n");
-
-	start = times(0);
-
-	if(rflag && nblock > 10000)
-		nblock = 10000;
-
-	for(i=0; i<nblock; i++) {
-		if(vtRead(z, data+perm[i]*VtScoreSize, VtDataType, buf, BlockSize) < 0)
-			vtFatal("vtRead failed: %d: %s", i, vtGetError());
-	}
-
-	print("time = %f\n", (times(0) - start)*0.001);
-
-	vtClose(z);
-	vtDetach();
-}
blob - /dev/null
blob + a2ac21550cee76c1ea7cb2db28fc0b8b8e1ba8f9 (mode 644)
--- /dev/null
+++ src/cmd/vac/unvac.c
@@ -0,0 +1,293 @@
+#include "stdinc.h"
+#include <auth.h>
+#include <fcall.h>
+#include <thread.h>
+#include "vac.h"
+
+VacFs *fs;
+int tostdout;
+int nwant;
+char **want;
+int *found;
+int chatty;
+VtConn *conn;
+int errors;
+int settimes;
+int table;
+
+int mtimefmt(Fmt*);
+void unvac(VacFile*, char*, VacDir*);
+
+void
+usage(void)
+{
+	fprint(2, "usage: unvac [-TVctv] [-h host] file.vac [file ...]\n");
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	int i;
+	char *host;
+	VacFile *f;
+
+	fmtinstall('H', encodefmt);
+	fmtinstall('V', vtscorefmt);
+	fmtinstall('F', vtfcallfmt);
+	fmtinstall('T', mtimefmt);
+	fmtinstall('M', dirmodefmt);
+	
+	host = nil;
+	ARGBEGIN{
+	case 'T':
+		settimes = 1;
+		break;
+	case 'V':
+		chattyventi = 1;
+		break;
+	case 'c':
+		tostdout++;
+		break;
+	case 'h':
+		host = EARGF(usage());
+		break;
+	case 't':
+		table++;
+		break;
+	case 'v':
+		chatty++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc < 1)
+		usage();
+
+	conn = vtdial(host);
+	if(conn == nil)
+		sysfatal("could not connect to server: %r");
+
+	if(vtconnect(conn) < 0)
+		sysfatal("vtconnect: %r");
+
+	fs = vacfsopen(conn, argv[0], VtOREAD, 128);
+	if(fs == nil)
+		sysfatal("vacfsopen: %r");
+
+	nwant = argc-1;
+	want = argv+1;
+	found = vtmallocz(nwant*sizeof found[0]);
+
+	if((f = vacfsgetroot(fs)) == nil)
+		sysfatal("vacfsgetroot: %r");
+	
+	unvac(f, nil, nil);
+	for(i=0; i<nwant; i++){
+		if(want[i] && !found[i]){
+			fprint(2, "warning: didn't find %s\n", want[i]);
+			errors++;
+		}
+	}
+	if(errors)
+		threadexitsall("errors");
+	threadexitsall(0);
+}
+
+int
+writen(int fd, char *buf, int n)
+{
+	int m;
+	int oldn;
+	
+	oldn = n;
+	while(n > 0){
+		m = write(fd, buf, n);
+		if(m <= 0)
+			return -1;
+		buf += m;
+		n -= m;
+	}
+	return oldn;
+}
+
+int
+wantfile(char *name)
+{
+	int i, namelen, n;
+	
+	if(nwant == 0)
+		return 1;
+
+	namelen = strlen(name);
+	for(i=0; i<nwant; i++){
+		if(want[i] == nil)
+			continue;
+		n = strlen(want[i]);
+		if(n < namelen && name[n] == '/' && memcmp(name, want[i], n) == 0)
+			return 1;
+		if(namelen < n && want[i][namelen] == '/' && memcmp(want[i], name, n) == 0)
+			return 1;
+		if(n == namelen && memcmp(name, want[i], n) == 0){
+			found[i] = 1;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void
+unvac(VacFile *f, char *name, VacDir *vdir)
+{
+	static char buf[65536];
+	int fd, mode, n, mode9;
+	char *newname;
+	char *what;
+	vlong off;
+	Dir d, *dp;
+	VacDirEnum *vde;
+	VacDir newvdir;
+	VacFile *newf;
+
+	if(vdir)
+		mode = vdir->mode;
+	else
+		mode = vacfilegetmode(f);
+
+	if(vdir){
+		if(table){
+			if(chatty){
+				mode9 = vdir->mode&0777;
+				if(mode&ModeDir)
+					mode9 |= DMDIR;
+				if(mode&ModeLink)
+					mode9 |= DMSYMLINK;
+				if(mode&ModeAppend)
+					mode9 |= DMAPPEND;
+				if(mode&ModeExclusive)
+					mode9 |= DMEXCL;
+				if(mode&ModeNamedPipe)
+					mode9 |= DMNAMEDPIPE;
+				if(mode&ModeSetUid)
+					mode9 |= DMSETUID;
+				if(mode&ModeSetGid)
+					mode9 |= DMSETGID;
+				if(mode&ModeDevice)
+					mode9 |= DMDEVICE;
+				print("%M %-10s %-10s %11lld %T %s\n",
+					mode9, vdir->uid, vdir->gid, vdir->size,
+					vdir->mtime, name);
+			}else
+				print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
+		}
+		else if(chatty)
+			fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
+	}
+
+	if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
+		if(table)
+			return;
+		if(mode&ModeDevice)
+			what = "device";
+		else if(mode&ModeLink)
+			what = "link";
+		else if(mode&ModeNamedPipe)
+			what = "named pipe";
+		else if(mode&ModeExclusive)
+			what = "lock";
+		else
+			what = "unknown type of file";
+		fprint(2, "warning: ignoring %s %s\n", what, name);
+		return;
+	}
+	
+	if(mode&ModeDir){
+		if((vde = vdeopen(f)) == nil){
+			fprint(2, "vdeopen %s: %r", name);
+			errors++;
+			return;
+		}
+		if(!table && !tostdout && vdir){
+			// create directory
+			if((dp = dirstat(name)) == nil){
+				if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){
+					fprint(2, "mkdir %s: %r\n", name);
+					vdeclose(vde);
+				}
+				close(fd);
+			}else{
+				if(!(dp->mode&DMDIR)){
+					fprint(2, "%s already exists and is not a directory\n", name);
+					errors++;
+					free(dp);
+					vdeclose(vde);
+					return;
+				}
+				free(dp);
+			}
+		}
+		while(vderead(vde, &newvdir) > 0){
+			if(name == nil)
+				newname = newvdir.elem;
+			else
+				newname = smprint("%s/%s", name, newvdir.elem);
+			if(wantfile(newname)){
+				if((newf = vacfilewalk(f, newvdir.elem)) == nil){
+					fprint(2, "walk %s: %r\n", name);
+					errors++;
+				}else if(newf == f){
+					fprint(2, "walk loop: %s\n", newname);
+					vacfiledecref(newf);
+				}else{
+					unvac(newf, newname, &newvdir);
+					vacfiledecref(newf);
+				}
+			}
+			if(newname != newvdir.elem)
+				free(newname);
+			vdcleanup(&newvdir);
+		}
+		vdeclose(vde);
+	}else{
+		if(!table){
+			if(tostdout)
+				fd = dup(1, -1);
+			else if((fd = create(name, OWRITE, mode&0777)) < 0){
+				fprint(2, "create %s: %r\n", name);
+				errors++;
+				return;
+			}
+			off = 0;
+			while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
+				if(writen(fd, buf, n) != n){
+					fprint(2, "write %s: %r\n", name);
+					errors++;
+					close(fd);
+					remove(name);
+					return;
+				}
+				off += n;
+			}
+			close(fd);
+		}
+	}
+	if(vdir && settimes && !tostdout){
+		nulldir(&d);
+		d.mtime = vdir->mtime;
+		if(dirwstat(name, &d) < 0)
+			fprint(2, "warning: setting mtime on %s: %r", name);
+	}
+}
+
+int
+mtimefmt(Fmt *f)
+{
+	Tm *tm;
+	
+	tm = localtime(va_arg(f->args, ulong));
+	fmtprint(f, "%04d-%02d-%02d %02d:%02d",
+		tm->year+1900, tm->mon+1, tm->mday,
+		tm->hour, tm->min);
+	return 0;
+}
blob - 8f3b2a0c9266fd148aec8f48c70a51d3e4bd6a2d (mode 644)
blob + /dev/null
--- src/cmd/vac/srcload.c
+++ /dev/null
@@ -1,302 +0,0 @@
-#include "stdinc.h"
-#include <bio.h>
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-#include "error.h"
-
-int num = 1000;
-int length = 20*1024;
-int block= 1024;
-int bush = 4;
-int iter = 10000;
-Biobuf *bout;
-int maxdepth;
-
-Source *mkroot(Cache*);
-void new(Source*, int trace, int);
-int delete(Source*);
-void dump(Source*, int indent, ulong nentry);
-void dumpone(Source *s);
-int count(Source *s, int);
-void stats(Source *s);
-
-void
-main(int argc, char *argv[])
-{
-	int i;
-	Cache *c;
-	char *host = nil;
-	VtSession *z;
-	int csize = 10000;
-	Source *r;
-	ulong t;
-
-	t = time(0);
-	fprint(1, "time = %lud\n", t);
-
-	srand(t);
-
-	ARGBEGIN{
-	case 'i':
-		iter = atoi(ARGF());
-		break;
-	case 'n':
-		num = atoi(ARGF());
-		break;
-	case 'l':
-		length = atoi(ARGF());
-		break;
-	case 'b':	
-		block = atoi(ARGF());
-		break;
-	case 'h':
-		host = ARGF();
-		break;
-	case 'u':
-		bush = atoi(ARGF());
-		break;
-	case 'c':
-		csize = atoi(ARGF());
-		break;
-	}ARGEND;
-
-	vtAttach();
-
-	bout = vtMemAllocZ(sizeof(Biobuf));
-	Binit(bout, 1, OWRITE);
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	z = vtDial(host);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-
-	if(!vtConnect(z, 0))
-		sysfatal("vtConnect: %r");
-
-	c = cacheAlloc(z, block, csize);
-	r = mkroot(c);
-	for(i=0; i<num; i++)
-		new(r, 0, 0);
-
-	for(i=0; i<iter; i++) {
-if(i % 10000 == 0)
-stats(r);
-		new(r, 0, 0);
-		delete(r);
-	}
-
-	fprint(2, "count = %d top = %lud\n", count(r, 0), sourceGetDirSize(r));
-/*	cacheCheck(c); */
-fprint(2, "deleting\n");
-	for(i=0; i<num; i++)
-		delete(r);
-
-/*	dump(r, 0, 0); */
-	
-	lumpDecRef(r->lump, 0);
-	sourceRemove(r);
-	cacheCheck(c);
-
-	vtClose(z);
-	vtDetach();
-
-	exits(0);
-}
-
-
-Source *
-mkroot(Cache *c)
-{
-	Lump *u;
-	VtEntry *dir;
-	Source *r;
-
-	u = cacheAllocLump(c, VtDirType, cacheGetBlockSize(c), 1);
-	dir = (VtEntry*)u->data;
-	vtPutUint16(dir->psize, cacheGetBlockSize(c));
-	vtPutUint16(dir->dsize, cacheGetBlockSize(c));
-	dir->flag = VtEntryActive|VtEntryDir;
-	memmove(dir->score, vtZeroScore, VtScoreSize);
-	
-	r = sourceAlloc(c, u, 0, 0);
-	vtUnlock(u->lk);
-	if(r == nil)
-		sysfatal("could not create root source: %r");
-	return r;
-}
-
-void
-new(Source *s, int trace, int depth)
-{
-	int i, n;
-	Source *ss;
-	
-	if(depth > maxdepth)
-		maxdepth = depth;
-
-	n = sourceGetDirSize(s);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, nrand(n), 0);
-		if(ss == nil)
-			continue;
-		if(ss->dir && frand() < 1./bush) {
-			if(trace) {
-				int j;
-				for(j=0; j<trace; j++)
-					Bprint(bout, " ");
-				Bprint(bout, "decend %d\n", i);
-			}
-			new(ss, trace?trace+1:0, depth+1);
-			sourceFree(ss);
-			return;
-		}
-		sourceFree(ss);
-	}
-	ss = sourceCreate(s, s->psize, s->dsize, 1+frand()>.5, 0);
-	if(ss == nil)
-		fprint(2, "could not create directory: %r\n");
-	if(trace) {
-		int j;
-		for(j=1; j<trace; j++)
-			Bprint(bout, " ");
-		Bprint(bout, "create %d %V\n", ss->entry, ss->lump->score);
-	}
-	sourceFree(ss);
-}
-
-int
-delete(Source *s)
-{
-	int i, n;
-	Source *ss;
-	
-	assert(s->dir);
-
-	n = sourceGetDirSize(s);
-	/* check if empty */
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss != nil) {
-			sourceFree(ss);
-			break;
-		}
-	}
-	if(i == n)
-		return 0;
-		
-	for(;;) {
-		ss = sourceOpen(s, nrand(n), 0);
-		if(ss == nil)
-			continue;
-		if(ss->dir && delete(ss)) {
-			sourceFree(ss);
-			return 1;
-		}
-		if(1)
-			break;
-		sourceFree(ss);
-	}
-
-
-	sourceRemove(ss);
-	return 1;
-}
-
-void
-dumpone(Source *s)
-{
-	ulong i, n;
-	Source *ss;
-
-	Bprint(bout, "gen %4lud depth %d %V", s->gen, s->depth, s->lump->score);
-	if(!s->dir) {
-		Bprint(bout, " data size: %llud\n", s->size);
-		return;
-	}
-	n = sourceGetDirSize(s);
-	Bprint(bout, " dir size: %lud\n", n);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil) {
-fprint(2, "%lud: %r\n", i);
-			continue;
-		}
-		Bprint(bout, "\t%lud %d %llud %V\n", i, ss->dir, ss->size, ss->lump->score);
-		sourceFree(ss);
-	}
-	return;
-}
-
-
-void
-dump(Source *s, int ident, ulong entry)
-{
-	ulong i, n;
-	Source *ss;
-
-	for(i=0; i<ident; i++)
-		Bprint(bout, " ");
-	Bprint(bout, "%4lud: gen %4lud depth %d", entry, s->gen, s->depth);
-	if(!s->dir) {
-		Bprint(bout, " data size: %llud\n", s->size);
-		return;
-	}
-	n = sourceGetDirSize(s);
-	Bprint(bout, " dir size: %lud\n", n);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil)
-			continue;
-		dump(ss, ident+1, i);
-		sourceFree(ss);
-	}
-	return;
-}
-
-int
-count(Source *s, int rec)
-{
-	ulong i, n;
-	int c;
-	Source *ss;
-
-	if(!s->dir)
-		return 0;
-	n = sourceGetDirSize(s);
-	c = 0;
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil)
-			continue;
-		if(rec)
-			c += count(ss, rec);
-		c++;
-		sourceFree(ss);
-	}
-	return c;
-}
-
-void
-stats(Source *s)
-{
-	int n, i, c, cc, max;
-	Source *ss;
-
-	cc = 0;
-	max = 0;
-	n = sourceGetDirSize(s);
-	for(i=0; i<n; i++) {
-		ss = sourceOpen(s, i, 1);
-		if(ss == nil)
-			continue;
-		cc++;
-		c = count(ss, 1);
-		if(c > max)
-			max = c;
-		sourceFree(ss);
-	}
-fprint(2, "count = %d top = %d depth=%d maxcount %d\n", cc, n, maxdepth, max);
-}
blob - f52acf6014db4bcbbbfd2471bcc54e4784485aad (mode 644)
blob + /dev/null
--- src/cmd/vac/util.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-int
-vtGetUint16(uchar *p)
-{
-	return (p[0]<<8)|p[1];
-}
-
-ulong
-vtGetUint32(uchar *p)
-{
-	return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-}
-
-uvlong
-vtGetUint48(uchar *p)
-{
-	return ((uvlong)p[0]<<40)|((uvlong)p[1]<<32)|
-		(p[2]<<24)|(p[3]<<16)|(p[4]<<8)|p[5];
-}
-
-uvlong
-vtGetUint64(uchar *p)
-{
-	return ((uvlong)p[0]<<56)|((uvlong)p[1]<<48)|((uvlong)p[2]<<40)|
-		((uvlong)p[3]<<32)|(p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
-}
-
-
-void
-vtPutUint16(uchar *p, int x)
-{
-	p[0] = x>>8;
-	p[1] = x;
-}
-
-void
-vtPutUint32(uchar *p, ulong x)
-{
-	p[0] = x>>24;
-	p[1] = x>>16;
-	p[2] = x>>8;
-	p[3] = x;
-}
-
-void
-vtPutUint48(uchar *p, uvlong x)
-{
-	p[0] = x>>40;
-	p[1] = x>>32;
-	p[2] = x>>24;
-	p[3] = x>>16;
-	p[4] = x>>8;
-	p[5] = x;
-}
-
-void
-vtPutUint64(uchar *p, uvlong x)
-{
-	p[0] = x>>56;
-	p[1] = x>>48;
-	p[2] = x>>40;
-	p[3] = x>>32;
-	p[4] = x>>24;
-	p[5] = x>>16;
-	p[6] = x>>8;
-	p[7] = x;
-}
blob - 637c49c03441f4bc3adaba13a1f71aae1b762386 (mode 644)
blob + /dev/null
--- src/cmd/vac/vac-orig.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-typedef struct Sink Sink;
-typedef struct MetaSink MetaSink;
-typedef struct DirSink DirSink;
-
-struct Sink {
-	VtSession *z;
-	VtEntry dir;
-	uchar *buf;
-	uchar *pbuf[VtPointerDepth+1];
-};
-
-struct DirSink {
-	Sink *sink;
-	MetaSink *msink;
-	ulong nentry;
-	uchar *buf;
-	uchar *p;	/* current pointer */
-	uchar *ep;	/* end pointer */
-};
-
-struct MetaSink {
-	Sink *sink;
-	uchar *buf;
-	int maxindex;
-	int nindex;
-	uchar *rp;	/* start of current record */
-	uchar *p;	/* current pointer */
-	uchar *ep;	/* end pointer */
-};
-
-static void usage(void);
-static int strpCmp(void*, void*);
-static void warn(char *fmt, ...);
-static void cleanup(void);
-static u64int unittoull(char *s);
-static int vac(VtSession *z, char *argv[]);
-static void vacFile(DirSink *dsink, char *lname, char *sname, VacFile*);
-static void vacStdin(DirSink *dsink, char *name, VacFile *vf);
-static void vacData(DirSink *dsink, int fd, char *lname, VacFile*, Dir*);
-static void vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile*);
-static int vacMerge(DirSink *dsink, char *lname, char *sname);
-
-Sink *sinkAlloc(VtSession *z, int psize, int dsize);
-void sinkWrite(Sink *k, uchar *data, int n);
-void sinkWriteScore(Sink *k, uchar *score, int n);
-void sinkClose(Sink *k);
-void sinkFree(Sink *k);
-
-DirSink *dirSinkAlloc(VtSession *z, int psize, int dsize);
-void dirSinkWrite(DirSink *k, VtEntry*);
-void dirSinkWriteSink(DirSink *k, Sink*);
-int dirSinkWriteFile(DirSink *k, VacFile *vf);
-void dirSinkClose(DirSink *k);
-void dirSinkFree(DirSink *k);
-
-MetaSink *metaSinkAlloc(VtSession *z, int psize, int dsize);
-void metaSinkPutc(MetaSink *k, int c);
-void metaSinkPutString(MetaSink *k, char *s);
-void metaSinkPutUint32(MetaSink *k, ulong x);
-void metaSinkPutUint64(MetaSink *k, uvlong x);
-void metaSinkWrite(MetaSink *k, uchar *data, int n);
-void metaSinkWriteDir(MetaSink *ms, VacDir *vd);
-void metaSinkEOR(MetaSink *k);
-void metaSinkClose(MetaSink *k);
-void metaSinkFree(MetaSink *k);
-void plan9ToVacDir(VacDir*, Dir*, ulong entry, uvlong qid);
-
-enum {
-	Version = 8,
-	BlockSize = 8*1024,
-	MaxExclude = 1000
-};
-
-struct {
-	ulong	file;
-	ulong	sfile;
-	ulong	data;
-	ulong	sdata;
-	ulong	skip;
-	ulong	meta;
-} stats;
-
-int bsize = BlockSize;
-int maxbsize;
-char *oname, *dfile;
-int verbose;
-uvlong fileid = 1;
-int qdiff;
-char *exclude[MaxExclude];
-int nexclude;
-int nowrite;
-int merge;
-char *isi;
-
-void
-main(int argc, char *argv[])
-{
-	VtSession *z;
-	char *p;
-	char *host = nil;
-	int statsFlag = 0;
-
-	atexit(cleanup);
-
-	ARGBEGIN{
-	default:
-		usage();
-	case 'b':
-		p = ARGF();
-		if(p == 0)
-			usage();
-		bsize = unittoull(p);
-		if(bsize == ~0)
-			usage();
-		break;
-	case 'd':
-		dfile = ARGF();
-		if(dfile == nil)
-			usage();
-		break;
-	case 'e':
-		if(nexclude >= MaxExclude)
-			sysfatal("too many exclusions\n");
-		exclude[nexclude] = ARGF();
-		if(exclude[nexclude] == nil)
-			usage();
-		nexclude++;
-		break;
-	case 'f':
-		oname = ARGF();
-		if(oname == 0)
-			usage();
-		break;
-	case 'h':
-		host = ARGF();
-		if(host == nil)
-			usage();
-		break;
-	case 'i':
-		isi = ARGF();
-		if(isi == nil)
-			usage();
-		break;
-	case 'n':
-		nowrite++;
-		break;
-	case 'm':
-		merge++;
-		break;
-	case 'q':
-		qdiff++;
-		break;
-	case 's':
-		statsFlag++;
-		break;
-	case 'v':
-		verbose++;
-		break;
-	}ARGEND;
-
-	if(bsize < 512)
-		bsize = 512;
-	if(bsize > VtMaxLumpSize)
-		bsize = VtMaxLumpSize;
-	maxbsize = bsize;
-
-	vtAttach();
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	z = vtDial(host, 0);
-	if(z == nil)
-		vtFatal("could not connect to server: %R");
-
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %R");
-
-	qsort(exclude, nexclude, sizeof(char*), strpCmp);
-
-	vac(z, argv);
-	if(!vtSync(z))
-		fprint(2, "warning: could not ask server to flush pending writes: %R\n");
-
-	if(statsFlag)
-		fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile,
-			stats.data, stats.skip, stats.sdata, stats.meta);
-/*packetStats(); */
-	vtClose(z);
-	vtDetach();
-
-	exits(0);
-}
-
-void
-static usage(void)
-{
-	fprint(2, "usage: %s [-amqsv] [-h host] [-d vacfile] [-b blocksize] [-i name] [-e exclude] [-f vacfile] file ... \n", argv0);
-	exits("usage");
-}
-
-static
-int strpCmp(void *p0, void *p1)
-{
-	return strcmp(*(char**)p0, *(char**)p1);
-}
-
-
-int
-readBlock(int fd, uchar *buf, int n)
-{
-	int m, t = 0;
-
-	while(t < n){
-		m = read(fd, buf+t, n-t);
-		if(m < 0)
-			return -1;
-		if(m == 0)
-			break;
-		t += m;
-	}
-	return t;
-}
-
-int
-vacWrite(VtSession *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
-{
-assert(n > 0);
-	if(nowrite) {
-		vtSha1(score, buf, n);
-		return 1;
-	}
-	if(!vtWrite(z, score, type, buf, n))
-		return 0;
-	if(!vtSha1Check(score, buf, n)) {
-		uchar score2[VtScoreSize];
-		
-		vtSha1(score2, buf, n);
-fprint(2, "vtSha1Check: n = %d %V %V\n", n, score, score2);
-		vtSetError("vtSha1Check failed");
-		return 0;
-	}
-	return 1;
-}
-
-
-static int
-vac(VtSession *z, char *argv[])
-{
-	DirSink *dsink, *ds;
-	MetaSink *ms;
-	VtRoot root;
-	uchar score[VtScoreSize], buf[VtRootSize];
-	char cwd[2048];
-	int cd, i;
-	char *cp2, *cp;
-	VacFS *fs;
-	VacFile *vff;
-	int fd;
-	Dir *dir;
-	VacDir vd;
-
-	if(getwd(cwd, sizeof(cwd)) == 0)
-		sysfatal("can't find current directory: %r\n");
-
-	dsink = dirSinkAlloc(z, bsize, bsize);
-
-	fs = nil;
-	if(dfile != nil) {
-		fs = vfsOpen(z, dfile, 1, 10000);
-		if(fs == nil)
-			fprint(2, "could not open diff: %s: %s\n", dfile, vtGetError());
-	}
-		
-
-	if(oname != nil) {
-		fd = create(oname, OWRITE, 0666);
-		if(fd < 0)
-			sysfatal("could not create file: %s: %r", oname);
-	} else 
-		fd = 1;
-
-	dir = dirfstat(fd);
-	if(dir == nil)
-		sysfatal("dirfstat failed: %r");
-
-	for(; *argv; argv++) {
-		cp2 = *argv;
-		cd = 0;
-		for (cp = *argv; *cp; cp++)
-			if (*cp == '/')
-				cp2 = cp;
-		if (cp2 != *argv) {
-			*cp2 = '\0';
-			chdir(*argv);
-			*cp2 = '/';
-			cp2++;
-			cd = 1;
-		}
-		vff = nil;
-		if(fs)
-			vff = vfOpen(fs, cp2);
-		vacFile(dsink, argv[0], cp2, vff);
-		if(vff)
-			vfDecRef(vff);
-		if(cd && chdir(cwd) < 0)
-			sysfatal("can't cd back to %s: %r\n", cwd);
-	}
-	
-	if(isi) {
-		vff = nil;
-		if(fs)
-			vff = vfOpen(fs, isi);
-		vacStdin(dsink, isi, vff);
-		if(vff)
-			vfDecRef(vff);
-	}
-
-	dirSinkClose(dsink);
-
-	/* build meta information for the root */
-	ms = metaSinkAlloc(z, bsize, bsize);
-	/* fake into a directory */
-	dir->mode |= (dir->mode&0444)>>2;
-	dir->qid.type |= QTDIR;
-	dir->mode |= DMDIR;
-	plan9ToVacDir(&vd, dir, 0, fileid++);
-	if(strcmp(vd.elem, "/") == 0){
-		vtMemFree(vd.elem);
-		vd.elem = vtStrDup("root");
-	}
-	metaSinkWriteDir(ms, &vd);
-	vdCleanup(&vd);
-	metaSinkClose(ms);
-	
-	ds = dirSinkAlloc(z, bsize, bsize);
-	dirSinkWriteSink(ds, dsink->sink);
-	dirSinkWriteSink(ds, dsink->msink->sink);
-	dirSinkWriteSink(ds, ms->sink);
-	dirSinkClose(ds);
-
-	memset(&root, 0, sizeof(root));		
-	root.version = VtRootVersion;
-	strncpy(root.name, dir->name, sizeof(root.name));
-	root.name[sizeof(root.name)-1] = 0;
-	free(dir);
-	sprint(root.type, "vac");
-	memmove(root.score, ds->sink->dir.score, VtScoreSize);
-	root.blockSize = maxbsize;
-	if(fs != nil)
-		vfsGetScore(fs, root.prev);
-
-	metaSinkFree(ms);
-	dirSinkFree(ds);
-	dirSinkFree(dsink);
-	if(fs != nil)
-		vfsClose(fs);
-	
-	vtRootPack(&root, buf);
-	if(!vacWrite(z, score, VtRootType, buf, VtRootSize))
-		vtFatal("vacWrite failed: %s", vtGetError());
-
-	fprint(fd, "vac:");
-	for(i=0; i<VtScoreSize; i++)
-		fprint(fd, "%.2x", score[i]);
-	fprint(fd, "\n");
-	
-	/* avoid remove at cleanup */
-	oname = nil;
-	return 1;
-}
-
-static int
-isExcluded(char *name)
-{
-	int bot, top, i, x;
-
-	bot = 0;	
-	top = nexclude;
-	while(bot < top) {
-		i = (bot+top)>>1;
-		x = strcmp(exclude[i], name);
-		if(x == 0)
-			return 1;
-		if(x < 0)
-			bot = i + 1;
-		else /* x > 0 */
-			top = i;
-	}
-	return 0;
-}
-
-static void
-vacFile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
-{
-	int fd;
-	Dir *dir;
-	VacDir vd;
-	ulong entry;
-
-	if(isExcluded(lname)) {
-		warn("excluding: %s", lname);
-		return;
-	}
-
-	if(merge && vacMerge(dsink, lname, sname))
-		return;
-
-	fd = open(sname, OREAD);
-	if(fd < 0) {
-		warn("could not open file: %s: %s", lname, vtOSError());
-		return;
-	}
-
-	if(verbose)
-		fprint(2, "%s\n", lname);
-
-	dir = dirfstat(fd);
-	if(dir == nil) {
-		warn("can't stat %s: %r", lname);
-		close(fd);
-		return;
-	}
-
-	entry = dsink->nentry;
-
-	if(dir->mode & DMDIR) 
-		vacDir(dsink, fd, lname, sname, vf);
-	else
-		vacData(dsink, fd, lname, vf, dir);
-
-	plan9ToVacDir(&vd, dir, entry, fileid++);
-	metaSinkWriteDir(dsink->msink, &vd);
-	vdCleanup(&vd);
-
-	free(dir);
-	close(fd);
-}
-
-static void
-vacStdin(DirSink *dsink, char *name, VacFile *vf)
-{
-	Dir *dir;
-	VacDir vd;
-	ulong entry;
-
-	if(verbose)
-		fprint(2, "%s\n", "<stdio>");
-
-	dir = dirfstat(0);
-	if(dir == nil) {
-		warn("can't stat <stdio>: %r");
-		return;
-	}
-
-	entry = dsink->nentry;
-
-	vacData(dsink, 0, "<stdin>", vf, dir);
-
-	plan9ToVacDir(&vd, dir, entry, fileid++);
-	vd.elem = vtStrDup(name);
-	metaSinkWriteDir(dsink->msink, &vd);
-	vdCleanup(&vd);
-
-	free(dir);
-}
-
-static ulong
-vacDataSkip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname)
-{
-	int n;
-	ulong i;
-	uchar score[VtScoreSize];
-
-	/* skip blocks for append only files */
-	if(seek(fd, (blocks-1)*bsize, 0) != (blocks-1)*bsize) {
-		warn("error seeking: %s", lname);
-		goto Err;
-	}
-	n = readBlock(fd, buf, bsize);
-	if(n < bsize) {
-		warn("error checking append only file: %s", lname);
-		goto Err;
-	}
-	if(!vfGetBlockScore(vf, blocks-1, score) || !vtSha1Check(score, buf, n)) {
-		warn("last block of append file did not match: %s", lname);
-		goto Err;
-	}
-
-	for(i=0; i<blocks; i++) {
-		if(!vfGetBlockScore(vf, i, score)) {
-			warn("could not get score: %s: %lud", lname, i);
-			seek(fd, i*bsize, 0);
-			return i;
-		}
-		stats.skip++;
-		sinkWriteScore(sink, score, bsize);
-	}
-
-	return i;
-Err:
-	seek(fd, 0, 0);
-	return 0;
-}
-
-static void
-vacData(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir)
-{
-	uchar *buf;
-	Sink *sink;
-	int n;
-	uchar score[VtScoreSize];
-	ulong block, same;
-	VacDir vd;
-	ulong vfblocks;
-
-	vfblocks = 0;
-	if(vf != nil && qdiff) {
-		vfGetDir(vf, &vd);
-		if(vd.mtime == dir->mtime)
-		if(vd.size == dir->length)
-		if(!vd.plan9 || /* vd.p9path == dir->qid.path && */ vd.p9version == dir->qid.vers)
-		if(dirSinkWriteFile(dsink, vf)) {
-			stats.sfile++;
-			vdCleanup(&vd);
-			return;
-		}
-
-		/* look for an append only file */
-		if((dir->mode&DMAPPEND) != 0)
-		if(vd.size < dir->length)
-		if(vd.plan9)
-		if(vd.p9path == dir->qid.path)
-			vfblocks = vd.size/bsize;
-
-		vdCleanup(&vd);
-	}
-	stats.file++;
-
-	buf = vtMemAlloc(bsize);
-	sink = sinkAlloc(dsink->sink->z, bsize, bsize);
-	block = 0;
-	same = stats.sdata+stats.skip;
-
-	if(vfblocks > 1)
-		block += vacDataSkip(sink, vf, fd, vfblocks, buf, lname);
-
-if(0) fprint(2, "vacData: %s: %ld\n", lname, block);
-	for(;;) {
-		n = readBlock(fd, buf, bsize);
-		if(0 && n < 0)
-			warn("file truncated due to read error: %s: %s", lname, vtOSError());
-		if(n <= 0)
-			break;
-		if(vf != nil && vfGetBlockScore(vf, block, score) && vtSha1Check(score, buf, n)) {
-			stats.sdata++;
-			sinkWriteScore(sink, score, n);
-		} else
-			sinkWrite(sink, buf, n);
-		block++;
-	}
-	same = stats.sdata+stats.skip - same;
-
-	if(same && (dir->mode&DMAPPEND) != 0)
-		if(0)fprint(2, "%s: total %lud same %lud:%lud diff %lud\n",
-			lname, block, same, vfblocks, block-same);
-
-	sinkClose(sink);
-	dirSinkWriteSink(dsink, sink);
-	sinkFree(sink);
-	free(buf);
-}
-
-
-static void
-vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf)
-{
-	Dir *dirs;
-	char *ln, *sn;
-	int i, nd;
-	DirSink *ds;
-	VacFile *vvf;
-	char *name;
-
-	ds = dirSinkAlloc(dsink->sink->z, bsize, bsize);
-	while((nd = dirread(fd, &dirs)) > 0){
-		for(i = 0; i < nd; i++){
-			name = dirs[i].name;
-			/* check for bad file names */
-			if(name[0] == 0 || strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-				continue;
-			ln = vtMemAlloc(strlen(lname) + strlen(name) + 2);
-			sn = vtMemAlloc(strlen(sname) + strlen(name) + 2);
-			sprint(ln, "%s/%s", lname, name);
-			sprint(sn, "%s/%s", sname, name);
-			if(vf != nil)
-				vvf = vfWalk(vf, name);
-			else
-				vvf = nil;
-			vacFile(ds, ln, sn, vvf);
-			if(vvf != nil)
-				vfDecRef(vvf);
-			vtMemFree(ln);
-			vtMemFree(sn);
-		}
-		free(dirs);
-	}
-	dirSinkClose(ds);
-	dirSinkWriteSink(dsink, ds->sink);
-	dirSinkWriteSink(dsink, ds->msink->sink);
-	dirSinkFree(ds);
-}
-
-static int
-vacMergeFile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max)
-{
-	uchar buf[VtEntrySize];
-	VtEntry dd, md;
-	int e;
-
-	if(vfRead(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) {
-		warn("could not read venti dir entry: %s\n", dir->elem);
-		return 0;
-	}
-	vtEntryUnpack(&dd, buf, 0);
-
-	if(dir->mode & ModeDir)	{
-		e = dir->mentry;
-		if(e == 0)
-			e = dir->entry + 1;
-		
-		if(vfRead(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) {
-			warn("could not read venti dir entry: %s\n", dir->elem);
-			return 0;
-		}
-		vtEntryUnpack(&md, buf, 0);
-	}
-
-	/* max might incorrect in some old dumps */
-	if(dir->qid >= *max) {
-		warn("qid out of range: %s", dir->elem);
-		*max = dir->qid;
-	}
-
-	dir->qid += offset;
-	dir->entry = dsink->nentry;
-
-	if(dir->qidSpace) {
-		dir->qidOffset += offset;
-	} else {
-		dir->qidSpace = 1;
-		dir->qidOffset = offset;
-		dir->qidMax = *max;
-	}
-
-	dirSinkWrite(dsink, &dd);
-	if(dir->mode & ModeDir)	
-		dirSinkWrite(dsink, &md);
-	metaSinkWriteDir(dsink->msink, dir);
-	
-	return 1;
-}
-
-static int
-vacMerge(DirSink *dsink, char *lname, char *sname)
-{
-	char *p;
-	VacFS *fs;
-	VacFile *vf;
-	VacDirEnum *d;
-	VacDir dir;
-	uvlong max;
-
-	p = strrchr(sname, '.');
-	if(p == 0 || strcmp(p, ".vac"))
-		return 0;
-
-	d = nil;
-	fs = vfsOpen(dsink->sink->z, sname, 1, 100);
-	if(fs == nil)
-		return 0;
-
-	vf = vfOpen(fs, "/");
-	if(vf == nil)
-		goto Done;
-	max = vfGetId(vf);
-	d = vdeOpen(fs, "/");
-	if(d == nil)
-		goto Done;
-
-	if(verbose)
-		fprint(2, "merging: %s\n", lname);
-
-	if(maxbsize < vfsGetBlockSize(fs))
-		maxbsize = vfsGetBlockSize(fs);
-
-	for(;;) {
-		if(vdeRead(d, &dir, 1) < 1)
-			break;
-		vacMergeFile(dsink, vf, &dir, fileid, &max);
-		vdCleanup(&dir);	
-	}
-	fileid += max;
-
-Done:
-	if(d != nil)
-		vdeFree(d);
-	if(vf != nil)
-		vfDecRef(vf);
-	vfsClose(fs);
-	return 1;
-}
-
-Sink *
-sinkAlloc(VtSession *z, int psize, int dsize)
-{
-	Sink *k;
-	int i;
-
-	if(psize < 512 || psize > VtMaxLumpSize)
-		vtFatal("sinkAlloc: bad psize");
-	if(dsize < 512 || dsize > VtMaxLumpSize)
-		vtFatal("sinkAlloc: bad psize");
-
-	psize = VtScoreSize*(psize/VtScoreSize);
-
-	k = vtMemAllocZ(sizeof(Sink));
-	k->z = z;
-	k->dir.flags = VtEntryActive;
-	k->dir.psize = psize;
-	k->dir.dsize = dsize;
-	k->buf = vtMemAllocZ(VtPointerDepth*k->dir.psize + VtScoreSize);
-	for(i=0; i<=VtPointerDepth; i++)
-		k->pbuf[i] = k->buf + i*k->dir.psize;
-	return k;
-}
-
-void
-sinkWriteScore(Sink *k, uchar score[VtScoreSize], int n)
-{
-	int i;
-	uchar *p;
-	VtEntry *d;
-
-	memmove(k->pbuf[0], score, VtScoreSize);
-
-	d = &k->dir;
-
-	for(i=0; i<VtPointerDepth; i++) {
-		k->pbuf[i] += VtScoreSize;
-		if(k->pbuf[i] < k->buf + d->psize*(i+1))
-			break;
-		if(i == VtPointerDepth-1)
-			vtFatal("file too big");
-		p = k->buf+i*d->psize;
-		stats.meta++;
-		if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, d->psize))
-			vtFatal("vacWrite failed: %s", vtGetError());
-		k->pbuf[i] = p;
-	}
-
-	/* round size up to multiple of dsize */
-	d->size = d->dsize * ((d->size + d->dsize-1)/d->dsize);
-	
-	d->size += n;
-}
-
-void
-sinkWrite(Sink *k, uchar *p, int n)
-{
-	int type;
-	uchar score[VtScoreSize];
-
-	if(n > k->dir.dsize)
-		vtFatal("sinkWrite: size too big");
-
-	if(k->dir.flags & VtEntryDir) {
-		type = VtDirType;
-		stats.meta++;
-	} else {
-		type = VtDataType;
-		stats.data++;
-	}
-	if(!vacWrite(k->z, score, type, p, n))
-		vtFatal("vacWrite failed: %s", vtGetError());
-
-	sinkWriteScore(k, score, n);
-}
-
-static int
-sizeToDepth(uvlong s, int psize, int dsize)
-{
-	int np;
-	int d;
-	
-	/* determine pointer depth */
-	np = psize/VtScoreSize;
-	s = (s + dsize - 1)/dsize;
-	for(d = 0; s > 1; d++)
-		s = (s + np - 1)/np;
-	return d;
-}
-
-void
-sinkClose(Sink *k)
-{
-	int i, n;
-	uchar *p;
-	VtEntry *kd;
-
-	kd = &k->dir;
-
-	/* empty */
-	if(kd->size == 0) {
-		memmove(kd->score, vtZeroScore, VtScoreSize);
-		return;
-	}
-
-	for(n=VtPointerDepth-1; n>0; n--)
-		if(k->pbuf[n] > k->buf + kd->psize*n)
-			break;
-
-	kd->depth = sizeToDepth(kd->size, kd->psize, kd->dsize);
-
-	/* skip full part of tree */
-	for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
-		;
-
-	/* is the tree completely full */
-	if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
-		memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
-		return;
-	}
-	n++;
-
-	/* clean up the edge */
-	for(; i<n; i++) {
-		p = k->buf+i*kd->psize;
-		stats.meta++;
-		if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, k->pbuf[i]-p))
-			vtFatal("vacWrite failed: %s", vtGetError());
-		k->pbuf[i+1] += VtScoreSize;
-	}
-	memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
-}
-
-void
-sinkFree(Sink *k)
-{
-	vtMemFree(k->buf);
-	vtMemFree(k);
-}
-
-DirSink *
-dirSinkAlloc(VtSession *z, int psize, int dsize)
-{
-	DirSink *k;
-	int ds;
-
-	ds = VtEntrySize*(dsize/VtEntrySize);
-
-	k = vtMemAllocZ(sizeof(DirSink));
-	k->sink = sinkAlloc(z, psize, ds);
-	k->sink->dir.flags |= VtEntryDir;
-	k->msink = metaSinkAlloc(z, psize, dsize);
-	k->buf = vtMemAlloc(ds);
-	k->p = k->buf;
-	k->ep = k->buf + ds;
-	return k;
-}
-
-void
-dirSinkWrite(DirSink *k, VtEntry *dir)
-{
-	if(k->p + VtEntrySize > k->ep) {
-		sinkWrite(k->sink, k->buf, k->p - k->buf);
-		k->p = k->buf;
-	}
-	vtEntryPack(dir, k->p, 0);
-	k->nentry++;
-	k->p += VtEntrySize;
-}
-
-void
-dirSinkWriteSink(DirSink *k, Sink *sink)
-{
-	dirSinkWrite(k, &sink->dir);
-}
-
-int
-dirSinkWriteFile(DirSink *k, VacFile *vf)
-{
-	VtEntry dir;
-
-	if(!vfGetVtEntry(vf, &dir))
-		return 0;
-	dirSinkWrite(k, &dir);
-	return 1;
-}
-
-void
-dirSinkClose(DirSink *k)
-{
-	metaSinkClose(k->msink);
-	if(k->p != k->buf)
-		sinkWrite(k->sink, k->buf, k->p - k->buf);
-	sinkClose(k->sink);
-}
-
-void
-dirSinkFree(DirSink *k)
-{
-	sinkFree(k->sink);
-	metaSinkFree(k->msink);
-	vtMemFree(k->buf);
-	vtMemFree(k);
-}
-
-MetaSink *
-metaSinkAlloc(VtSession *z, int psize, int dsize)
-{
-	MetaSink *k;
-
-	k = vtMemAllocZ(sizeof(MetaSink));
-	k->sink = sinkAlloc(z, psize, dsize);
-	k->buf = vtMemAlloc(dsize);
-	k->maxindex = dsize/100;	/* 100 byte entries seems reasonable */
-	if(k->maxindex < 1)
-		k->maxindex = 1;
-	k->rp = k->p = k->buf + MetaHeaderSize + k->maxindex*MetaIndexSize;
-	k->ep = k->buf + dsize;
-	return k;
-}
-
-/* hack to get base to compare routine - not reentrant */
-uchar *blockBase;
-
-int
-dirCmp(void *p0, void *p1)
-{
-	uchar *q0, *q1;
-	int n0, n1, r;
-
-	/* name is first element of entry */
-	q0 = p0;
-	q0 = blockBase + (q0[0]<<8) + q0[1];
-	n0 = (q0[6]<<8) + q0[7];
-	q0 += 8;
-
-	q1 = p1;
-	q1 = blockBase + (q1[0]<<8) + q1[1];
-	n1 = (q1[6]<<8) + q1[7];
-	q1 += 8;
-
-	if(n0 == n1)
-		return memcmp(q0, q1, n0);
-	else if (n0 < n1) {
-		r = memcmp(q0, q1, n0);
-		return (r==0)?1:r;
-	} else  {
-		r = memcmp(q0, q1, n1);
-		return (r==0)?-1:r;
-	}
-}
-
-void
-metaSinkFlush(MetaSink *k)
-{
-	uchar *p;
-	int n;
-	MetaBlock mb;
-
-	if(k->nindex == 0)
-		return;
-	assert(k->nindex <= k->maxindex);
-
-	p = k->buf;
-	n = k->rp - p;
-
-	mb.size = n;
-	mb.free = 0;
-	mb.nindex = k->nindex;
-	mb.maxindex = k->maxindex;
-	mb.buf = p;
-	mbPack(&mb);
-	
-	p += MetaHeaderSize;
-
-	/* XXX this is not reentrant! */
-	blockBase = k->buf;
-	qsort(p, k->nindex, MetaIndexSize, dirCmp);
-	p += k->nindex*MetaIndexSize;
-	
-	memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize);
-	p += (k->maxindex-k->nindex)*MetaIndexSize;
-
-	sinkWrite(k->sink, k->buf, n);
-
-	/* move down partial entry */
-	n = k->p - k->rp;
-	memmove(p, k->rp, n);
-	k->rp = p;
-	k->p = p + n;
-	k->nindex = 0;
-}
-
-void
-metaSinkPutc(MetaSink *k, int c)
-{
-	if(k->p+1 > k->ep)
-		metaSinkFlush(k);
-	if(k->p+1 > k->ep)
-		vtFatal("directory entry too large");
-	k->p[0] = c;
-	k->p++;
-}
-
-void
-metaSinkPutString(MetaSink *k, char *s)
-{
-	int n = strlen(s);
-	metaSinkPutc(k, n>>8);
-	metaSinkPutc(k, n);
-	metaSinkWrite(k, (uchar*)s, n);
-}
-
-void
-metaSinkPutUint32(MetaSink *k, ulong x)
-{
-	metaSinkPutc(k, x>>24);
-	metaSinkPutc(k, x>>16);
-	metaSinkPutc(k, x>>8);
-	metaSinkPutc(k, x);
-}
-
-void
-metaSinkPutUint64(MetaSink *k, uvlong x)
-{
-	metaSinkPutUint32(k, x>>32);
-	metaSinkPutUint32(k, x);
-}
-
-void
-metaSinkWrite(MetaSink *k, uchar *data, int n)
-{
-	if(k->p + n > k->ep)
-		metaSinkFlush(k);
-	if(k->p + n > k->ep)
-		vtFatal("directory entry too large");
-	
-	memmove(k->p, data, n);
-	k->p += n;
-}
-
-void
-metaSinkWriteDir(MetaSink *ms, VacDir *dir)
-{
-	metaSinkPutUint32(ms, DirMagic);
-	metaSinkPutc(ms, Version>>8);
-	metaSinkPutc(ms, Version);		
-	metaSinkPutString(ms, dir->elem);
-	metaSinkPutUint32(ms, dir->entry);
-	metaSinkPutUint64(ms, dir->qid);
-	metaSinkPutString(ms, dir->uid);
-	metaSinkPutString(ms, dir->gid);
-	metaSinkPutString(ms, dir->mid);
-	metaSinkPutUint32(ms, dir->mtime);
-	metaSinkPutUint32(ms, dir->mcount);
-	metaSinkPutUint32(ms, dir->ctime);
-	metaSinkPutUint32(ms, dir->atime);
-	metaSinkPutUint32(ms, dir->mode);
-
-	if(dir->plan9) {
-		metaSinkPutc(ms, DirPlan9Entry);	/* plan9 extra info */
-		metaSinkPutc(ms, 0);			/* plan9 extra size */
-		metaSinkPutc(ms, 12);			/* plan9 extra size */
-		metaSinkPutUint64(ms, dir->p9path);
-		metaSinkPutUint32(ms, dir->p9version);
-	}
-
-	if(dir->qidSpace != 0) {
-		metaSinkPutc(ms, DirQidSpaceEntry);
-		metaSinkPutc(ms, 0);
-		metaSinkPutc(ms, 16);
-		metaSinkPutUint64(ms, dir->qidOffset);
-		metaSinkPutUint64(ms, dir->qidMax);
-	}
-
-	if(dir->gen != 0) {
-		metaSinkPutc(ms, DirGenEntry);
-		metaSinkPutc(ms, 0);
-		metaSinkPutc(ms, 4);
-		metaSinkPutUint32(ms, dir->gen);
-	}
-
-	metaSinkEOR(ms);
-}
-
-
-void
-plan9ToVacDir(VacDir *vd, Dir *dir, ulong entry, uvlong qid)
-{
-	memset(vd, 0, sizeof(VacDir));
-
-	vd->elem = vtStrDup(dir->name);
-	vd->entry = entry;
-	vd->qid = qid;
-	vd->uid = vtStrDup(dir->uid);
-	vd->gid = vtStrDup(dir->gid);
-	vd->mid = vtStrDup(dir->muid);
-	vd->mtime = dir->mtime;
-	vd->mcount = 0;
-	vd->ctime = dir->mtime;		/* ctime: not available on plan 9 */
-	vd->atime = dir->atime;
-
-	vd->mode = dir->mode & 0777;
-	if(dir->mode & DMDIR)
-		vd->mode |= ModeDir;
-	if(dir->mode & DMAPPEND)
-		vd->mode |= ModeAppend;
-	if(dir->mode & DMEXCL)
-		vd->mode |= ModeExclusive;
-
-	vd->plan9 = 1;
-	vd->p9path = dir->qid.path;
-	vd->p9version = dir->qid.vers;
-}
-
-
-void
-metaSinkEOR(MetaSink *k)
-{
-	uchar *p;
-	int o, n;
-
-	p = k->buf + MetaHeaderSize;
-	p += k->nindex * MetaIndexSize;
-	o = k->rp-k->buf; 	/* offset from start of block */
-	n = k->p-k->rp;		/* size of entry */
-	p[0] = o >> 8;
-	p[1] = o;
-	p[2] = n >> 8;
-	p[3] = n;
-	k->rp = k->p;
-	k->nindex++;
-	if(k->nindex == k->maxindex)
-		metaSinkFlush(k);
-}
-
-void
-metaSinkClose(MetaSink *k)
-{
-	metaSinkFlush(k);
-	sinkClose(k->sink);
-}
-
-void
-metaSinkFree(MetaSink *k)
-{
-	sinkFree(k->sink);
-	vtMemFree(k->buf);
-	vtMemFree(k);
-}
-
-static void
-warn(char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	fprint(2, "%s: ", argv0);
-	vfprint(2, fmt, arg);
-	fprint(2, "\n");
-	va_end(arg);
-}
-
-static void
-cleanup(void)
-{
-	if(oname != nil)
-		remove(oname);
-}
-
-#define TWID64	((u64int)~(u64int)0)
-
-static u64int
-unittoull(char *s)
-{
-	char *es;
-	u64int n;
-
-	if(s == nil)
-		return TWID64;
-	n = strtoul(s, &es, 0);
-	if(*es == 'k' || *es == 'K'){
-		n *= 1024;
-		es++;
-	}else if(*es == 'm' || *es == 'M'){
-		n *= 1024*1024;
-		es++;
-	}else if(*es == 'g' || *es == 'G'){
-		n *= 1024*1024*1024;
-		es++;
-	}
-	if(*es != '\0')
-		return TWID64;
-	return n;
-}
blob - 963a56a0033f424cb033ccdf350e564aad34a638
blob + 7637e03431ca51072ae35eef03a5cf179e1ba5b6
--- src/cmd/vac/vac.c
+++ src/cmd/vac/vac.c
@@ -5,7 +5,18 @@
 #include "dat.h"
 #include "fns.h"
 
-int mainstacksize = 128*1024;
+/*
+ * We're between a rock and a hard place here.
+ * The pw library (getpwnam, etc.) reads the 
+ * password and group files into an on-stack buffer,
+ * so if you have some huge groups, you overflow
+ * the stack.  Because of this, the thread library turns
+ * it off by default, so that dirstat returns "14571" instead of "rsc".
+ * But for vac we want names.  So cautiously turn the pwlibrary
+ * back on (see threadmain) and make the main thread stack huge.
+ */
+extern int _p9usepwlibrary;
+int mainstacksize = 4*1024*1024;
 
 typedef struct Sink Sink;
 typedef struct MetaSink MetaSink;
@@ -101,6 +112,8 @@ int nowrite;
 int merge;
 char *isi;
 
+char **expandargv(char**);
+
 static void
 usage(void)
 {
@@ -116,6 +129,9 @@ threadmain(int argc, char *argv[])
 	char *host = nil;
 	int statsflag = 0;
 
+	/* see comment above */
+	_p9usepwlibrary = 1;
+
 	atexit(cleanup);
 
 	ARGBEGIN{
@@ -194,18 +210,69 @@ threadmain(int argc, char *argv[])
 
 	qsort(exclude, nexclude, sizeof(char*), strpcmp);
 
+	argv = expandargv(argv);
+
 	vac(z, argv);
 
 	if(vtsync(z) < 0)
 		fprint(2, "warning: could not ask server to flush pending writes: %r\n");
 
-	if(statsflag)
+	if(statsflag){
 		fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile,
 			stats.data, stats.skip, stats.sdata, stats.meta);
-/*packetStats(); */
+		dup(2, 1);
+		packetstats();
+	}
 	vthangup(z);
 
 	threadexitsall(0);
+}
+
+// Expand special directory names like / and . and .. into a list of their files.
+char**
+expandargv(char **argv)
+{
+	char **nargv;
+	int nargc;
+	int i, n;
+	Dir *d;
+	int fd;
+	char *s;
+
+	nargc = 0;
+	nargv = nil;
+	for(; *argv; argv++){
+		cleanname(*argv);
+		if(strcmp(*argv, "/") == 0 || strcmp(*argv, ".") == 0 || strcmp(*argv, "..") == 0
+				|| (strlen(*argv) > 3 && strcmp(*argv+strlen(*argv)-3, "/..") == 0)){
+			if((fd = open(*argv, OREAD)) < 0){
+				warn("could not open %s: %r", *argv);
+				continue;
+			}
+			n = dirreadall(fd, &d);
+			close(fd);
+			if(n < 0){
+				warn("could not read %s: %r", *argv);
+				continue;
+			}
+			nargv = vtrealloc(nargv, (nargc+n)*sizeof nargv[0]);
+			for(i=0; i<n; i++){
+				s = vtmalloc(strlen(*argv)+1+strlen(d[i].name)+1);
+				strcpy(s, *argv);
+				strcat(s, "/");
+				strcat(s, d[i].name);
+				cleanname(s);
+				nargv[nargc++] = s;
+			}
+			free(d);
+			continue;
+		}
+		nargv = vtrealloc(nargv, (nargc+1)*sizeof nargv[0]);
+		nargv[nargc++] = *argv;
+	}
+	nargv = vtrealloc(nargv, (nargc+1)*sizeof nargv[0]);
+	nargv[nargc] = nil;
+	return nargv;
 }
 
 static int
@@ -353,7 +420,7 @@ vac(VtConn *z, char *argv[])
 	
 	vtrootpack(&root, buf);
 	if(vacwrite(z, score, VtRootType, buf, VtRootSize) < 0)
-		sysfatal("vacWrite failed: %r");
+		sysfatal("vacwrite: %r");
 
 	fprint(fd, "vac:%V\n", score);
 
@@ -566,7 +633,6 @@ vacdata(DirSink *dsink, int fd, char *lname, VacFile *
 	if(vfblocks > 1)
 		block += vacdataskip(sink, vf, fd, vfblocks, buf, lname);
 
-if(0) fprint(2, "vacData: %s: %ld\n", lname, block);
 	for(;;) {
 		n = readn(fd, buf, bsize);
 		if(0 && n < 0)
@@ -857,7 +923,7 @@ sinkwrite(Sink *k, uchar *p, int n)
 		return;
 
 	if(n > k->dir.dsize)
-		sysfatal("sinkWrite: size too big");
+		sysfatal("sinkwrite: size too big");
 
 	if((k->dir.type&~VtTypeDepthMask) == VtDirType){
 		type = VtDirType;
@@ -867,7 +933,7 @@ sinkwrite(Sink *k, uchar *p, int n)
 		stats.data++;
 	}
 	if(vacwrite(k->z, score, type, p, n) < 0)
-		sysfatal("vacWrite failed: %r");
+		sysfatal("vacwrite: %r");
 
 	sinkwritescore(k, score, n);
 }
@@ -924,7 +990,7 @@ sinkclose(Sink *k)
 		p = k->buf+i*kd->psize;
 		stats.meta++;
 		if(vacwrite(k->z, k->pbuf[i+1], base+1+i, p, k->pbuf[i]-p) < 0)
-			sysfatal("vacWrite failed: %r");
+			sysfatal("vacwrite: %r");
 		k->pbuf[i+1] += VtScoreSize;
 	}
 	memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
@@ -1141,6 +1207,7 @@ metasinkwrite(MetaSink *k, uchar *data, int n)
 void
 metasinkwritedir(MetaSink *ms, VacDir *dir)
 {
+	
 	metasinkputuint32(ms, DirMagic);
 	metasinkputc(ms, Version>>8);
 	metasinkputc(ms, Version);		
@@ -1218,7 +1285,6 @@ plan9tovacdir(VacDir *vd, Dir *dir, ulong entry, uvlon
 	vd->p9version = dir->qid.vers;
 }
 
-
 void
 metasinkeor(MetaSink *k)
 {
blob - 6d5a82053cb18b94a1c50b24d1430eb500bb773a
blob + a0c4a91fb49027583ddd0eaae957bcf2604d4c45
--- src/cmd/vac/vac.h
+++ src/cmd/vac/vac.h
@@ -101,13 +101,6 @@ int		vacfssync(VacFs *fs);
 int		vacfssnapshot(VacFs *fs, char *src, char *dst);
 int		vacfsgetscore(VacFs *fs, u8int *score);
 
-/* 
- * other ideas
- *
- * VacFs *vfsSnapshot(VacFs*, char *src);
- * int vfsGraft(VacFs*, char *name, VacFs*);
- */
-
 VacFile *vacfsgetroot(VacFs *fs);
 VacFile	*vacfileopen(VacFs *fs, char *path);
 VacFile	*vacfilecreate(VacFile *file, char *elem, ulong perm, char *muid);
@@ -140,4 +133,4 @@ void		vdcopy(VacDir *dst, VacDir *src);
 VacDirEnum	*vdeopen(VacFile*);
 int			vderead(VacDirEnum*, VacDir *);
 void			vdeclose(VacDirEnum*);
-
+int	vdeunread(VacDirEnum*);
blob - 8cf786426cefe54f1da005987a43c8a25d2489ad
blob + 1ce3e2df57f6fc902478335128b230acd45bfe85
--- src/cmd/vac/vacfs.c
+++ src/cmd/vac/vacfs.c
@@ -5,18 +5,12 @@
 #include "vac.h"
 
 typedef struct Fid Fid;
-typedef struct DirBuf DirBuf;
 
 enum
 {
 	OPERM	= 0x3		/* mask of all permission types in open mode */
 };
 
-enum
-{
-	DirBufSize = 20
-};
-
 struct Fid
 {
 	short busy;
@@ -25,20 +19,10 @@ struct Fid
 	char *user;
 	Qid qid;
 	VacFile *file;
-
-	DirBuf *db;
-
+	VacDirEnum *vde;
 	Fid	*next;
 };
 
-struct DirBuf
-{
-	VacDirEnum *vde;
-	VacDir buf[DirBufSize];
-	int i, n;
-	int eof;
-};
-
 enum
 {
 	Pexec =		1,
@@ -73,12 +57,8 @@ int	perm(Fid*, int);
 int	permf(VacFile*, char*, int);
 ulong	getl(void *p);
 void	init(char*, char*, long, int);
-DirBuf	*dirBufAlloc(VacFile*);
-VacDir	*dirBufGet(DirBuf*);
-int	dirBufUnget(DirBuf*);
-void	dirBufFree(DirBuf*);
 int	vacdirread(Fid *f, char *p, long off, long cnt);
-int	vdStat(VacFile *parent, VacDir *vd, uchar *p, int np);
+int	vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
 void 	srv(void* a);
 
 
@@ -141,7 +121,6 @@ threadmain(int argc, char *argv[])
 	int stdio = 0;
 	char *host = nil;
 	long ncache = 1000;
-	int readOnly = 1;
 
 	fmtinstall('H', encodefmt);
 	fmtinstall('V', vtscorefmt);
@@ -184,8 +163,21 @@ threadmain(int argc, char *argv[])
 		usage();
 
 	initfcalls();
-	init(argv[0], host, ncache, readOnly);
 
+	notify(notifyf);
+	user = getuser();
+
+	conn = vtdial(host);
+	if(conn == nil)
+		sysfatal("could not connect to server: %r");
+
+	if(vtconnect(conn) < 0)
+		sysfatal("vtconnect: %r");
+
+	fs = vacfsopen(conn, argv[0], VtOREAD, ncache);
+	if(fs == nil)
+		sysfatal("vacfsopen: %r");
+
 	if(pipe(p) < 0)
 		sysfatal("pipe failed: %r");
 
@@ -294,19 +286,6 @@ rattach(Fid *f)
 	return 0;
 }
 
-VacFile*
-_vfWalk(VacFile *file, char *name)
-{
-	VacFile *n;
-
-	n = vacfilewalk(file, name);
-	if(n)
-		return n;
-	if(strcmp(name, "SLASH") == 0)
-		return vacfilewalk(file, "/");
-	return nil;
-}
-
 char*
 rwalk(Fid *f)
 {
@@ -356,7 +335,7 @@ rwalk(Fid *f)
 			err = Eperm;
 			break;
 		}
-		nfile = _vfWalk(file, rhdr.wname[nqid]);
+		nfile = vacfilewalk(file, rhdr.wname[nqid]);
 		if(nfile == nil)
 			break;
 		vacfiledecref(file);
@@ -410,7 +389,7 @@ ropen(Fid *f)
 		if(!perm(f, Pread))
 			return vtstrdup(Eperm);
 		thdr.qid = f->qid;
-		f->db = nil;
+		f->vde = nil;
 		f->open = 1;
 		return 0;
 	}
@@ -564,8 +543,8 @@ rclunk(Fid *f)
 	if(f->file)
 		vacfiledecref(f->file);
 	f->file = nil;
-	dirBufFree(f->db);
-	f->db = nil;
+	vdeclose(f->vde);
+	f->vde = nil;
 	return 0;
 }
 
@@ -588,8 +567,6 @@ rremove(Fid *f)
 
 	if(!vacfileremove(vf, "none")) {
 		rerrstr(errbuf, sizeof errbuf);
-print("vfRemove failed: %s\n", errbuf);
-
 		err = errbuf;
 	}
 
@@ -611,7 +588,7 @@ rstat(Fid *f)
 	parent = vacfilegetparent(f->file);
 	vacfilegetdir(f->file, &dir);
 	thdr.stat = statbuf;
-	thdr.nstat = vdStat(parent, &dir, thdr.stat, sizeof statbuf);
+	thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
 	vdcleanup(&dir);
 	vacfiledecref(parent);
 	return 0;
@@ -626,7 +603,7 @@ rwstat(Fid *f)
 }
 
 int
-vdStat(VacFile *parent, VacDir *vd, uchar *p, int np)
+vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
 {
 	char *ext;
 	int n, ret;
@@ -692,98 +669,41 @@ vdStat(VacFile *parent, VacDir *vd, uchar *p, int np)
 	ret = convD2Mu(&dir, p, np, dotu);
 	free(ext);
 	return ret;
-}
-
-DirBuf*
-dirBufAlloc(VacFile *vf)
-{
-	DirBuf *db;
-
-	db = vtmallocz(sizeof(DirBuf));
-	db->vde = vdeopen(vf);
-	return db;
-}
-
-VacDir *
-dirBufGet(DirBuf *db)
-{
-	VacDir *vd;
-	int n;
-
-	if(db->eof)
-		return nil;
-
-	if(db->i >= db->n) {
-		n = vderead(db->vde, db->buf);
-		if(n < 0)
-			return nil;
-		db->i = 0;
-		db->n = n;
-		if(n == 0) {
-			db->eof = 1;
-			return nil;
-		}
-	}
-
-	vd = db->buf + db->i;
-	db->i++;
-
-	return vd;
 }
 
 int
-dirBufUnget(DirBuf *db)
-{
-	assert(db->i > 0);
-	db->i--;
-	return 1;
-}
-
-void
-dirBufFree(DirBuf *db)
-{
-	int i;
-
-	if(db == nil)
-		return;
-
-	for(i=db->i; i<db->n; i++)
-		vdcleanup(db->buf + i);
-	vdeclose(db->vde);
-	vtfree(db);
-}
-
-int
 vacdirread(Fid *f, char *p, long off, long cnt)
 {
-	int n, nb;
-	VacDir *vd;
+	int i, n, nb;
+	VacDir vd;
 
 	/*
 	 * special case of rewinding a directory
 	 * otherwise ignore the offset
 	 */
-	if(off == 0 && f->db) {
-		dirBufFree(f->db);
-		f->db = nil;
+	if(off == 0 && f->vde){
+		vdeclose(f->vde);
+		f->vde = nil;
 	}
 
-	if(f->db == nil)
-		f->db = dirBufAlloc(f->file);
+	if(f->vde == nil){
+		f->vde = vdeopen(f->file);
+		if(f->vde == nil)
+			return -1;
+	}
 
 	for(nb = 0; nb < cnt; nb += n) {
-		vd = dirBufGet(f->db);
-		if(vd == nil) {
-			if(!f->db->eof)
-				return -1;
+		i = vderead(f->vde, &vd);
+		if(i < 0)
+			return -1;
+		if(i == 0)
 			break;
-		}
-		n = vdStat(f->file, vd, (uchar*)p, cnt-nb);
+		n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
 		if(n <= BIT16SZ) {
-			dirBufUnget(f->db);
+			vdeunread(f->vde);
 			break;
 		}
-		vdcleanup(vd);
+		vdcleanup(&vd);
 		p += n;
 	}
 	return nb;
@@ -886,24 +806,6 @@ perm(Fid *f, int p)
 }
 
 void
-init(char *file, char *host, long ncache, int readOnly)
-{
-	notify(notifyf);
-	user = getuser();
-
-	conn = vtdial(host);
-	if(conn == nil)
-		sysfatal("could not connect to server: %r");
-
-	if(vtconnect(conn) < 0)
-		sysfatal("vtconnect: %r");
-
-	fs = vacfsopen(conn, file, /*readOnly ? ModeSnapshot :*/ VtOREAD, ncache);
-	if(fs == nil)
-		sysfatal("vfsOpen: %r");
-}
-
-void
 vacshutdown(void)
 {
 	Fid *f;
blob - c456604f854b14b6e115a3712af29ff6d45da428 (mode 644)
blob + /dev/null
--- src/cmd/vac/vactest.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include "stdinc.h"
-#include "vac.h"
-#include "dat.h"
-#include "fns.h"
-
-void usage(void);
-int unvac(VacFS *fs);
-int readScore(int fd, uchar score[VtScoreSize]);
-static void warn(char *fmt, ...);
-void dirlist(VacFS *fs, char *path);
-
-static	int	nwant;
-static	char	**want;
-static	int	dflag = 1;
-static	int	cflag;
-static	int	lower;
-static	int	verbose;
-static	int	settimes;
-
-void
-main(int argc, char *argv[])
-{
-	char *zfile;
-	int ok, table;
-	VtSession *z;
-	char *vsrv = nil;
-	char *host = nil;
-	char *p;
-	int ncache = 1000;
-	VacFS *fs;
-
-	table = 0;
-	zfile = nil;
-	ARGBEGIN{
-	case 'D':
-		dflag++;
-		break;
-	case 'c':
-		cflag++;
-		break;
-	case 'C':
-		p = ARGF();
-		if(p == nil)
-			usage();
-		ncache = atoi(p);
-		if(ncache < 10)
-			ncache = 10;
-		if(ncache > 1000000)
-			ncache = 1000000;
-		break;
-	case 'i':
-		lower++;
-		break;
-	case 'f':
-		zfile = ARGF();
-		if(zfile == nil)
-			usage();
-		break;
-	case 'h':
-		host = ARGF();
-		break;
-	case 't':
-		table++;
-		break;
-	case 'T':
-		settimes++;
-		break;
-	case 's':
-		vsrv = ARGF();
-		break;
-	case 'v':
-		verbose++;
-		break;
-	default:
-		usage();
-		break;
-	}ARGEND
-
-	nwant = argc;
-	want = argv;
-
-	vtAttach();
-
-	if(zfile == nil)
-		usage();
-
-	if(vsrv != nil)
-		z = vtStdioServer(vsrv);
-	else
-		z = vtDial(host);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-	vtSetDebug(z, 0);
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-	fs = vfsOpen(z, zfile, 1, ncache);
-	if(fs == nil)
-		vtFatal("vfsOpen: %s", vtGetError());
-	ok = unvac(fs);
-	vtClose(z);
-	vtDetach();
-	
-	exits(ok? 0 : "error");
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-tTcDv] -f zipfile [-s ventid] [-h host] [file ...]\n", argv0);
-	exits("usage");
-}
-
-void
-suck(VacFile *f)
-{
-	USED(f);
-}
-
-
-void
-vacfile(VacFS *fs, char *path, VacDir *vd)
-{
-	char *path2;
-
-	path2 = vtMemAlloc(strlen(path) + 1 + strlen(vd->elem) + 1);
-	if(path[1] == 0)
-		sprintf(path2, "/%s", vd->elem);
-	else
-		sprintf(path2, "%s/%s", path, vd->elem);
-fprint(2, "vac file: %s\n", path2);
-	if(vd->mode & ModeDir)
-		dirlist(fs, path2);
-	vtMemFree(path2);
-}
-
-void
-dirlist(VacFS *fs, char *path)
-{
-	VacDir vd[50];
-	VacDirEnum *ds;
-	int i, n;
-
-	ds = vdeOpen(fs, path);
-	if(ds == nil) {
-		fprint(2, "could not open: %s: %s\n", path, vtGetError());
-		return;
-	}
-	for(;;) {
-		n = vdeRead(ds, vd, sizeof(vd)/sizeof(VacDir));
-		if(n < 0) {
-			warn("vdRead failed: %s: %s", path, vtGetError());
-			return;
-		}
-		if(n == 0)
-			break;
-		for(i=0; i<n; i++) {
-			vacfile(fs, path, &vd[i]);
-			vdCleanup(&vd[i]);
-		}
-	}
-	vdeFree(ds);
-}
-
-int
-unvac(VacFS *fs)
-{
-	dirlist(fs, "/");
-
-	return 1;
-}
-
-static void
-warn(char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	fprint(2, "%s: ", argv0);
-	vfprint(2, fmt, arg);
-	fprint(2, "\n");
-	va_end(arg);
-}
blob - 8550279f4c88e7541015e2c553fc87d0db7e1f84 (mode 644)
blob + /dev/null
--- src/cmd/vac/vtread.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include "stdinc.h"
-#include <bio.h>
-
-typedef struct Source Source;
-
-struct Source
-{
-	ulong gen;
-	int psize;
-	int dsize;
-	int dir;
-	int active;
-	int depth;
-	uvlong size;
-	uchar score[VtScoreSize];
-	int reserved;
-};
-
-int bsize;
-Biobuf *bout;
-VtRootLump root;
-int ver;
-int cmp;
-int all;
-int find;
-uchar fscore[VtScoreSize];
-int dirSize;
-void (*parse)(Source*, uchar*);
-VtSession *z;
-
-int vtGetUint16(uchar *p);
-ulong vtGetUint32(uchar *p);
-uvlong vtGetUint48(uchar *p);
-void usage(void);
-int parseScore(uchar *score, char *buf, int n);
-void readRoot(VtRootLump*, uchar *score, char *file);
-void parse1(Source*, uchar*);
-void parse2(Source*, uchar*);
-int dumpDir(Source*, int indent);
-
-void
-main(int argc, char *argv[])
-{
-	char *host = nil;
-	uchar score[VtScoreSize];
-	uchar buf[VtMaxLumpSize];
-	int type;
-	int n;
-	
-	type = VtDataType;
-
-	ARGBEGIN{
-	case 't':
-		type = atoi(ARGF());
-		break;
-	}ARGEND
-
-	vtAttach();
-
-	bout = vtMemAllocZ(sizeof(Biobuf));
-	Binit(bout, 1, OWRITE);
-
-	if(argc != 1)
-		usage();
-
-	vtAttach();
-
-	fmtinstall('V', vtScoreFmt);
-	fmtinstall('R', vtErrFmt);
-
-	z = vtDial(host);
-	if(z == nil)
-		vtFatal("could not connect to server: %s", vtGetError());
-
-	if(!vtConnect(z, 0))
-		sysfatal("vtConnect: %r");
-
-	if(!parseScore(score, argv[0], strlen(argv[0])))
-		vtFatal("could not parse score: %s", vtGetError());
-
-	n = vtRead(z, score, type, buf, VtMaxLumpSize);
-	if(n < 0)
-		vtFatal("could not read block: %s", vtGetError());
-	Bwrite(bout, buf, n);
-
-	Bterm(bout);
-
-	vtClose(z);
-	vtDetach();
-	exits(0);
-}
-
-void
-usage(void)
-{
-	fprint(2, "%s: -t type score\n", argv0);
-	exits("usage");
-}
-
-int
-parseScore(uchar *score, char *buf, int n)
-{
-	int i, c;
-
-	memset(score, 0, VtScoreSize);
-
-	if(n < VtScoreSize*2)
-		return 0;
-	for(i=0; i<VtScoreSize*2; i++) {
-		if(buf[i] >= '0' && buf[i] <= '9')
-			c = buf[i] - '0';
-		else if(buf[i] >= 'a' && buf[i] <= 'f')
-			c = buf[i] - 'a' + 10;
-		else if(buf[i] >= 'A' && buf[i] <= 'F')
-			c = buf[i] - 'A' + 10;
-		else {
-			return 0;
-		}
-
-		if((i & 1) == 0)
-			c <<= 4;
-	
-		score[i>>1] |= c;
-	}
-	return 1;
-}
blob - 35dc8233bc46cb8dfdadcfee68e8fde91e20ff3a (mode 644)
blob + /dev/null
--- src/cmd/vac/wtest.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "stdinc.h"
-
-enum {
-	Nblock = 10000,
-	BlockSize = 8*1024
-};
-
-uchar data[Nblock*BlockSize];
-
-void
-main(int argc, char *argv[])
-{
-	VtSession *z;
-	int i;
-	uchar score[VtScoreSize];
-	int start;
-
-	ARGBEGIN{
-	}ARGEND
-
-	for(i=0; i<Nblock; i++) {
-		if(readn(0, data+i*BlockSize, BlockSize) < BlockSize)
-			sysfatal("read failed: %r");
-	}
-
-	vtAttach();
-
-	z = vtDial("iolaire2");
-	if(z == nil)
-		sysfatal("cound not connect to venti");
-	if(!vtConnect(z, 0))
-		vtFatal("vtConnect: %s", vtGetError());
-
-	print("starting\n");
-
-	start = times(0);
-
-	for(i=0; i<Nblock; i++) {
-		if(!vtWrite(z, score, VtDataType, data+i*BlockSize, BlockSize))
-			vtFatal("vtWrite failed: %s", vtGetError());
-	}
-
-	print("time = %f\n", (times(0) - start)*0.001);
-
-	vtClose(z);
-	vtDetach();
-}