1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237 |
- #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 {
- Debug = 1,
- 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 *host = nil;
- int statsFlag = 0;
- atexit(cleanup);
- ARGBEGIN{
- default:
- usage();
- case 'b':
- bsize = unittoull(EARGF(usage()));
- if(bsize == ~0)
- usage();
- break;
- case 'd':
- dfile = EARGF(usage());
- break;
- case 'e':
- if(nexclude >= MaxExclude)
- sysfatal("too many exclusions");
- exclude[nexclude++] = EARGF(usage());
- break;
- case 'f':
- oname = EARGF(usage());
- break;
- case 'h':
- host = EARGF(usage());
- break;
- case 'i':
- isi = EARGF(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,
- "%s: warning: could not ask server to flush pending writes: %R\n",
- argv0);
- if(statsFlag)
- fprint(2, "%s: files %ld:%ld data %ld:%ld:%ld meta %ld\n",
- argv0, stats.file, stats.sfile,
- stats.data, stats.skip, stats.sdata, stats.meta);
- //packetStats();
- vtClose(z);
- vtDetach();
- exits(0);
- }
- static void
- 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, "%s: vtSha1Check: n = %d %V %V\n",
- argv0, 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");
- dsink = dirSinkAlloc(z, bsize, bsize);
- fs = nil;
- if(dfile != nil) {
- fs = vfsOpen(z, dfile, 1, 10000);
- if(fs == nil)
- fprint(2, "%s: could not open diff: %s: %s\n",
- argv0, 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';
- if (chdir(*argv) < 0)
- sysfatal("can't cd to %s: %r", *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", 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;
- Dir fake;
- 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());
- /*
- * fake up dsink & vf contents so we don't explode later.
- * I'm not certain that this is needed, but it seems like
- * a wise precaution.
- */
- entry = dsink->nentry;
- /* pretend it's a plain file */
- dir = &fake;
- nulldir(dir);
- dir->type = 'M';
- dir->dev = 10;
- dir->qid = (Qid){ 10, 2, QTFILE};
- dir->mode = 0664;
- dir->atime = dir->mtime = time(nil);
- dir->length = 0;
- dir->name = sname;
- dir->uid = dir->gid = dir->muid = "missing";
- vacData(dsink, fd, lname, vf, dir);
- plan9ToVacDir(&vd, dir, entry, fileid++);
- metaSinkWriteDir(dsink->msink, &vd);
- vdCleanup(&vd);
- 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 && vd.size == dir->length &&
- (!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) && vd.size < dir->length &&
- vd.plan9 && 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))
- 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;
- char *name;
- int i, nd;
- DirSink *ds;
- VacFile *vvf;
- /*
- * if we could see the score underlying dir, we could quickly
- * short-circuit further directory descent if vf (see vacfs(vf)->score)
- * and dir had identical scores.
- */
- 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 || name[0] == '/' ||
- strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
- continue;
- ln = smprint("%s/%s", lname, name);
- sn = smprint("%s/%s", sname, name);
- if (ln == nil || sn == nil)
- sysfatal("out of memory");
- if(vf != nil)
- vvf = vfWalk(vf, name);
- else
- vvf = nil;
- vacFile(ds, ln, sn, vvf);
- if(vvf != nil)
- vfDecRef(vvf);
- free(ln);
- free(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 be 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, "%s: merging: %s\n", argv0, 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;
- }
|