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