Add --compare-dest option which enables specifying an additional destination

for comparisons when syncing.  Useful for syncing into a scratch area and
doing a flash-cutover when it is completed.
This commit is contained in:
David Dykstra
1998-10-26 21:42:38 +00:00
parent b41c3f9273
commit 375a4556c7
5 changed files with 117 additions and 11 deletions

View File

@@ -162,6 +162,9 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
struct sum_struct *s;
int statret;
struct file_struct *file = flist->files[i];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
extern char *compare_dest;
if (verbose > 2)
rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
@@ -262,6 +265,21 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
return;
}
fnamecmp = fname;
if ((statret == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
int saveerrno = errno;
slprintf(fnamecmpbuf,MAXPATHLEN-1,"%s/%s",compare_dest,fname);
statret = link_stat(fnamecmpbuf,&st);
if (!S_ISREG(st.st_mode))
statret = -1;
if (statret == -1)
errno = saveerrno;
else
fnamecmp = fnamecmpbuf;
}
if (statret == -1) {
if (errno == ENOENT) {
write_int(f_out,i);
@@ -284,7 +302,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
return;
}
if (update_only && st.st_mtime > file->modtime) {
if (update_only && st.st_mtime > file->modtime && fnamecmp == fname) {
if (verbose > 1)
rprintf(FINFO,"%s is newer\n",fname);
return;
@@ -307,10 +325,10 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
}
/* open the file */
fd = open(fname,O_RDONLY);
fd = open(fnamecmp,O_RDONLY);
if (fd == -1) {
rprintf(FERROR,"failed to open %s : %s\n",fname,strerror(errno));
rprintf(FERROR,"failed to open %s : %s\n",fnamecmp,strerror(errno));
rprintf(FERROR,"skipping %s\n",fname);
return;
}
@@ -322,7 +340,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
}
if (verbose > 3)
rprintf(FINFO,"gen mapped %s of size %d\n",fname,(int)st.st_size);
rprintf(FINFO,"gen mapped %s of size %d\n",fnamecmp,(int)st.st_size);
s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));

View File

@@ -64,6 +64,7 @@ int block_size=BLOCK_SIZE;
char *backup_suffix = BACKUP_SUFFIX;
char *tmpdir = NULL;
char *compare_dest = NULL;
char *config_file = RSYNCD_CONF;
char *shell_cmd = NULL;
@@ -118,6 +119,7 @@ void usage(int F)
rprintf(F," --timeout=TIME set IO timeout in seconds\n");
rprintf(F," -I, --ignore-times don't exclude files that match length and time\n");
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
rprintf(F," -z, --compress compress file data\n");
rprintf(F," --exclude=PATTERN exclude file FILE\n");
rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n");
@@ -144,7 +146,7 @@ enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS,
OPT_SAFE_LINKS};
OPT_SAFE_LINKS, OPT_COMPARE_DEST};
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
@@ -188,6 +190,7 @@ static struct option long_options[] = {
{"block-size", 1, 0, 'B'},
{"timeout", 1, 0, OPT_TIMEOUT},
{"temp-dir", 1, 0, 'T'},
{"compare-dest", 1, 0, OPT_COMPARE_DEST},
{"compress", 0, 0, 'z'},
{"daemon", 0, 0, OPT_DAEMON},
{"stats", 0, 0, OPT_STATS},
@@ -384,6 +387,10 @@ int parse_arguments(int argc, char *argv[])
tmpdir = optarg;
break;
case OPT_COMPARE_DEST:
compare_dest = optarg;
break;
case 'z':
do_compression = 1;
break;
@@ -516,6 +523,16 @@ void server_options(char **args,int *argc)
args[ac++] = tmpdir;
}
if (compare_dest && am_sender) {
/* the server only needs this option if it is not the sender,
* and it may be an older version that doesn't know this
* option, so don't send it if client is the sender.
*/
args[ac++] = "--compare-dest";
args[ac++] = compare_dest;
}
*argc = ac;
}

View File

@@ -32,6 +32,7 @@ extern int preserve_hard_links;
extern int cvs_exclude;
extern int io_error;
extern char *tmpdir;
extern char *compare_dest;
static struct delete_list {
@@ -284,6 +285,8 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
STRUCT_STAT st;
char *fname;
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
struct map_struct *buf;
int i;
struct file_struct *file;
@@ -338,18 +341,28 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if (verbose > 2)
rprintf(FINFO,"recv_files(%s)\n",fname);
fnamecmp = fname;
/* open the file */
fd1 = open(fname,O_RDONLY);
fd1 = open(fnamecmp,O_RDONLY);
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
slprintf(fnamecmpbuf,MAXPATHLEN-1,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = open(fnamecmp,O_RDONLY);
}
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
rprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno));
rprintf(FERROR,"fstat %s : %s\n",fnamecmp,strerror(errno));
receive_data(f_in,NULL,-1,NULL,file->length);
close(fd1);
continue;
}
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
rprintf(FERROR,"%s : not a regular file (recv_files)\n",fname);
rprintf(FERROR,"%s : not a regular file (recv_files)\n",fnamecmp);
receive_data(f_in,NULL,-1,NULL,file->length);
close(fd1);
continue;
@@ -358,7 +371,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size);
rprintf(FINFO,"recv mapped %s of size %d\n",fnamecmp,(int)st.st_size);
} else {
buf = NULL;
}

View File

@@ -231,6 +231,7 @@ Options
--timeout=TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
-T --temp-dir=DIR create temporary files in directory DIR
--compare-dest=DIR also compare destination files relative to DIR
-z, --compress compress file data
--exclude=PATTERN exclude file FILE
--exclude-from=PATTERN exclude files listed in FILE
@@ -477,11 +478,21 @@ checksum length by default, using a 16 byte file checksum to determine
if a 2nd pass is required with a longer block checksum. Only use this
option if you have read the source code and know what you are doing.
dit(bf(-T, --temp-dir DIR)) This options instructs rsync to use DIR as a
scratch directory when creating a temporary copies of the files
dit(bf(-T, --temp-dir DIR)) This option instructs rsync to use DIR as a
scratch directory when creating temporary copies of the files
transferred on the receiving side. The default behavior is to create
the temporary files in the receiving directory.
dit(bf(--compare-dest DIR)) This option instructs rsync to use DIR as an
additional directory to compare destination files against when doing
transfers. This is useful for doing transfers to a new destination while
leaving existing files intact, and then doing a flash-cutover when all
files have been successfully transfered (for example by moving directories
around and removing the old directory). This option increases the
usefulness of --partial because partially transferred files will remain in
the new temporary destination until they have a chance to be completed.
If DIR is a relative path, it is relative to the destination directory.
dit(bf(-z, --compress)) With this option, rsync compresses any data from
the source file(s) which it sends to the destination machine. This
option is useful on slow links. The compression method used is the

47
util.c
View File

@@ -752,3 +752,50 @@ int unsafe_symlink(char *dest, char *src)
free(dest);
return (depth < 0);
}
/*
* Make path appear as if a chroot had occurred:
* 1. remove leading "/" (or replace with "." if at end)
* 2. remove leading ".." components
* 3. delete any other "<dir>/.." (recursively)
* Return a malloc'ed copy.
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
char *sanitize_path(char *p)
{
char *copy, *copyp;
copy = (char *) malloc(strlen(p)+1);
copyp = copy;
while (*p != '\0') {
if ((*p == '/') && (copyp == copy)) {
/* remove leading slash */
p++;
}
else if ((*p == '.') && (*(p+1) == '.') &&
((*(p+2) == '/') || (*(p+2) == '\0'))) {
/* remove .. followed by slash or end */
p += 2;
if (copyp != copy) {
/* backup the copy one level */
while ((--copyp != copy) && (*copyp == '/'))
/* skip trailing slashes */
;
while ((copyp != copy) && (*copyp != '/'))
/* skip back through slash */
copyp--;
}
} else {
/* copy one component */
while (1) {
*copyp++ = *p++;
if ((*p == '\0') || (*(p-1) == '/'))
break;
}
}
}
*copyp = '\0';
return(copy);
}