Add --compare-dest option which enables specifying an additional destination
authorDavid Dykstra <dwd@samba.org>
Mon, 26 Oct 1998 21:42:38 +0000 (21:42 +0000)
committerDavid Dykstra <dwd@samba.org>
Mon, 26 Oct 1998 21:42:38 +0000 (21:42 +0000)
for comparisons when syncing.  Useful for syncing into a scratch area and
doing a flash-cutover when it is completed.

generator.c
options.c
receiver.c
rsync.yo
util.c

index ffde4444b9ffc282f98fb392cf78ccb27abef9d5..99052220ce67bd5413d5b1763354ef454ec5b16d 100644 (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));
 
index 23b3c8cd4f128b11a14fc0f639f20f66689145bb..a79443fc77e7a4212b467985fe54e7b8d3a64ec0 100644 (file)
--- a/options.c
+++ b/options.c
@@ -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;
 }
 
index c565a6f68313070977e219ee6f169c4a4462dab4..204933ff21d80dbac37288b721755e0d0b57589a 100644 (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;
                }
index 8da75b99a62ffcf6a3700f609e9c0c92e30bd069..cedf578176b728f01ea4dc9299c9cc9e095401bb 100644 (file)
--- a/rsync.yo
+++ b/rsync.yo
@@ -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 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
diff --git a/util.c b/util.c
index 6e0fbabac5ca6f03c1a01eb6c1526cc2e6e05ecf..3c23cb7a55228c33ec2a674e5b9e43b969f588bd 100644 (file)
--- a/util.c
+++ b/util.c
@@ -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);
+}
+