rsync-exclude.patch.

John Bowman bowman at math.ualberta.ca
Sun Feb 16 11:16:46 EST 2003


> 	I like the idea of your rsync-exclude.patch and have thought
> about hacking it in myself. However as you already have done the work
> may I make a small suggestion...... can the name of the exclude file 
> (your .rsync) be specified in the flags.... e.g.
> 
> 	rsync --rsync-exclude=.snapshot -axvH /here /there
> 
> In this way different invocations (e.g. system and personal) can exclude
> different files.
> 
> Anthony R Iano-Fletcher        Anthony.Iano-Fletcher at nih.gov
>                                http://cbel.cit.nih.gov/~arif
>                                CBEL, CIT, NIH, Bethesda, MD, USA.

A good idea. I have implemented this as 

http://www.math.ualberta.ca/imaging/rlbackup/rsync-exclude-file.patch

Unfortunately, backwards compatibility with the previous syntax

	rsync --rsync-exclude -axvH /here /there

does not appear to be possible, because of deficiencies in the popt
option routines relative to getopt_long: popt doesn't really handle
optional arguments correctly, even with POPT_ARGFLAG_OPTIONAL.

Anyway, below is the new version of the --rsync-exclude patch.
This is a useful and general enough feature that I hope it will be added
to the next release of rsync.

-- John Bowman
University of Alberta

This is a patch to add an --rsync-exclude=FILE option to rsync-2.5.6.
Patterns in FILE are used to recursively exclude/include files in a
directory and all of its subdirectories. For example,

rsync --rsync-exclude=.rsync -vaxH /here /there

will copy all files from /here to /there, excluding any files listed in
a file .rsync from the directory containing this file and all of its
subdirectories. As usual, prefixing a pattern with "+ " forces inclusion
rather than exclusion.

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.6/exclude.c rsync-2.5.6J/exclude.c
--- rsync-2.5.6/exclude.c	Sun Jan 26 13:10:23 2003
+++ rsync-2.5.6J/exclude.c	Wed Jan 29 17:16:39 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: FILE, .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.6/flist.c rsync-2.5.6J/flist.c
--- rsync-2.5.6/flist.c	Sat Jan 18 11:00:23 2003
+++ rsync-2.5.6J/flist.c	Thu Feb 13 09:59:40 2003
@@ -39,6 +39,7 @@
 extern int always_checksum;
 
 extern int cvs_exclude;
+extern const char *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_exclude) <= MAXPATHLEN - 1) {
+			strcpy(p, rsync_exclude);
+			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.6/options.c rsync-2.5.6J/options.c
--- rsync-2.5.6/options.c	Mon Jan 27 20:11:57 2003
+++ rsync-2.5.6J/options.c	Thu Feb 13 11:13:01 2003
@@ -45,6 +45,7 @@
 int preserve_times = 0;
 int update_only = 0;
 int cvs_exclude = 0;
+const char *rsync_exclude = NULL;
 int dry_run=0;
 int local_server=0;
 int ignore_times=0;
@@ -84,7 +85,6 @@
 int modify_window=0;
 int blocking_io=-1;
 
-
 /** Network address family. **/
 #ifdef INET6
 int default_af_hint = 0;	/* Any protocol */
@@ -233,6 +233,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=FILE    recursively exclude files listed in FILE\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");
@@ -320,6 +321,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_STRING, &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.6/proto.h rsync-2.5.6J/proto.h
--- rsync-2.5.6/proto.h	Sun Jan 26 20:35:09 2003
+++ rsync-2.5.6J/proto.h	Wed Jan 29 17:16:39 2003
@@ -58,6 +58,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.6/rsync.yo rsync-2.5.6J/rsync.yo
--- rsync-2.5.6/rsync.yo	Mon Jan 27 20:11:57 2003
+++ rsync-2.5.6J/rsync.yo	Thu Feb 13 11:57:07 2003
@@ -311,6 +311,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=FILE    recursively exclude files listed in FILE
      --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 +655,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)) Patterns in FILE 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: FILE, .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