static int forward_patch_and_reverse_diff( struct fdirs *fdirs, struct fzp **delfp, const char *deltabdir, const char *deltafdir, const char *deltafpath, const char *sigpath, const char *oldpath, const char *newpath, const char *datapth, const char *finpath, int hardlinked_current, struct sbuf *sb, struct conf **cconfs ) { int lrs; int ret=-1; 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, cconfs)) { logp("error when inflating old file: %s\n", oldpath); goto end; } if((lrs=do_patch(NULL, infpath, deltafpath, newpath, sb->compression, sb->compression /* from manifest */))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); cntr_add(get_cntr(cconfs), CMD_WARNING, 1); // Try to carry on with the rest of the backup regardless. // Remove anything that got written. unlink(newpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=fzp_open(fdirs->deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. goto end; } if(sbuf_to_manifest(sb, *delfp)) goto end; if(fzp_flush(*delfp)) { logp("error fflushing deletions file in %s: %s\n", __func__, strerror(errno)); goto end; } ret=0; goto end; } // 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, cconfs)) 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); } ret=0; end: if(infpath) { unlink(infpath); free_w(&infpath); } 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, struct fzp **delfp, struct conf **cconfs) { int ret=-1; struct stat statp; char *oldpath=NULL; char *newpath=NULL; char *finpath=NULL; char *deltafpath=NULL; const char *datapth=sb->protocol1->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, cconfs)) { logp("error when inflating old file: %s\n", oldpath); free_w(&infpath); goto end; } if((lrs=do_patch(NULL, infpath, deltafpath, newpath, sb->compression, sb->compression /* from manifest */))) { logp("WARNING: librsync error when patching %s: %d\n", oldpath, lrs); cntr_add(get_cntr(cconfs), 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_w(&infpath); // First, note that we want to remove this entry from // the manifest. if(!*delfp && !(*delfp=fzp_open(fdirs->deletionsfile, "ab"))) { // Could not mark this file as deleted. Fatal. goto end; } if(sbuf_to_manifest(sb, *delfp)) goto end; if(fzp_flush(*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_w(&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, cconfs)) 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, cconfs, 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; }