Пример #1
0
static int changed_non_file(struct sbuf *p1b, FILE *ucfp, char cmd, struct cntr *cntr)
{
	// As new_non_file.
	if(sbuf_to_manifest(p1b, ucfp, NULL))
		return -1;
	else
		do_filecounter_changed(cntr, cmd);
	free_sbuf(p1b);
	return 0;
}
Пример #2
0
static int new_non_file(struct sbuf *p1b, FILE *ucfp, char cmd, struct cntr *cntr)
{
	// 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(sbuf_to_manifest(p1b, ucfp, NULL))
		return -1;
	else
		do_filecounter(cntr, cmd, 0);
	free_sbuf(p1b);
	return 0;
}
Пример #3
0
static int process_unchanged_file(struct sbuf *cb, FILE *ucfp, struct cntr *cntr)
{
	if(sbuf_to_manifest(cb, ucfp, NULL))
	{
		free_sbuf(cb);
		return -1;
	}
	else
	{
		do_filecounter_same(cntr, cb->cmd);
	}
	if(cb->endfile) do_filecounter_bytes(cntr,
		 strtoull(cb->endfile, NULL, 10));
	free_sbuf(cb);
	return 1;
}
Пример #4
0
int manio_write_sbuf(struct manio *manio, struct sbuf *sb)
{
	if(!manio->fzp && manio_open_next_fpath(manio)) return -1;
	return sbuf_to_manifest(sb, manio->fzp);
}
Пример #5
0
// Combine the phase1 and phase2 files into a new manifest.
int backup_phase3_server(const char *phase2data, const char *unchangeddata, const char *manifest, int recovery, int compress, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf)
{
	int ars=0;
	int ret=0;
	int pcmp=0;
	FILE *ucfp=NULL;
	FILE *p2fp=NULL;
	FILE *mp=NULL;
	gzFile mzp=NULL;
	struct sbuf ucb;
	struct sbuf p2b;
	char *manifesttmp=NULL;

	logp("Begin phase3 (merge manifests)\n");

	if(!(manifesttmp=get_tmp_filename(manifest))) return -1;

        if(!(ucfp=open_file(unchangeddata, "rb"))
	  || !(p2fp=open_file(phase2data, "rb"))
	  || (compress && !(mzp=gzopen_file(manifesttmp, comp_level(cconf))))
          || (!compress && !(mp=open_file(manifesttmp, "wb"))))
	{
		close_fp(&ucfp);
		gzclose_fp(&mzp);
		close_fp(&p2fp);
		close_fp(&mp);
		free(manifesttmp);
		return -1;
	}

	init_sbuf(&ucb);
	init_sbuf(&p2b);

	while(ucfp || p2fp)
	{
		if(ucfp && !ucb.path && (ars=sbuf_fill(ucfp, NULL, &ucb, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			close_fp(&ucfp);
		}
		if(p2fp && !p2b.path && (ars=sbuf_fill(p2fp, NULL, &p2b, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			close_fp(&p2fp);

			// In recovery mode, only want to read to the last
			// entry in the phase 2 file.
			if(recovery) break;
		}

		if(ucb.path && !p2b.path)
		{
			write_status(client, STATUS_MERGING, ucb.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&ucb, mp, mzp)) { ret=-1; break; }
			free_sbuf(&ucb);
		}
		else if(!ucb.path && p2b.path)
		{
			write_status(client, STATUS_MERGING, p2b.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; }
			free_sbuf(&p2b);
		}
		else if(!ucb.path && !p2b.path) 
		{
			continue;
		}
		else if(!(pcmp=sbuf_pathcmp(&ucb, &p2b)))
		{
			// They were the same - write one and free both.
			write_status(client, STATUS_MERGING, p2b.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; }
			free_sbuf(&p2b);
			free_sbuf(&ucb);
		}
		else if(pcmp<0)
		{
			write_status(client, STATUS_MERGING, ucb.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&ucb, mp, mzp)) { ret=-1; break; }
			free_sbuf(&ucb);
		}
		else
		{
			write_status(client, STATUS_MERGING, p2b.path,
				p1cntr, cntr);
			if(sbuf_to_manifest(&p2b, mp, mzp)) { ret=-1; break; }
			free_sbuf(&p2b);
		}
	}

	free_sbuf(&ucb);
	free_sbuf(&p2b);

	close_fp(&p2fp);
	close_fp(&ucfp);
	if(close_fp(&mp))
	{
		logp("error closing %s in backup_phase3_server\n",
			manifesttmp);
		ret=-1;
	}
	if(gzclose_fp(&mzp))
	{
		logp("error gzclosing %s in backup_phase3_server\n",
			manifesttmp);
		ret=-1;
	}

	if(!ret)
	{
		if(do_rename(manifesttmp, manifest))
			ret=-1;
		else
		{
			unlink(phase2data);
			unlink(unchangeddata);
		}
	}

	free(manifesttmp);

	logp("End phase3 (merge manifests)\n");

	return ret;
}
Пример #6
0
static int maybe_delete_files_from_manifest(const char *manifesttmp,
	struct fdirs *fdirs, struct conf **cconfs)
{
	int ars=0;
	int ret=-1;
	int pcmp=0;
	struct fzp *dfp=NULL;
	struct fzp *nmzp=NULL;
	struct fzp *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=fzp_open(fdirs->deletionsfile, "rb"))
	  || !(omzp=fzp_gzopen(fdirs->manifest, "rb"))
	  || !(nmzp=fzp_gzopen(manifesttmp,
		comp_level(get_int(cconfs[OPT_COMPRESSION]))))
	  || !(db=sbuf_alloc(PROTO_1))
	  || !(mb=sbuf_alloc(PROTO_1)))
		goto end;

	while(omzp || dfp)
	{
		if(dfp && !db->path.buf
		  && (ars=sbuf_fill_from_file(db, dfp, NULL, NULL)))
		{
			if(ars<0) goto end;
			// ars==1 means it ended ok.
			fzp_close(&dfp);
		}
		if(omzp && !mb->path.buf
		  && (ars=sbuf_fill_from_file(mb, omzp, NULL, NULL)))
		{
			if(ars<0) goto end;
			// ars==1 means it ended ok.
			fzp_close(&omzp);
		}

		if(mb->path.buf && !db->path.buf)
		{
			if(sbuf_to_manifest(mb, 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(sbuf_to_manifest(mb, nmzp)) goto end;
			sbuf_free_content(mb);
		}
		else
		{
			// Behind in deletions file. Do not write.
			sbuf_free_content(db);
		}
	}

	ret=0;
end:
	if(fzp_close(&nmzp))
	{
		logp("error closing %s in %s\n", manifesttmp, __func__);
		ret=-1;
	}
	
	fzp_close(&dfp);
	fzp_close(&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;
}
Пример #7
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;
}
Пример #8
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;
}
Пример #9
0
static int maybe_delete_files_from_manifest(const char *manifest, const char *deletionsfile, struct config *cconf, struct cntr *cntr)
{
	int ars=0;
	int ret=0;
	int pcmp=0;
	FILE *dfp=NULL;
	struct sbuf db;
	struct sbuf mb;
	gzFile nmzp=NULL;
	gzFile omzp=NULL;
	char *manifesttmp=NULL;
	struct stat statp;

	if(lstat(deletionsfile, &statp))
	{
		// No deletions, no problem.
		return 0;
	}
	logp("Performing deletions on manifest\n");

	if(!(manifesttmp=get_tmp_filename(manifest)))
	{
		ret=-1;
		goto end;
	}

        if(!(dfp=open_file(deletionsfile, "rb"))
	  || !(omzp=gzopen_file(manifest, "rb"))
	  || !(nmzp=gzopen_file(manifesttmp, comp_level(cconf))))
	{
		ret=-1;
		goto end;
	}

	init_sbuf(&db);
	init_sbuf(&mb);

	while(omzp || dfp)
	{
		if(dfp && !db.path && (ars=sbuf_fill(dfp, NULL, &db, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			close_fp(&dfp);
		}
		if(omzp && !mb.path && (ars=sbuf_fill(NULL, omzp, &mb, cntr)))
		{
			if(ars<0) { ret=-1; break; }
			// ars==1 means it ended ok.
			gzclose_fp(&omzp);
		}

		if(mb.path && !db.path)
		{
			if(sbuf_to_manifest(&mb, NULL, nmzp)) { ret=-1; break; }
			free_sbuf(&mb);
		}
		else if(!mb.path && db.path)
		{
			free_sbuf(&db);
		}
		else if(!mb.path && !db.path) 
		{
			continue;
		}
		else if(!(pcmp=sbuf_pathcmp(&mb, &db)))
		{
			// They were the same - do not write.
			free_sbuf(&mb);
			free_sbuf(&db);
		}
		else if(pcmp<0)
		{
			// Behind in manifest. Write.
			if(sbuf_to_manifest(&mb, NULL, nmzp)) { ret=-1; break; }
			free_sbuf(&mb);
		}
		else
		{
			// Behind in deletions file. Do not write.
			free_sbuf(&db);
		}
	}

end:
	if(gzclose_fp(&nmzp))
	{
		logp("error closing %s in maybe_delete_files_from_manifest\n",
			manifesttmp);
		ret=-1;
	}
	
	close_fp(&dfp);
	gzclose_fp(&omzp);
	free_sbuf(&db);
	free_sbuf(&mb);
	if(!ret)
	{
		unlink(deletionsfile);
		if(do_rename(manifesttmp, manifest))
		{
			free(manifesttmp);
			return -1;
		}
	}
	if(manifesttmp)
	{
		unlink(manifesttmp);
		free(manifesttmp);
	}
	return ret;
}
Пример #10
0
static int jiggle(const char *datapth, const char *currentdata, const char *datadirtmp, const char *datadir, const char *deltabdir, const char *deltafdir, const char *sigpath, const char *endfile, const char *deletionsfile, FILE **delfp, struct sbuf *sb, int hardlinked, int compression, struct cntr *cntr, struct config *cconf)
{
	int ret=0;
	struct stat statp;
	char *oldpath=NULL;
	char *newpath=NULL;
	char *finpath=NULL;
	char *deltafpath=NULL;

	if(!(oldpath=prepend_s(currentdata, datapth, strlen(datapth)))
	  || !(newpath=prepend_s(datadirtmp, datapth, strlen(datapth)))
	  || !(finpath=prepend_s(datadir, datapth, strlen(datapth)))
	  || !(deltafpath=prepend_s(deltafdir, datapth, strlen(datapth))))
	{
		log_out_of_memory(__FUNCTION__);
		ret=-1;	
		goto cleanup;
	}
	else 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, datadir))
	{
		logp("could not create path for: %s\n", finpath);
		ret=-1;
		goto cleanup;
	}
	else if(mkpath(&newpath, datadirtmp))
	{
		logp("could not create path for: %s\n", newpath);
		ret=-1;
		goto cleanup;
	}
	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", strlen("inflate"))))
		{
			log_out_of_memory(__FUNCTION__);
			ret=-1;
			goto cleanup;
		}

		//logp("Fixing up: %s\n", datapth);
		if(inflate_or_link_oldfile(oldpath, infpath, compression, cconf))
		{
			logp("error when inflating old file: %s\n", oldpath);
			ret=-1;
			free(infpath);
			goto cleanup;
		}

		if((lrs=do_patch(infpath, deltafpath, newpath,
			cconf->compression,
			compression /* from the manifest */, cntr, cconf)))
		{
			logp("WARNING: librsync error when patching %s: %d\n",
				oldpath, lrs);
			do_filecounter(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(deletionsfile, "ab")))
			{
				// Could not mark this file as deleted. Fatal.
				ret=-1;
				goto cleanup;
			}
			if(sbuf_to_manifest(sb, *delfp, NULL))
				ret=-1;
			if(fflush(*delfp))
			{
				logp("error fflushing deletions file in jiggle: %s\n", strerror(errno));
				ret=-1;
			}

			goto cleanup;
		}

		// 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)
		{
			if(gen_rev_delta(sigpath, deltabdir,
				oldpath, newpath, datapth, endfile,
				compression, cntr, cconf))
			{
				ret=-1;
				goto cleanup;
			}
		}

		// 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.
		if(do_rename(newpath, finpath))
		{
			ret=-1;
			goto cleanup;
		}
		else
		{
			// 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.
			// TODO: Put in something to
			// detect this.
			// ie, both a reverse delta and the
			// old file exist.
			if(!hardlinked)
			{
				//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.
		//logp("Using newly received file\n");
		if(do_rename(newpath, finpath))
		{
			ret=-1;
			goto cleanup;
		}
	}
	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,
		  FALSE /* do not overwrite finpath (should never need to) */))
		{
			ret=-1;
			goto cleanup;
		}
		else
		{
			// If we are not keeping a hardlinked
			// archive, delete the old link.
			if(!hardlinked)
			{
				//logp("Unlinking old file: %s\n", oldpath);
				unlink(oldpath);
			}
		}
	}
	else
	{
		logp("could not find: %s\n", oldpath);
		ret=-1;
		goto cleanup;
	}

cleanup:
	if(oldpath) { free(oldpath); oldpath=NULL; }
	if(newpath) { free(newpath); newpath=NULL; }
	if(finpath) { free(finpath); finpath=NULL; }
	if(deltafpath) { free(deltafpath); deltafpath=NULL; }

	return ret;
}
Пример #11
0
// returns 1 for finished ok.
static int do_stuff_to_receive(struct sbuf *rb, FILE *p2fp, const char *datadirtmp, struct dpth *dpth, const char *working, char **last_requested, const char *deltmppath, struct cntr *cntr, struct config *cconf)
{
	int ret=0;
	char rcmd;
	size_t rlen=0;
	size_t wlen=0;
	char *rbuf=NULL;

	// This also attempts to write anything in the write buffer.
	if(async_rw(&rcmd, &rbuf, &rlen, '\0', NULL, &wlen))
	{
		logp("error in async_rw\n");
		return -1;
	}

	if(rbuf)
	{
		if(rcmd==CMD_WARNING)
		{
			logp("WARNING: %s\n", rbuf);
			do_filecounter(cntr, rcmd, 0);
		}
		else if(rb->fp || rb->zp)
		{
			// Currently writing a file (or meta data)
			if(rcmd==CMD_APPEND)
			{
				int app;
				//logp("rlen: %d\n", rlen);
				if((rb->zp
				  && (app=gzwrite(rb->zp, rbuf, rlen))<=0)
				|| (rb->fp
				  && (app=fwrite(rbuf, 1, rlen, rb->fp))<=0))
				{
					logp("error when appending: %d\n", app);
					async_write_str(CMD_ERROR, "write failed");
					ret=-1;
				}
				do_filecounter_recvbytes(cntr, rlen);
			}
			else if(rcmd==CMD_END_FILE)
			{
				// Finished the file.
				// Write it to the phase2 file, and free the
				// buffers.

				if(close_fp(&(rb->fp)))
				{
					logp("error closing delta for %s in receive\n", rb->path);
					ret=-1;
				}
				if(gzclose_fp(&(rb->zp)))
				{
					logp("error gzclosing delta for %s in receive\n", rb->path);
					ret=-1;
				}
				rb->endfile=rbuf;
				rb->elen=rlen;
				rbuf=NULL;
				if(!ret && rb->receivedelta
				  && finish_delta(rb, working, deltmppath))
					ret=-1;
				else if(!ret)
				{
					if(sbuf_to_manifest(rb, p2fp, NULL))
						ret=-1;
					else
					{
					  char cmd=rb->cmd;
					  if(rb->receivedelta)
						do_filecounter_changed(cntr,
							cmd);
					  else
						do_filecounter(cntr, cmd, 0);
					  if(*last_requested
					  && !strcmp(rb->path, *last_requested))
					  {
						free(*last_requested);
						*last_requested=NULL;
					  }
					}
				}

				if(!ret)
				{
					char *cp=NULL;
					cp=strchr(rb->endfile, ':');
					if(rb->endfile)
					 do_filecounter_bytes(cntr,
					  strtoull(rb->endfile, NULL, 10));
					if(cp)
					{
						// checksum stuff goes here
					}
				}

				free_sbuf(rb);
			}
			else
			{
				logp("unexpected cmd from client while writing file: %c %s\n", rcmd, rbuf);
				ret=-1;
			}
		}
		// Otherwise, expecting to be told of a file to save.
		else if(rcmd==CMD_DATAPTH)
		{
			rb->datapth=rbuf;
			rbuf=NULL;
		}
		else if(rcmd==CMD_STAT)
		{
			rb->statbuf=rbuf;
			rb->slen=rlen;
			rbuf=NULL;
		}
		else if(filedata(rcmd))
		{
			rb->cmd=rcmd;
			rb->plen=rlen;
			rb->path=rbuf;
			rbuf=NULL;

			if(rb->datapth)
			{
				// Receiving a delta.
				if(start_to_receive_delta(rb,
				  working, deltmppath, cconf))
				{
					logp("error in start_to_receive_delta\n");
					ret=-1;
				}
			}
			else
			{
				// Receiving a whole new file.
				if(start_to_receive_new_file(rb,
					datadirtmp, dpth, cntr, cconf))
				{
					logp("error in start_to_receive_new_file\n");
					ret=-1;
				}
			}
		}
		else if(rcmd==CMD_GEN && !strcmp(rbuf, "okbackupphase2end"))
		{
			ret=1;
			//logp("got okbackupphase2end\n");
		}
		else if(rcmd==CMD_INTERRUPT)
		{
			// Interrupt - forget about the last requested file
			// if it matches. Otherwise, we can get stuck on the
			// select in the async stuff, waiting for something
			// that will never arrive.
			if(*last_requested && !strcmp(rbuf, *last_requested))
			{
				free(*last_requested);
				*last_requested=NULL;
			}
		}
		else
		{
			logp("unexpected cmd from client while expecting a file: %c %s\n", rcmd, rbuf);
			ret=-1;
		}

		if(rbuf) { free(rbuf); rbuf=NULL; }
	}

	//logp("returning: %d\n", ret);
	return ret;
}