Fixed a failing hunk.
[rsync/rsync-patches.git] / filter.diff
CommitLineData
8a529471
WD
1After applying this patch and running configure, you MUST run this
2command before "make":
3
4 make proto
5
524989ae 6This patch adds the ability to merge rules into your excludes/includes
2e064775
WD
7using either "+m FILE" (for merged includes) or "-m FILE" (for merged
8excludes). It also lets you specify either "+p FILE" or "-p FILE" in
9order to specify a per-directory merge file -- one that will be looked
10for in every sub-directory that rsync visits, and the rules found in
11that subdirectory's file will affect that dir and (if desired) its
12subdirs.
a55d21aa
WD
13
14For example:
15
2e064775 16 rsync -av --exclude='-p .excl' from/ to
a55d21aa
WD
17
18The above will look for a file named ".excl" in every directory of the
524989ae
WD
19hierarchy that rsync visits, and it will exclude (by default) names
20based on the rules found therein. If one of the .excl files contains
21this:
a55d21aa
WD
22
23 + *.c
2e064775
WD
24 -p .excl2
25 -m .excl3
524989ae 26 *.o
5f98a4b1 27 /foobar
a55d21aa 28
d34d9fad 29Then the file ".excl2" will also be read in from the current dir and all
2e064775
WD
30its subdirs. The file ".excl3" would just be read in from the current
31dir. The exclusion of "foobar" will only happen in that .excl file's
32directory because the rule is anchored, so that's how you can make rules
33local instead of inherited.
a55d21aa
WD
34
35..wayne..
36
37da98ae 37--- orig/clientserver.c 2005-01-01 21:11:00
3d3aaf9f 38+++ clientserver.c 2004-08-10 15:44:15
37da98ae 39@@ -49,12 +49,14 @@ extern int no_detach;
40e20a69
WD
40 extern int default_af_hint;
41 extern char *bind_address;
42 extern struct exclude_list_struct server_exclude_list;
43-extern char *exclude_path_prefix;
44 extern char *config_file;
45 extern char *files_from;
40e20a69
WD
46
47 char *auth_user;
48
3d3aaf9f 49+/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */
45795ec6
WD
50+unsigned int module_dirlen = 0;
51+
52 /**
53 * Run a client connected to an rsyncd. The alternative to this
54 * function for remote-shell connections is do_cmd().
37da98ae 55@@ -304,26 +306,28 @@ static int rsync_module(int f_in, int f_
40e20a69
WD
56 /* TODO: Perhaps take a list of gids, and make them into the
57 * supplementary groups. */
58
59- exclude_path_prefix = use_chroot? "" : lp_path(i);
60- if (*exclude_path_prefix == '/' && !exclude_path_prefix[1])
61- exclude_path_prefix = "";
45795ec6
WD
62+ if (use_chroot) {
63+ module_dirlen = 0;
64+ set_excludes_dir("/", 1);
65+ } else {
66+ module_dirlen = strlen(lp_path(i));
67+ set_excludes_dir(lp_path(i), module_dirlen);
68+ }
40e20a69
WD
69
70 p = lp_include_from(i);
71 add_exclude_file(&server_exclude_list, p,
72- XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
73+ XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE | XFLG_ABS_PATH);
74
75 p = lp_include(i);
76 add_exclude(&server_exclude_list, p,
77- XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE);
78+ XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE | XFLG_ABS_PATH);
79
80 p = lp_exclude_from(i);
81 add_exclude_file(&server_exclude_list, p,
82- XFLG_FATAL_ERRORS);
83+ XFLG_FATAL_ERRORS | XFLG_ABS_PATH);
84
85 p = lp_exclude(i);
86- add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT);
45795ec6 87-
40e20a69 88- exclude_path_prefix = NULL;
45795ec6 89+ add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT | XFLG_ABS_PATH);
40e20a69
WD
90
91 log_init();
92
2e064775
WD
93--- orig/exclude.c 2005-01-13 23:15:56
94+++ exclude.c 2005-01-15 05:29:58
b338da5b 95@@ -30,13 +30,69 @@ extern int verbose;
a55d21aa
WD
96 extern int eol_nulls;
97 extern int list_only;
98 extern int recurse;
99+extern int io_error;
56babefa 100+extern int sanitize_paths;
a55d21aa
WD
101
102 extern char curr_dir[];
56babefa 103+extern unsigned int curr_dir_len;
45795ec6 104+extern unsigned int module_dirlen;
a55d21aa 105
d8af8661 106 struct exclude_list_struct exclude_list = { 0, 0, "" };
524989ae 107-struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " };
d8af8661 108 struct exclude_list_struct server_exclude_list = { 0, 0, "server " };
40e20a69
WD
109-char *exclude_path_prefix = NULL;
110+
eabda998 111+struct mergelist_save_struct {
d1e7c1c8 112+ struct exclude_list_struct *array;
d8af8661
WD
113+ int count;
114+};
524989ae 115+
db4f43dd
WD
116+/* The dirbuf is set by push_local_excludes() to the current subdirectory
117+ * relative to curr_dir that is being processed. The path always has a
45795ec6
WD
118+ * trailing slash appended, and the variable dirbuf_len contains the length
119+ * of this path prefix. The path is always absolute. */
120+static char dirbuf[MAXPATHLEN+1];
121+static unsigned int dirbuf_len = 0;
b338da5b 122+static int dirbuf_depth;
45795ec6
WD
123+
124+/* This is True when we're scanning parent dirs for per-dir merge-files. */
125+static BOOL parent_dirscan = False;
db4f43dd
WD
126+
127+/* This array contains a list of all the currently active per-dir merge
128+ * files. This makes it easier to save the appropriate values when we
129+ * "push" down into each subdirectory. */
d34d9fad
WD
130+static struct exclude_struct **mergelist_parents;
131+static int mergelist_cnt = 0;
132+static int mergelist_size = 0;
a55d21aa 133+
d1e7c1c8
WD
134+/* Each exclude_list_struct describes a singly-linked list by keeping track
135+ * of both the head and tail pointers. The list is slightly unusual in that
136+ * a parent-dir's content can be appended to the end of the local list in a
137+ * special way: the last item in the local list has its "next" pointer set
0c7d1fd8 138+ * to point to the inherited list, but the local list's tail pointer points
d1e7c1c8 139+ * at the end of the local list. Thus, if the local list is empty, the head
0c7d1fd8 140+ * will be pointing at the inherited content but the tail will be NULL. To
d1e7c1c8
WD
141+ * help you visualize this, here are the possible list arrangements:
142+ *
143+ * Completely Empty Local Content Only
144+ * ================================== ====================================
145+ * head -> NULL head -> Local1 -> Local2 -> NULL
146+ * tail -> NULL tail -------------^
147+ *
148+ * Inherited Content Only Both Local and Inherited Content
149+ * ================================== ====================================
150+ * head -> Parent1 -> Parent2 -> NULL head -> L1 -> L2 -> P1 -> P2 -> NULL
151+ * tail -> NULL tail ---------^
152+ *
2e064775 153+ * This means that anyone wanting to traverse the whole list to use it just
d1e7c1c8
WD
154+ * needs to start at the head and use the "next" pointers until it goes
155+ * NULL. To add new local content, we insert the item after the tail item
156+ * and update the tail (obviously, if "tail" was NULL, we insert it at the
157+ * head). To clear the local list, WE MUST NOT FREE THE INHERITED CONTENT
bc95f62b
WD
158+ * because it is shared between the current list and our parent list(s).
159+ * The easiest way to handle this is to simply truncate the list after the
160+ * tail item and then free the local list from the head. When inheriting
161+ * the list for a new local dir, we just save off the exclude_list_struct
0c7d1fd8 162+ * values (so we can pop back to them later) and set the tail to NULL.
d1e7c1c8 163+ */
40e20a69 164
0c7d1fd8
WD
165 /** Build an exclude structure given an exclude pattern. */
166 static void make_exclude(struct exclude_list_struct *listp, const char *pat,
b338da5b 167@@ -46,23 +102,50 @@ static void make_exclude(struct exclude_
a55d21aa 168 const char *cp;
0c7d1fd8
WD
169 unsigned int ex_len;
170
d34d9fad
WD
171+ if (verbose > 2) {
172+ rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s%sclude)\n",
173+ who_am_i(), (int)pat_len, pat, listp->debug_type,
174+ mflags & MATCHFLG_MERGE_FILE ? "FILE " : "",
175+ mflags & MATCHFLG_INCLUDE ? "in" : "ex");
176+ }
177+
524989ae 178+ if (mflags & MATCHFLG_MERGE_FILE) {
eabda998 179+ int i;
2e064775 180+ /* If the local merge file was already mentioned, don't
524989ae 181+ * add it again. */
eabda998
WD
182+ for (i = 0; i < mergelist_cnt; i++) {
183+ struct exclude_struct *ex = mergelist_parents[i];
184+ if (strlen(ex->pattern) == pat_len
d8af8661 185+ && memcmp(ex->pattern, pat, pat_len) == 0)
a55d21aa
WD
186+ return;
187+ }
524989ae
WD
188+ if ((pat_len == 10 || (pat_len > 10 && pat[pat_len-11] == '/'))
189+ && strncmp(pat+pat_len-10, ".cvsignore", 10) == 0) {
a55d21aa 190+ mflags |= MATCHFLG_CVSIGNORE;
40e20a69 191+ mflags &= ~MATCHFLG_INCLUDE;
a55d21aa
WD
192+ } else
193+ mflags &= ~MATCHFLG_CVSIGNORE;
194+ }
0c7d1fd8 195+
a55d21aa
WD
196 ret = new(struct exclude_struct);
197 if (!ret)
198 out_of_memory("make_exclude");
40e20a69
WD
199
200 memset(ret, 0, sizeof ret[0]);
201
202- if (exclude_path_prefix)
203- mflags |= MATCHFLG_ABS_PATH;
204- if (exclude_path_prefix && *pat == '/')
205- ex_len = strlen(exclude_path_prefix);
206- else
207+ if (mflags & MATCHFLG_ABS_PATH) {
208+ if (*pat != '/') {
209+ mflags &= ~MATCHFLG_ABS_PATH;
210+ ex_len = 0;
45795ec6
WD
211+ } else
212+ ex_len = dirbuf_len - module_dirlen - 1;
40e20a69
WD
213+ } else
214 ex_len = 0;
215 ret->pattern = new_array(char, ex_len + pat_len + 1);
216 if (!ret->pattern)
217 out_of_memory("make_exclude");
45795ec6 218 if (ex_len)
40e20a69 219- memcpy(ret->pattern, exclude_path_prefix, ex_len);
5f98a4b1 220+ memcpy(ret->pattern, dirbuf + module_dirlen, ex_len);
40e20a69
WD
221 strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
222 pat_len += ex_len;
223
b338da5b 224@@ -81,14 +164,40 @@ static void make_exclude(struct exclude_
7b22909b 225 mflags |= MATCHFLG_DIRECTORY;
a55d21aa
WD
226 }
227
7b22909b 228- for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
bc95f62b 229- ret->slash_cnt++;
524989ae 230+ if (mflags & MATCHFLG_MERGE_FILE) {
d8af8661
WD
231+ struct exclude_list_struct *lp
232+ = new_array(struct exclude_list_struct, 1);
233+ if (!lp)
a55d21aa 234+ out_of_memory("make_exclude");
7cb7ae4e 235+ lp->head = lp->tail = NULL;
d34d9fad
WD
236+ if ((cp = strrchr(ret->pattern, '/')) != NULL)
237+ cp++;
238+ else
239+ cp = ret->pattern;
240+ if (asprintf(&lp->debug_type, "per-dir %s ", cp) < 0)
a55d21aa 241+ out_of_memory("make_exclude");
eabda998
WD
242+ ret->u.mergelist = lp;
243+ if (mergelist_cnt == mergelist_size) {
d34d9fad
WD
244+ mergelist_size += 5;
245+ mergelist_parents = realloc_array(mergelist_parents,
246+ struct exclude_struct *,
247+ mergelist_size);
248+ if (!mergelist_parents)
249+ out_of_memory("make_exclude");
eabda998
WD
250+ }
251+ mergelist_parents[mergelist_cnt++] = ret;
7b22909b
WD
252+ } else {
253+ for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
254+ ret->u.slash_cnt++;
abe86b1f 255+ }
7b22909b 256
0c7d1fd8 257 ret->match_flags = mflags;
a55d21aa 258
7b22909b
WD
259- if (!listp->tail)
260+ if (!listp->tail) {
261+ ret->next = listp->head;
262 listp->head = listp->tail = ret;
263- else {
264+ } else {
265+ ret->next = listp->tail->next;
266 listp->tail->next = ret;
267 listp->tail = ret;
268 }
b338da5b 269@@ -96,22 +205,267 @@ static void make_exclude(struct exclude_
d8af8661
WD
270
271 static void free_exclude(struct exclude_struct *ex)
272 {
273+ if (ex->match_flags & MATCHFLG_MERGE_FILE) {
eabda998
WD
274+ free(ex->u.mergelist->debug_type);
275+ free(ex->u.mergelist);
d8af8661
WD
276+ }
277 free(ex->pattern);
a55d21aa
WD
278 free(ex);
279 }
280
d8af8661
WD
281-void clear_exclude_list(struct exclude_list_struct *listp)
282+static void clear_exclude_list(struct exclude_list_struct *listp)
a55d21aa 283 {
7cb7ae4e
WD
284- struct exclude_struct *ent, *next;
285-
286- for (ent = listp->head; ent; ent = next) {
287- next = ent->next;
288- free_exclude(ent);
289+ if (listp->tail) {
290+ struct exclude_struct *ent, *next;
bc95f62b 291+ /* Truncate any inherited items from the local list. */
7cb7ae4e 292+ listp->tail->next = NULL;
dc5cce3c 293+ /* Now free everything that is left. */
7cb7ae4e
WD
294+ for (ent = listp->head; ent; ent = next) {
295+ next = ent->next;
296+ free_exclude(ent);
297+ }
524989ae
WD
298 }
299
7cb7ae4e
WD
300 listp->head = listp->tail = NULL;
301 }
a55d21aa 302
db4f43dd 303+/* This returns an expanded (absolute) filename for the merge-file name if
45795ec6 304+ * the name has any slashes in it OR if the parent_dirscan var is True;
db4f43dd 305+ * otherwise it returns the original merge_file name. If the len_ptr value
45795ec6
WD
306+ * is non-NULL the merge_file name is limited by the referenced length
307+ * value and will be updated with the length of the resulting name. We
308+ * always return a name that is null terminated, even if the merge_file
309+ * name was not. */
310+static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
311+ unsigned int prefix_skip)
41ebea83
WD
312+{
313+ static char buf[MAXPATHLEN];
314+ char *fn, tmpbuf[MAXPATHLEN];
45795ec6 315+ unsigned int fn_len;
41ebea83 316+
40e20a69 317+ if (!parent_dirscan && *merge_file != '/') {
db4f43dd 318+ /* Return the name unchanged it doesn't have any slashes. */
41ebea83 319+ if (len_ptr) {
db4f43dd
WD
320+ const char *p = merge_file + *len_ptr;
321+ while (--p > merge_file && *p != '/') {}
322+ if (p == merge_file) {
323+ strlcpy(buf, merge_file, *len_ptr + 1);
324+ return buf;
325+ }
326+ } else if (strchr(merge_file, '/') == NULL)
41ebea83
WD
327+ return (char *)merge_file;
328+ }
329+
330+ fn = *merge_file == '/' ? buf : tmpbuf;
331+ if (sanitize_paths) {
45795ec6 332+ const char *r = prefix_skip ? "/" : NULL;
41ebea83
WD
333+ /* null-terminate the name if it isn't already */
334+ if (len_ptr && merge_file[*len_ptr]) {
335+ char *to = fn == buf ? tmpbuf : buf;
336+ strlcpy(to, merge_file, *len_ptr + 1);
337+ merge_file = to;
338+ }
b338da5b 339+ if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
45795ec6 340+ rprintf(FERROR, "merge-file name overflows: %s\n",
41ebea83
WD
341+ merge_file);
342+ return NULL;
343+ }
344+ } else {
345+ strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN);
20f8d513 346+ clean_fname(fn, 1);
41ebea83
WD
347+ }
348+
41ebea83 349+ fn_len = strlen(fn);
45795ec6
WD
350+ if (fn == buf)
351+ goto done;
352+
353+ if (dirbuf_len + fn_len >= MAXPATHLEN) {
354+ rprintf(FERROR, "merge-file name overflows: %s\n", fn);
41ebea83
WD
355+ return NULL;
356+ }
45795ec6
WD
357+ memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
358+ memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1);
20f8d513 359+ fn_len = clean_fname(buf, 1);
45795ec6
WD
360+
361+ done:
41ebea83
WD
362+ if (len_ptr)
363+ *len_ptr = fn_len;
41ebea83
WD
364+ return buf;
365+}
366+
45795ec6
WD
367+/* Sets the dirbuf and dirbuf_len values. */
368+void set_excludes_dir(const char *dir, unsigned int dirlen)
40e20a69 369+{
45795ec6
WD
370+ unsigned int len;
371+ if (*dir != '/') {
372+ memcpy(dirbuf, curr_dir, curr_dir_len);
373+ dirbuf[curr_dir_len] = '/';
374+ len = curr_dir_len + 1;
470aa8d5
WD
375+ if (len + dirlen >= MAXPATHLEN)
376+ dirlen = 0;
45795ec6
WD
377+ } else
378+ len = 0;
379+ memcpy(dirbuf + len, dir, dirlen);
380+ dirbuf[dirlen + len] = '\0';
20f8d513 381+ dirbuf_len = clean_fname(dirbuf, 1);
45795ec6
WD
382+ if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.'
383+ && dirbuf[dirbuf_len-2] == '/')
384+ dirbuf_len -= 2;
385+ dirbuf[dirbuf_len++] = '/';
386+ dirbuf[dirbuf_len] = '\0';
b338da5b
WD
387+ if (sanitize_paths)
388+ dirbuf_depth = count_dir_elements(dirbuf + module_dirlen);
40e20a69
WD
389+}
390+
45795ec6 391+/* This routine takes a per-dir merge-file entry and finishes its setup.
db4f43dd
WD
392+ * If the name has a path portion then we check to see if it refers to a
393+ * parent directory of the first transfer dir. If it does, we scan all the
394+ * dirs from that point through the parent dir of the transfer dir looking
45795ec6
WD
395+ * for the per-dir merge-file in each one. */
396+static BOOL setup_merge_file(struct exclude_struct *ex,
397+ struct exclude_list_struct *lp, int flags)
1e476835 398+{
d34d9fad 399+ char buf[MAXPATHLEN];
db4f43dd
WD
400+ char *x, *y, *pat = ex->pattern;
401+ unsigned int len;
56babefa 402+
45795ec6
WD
403+ if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/')
404+ return 0;
1e476835 405+
db4f43dd
WD
406+ y = strrchr(x, '/');
407+ *y = '\0';
408+ ex->pattern = strdup(y+1);
db4f43dd
WD
409+ if (!*x)
410+ x = "/";
411+ if (*x == '/')
412+ strlcpy(buf, x, MAXPATHLEN);
d34d9fad 413+ else
db4f43dd 414+ pathjoin(buf, MAXPATHLEN, dirbuf, x);
d34d9fad 415+
20f8d513 416+ len = clean_fname(buf, 1);
db4f43dd
WD
417+ if (len != 1 && len < MAXPATHLEN-1) {
418+ buf[len++] = '/';
419+ buf[len] = '\0';
420+ }
db4f43dd 421+ /* This ensures that the specified dir is a parent of the transfer. */
45795ec6 422+ for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {}
d34d9fad 423+ if (*x)
db4f43dd 424+ y += strlen(y); /* nope -- skip the scan */
d34d9fad 425+
45795ec6 426+ parent_dirscan = True;
d34d9fad
WD
427+ while (*y) {
428+ char save[MAXPATHLEN];
41ebea83 429+ strlcpy(save, y, MAXPATHLEN);
db4f43dd 430+ *y = '\0';
45795ec6 431+ dirbuf_len = y - dirbuf;
db4f43dd 432+ strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
40e20a69
WD
433+ add_exclude_file(lp, buf, flags | XFLG_ABS_PATH);
434+ if (ex->match_flags & MATCHFLG_CVSIGNORE)
435+ lp->head = NULL; /* CVS doesn't inherit rules. */
d34d9fad 436+ lp->tail = NULL;
41ebea83 437+ strlcpy(y, save, MAXPATHLEN);
d34d9fad 438+ while ((*x++ = *y++) != '/') {}
1e476835 439+ }
45795ec6 440+ parent_dirscan = False;
db4f43dd 441+ free(pat);
45795ec6 442+ return 1;
1e476835
WD
443+}
444+
db4f43dd 445+/* Each time rsync changes to a new directory it call this function to
45795ec6
WD
446+ * handle all the per-dir merge-files. The "dir" value is the current path
447+ * relative to curr_dir (which might not be null-terminated). We copy it
448+ * into dirbuf so that we can easily append a file name on the end. */
40e20a69 449+void *push_local_excludes(const char *dir, unsigned int dirlen)
a55d21aa 450+{
eabda998
WD
451+ struct mergelist_save_struct *push;
452+ struct exclude_list_struct *ap;
453+ int i;
454+
45795ec6 455+ set_excludes_dir(dir, dirlen);
eabda998
WD
456+
457+ if (!(push = new_array(struct mergelist_save_struct, 1)))
458+ out_of_memory("push_local_excludes");
459+
460+ push->count = mergelist_cnt;
461+ push->array = new_array(struct exclude_list_struct, mergelist_cnt);
462+ if (!push->array)
463+ out_of_memory("push_local_excludes");
524989ae 464+
eabda998
WD
465+ for (i = 0, ap = push->array; i < mergelist_cnt; i++) {
466+ memcpy(ap++, mergelist_parents[i]->u.mergelist,
467+ sizeof (struct exclude_list_struct));
468+ }
469+
470+ /* Note: add_exclude_file() might increase mergelist_cnt, so keep
471+ * this loop separate from the above loop. */
472+ for (i = 0; i < mergelist_cnt; i++) {
473+ struct exclude_struct *ex = mergelist_parents[i];
474+ struct exclude_list_struct *lp = ex->u.mergelist;
a55d21aa 475+ int flags;
524989ae
WD
476+
477+ if (verbose > 2) {
478+ rprintf(FINFO, "[%s] pushing %sexclude list\n",
d8af8661 479+ who_am_i(), lp->debug_type);
524989ae 480+ }
d8af8661 481+
40e20a69
WD
482+ if (ex->match_flags & MATCHFLG_CVSIGNORE) {
483+ lp->head = NULL; /* CVS doesn't inherit rules. */
ee1af13c 484+ flags = XFLG_WORD_SPLIT | XFLG_WORDS_ONLY;
40e20a69 485+ } else {
eabda998 486+ flags = ex->match_flags & MATCHFLG_INCLUDE
524989ae 487+ ? XFLG_DEF_INCLUDE : 0;
a55d21aa 488+ }
40e20a69 489+ lp->tail = NULL; /* Switch any local rules to inherited. */
d34d9fad 490+
40e20a69
WD
491+ if (ex->match_flags & MATCHFLG_FINISH_SETUP) {
492+ ex->match_flags &= ~MATCHFLG_FINISH_SETUP;
45795ec6
WD
493+ if (setup_merge_file(ex, lp, flags))
494+ set_excludes_dir(dir, dirlen);
d34d9fad
WD
495+ }
496+
45795ec6
WD
497+ if (strlcpy(dirbuf + dirbuf_len, ex->pattern,
498+ MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len)
40e20a69 499+ add_exclude_file(lp, dirbuf, flags | XFLG_ABS_PATH);
524989ae 500+ else {
a55d21aa
WD
501+ io_error |= IOERR_GENERAL;
502+ rprintf(FINFO,
503+ "cannot add local excludes in long-named directory %s\n",
d8af8661 504+ full_fname(dirbuf));
a55d21aa 505+ }
45795ec6 506+ dirbuf[dirbuf_len] = '\0';
a55d21aa
WD
507+ }
508+
524989ae 509+ return (void*)push;
a55d21aa
WD
510+}
511+
eabda998 512+void pop_local_excludes(void *mem)
a55d21aa 513+{
eabda998
WD
514+ struct mergelist_save_struct *pop = (struct mergelist_save_struct*)mem;
515+ struct exclude_list_struct *ap;
516+ int i;
d8af8661 517+
066e3b3e 518+ for (i = mergelist_cnt; i-- > 0; ) {
eabda998
WD
519+ struct exclude_struct *ex = mergelist_parents[i];
520+ struct exclude_list_struct *lp = ex->u.mergelist;
524989ae 521+
524989ae
WD
522+ if (verbose > 2) {
523+ rprintf(FINFO, "[%s] popping %sexclude list\n",
d8af8661 524+ who_am_i(), lp->debug_type);
524989ae 525+ }
d8af8661
WD
526+
527+ clear_exclude_list(lp);
a55d21aa 528+ }
d8af8661 529+
40e20a69 530+ mergelist_cnt = pop->count;
eabda998
WD
531+ for (i = 0, ap = pop->array; i < mergelist_cnt; i++) {
532+ memcpy(mergelist_parents[i]->u.mergelist, ap++,
533+ sizeof (struct exclude_list_struct));
534+ }
d8af8661
WD
535+
536+ free(pop->array);
537+ free(pop);
7cb7ae4e
WD
538+}
539+
a55d21aa 540 static int check_one_exclude(char *name, struct exclude_struct *ex,
7cb7ae4e
WD
541 int name_is_dir)
542 {
b338da5b 543@@ -125,13 +479,14 @@ static int check_one_exclude(char *name,
bc95f62b
WD
544 /* If the pattern does not have any slashes AND it does not have
545 * a "**" (which could match a slash), then we just match the
546 * name portion of the path. */
547- if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
548+ if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
549 if ((p = strrchr(name,'/')) != NULL)
550 name = p+1;
551 }
3d3aaf9f
WD
552 else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
553- && curr_dir[1]) {
554- pathjoin(full_name, sizeof full_name, curr_dir + 1, name);
555+ && curr_dir_len > module_dirlen + 1) {
556+ pathjoin(full_name, sizeof full_name,
557+ curr_dir + module_dirlen + 1, name);
045caa90
WD
558 name = full_name;
559 }
560
b338da5b 561@@ -148,9 +503,9 @@ static int check_one_exclude(char *name,
bc95f62b
WD
562 if (ex->match_flags & MATCHFLG_WILD) {
563 /* A non-anchored match with an infix slash and no "**"
564 * needs to match the last slash_cnt+1 name elements. */
0c7d1fd8
WD
565- if (!match_start && ex->slash_cnt
566+ if (!match_start && ex->u.slash_cnt
567 && !(ex->match_flags & MATCHFLG_WILD2)) {
bc95f62b
WD
568- int cnt = ex->slash_cnt + 1;
569+ int cnt = ex->u.slash_cnt + 1;
570 for (p = name + strlen(name) - 1; p >= name; p--) {
571 if (*p == '/' && !--cnt)
572 break;
b338da5b 573@@ -221,6 +576,13 @@ int check_exclude(struct exclude_list_st
a55d21aa
WD
574 struct exclude_struct *ent;
575
576 for (ent = listp->head; ent; ent = ent->next) {
524989ae 577+ if (ent->match_flags & MATCHFLG_MERGE_FILE) {
eabda998 578+ int rc = check_exclude(ent->u.mergelist, name,
d8af8661 579+ name_is_dir);
a55d21aa
WD
580+ if (rc)
581+ return rc;
582+ continue;
583+ }
584 if (check_one_exclude(name, ent, name_is_dir)) {
585 report_exclude_result(name, ent, name_is_dir,
586 listp->debug_type);
2e064775 587@@ -254,12 +616,28 @@ static const char *get_exclude_tok(const
a55d21aa
WD
588 p = (const char *)s;
589 }
590
591- /* Is this a '+' or '-' followed by a space (not whitespace)? */
2e064775 592- if (!(xflags & XFLG_WORDS_ONLY)
a55d21aa 593- && (*s == '-' || *s == '+') && s[1] == ' ') {
2e064775
WD
594+ /* Check for a leading '+' or '-'. */
595+ if (!(xflags & XFLG_WORDS_ONLY) && (*s == '-' || *s == '+')) {
0c7d1fd8
WD
596 if (*s == '+')
597 mflags |= MATCHFLG_INCLUDE;
2e064775
WD
598- s += 2;
599+ while (*++s != ' ') {
600+ switch (*s) {
601+ case 'p':
602+ mflags |= MATCHFLG_MERGE_FILE
603+ | MATCHFLG_PERDIR_MERGE
604+ | MATCHFLG_FINISH_SETUP;
605+ break;
606+ case 'm':
607+ mflags |= MATCHFLG_MERGE_FILE;
608+ break;
609+ default:
610+ rprintf(FERROR,
611+ "invalid include/exclude option after %c: %c\n",
612+ *p, *s);
613+ exit_cleanup(RERR_SYNTAX);
d34d9fad 614+ }
a55d21aa 615+ }
2e064775 616+ s++;
0c7d1fd8
WD
617 } else if (xflags & XFLG_DEF_INCLUDE)
618 mflags |= MATCHFLG_INCLUDE;
2e064775
WD
619 if (xflags & XFLG_DIRECTORY)
620@@ -276,6 +654,8 @@ static const char *get_exclude_tok(const
40e20a69 621
5388f859 622 if (*p == '!' && len == 1)
40e20a69
WD
623 mflags |= MATCHFLG_CLEAR_LIST;
624+ if (xflags & XFLG_ABS_PATH)
625+ mflags |= MATCHFLG_ABS_PATH;
626
627 *len_ptr = len;
628 *flag_ptr = mflags;
2e064775 629@@ -287,7 +667,7 @@ void add_exclude(struct exclude_list_str
45795ec6
WD
630 int xflags)
631 {
632 unsigned int pat_len, mflags;
633- const char *cp;
634+ const char *cp, *p;
635
636 if (!pattern)
637 return;
2e064775 638@@ -295,9 +675,15 @@ void add_exclude(struct exclude_list_str
045caa90
WD
639 cp = pattern;
640 pat_len = 0;
641 while (1) {
642+ /* Remember that the returned string is NOT '\0' terminated! */
643 cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags);
644 if (!pat_len)
645 break;
41ebea83
WD
646+ if (pat_len >= MAXPATHLEN) {
647+ rprintf(FERROR, "discarding over-long exclude: %s\n",
648+ cp);
649+ continue;
650+ }
651
652 if (mflags & MATCHFLG_CLEAR_LIST) {
653 if (verbose > 2) {
2e064775 654@@ -309,13 +695,24 @@ void add_exclude(struct exclude_list_str
0c7d1fd8
WD
655 continue;
656 }
a55d21aa 657
d34d9fad
WD
658- make_exclude(listp, cp, pat_len, mflags);
659-
660- if (verbose > 2) {
661- rprintf(FINFO, "[%s] add_exclude(%.*s, %s%sclude)\n",
662- who_am_i(), (int)pat_len, cp, listp->debug_type,
663- mflags & MATCHFLG_INCLUDE ? "in" : "ex");
524989ae 664+ if (mflags & MATCHFLG_MERGE_FILE) {
45795ec6 665+ unsigned int len = pat_len;
41ebea83 666+ if (mflags & MATCHFLG_PERDIR_MERGE) {
40e20a69 667+ if (parent_dirscan) {
45795ec6 668+ if (!(p = parse_merge_name(cp, &len, module_dirlen)))
41ebea83 669+ continue;
45795ec6 670+ make_exclude(listp, p, len, mflags);
d34d9fad
WD
671+ continue;
672+ }
41ebea83 673+ } else {
45795ec6 674+ if (!(p = parse_merge_name(cp, &len, 0)))
d34d9fad 675+ continue;
45795ec6 676+ add_exclude_file(listp, p, xflags | XFLG_FATAL_ERRORS);
41ebea83 677+ continue;
0c7d1fd8 678+ }
a55d21aa 679 }
d34d9fad
WD
680+
681+ make_exclude(listp, cp, pat_len, mflags);
0c7d1fd8 682 }
d34d9fad
WD
683 }
684
2e064775 685@@ -324,7 +721,7 @@ void add_exclude_file(struct exclude_lis
41ebea83
WD
686 int xflags)
687 {
688 FILE *fp;
689- char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
2e064775 690+ char line[MAXPATHLEN+4]; /* Room for prefix chars and trailing slash. */
41ebea83
WD
691 char *eob = line + sizeof line - 1;
692 int word_split = xflags & XFLG_WORD_SPLIT;
693
2e064775 694@@ -345,6 +742,12 @@ void add_exclude_file(struct exclude_lis
45795ec6 695 }
c4e46f36
WD
696 return;
697 }
45795ec6
WD
698+ dirbuf[dirbuf_len] = '\0';
699+
c4e46f36 700+ if (verbose > 2) {
1e476835
WD
701+ rprintf(FINFO, "[%s] add_exclude_file(%s,%d)\n",
702+ who_am_i(), fname, xflags);
c4e46f36 703+ }
45795ec6 704
c4e46f36
WD
705 while (1) {
706 char *s = line;
2e064775
WD
707@@ -402,7 +805,20 @@ void send_exclude_list(int f)
708 p[l] = '\0';
709 }
710
711- if (ent->match_flags & MATCHFLG_INCLUDE) {
712+ if (ent->match_flags & MATCHFLG_MERGE_FILE) {
41ebea83 713+ char buf[32], *op = buf;
2e064775
WD
714+ if (ent->match_flags & MATCHFLG_INCLUDE)
715+ *op++ = '+';
716+ else
41ebea83 717+ *op++ = '-';
2e064775 718+ if (ent->match_flags & MATCHFLG_PERDIR_MERGE)
41ebea83 719+ *op++ = 'p';
2e064775
WD
720+ else
721+ *op++ = 'm';
722+ *op++ = ' ';
41ebea83
WD
723+ write_int(f, l + (op - buf));
724+ write_buf(f, buf, op - buf);
2e064775 725+ } else if (ent->match_flags & MATCHFLG_INCLUDE) {
a55d21aa 726 write_int(f, l + 2);
2e064775
WD
727 write_buf(f, "+ ", 2);
728 } else if (*p == '-' || *p == '+') {
729@@ -419,7 +835,7 @@ void send_exclude_list(int f)
730
731 void recv_exclude_list(int f)
732 {
733- char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
734+ char line[MAXPATHLEN+4]; /* Room for prefix and trailing slash. */
735 unsigned int l;
736
737 while ((l = read_int(f)) != 0) {
738@@ -446,6 +862,7 @@ void add_cvs_excludes(void)
a55d21aa
WD
739 char fname[MAXPATHLEN];
740 char *p;
741
2e064775 742+ add_exclude(&exclude_list, "-p .cvsignore", 0);
a55d21aa 743 add_exclude(&exclude_list, default_cvsignore,
ee1af13c 744 XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
a55d21aa 745
37da98ae 746--- orig/flist.c 2005-01-01 21:11:00
20f8d513 747+++ flist.c 2004-08-12 18:59:28
a6587818 748@@ -40,10 +40,9 @@ extern int module_id;
a55d21aa
WD
749 extern int ignore_errors;
750 extern int numeric_ids;
751
752-extern int cvs_exclude;
753-
754 extern int recurse;
755 extern char curr_dir[MAXPATHLEN];
d34d9fad 756+extern unsigned int curr_dir_len;
a55d21aa 757 extern char *files_from;
d34d9fad
WD
758 extern int filesfrom_fd;
759
a6587818 760@@ -67,7 +66,6 @@ extern int list_only;
a55d21aa
WD
761
762 extern struct exclude_list_struct exclude_list;
763 extern struct exclude_list_struct server_exclude_list;
764-extern struct exclude_list_struct local_exclude_list;
765
766 int io_error;
767
a6587818 768@@ -223,8 +221,6 @@ int link_stat(const char *path, STRUCT_S
a55d21aa
WD
769 */
770 static int check_exclude_file(char *fname, int is_dir, int exclude_level)
771 {
772- int rc;
773-
774 #if 0 /* This currently never happens, so avoid a useless compare. */
775 if (exclude_level == NO_EXCLUDES)
776 return 0;
a6587818 777@@ -246,10 +242,7 @@ static int check_exclude_file(char *fnam
a55d21aa
WD
778 if (exclude_level != ALL_EXCLUDES)
779 return 0;
780 if (exclude_list.head
781- && (rc = check_exclude(&exclude_list, fname, is_dir)) != 0)
782- return rc < 0;
783- if (local_exclude_list.head
784- && check_exclude(&local_exclude_list, fname, is_dir) < 0)
785+ && check_exclude(&exclude_list, fname, is_dir) < 0)
786 return 1;
787 return 0;
788 }
37da98ae 789@@ -983,15 +976,7 @@ void send_file_name(int f, struct file_l
a55d21aa
WD
790
791 if (recursive && S_ISDIR(file->mode)
792 && !(file->flags & FLAG_MOUNT_POINT)) {
793- struct exclude_list_struct last_list = local_exclude_list;
794- local_exclude_list.head = local_exclude_list.tail = NULL;
795 send_directory(f, flist, f_name_to(file, fbuf));
7cb7ae4e
WD
796- if (verbose > 2) {
797- rprintf(FINFO, "[%s] popping %sexclude list\n",
798- who_am_i(), local_exclude_list.debug_type);
799- }
d8af8661 800- clear_exclude_list(&local_exclude_list);
a55d21aa
WD
801- local_exclude_list = last_list;
802 }
803 }
804
37da98ae 805@@ -1002,6 +987,7 @@ static void send_directory(int f, struct
a55d21aa
WD
806 struct dirent *di;
807 char fname[MAXPATHLEN];
808 unsigned int offset;
809+ void *save_excludes;
810 char *p;
811
812 d = opendir(dir);
37da98ae 813@@ -1025,18 +1011,7 @@ static void send_directory(int f, struct
a55d21aa
WD
814 offset++;
815 }
816
817- if (cvs_exclude) {
818- if (strlcpy(p, ".cvsignore", MAXPATHLEN - offset)
819- < MAXPATHLEN - offset) {
820- add_exclude_file(&local_exclude_list, fname,
ee1af13c 821- XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
a55d21aa
WD
822- } else {
823- io_error |= IOERR_GENERAL;
824- rprintf(FINFO,
825- "cannot cvs-exclude in long-named directory %s\n",
826- full_fname(fname));
827- }
045caa90 828- }
045caa90
WD
829+ save_excludes = push_local_excludes(fname, offset);
830
a55d21aa
WD
831 for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
832 char *dname = d_name(di);
37da98ae 833@@ -1057,6 +1032,8 @@ static void send_directory(int f, struct
bc95f62b 834 rsyserr(FERROR, errno, "readdir(%s)", dir);
a55d21aa 835 }
a55d21aa 836
eabda998
WD
837+ pop_local_excludes(save_excludes);
838+
a55d21aa
WD
839 closedir(d);
840 }
eabda998 841
37da98ae 842@@ -1076,6 +1053,7 @@ struct file_list *send_file_list(int f,
d34d9fad
WD
843 char *p, *dir, olddir[sizeof curr_dir];
844 char lastpath[MAXPATHLEN] = "";
845 struct file_list *flist;
45795ec6 846+ BOOL need_first_push = True;
d34d9fad
WD
847 int64 start_write;
848 int use_ff_fd = 0;
849
37da98ae 850@@ -1096,6 +1074,10 @@ struct file_list *send_file_list(int f,
d34d9fad
WD
851 exit_cleanup(RERR_FILESELECT);
852 }
853 use_ff_fd = 1;
854+ if (curr_dir_len < MAXPATHLEN - 1) {
40e20a69 855+ push_local_excludes(curr_dir, curr_dir_len);
45795ec6 856+ need_first_push = False;
1e476835 857+ }
d34d9fad
WD
858 }
859 }
860
37da98ae 861@@ -1126,6 +1108,15 @@ struct file_list *send_file_list(int f,
d34d9fad
WD
862 }
863 }
864
45795ec6 865+ if (need_first_push) {
d34d9fad 866+ if ((p = strrchr(fname, '/')) != NULL) {
45795ec6
WD
867+ if (*++p && strcmp(p, ".") != 0)
868+ push_local_excludes(fname, p - fname);
869+ } else if (strcmp(fname, ".") != 0)
870+ push_local_excludes(fname, 0);
871+ need_first_push = False;
d34d9fad 872+ }
1e476835 873+
d34d9fad
WD
874 if (link_stat(fname, &st, keep_dirlinks) != 0) {
875 if (f != -1) {
876 io_error |= IOERR_GENERAL;
2e064775
WD
877--- orig/options.c 2005-01-15 04:40:15
878+++ options.c 2005-01-13 23:52:00
4c1f2ca5 879@@ -296,6 +296,7 @@ void usage(enum logcode F)
40e20a69
WD
880 rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n");
881 rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
882 rprintf(F," --files-from=FILE read FILE for list of source-file names\n");
2e064775 883+ rprintf(F," -E same as --exclude='-p /.rsync-excludes'\n");
40e20a69
WD
884 rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
885 rprintf(F," --version print version number\n");
37da98ae
WD
886 rprintf(F," --port=PORT specify double-colon alternate port number\n");
887@@ -393,6 +394,7 @@ static struct poptOption long_options[]
d34d9fad
WD
888 {"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
889 {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
890 {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
5388f859
WD
891+ {0, 'E', POPT_ARG_NONE, 0, 'E', 0, 0 },
892 {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
37da98ae 893 {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
5388f859 894 {"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 },
37da98ae 895@@ -668,6 +670,11 @@ int parse_arguments(int *argc, const cha
d34d9fad
WD
896 am_sender = 1;
897 break;
898
899+ case 'E':
900+ add_exclude(&exclude_list,
2e064775 901+ "-p /.rsync-excludes", 0);
d34d9fad 902+ break;
1e476835 903+
d34d9fad
WD
904 case 'P':
905 do_progress = 1;
906 keep_partial = 1;
2e064775 907--- orig/rsync.h 2005-01-10 00:21:12
a60267ab 908+++ rsync.h 2004-09-22 08:48:53
4c1f2ca5 909@@ -111,6 +111,7 @@
40e20a69
WD
910 #define XFLG_WORDS_ONLY (1<<2)
911 #define XFLG_WORD_SPLIT (1<<3)
a60267ab
WD
912 #define XFLG_DIRECTORY (1<<4)
913+#define XFLG_ABS_PATH (1<<5)
40e20a69
WD
914
915 #define PERMS_REPORT (1<<0)
916 #define PERMS_SKIP_MTIME (1<<1)
4c1f2ca5 917@@ -510,11 +511,18 @@ struct map_struct {
0c7d1fd8
WD
918 #define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
919 #define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */
920 #define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */
524989ae 921+#define MATCHFLG_MERGE_FILE (1<<7) /* specifies a file to merge */
a55d21aa 922+#define MATCHFLG_CVSIGNORE (1<<8) /* parse this as a .cvsignore file */
40e20a69
WD
923+#define MATCHFLG_PERDIR_MERGE (1<<9) /* merge-file is searched per-dir */
924+#define MATCHFLG_FINISH_SETUP (1<<10)/* per-dir merge file needs setup */
a55d21aa
WD
925 struct exclude_struct {
926 struct exclude_struct *next;
927 char *pattern;
0c7d1fd8 928 unsigned int match_flags;
bc95f62b 929- int slash_cnt;
bc95f62b
WD
930+ union {
931+ int slash_cnt;
eabda998 932+ struct exclude_list_struct *mergelist;
bc95f62b 933+ } u;
a55d21aa
WD
934 };
935
936 struct exclude_list_struct {
2e064775
WD
937--- orig/rsync.yo 2005-01-15 04:36:32
938+++ rsync.yo 2005-01-14 00:10:38
4c1f2ca5 939@@ -366,6 +366,7 @@ verb(
1e476835
WD
940 --include=PATTERN don't exclude files matching PATTERN
941 --include-from=FILE don't exclude patterns listed in FILE
1e476835 942 --files-from=FILE read FILE for list of source-file names
2e064775 943+ -E same as --exclude='-p /.rsync-excludes'
1e476835
WD
944 -0 --from0 all file lists are delimited by nulls
945 --version print version number
37da98ae 946 --port=PORT specify double-colon alternate port number
2e064775 947@@ -1114,24 +1115,32 @@ The exclude and include patterns specifi
5f98a4b1
WD
948 selection of which files to transfer and which files to skip.
949
950 Rsync builds an ordered list of include/exclude options as specified on
951-the command line. Rsync checks each file and directory
952-name against each exclude/include pattern in turn. The first matching
953+the command line.
954+It can also be told to check for include/exclude options in each
955+directory that rsync visits during the transfer (see the section on
956+MERGED EXCLUDE FILES for the details on these per-directory exclude
957+files).
958+
959+As the list of files/directories to transfer is built, rsync checks each
960+name against every exclude/include pattern in turn. The first matching
961 pattern is acted on. If it is an exclude pattern, then that file is
962 skipped. If it is an include pattern then that filename is not
963 skipped. If no matching include/exclude pattern is found then the
964 filename is not skipped.
965
966-The filenames matched against the exclude/include patterns are relative
967-to the "root of the transfer". If you think of the transfer as a
85c7c40a
WD
968-subtree of names that are being sent from sender to receiver, the root
969-is where the tree starts to be duplicated in the destination directory.
970-This root governs where patterns that start with a / match (see below).
5f98a4b1
WD
971+The global include/exclude rules are anchored at the "root of the
972+transfer" (as opposed to per-directory rules, which are anchored at
85c7c40a
WD
973+the merge-file's directory). If you think of the transfer as a
974+subtree of names that are being sent from sender to receiver, the
975+transfer-root is where the tree starts to be duplicated in the
976+destination directory. This root governs where patterns that start
977+with a / match (as described in the list on pattern forms below).
978
979 Because the matching is relative to the transfer-root, changing the
5f98a4b1
WD
980 trailing slash on a source path or changing your use of the --relative
981 option affects the path you need to use in your matching (in addition to
982 changing how much of the file tree is duplicated on the destination
983-system). The following examples demonstrate this.
984+host). The following examples demonstrate this.
985
986 Let's say that we want to match two source files, one with an absolute
987 path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz".
2e064775 988@@ -1178,23 +1187,27 @@ because rsync did not descend through th
5f98a4b1
WD
989 hierarchy.
990
991 Note also that the --include and --exclude options take one pattern
992-each. To add multiple patterns use the --include-from and
993---exclude-from options or multiple --include and --exclude options.
994+each. To add multiple patterns use the --include-from and --exclude-from
85c7c40a 995+options or multiple --include and --exclude options.
5f98a4b1
WD
996
997-The patterns can take several forms. The rules are:
998+The include/exclude patterns can take several forms. The rules are:
999
1000 itemize(
1001
1002- it() if the pattern starts with a / then it is matched against the
1003- start of the filename, otherwise it is matched against the end of
1004- the filename.
1005- This is the equivalent of a leading ^ in regular expressions.
1006- Thus "/foo" would match a file called "foo" at the transfer-root
1007- (see above for how this is different from the filesystem-root).
1008- On the other hand, "foo" would match any file called "foo"
1009+ it() if the pattern starts with a / then it is anchored to a
1010+ particular spot in the hierarchy of files, otherwise it is matched
1011+ against the end of the pathname. This is similar to a leading ^ in
1012+ regular expressions.
1013+ Thus "/foo" would match a file called "foo" at either the "root of the
85c7c40a 1014+ transfer" (for a global rule) or in the merge-file's directory (for a
5f98a4b1
WD
1015+ per-directory rule).
1016+ An unqualified "foo" would match any file or directory named "foo"
1017 anywhere in the tree because the algorithm is applied recursively from
1018+ the
1019 top down; it behaves as if each path component gets a turn at being the
1020- end of the file name.
1021+ end of the file name. Even the unanchored "sub/foo" would match at
1022+ any point in the hierarchy where a "foo" was found within a directory
1023+ named "sub".
1024
1025 it() if the pattern ends with a / then it will only match a
1026 directory, not a file, link, or device.
2e064775 1027@@ -1207,22 +1220,44 @@ itemize(
5f98a4b1
WD
1028 single asterisk pattern "*" will stop at slashes.
1029
1030 it() if the pattern contains a / (not counting a trailing /) or a "**"
1031- then it is matched against the full filename, including any leading
1032- directory. If the pattern doesn't contain a / or a "**", then it is
1033+ then it is matched against the full pathname, including any leading
1034+ directories. If the pattern doesn't contain a / or a "**", then it is
1035 matched only against the final component of the filename. Again,
1036 remember that the algorithm is applied recursively so "full filename" can
1037 actually be any portion of a path below the starting directory.
1038
2e064775
WD
1039- it() if the pattern starts with "+ " (a plus followed by a space)
1040- then it is always considered an include pattern, even if specified as
5f98a4b1 1041- part of an exclude option. The prefix is discarded before matching.
2e064775
WD
1042-
1043- it() if the pattern starts with "- " (a minus followed by a space)
1044- then it is always considered an exclude pattern, even if specified as
5f98a4b1 1045- part of an include option. The prefix is discarded before matching.
2e064775
WD
1046+ it() if the pattern starts with "+" (a plus), the actual pattern begins
1047+ after the first space, and is always considered to be an include pattern,
1048+ even if specified as part of an exclude file/option. Option letters may
1049+ follow the "+" prior to the separating space (see below).
1050+
1051+ it() if the pattern starts with "-" (a minus), the actual pattern begins
1052+ after the first space, and is always considered to be an exclude pattern,
1053+ even if specified as part of an include file/option. Option letters may
1054+ follow the "-" prior to the separating space (see below).
1055
1056- it() if the pattern is a single exclamation mark ! then the current
1057+ it() if the pattern is a "!" (single exclamation mark) then the current
1e476835 1058 include/exclude list is reset, removing all previously defined patterns.
5f98a4b1
WD
1059+ The "current" list is either the global list of rules (which are
1060+ specified via options) or a set of per-directory rules (which are
1061+ inherited in their own sub-list, so a subdirectory can use this to
1062+ clear out the parent's rules).
2e064775
WD
1063+
1064+)
1065+
1066+For a line that starts with a "+" (plus) or a "-" (minus), the following
1067+option letters may be suffixed:
1068+
1069+itemize(
1070+
1071+ it() An "m" means that the string following the space is to be taken to
1072+ be a merge-file that is read in to supplement the current rules. See the
1073+ section on MERGED EXCLUDE FILES for more information.
1074+
1075+ it() A "p" means that the string following the space is to be taken to be
1076+ a per-directory merge-file that is read in to supplement the current
1077+ rules. See the section on MERGED EXCLUDE FILES for more information.
1078+
524989ae
WD
1079 )
1080
5f98a4b1 1081 The +/- rules are most useful in a list that was read from a file, allowing
2e064775 1082@@ -1269,8 +1304,157 @@ itemize(
5f98a4b1
WD
1083 it() --include "*/" --include "*.c" --exclude "*" would include all
1084 directories and C source files
1085 it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
1086- only foo/bar.c (the foo/ directory must be explicitly included or
1087- it would be excluded by the "*")
1088+ only the foo directory and foo/bar.c (the foo directory must be
1089+ explicitly included or it would be excluded by the "*")
1090+)
1091+
1092+manpagesection(MERGED EXCLUDE FILES)
524989ae 1093+
2e064775
WD
1094+You can merge whole files into an exclude file by specifying either the
1095+"m" or "p" option following the initial "+" or "-", and putting a filename
1096+in place of the pattern. There are two kinds of merged exclude files --
1097+single-instance ("m") and per-directory ("p"). For example:
d34d9fad 1098+
2e064775
WD
1099+verb(
1100+ -m /etc/rsync/default.excludes
1101+ +p .per-dir-includes
1102+)
d34d9fad 1103+
2e064775 1104+For a per-directory merge file, rsync will scan
d34d9fad 1105+every directory that it traverses for the named file, merging its contents
3d3aaf9f
WD
1106+when the file exists. These exclude files must exist on the sending side
1107+because it is the sending side that is being scanned for available files
1108+to send. The files may also need to be transferred to the receiving side
1109+if you want them to affect what files don't get deleted (see PER-DIRECTORY
1110+EXCLUDES AND DELETE below).
5f98a4b1 1111+
85c7c40a
WD
1112+Per-directory rules are inherited in all subdirectories of the directory
1113+where the merge-file was found. Each subdirectory's rules are prefixed
1114+to the inherited rules from the parent directories, which gives the
1115+newest rules a higher priority than the inherited rules. The entire set
1116+of per-dir rules is grouped together in the spot where the merge-file was
1117+specified, so it is possible to override per-dir rules via a rule that
1118+got specified earlier in the list of global rules.
1119+
1120+If you don't want a per-dir rule to be inherited, anchor it with a leading
1121+slash. Anchored rules in a per-directory merge-file are relative to the
1122+merge-file's directory, so a rule "/foo" would only exclude the file "foo"
1123+in the directory where the per-dir exclude file was found.
1124+
1125+Here's an example exclude file which you'd specify via the normal
1126+--exclude-from=FILE option:
524989ae
WD
1127+
1128+verb(
2e064775 1129+ -m /home/user/.global_excludes
41ebea83 1130+ *.gz
2e064775 1131+ +p .incl
524989ae 1132+ + *.[ch]
41ebea83 1133+ *.o
3d3aaf9f
WD
1134+)
1135+
524989ae 1136+This will merge the contents of the /home/user/.global_excludes file at the
2e064775
WD
1137+start of the list and also turns the ".incl" filename into a per-directory
1138+include file. All rules read in prior to the start of the directory scan
1139+follow the global anchoring rules (i.e. a leading slash matches at the root
1140+of the transfer).
524989ae 1141+
5f98a4b1 1142+If a per-directory merge-file is specified with a path that is a parent
d34d9fad
WD
1143+directory of the first transfer directory, rsync will scan all the parent
1144+dirs from that starting point to the transfer directory for the indicated
1145+per-directory file. For instance, the -E option is an abbreviation for
1146+this command:
1147+
1148+verb(
2e064775 1149+ --exclude='-p /.rsync-excludes'
d34d9fad
WD
1150+)
1151+
1152+That exclude tells rsync to scan for the file .rsync-excludes in all
85c7c40a
WD
1153+directories from the root down through the source of the transfer. (For
1154+an rsync daemon, the "root dir" is always the module's "path" setting.)
41ebea83
WD
1155+
1156+Some examples of this pre-scanning for per-directory files:
d34d9fad
WD
1157+
1158+verb(
1159+ rsync -avE /src/path/ /dest/dir
2e064775
WD
1160+ rsync -av --exclude='-p ../../.rsync-excludes' /src/path/ /dest/dir
1161+ rsync -av --exclude='-p .rsync-excludes' /src/path/ /dest/dir
d34d9fad 1162+)
1e476835 1163+
5f98a4b1 1164+The first two commands above will look for ".rsync-excludes" in "/" and
41ebea83 1165+"/src" before the normal scan begins looking for the file in "/src/path"
5f98a4b1
WD
1166+and its subdirectories. The last command avoids the parent-dir scan
1167+and only looks for the ".rsync-excludes" files in each directory that is
1168+a part of the transfer.
1169+
1170+Finally, note that the parsing of any merge-file named ".cvsignore" is
1171+always done in a CVS-compatible manner, even if -C wasn't specified. This
1172+means that its rules are always excludes (even if an include option
1173+specified the file), patterns are split on whitespace, the rules are never
2e064775
WD
1174+inherited, and no special characters are honored except for "!" (e.g. no
1175+comments, and no +/- prefixes).
5f98a4b1
WD
1176+
1177+Additionally, you can affect where the --cvs-exclude (-C) option's
1178+inclusion of the per-directory .cvsignore file gets placed into your rules
1179+by adding your own explicit per-directory merge rule for ".cvsignore".
2e064775 1180+Without this, rsync would add this rule at the end of all your other
5f98a4b1
WD
1181+rules (giving it a lower priority than your command-line rules). For
1182+example:
1183+
1184+verb(
2e064775 1185+ rsync -avC --exclude='-p .cvsignore' --exclude-from=foo a/ b
5f98a4b1
WD
1186+)
1187+
1188+The above will merge all the per-directory .cvsignore rules at the start of
1189+your list rather than at the end. This allows their dir-specific rules to
1190+supersede your rules instead of being subservient to them. (The global
1191+rules taken from the $HOME/.cvsignore file and from $CVSIGNORE are not
1192+repositioned by this.)
524989ae 1193+
3d3aaf9f
WD
1194+manpagesection(PER-DIRECTORY EXCLUDES AND DELETE)
1195+
1196+Without a delete option, per-directory excludes are only relevant on the
1197+sending side, so you can feel free to exclude the merge files themselves
1198+without affecting the transfer:
1199+
1200+verb(
2e064775 1201+ rsync -av --exclude='-p .excl' --exclude=.excl host:src/dir /dest
3d3aaf9f
WD
1202+)
1203+
1204+However, if you want to do a delete on the receiving side AND you want some
1205+files to be excluded from being deleted, you'll need to be sure that the
1206+receiving side knows what files to exclude. The easiest way is to include
1207+the per-directory merge files in the transfer and use --delete-after
1208+because this ensures that the receiving side gets all the same exclude
1209+rules as the sending side before it tries to delete anything:
1210+
1211+verb(
1212+ rsync -avE --delete-after host:src/dir /dest
1213+)
1214+
2e064775 1215+However, if the merge files are not a part of the transfer, you'll need
3d3aaf9f
WD
1216+to either use a global exclude rule (i.e. specified on the command line),
1217+or you'll need to maintain your own per-directory merge files on the
1218+receiving side. An example of the first is this (assume that the remote
1219+.ctrl files exclude themselves):
1220+
1221+verb(
2e064775 1222+ rsync -av --exclude='-p .ctrl' --exclude-from=/my/extra.rules
3d3aaf9f
WD
1223+ --delete host:src/dir /dest
1224+)
1225+
1226+In the above example the extra.rules file can affect both sides of the
1227+transfer, but the rules are subservient to the rules merged from the .ctrl
1228+files because they were specified after the per-directory merge rule.
1229+
2e064775 1230+In one final example, the remote side is excluding the .rsync-excludes
3d3aaf9f
WD
1231+files from the transfer, but we want to use our own .rsync-excludes files
1232+to control what gets deleted on the receiving side. To do this we must
1233+specifically exclude the per-directory merge files (so that they don't get
1234+deleted) and then put rules into the local files to control what else
1235+should not get deleted. Like this:
1236+
1237+verb(
1238+ rsync -avE --exclude=.rsync-excludes --delete host:src/dir /dest
1239 )
524989ae 1240
3d3aaf9f 1241 manpagesection(BATCH MODE)
13bed3dd 1242--- orig/testsuite/exclude.test 2004-05-29 21:25:45
2e064775 1243+++ testsuite/exclude.test 2005-01-14 00:14:33
c4e46f36 1244@@ -23,19 +23,47 @@ export HOME CVSIGNORE
7d31425d
WD
1245 makepath "$fromdir/foo/down/to/you"
1246 makepath "$fromdir/bar/down/to/foo/too"
1247 makepath "$fromdir/mid/for/foo/and/that/is/who"
c4e46f36 1248+cat >"$fromdir/.excl" <<EOF
7d31425d
WD
1249+.excl
1250+*.bak
1251+*.old
1252+*.junk
c4e46f36 1253+EOF
7d31425d
WD
1254 echo kept >"$fromdir/foo/file1"
1255 echo removed >"$fromdir/foo/file2"
1256 echo cvsout >"$fromdir/foo/file2.old"
c4e46f36 1257+cat >"$fromdir/foo/.excl" <<EOF
7d31425d
WD
1258++ .excl
1259+- file1
c4e46f36
WD
1260+EOF
1261+cat >"$fromdir/bar/.excl" <<EOF
7d31425d 1262+home-cvs-exclude
2e064775 1263+-p .excl2
7d31425d 1264++ to
c4e46f36 1265+EOF
7d31425d 1266 echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
c4e46f36 1267+cat >"$fromdir/bar/down/to/.excl2" <<EOF
7d31425d 1268+.excl2
c4e46f36 1269+EOF
7d31425d
WD
1270 echo keeper >"$fromdir/bar/down/to/foo/file1"
1271 echo cvsout >"$fromdir/bar/down/to/foo/file1.bak"
1272 echo gone >"$fromdir/bar/down/to/foo/file3"
1273 echo lost >"$fromdir/bar/down/to/foo/file4"
1274 echo cvsout >"$fromdir/bar/down/to/foo/file4.junk"
1275 echo smashed >"$fromdir/bar/down/to/foo/to"
c4e46f36 1276+cat >"$fromdir/bar/down/to/foo/.excl2" <<EOF
7d31425d 1277++ *.junk
c4e46f36 1278+EOF
7d31425d 1279+# This one should be ineffectual
c4e46f36 1280+cat >"$fromdir/mid/.excl2" <<EOF
7d31425d 1281+extra
c4e46f36 1282+EOF
7d31425d
WD
1283 echo cvsout >"$fromdir/mid/one-in-one-out"
1284 echo one-in-one-out >"$fromdir/mid/.cvsignore"
1285 echo cvsin >"$fromdir/mid/one-for-all"
c4e46f36 1286+cat >"$fromdir/mid/.excl" <<EOF
2e064775 1287+-p .cvsignore
c4e46f36 1288+EOF
7d31425d
WD
1289 echo cvsin >"$fromdir/mid/for/one-in-one-out"
1290 echo expunged >"$fromdir/mid/for/foo/extra"
1291 echo retained >"$fromdir/mid/for/foo/keep"
c4e46f36
WD
1292@@ -100,5 +128,24 @@ $RSYNC -av --existing --include='*/' --e
1293 checkit "$RSYNC -avvC --exclude-from=\"$excl\" \
1294 --delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
7d31425d
WD
1295
1296+# Modify the chk dir for our merge-exclude test and then tweak the dir times.
1297+
1298+rm "$chkdir"/.excl
1299+rm "$chkdir"/foo/file1
1300+rm "$chkdir"/bar/.excl
1301+rm "$chkdir"/bar/down/to/.excl2
1302+rm "$chkdir"/bar/down/to/foo/.excl2
1303+rm "$chkdir"/mid/.excl
1304+cp -p "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo
1305+cp -p "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo
1306+
1307+$RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
1308+
1309+# Now, test if rsync excludes the same files, this time with a merge-exclude
1310+# file.
1311+
2e064775 1312+checkit "$RSYNC -avv --exclude='-p .excl' --exclude-from=\"$excl\" \
c4e46f36 1313+ --delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
7d31425d
WD
1314+
1315 # The script would have aborted on error, so getting here means we've won.
1316 exit 0