Exclude sets generated with -C

David Sitsky david_sitsky at yahoo.com
Sun Sep 30 10:37:04 EST 2001


Hi guys,

I recently stumbled across what I think is an rsync bug.  The problem
was I was trying to rsync from one CVS checkout, to another, and was
using rsync -Cavz to do the job.  In this CVS module, there happens to
be two sub-directories with the names of "core" and "tags"
respectively, which were ignored, since these names matched the
default CVS ignore list.

When rsync builds the file lists with the -C option, it should include
any CVS controlled files (by checking CVS/Entries) before applying the
default CVS excludes, and the per-directory .cvsignore files.

Its actually surprising how many projects out there have
sub-directories with the name "core".  Linux is one of them.

Anyway, I have included a patch against rsync 2.4.6 which I believe
fixes this bug.  If this patch is ok, could it be included in the next
release?

Thanks for writing and maintaining such a useful tool!

--
Cheers,
David

diff -r -u --exclude=.o --exclude=rsync --exclude=configure --exclude=config.log /home/sits/orig/rsync-2.4.6/exclude.c ./exclude.c
--- /home/sits/orig/rsync-2.4.6/exclude.c	Wed Sep  6 13:46:43 2000
+++ ./exclude.c	Sat Sep 29 21:45:53 2001
@@ -27,6 +27,10 @@
 
 static struct exclude_struct **exclude_list;
 
+/* Global CVS exclude list, set from cvs_ignore_list, ~/.cvsignore
+   and getenv("CVSIGNORE"). */
+static struct exclude_struct **global_cvs_exclude_list;
+
 /* build an exclude structure given a exclude pattern */
 static struct exclude_struct *make_exclude(char *pattern, int include)
 {
@@ -125,6 +129,7 @@
 		  STRUCT_STAT *st)
 {
 	int n;
+	extern int cvs_exclude;
 
 	if (name && (name[0] == '.') && !name[1])
 		/* never exclude '.', even if somebody does --exclude '*' */
@@ -142,6 +147,18 @@
 				return !local_exclude_list[n]->include;
 	}
 
+	/* The global CVS exclude list must be checked last, since the user may
+	   have files under CVS control (eg directories called "core" or
+	   "tags") that should not be excluded if cvs_exclude is set.  CVS
+	   controlled files and directories will be set in
+	   local_exclude_list.	*/
+	if (cvs_exclude) {
+		for (n=0; global_cvs_exclude_list[n]; n++)
+			if (check_one_exclude(name,
+					      global_cvs_exclude_list[n],st))
+				return !global_cvs_exclude_list[n]->include;
+	}
+
 	return 0;
 }
 
@@ -319,16 +336,21 @@
 	return(t);
 }
 
-	
-void add_exclude_line(char *p)
+static void add_exclude_line_to_list(char *p,
+				     struct exclude_struct ***list)
 {
 	char *tok;
 	if (!p || !*p) return;
 	p = strdup(p);
 	if (!p) out_of_memory("add_exclude_line");
  	for (tok=get_exclude_tok(p); tok; tok=get_exclude_tok(NULL))
-		add_exclude(tok, 0);
+		add_exclude_list(tok, list, 0);
 	free(p);
+}	
+	
+void add_exclude_line(char *p)
+{
+	add_exclude_line_to_list(p, &exclude_list);
 }
 
 void add_include_line(char *p)
@@ -342,6 +364,35 @@
 	free(p);
 }
 
+/* Include all entries from fname, which is a CVS/Entries file, into list */
+void add_cvs_entries(char *fname, struct exclude_struct ***list)
+{
+	char line[MAXPATHLEN];
+	FILE *f = fopen(fname,"r");
+	if (f) {
+		while (fgets(line,MAXPATHLEN,f)) {
+			int len = strlen(line);
+			int offset = -1;
+
+			/* Determine offset for filename in line, depending
+			   if the entry is a directory or a file */
+			if (len >= 4 && line[0] == 'D' && line[1] == '/')
+				offset = 2;
+			else if (len >= 3 && line[0] == '/')
+				offset = 1;
+
+			/* Extract the entry name */
+			if (offset != -1) {
+				char *p = strchr(&line[offset],'/');
+				if (p) {
+					*p = 0;
+					add_exclude_list(&line[offset],
+							 list, 1);
+				}
+			}
+		}
+	}
+}
 
 static char *cvs_ignore_list[] = {
   "RCS","SCCS","CVS","CVS.adm","RCSLOG","cvslog.*",
@@ -359,12 +410,13 @@
 	int i;
   
 	for (i=0; cvs_ignore_list[i]; i++)
-		add_exclude(cvs_ignore_list[i], 0);
+		add_exclude_list(cvs_ignore_list[i], &global_cvs_exclude_list, 0);
 
 	if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
 		slprintf(fname,sizeof(fname), "%s/.cvsignore",p);
-		add_exclude_file(fname,0,0);
+		global_cvs_exclude_list =
+			make_exclude_list(fname, global_cvs_exclude_list, 0, 0);
 	}
 
-	add_exclude_line(getenv("CVSIGNORE"));
+	add_exclude_line_to_list(getenv("CVSIGNORE"), &global_cvs_exclude_list);
 }
Binary files /home/sits/orig/rsync-2.4.6/exclude.o and ./exclude.o differ
diff -r -u --exclude=.o --exclude=rsync --exclude=configure --exclude=config.log /home/sits/orig/rsync-2.4.6/flist.c ./flist.c
--- /home/sits/orig/rsync-2.4.6/flist.c	Wed Sep  6 13:46:43 2000
+++ ./flist.c	Sat Sep 29 21:46:59 2001
@@ -663,9 +663,26 @@
 	local_exclude_list = NULL;
 
 	if (cvs_exclude) {
+		/* Add the files specified in CVS/Entries to
+		   local_include_list, since they may contain directory
+		   names like "core" and "tags" which shouldn't be
+		   ignored.  Note this should be added before the exclude
+		   patterns in ./.cvsignore, since it may contain bogus
+		   entries that actually refer to CVS controlled files. */
+		if (strlen(fname) + strlen("CVS/Entries") <= MAXPATHLEN-1) {
+			strcpy(p,"CVS/Entries");
+			add_cvs_entries(fname,&local_exclude_list);
+		} else {
+			io_error = 1;
+			rprintf(FINFO,"cannot scan CVS/Entries in long-named directory %s\n",fname);
+		}
+
+		/* Add the exclude patterns specified in the ./.cvsignore file
+		   if it exists. */
 		if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) {
 			strcpy(p,".cvsignore");
-			local_exclude_list = make_exclude_list(fname,NULL,0,0);
+			local_exclude_list = make_exclude_list(fname,local_exclude_list,
+							       0,0);
 		} else {
 			io_error = 1;
 			rprintf(FINFO,"cannot cvs-exclude in long-named directory %s\n",fname);
@@ -681,6 +698,7 @@
 		send_file_name(f,flist,fname,recurse,0);
 	}
 
+	/* Free the exclude entries in local_exclude_list */
 	if (local_exclude_list) {
 		add_exclude_list("!", &local_exclude_list, 0);
 	}
Binary files /home/sits/orig/rsync-2.4.6/flist.o and ./flist.o differ
diff -r -u --exclude=.o --exclude=rsync --exclude=configure --exclude=config.log /home/sits/orig/rsync-2.4.6/proto.h ./proto.h
--- /home/sits/orig/rsync-2.4.6/proto.h	Wed Sep  6 13:46:43 2000
+++ ./proto.h	Sat Sep 29 20:33:47 2001
@@ -33,6 +33,7 @@
 char *get_exclude_tok(char *p);
 void add_exclude_line(char *p);
 void add_include_line(char *p);
+void add_cvs_entries(char *fname, struct exclude_struct ***list);
 void add_cvs_excludes(void);
 int sparse_end(int f);
 int write_file(int f,char *buf,int len);





More information about the rsync mailing list