Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
0
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;
}
Пример #5
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #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, 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;
}