Beispiel #1
0
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;
}
Beispiel #2
0
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;
}