.rsync-/.rsync+ patch and --link-dest example

John Bowman bowman at math.ualberta.ca
Fri Jan 17 06:07:01 EST 2003


The patch below supercedes my patch dated 14 Jan 2003. The new version
fixes serious problems due to memory reallocation/freeing of lists and is
also more efficient. The scheme has been simplified to store excluded
patterns in .rsync only (a "+ " pattern prefix may be used to force inclusion).

Note: The precedence in check_exclude has been improved to use the most local
and most recent matching pattern. This is accomplished by searching
(backwards in each file) first the patterns found in .rsync, then in
.cvsignore, and finally in the global --exclude list.

The latest version of this patch is available at

http://www.math.ualberta.ca/imaging/rlbackup/

-- John Bowman

Associate Professor
Department of Mathematical and Statistical Sciences
University of Alberta
Edmonton, Alberta
Canada T6G 2G1

This is a patch to add an --rsync-exclude option to rsync-2.5.6cvs.
Patterns in .rsync can be used to recursively exclude/include files in the
current directory and all of its subdirectories.

This has advantages over --cvs-exclude for backing up large file systems
since the .cvsignore files only apply to the current directory:
unless the .cvsignore restrictions apply to the entire tree they must be
duplicated in each subdirectory. In any case, the --cvs-exclude option
isn't intended for general system backups (for example, unless the default
list is cleared with "!", it automatically excludes *.a and *.so libraries).

diff -ru rsync-2.5.6cvs/exclude.c rsync-2.5.6cvsJ/exclude.c
--- rsync-2.5.6cvs/exclude.c	Tue Jan 14 09:35:25 2003
+++ rsync-2.5.6cvsJ/exclude.c	Thu Jan 16 19:08:45 2003
@@ -127,6 +127,7 @@
 
 static void report_exclude_result(char const *name,
                                   struct exclude_struct const *ent,
+				  char const *type,
                                   STRUCT_STAT const *st)
 {
         /* If a trailing slash is present to match only directories,
@@ -134,10 +135,10 @@
          * case we add it back in here. */
         
         if (verbose >= 2)
-                rprintf(FINFO, "%s %s %s because of pattern %s%s\n",
+                rprintf(FINFO, "%s %s %s because of %s pattern %s%s\n",
                         ent->include ? "including" : "excluding",
                         S_ISDIR(st->st_mode) ? "directory" : "file",
-                        name, ent->pattern,
+                        name, type, ent->pattern,
                         ent->directory ? "/" : "");
 }
 
@@ -147,6 +148,7 @@
  * LOCAL_EXCLUDE_LIST or the globals EXCLUDE_LIST.
  */
 int check_exclude(char *name, struct exclude_struct **local_exclude_list,
+		  struct exclude_struct **recur_local_exclude_list,
 		  STRUCT_STAT *st)
 {
 	int n;
@@ -156,21 +158,37 @@
 		/* never exclude '.', even if somebody does --exclude '*' */
 		return 0;
 
-	if (exclude_list) {
-		for (n=0; exclude_list[n]; n++) {
-                        ent = exclude_list[n];
+	/* Precedence: use the most local and most recent matching pattern,
+	   in this order: .rsync, .cvsignore, --exclude */
+	
+	if (recur_local_exclude_list) {
+		for (n=0; recur_local_exclude_list[n]; n++) ;
+		for (n--; n >= 0; n--) {
+                        ent = recur_local_exclude_list[n];
 			if (check_one_exclude(name, ent, st)) {
-                                report_exclude_result(name, ent, st);
+                                report_exclude_result(name, ent, "rsync", st);
 				return !ent->include;
                         }
                 }
 	}
 
 	if (local_exclude_list) {
-		for (n=0; local_exclude_list[n]; n++) {
+		for (n=0; local_exclude_list[n]; n++) ;
+		for (n--; n >= 0; n--) {
                         ent = local_exclude_list[n];
 			if (check_one_exclude(name, ent, st)) {
-                                report_exclude_result(name, ent, st);
+                                report_exclude_result(name, ent, "cvsignore", st);
+				return !ent->include;
+                        }
+                }
+	}
+
+	if (exclude_list) {
+		for (n=0; exclude_list[n]; n++) ;
+		for (n--; n >= 0; n--) {
+                        ent = exclude_list[n];
+			if (check_one_exclude(name, ent, st)) {
+                                report_exclude_result(name, ent, "global", st);
 				return !ent->include;
                         }
                 }
diff -ru rsync-2.5.6cvs/flist.c rsync-2.5.6cvsJ/flist.c
--- rsync-2.5.6cvs/flist.c	Wed Jan 15 23:09:15 2003
+++ rsync-2.5.6cvsJ/flist.c	Thu Jan 16 19:09:00 2003
@@ -39,6 +39,7 @@
 extern int always_checksum;
 
 extern int cvs_exclude;
+extern int rsync_exclude;
 
 extern int recurse;
 
@@ -62,6 +63,7 @@
 extern int write_batch;
 
 static struct exclude_struct **local_exclude_list;
+static struct exclude_struct **recur_local_exclude_list;
 
 static struct file_struct null_file;
 
@@ -258,7 +260,8 @@
 	if ((f == -1) && delete_excluded) {
 		return 0;
 	}
-	if (check_exclude(fname, local_exclude_list, st)) {
+	if (check_exclude(fname, local_exclude_list, 
+			  recur_local_exclude_list, st)) {
 		return 1;
 	}
 	return 0;
@@ -773,7 +776,32 @@
 	return file;
 }
 
+static struct exclude_struct **copy_exclude_list(struct exclude_struct **from) {
+	struct exclude_struct **to;
+	int i;
+	int len=0;
+	int size;
+	
+	if (!from) return NULL;
+	
+	for (; from[len]; len++) ;
+	size=sizeof(struct exclude_struct *)*(len+1);
+	to = (struct exclude_struct **) malloc(size);
+	if (!to) out_of_memory("copy_exclude_list");
+
+	size=sizeof(struct exclude_struct);
+	for (i=0; i < len; i++) {
+	        struct exclude_struct *p;
+		p=to[i]=(struct exclude_struct *) malloc(size);
+		if (!p) out_of_memory("copy_exclude_list");
+		*p=*from[i];
+		p->pattern=strdup(from[i]->pattern);
+		if (!p->pattern) out_of_memory("copy_exclude_list");
+	}
+	to[len]=NULL;
 
+	return to;
+}
 
 void send_file_name(int f, struct file_list *flist, char *fname,
 		    int recursive, unsigned base_flags)
@@ -800,8 +828,11 @@
 	if (S_ISDIR(file->mode) && recursive) {
 		struct exclude_struct **last_exclude_list =
 		    local_exclude_list;
+		struct exclude_struct **recur_last_exclude_list =
+		    recur_local_exclude_list;
 		send_directory(f, flist, f_name(file));
 		local_exclude_list = last_exclude_list;
+		recur_local_exclude_list = recur_last_exclude_list;
 		return;
 	}
 }
@@ -840,6 +871,7 @@
 	p = fname + strlen(fname);
 
 	local_exclude_list = NULL;
+	recur_local_exclude_list = copy_exclude_list(recur_local_exclude_list);
 
 	if (cvs_exclude) {
 		if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN - 1) {
@@ -854,6 +886,19 @@
 		}
 	}
 
+	if (rsync_exclude) {
+		if (strlen(fname) + strlen(".rsync") <= MAXPATHLEN - 1) {
+			strcpy(p, ".rsync");
+			recur_local_exclude_list =
+			    make_exclude_list(fname, recur_local_exclude_list, 0, 0);
+		} else {
+			io_error = 1;
+			rprintf(FINFO,
+				"cannot cvs-exclude in long-named directory %s\n",
+				fname);
+		}
+	}
+
 	for (di = readdir(d); di; di = readdir(d)) {
 		char *dname = d_name(di);
 		if (strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0)
@@ -866,6 +911,10 @@
 		add_exclude_list("!", &local_exclude_list, 0);
 	}
 
+	if (recur_local_exclude_list) {
+		add_exclude_list("!", &recur_local_exclude_list, 0);
+	}
+
 	closedir(d);
 }
 
@@ -887,6 +936,8 @@
 	if (show_filelist_p() && f != -1)
 		start_filelist_progress("building file list");
 
+	recur_local_exclude_list = NULL;
+	
 	start_write = stats.total_written;
 
 	flist = flist_new();
diff -ru rsync-2.5.6cvs/options.c rsync-2.5.6cvsJ/options.c
--- rsync-2.5.6cvs/options.c	Thu Jan 16 19:17:23 2003
+++ rsync-2.5.6cvsJ/options.c	Thu Jan 16 19:14:38 2003
@@ -45,6 +45,7 @@
 int preserve_times = 0;
 int update_only = 0;
 int cvs_exclude = 0;
+int rsync_exclude = 0;
 int dry_run=0;
 int local_server=0;
 int ignore_times=0;
@@ -237,6 +238,7 @@
   rprintf(F," -e, --rsh=COMMAND           specify the remote shell\n");
   rprintf(F,"     --rsync-path=PATH       specify path to rsync on the remote machine\n");
   rprintf(F," -C, --cvs-exclude           auto ignore files in the same way CVS does\n");
+  rprintf(F,"     --rsync-exclude         recursively exclude files listed in .rsync\n");
   rprintf(F,"     --existing              only update files that already exist\n");
   rprintf(F,"     --ignore-existing       ignore files that already exist on the receiving side\n");
   rprintf(F,"     --delete                delete files that don't exist on the sending side\n");
@@ -324,6 +326,7 @@
   {"dry-run",         'n', POPT_ARG_NONE,   &dry_run , 0, 0, 0 },
   {"sparse",          'S', POPT_ARG_NONE,   &sparse_files , 0, 0, 0 },
   {"cvs-exclude",     'C', POPT_ARG_NONE,   &cvs_exclude , 0, 0, 0 },
+  {"rsync-exclude",     0, POPT_ARG_NONE,   &rsync_exclude , 0, 0, 0 },
   {"update",          'u', POPT_ARG_NONE,   &update_only , 0, 0, 0 },
   {"links",           'l', POPT_ARG_NONE,   &preserve_links , 0, 0, 0 },
   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links , 0, 0, 0 },
diff -ru rsync-2.5.6cvs/proto.h rsync-2.5.6cvsJ/proto.h
--- rsync-2.5.6cvs/proto.h	Wed Jan 15 23:09:15 2003
+++ rsync-2.5.6cvsJ/proto.h	Thu Jan 16 11:50:52 2003
@@ -57,6 +57,7 @@
 void setup_protocol(int f_out,int f_in);
 int claim_connection(char *fname,int max_connections);
 int check_exclude(char *name, struct exclude_struct **local_exclude_list,
+		  struct exclude_struct **recur_local_exclude_list,
 		  STRUCT_STAT *st);
 void add_exclude_list(const char *pattern, struct exclude_struct ***list, int include);
 void add_exclude(const char *pattern, int include);
diff -ru rsync-2.5.6cvs/rsync.yo rsync-2.5.6cvsJ/rsync.yo
--- rsync-2.5.6cvs/rsync.yo	Thu Jan 16 19:17:23 2003
+++ rsync-2.5.6cvsJ/rsync.yo	Thu Jan 16 19:14:38 2003
@@ -311,6 +316,7 @@
  -e, --rsh=COMMAND           specify the remote shell to use
      --rsync-path=PATH       specify path to rsync on the remote machine
  -C, --cvs-exclude           auto ignore files in the same way CVS does
+     --rsync-exclude         recursively exclude files listed in .rsync
      --existing              only update files that already exist
      --ignore-existing       ignore files that already exist on the receiving side
      --delete                delete files that don't exist on the sending side
@@ -654,6 +660,12 @@
 .cvsignore file and matches one of the patterns listed therein.  See
 the bf(cvs(1)) manual for more information.
 
+dit(bf(--rsync-exclude)) File names in .rsync are excluded from the file
+lists associated with the current directory and all of its subdirectories.
+Prefixing the file name with "+ " will force inclusion of the file.
+If there are multiplying matching patterns, the most local and most recent
+matching pattern will be used, in this order: .rsync, .cvsignore, --exclude.
+
 dit(bf(--csum-length=LENGTH)) By default the primary checksum used in
 rsync is a very strong 16 byte MD4 checksum. In most cases you will
 find that a truncated version of this checksum is quite efficient, and



More information about the rsync mailing list