Esempio n. 1
0
int backup_phase4_server_burp1(struct sdirs *sdirs, struct conf *cconf)
{
	int ret=-1;
	struct stat statp;
	ssize_t len=0;
	char realcurrent[256]="";
	unsigned long bno=0;
	int hardlinked_current=0;
	char tstmp[64]="";
	int previous_backup=0;
	struct fdirs *fdirs=NULL;

	if((len=readlink(sdirs->current, realcurrent, sizeof(realcurrent)-1))<0)
		len=0;
	realcurrent[len]='\0';

	if(!(fdirs=fdirs_alloc())
	  || fdirs_init(fdirs, sdirs, realcurrent))
		goto end;

	if(set_logfp(fdirs->logpath, cconf))
		goto end;

	logp("Begin phase4 (shuffle files)\n");

	if(write_status(STATUS_SHUFFLING, NULL, cconf))
		goto end;

	if(!lstat(sdirs->current, &statp)) // Had a previous backup.
	{
		previous_backup++;

		if(lstat(fdirs->hlinkedcurrent, &statp))
		{
			hardlinked_current=0;
			logp("Previous backup is not a hardlinked_archive\n");
			logp(" will generate reverse deltas\n");
		}
		else
		{
			hardlinked_current=1;
			logp("Previous backup is a hardlinked_archive\n");
			logp(" will not generate reverse deltas\n");
		}

		// If current was not a hardlinked_archive, need to duplicate
		// it.
		if(!hardlinked_current && lstat(fdirs->currentdup, &statp))
		{
			// Have not duplicated the current backup yet.
			if(!lstat(fdirs->currentduptmp, &statp))
			{
				logp("Removing previous directory: %s\n",
					fdirs->currentduptmp);
				if(recursive_delete(fdirs->currentduptmp,
					NULL, 1 /* del files */))
				{
					logp("Could not delete %s\n",
						fdirs->currentduptmp);
					goto end;
				}
			}
			logp("Duplicating current backup.\n");
			if(recursive_hardlink(sdirs->current,
				fdirs->currentduptmp, cconf)
			// The rename race condition is of no consequence here
			// because currentdup does not exist.
			  || do_rename(fdirs->currentduptmp, fdirs->currentdup))
				goto end;
		}
	}

	if(timestamp_read(fdirs->timestamp, tstmp, sizeof(tstmp)))
	{
		logp("could not read timestamp file: %s\n",
			fdirs->timestamp);
		goto end;
	}
	// Get the backup number.
	bno=strtoul(tstmp, NULL, 10);

	// Determine whether the new backup should be a hardlinked
	// archive or not, from the conf and the backup number...
	if(need_hardlinked_archive(cconf, bno))
	{
		// Create a file to indicate that the previous backup
		// does not have others depending on it.
		FILE *hfp=NULL;
		if(!(hfp=open_file(fdirs->hlinked, "wb"))) goto end;

		// Stick the next backup timestamp in it. It might
		// be useful one day when wondering when the next
		// backup, now deleted, was made.
		fprintf(hfp, "%s\n", tstmp);
		if(close_fp(&hfp))
		{
			logp("error closing hardlinked indication\n");
			goto end;
		}
	}
	else
		unlink(fdirs->hlinked);

	if(atomic_data_jiggle(sdirs, fdirs, hardlinked_current, cconf, bno))
	{
		logp("could not finish up backup.\n");
		goto end;
	}

	if(write_status(STATUS_SHUFFLING, "deleting temporary files", cconf))
		goto end;

	// Remove the temporary data directory, we have now removed
	// everything useful from it.
	recursive_delete(fdirs->datadirtmp, NULL, 1 /* del files */);

	// Clean up the currentdata directory - this is now the 'old'
	// currentdata directory. Any files that were deleted from
	// the client will be left in there, so call recursive_delete
	// with the option that makes it not delete files.
	// This will have the effect of getting rid of unnecessary
	// directories.
	sync(); // try to help CIFS
	recursive_delete(fdirs->currentdupdata, NULL, 0 /* do not del files */);

	// Rename the old current to something that we know to delete.
	if(previous_backup && !hardlinked_current)
	{
		if(deleteme_move(sdirs->client,
			fdirs->fullrealcurrent, realcurrent, cconf)
		// I have tested that potential race conditions on the
		// rename() are automatically recoverable here.
		  || do_rename(fdirs->currentdup, fdirs->fullrealcurrent))
			goto end;
	}

	if(deleteme_maybe_delete(cconf, sdirs->client))
		goto end;

	cntr_stats_to_file(cconf->cntr, sdirs->finishing, ACTION_BACKUP);

	logp("End phase4 (shuffle files)\n");

	ret=0;
end:
	fdirs_free(fdirs);
	return ret;
}
Esempio n. 2
0
int backup_phase4_server(struct sdirs *sdirs, struct conf *cconf)
{
	int ret=-1;
	struct stat statp;
	char *manifest=NULL;
	char *deletionsfile=NULL;
	char *datadir=NULL;
	char *datadirtmp=NULL;
	char *currentdup=NULL;
	char *currentduptmp=NULL;
	char *currentdupdata=NULL;
	char *timestamp=NULL;
	char *fullrealcurrent=NULL;
	char *logpath=NULL;
	char *hlinkedpath=NULL;
	ssize_t len=0;
	char realcurrent[256]="";

	unsigned long bno=0;
	int hardlinked=0;
	char tstmp[64]="";
	int newdup=0;
	int previous_backup=0;

	if((len=readlink(sdirs->current, realcurrent, sizeof(realcurrent)-1))<0)
		len=0;
	realcurrent[len]='\0';

	if(!(datadir=prepend_s(sdirs->finishing, "data"))
	  || !(datadirtmp=prepend_s(sdirs->finishing, "data.tmp"))
	  || !(manifest=prepend_s(sdirs->finishing, "manifest.gz"))
	  || !(deletionsfile=prepend_s(sdirs->finishing, "deletions"))
	  || !(currentdup=prepend_s(sdirs->finishing, "currentdup"))
	  || !(currentduptmp=prepend_s(sdirs->finishing, "currentdup.tmp"))
	  || !(currentdupdata=prepend_s(currentdup, "data"))
	  || !(timestamp=prepend_s(sdirs->finishing, "timestamp"))
	  || !(fullrealcurrent=prepend_s(sdirs->client, realcurrent))
	  || !(logpath=prepend_s(sdirs->finishing, "log"))
	  || !(hlinkedpath=prepend_s(currentdup, "hardlinked")))
		goto end;

	if(set_logfp(logpath, cconf))
		goto end;

	logp("Begin phase4 (shuffle files)\n");

	if(write_status(STATUS_SHUFFLING, NULL, cconf))
		goto end;

	if(!lstat(sdirs->current, &statp)) // Had a previous backup
	{
		previous_backup++;

		if(lstat(currentdup, &statp))
		{
			// Have not duplicated the current backup yet.
			if(!lstat(currentduptmp, &statp))
			{
				logp("Removing previous currentduptmp directory: %s\n", currentduptmp);
				if(recursive_delete(currentduptmp,
					NULL, 1 /* del files */))
				{
					logp("Could not delete %s\n",
						currentduptmp);
					goto end;
				}
			}
			logp("Duplicating current backup.\n");
			if(recursive_hardlink(sdirs->current, currentduptmp, cconf)
			  || do_rename(currentduptmp, currentdup))
				goto end;
			newdup++;
		}

		if(read_timestamp(timestamp, tstmp, sizeof(tstmp)))
		{
			logp("could not read timestamp file: %s\n", timestamp);
			goto end;
		}
		// Get the backup number.
		bno=strtoul(tstmp, NULL, 10);

		if(newdup)
		{
			// When we have just created currentdup, determine
			// hardlinked archive from the conf and the backup
			// number...
			hardlinked=do_hardlinked_archive(cconf, bno);
		}
		else
		{
			// ...if recovering, find out what currentdup started
			// out as.
			// Otherwise it is possible that things can be messed
			// up by somebody swapping between hardlinked and
			// not hardlinked at the same time as a resume happens.
			if(lstat(hlinkedpath, &statp))
			{
				logp("previous attempt started not hardlinked\n");
				hardlinked=0;
			}
			else
			{
				logp("previous attempt started hardlinked\n");
				hardlinked=1;
			}
		}

		if(hardlinked)
		{
			// Create a file to indicate that the previous backup
			// does not have others depending on it.
			FILE *hfp=NULL;
			if(!(hfp=open_file(hlinkedpath, "wb")))
				goto end;
			// Stick the next backup timestamp in it. It might
			// be useful one day when wondering when the next
			// backup, now deleted, was made.
			fprintf(hfp, "%s\n", tstmp);
			if(close_fp(&hfp))
			{
				logp("error closing hardlinked indication\n");
				goto end;
			}
			logp(" doing hardlinked archive\n");
			logp(" will not generate reverse deltas\n");
		}
		else
		{
			logp(" not doing hardlinked archive\n");
			logp(" will generate reverse deltas\n");
			unlink(hlinkedpath);
		}
	}

	if(atomic_data_jiggle(sdirs, cconf, manifest, currentdup,
		currentdupdata, datadir, datadirtmp, deletionsfile,
		hardlinked, bno))
	{
		logp("could not finish up backup.\n");
		goto end;
	}

	if(write_status(STATUS_SHUFFLING, "deleting temporary files", cconf))
		goto end;

	// Remove the temporary data directory, we have now removed
	// everything useful from it.
	recursive_delete(datadirtmp, NULL, 1 /* del files */);

	// Clean up the currentdata directory - this is now the 'old'
	// currentdata directory. Any files that were deleted from
	// the client will be left in there, so call recursive_delete
	// with the option that makes it not delete files.
	// This will have the effect of getting rid of unnecessary
	// directories.
	sync(); // try to help CIFS
	recursive_delete(currentdupdata, NULL, 0 /* do not del files */);

	// Rename the old current to something that we know to delete.
	if(previous_backup)
	{
		if(deleteme_move(sdirs->client,
			fullrealcurrent, realcurrent, cconf)
		  || do_rename(currentdup, fullrealcurrent))
			goto end;
	}

	if(deleteme_maybe_delete(cconf, sdirs->client))
		goto end;

	cntr_stats_to_file(cconf->cntr, sdirs->finishing, ACTION_BACKUP);

	// Rename the finishing symlink so that it becomes the current symlink
	do_rename(sdirs->finishing, sdirs->current);

	cntr_print(cconf->cntr, ACTION_BACKUP);
	logp("Backup completed.\n");
	logp("End phase4 (shuffle files)\n");
	set_logfp(NULL, cconf); // will close logfp.

	compress_filename(sdirs->current, "log", "log.gz", cconf);

	ret=0;
end:
	if(datadir) free(datadir);
	if(datadirtmp) free(datadirtmp);
	if(manifest) free(manifest);
	if(deletionsfile) free(deletionsfile);
	if(currentdup) free(currentdup);
	if(currentduptmp) free(currentduptmp);
	if(currentdupdata) free(currentdupdata);
	if(timestamp) free(timestamp);
	if(fullrealcurrent) free(fullrealcurrent);
	if(logpath) free(logpath);
	if(hlinkedpath) free(hlinkedpath);

	return ret;
}
Esempio n. 3
0
File: link.c Progetto: EmisFR/burp
int recursive_hardlink(const char *src, const char *dst, struct conf **confs)
{
	int n=-1;
	int ret=0;
	struct dirent **dir;
	char *tmp=NULL;
	char *fullpatha=NULL;
	char *fullpathb=NULL;
	//logp("in rec hl: %s %s\n", src, dst);
	if(!(tmp=prepend_s(dst, "dummy"))) return -1;
	if(mkpath(&tmp, dst))
	{
		logp("could not mkpath for %s\n", tmp);
		free_w(&tmp);
		return -1;
	}
	free_w(&tmp);

	if((n=scandir(src, &dir, 0, 0))<0)
	{
		logp("recursive_hardlink scandir %s: %s\n",
			src, strerror(errno));
		return -1;
	}
	while(n--)
	{
		struct stat statp;
		if(dir[n]->d_ino==0
		  || !strcmp(dir[n]->d_name, ".")
		  || !strcmp(dir[n]->d_name, ".."))
			{ free(dir[n]); continue; }
		free_w(&fullpatha);
		free_w(&fullpathb);
		if(!(fullpatha=prepend_s(src, dir[n]->d_name))
		  || !(fullpathb=prepend_s(dst, dir[n]->d_name)))
			break;

#ifdef _DIRENT_HAVE_D_TYPE
// Faster evaluation on most systems.
		if(dir[n]->d_type==DT_DIR)
		{
			if(recursive_hardlink(fullpatha, fullpathb, confs))
				break;
		}
		else
#endif
		// Otherwise, we have to do an lstat() anyway, because we
		// will need to check the number of hardlinks in do_link().
		if(lstat(fullpatha, &statp))
		{
			logp("could not lstat %s\n", fullpatha);
		}
		else if(S_ISDIR(statp.st_mode))
		{
			if(recursive_hardlink(fullpatha, fullpathb, confs))
				break;
		}
		else
		{
			//logp("hardlinking %s to %s\n", fullpathb, fullpatha);
			if(write_status(CNTR_STATUS_SHUFFLING, fullpathb,
				get_cntr(confs))
			  || do_link(fullpatha, fullpathb, &statp, confs,
				0 /* do not overwrite target */))
				break;
		}
		free(dir[n]);
	}
	if(n>0)
	{
		ret=-1;
		for(; n>0; n--) free(dir[n]);
	}
	free(dir);

	free_w(&fullpatha);
	free_w(&fullpathb);

	return ret;
}
Esempio n. 4
0
int backup_phase4_server(const char *basedir, const char *working, const char *current, const char *currentdata, const char *finishing, struct config *cconf, const char *client, struct cntr *p1cntr, struct cntr *cntr)
{
	int ret=0;
	struct stat statp;
	char *manifest=NULL;
	char *datadir=NULL;
	char *datadirtmp=NULL;
	char *currentdup=NULL;
	char *currentduptmp=NULL;
	char *currentdupdata=NULL;
	char *forward=NULL;
	char *timestamp=NULL;
	char *fullrealcurrent=NULL;
	char *deleteme=NULL;
	char *logpath=NULL;
	char *hlinkedpath=NULL;
	int len=0;
	char realcurrent[256]="";
	FILE *logfp=NULL;

	if((len=readlink(current, realcurrent, sizeof(realcurrent)-1))<0)
		len=0;
	realcurrent[len]='\0';

	if(!(datadir=prepend_s(finishing, "data", strlen("data")))
	  || !(datadirtmp=prepend_s(finishing, "data.tmp", strlen("data.tmp")))
	  || !(manifest=prepend_s(finishing, "manifest.gz", strlen("manifest.gz")))
	  || !(currentdup=prepend_s(finishing, "currentdup", strlen("currentdup")))
	  || !(currentduptmp=prepend_s(finishing, "currentdup.tmp", strlen("currentdup.tmp")))
	  || !(currentdupdata=prepend_s(currentdup, "data", strlen("data")))
	  || !(forward=prepend_s(currentdup, "forward", strlen("forward")))
	  || !(timestamp=prepend_s(finishing, "timestamp", strlen("timestamp")))
	  || !(fullrealcurrent=prepend_s(basedir, realcurrent, strlen(realcurrent)))
	  || !(deleteme=prepend_s(basedir, "deleteme", strlen("deleteme")))
	  || !(logpath=prepend_s(finishing, "log", strlen("log")))
	  || !(hlinkedpath=prepend_s(currentdup, "hardlinked", strlen("hardlinked"))))
	{
		ret=-1;
		goto endfunc;
	}

	if(!(logfp=open_file(logpath, "ab")) || set_logfp(logfp, cconf))
	{
		ret=-1;
		goto endfunc;
	}

	logp("Begin phase4 (shuffle files)\n");

	write_status(client, STATUS_SHUFFLING, NULL, p1cntr, cntr);

	if(!lstat(current, &statp)) // Had a previous backup
	{
		unsigned long bno=0;
		FILE *fwd=NULL;
		int hardlinked=0;
		char tstmp[64]="";
		int newdup=0;

		if(lstat(currentdup, &statp))
		{
			// Have not duplicated the current backup yet.
			if(!lstat(currentduptmp, &statp))
			{
				logp("Removing previous currentduptmp directory: %s\n", currentduptmp);
				if(recursive_delete(currentduptmp,
					NULL, TRUE /* del files */))
				{
					logp("Could not delete %s\n",
						currentduptmp);
					ret=-1;
					goto endfunc;
				}
			}
			logp("Duplicating current backup.\n");
			if(recursive_hardlink(current, currentduptmp, client,
				p1cntr, cntr, cconf)
			  || do_rename(currentduptmp, currentdup))
			{
				ret=-1;
				goto endfunc;
			}
			newdup++;
		}

		if(read_timestamp(timestamp, tstmp, sizeof(tstmp)))
		{
			logp("could not read timestamp file: %s\n", timestamp);
			ret=-1;
			goto endfunc;
		}
		// Get the backup number.
		bno=strtoul(tstmp, NULL, 10);

		// Put forward reference in, indicating the timestamp of
		// the working directory (which will soon become the current
		// directory).
		if(!(fwd=open_file(forward, "wb")))
		{
			log_and_send("could not create forward file");
			ret=-1;
			goto endfunc;
		}
		fprintf(fwd, "%s\n", tstmp);
		close_fp(&fwd);

		if(newdup)
		{
			// When we have just created currentdup, determine
			// hardlinked archive from the conf and the backup
			// number...
			hardlinked=do_hardlinked_archive(cconf, bno);
		}
		else
		{
			// ...if recovering, find out what currentdup started
			// out as.
			// Otherwise it is possible that things can be messed
			// up by somebody swapping between hardlinked and
			// not hardlinked at the same time as a resume happens.
			if(lstat(hlinkedpath, &statp))
			{
				logp("previous attempt started not hardlinked\n");
				hardlinked=0;
			}
			else
			{
				logp("previous attempt started hardlinked\n");
				hardlinked=1;
			}
		}

		if(hardlinked)
		{
			// Create a file to indicate that the previous backup
			// does not have others depending on it.
			FILE *hfp=NULL;
			if(!(hfp=open_file(hlinkedpath, "wb")))
			{
				ret=-1;
				goto endfunc;
			}
			// Stick the next backup timestamp in it. It might
			// be useful one day when wondering when the next
			// backup, now deleted, was made.
			fprintf(hfp, "%s\n", tstmp);
			close_fp(&hfp);
			logp(" doing hardlinked archive\n");
			logp(" will not generate reverse deltas\n");
		}
		else
		{
			logp(" not doing hardlinked archive\n");
			logp(" will generate reverse deltas\n");
			unlink(hlinkedpath);
		}

		if(atomic_data_jiggle(finishing,
			working, manifest, currentdup,
			currentdupdata,
			datadir, datadirtmp, cconf, client,
			hardlinked, bno, p1cntr, cntr))
		{
			logp("could not finish up backup.\n");
			ret=-1;
			goto endfunc;
		}

		write_status(client, STATUS_SHUFFLING,
			"deleting temporary files", p1cntr, cntr);

		// Remove the temporary data directory, we have now removed
		// everything useful from it.
		recursive_delete(datadirtmp, NULL, TRUE /* del files */);

		// Clean up the currentdata directory - this is now the 'old'
		// currentdata directory. Any files that were deleted from
		// the client will be left in there, so call recursive_delete
		// with the option that makes it not delete files.
		// This will have the effect of getting rid of unnecessary
		// directories.
		sync(); // try to help CIFS
		recursive_delete(currentdupdata, NULL, FALSE /* do not del files */);

		// Rename the old current to something that we know to
		// delete.
		if(do_rename(fullrealcurrent, deleteme))
		{
			ret=-1;
			goto endfunc;
		}
	}
	else
	{
		// No previous backup, just put datadirtmp in the right place.
		if(do_rename(datadirtmp, datadir))
		{
			ret=-1;
			goto endfunc;
		}
	}

	if(!lstat(deleteme, &statp))
	{
		// Rename the currentdup directory...
		// IMPORTANT TODO: read the path to fullrealcurrent
		// from the deleteme timestamp.
		do_rename(currentdup, fullrealcurrent);

		recursive_delete(deleteme, NULL, TRUE /* delete all */);
	}

	// Rename the finishing symlink so that it becomes the current symlink
	do_rename(finishing, current);

	print_filecounters(p1cntr, cntr, ACTION_BACKUP, 0);
	logp("Backup completed.\n");
	logp("End phase4 (shuffle files)\n");
	set_logfp(NULL, cconf); // will close logfp.

	compress_filename(current, "log", "log.gz", cconf);

endfunc:
	if(datadir) free(datadir);
	if(datadirtmp) free(datadirtmp);
	if(manifest) free(manifest);
	if(currentdup) free(currentdup);
	if(currentduptmp) free(currentduptmp);
	if(currentdupdata) free(currentdupdata);
	if(forward) free(forward);
	if(timestamp) free(timestamp);
	if(fullrealcurrent) free(fullrealcurrent);
	if(deleteme) free(deleteme);
	if(logpath) free(logpath);
	if(hlinkedpath) free(hlinkedpath);

	return ret;
}
Esempio n. 5
-1
int recursive_hardlink(const char *src, const char *dst, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *conf)
{
	int n=-1;
	int ret=0;
	struct dirent **dir;
	char *tmp=NULL;
	//logp("in rec hl: %s %s\n", src, dst);
	if(!(tmp=prepend_s(dst, "dummy", strlen("dummy"))))
		return -1;
	if(mkpath(&tmp, dst))
	{
		logp("could not mkpath for %s\n", tmp);
		free(tmp);
		return -1;
	}
	free(tmp);

	if((n=scandir(src, &dir, 0, 0))<0)
	{
		logp("recursive_hardlink scandir %s: %s\n",
			src, strerror(errno));
		return -1;
	}
	while(n--)
	{
		struct stat statp;
		char *fullpatha=NULL;
		char *fullpathb=NULL;
		if(dir[n]->d_ino==0
		  || !strcmp(dir[n]->d_name, ".")
		  || !strcmp(dir[n]->d_name, ".."))
			{ free(dir[n]); continue; }
		if(!(fullpatha=prepend_s(src,
			dir[n]->d_name, strlen(dir[n]->d_name)))
		|| !(fullpathb=prepend_s(dst,
			dir[n]->d_name, strlen(dir[n]->d_name))))
		{
			if(fullpatha) free(fullpatha);
			if(fullpathb) free(fullpathb);
			break;
		}

		if(lstat(fullpatha, &statp))
		{
			logp("could not lstat %s\n", fullpatha);
		}
		else if(S_ISDIR(statp.st_mode))
		{
			if(recursive_hardlink(fullpatha, fullpathb, client,
				p1cntr, cntr, conf))
			{
				free(fullpatha);
				free(fullpathb);
				break;
			}
		}
		else
		{
			//logp("hardlinking %s to %s\n", fullpathb, fullpatha);
			write_status(client, STATUS_SHUFFLING, fullpathb,
				p1cntr, cntr);
			if(do_link(fullpatha, fullpathb, &statp, conf,
				FALSE /* do not overwrite target */))
			{
				free(fullpatha);
				free(fullpathb);
				break;
			}
		}
		free(fullpatha);
		free(fullpathb);
		free(dir[n]);
	}
	if(n>0)
	{
		ret=-1;
		for(; n>0; n--) free(dir[n]);
	}
	free(dir);

	return ret;
}