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);
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);
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;
}
/* 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;
}
}
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));
char *backup_suffix = BACKUP_SUFFIX;
char *tmpdir = NULL;
+char *compare_dest = NULL;
char *config_file = RSYNCD_CONF;
char *shell_cmd = NULL;
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");
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";
{"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},
tmpdir = optarg;
break;
+ case OPT_COMPARE_DEST:
+ compare_dest = optarg;
+ break;
+
case 'z':
do_compression = 1;
break;
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;
}
extern int cvs_exclude;
extern int io_error;
extern char *tmpdir;
+extern char *compare_dest;
static struct delete_list {
STRUCT_STAT st;
char *fname;
char fnametmp[MAXPATHLEN];
+ char *fnamecmp;
+ char fnamecmpbuf[MAXPATHLEN];
struct map_struct *buf;
int i;
struct file_struct *file;
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;
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;
}
--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
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
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);
+}
+