aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vac
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2008-06-15 01:19:37 -0400
committerRuss Cox <rsc@swtch.com>2008-06-15 01:19:37 -0400
commit003c13aa185cebc8797b8b04e8bd0722643467aa (patch)
tree248ed1d3e36efaf6e4bff072e460800137b8dfc2 /src/cmd/vac
parentada3d479a7d132a0da51a2cca3e9354bf2e7661c (diff)
downloadplan9port-003c13aa185cebc8797b8b04e8bd0722643467aa.tar.gz
plan9port-003c13aa185cebc8797b8b04e8bd0722643467aa.tar.bz2
plan9port-003c13aa185cebc8797b8b04e8bd0722643467aa.zip
vac: make qids unique
Diffstat (limited to 'src/cmd/vac')
-rw-r--r--src/cmd/vac/file.c49
-rw-r--r--src/cmd/vac/fns.h1
-rw-r--r--src/cmd/vac/mkfile4
-rw-r--r--src/cmd/vac/pack.c2
-rw-r--r--src/cmd/vac/vac.c1684
-rw-r--r--src/cmd/vac/vac.h9
-rw-r--r--src/cmd/vac/vtdump.c372
7 files changed, 557 insertions, 1564 deletions
diff --git a/src/cmd/vac/file.c b/src/cmd/vac/file.c
index 53cc95e3..fac419b1 100644
--- a/src/cmd/vac/file.c
+++ b/src/cmd/vac/file.c
@@ -45,6 +45,8 @@ struct VacFile
VtFile *msource; /* metadata for children in a directory */
VacFile *down; /* children */
int mode;
+
+ uvlong qidoffset; /* qid offset */
};
static VacFile*
@@ -140,7 +142,7 @@ uvlong
vacfilegetid(VacFile *f)
{
/* immutable */
- return f->dir.qid;
+ return f->qidoffset + f->dir.qid;
}
ulong
@@ -400,6 +402,7 @@ dirlookup(VacFile *f, char *elem)
filefree(ff);
goto Err;
}
+ ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
vtfileunlock(meta);
vtblockput(b);
ff->boff = bo;
@@ -993,6 +996,7 @@ Found:
me.p = p;
me.size = n;
vdpack(dir, &me, VacDirVersion);
+vdunpack(dir, &me);
mbinsert(&mb, i, &me);
mbpack(&mb);
vtblockput(b);
@@ -1062,6 +1066,7 @@ filemetaflush(VacFile *f, char *oelem)
/* Pack new data into new location. */
vdpack(&f->dir, &me, VacDirVersion);
+vdunpack(&f->dir, &me);
mbinsert(&mb, i, &me);
mbpack(&mb);
@@ -1269,6 +1274,7 @@ vacfilecreate(VacFile *fp, char *elem, ulong mode)
if(vtfilelock2(fp->source, fp->msource, -1) < 0)
goto Err1;
ff = filealloc(fp->fs);
+ ff->qidoffset = fp->qidoffset; /* hopefully fp->qidoffset == 0 */
type = VtDataType;
if(mode & ModeDir)
type = VtDirType;
@@ -1601,10 +1607,16 @@ vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
if(filelock(f) < 0)
return -1;
+ if(f->source->mode != VtORDWR){
+ fileunlock(f);
+ werrstr(EReadOnly);
+ return -1;
+ }
filemetalock(f);
f->dir.qidspace = 1;
f->dir.qidoffset = offset;
f->dir.qidmax = max;
+ f->dirty = 1;
ret = filemetaflush(f, nil);
filemetaunlock(f);
fileunlock(f);
@@ -1853,6 +1865,34 @@ _vacfsnextqid(VacFs *fs, uvlong *qid)
}
void
+vacfsjumpqid(VacFs *fs, uvlong step)
+{
+ fs->qid += step;
+}
+
+/*
+ * Set *maxqid to the maximum qid expected in this file system.
+ * In newer vac archives, the maximum qid is stored in the
+ * qidspace VacDir annotation. In older vac archives, the root
+ * got created last, so it had the maximum qid.
+ */
+int
+vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
+{
+ VacDir vd;
+
+ if(vacfilegetdir(fs->root, &vd) < 0)
+ return -1;
+ if(vd.qidspace)
+ *maxqid = vd.qidmax;
+ else
+ *maxqid = vd.qid;
+ vdcleanup(&vd);
+ return 0;
+}
+
+
+void
vacfsclose(VacFs *fs)
{
if(fs->root)
@@ -1952,6 +1992,13 @@ vacfssync(VacFs *fs)
/* Sync the entire vacfs to disk. */
if(vacfileflush(fs->root, 1) < 0)
return -1;
+ if(vtfilelock(fs->root->up->msource, -1) < 0)
+ return -1;
+ if(vtfileflush(fs->root->up->msource) < 0){
+ vtfileunlock(fs->root->up->msource);
+ return -1;
+ }
+ vtfileunlock(fs->root->up->msource);
/* Prepare the dir stream for the root block. */
if(getentry(fs->root->source, &e) < 0)
diff --git a/src/cmd/vac/fns.h b/src/cmd/vac/fns.h
index 27cd479f..3cf87840 100644
--- a/src/cmd/vac/fns.h
+++ b/src/cmd/vac/fns.h
@@ -22,3 +22,4 @@ void vdpack(VacDir *dir, MetaEntry*, int);
VacFile *_vacfileroot(VacFs *fs, VtFile *file);
int _vacfsnextqid(VacFs *fs, uvlong *qid);
+void vacfsjumpqid(VacFs*, uvlong step);
diff --git a/src/cmd/vac/mkfile b/src/cmd/vac/mkfile
index 224ab882..98e122b8 100644
--- a/src/cmd/vac/mkfile
+++ b/src/cmd/vac/mkfile
@@ -15,10 +15,8 @@ HFILES=\
dat.h\
fns.h\
-TARG=vac vacfs unvac # vtdump
+TARG=vac vacfs unvac
default:V: all
-test:V: $O.srcload $O.wtest $O.rtest $O.vtdump $O.vtread
-
<$PLAN9/src/mkmany
diff --git a/src/cmd/vac/pack.c b/src/cmd/vac/pack.c
index cb92fad8..9777464f 100644
--- a/src/cmd/vac/pack.c
+++ b/src/cmd/vac/pack.c
@@ -463,7 +463,7 @@ vdpack(VacDir *dir, MetaEntry *me, int version)
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);
diff --git a/src/cmd/vac/vac.c b/src/cmd/vac/vac.c
index 71244f43..c1508549 100644
--- a/src/cmd/vac/vac.c
+++ b/src/cmd/vac/vac.c
@@ -1,154 +1,103 @@
-#include <u.h>
-#include <sys/stat.h>
#include "stdinc.h"
#include "vac.h"
#include "dat.h"
#include "fns.h"
-/*
- * 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;
-typedef struct DirSink DirSink;
-
-struct Sink {
- VtConn *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 */
-};
+// TODO: qids
-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(const void*, const void*);
-static void warn(char *fmt, ...);
-static void cleanup(void);
-static u64int unittoull(char *s);
-static void vac(VtConn *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);
-static int vacspecial(DirSink *dsink, Dir *dir, char *lname, char *sname, VacFile *vf);
-Sink *sinkalloc(VtConn *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(VtConn *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(VtConn *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);
+void
+usage(void)
+{
+ fprint(2, "usage: vac [-b blocksize] [-h host] file...\n");
+ threadexitsall("usage");
+}
-enum {
- Version = 8,
+enum
+{
BlockSize = 8*1024,
MaxExclude = 1000
};
-struct {
- ulong file;
- ulong sfile;
- ulong data;
- ulong sdata;
- ulong skip;
- ulong meta;
+struct
+{
+ int nfile;
+ int ndir;
+ vlong data;
+ vlong skipdata;
+ int skipfiles;
} stats;
-int bsize = BlockSize;
-int maxbsize;
-char *oname, *dfile;
-int verbose;
-uvlong fileid = 1;
int qdiff;
+int merge;
+int verbose;
+char *host;
+VtConn *z;
+VacFs *fs;
char *exclude[MaxExclude];
int nexclude;
-int nowrite;
-int merge;
-char *isi;
+char *vacfile;
-char **expandargv(char**);
+int vacmerge(VacFile*, char*);
+void vac(VacFile*, VacFile*, char*, Dir*);
+void vacstdin(VacFile*, char*);
-static void
-usage(void)
-{
- fprint(2, "usage: %s [-amqsv] [-h host] [-d vacfile] [-b blocksize] [-i name] [-e exclude] [-f vacfile] file ... \n", argv0);
- threadexitsall("usage");
-}
+static u64int unittoull(char*);
+static void warn(char *fmt, ...);
+static int strpcmp(const void*, const void*);
+static void removevacfile(void);
+
+/*
+ * 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;
void
-threadmain(int argc, char *argv[])
+threadmain(int argc, char **argv)
{
- VtConn *z;
- char *p;
- char *host = nil;
- int statsflag = 0;
-
+ int i, j, fd, n, printstats;
+ Dir *d;
+ char *s;
+ uvlong u;
+ VacFile *f, *fdiff;
+ VacFs *fsdiff;
+ int blocksize;
+ int outfd;
+ char *stdinname;
+ char *diffvac;
+ uvlong qid;
+
+#ifdef PLAN9PORT
/* see comment above */
_p9usepwlibrary = 1;
+#endif
- atexit(cleanup);
+ fmtinstall('H', encodefmt);
+ fmtinstall('V', vtscorefmt);
+ blocksize = BlockSize;
+ stdinname = nil;
+ printstats = 0;
+ fsdiff = nil;
+ diffvac = nil;
ARGBEGIN{
- default:
- usage();
case 'b':
- p = ARGF();
- if(p == 0)
- usage();
- bsize = unittoull(p);
- if(bsize == ~0)
- usage();
+ u = unittoull(EARGF(usage()));
+ if(u < 512)
+ u = 512;
+ if(u > VtMaxLumpSize)
+ u = VtMaxLumpSize;
+ blocksize = u;
break;
case 'd':
- dfile = ARGF();
- if(dfile == nil)
- usage();
+ diffvac = EARGF(usage());
break;
case 'e':
if(nexclude >= MaxExclude)
@@ -159,22 +108,13 @@ threadmain(int argc, char *argv[])
nexclude++;
break;
case 'f':
- oname = ARGF();
- if(oname == 0)
- usage();
+ vacfile = EARGF(usage());
break;
case 'h':
- host = ARGF();
- if(host == nil)
- usage();
+ host = EARGF(usage());
break;
case 'i':
- isi = ARGF();
- if(isi == nil)
- usage();
- break;
- case 'n':
- nowrite++;
+ stdinname = EARGF(usage());
break;
case 'm':
merge++;
@@ -183,249 +123,135 @@ threadmain(int argc, char *argv[])
qdiff++;
break;
case 's':
- statsflag++;
+ printstats++;
break;
case 'v':
verbose++;
break;
- }ARGEND;
-
- if(argc == 0)
+ default:
+ usage();
+ }ARGEND
+
+ if(argc == 0 && !stdinname)
usage();
- if(bsize < 512)
- bsize = 512;
- if(bsize > VtMaxLumpSize)
- bsize = VtMaxLumpSize;
- maxbsize = bsize;
+ if(vacfile == nil)
+ outfd = 1;
+ else if((outfd = create(vacfile, OWRITE, 0666)) < 0)
+ sysfatal("create %s: %r", vacfile);
+ atexit(removevacfile);
- fmtinstall('V', vtscorefmt);
+ qsort(exclude, nexclude, sizeof(char*), strpcmp);
z = vtdial(host);
if(z == nil)
sysfatal("could not connect to server: %r");
-
if(vtconnect(z) < 0)
sysfatal("vtconnect: %r");
-
- 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){
- fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile,
- stats.data, stats.skip, stats.sdata, stats.meta);
- dup(2, 1);
- packetstats();
+
+ if(diffvac){
+ if((fsdiff = vacfsopen(z, diffvac, VtOREAD, 128)) == nil)
+ warn("vacfsopen %s: %r", diffvac);
}
- 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;
+ if((fs = vacfscreate(z, blocksize, 512)) == nil)
+ sysfatal("vacfscreate: %r");
- 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);
+ f = vacfsgetroot(fs);
+ if(fsdiff)
+ fdiff = vacfsgetroot(fsdiff);
+ else
+ fdiff = nil;
+ if(stdinname)
+ vacstdin(f, stdinname);
+ for(i=0; i<argc; i++){
+ // We can't use / and . and .. and ../.. as valid archive
+ // names, so expand to the list of files in the directory.
+ if(argv[i][0] == 0){
+ warn("empty string given as command-line argument");
+ continue;
+ }
+ cleanname(argv[i]);
+ if(strcmp(argv[i], "/") == 0
+ || strcmp(argv[i], ".") == 0
+ || strcmp(argv[i], "..") == 0
+ || (strlen(argv[i]) > 3 && strcmp(argv[i]+strlen(argv[i])-3, "/..") == 0)){
+ if((fd = open(argv[i], OREAD)) < 0){
+ warn("open %s: %r", argv[i]);
continue;
}
- n = dirreadall(fd, &d);
- close(fd);
- if(n < 0){
- warn("could not read %s: %r", *argv);
- continue;
+ while((n = dirread(fd, &d)) > 0){
+ for(j=0; j<n; j++){
+ s = vtmalloc(strlen(argv[i])+1+strlen(d[j].name)+1);
+ strcpy(s, argv[i]);
+ strcat(s, "/");
+ strcat(s, d[j].name);
+ cleanname(s);
+ vac(f, fdiff, s, &d[j]);
+ }
+ free(d);
}
- 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);
+ close(fd);
+ continue;
+ }
+ if((d = dirstat(argv[i])) == nil){
+ warn("stat %s: %r", argv[i]);
continue;
}
- nargv = vtrealloc(nargv, (nargc+1)*sizeof nargv[0]);
- nargv[nargc++] = *argv;
+ vac(f, fdiff, argv[i], d);
+ free(d);
}
- nargv = vtrealloc(nargv, (nargc+1)*sizeof nargv[0]);
- nargv[nargc] = nil;
- return nargv;
-}
-
-static int
-strpcmp(const void *p0, const void *p1)
-{
- return strcmp(*(char**)p0, *(char**)p1);
-}
+ if(fdiff)
+ vacfiledecref(fdiff);
+
+ /*
+ * Record the maximum qid so that vacs can be merged
+ * without introducing overlapping qids. Older versions
+ * of vac arranged that the root would have the largest
+ * qid in the file system, but we can't do that anymore
+ * (the root gets created first!).
+ */
+ if(_vacfsnextqid(fs, &qid) >= 0)
+ vacfilesetqidspace(f, 0, qid);
+ vacfiledecref(f);
+
+ /*
+ * Copy fsdiff's root block score into fs's slot for that,
+ * so that vacfssync will copy it into root.prev for us.
+ * Just nice documentation, no effect.
+ */
+ if(fsdiff)
+ memmove(fs->score, fsdiff->score, VtScoreSize);
+ if(vacfssync(fs) < 0)
+ fprint(2, "vacfssync: %r\n");
+
+ fprint(outfd, "vac:%V\n", fs->score);
+ vacfsclose(fs);
+ atexitdont(removevacfile);
+ vthangup(z);
-int
-vacwrite(VtConn *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
-{
- assert(n > 0);
- if(nowrite){
- sha1(buf, n, score, nil);
- return 0;
+ if(printstats){
+ fprint(2,
+ "%d files, %d files skipped, %d directories\n"
+ "%lld data bytes written, %lld data bytes skipped\n",
+ stats.nfile, stats.skipfiles, stats.ndir, stats.data, stats.skipdata);
+ dup(2, 1);
+ packetstats();
}
- return vtwrite(z, score, type, buf, n);
+ threadexitsall(0);
}
-static char*
-lastelem(char *oname)
+static void
+removevacfile(void)
{
- char *p;
-
- if(oname == nil)
- abort();
- if((p = strrchr(oname, '/')) == nil)
- return oname;
- return p+1;
+ if(vacfile)
+ remove(vacfile);
}
-static void
-vac(VtConn *z, char *argv[])
+static int
+strpcmp(const void *p0, const void *p1)
{
- DirSink *dsink, *ds;
- MetaSink *ms;
- VtRoot root;
- uchar score[VtScoreSize], buf[VtRootSize];
- char cwd[2048];
- int cd;
- 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 = vacfsopen(z, dfile, VtOREAD, 1000);
- if(fs == nil)
- fprint(2, "could not open diff: %s: %r\n", dfile);
- }
-
-
- 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");
- if(oname)
- dir->name = lastelem(oname);
- else
- dir->name = "stdin";
-
- 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 = vacfileopen(fs, cp2);
- vacfile(dsink, argv[0], cp2, vff);
- if(vff)
- vacfiledecref(vff);
- if(cd && chdir(cwd) < 0)
- sysfatal("can't cd back to %s: %r\n", cwd);
- }
-
- if(isi) {
- vff = nil;
- if(fs)
- vff = vacfileopen(fs, isi);
- vacstdin(dsink, isi, vff);
- if(vff)
- vacfiledecref(vff);
- }
-
- dirsinkclose(dsink);
-
- /* build meta information for the root */
- ms = metasinkalloc(z, bsize, bsize);
- /* fake into a directory */
- dir->mode = DMDIR|0555;
- dir->qid.type |= QTDIR;
- plan9tovacdir(&vd, dir, 0, fileid++);
- if(strcmp(vd.elem, "/") == 0){
- vtfree(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));
- 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)
- vacfsgetscore(fs, root.prev);
-
- metasinkfree(ms);
- dirsinkfree(ds);
- dirsinkfree(dsink);
- if(fs != nil)
- vacfsclose(fs);
-
- vtrootpack(&root, buf);
- if(vacwrite(z, score, VtRootType, buf, VtRootSize) < 0)
- sysfatal("vacwrite: %r");
-
- fprint(fd, "vac:%V\n", score);
-
- /* avoid remove at cleanup */
- oname = nil;
+ return strcmp(*(char**)p0, *(char**)p1);
}
static int
@@ -448,897 +274,370 @@ isexcluded(char *name)
return 0;
}
-static void
-vacfile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
+void
+plan9tovacdir(VacDir *vd, Dir *dir)
{
- int fd;
- Dir *dir;
- VacDir vd;
- ulong entry;
+ memset(vd, 0, sizeof *vd);
- if(isexcluded(lname)) {
- warn("excluding: %s", lname);
- return;
- }
+ vd->elem = dir->name;
+ vd->uid = dir->uid;
+ vd->gid = dir->gid;
+ vd->mid = dir->muid;
+ if(vd->mid == nil)
+ vd->mid = "";
+ vd->mtime = dir->mtime;
+ vd->mcount = 0;
+ vd->ctime = dir->mtime; /* ctime: not available on plan 9 */
+ vd->atime = dir->atime;
+ vd->size = dir->length;
- if(merge && vacmerge(dsink, lname, sname) >= 0)
- return;
+ 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;
+#ifdef PLAN9PORT
+ if(dir->mode & DMDEVICE)
+ vd->mode |= ModeDevice;
+ if(dir->mode & DMNAMEDPIPE)
+ vd->mode |= ModeNamedPipe;
+ if(dir->mode & DMSYMLINK)
+ vd->mode |= ModeLink;
+#endif
- if((dir = dirstat(sname)) == nil){
- warn("could not stat file %s: %r", lname);
- return;
- }
- if(dir->mode&(DMSYMLINK|DMDEVICE|DMNAMEDPIPE)){
- vacspecial(dsink, dir, lname, sname, vf);
- free(dir);
- return;
- }else if(dir->mode&DMSOCKET){
- free(dir);
- return;
- }
- free(dir);
-
- fd = open(sname, OREAD);
- if(fd < 0) {
- warn("could not open file: %s: %r", lname);
- return;
- }
+ vd->plan9 = 1;
+ vd->p9path = dir->qid.path;
+ vd->p9version = dir->qid.vers;
+}
- if(verbose)
- fprint(2, "%s\n", lname);
+#ifdef PLAN9PORT
+enum {
+ Special =
+ DMSOCKET |
+ DMSYMLINK |
+ DMNAMEDPIPE |
+ DMDEVICE
+};
+#endif
+
+/*
+ * Does block b of f have the same SHA1 hash as the n bytes at buf?
+ */
+static int
+sha1matches(VacFile *f, ulong b, uchar *buf, int n)
+{
+ uchar fscore[VtScoreSize];
+ uchar bufscore[VtScoreSize];
+
+ if(vacfileblockscore(f, b, fscore) < 0)
+ return 0;
+ n = vtzerotruncate(VtDataType, buf, n);
+ sha1(buf, n, bufscore, nil);
+ if(memcmp(bufscore, fscore, VtScoreSize) == 0)
+ return 1;
+ return 0;
+}
- dir = dirfstat(fd);
- if(dir == nil) {
- warn("can't stat %s: %r", lname);
- close(fd);
+/*
+ * Archive the file named name, which has stat info d,
+ * into the vac directory fp (p = parent).
+ *
+ * If we're doing a vac -d against another archive, the
+ * equivalent directory to fp in that archive is diffp.
+ */
+void
+vac(VacFile *fp, VacFile *diffp, char *name, Dir *d)
+{
+ char *elem, *s;
+ static char buf[65536];
+ int fd, i, n, bsize;
+ vlong off;
+ Dir *dk; // kids
+ VacDir vd, vddiff;
+ VacFile *f, *fdiff;
+ VtEntry e;
+
+ if(isexcluded(name)){
+ warn("excluding %s%s", name, (d->mode&DMDIR) ? "/" : "");
return;
}
- dir->name = lastelem(sname);
-
- entry = dsink->nentry;
- if(dir->mode & DMDIR)
- vacdir(dsink, fd, lname, sname, vf);
+ if(d->mode&DMDIR)
+ stats.ndir++;
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;
+ stats.nfile++;
+ if(merge && vacmerge(fp, name) >= 0)
+ return;
+
if(verbose)
- fprint(2, "%s\n", "<stdio>");
+ fprint(2, "%s%s\n", name, (d->mode&DMDIR) ? "/" : "");
- dir = dirfstat(0);
- if(dir == nil) {
- warn("can't stat <stdio>: %r");
+#ifdef PLAN9PORT
+ if(d->mode&Special)
+ fd = -1;
+ else
+#endif
+ if((fd = open(name, OREAD)) < 0){
+ warn("open %s: %r", name);
return;
}
- dir->name = "stdin";
- 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 int
-sha1check(u8int *score, uchar *buf, int n)
-{
- uchar score2[VtScoreSize];
-
- sha1(buf, n, score2, nil);
- if(memcmp(score, score2, VtScoreSize) == 0)
- return 0;
- return -1;
-}
-
-static ulong
-vacdataskip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname)
-{
- int n;
- ulong i;
- uchar score[VtScoreSize];
+ elem = strrchr(name, '/');
+ if(elem)
+ elem++;
+ else
+ elem = name;
- /* skip blocks for append only files */
- if(seek(fd, (blocks-1)*bsize, 0) != (blocks-1)*bsize) {
- warn("error seeking: %s", lname);
- goto Err;
- }
- n = readn(fd, buf, bsize);
- if(n < bsize) {
- warn("error checking append only file: %s", lname);
- goto Err;
- }
- if(vacfileblockscore(vf, blocks-1, score)<0 || sha1check(score, buf, n)<0) {
- warn("last block of append file did not match: %s", lname);
- goto Err;
+ plan9tovacdir(&vd, d);
+ if((f = vacfilecreate(fp, elem, vd.mode)) == nil){
+ warn("vacfilecreate %s: %r", name);
+ return;
}
+ if(diffp)
+ fdiff = vacfilewalk(diffp, elem);
+ else
+ fdiff = nil;
- for(i=0; i<blocks; i++) {
- if(vacfileblockscore(vf, i, score) < 0) {
- warn("could not get score: %s: %lud", lname, i);
- seek(fd, i*bsize, 0);
- return i;
+ if(vacfilesetdir(f, &vd) < 0)
+ warn("vacfilesetdir %s: %r", name);
+
+#ifdef PLAN9PORT
+ if(d->mode&(DMSOCKET|DMNAMEDPIPE)){
+ /* don't write anything */
+ }
+ else if(d->mode&DMSYMLINK){
+ n = readlink(name, buf, sizeof buf);
+ if(n > 0 && vacfilewrite(f, buf, n, 0) < 0){
+ warn("venti write %s: %r", name);
+ goto Out;
}
- stats.skip++;
- sinkwritescore(sink, score, bsize);
- }
-
- return i;
-Err:
- seek(fd, 0, 0);
- return 0;
+ stats.data += n;
+ }else if(d->mode&DMDEVICE){
+ snprint(buf, sizeof buf, "%c %d %d",
+ (char)((d->qid.path >> 16) & 0xFF),
+ (int)(d->qid.path & 0xFF),
+ (int)((d->qid.path >> 8) & 0xFF));
+ if(vacfilewrite(f, buf, strlen(buf), 0) < 0){
+ warn("venti write %s: %r", name);
+ goto Out;
+ }
+ stats.data += strlen(buf);
+ }else
+#endif
+ if(d->mode&DMDIR){
+ while((n = dirread(fd, &dk)) > 0){
+ for(i=0; i<n; i++){
+ s = vtmalloc(strlen(name)+1+strlen(dk[i].name)+1);
+ strcpy(s, name);
+ strcat(s, "/");
+ strcat(s, dk[i].name);
+ vac(f, fdiff, s, &dk[i]);
+ free(s);
+ }
+ free(dk);
+ }
+ }else{
+ off = 0;
+ bsize = fs->bsize;
+ if(fdiff){
+ /*
+ * Copy fdiff's contents into f by moving the score.
+ * We'll diff and update below.
+ */
+ if(vacfilegetentries(fdiff, &e, nil) >= 0)
+ if(vacfilesetentries(f, &e, nil) >= 0){
+ bsize = e.dsize;
+
+ /*
+ * Or if -q is set, and the metadata looks the same,
+ * don't even bother reading the file.
+ */
+ if(qdiff && vacfilegetdir(fdiff, &vddiff) >= 0){
+ if(vddiff.mtime == vd.mtime)
+ if(vddiff.size == vd.size)
+ if(!vddiff.plan9 || (/* vddiff.p9path == vd.p9path && */ vddiff.p9version == vd.p9version)){
+ stats.skipfiles++;
+ stats.nfile--;
+ vdcleanup(&vddiff);
+ goto Out;
+ }
+
+ /*
+ * Skip over presumably-unchanged prefix
+ * of an append-only file.
+ */
+ if(vd.mode&ModeAppend)
+ if(vddiff.size < vd.size)
+ if(vddiff.plan9 && vd.plan9)
+ if(vddiff.p9path == vd.p9path){
+ off = vd.size/bsize*bsize;
+ if(seek(fd, off, 0) >= 0)
+ stats.skipdata += off;
+ else{
+ seek(fd, 0, 0); // paranoia
+ off = 0;
+ }
+ }
+
+ vdcleanup(&vddiff);
+ // XXX different verbose chatty prints for kaminsky?
+ }
+ }
+ }
+ if(qdiff && verbose)
+ fprint(2, "+%s\n", name);
+ while((n = readn(fd, buf, bsize)) > 0){
+ if(fdiff && sha1matches(f, off/bsize, (uchar*)buf, n)){
+ off += n;
+ stats.skipdata += n;
+ continue;
+ }
+ if(vacfilewrite(f, buf, n, off) < 0){
+ warn("venti write %s: %r", name);
+ goto Out;
+ }
+ stats.data += n;
+ off += n;
+ }
+ /*
+ * Since we started with fdiff's contents,
+ * set the size in case fdiff was bigger.
+ */
+ if(fdiff && vacfilesetsize(f, off) < 0)
+ warn("vtfilesetsize %s: %r", name);
+ }
+
+Out:
+ vacfileflush(f, 1);
+ vacfiledecref(f);
+ if(fdiff)
+ vacfiledecref(fdiff);
+ close(fd);
}
-static void
-vacdata(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir)
+void
+vacstdin(VacFile *fp, char *name)
{
- uchar *buf;
- Sink *sink;
+ vlong off;
+ VacFile *f;
+ static char buf[8192];
int n;
- uchar score[VtScoreSize];
- ulong block, same;
- VacDir vd;
- ulong vfblocks;
-
- vfblocks = 0;
- if(vf != nil && qdiff) {
- vacfilegetdir(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) >= 0) {
- stats.sfile++;
- vdcleanup(&vd);
- return;
- }
-
- if(verbose)
- fprint(2, "+ %s\n", lname);
-
- /* 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 = vtmalloc(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);
-
- for(;;) {
- n = readn(fd, buf, bsize);
- if(0 && n < 0)
- warn("file truncated due to read error: %s: %r", lname);
- if(n <= 0)
- break;
- if(vf != nil && vacfileblockscore(vf, block, score)>=0 && sha1check(score, buf, n)>=0) {
- stats.sdata++;
- sinkwritescore(sink, score, n);
- } else
- sinkwrite(sink, buf, n);
- block++;
+ if((f = vacfilecreate(fp, name, 0666)) == nil){
+ warn("vacfilecreate %s: %r", name);
+ return;
}
- 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 = vtmalloc(strlen(lname) + strlen(name) + 2);
- sn = vtmalloc(strlen(sname) + strlen(name) + 2);
- strcpy(ln, lname);
- strcat(ln, "/");
- strcat(ln, name);
- strcpy(sn, sname);
- strcat(sn, "/");
- strcat(sn, name);
- if(vf != nil)
- vvf = vacfilewalk(vf, name);
- else
- vvf = nil;
- vacfile(ds, ln, sn, vvf);
- if(vvf != nil)
- vacfiledecref(vvf);
- vtfree(ln);
- vtfree(sn);
+
+ off = 0;
+ while((n = read(0, buf, sizeof buf)) > 0){
+ if(vacfilewrite(f, buf, n, off) < 0){
+ warn("venti write %s: %r", name);
+ vacfiledecref(f);
+ return;
}
- free(dirs);
+ off += n;
}
- dirsinkclose(ds);
- dirsinkwritesink(dsink, ds->sink);
- dirsinkwritesink(dsink, ds->msink->sink);
- dirsinkfree(ds);
+ vacfileflush(f, 1);
+ vacfiledecref(f);
}
-static int
-vacmergefile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max)
+/*
+ * fp is the directory we're writing.
+ * mp is the directory whose contents we're merging in.
+ * d is the directory entry of the file from mp that we want to add to fp.
+ * vacfile is the name of the .vac file, for error messages.
+ * offset is the qid that qid==0 in mp should correspond to.
+ * max is the maximum qid we expect to see (not really needed).
+ */
+int
+vacmergefile(VacFile *fp, VacFile *mp, VacDir *d, char *vacfile,
+ vlong offset, vlong max)
{
- uchar buf[VtEntrySize];
- VtEntry dd, md;
- int e;
-
- if(vacfileread(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) {
- warn("could not read venti dir entry: %s\n", dir->elem);
+ VtEntry ed, em;
+ VacFile *mf;
+ VacFile *f;
+
+ mf = vacfilewalk(mp, d->elem);
+ if(mf == nil){
+ warn("could not walk %s in %s", d->elem, vacfile);
return -1;
}
- vtentryunpack(&dd, buf, 0);
-
- if(dir->mode & ModeDir) {
- e = dir->mentry;
- if(e == 0)
- e = dir->entry + 1;
-
- if(vacfileread(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;
+ if(vacfilegetentries(mf, &ed, &em) < 0){
+ warn("could not get entries for %s in %s", d->elem, vacfile);
+ vacfiledecref(mf);
+ return -1;
}
-
- dirsinkwrite(dsink, &dd);
- if(dir->mode & ModeDir)
- dirsinkwrite(dsink, &md);
- metasinkwritedir(dsink->msink, dir);
- return 0;
-}
-
-static int
-vacmerge(DirSink *dsink, char *lname, char *sname)
-{
- char *p;
- VacFs *fs;
- VacFile *vf;
- VacDirEnum *d;
- VacDir dir;
- uvlong max;
-
- if((p=strrchr(sname, '.')) == nil || strcmp(p, ".vac") != 0)
+ if((f = vacfilecreate(fp, d->elem, d->mode)) == nil){
+ warn("vacfilecreate %s: %r", d->elem);
+ vacfiledecref(mf);
return -1;
-
- d = nil;
- fs = vacfsopen(dsink->sink->z, sname, VtOREAD, 100);
- if(fs == nil)
+ }
+ if(d->qidspace){
+ d->qidoffset += offset;
+ d->qidmax += offset;
+ }else{
+ d->qidspace = 1;
+ d->qidoffset = offset;
+ d->qidmax = max;
+ }
+ if(vacfilesetdir(f, d) < 0 || vacfilesetentries(f, &ed, &em) < 0){
+ warn("vacmergefile %s: %r", d->elem);
+ vacfiledecref(mf);
+ vacfiledecref(f);
return -1;
-
- vf = vacfileopen(fs, "/");
- if(vf == nil)
- goto Done;
- max = vacfilegetid(vf);
- d = vdeopen(vf);
- if(d == nil)
- goto Done;
-
- if(verbose)
- fprint(2, "merging: %s\n", lname);
-
- if(maxbsize < fs->bsize)
- maxbsize = fs->bsize;
-
- for(;;) {
- if(vderead(d, &dir) < 1)
- break;
- vacmergefile(dsink, vf, &dir, fileid, &max);
- vdcleanup(&dir);
}
- fileid += max;
-
-Done:
- if(d != nil)
- vdeclose(d);
- if(vf != nil)
- vacfiledecref(vf);
- vacfsclose(fs);
+
+ vacfiledecref(mf);
+ vacfiledecref(f);
return 0;
}
-static int
-vacspecial(DirSink *dsink, Dir* dir, char *lname, char *sname, VacFile *vf)
+int
+vacmerge(VacFile *fp, char *name)
{
- char *btmp, *buf;
- int buflen, dtype, major, minor, n;
- ulong entry;
- Sink *sink;
+ VacFs *mfs;
VacDir vd;
+ VacDirEnum *de;
+ VacFile *mp;
+ uvlong maxqid, offset;
- n = 0;
- buflen = 128;
- buf = malloc(buflen);
- if(buf == nil)
+ if(strlen(name) < 4 || strcmp(name+strlen(name)-4, ".vac") != 0)
+ return -1;
+ if((mfs = vacfsopen(z, name, VtOREAD, 100)) == nil)
return -1;
-
if(verbose)
- fprint(2, "%s\n", lname);
-
- dir->name = lastelem(sname);
-
- if(dir->mode & DMSYMLINK){
- while((n = readlink(sname, buf, buflen)) == buflen){
- buflen *= 2;
- btmp = vtrealloc(buf, buflen);
- if(btmp == nil){
- free(buf);
- return -1;
+ fprint(2, "merging %s\n", name);
+
+ de = vdeopen(fs->root);
+ if(de){
+ mp = vacfsgetroot(mfs);
+ offset = 0;
+ if(vacfsgetmaxqid(mfs, &maxqid) >= 0){
+ _vacfsnextqid(fs, &offset);
+ vacfsjumpqid(fs, maxqid+1);
+ }
+ while(vderead(de, &vd) > 0){
+ if(vd.qid > maxqid){
+ warn("vacmerge %s: maxqid=%lld but %s has %lld",
+ name, maxqid, vd.elem, vd.qid);
+ vacfsjumpqid(fs, vd.qid - maxqid);
+ maxqid = vd.qid;
}
- buf = btmp;
+ vacmergefile(fp, mp, &vd, name,
+ offset, maxqid);
+ vdcleanup(&vd);
}
- dir->mode &= ~DMDIR;
- dir->mode |= DMSYMLINK;
- }else if(dir->mode & DMDEVICE){
- dtype = (dir->qid.path >> 16) & 0xFF;
- minor = dir->qid.path & 0xff;
- major = (dir->qid.path >> 8) & 0xFF;
- n = snprint(buf, buflen, "%c %d %d", dtype, major, minor);
- }
-
- entry = dsink->nentry;
-
- sink = sinkalloc(dsink->sink->z, bsize, bsize);
- sinkwrite(sink, (uchar*)buf, n);
- sinkclose(sink);
- dirsinkwritesink(dsink, sink);
- sinkfree(sink);
- free(buf);
-
- dir->name = lastelem(sname);
- dir->length = n;
- plan9tovacdir(&vd, dir, entry, fileid++);
- metasinkwritedir(dsink->msink, &vd);
- vdcleanup(&vd);
-
- return 0;
-}
-
-
-Sink *
-sinkalloc(VtConn *z, int psize, int dsize)
-{
- Sink *k;
- int i;
-
- if(psize < 512 || psize > VtMaxLumpSize)
- sysfatal("sinkalloc: bad psize");
- if(dsize < 512 || dsize > VtMaxLumpSize)
- sysfatal("sinkalloc: bad psize");
-
- psize = VtScoreSize*(psize/VtScoreSize);
-
- k = vtmallocz(sizeof(Sink));
- k->z = z;
- k->dir.flags = VtEntryActive;
- k->dir.psize = psize;
- k->dir.dsize = dsize;
- k->buf = vtmallocz(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)
- sysfatal("file too big");
- p = k->buf+i*d->psize;
- stats.meta++;
- if(vacwrite(k->z, k->pbuf[i+1], VtDataType+1+i, p, d->psize) < 0)
- sysfatal("vacwrite failed: %r");
- k->pbuf[i] = p;
+ vdeclose(de);
+ vacfiledecref(mp);
}
-
- /* 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 == 0)
- return;
-
- if(n > k->dir.dsize)
- sysfatal("sinkwrite: size too big");
-
- if((k->dir.type&~VtTypeDepthMask) == VtDirType){
- type = VtDirType;
- stats.meta++;
- } else {
- type = VtDataType;
- stats.data++;
- }
- if(vacwrite(k->z, score, type, p, n) < 0)
- sysfatal("vacwrite: %r");
-
- 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, base;
- 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;
-
- base = kd->type&~VtTypeDepthMask;
- kd->type = base + 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], base+1+i, p, k->pbuf[i]-p) < 0)
- sysfatal("vacwrite: %r");
- k->pbuf[i+1] += VtScoreSize;
- }
- memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
-}
-
-void
-sinkfree(Sink *k)
-{
- vtfree(k->buf);
- vtfree(k);
-}
-
-DirSink *
-dirsinkalloc(VtConn *z, int psize, int dsize)
-{
- DirSink *k;
- int ds;
-
- ds = VtEntrySize*(dsize/VtEntrySize);
-
- k = vtmallocz(sizeof(DirSink));
- k->sink = sinkalloc(z, psize, ds);
- k->sink->dir.type = VtDirType;
- k->msink = metasinkalloc(z, psize, dsize);
- k->buf = vtmalloc(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(vacfilegetentries(vf, &dir, nil) < 0)
- return -1;
- dirsinkwrite(k, &dir);
+ vacfsclose(mfs);
return 0;
}
-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);
- vtfree(k->buf);
- vtfree(k);
-}
-
-MetaSink*
-metasinkalloc(VtConn *z, int psize, int dsize)
-{
- MetaSink *k;
-
- k = vtmallocz(sizeof(MetaSink));
- k->sink = sinkalloc(z, psize, dsize);
- k->buf = vtmalloc(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(const void *p0, const void *p1)
-{
- uchar *q0, *q1;
- int n0, n1, r;
-
- /* name is first element of entry */
- q0 = (uchar*)p0;
- q0 = blockbase + (q0[0]<<8) + q0[1];
- n0 = (q0[6]<<8) + q0[7];
- q0 += 8;
-
- q1 = (uchar*)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)
- sysfatal("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)
- sysfatal("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;
- if(dir->mode & DMDEVICE)
- vd->mode |= ModeDevice;
- if(dir->mode & DMNAMEDPIPE)
- vd->mode |= ModeNamedPipe;
- if(dir->mode & DMSYMLINK)
- vd->mode |= ModeLink;
-
- 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);
- vtfree(k->buf);
- vtfree(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
@@ -1364,3 +663,16 @@ unittoull(char *s)
return TWID64;
return n;
}
+
+static void
+warn(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ fprint(2, "vac: ");
+ vfprint(2, fmt, arg);
+ fprint(2, "\n");
+ va_end(arg);
+}
+
diff --git a/src/cmd/vac/vac.h b/src/cmd/vac/vac.h
index 5ce69734..610028f4 100644
--- a/src/cmd/vac/vac.h
+++ b/src/cmd/vac/vac.h
@@ -3,6 +3,11 @@ typedef struct VacDir VacDir;
typedef struct VacFile VacFile;
typedef struct VacDirEnum VacDirEnum;
+#ifndef PLAN9PORT
+#pragma incomplete VacFile
+#pragma incomplete VacDirEnum
+#endif
+
/*
* Mode bits
*/
@@ -99,6 +104,8 @@ void vacfsclose(VacFs *fs);
int vacfssync(VacFs *fs);
int vacfssnapshot(VacFs *fs, char *src, char *dst);
int vacfsgetscore(VacFs *fs, u8int *score);
+int vacfsgetmaxqid(VacFs*, uvlong*);
+void vacfsjumpqid(VacFs*, uvlong);
VacFile *vacfsgetroot(VacFs *fs);
VacFile *vacfileopen(VacFs *fs, char *path);
@@ -127,7 +134,7 @@ int vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me);
void vdcleanup(VacDir *dir);
void vdcopy(VacDir *dst, VacDir *src);
-
+int vacfilesetqidspace(VacFile*, u64int, u64int);
VacDirEnum *vdeopen(VacFile*);
int vderead(VacDirEnum*, VacDir *);
diff --git a/src/cmd/vac/vtdump.c b/src/cmd/vac/vtdump.c
deleted file mode 100644
index 2daaf1bb..00000000
--- a/src/cmd/vac/vtdump.c
+++ /dev/null
@@ -1,372 +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;
-VtRoot root;
-int ver;
-int cmp;
-int all;
-int find;
-uchar fscore[VtScoreSize];
-VtConn *z;
-
-int vtgetuint16(uchar *p);
-ulong vtgetuint32(uchar *p);
-uvlong vtgetuint48(uchar *p);
-void usage(void);
-void readroot(VtRoot*, uchar *score, char *file);
-int dumpdir(Source*, int indent);
-int timevtread(VtConn*, uchar*, int, void*, int);
-
-int mainstacksize = 512*1024;
-
-void
-threadmain(int argc, char *argv[])
-{
- char *host = nil, *pref;
- uchar score[VtScoreSize];
- Source source;
- char *p;
- int n;
- uchar buf[VtMaxLumpSize];
-
- ARGBEGIN{
- case 'h':
- host = ARGF();
- break;
- case 'c':
- cmp++;
- break;
- case 'f':
- find++;
- p = ARGF();
- if(p == nil || vtparsescore(p, &pref, fscore) < 0 || !pref || strcmp(pref, "vac") != 0)
- usage();
- break;
- case 'a':
- all = 1;
- break;
- }ARGEND
-
- bout = vtmallocz(sizeof(Biobuf));
- Binit(bout, 1, OWRITE);
-
- if(argc > 1)
- usage();
-
- fmtinstall('V', vtscorefmt);
- fmtinstall('H', encodefmt);
-
- z = vtdial(host);
- if(z == nil)
- sysfatal("could not connect to server: %r");
-
- if(vtconnect(z) < 0)
- sysfatal("vtconnect: %r");
-
- readroot(&root, score, argv[0]);
- bsize = root.blocksize;
- if(!find) {
- Bprint(bout, "score: %V\n", score);
- Bprint(bout, "name: %s\n", root.name);
- Bprint(bout, "type: %s\n", root.type);
- Bprint(bout, "bsize: %d\n", bsize);
- Bprint(bout, "prev: %V\n", root.prev);
- }
-
-fprint(2, "read...\n");
- n = timevtread(z, root.score, VtDirType, buf, bsize);
- if(n < 0)
- sysfatal("could not read root dir");
-
-fprint(2, "...\n");
- /* fake up top level source */
- memset(&source, 0, sizeof(source));
- memmove(source.score, root.score, VtScoreSize);
- source.psize = bsize;
- source.dsize = bsize;
- source.dir = 1;
- source.active = 1;
- source.depth = 0;
- source.size = n;
-
- dumpdir(&source, 0);
-
- Bterm(bout);
-
- vthangup(z);
- threadexitsall(0);
-}
-
-void
-sourceprint(Source *s, int indent, int entry)
-{
- int i;
- uvlong size;
- int ne;
-
- for(i=0; i<indent; i++)
- Bprint(bout, " ");
- Bprint(bout, "%4d", entry);
- if(s->active) {
- /* dir size in directory entries */
- if(s->dir) {
- ne = s->dsize/VtEntrySize;
- size = ne*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
- } else
- size = s->size;
- if(cmp) {
- Bprint(bout, ": gen: %lud size: %llud",
- s->gen, size);
- if(!s->dir)
- Bprint(bout, ": %V", s->score);
- } else {
- Bprint(bout, ": gen: %lud psize: %d dsize: %d",
- s->gen, s->psize, s->dsize);
- Bprint(bout, " depth: %d size: %llud: %V",
- s->depth, size, s->score);
- }
-
- if(s->reserved)
- Bprint(bout, ": reserved not emtpy");
- }
- Bprint(bout, "\n");
-}
-
-int
-parse(Source *s, uchar *p)
-{
- VtEntry dir;
-
- memset(s, 0, sizeof(*s));
- if(vtentryunpack(&dir, p, 0) < 0)
- return -1;
-
- if(!(dir.flags & VtEntryActive))
- return 0;
-
- s->active = 1;
- s->gen = dir.gen;
- s->psize = dir.psize;
- s->dsize = dir.dsize;
- s->size = dir.size;
- memmove(s->score, dir.score, VtScoreSize);
- if((dir.type&~VtTypeDepthMask) == VtDirType)
- s->dir = 1;
- s->depth = dir.type&VtTypeDepthMask;
- return 0;
-}
-
-int
-sourceread(Source *s, ulong block, uchar *p, int n)
-{
- uchar *buf;
- uchar score[VtScoreSize];
- int i, nn, np, type;
- int elem[VtPointerDepth];
-
- buf = vtmalloc(VtMaxLumpSize);
-
- memmove(score, s->score, VtScoreSize);
-
- np = s->psize/VtScoreSize;
- for(i=0; i<s->depth; i++) {
- elem[i] = block % np;
- block /= np;
- }
- assert(block == 0);
-
- for(i=s->depth-1; i>=0; i--) {
- nn = timevtread(z, score, (s->dir ? VtDirType : VtDataType)+1+i, buf, s->psize);
- if(nn < 0){
-fprint(2, "vtread %V %d: %r\n", score, (s->dir ? VtDirType : VtDataType)+1+i);
- free(buf);
- return -1;
- }
-
- if((elem[i]+1)*VtScoreSize > nn){
- free(buf);
- return 0;
- }
- memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
- }
-
- if(s->dir)
- type = VtDirType;
- else
- type = VtDataType;
-
- nn = timevtread(z, score, type, p, n);
- if(nn < 0){
-fprint(2, "vtread %V %d: %r\n", score, type);
-abort();
- free(buf);
- return -1;
- }
-
- free(buf);
- return nn;
-}
-
-void
-dumpfilecontents(Source *s)
-{
- int nb, lb, i, n;
- uchar buf[VtMaxLumpSize];
-
- nb = (s->size + s->dsize - 1)/s->dsize;
- lb = s->size%s->dsize;
- for(i=0; i<nb; i++) {
- memset(buf, 0, s->dsize);
- n = sourceread(s, i, buf, s->dsize);
- if(n < 0) {
- fprint(2, "could not read block: %d: %r\n", i);
- continue;
- }
- if(i < nb-1)
- Bwrite(bout, buf, s->dsize);
- else
- Bwrite(bout, buf, lb);
- }
-}
-
-void
-dumpfile(Source *s, int indent)
-{
- int nb, i, j, n;
- uchar *buf;
- uchar score[VtScoreSize];
-
- buf = vtmalloc(VtMaxLumpSize);
- nb = (s->size + s->dsize - 1)/s->dsize;
- for(i=0; i<nb; i++) {
- memset(buf, 0, s->dsize);
- n = sourceread(s, i, buf, s->dsize);
- if(n < 0) {
- fprint(2, "could not read block: %d: %r\n", i);
- continue;
- }
- for(j=0; j<indent; j++)
- Bprint(bout, " ");
- sha1(buf, n, score, nil);
- Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
- }
- vtfree(buf);
-}
-
-int
-dumpdir(Source *s, int indent)
-{
- int pb, ne, nb, i, j, n, entry;
- Source ss;
- uchar *buf;
-
- buf = vtmalloc(VtMaxLumpSize);
- pb = s->dsize/VtEntrySize;
- ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
- nb = (s->size + s->dsize - 1)/s->dsize;
- for(i=0; i<nb; i++) {
- memset(buf, 0, s->dsize);
- n = sourceread(s, i, buf, s->dsize);
- if(n < 0) {
- fprint(2, "could not read block: %d: %r\n", i);
- continue;
- }
- for(j=0; j<pb; j++) {
- entry = i*pb + j;
- if(entry >= ne)
- break;
- parse(&ss, buf + j * VtEntrySize);
-
- if(!find)
- sourceprint(&ss, indent, entry);
- else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
- dumpfilecontents(&ss);
- free(buf);
- return -1;
- }
-
- if(ss.dir) {
- if(dumpdir(&ss, indent+1) < 0){
- free(buf);
- return -1;
- }
- } else if(all)
- dumpfile(&ss, indent+1);
- }
- }
- free(buf);
- return 0;
-}
-
-void
-usage(void)
-{
- fprint(2, "%s: [file]\n", argv0);
- threadexits("usage");
-}
-
-void
-readroot(VtRoot *root, uchar *score, char *file)
-{
- int fd;
- char *pref;
- char buf[VtRootSize];
- int n, nn;
-
- if(file == 0)
- fd = 0;
- else {
- fd = open(file, OREAD);
- if(fd < 0)
- sysfatal("could not open file: %s: %r\n", file);
- }
- n = readn(fd, buf, sizeof(buf)-1);
- if(n < 0)
- sysfatal("read failed: %r\n");
- if(n==0 || buf[n-1] != '\n')
- sysfatal("not a root file");
- buf[n-1] = 0;
- close(fd);
-
- if(vtparsescore(buf, &pref, score) < 0){
- sysfatal("not a root file");
- }
- nn = timevtread(z, score, VtRootType, buf, VtRootSize);
- if(nn < 0)
- sysfatal("cannot read root %V", score);
- if(vtrootunpack(root, buf) < 0)
- sysfatal("cannot parse root: %r");
-}
-
-int
-timevtread(VtConn *z, uchar *score, int type, void *buf, int nbuf)
-{
-/*
- ulong t0, t1;
- int n;
-
- t0 = nsec();
- n = vtread(z, score, type, buf, nbuf);
- t1 = nsec();
- fprint(2, "read %V: %.6f seconds\n", score, (t1-t0)/1.e9);
- return n;
-*/
- return vtread(z, score, type, buf, nbuf);
-}