1This patch causes the --cvs-exclude option to prefix the names listed 2in each dir's CVS/Entries file as per-dir includes before the dir's list 3of excludes taken from the .cvsignore file. 4 5To use this patch, run these commands for a successful build: 6 7 patch -p1 <patches/cvs-entries.diff 8 ./configure (optional if already run) 9 make 10 11--- old/exclude.c 12+++ new/exclude.c 13@@ -216,6 +216,8 @@ static void add_rule(struct filter_list_ 14 if (!(lp = new_array(struct filter_list_struct, 1))) 15 out_of_memory("add_rule"); 16 lp->head = lp->tail = NULL; 17+ if (mflags & MATCHFLG_CVS_IGNORE) 18+ cp = "CVS"; 19 if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0) 20 out_of_memory("add_rule"); 21 ret->u.mergelist = lp; 22@@ -448,6 +450,14 @@ void *push_local_filters(const char *dir 23 set_filter_dir(dir, dirlen); 24 } 25 26+ if (ex->match_flags & MATCHFLG_CVS_IGNORE 27+ && strlcpy(dirbuf + dirbuf_len, "CVS/Entries", 28+ MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) { 29+ /* Start by adding include rules for all the names in CVS/Entries. */ 30+ parse_filter_file(lp, dirbuf, 31+ MATCHFLG_NO_PREFIXES | MATCHFLG_INCLUDE, 32+ XFLG_CVS_ENTRIES); 33+ } 34 if (strlcpy(dirbuf + dirbuf_len, ex->pattern, 35 MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) { 36 parse_filter_file(lp, dirbuf, ex->match_flags, 37@@ -973,6 +983,7 @@ void parse_filter_file(struct filter_lis 38 char line[BIGPATHBUFLEN]; 39 char *eob = line + sizeof line - 1; 40 int word_split = mflags & MATCHFLG_WORD_SPLIT; 41+ int slash_parse = xflags & XFLG_CVS_ENTRIES ? 1 : 0; 42 43 if (!fname || !*fname) 44 return; 45@@ -1019,6 +1030,24 @@ void parse_filter_file(struct filter_lis 46 } 47 break; 48 } 49+ switch (slash_parse) { /* CVS/Entries parsing: */ 50+ case 1: /* Ignore starting chars until first slash. */ 51+ if (ch == '/') 52+ slash_parse = 2; 53+ continue; 54+ case 2: /* Name ends at 2nd slash on the line. */ 55+ if (ch == '/') { 56+ slash_parse = 3; 57+ continue; 58+ } 59+ break; 60+ case 3: /* Ignore trailing chars until EOL. */ 61+ if (ch == '\n' || ch == '\r') { 62+ slash_parse = 1; 63+ goto end_the_line; 64+ } 65+ continue; 66+ } 67 if (word_split && isspace(ch)) 68 break; 69 if (eol_nulls? !ch : (ch == '\n' || ch == '\r')) 70@@ -1028,13 +1057,15 @@ void parse_filter_file(struct filter_lis 71 else 72 overflow = 1; 73 } 74+ end_the_line: 75 if (overflow) { 76 rprintf(FERROR, "discarding over-long filter: %s...\n", line); 77 s = line; 78 } 79 *s = '\0'; 80 /* Skip an empty token and (when line parsing) comments. */ 81- if (*line && (word_split || (*line != ';' && *line != '#'))) 82+ if (*line && (word_split || slash_parse 83+ || (*line != ';' && *line != '#'))) 84 parse_rule(listp, line, mflags, xflags); 85 if (ch == EOF) 86 break; 87--- old/rsync.h 88+++ new/rsync.h 89@@ -117,6 +117,7 @@ 90 #define XFLG_OLD_PREFIXES (1<<1) 91 #define XFLG_ANCHORED2ABS (1<<2) 92 #define XFLG_ABS_IF_SLASH (1<<3) 93+#define XFLG_CVS_ENTRIES (1<<4) 94 95 #define ATTRS_REPORT (1<<0) 96 #define ATTRS_SKIP_MTIME (1<<1) 97--- old/testsuite/exclude.test 98+++ new/testsuite/exclude.test 99@@ -19,6 +19,7 @@ export CVSIGNORE 100 101 makepath "$fromdir/foo/down/to/you" 102 makepath "$fromdir/foo/sub" 103+makepath "$fromdir/bar/down/to/CVS" 104 makepath "$fromdir/bar/down/to/foo/too" 105 makepath "$fromdir/bar/down/to/bar/baz" 106 makepath "$fromdir/mid/for/foo/and/that/is/who" 107@@ -57,6 +58,9 @@ echo cvsout >"$fromdir/bar/down/to/foo/f 108 echo gone >"$fromdir/bar/down/to/foo/file3" 109 echo lost >"$fromdir/bar/down/to/foo/file4" 110 echo weird >"$fromdir/bar/down/to/foo/+ file3" 111+echo cvsin >"$fromdir/bar/down/to/not.junk" 112+echo cvsout >"$fromdir/bar/down/to/not.good" 113+echo cvsout >"$fromdir/bar/down/to/D" 114 echo cvsout-but-filtin >"$fromdir/bar/down/to/foo/file4.junk" 115 echo smashed >"$fromdir/bar/down/to/foo/to" 116 cat >"$fromdir/bar/down/to/bar/.filt2" <<EOF 117@@ -103,7 +107,18 @@ cat >"$excl" <<EOF 118 EOF 119 120 cat >"$scratchdir/.cvsignore" <<EOF 121-home-cvs-exclude 122+home-cvs-exclude D 123+EOF 124+cat >"$fromdir/bar/down/to/CVS/Entries" <<EOF 125+/not.junk/1.1/Mon Jan 1 11:11:11 2001// 126+filt2 127+/another.file/1.1/Tue Jan 1 22:22:22 2002// 128+invalid lines should just be ignored... 129+D/directory//// 130+D 131+EOF 132+cat >"$fromdir/bar/down/to/.cvsignore" <<EOF 133+not.good 134 EOF 135 136 # Create the chk dir with what we expect to be excluded 137@@ -132,6 +147,10 @@ checkit "$RSYNC -avv --exclude-from=\"$e 138 # Modify the chk dir by removing cvs-ignored files and then tweaking the dir times. 139 140 rm "$chkdir"/foo/*.old 141+rm "$chkdir"/bar/down/to/D 142+rm "$chkdir"/bar/down/to/CVS/Entries 143+rmdir "$chkdir"/bar/down/to/CVS 144+rm "$chkdir"/bar/down/to/not.good 145 rm "$chkdir"/bar/down/to/foo/*.bak 146 rm "$chkdir"/bar/down/to/foo/*.junk 147 rm "$chkdir"/bar/down/to/home-cvs-exclude 148@@ -147,8 +166,12 @@ checkit "$RSYNC -avvC --filter=\"merge $ 149 150 # Modify the chk dir for our merge-exclude test and then tweak the dir times. 151 152+makepath "$chkdir/bar/down/to/CVS" 153 rm "$chkdir"/foo/file1 154 rm "$chkdir"/bar/down/to/bar/baz/*.deep 155+cp -p "$fromdir"/bar/down/to/D "$chkdir"/bar/down/to/D 156+cp -p "$fromdir"/bar/down/to/not.good "$chkdir"/bar/down/to/not.good 157+cp -p "$fromdir"/bar/down/to/CVS/Entries "$chkdir"/bar/down/to/CVS/Entries 158 cp -p "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo 159 cp -p "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo 160 161