/* * 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; int64_t off; Dir *dk; // kids VacDir vd, vddiff; VacFile *f, *fdiff; VtEntry e; if(!includefile(name)){ warn("excluding %s%s", name, (d->mode&DMDIR) ? "/" : ""); return; } if(d->mode&DMDIR) stats.ndir++; else stats.nfile++; if(merge && vacmerge(fp, name) >= 0) return; if(verbose) fprint(2, "%s%s\n", name, (d->mode&DMDIR) ? "/" : ""); if((fd = open(name, OREAD)) < 0){ warn("open %s: %r", name); return; } elem = strrchr(name, '/'); if(elem) elem++; else elem = name; 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; if(vacfilesetdir(f, &vd) < 0) warn("vacfilesetdir %s: %r", name); 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, (uint8_t*)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); }
/* * 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; int fd, i, n, bsize; vlong off; Dir *dk; // kids VacDir vd, vddiff; VacFile *f, *fdiff; VtEntry e; if(!includefile(name)){ warn("excluding %s%s", name, (d->mode&DMDIR) ? "/" : ""); return; } if(d->mode&DMDIR) stats.ndir++; else stats.nfile++; if(merge && vacmerge(fp, name) >= 0) return; if(verbose) fprint(2, "%s%s\n", name, (d->mode&DMDIR) ? "/" : ""); #ifdef PLAN9PORT if(d->mode&Special) fd = -1; else #endif if((fd = open(name, OREAD)) < 0){ warn("open %s: %r", name); return; } elem = strrchr(name, '/'); if(elem) elem++; else elem = name; 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; if(vacfilesetdir(f, &vd) < 0) warn("vacfilesetdir %s: %r", name); bsize = fs->bsize; if(buf == nil) buf = vtmallocz(bsize); #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.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