Depends-On-Patch: g2r-basis-filename.diff

This patch allows multiple --compare-dest or --link-dest options to be
used, making the transfer of some files more optimal.  Note that the
algorithm does NOT search for the best match -- it stops at the first
match and uses that as the basis file for the transfer, so be sure to
order your arguments appropriately (the args are searched in the order
they are suppled).

Before compiling, be sure to run "make proto".

--- orig/generator.c	2004-07-30 07:18:03
+++ generator.c	2004-07-30 07:28:13
@@ -43,7 +43,7 @@ extern int io_timeout;
 extern int protocol_version;
 extern int always_checksum;
 extern char *partial_dir;
-extern char *compare_dest;
+extern char *compare_dest[];
 extern int link_dest;
 extern int whole_file;
 extern int local_server;
@@ -413,11 +413,19 @@ static void recv_generator(char *fname, 
 	fnamecmp = fname;
 	fnamecmp_type = G2R_FNAME;
 
-	if (statret == -1 && compare_dest != NULL) {
+	if (statret == -1 && compare_dest[0] != NULL) {
 		/* try the file at compare_dest instead */
-		pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
-		if (link_stat(fnamecmpbuf, &st, 0) == 0
-		    && S_ISREG(st.st_mode)) {
+		int i = 0;
+		do {
+			pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
+				 compare_dest[i], fname);
+			if (link_stat(fnamecmpbuf, &st, 0) == 0
+			    && S_ISREG(st.st_mode)) {
+				statret = 0;
+				break;
+			}
+		} while (compare_dest[++i] != NULL);
+		if (statret == 0) {
 #if HAVE_LINK
 			if (link_dest && !dry_run) {
 				if (do_link(fnamecmpbuf, fname) < 0) {
@@ -428,15 +436,14 @@ static void recv_generator(char *fname, 
 							safe_fname(fname));
 					}
 					fnamecmp = fnamecmpbuf;
-					fnamecmp_type = 0;
+					fnamecmp_type = i;
 				}
 			} else
 #endif
 			{
 				fnamecmp = fnamecmpbuf;
-				fnamecmp_type = 0;
+				fnamecmp_type = i;
 			}
-			statret = 0;
 		}
 	}
 
--- orig/main.c	2004-07-22 00:10:43
+++ main.c	2004-07-30 07:23:54
@@ -59,7 +59,7 @@ extern int filesfrom_fd;
 extern pid_t cleanup_child_pid;
 extern char *files_from;
 extern char *remote_filesfrom_file;
-extern char *compare_dest;
+extern char *compare_dest[];
 extern char *rsync_path;
 extern char *shell_cmd;
 extern char *batch_name;
@@ -459,7 +459,7 @@ static int do_recv(int f_in,int f_out,st
 	int pid;
 	int status = 0;
 	int error_pipe[2], name_pipe[2];
-	BOOL need_name_pipe = compare_dest && !dry_run;
+	BOOL need_name_pipe = compare_dest[0] && !dry_run;
 
 	/* The receiving side mustn't obey this, or an existing symlink that
 	 * points to an identical file won't be replaced by the referent. */
--- orig/options.c	2004-08-03 15:41:32
+++ options.c	2004-07-30 07:23:54
@@ -115,12 +115,13 @@ int write_batch = 0;
 int read_batch = 0;
 int backup_dir_len = 0;
 int backup_suffix_len;
+int num_comp_dest = 0;
 unsigned int backup_dir_remainder;
 
 char *backup_suffix = NULL;
 char *tmpdir = NULL;
 char *partial_dir = NULL;
-char *compare_dest = NULL;
+char *compare_dest[MAX_COMP_DEST+1];
 char *config_file = NULL;
 char *shell_cmd = NULL;
 char *log_format = NULL;
@@ -141,6 +142,7 @@ char *batch_name = NULL;
 
 static int daemon_opt;   /* sets am_daemon after option error-reporting */
 static int modify_window_set;
+static int saw_compare_dest = 0;
 
 /** Local address to bind.  As a character string because it's
  * interpreted by the IPv6 layer: should be a numeric IP4 or IP6
@@ -318,7 +320,7 @@ void usage(enum logcode F)
 }
 
 enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
-      OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
+      OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_COMPARE_DEST, OPT_LINK_DEST,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
       OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT,
       OPT_REFUSED_BASE = 9000};
@@ -377,8 +379,8 @@ static struct poptOption long_options[] 
   {"max-delete",       0,  POPT_ARG_INT,    &max_delete, 0, 0, 0 },
   {"timeout",          0,  POPT_ARG_INT,    &io_timeout, OPT_TIMEOUT, 0, 0 },
   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
-  {"compare-dest",     0,  POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
-  {"link-dest",        0,  POPT_ARG_STRING, &compare_dest,  OPT_LINK_DEST, 0, 0 },
+  {"compare-dest",     0,  POPT_ARG_STRING, 0,              OPT_COMPARE_DEST, 0, 0 },
+  {"link-dest",        0,  POPT_ARG_STRING, 0,              OPT_LINK_DEST, 0, 0 },
   /* TODO: Should this take an optional int giving the compression level? */
   {"compress",        'z', POPT_ARG_NONE,   &do_compression, 0, 0, 0 },
   {"daemon",           0,  POPT_ARG_NONE,   &daemon_opt, 0, 0, 0 },
@@ -607,8 +609,28 @@ int parse_arguments(int *argc, const cha
 				select_timeout = io_timeout;
 			break;
 
+		case OPT_COMPARE_DEST:
+			if (num_comp_dest >= MAX_COMP_DEST-1) {
+				rprintf(FERROR, "ERROR: %s\n", "too many --compare-dest args given");
+				return 0;
+			}
+			arg = poptGetOptArg(pc);
+			if (sanitize_paths)
+				arg = alloc_sanitize_path(arg, curr_dir);
+			compare_dest[num_comp_dest++] = (char *)arg;
+			saw_compare_dest = 1;
+			break;
+
 		case OPT_LINK_DEST:
 #if HAVE_LINK
+			if (num_comp_dest >= MAX_COMP_DEST-1) {
+				rprintf(FERROR, "ERROR: %s\n", "too many --link-dest args given");
+				return 0;
+			}
+			arg = poptGetOptArg(pc);
+			if (sanitize_paths)
+				arg = alloc_sanitize_path(arg, curr_dir);
+			compare_dest[num_comp_dest++] = (char *)arg;
 			link_dest = 1;
 			break;
 #else
@@ -701,6 +723,11 @@ int parse_arguments(int *argc, const cha
 		return 0;
 	}
 
+	if (saw_compare_dest && link_dest) {
+		rprintf(FINFO,
+			"WARNING: promoting --compare-dest options to --link-dest.\n");
+	}
+
 	if (archive_mode) {
 		if (!files_from)
 			recurse = 1;
@@ -731,8 +758,6 @@ int parse_arguments(int *argc, const cha
 			tmpdir = alloc_sanitize_path(tmpdir, curr_dir);
 		if (partial_dir)
 			partial_dir = alloc_sanitize_path(partial_dir, curr_dir);
-		if (compare_dest)
-			compare_dest = alloc_sanitize_path(compare_dest, curr_dir);
 		if (backup_dir)
 			backup_dir = alloc_sanitize_path(backup_dir, curr_dir);
 		if (files_from)
@@ -882,8 +907,8 @@ int parse_arguments(int *argc, const cha
  **/
 void server_options(char **args,int *argc)
 {
+	static char argstr[50+MAX_COMP_DEST*2];
 	int ac = *argc;
-	static char argstr[50];
 	char *arg;
 
 	int i, x;
@@ -1067,13 +1092,16 @@ void server_options(char **args,int *arg
 		args[ac++] = tmpdir;
 	}
 
-	if (compare_dest && am_sender) {
+	if (compare_dest[0] && 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++] = link_dest ? "--link-dest" : "--compare-dest";
-		args[ac++] = compare_dest;
+		int i;
+		for (i = 0; i < num_comp_dest; i++) {
+			args[ac++] = link_dest ? "--link-dest" : "--compare-dest";
+			args[ac++] = compare_dest[i];
+		}
 	}
 
 	if (files_from && (!am_sender || remote_filesfrom_file)) {
--- orig/receiver.c	2004-07-30 07:17:48
+++ receiver.c	2004-07-30 07:31:12
@@ -38,7 +38,7 @@ extern int cvs_exclude;
 extern int io_error;
 extern char *tmpdir;
 extern char *partial_dir;
-extern char *compare_dest;
+extern char *compare_dest[];
 extern int make_backups;
 extern int do_progress;
 extern char *backup_dir;
@@ -442,7 +442,8 @@ int recv_files(int f_in, struct file_lis
 		partialptr = partial_dir ? partial_dir_fname(fname) : fname;
 
 		if (f_in_name >= 0) {
-			switch (read_byte(f_in_name)) {
+			uchar j;
+			switch (j = read_byte(f_in_name)) {
 			case G2R_FNAME:
 				fnamecmp = fname;
 				break;
@@ -451,7 +452,7 @@ int recv_files(int f_in, struct file_lis
 				break;
 			default:
 				pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
-					 compare_dest, fname);
+					 compare_dest[j], fname);
 				fnamecmp = fnamecmpbuf;
 				break;
 			}
--- orig/rsync.h	2004-07-30 07:16:38
+++ rsync.h	2004-07-30 07:23:54
@@ -98,6 +98,8 @@
 
 #define MAX_ARGS 1000
 
+#define MAX_COMP_DEST 20
+
 #define MPLEX_BASE 7
 
 #define NO_EXCLUDES	0
