static int changed_non_file(struct sbuf *p1b, FILE *ucfp, char cmd, struct conf *cconf) { // As new_non_file. if(sbufl_to_manifest(p1b, ucfp, NULL)) return -1; else cntr_add_changed(cconf->cntr, cmd); sbuf_free_content(p1b); return 0; }
static int changed_non_file(struct sbuf *p1b, struct fzp *ucfp, enum cmd cmd, struct conf **cconfs) { // As new_non_file. if(sbufl_to_manifest(p1b, ucfp)) return -1; else cntr_add_changed(get_cntr(cconfs[OPT_CNTR]), cmd); sbuf_free_content(p1b); return 0; }
static int deal_with_receive_end_file(struct asfd *asfd, struct sdirs *sdirs, struct sbuf *rb, FILE *p2fp, struct conf *cconf, char **last_requested) { static char *cp=NULL; static struct iobuf *rbuf; rbuf=asfd->rbuf; // Finished the file. // Write it to the phase2 file, and free the buffers. if(close_fp(&(rb->burp1->fp))) { logp("error closing delta for %s in receive\n", rb->path); goto error; } if(gzclose_fp(&(rb->burp1->zp))) { logp("error gzclosing delta for %s in receive\n", rb->path); goto error; } iobuf_copy(&rb->burp1->endfile, rbuf); rbuf->buf=NULL; if(rb->flags & SBUFL_RECV_DELTA && finish_delta(sdirs, rb)) goto error; if(sbufl_to_manifest(rb, p2fp, NULL)) goto error; if(rb->flags & SBUFL_RECV_DELTA) cntr_add_changed(cconf->cntr, rb->path.cmd); else cntr_add(cconf->cntr, rb->path.cmd, 0); if(*last_requested && !strcmp(rb->path.buf, *last_requested)) { free(*last_requested); *last_requested=NULL; } cp=strchr(rb->burp1->endfile.buf, ':'); if(rb->burp1->endfile.buf) cntr_add_bytes(cconf->cntr, strtoull(rb->burp1->endfile.buf, NULL, 10)); if(cp) { // checksum stuff goes here } sbuf_free_content(rb); return 0; error: sbuf_free_content(rb); return -1; }
static int new_non_file(struct sbuf *p1b, FILE *ucfp, struct conf *cconf) { // Is something that does not need more data backed up. // Like a directory or a link or something like that. // Goes into the unchanged file, so that it does not end up out of // order with normal files, which has to wait around for their data // to turn up. if(sbufl_to_manifest(p1b, ucfp, NULL)) return -1; else cntr_add(cconf->cntr, p1b->path.cmd, 0); sbuf_free_content(p1b); return 0; }
static int process_unchanged_file(struct sbuf *cb, FILE *ucfp, struct conf *cconf) { if(sbufl_to_manifest(cb, ucfp, NULL)) { sbuf_free_content(cb); return -1; } else { cntr_add_same(cconf->cntr, cb->path.cmd); } if(cb->burp1->endfile.buf) cntr_add_bytes(cconf->cntr, strtoull(cb->burp1->endfile.buf, NULL, 10)); sbuf_free_content(cb); return 1; }
static int process_unchanged_file(struct sbuf *p1b, struct sbuf *cb, struct fzp *ucfp, struct conf **cconfs) { // Need to re-encode the p1b attribs to include compression and // other bits and pieces that are recorded on cb. iobuf_move(&p1b->protocol1->datapth, &cb->protocol1->datapth); iobuf_move(&p1b->protocol1->endfile, &cb->protocol1->endfile); p1b->compression=cb->compression; if(attribs_encode(p1b)) return -1; if(sbufl_to_manifest(p1b, ucfp)) return -1; cntr_add_same(get_cntr(cconfs[OPT_CNTR]), p1b->path.cmd); if(p1b->protocol1->endfile.buf) cntr_add_bytes( get_cntr(cconfs[OPT_CNTR]), strtoull(p1b->protocol1->endfile.buf, NULL, 10)); sbuf_free_content(cb); return 1; }
static int maybe_delete_files_from_manifest(const char *manifesttmp, struct fdirs *fdirs, struct conf *cconf) { int ars=0; int ret=-1; int pcmp=0; FILE *dfp=NULL; gzFile nmzp=NULL; gzFile omzp=NULL; struct sbuf *db=NULL; struct sbuf *mb=NULL; struct stat statp; if(lstat(fdirs->deletionsfile, &statp)) // No deletions, no problem. return 0; logp("Performing deletions on manifest\n"); if(!(manifesttmp=get_tmp_filename(fdirs->manifest))) goto end; if(!(dfp=open_file(fdirs->deletionsfile, "rb")) || !(omzp=gzopen_file(fdirs->manifest, "rb")) || !(nmzp=gzopen_file(manifesttmp, comp_level(cconf))) || !(db=sbuf_alloc(cconf)) || !(mb=sbuf_alloc(cconf))) goto end; while(omzp || dfp) { if(dfp && !db->path.buf && (ars=sbufl_fill(db, NULL, dfp, NULL, cconf->cntr))) { if(ars<0) goto end; // ars==1 means it ended ok. close_fp(&dfp); } if(omzp && !mb->path.buf && (ars=sbufl_fill(mb, NULL, NULL, omzp, cconf->cntr))) { if(ars<0) goto end; // ars==1 means it ended ok. gzclose_fp(&omzp); } if(mb->path.buf && !db->path.buf) { if(sbufl_to_manifest(mb, NULL, nmzp)) goto end; sbuf_free_content(mb); } else if(!mb->path.buf && db->path.buf) { sbuf_free_content(db); } else if(!mb->path.buf && !db->path.buf) { continue; } else if(!(pcmp=sbuf_pathcmp(mb, db))) { // They were the same - do not write. sbuf_free_content(mb); sbuf_free_content(db); } else if(pcmp<0) { // Behind in manifest. Write. if(sbufl_to_manifest(mb, NULL, nmzp)) goto end; sbuf_free_content(mb); } else { // Behind in deletions file. Do not write. sbuf_free_content(db); } } ret=0; end: if(gzclose_fp(&nmzp)) { logp("error closing %s in %s\n", manifesttmp, __func__); ret=-1; } close_fp(&dfp); gzclose_fp(&omzp); sbuf_free(&db); sbuf_free(&mb); if(!ret) { unlink(fdirs->deletionsfile); // The rename race condition is not a problem here, as long // as manifesttmp is the same path as that generated in the // atomic data jiggle. if(do_rename(manifesttmp, fdirs->manifest)) return -1; } if(manifesttmp) unlink(manifesttmp); return ret; }
static int jiggle(struct sdirs *sdirs, struct fdirs *fdirs, struct sbuf *sb, int hardlinked_current, const char *deltabdir, const char *deltafdir, const char *sigpath, FILE **delfp, struct conf *cconf) { int ret=-1; struct stat statp; char *oldpath=NULL; char *newpath=NULL; char *finpath=NULL; char *deltafpath=NULL; const char *datapth=sb->burp1->datapth.buf; // If the previous backup was a hardlinked_archive, there will not be // a currentdup directory - just directly use the file in the previous // backup. if(!(oldpath=prepend_s(hardlinked_current? sdirs->currentdata:fdirs->currentdupdata, datapth)) || !(newpath=prepend_s(fdirs->datadirtmp, datapth)) || !(finpath=prepend_s(fdirs->datadir, datapth)) || !(deltafpath=prepend_s(deltafdir, datapth))) goto end; if(!lstat(finpath, &statp) && S_ISREG(statp.st_mode)) { // Looks like an interrupted jiggle // did this file already. static int donemsg=0; if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { logp("deleting unneeded forward delta: %s\n", deltafpath); unlink(deltafpath); } if(!donemsg) { logp("skipping already present file: %s\n", finpath); logp("to save log space, skips of other already present files will not be logged\n"); donemsg++; } } else if(mkpath(&finpath, fdirs->datadir)) { logp("could not create path for: %s\n", finpath); goto end; } else if(mkpath(&newpath, fdirs->datadirtmp)) { logp("could not create path for: %s\n", newpath); goto end; } else if(!lstat(deltafpath, &statp) && S_ISREG(statp.st_mode)) { int lrs; char *infpath=NULL; // Got a forward patch to do. // First, need to gunzip the old file, // otherwise the librsync patch will take // forever, because it will be doing seeks // all over the place, and gzseeks are slow. if(!(infpath=prepend_s(deltafdir, "inflate"))) { log_out_of_memory(__func__); goto end; } //logp("Fixing up: %s\n", datapth); if(inflate_or_link_oldfile(oldpath, infpath, sb->compression, cconf)) { logp("error when inflating old file: %s\n", oldpath); free(infpath); goto end; } if((lrs=do_patch(NULL, infpath, deltafpath, newpath, cconf->compression, sb->compression /* from the manifest */, cconf))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); cntr_add(cconf->cntr, CMD_WARNING, 1); // Try to carry on with the rest of the backup // regardless. //ret=-1; // Remove anything that got written. unlink(newpath); unlink(infpath); free(infpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=open_file(fdirs->deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. goto end; } if(sbufl_to_manifest(sb, *delfp, NULL)) goto end; if(fflush(*delfp)) { logp("error fflushing deletions file in %s: %s\n", __func__, strerror(errno)); goto end; } ret=0; goto end; } // Get rid of the inflated old file. unlink(infpath); free(infpath); // Need to generate a reverse diff, unless we are keeping a // hardlinked archive. if(!hardlinked_current) { if(gen_rev_delta(sigpath, deltabdir, oldpath, newpath, datapth, sb, cconf)) goto end; } // Power interruptions should be recoverable. If it happens // before this point, the data jiggle for this file has to be // done again. // Once finpath is in place, no more jiggle is required. // Use the fresh new file. // Rename race condition is of no consequence, because finpath // will just get recreated automatically. if(do_rename(newpath, finpath)) goto end; // Remove the forward delta, as it is no longer needed. There // is a reverse diff and the finished finished file is in place. //logp("Deleting delta.forward...\n"); unlink(deltafpath); // Remove the old file. If a power cut happens just before // this, the old file will hang around forever. // FIX THIS: maybe put in something to detect this. // ie, both a reverse delta and the old file exist. if(!hardlinked_current) { //logp("Deleting oldpath...\n"); unlink(oldpath); } } else if(!lstat(newpath, &statp) && S_ISREG(statp.st_mode)) { // Use the fresh new file. // This needs to happen after checking // for the forward delta, because the // patching stuff writes to newpath. // Rename race condition is of no consequence, because finpath // will just get recreated automatically. //logp("Using newly received file\n"); if(do_rename(newpath, finpath)) goto end; } else if(!lstat(oldpath, &statp) && S_ISREG(statp.st_mode)) { // Use the old unchanged file. // Hard link it first. //logp("Hard linking to old file: %s\n", datapth); if(do_link(oldpath, finpath, &statp, cconf, 0 /* do not overwrite finpath (should never need to) */)) goto end; else { // If we are not keeping a hardlinked // archive, delete the old link. if(!hardlinked_current) { //logp("Unlinking old file: %s\n", oldpath); unlink(oldpath); } } } else { logp("could not find: %s\n", oldpath); goto end; } ret=0; end: free_w(&oldpath); free_w(&newpath); free_w(&finpath); free_w(&deltafpath); return ret; }