ARGBEGIN{
case 'V':
chattyventi++;
break;
case 'a':
archivefile = EARGF(usage());
break;
case 'b':
u = unittoull(EARGF(usage()));
if(u < 512)
u = 512;
if(u > VtMaxLumpSize)
u = VtMaxLumpSize;
blocksize = u;
break;
case 'd':
diffvac = EARGF(usage());
break;
case 'e':
excludepattern(EARGF(usage()));
break;
case 'f':
vacfile = EARGF(usage());
break;
case 'h':
host = EARGF(usage());
break;
case 'i':
stdinname = EARGF(usage());
break;
case 'm':
merge++;
break;
case 'q':
qdiff++;
break;
case 's':
printstats++;
break;
case 'v':
verbose++;
break;
case 'x':
loadexcludefile(EARGF(usage()));
break;
default:
usage();
}ARGEND
if(argc == 0 && !stdinname)
usage();
if(archivefile && (vacfile || diffvac)){
fprint(2, "cannot use -a with -f, -d\n");
usage();
}
z = vtdial(host);
if(z == nil)
sysfatal("could not connect to server: %r");
if(vtconnect(z) < 0)
sysfatal("vtconnect: %r");
// Setup:
// fs is the output vac file system
// f is directory in output vac to write new files
// fdiff is corresponding directory in existing vac
if(archivefile){
VacFile *fp;
char yyyy[5];
char mmdd[10];
char oldpath[40];
Tm tm;
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;
}
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);
}
close(fd);
continue;
}
if((d = dirstat(argv[i])) == nil){
warn("stat %s: %r", argv[i]);
continue;
}
vac(f, fdiff, argv[i], d);
free(d);
}
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");
/*
* 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;
/*
* 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)
{
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;
}
if(vacfilegetentries(mf, &ed, &em) < 0){
warn("could not get entries for %s in %s", d->elem, vacfile);
vacfiledecref(mf);
return -1;
}