Another round of re-think for the enhanced syntax. This time the
[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
147a9095
WD
6This patch adds the --filter option, which implements an improved set of
7excludes/includes rules:
8
9 . SINGLE-INSTANCE_MERGE_FILE
10 : PER-DIRECTORY_MERGE_FILE
11 - exclude-pattern
12 + include-pattern
13
14Note that the prefix for a filter rule is NOT optional, and that the
15separating space can be an equal-sign (=), if desired. There are also
16optional modifiers that can be specified for a merge-file rule.
17
18A per-directory merge file is one that will be looked for in every
19sub-directory that rsync visits, and the rules found in that sub-
20directory's file will affect that dir and (if desired) its subdirs.
a55d21aa
WD
21
22For example:
23
147a9095 24 rsync -av --filter :=.filt from/ to
a55d21aa 25
147a9095
WD
26The above will look for a file named ".filt" in every directory of the
27hierarchy that rsync visits, and it will filter names based on the rules
28found therein. If one of the .filt files contains this:
a55d21aa
WD
29
30 + *.c
147a9095
WD
31 : .filt2
32 . .filt3
33 - *.o
34 - /foobar
a55d21aa 35
147a9095
WD
36Then the file ".filt2" will also be read in from the current dir and all
37its subdirs. The file ".filt3" would just be read in from the current dir
38only. The exclusion of "foobar" will only happen in that .filt file's
39directory because the rule is anchored, which is one way to make a rule
40local instead of inherited (see also the 'n' option).
a55d21aa
WD
41
42..wayne..
43
37da98ae 44--- orig/clientserver.c 2005-01-01 21:11:00
147a9095 45+++ clientserver.c 2005-01-16 23:33:02
37da98ae 46@@ -49,12 +49,14 @@ extern int no_detach;
40e20a69
WD
47 extern int default_af_hint;
48 extern char *bind_address;
49 extern struct exclude_list_struct server_exclude_list;
50-extern char *exclude_path_prefix;
51 extern char *config_file;
52 extern char *files_from;
40e20a69
WD
53
54 char *auth_user;
55
3d3aaf9f 56+/* Length of lp_path() string when in daemon mode & not chrooted, else 0. */
45795ec6
WD
57+unsigned int module_dirlen = 0;
58+
59 /**
60 * Run a client connected to an rsyncd. The alternative to this
61 * function for remote-shell connections is do_cmd().
147a9095 62@@ -304,26 +306,33 @@ static int rsync_module(int f_in, int f_
40e20a69
WD
63 /* TODO: Perhaps take a list of gids, and make them into the
64 * supplementary groups. */
65
66- exclude_path_prefix = use_chroot? "" : lp_path(i);
67- if (*exclude_path_prefix == '/' && !exclude_path_prefix[1])
68- exclude_path_prefix = "";
45795ec6
WD
69+ if (use_chroot) {
70+ module_dirlen = 0;
71+ set_excludes_dir("/", 1);
72+ } else {
73+ module_dirlen = strlen(lp_path(i));
74+ set_excludes_dir(lp_path(i), module_dirlen);
75+ }
147a9095
WD
76+
77+ p = lp_filter(i);
78+ add_exclude(&server_exclude_list, p,
79+ XFLG_WORD_SPLIT | XFLG_ABS_PATH);
40e20a69
WD
80
81 p = lp_include_from(i);
82 add_exclude_file(&server_exclude_list, p,
83- XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
147a9095 84+ XFLG_FATAL_ERRORS | XFLG_ABS_PATH | XFLG_DEF_INCLUDE);
40e20a69
WD
85
86 p = lp_include(i);
87 add_exclude(&server_exclude_list, p,
88- XFLG_WORD_SPLIT | XFLG_DEF_INCLUDE);
147a9095 89+ XFLG_WORD_SPLIT | XFLG_ABS_PATH | XFLG_DEF_INCLUDE);
40e20a69
WD
90
91 p = lp_exclude_from(i);
92 add_exclude_file(&server_exclude_list, p,
93- XFLG_FATAL_ERRORS);
147a9095 94+ XFLG_FATAL_ERRORS | XFLG_ABS_PATH | XFLG_DEF_EXCLUDE);
40e20a69
WD
95
96 p = lp_exclude(i);
97- add_exclude(&server_exclude_list, p, XFLG_WORD_SPLIT);
45795ec6 98-
40e20a69 99- exclude_path_prefix = NULL;
147a9095
WD
100+ add_exclude(&server_exclude_list, p,
101+ XFLG_WORD_SPLIT | XFLG_ABS_PATH | XFLG_DEF_EXCLUDE);
40e20a69
WD
102
103 log_init();
104
2e064775 105--- orig/exclude.c 2005-01-13 23:15:56
147a9095
WD
106+++ exclude.c 2005-01-17 00:25:08
107@@ -30,15 +30,73 @@ extern int verbose;
a55d21aa
WD
108 extern int eol_nulls;
109 extern int list_only;
110 extern int recurse;
111+extern int io_error;
56babefa 112+extern int sanitize_paths;
147a9095 113+extern int protocol_version;
a55d21aa
WD
114
115 extern char curr_dir[];
56babefa 116+extern unsigned int curr_dir_len;
45795ec6 117+extern unsigned int module_dirlen;
a55d21aa 118
d8af8661 119 struct exclude_list_struct exclude_list = { 0, 0, "" };
524989ae 120-struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " };
d8af8661 121 struct exclude_list_struct server_exclude_list = { 0, 0, "server " };
40e20a69 122-char *exclude_path_prefix = NULL;
147a9095
WD
123
124-/** Build an exclude structure given an exclude pattern. */
eabda998 125+struct mergelist_save_struct {
d1e7c1c8 126+ struct exclude_list_struct *array;
d8af8661
WD
127+ int count;
128+};
524989ae 129+
db4f43dd
WD
130+/* The dirbuf is set by push_local_excludes() to the current subdirectory
131+ * relative to curr_dir that is being processed. The path always has a
45795ec6
WD
132+ * trailing slash appended, and the variable dirbuf_len contains the length
133+ * of this path prefix. The path is always absolute. */
134+static char dirbuf[MAXPATHLEN+1];
135+static unsigned int dirbuf_len = 0;
b338da5b 136+static int dirbuf_depth;
45795ec6
WD
137+
138+/* This is True when we're scanning parent dirs for per-dir merge-files. */
139+static BOOL parent_dirscan = False;
db4f43dd
WD
140+
141+/* This array contains a list of all the currently active per-dir merge
142+ * files. This makes it easier to save the appropriate values when we
143+ * "push" down into each subdirectory. */
d34d9fad
WD
144+static struct exclude_struct **mergelist_parents;
145+static int mergelist_cnt = 0;
146+static int mergelist_size = 0;
a55d21aa 147+
d1e7c1c8
WD
148+/* Each exclude_list_struct describes a singly-linked list by keeping track
149+ * of both the head and tail pointers. The list is slightly unusual in that
150+ * a parent-dir's content can be appended to the end of the local list in a
151+ * special way: the last item in the local list has its "next" pointer set
0c7d1fd8 152+ * to point to the inherited list, but the local list's tail pointer points
d1e7c1c8 153+ * at the end of the local list. Thus, if the local list is empty, the head
0c7d1fd8 154+ * will be pointing at the inherited content but the tail will be NULL. To
d1e7c1c8
WD
155+ * help you visualize this, here are the possible list arrangements:
156+ *
157+ * Completely Empty Local Content Only
158+ * ================================== ====================================
159+ * head -> NULL head -> Local1 -> Local2 -> NULL
160+ * tail -> NULL tail -------------^
161+ *
162+ * Inherited Content Only Both Local and Inherited Content
163+ * ================================== ====================================
164+ * head -> Parent1 -> Parent2 -> NULL head -> L1 -> L2 -> P1 -> P2 -> NULL
165+ * tail -> NULL tail ---------^
166+ *
2e064775 167+ * This means that anyone wanting to traverse the whole list to use it just
d1e7c1c8
WD
168+ * needs to start at the head and use the "next" pointers until it goes
169+ * NULL. To add new local content, we insert the item after the tail item
170+ * and update the tail (obviously, if "tail" was NULL, we insert it at the
171+ * head). To clear the local list, WE MUST NOT FREE THE INHERITED CONTENT
bc95f62b
WD
172+ * because it is shared between the current list and our parent list(s).
173+ * The easiest way to handle this is to simply truncate the list after the
174+ * tail item and then free the local list from the head. When inheriting
175+ * the list for a new local dir, we just save off the exclude_list_struct
0c7d1fd8 176+ * values (so we can pop back to them later) and set the tail to NULL.
d1e7c1c8 177+ */
147a9095
WD
178+
179+/* Build an exclude structure given an exclude pattern. The value in "pat"
180+ * is not null-terminated. */
0c7d1fd8 181 static void make_exclude(struct exclude_list_struct *listp, const char *pat,
147a9095
WD
182 unsigned int pat_len, unsigned int mflags)
183 {
184@@ -46,23 +104,44 @@ static void make_exclude(struct exclude_
a55d21aa 185 const char *cp;
0c7d1fd8
WD
186 unsigned int ex_len;
187
d34d9fad 188+ if (verbose > 2) {
147a9095 189+ rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s)\n",
d34d9fad 190+ who_am_i(), (int)pat_len, pat, listp->debug_type,
147a9095
WD
191+ mflags & MATCHFLG_MERGE_FILE ? "MERGE-FILE"
192+ : mflags & MATCHFLG_INCLUDE ? "include" : "exclude");
d34d9fad
WD
193+ }
194+
524989ae 195+ if (mflags & MATCHFLG_MERGE_FILE) {
eabda998 196+ int i;
2e064775 197+ /* If the local merge file was already mentioned, don't
524989ae 198+ * add it again. */
eabda998
WD
199+ for (i = 0; i < mergelist_cnt; i++) {
200+ struct exclude_struct *ex = mergelist_parents[i];
201+ if (strlen(ex->pattern) == pat_len
d8af8661 202+ && memcmp(ex->pattern, pat, pat_len) == 0)
a55d21aa
WD
203+ return;
204+ }
a55d21aa 205+ }
0c7d1fd8 206+
a55d21aa
WD
207 ret = new(struct exclude_struct);
208 if (!ret)
209 out_of_memory("make_exclude");
40e20a69
WD
210
211 memset(ret, 0, sizeof ret[0]);
212
213- if (exclude_path_prefix)
214- mflags |= MATCHFLG_ABS_PATH;
215- if (exclude_path_prefix && *pat == '/')
216- ex_len = strlen(exclude_path_prefix);
217- else
218+ if (mflags & MATCHFLG_ABS_PATH) {
219+ if (*pat != '/') {
220+ mflags &= ~MATCHFLG_ABS_PATH;
221+ ex_len = 0;
45795ec6
WD
222+ } else
223+ ex_len = dirbuf_len - module_dirlen - 1;
40e20a69
WD
224+ } else
225 ex_len = 0;
226 ret->pattern = new_array(char, ex_len + pat_len + 1);
227 if (!ret->pattern)
228 out_of_memory("make_exclude");
45795ec6 229 if (ex_len)
40e20a69 230- memcpy(ret->pattern, exclude_path_prefix, ex_len);
5f98a4b1 231+ memcpy(ret->pattern, dirbuf + module_dirlen, ex_len);
40e20a69
WD
232 strlcpy(ret->pattern + ex_len, pat, pat_len + 1);
233 pat_len += ex_len;
234
147a9095 235@@ -81,14 +160,40 @@ static void make_exclude(struct exclude_
7b22909b 236 mflags |= MATCHFLG_DIRECTORY;
a55d21aa
WD
237 }
238
7b22909b 239- for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
bc95f62b 240- ret->slash_cnt++;
524989ae 241+ if (mflags & MATCHFLG_MERGE_FILE) {
d8af8661
WD
242+ struct exclude_list_struct *lp
243+ = new_array(struct exclude_list_struct, 1);
244+ if (!lp)
a55d21aa 245+ out_of_memory("make_exclude");
7cb7ae4e 246+ lp->head = lp->tail = NULL;
d34d9fad
WD
247+ if ((cp = strrchr(ret->pattern, '/')) != NULL)
248+ cp++;
249+ else
250+ cp = ret->pattern;
251+ if (asprintf(&lp->debug_type, "per-dir %s ", cp) < 0)
a55d21aa 252+ out_of_memory("make_exclude");
eabda998
WD
253+ ret->u.mergelist = lp;
254+ if (mergelist_cnt == mergelist_size) {
d34d9fad
WD
255+ mergelist_size += 5;
256+ mergelist_parents = realloc_array(mergelist_parents,
257+ struct exclude_struct *,
258+ mergelist_size);
259+ if (!mergelist_parents)
260+ out_of_memory("make_exclude");
eabda998
WD
261+ }
262+ mergelist_parents[mergelist_cnt++] = ret;
7b22909b
WD
263+ } else {
264+ for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
265+ ret->u.slash_cnt++;
abe86b1f 266+ }
7b22909b 267
0c7d1fd8 268 ret->match_flags = mflags;
a55d21aa 269
7b22909b
WD
270- if (!listp->tail)
271+ if (!listp->tail) {
272+ ret->next = listp->head;
273 listp->head = listp->tail = ret;
274- else {
275+ } else {
276+ ret->next = listp->tail->next;
277 listp->tail->next = ret;
278 listp->tail = ret;
279 }
147a9095 280@@ -96,22 +201,270 @@ static void make_exclude(struct exclude_
d8af8661
WD
281
282 static void free_exclude(struct exclude_struct *ex)
283 {
284+ if (ex->match_flags & MATCHFLG_MERGE_FILE) {
eabda998
WD
285+ free(ex->u.mergelist->debug_type);
286+ free(ex->u.mergelist);
d8af8661
WD
287+ }
288 free(ex->pattern);
a55d21aa
WD
289 free(ex);
290 }
291
d8af8661
WD
292-void clear_exclude_list(struct exclude_list_struct *listp)
293+static void clear_exclude_list(struct exclude_list_struct *listp)
a55d21aa 294 {
7cb7ae4e
WD
295- struct exclude_struct *ent, *next;
296-
297- for (ent = listp->head; ent; ent = next) {
298- next = ent->next;
299- free_exclude(ent);
300+ if (listp->tail) {
301+ struct exclude_struct *ent, *next;
bc95f62b 302+ /* Truncate any inherited items from the local list. */
7cb7ae4e 303+ listp->tail->next = NULL;
dc5cce3c 304+ /* Now free everything that is left. */
7cb7ae4e
WD
305+ for (ent = listp->head; ent; ent = next) {
306+ next = ent->next;
307+ free_exclude(ent);
308+ }
524989ae
WD
309 }
310
7cb7ae4e
WD
311 listp->head = listp->tail = NULL;
312 }
a55d21aa 313
db4f43dd 314+/* This returns an expanded (absolute) filename for the merge-file name if
45795ec6 315+ * the name has any slashes in it OR if the parent_dirscan var is True;
db4f43dd 316+ * otherwise it returns the original merge_file name. If the len_ptr value
45795ec6
WD
317+ * is non-NULL the merge_file name is limited by the referenced length
318+ * value and will be updated with the length of the resulting name. We
319+ * always return a name that is null terminated, even if the merge_file
320+ * name was not. */
321+static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr,
322+ unsigned int prefix_skip)
41ebea83
WD
323+{
324+ static char buf[MAXPATHLEN];
325+ char *fn, tmpbuf[MAXPATHLEN];
45795ec6 326+ unsigned int fn_len;
41ebea83 327+
40e20a69 328+ if (!parent_dirscan && *merge_file != '/') {
db4f43dd 329+ /* Return the name unchanged it doesn't have any slashes. */
41ebea83 330+ if (len_ptr) {
db4f43dd
WD
331+ const char *p = merge_file + *len_ptr;
332+ while (--p > merge_file && *p != '/') {}
333+ if (p == merge_file) {
334+ strlcpy(buf, merge_file, *len_ptr + 1);
335+ return buf;
336+ }
337+ } else if (strchr(merge_file, '/') == NULL)
41ebea83
WD
338+ return (char *)merge_file;
339+ }
340+
341+ fn = *merge_file == '/' ? buf : tmpbuf;
342+ if (sanitize_paths) {
45795ec6 343+ const char *r = prefix_skip ? "/" : NULL;
41ebea83
WD
344+ /* null-terminate the name if it isn't already */
345+ if (len_ptr && merge_file[*len_ptr]) {
346+ char *to = fn == buf ? tmpbuf : buf;
347+ strlcpy(to, merge_file, *len_ptr + 1);
348+ merge_file = to;
349+ }
b338da5b 350+ if (!sanitize_path(fn, merge_file, r, dirbuf_depth)) {
45795ec6 351+ rprintf(FERROR, "merge-file name overflows: %s\n",
41ebea83
WD
352+ merge_file);
353+ return NULL;
354+ }
355+ } else {
356+ strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN);
20f8d513 357+ clean_fname(fn, 1);
41ebea83
WD
358+ }
359+
41ebea83 360+ fn_len = strlen(fn);
45795ec6
WD
361+ if (fn == buf)
362+ goto done;
363+
364+ if (dirbuf_len + fn_len >= MAXPATHLEN) {
365+ rprintf(FERROR, "merge-file name overflows: %s\n", fn);
41ebea83
WD
366+ return NULL;
367+ }
45795ec6
WD
368+ memcpy(buf, dirbuf + prefix_skip, dirbuf_len - prefix_skip);
369+ memcpy(buf + dirbuf_len - prefix_skip, fn, fn_len + 1);
20f8d513 370+ fn_len = clean_fname(buf, 1);
45795ec6
WD
371+
372+ done:
41ebea83
WD
373+ if (len_ptr)
374+ *len_ptr = fn_len;
41ebea83
WD
375+ return buf;
376+}
377+
45795ec6
WD
378+/* Sets the dirbuf and dirbuf_len values. */
379+void set_excludes_dir(const char *dir, unsigned int dirlen)
40e20a69 380+{
45795ec6
WD
381+ unsigned int len;
382+ if (*dir != '/') {
383+ memcpy(dirbuf, curr_dir, curr_dir_len);
384+ dirbuf[curr_dir_len] = '/';
385+ len = curr_dir_len + 1;
470aa8d5
WD
386+ if (len + dirlen >= MAXPATHLEN)
387+ dirlen = 0;
45795ec6
WD
388+ } else
389+ len = 0;
390+ memcpy(dirbuf + len, dir, dirlen);
391+ dirbuf[dirlen + len] = '\0';
20f8d513 392+ dirbuf_len = clean_fname(dirbuf, 1);
45795ec6
WD
393+ if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.'
394+ && dirbuf[dirbuf_len-2] == '/')
395+ dirbuf_len -= 2;
396+ dirbuf[dirbuf_len++] = '/';
397+ dirbuf[dirbuf_len] = '\0';
b338da5b
WD
398+ if (sanitize_paths)
399+ dirbuf_depth = count_dir_elements(dirbuf + module_dirlen);
40e20a69
WD
400+}
401+
45795ec6 402+/* This routine takes a per-dir merge-file entry and finishes its setup.
db4f43dd
WD
403+ * If the name has a path portion then we check to see if it refers to a
404+ * parent directory of the first transfer dir. If it does, we scan all the
405+ * dirs from that point through the parent dir of the transfer dir looking
45795ec6
WD
406+ * for the per-dir merge-file in each one. */
407+static BOOL setup_merge_file(struct exclude_struct *ex,
408+ struct exclude_list_struct *lp, int flags)
1e476835 409+{
d34d9fad 410+ char buf[MAXPATHLEN];
db4f43dd
WD
411+ char *x, *y, *pat = ex->pattern;
412+ unsigned int len;
56babefa 413+
45795ec6
WD
414+ if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/')
415+ return 0;
1e476835 416+
db4f43dd
WD
417+ y = strrchr(x, '/');
418+ *y = '\0';
419+ ex->pattern = strdup(y+1);
db4f43dd
WD
420+ if (!*x)
421+ x = "/";
422+ if (*x == '/')
423+ strlcpy(buf, x, MAXPATHLEN);
d34d9fad 424+ else
db4f43dd 425+ pathjoin(buf, MAXPATHLEN, dirbuf, x);
d34d9fad 426+
20f8d513 427+ len = clean_fname(buf, 1);
db4f43dd
WD
428+ if (len != 1 && len < MAXPATHLEN-1) {
429+ buf[len++] = '/';
430+ buf[len] = '\0';
431+ }
db4f43dd 432+ /* This ensures that the specified dir is a parent of the transfer. */
45795ec6 433+ for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {}
d34d9fad 434+ if (*x)
db4f43dd 435+ y += strlen(y); /* nope -- skip the scan */
d34d9fad 436+
45795ec6 437+ parent_dirscan = True;
d34d9fad
WD
438+ while (*y) {
439+ char save[MAXPATHLEN];
41ebea83 440+ strlcpy(save, y, MAXPATHLEN);
db4f43dd 441+ *y = '\0';
45795ec6 442+ dirbuf_len = y - dirbuf;
db4f43dd 443+ strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf));
40e20a69 444+ add_exclude_file(lp, buf, flags | XFLG_ABS_PATH);
147a9095
WD
445+ if (ex->match_flags & MATCHFLG_NO_INHERIT)
446+ lp->head = NULL;
d34d9fad 447+ lp->tail = NULL;
41ebea83 448+ strlcpy(y, save, MAXPATHLEN);
d34d9fad 449+ while ((*x++ = *y++) != '/') {}
1e476835 450+ }
45795ec6 451+ parent_dirscan = False;
db4f43dd 452+ free(pat);
45795ec6 453+ return 1;
1e476835
WD
454+}
455+
db4f43dd 456+/* Each time rsync changes to a new directory it call this function to
45795ec6
WD
457+ * handle all the per-dir merge-files. The "dir" value is the current path
458+ * relative to curr_dir (which might not be null-terminated). We copy it
459+ * into dirbuf so that we can easily append a file name on the end. */
40e20a69 460+void *push_local_excludes(const char *dir, unsigned int dirlen)
a55d21aa 461+{
eabda998
WD
462+ struct mergelist_save_struct *push;
463+ struct exclude_list_struct *ap;
464+ int i;
465+
45795ec6 466+ set_excludes_dir(dir, dirlen);
eabda998
WD
467+
468+ if (!(push = new_array(struct mergelist_save_struct, 1)))
469+ out_of_memory("push_local_excludes");
470+
471+ push->count = mergelist_cnt;
472+ push->array = new_array(struct exclude_list_struct, mergelist_cnt);
473+ if (!push->array)
474+ out_of_memory("push_local_excludes");
524989ae 475+
eabda998
WD
476+ for (i = 0, ap = push->array; i < mergelist_cnt; i++) {
477+ memcpy(ap++, mergelist_parents[i]->u.mergelist,
478+ sizeof (struct exclude_list_struct));
479+ }
480+
481+ /* Note: add_exclude_file() might increase mergelist_cnt, so keep
482+ * this loop separate from the above loop. */
483+ for (i = 0; i < mergelist_cnt; i++) {
484+ struct exclude_struct *ex = mergelist_parents[i];
485+ struct exclude_list_struct *lp = ex->u.mergelist;
147a9095 486+ int flags = 0;
524989ae
WD
487+
488+ if (verbose > 2) {
489+ rprintf(FINFO, "[%s] pushing %sexclude list\n",
d8af8661 490+ who_am_i(), lp->debug_type);
524989ae 491+ }
d8af8661 492+
40e20a69 493+ lp->tail = NULL; /* Switch any local rules to inherited. */
147a9095
WD
494+ if (ex->match_flags & MATCHFLG_NO_INHERIT)
495+ lp->head = NULL;
496+ if (ex->match_flags & MATCHFLG_WORD_SPLIT)
497+ flags |= XFLG_WORD_SPLIT;
498+ if (ex->match_flags & MATCHFLG_NO_PREFIXES)
499+ flags |= XFLG_NO_PREFIXES;
500+ if (ex->match_flags & MATCHFLG_INCLUDE)
501+ flags |= XFLG_DEF_INCLUDE;
502+ else if (ex->match_flags & MATCHFLG_NO_PREFIXES)
503+ flags |= XFLG_DEF_EXCLUDE;
d34d9fad 504+
40e20a69
WD
505+ if (ex->match_flags & MATCHFLG_FINISH_SETUP) {
506+ ex->match_flags &= ~MATCHFLG_FINISH_SETUP;
45795ec6
WD
507+ if (setup_merge_file(ex, lp, flags))
508+ set_excludes_dir(dir, dirlen);
d34d9fad
WD
509+ }
510+
45795ec6
WD
511+ if (strlcpy(dirbuf + dirbuf_len, ex->pattern,
512+ MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len)
40e20a69 513+ add_exclude_file(lp, dirbuf, flags | XFLG_ABS_PATH);
524989ae 514+ else {
a55d21aa
WD
515+ io_error |= IOERR_GENERAL;
516+ rprintf(FINFO,
517+ "cannot add local excludes in long-named directory %s\n",
d8af8661 518+ full_fname(dirbuf));
a55d21aa 519+ }
45795ec6 520+ dirbuf[dirbuf_len] = '\0';
a55d21aa
WD
521+ }
522+
524989ae 523+ return (void*)push;
a55d21aa
WD
524+}
525+
eabda998 526+void pop_local_excludes(void *mem)
a55d21aa 527+{
eabda998
WD
528+ struct mergelist_save_struct *pop = (struct mergelist_save_struct*)mem;
529+ struct exclude_list_struct *ap;
530+ int i;
d8af8661 531+
066e3b3e 532+ for (i = mergelist_cnt; i-- > 0; ) {
eabda998
WD
533+ struct exclude_struct *ex = mergelist_parents[i];
534+ struct exclude_list_struct *lp = ex->u.mergelist;
524989ae 535+
524989ae
WD
536+ if (verbose > 2) {
537+ rprintf(FINFO, "[%s] popping %sexclude list\n",
d8af8661 538+ who_am_i(), lp->debug_type);
524989ae 539+ }
d8af8661
WD
540+
541+ clear_exclude_list(lp);
a55d21aa 542+ }
d8af8661 543+
40e20a69 544+ mergelist_cnt = pop->count;
eabda998
WD
545+ for (i = 0, ap = pop->array; i < mergelist_cnt; i++) {
546+ memcpy(mergelist_parents[i]->u.mergelist, ap++,
547+ sizeof (struct exclude_list_struct));
548+ }
d8af8661
WD
549+
550+ free(pop->array);
551+ free(pop);
7cb7ae4e
WD
552+}
553+
a55d21aa 554 static int check_one_exclude(char *name, struct exclude_struct *ex,
7cb7ae4e
WD
555 int name_is_dir)
556 {
147a9095 557@@ -125,13 +478,14 @@ static int check_one_exclude(char *name,
bc95f62b
WD
558 /* If the pattern does not have any slashes AND it does not have
559 * a "**" (which could match a slash), then we just match the
560 * name portion of the path. */
561- if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
562+ if (!ex->u.slash_cnt && !(ex->match_flags & MATCHFLG_WILD2)) {
563 if ((p = strrchr(name,'/')) != NULL)
564 name = p+1;
565 }
3d3aaf9f
WD
566 else if (ex->match_flags & MATCHFLG_ABS_PATH && *name != '/'
567- && curr_dir[1]) {
568- pathjoin(full_name, sizeof full_name, curr_dir + 1, name);
569+ && curr_dir_len > module_dirlen + 1) {
570+ pathjoin(full_name, sizeof full_name,
571+ curr_dir + module_dirlen + 1, name);
045caa90
WD
572 name = full_name;
573 }
574
147a9095 575@@ -148,9 +502,9 @@ static int check_one_exclude(char *name,
bc95f62b
WD
576 if (ex->match_flags & MATCHFLG_WILD) {
577 /* A non-anchored match with an infix slash and no "**"
578 * needs to match the last slash_cnt+1 name elements. */
0c7d1fd8
WD
579- if (!match_start && ex->slash_cnt
580+ if (!match_start && ex->u.slash_cnt
581 && !(ex->match_flags & MATCHFLG_WILD2)) {
bc95f62b
WD
582- int cnt = ex->slash_cnt + 1;
583+ int cnt = ex->u.slash_cnt + 1;
584 for (p = name + strlen(name) - 1; p >= name; p--) {
585 if (*p == '/' && !--cnt)
586 break;
147a9095 587@@ -221,6 +575,13 @@ int check_exclude(struct exclude_list_st
a55d21aa
WD
588 struct exclude_struct *ent;
589
590 for (ent = listp->head; ent; ent = ent->next) {
524989ae 591+ if (ent->match_flags & MATCHFLG_MERGE_FILE) {
eabda998 592+ int rc = check_exclude(ent->u.mergelist, name,
d8af8661 593+ name_is_dir);
a55d21aa
WD
594+ if (rc)
595+ return rc;
596+ continue;
597+ }
598 if (check_one_exclude(name, ent, name_is_dir)) {
599 report_exclude_result(name, ent, name_is_dir,
600 listp->debug_type);
147a9095
WD
601@@ -236,7 +597,7 @@ int check_exclude(struct exclude_list_st
602 * be '\0' terminated, so use the returned length to limit the string.
603 * Also, be sure to add this length to the returned pointer before passing
604 * it back to ask for the next token. This routine parses the "!" (list-
605- * clearing) token and (if xflags does NOT contain XFLG_WORDS_ONLY) the
606+ * clearing) token and (if xflags does NOT contain XFLG_NO_PREFIXES) the
607 * +/- prefixes for overriding the include/exclude mode. The *flag_ptr
608 * value will also be set to the MATCHFLG_* bits for the current token.
609 */
610@@ -245,6 +606,7 @@ static const char *get_exclude_tok(const
611 {
612 const unsigned char *s = (const unsigned char *)p;
613 unsigned int len, mflags = 0;
614+ int add_dot_cvsinore = 0;
615
616 if (xflags & XFLG_WORD_SPLIT) {
617 /* Skip over any initial whitespace. */
618@@ -254,14 +616,74 @@ static const char *get_exclude_tok(const
a55d21aa
WD
619 p = (const char *)s;
620 }
621
622- /* Is this a '+' or '-' followed by a space (not whitespace)? */
2e064775 623- if (!(xflags & XFLG_WORDS_ONLY)
2e064775 624+ /* Check for a leading '+' or '-'. */
147a9095
WD
625+ if (!(xflags & (XFLG_DEF_INCLUDE | XFLG_DEF_EXCLUDE))) {
626+ char *mods = "";
627+ switch (*s) {
628+ case ':':
629+ mflags |= MATCHFLG_PERDIR_MERGE
630+ | MATCHFLG_FINISH_SETUP;
631+ /* FALL THROUGH */
632+ case '.':
633+ mflags |= MATCHFLG_MERGE_FILE;
634+ mods = "-+Cens";
635+ break;
636+ case '+':
637+ mflags |= MATCHFLG_INCLUDE;
638+ break;
639+ case '-':
640+ break;
641+ case '!':
642+ break;
643+ case '\0':
644+ len = 0;
645+ goto all_done;
646+ default:
647+ rprintf(FERROR, "Unknown filter command: %s\n", p);
6e313719
WD
648+ exit_cleanup(RERR_SYNTAX);
649+ }
147a9095
WD
650+ while (*++s && *s != ' ' && *s != '=') {
651+ if (strchr(mods, *s) == NULL) {
652+ rprintf(FERROR,
653+ "unknown option '%c' in filter command: %s\n",
654+ *s, p);
655+ exit_cleanup(RERR_SYNTAX);
656+ }
2e064775 657+ switch (*s) {
147a9095
WD
658+ case '-':
659+ mflags |= MATCHFLG_NO_PREFIXES;
660+ break;
661+ case '+':
662+ mflags |= MATCHFLG_NO_PREFIXES
663+ | MATCHFLG_INCLUDE;
664+ break;
6e313719 665+ case 'C':
147a9095
WD
666+ add_dot_cvsinore = 1;
667+ mflags |= MATCHFLG_NO_PREFIXES
668+ | MATCHFLG_WORD_SPLIT
669+ | MATCHFLG_NO_INHERIT;
6e313719 670+ break;
147a9095 671+ case 'e':
6e313719
WD
672+ mflags |= MATCHFLG_EXCLUDE_SELF;
673+ break;
147a9095
WD
674+ case 'n':
675+ mflags |= MATCHFLG_NO_INHERIT;
2e064775 676+ break;
147a9095
WD
677+ case 's':
678+ mflags |= MATCHFLG_WORD_SPLIT;
2e064775 679+ break;
d34d9fad 680+ }
a55d21aa 681+ }
6e313719
WD
682+ if (*s)
683+ s++;
147a9095
WD
684+ } else if (!(xflags & XFLG_NO_PREFIXES)
685 && (*s == '-' || *s == '+') && s[1] == ' ') {
686 if (*s == '+')
687 mflags |= MATCHFLG_INCLUDE;
688 s += 2;
0c7d1fd8
WD
689 } else if (xflags & XFLG_DEF_INCLUDE)
690 mflags |= MATCHFLG_INCLUDE;
147a9095 691+
2e064775 692 if (xflags & XFLG_DIRECTORY)
147a9095
WD
693 mflags |= MATCHFLG_DIRECTORY;
694
695@@ -274,9 +696,20 @@ static const char *get_exclude_tok(const
6e313719
WD
696 } else
697 len = strlen(s);
40e20a69 698
147a9095
WD
699+ if (add_dot_cvsinore && !len) {
700+ s = ".cvsignore";
701+ len = 10;
702+ } else if (!len && *p) {
703+ rprintf(FERROR, "truncated filter command: %s\n", p);
704+ exit_cleanup(RERR_SYNTAX);
6e313719
WD
705+ }
706+
5388f859 707 if (*p == '!' && len == 1)
40e20a69
WD
708 mflags |= MATCHFLG_CLEAR_LIST;
709+ if (xflags & XFLG_ABS_PATH)
710+ mflags |= MATCHFLG_ABS_PATH;
711
147a9095 712+ all_done:
40e20a69
WD
713 *len_ptr = len;
714 *flag_ptr = mflags;
147a9095
WD
715 return (const char *)s;
716@@ -287,7 +720,7 @@ void add_exclude(struct exclude_list_str
45795ec6
WD
717 int xflags)
718 {
719 unsigned int pat_len, mflags;
720- const char *cp;
721+ const char *cp, *p;
722
723 if (!pattern)
724 return;
147a9095 725@@ -295,9 +728,15 @@ void add_exclude(struct exclude_list_str
045caa90
WD
726 cp = pattern;
727 pat_len = 0;
728 while (1) {
729+ /* Remember that the returned string is NOT '\0' terminated! */
730 cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags);
731 if (!pat_len)
732 break;
41ebea83
WD
733+ if (pat_len >= MAXPATHLEN) {
734+ rprintf(FERROR, "discarding over-long exclude: %s\n",
735+ cp);
736+ continue;
737+ }
738
739 if (mflags & MATCHFLG_CLEAR_LIST) {
740 if (verbose > 2) {
147a9095 741@@ -309,13 +748,39 @@ void add_exclude(struct exclude_list_str
0c7d1fd8
WD
742 continue;
743 }
a55d21aa 744
d34d9fad
WD
745- make_exclude(listp, cp, pat_len, mflags);
746-
747- if (verbose > 2) {
748- rprintf(FINFO, "[%s] add_exclude(%.*s, %s%sclude)\n",
749- who_am_i(), (int)pat_len, cp, listp->debug_type,
750- mflags & MATCHFLG_INCLUDE ? "in" : "ex");
524989ae 751+ if (mflags & MATCHFLG_MERGE_FILE) {
45795ec6 752+ unsigned int len = pat_len;
6e313719
WD
753+ if (mflags & MATCHFLG_EXCLUDE_SELF) {
754+ const char *name = strrchr(cp, '/');
755+ if (name)
756+ len -= ++name - cp;
757+ else
758+ name = cp;
759+ make_exclude(listp, name, len, 0);
760+ mflags &= ~MATCHFLG_EXCLUDE_SELF;
761+ len = pat_len;
762+ }
41ebea83 763+ if (mflags & MATCHFLG_PERDIR_MERGE) {
40e20a69 764+ if (parent_dirscan) {
45795ec6 765+ if (!(p = parse_merge_name(cp, &len, module_dirlen)))
41ebea83 766+ continue;
45795ec6 767+ make_exclude(listp, p, len, mflags);
d34d9fad
WD
768+ continue;
769+ }
41ebea83 770+ } else {
6e313719 771+ int flgs = XFLG_FATAL_ERRORS;
45795ec6 772+ if (!(p = parse_merge_name(cp, &len, 0)))
d34d9fad 773+ continue;
6e313719
WD
774+ if (mflags & MATCHFLG_INCLUDE)
775+ flgs |= XFLG_DEF_INCLUDE;
147a9095
WD
776+ else if (mflags & MATCHFLG_NO_PREFIXES)
777+ flgs |= XFLG_DEF_EXCLUDE;
6e313719 778+ add_exclude_file(listp, p, flgs);
41ebea83 779+ continue;
0c7d1fd8 780+ }
a55d21aa 781 }
d34d9fad
WD
782+
783+ make_exclude(listp, cp, pat_len, mflags);
0c7d1fd8 784 }
d34d9fad
WD
785 }
786
147a9095 787@@ -324,7 +789,7 @@ void add_exclude_file(struct exclude_lis
41ebea83
WD
788 int xflags)
789 {
790 FILE *fp;
791- char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
147a9095 792+ char line[MAXPATHLEN+11]; /* Room for prefix chars and trailing slash. */
41ebea83
WD
793 char *eob = line + sizeof line - 1;
794 int word_split = xflags & XFLG_WORD_SPLIT;
795
147a9095 796@@ -338,13 +803,19 @@ void add_exclude_file(struct exclude_lis
6e313719
WD
797 if (!fp) {
798 if (xflags & XFLG_FATAL_ERRORS) {
799 rsyserr(FERROR, errno,
800- "failed to open %s file %s",
801- xflags & XFLG_DEF_INCLUDE ? "include" : "exclude",
802+ "failed to open %sclude file %s",
803+ xflags & XFLG_DEF_INCLUDE ? "in" : "ex",
804 fname);
805 exit_cleanup(RERR_FILEIO);
45795ec6 806 }
c4e46f36
WD
807 return;
808 }
45795ec6
WD
809+ dirbuf[dirbuf_len] = '\0';
810+
c4e46f36 811+ if (verbose > 2) {
1e476835
WD
812+ rprintf(FINFO, "[%s] add_exclude_file(%s,%d)\n",
813+ who_am_i(), fname, xflags);
c4e46f36 814+ }
45795ec6 815
c4e46f36
WD
816 while (1) {
817 char *s = line;
147a9095
WD
818@@ -388,7 +859,7 @@ void send_exclude_list(int f)
819 * FIXME: This pattern shows up in the output of
820 * report_exclude_result(), which is not ideal. */
821 if (list_only && !recurse)
822- add_exclude(&exclude_list, "/*/*", 0);
823+ add_exclude(&exclude_list, "/*/*", XFLG_DEF_EXCLUDE);
824
825 for (ent = exclude_list.head; ent; ent = ent->next) {
826 unsigned int l;
827@@ -402,10 +873,33 @@ void send_exclude_list(int f)
2e064775
WD
828 p[l] = '\0';
829 }
830
831- if (ent->match_flags & MATCHFLG_INCLUDE) {
147a9095 832+ if (ent->match_flags & MATCHFLG_PERDIR_MERGE) {
41ebea83 833+ char buf[32], *op = buf;
147a9095
WD
834+ if (protocol_version < 29) {
835+ rprintf(FERROR, "remote rsync is too old to understand per-directory filter files.\n");
836+ exit_cleanup(RERR_SYNTAX);
837+ }
838+ *op++ = ':';
839+ if (ent->match_flags & MATCHFLG_WORD_SPLIT)
840+ *op++ = 's';
841+ if (ent->match_flags & MATCHFLG_NO_INHERIT)
842+ *op++ = 'n';
843+ if (ent->match_flags & MATCHFLG_EXCLUDE_SELF)
844+ *op++ = 'e';
845+ if (ent->match_flags & MATCHFLG_NO_PREFIXES) {
846+ if (ent->match_flags & MATCHFLG_INCLUDE)
847+ *op++ = '+';
848+ else
849+ *op++ = '-';
850+ }
2e064775 851+ *op++ = ' ';
41ebea83
WD
852+ write_int(f, l + (op - buf));
853+ write_buf(f, buf, op - buf);
2e064775 854+ } else if (ent->match_flags & MATCHFLG_INCLUDE) {
a55d21aa 855 write_int(f, l + 2);
2e064775 856 write_buf(f, "+ ", 2);
147a9095
WD
857- } else if (*p == '-' || *p == '+') {
858+ } else if (protocol_version >= 29
859+ || ((*p == '-' || *p == '+') && p[1] == ' ')) {
860 write_int(f, l + 2);
861 write_buf(f, "- ", 2);
862 } else
863@@ -419,14 +913,15 @@ void send_exclude_list(int f)
2e064775
WD
864
865 void recv_exclude_list(int f)
866 {
867- char line[MAXPATHLEN+3]; /* Room for "x " prefix and trailing slash. */
147a9095
WD
868+ char line[MAXPATHLEN+11]; /* Room for prefix and trailing slash. */
869+ unsigned int xflags = protocol_version >= 29 ? 0 : XFLG_DEF_EXCLUDE;
2e064775
WD
870 unsigned int l;
871
872 while ((l = read_int(f)) != 0) {
147a9095
WD
873 if (l >= sizeof line)
874 overflow("recv_exclude_list");
875 read_sbuf(f, line, l);
876- add_exclude(&exclude_list, line, 0);
877+ add_exclude(&exclude_list, line, xflags);
878 }
879 }
880
881@@ -443,18 +938,18 @@ static char default_cvsignore[] =
882
883 void add_cvs_excludes(void)
884 {
885+ static unsigned int cvs_flags = XFLG_WORD_SPLIT | XFLG_NO_PREFIXES
886+ | XFLG_DEF_EXCLUDE;
a55d21aa
WD
887 char fname[MAXPATHLEN];
888 char *p;
889
147a9095
WD
890- add_exclude(&exclude_list, default_cvsignore,
891- XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
892+ add_exclude(&exclude_list, ":C", 0);
893+ add_exclude(&exclude_list, default_cvsignore, cvs_flags);
a55d21aa 894
147a9095
WD
895 if ((p = getenv("HOME"))
896 && pathjoin(fname, sizeof fname, p, ".cvsignore") < sizeof fname) {
897- add_exclude_file(&exclude_list, fname,
898- XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
899+ add_exclude_file(&exclude_list, fname, cvs_flags);
900 }
901
902- add_exclude(&exclude_list, getenv("CVSIGNORE"),
903- XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
904+ add_exclude(&exclude_list, getenv("CVSIGNORE"), cvs_flags);
905 }
37da98ae 906--- orig/flist.c 2005-01-01 21:11:00
20f8d513 907+++ flist.c 2004-08-12 18:59:28
a6587818 908@@ -40,10 +40,9 @@ extern int module_id;
a55d21aa
WD
909 extern int ignore_errors;
910 extern int numeric_ids;
911
912-extern int cvs_exclude;
913-
914 extern int recurse;
915 extern char curr_dir[MAXPATHLEN];
d34d9fad 916+extern unsigned int curr_dir_len;
a55d21aa 917 extern char *files_from;
d34d9fad
WD
918 extern int filesfrom_fd;
919
a6587818 920@@ -67,7 +66,6 @@ extern int list_only;
a55d21aa
WD
921
922 extern struct exclude_list_struct exclude_list;
923 extern struct exclude_list_struct server_exclude_list;
924-extern struct exclude_list_struct local_exclude_list;
925
926 int io_error;
927
a6587818 928@@ -223,8 +221,6 @@ int link_stat(const char *path, STRUCT_S
a55d21aa
WD
929 */
930 static int check_exclude_file(char *fname, int is_dir, int exclude_level)
931 {
932- int rc;
933-
934 #if 0 /* This currently never happens, so avoid a useless compare. */
935 if (exclude_level == NO_EXCLUDES)
936 return 0;
a6587818 937@@ -246,10 +242,7 @@ static int check_exclude_file(char *fnam
a55d21aa
WD
938 if (exclude_level != ALL_EXCLUDES)
939 return 0;
940 if (exclude_list.head
941- && (rc = check_exclude(&exclude_list, fname, is_dir)) != 0)
942- return rc < 0;
943- if (local_exclude_list.head
944- && check_exclude(&local_exclude_list, fname, is_dir) < 0)
945+ && check_exclude(&exclude_list, fname, is_dir) < 0)
946 return 1;
947 return 0;
948 }
37da98ae 949@@ -983,15 +976,7 @@ void send_file_name(int f, struct file_l
a55d21aa
WD
950
951 if (recursive && S_ISDIR(file->mode)
952 && !(file->flags & FLAG_MOUNT_POINT)) {
953- struct exclude_list_struct last_list = local_exclude_list;
954- local_exclude_list.head = local_exclude_list.tail = NULL;
955 send_directory(f, flist, f_name_to(file, fbuf));
7cb7ae4e
WD
956- if (verbose > 2) {
957- rprintf(FINFO, "[%s] popping %sexclude list\n",
958- who_am_i(), local_exclude_list.debug_type);
959- }
d8af8661 960- clear_exclude_list(&local_exclude_list);
a55d21aa
WD
961- local_exclude_list = last_list;
962 }
963 }
964
37da98ae 965@@ -1002,6 +987,7 @@ static void send_directory(int f, struct
a55d21aa
WD
966 struct dirent *di;
967 char fname[MAXPATHLEN];
968 unsigned int offset;
969+ void *save_excludes;
970 char *p;
971
972 d = opendir(dir);
37da98ae 973@@ -1025,18 +1011,7 @@ static void send_directory(int f, struct
a55d21aa
WD
974 offset++;
975 }
976
977- if (cvs_exclude) {
978- if (strlcpy(p, ".cvsignore", MAXPATHLEN - offset)
979- < MAXPATHLEN - offset) {
980- add_exclude_file(&local_exclude_list, fname,
ee1af13c 981- XFLG_WORD_SPLIT | XFLG_WORDS_ONLY);
a55d21aa
WD
982- } else {
983- io_error |= IOERR_GENERAL;
984- rprintf(FINFO,
985- "cannot cvs-exclude in long-named directory %s\n",
986- full_fname(fname));
987- }
045caa90 988- }
045caa90
WD
989+ save_excludes = push_local_excludes(fname, offset);
990
a55d21aa
WD
991 for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
992 char *dname = d_name(di);
37da98ae 993@@ -1057,6 +1032,8 @@ static void send_directory(int f, struct
bc95f62b 994 rsyserr(FERROR, errno, "readdir(%s)", dir);
a55d21aa 995 }
a55d21aa 996
eabda998
WD
997+ pop_local_excludes(save_excludes);
998+
a55d21aa
WD
999 closedir(d);
1000 }
eabda998 1001
37da98ae 1002@@ -1076,6 +1053,7 @@ struct file_list *send_file_list(int f,
d34d9fad
WD
1003 char *p, *dir, olddir[sizeof curr_dir];
1004 char lastpath[MAXPATHLEN] = "";
1005 struct file_list *flist;
45795ec6 1006+ BOOL need_first_push = True;
d34d9fad
WD
1007 int64 start_write;
1008 int use_ff_fd = 0;
1009
37da98ae 1010@@ -1096,6 +1074,10 @@ struct file_list *send_file_list(int f,
d34d9fad
WD
1011 exit_cleanup(RERR_FILESELECT);
1012 }
1013 use_ff_fd = 1;
1014+ if (curr_dir_len < MAXPATHLEN - 1) {
40e20a69 1015+ push_local_excludes(curr_dir, curr_dir_len);
45795ec6 1016+ need_first_push = False;
1e476835 1017+ }
d34d9fad
WD
1018 }
1019 }
1020
37da98ae 1021@@ -1126,6 +1108,15 @@ struct file_list *send_file_list(int f,
d34d9fad
WD
1022 }
1023 }
1024
45795ec6 1025+ if (need_first_push) {
d34d9fad 1026+ if ((p = strrchr(fname, '/')) != NULL) {
45795ec6
WD
1027+ if (*++p && strcmp(p, ".") != 0)
1028+ push_local_excludes(fname, p - fname);
1029+ } else if (strcmp(fname, ".") != 0)
1030+ push_local_excludes(fname, 0);
1031+ need_first_push = False;
d34d9fad 1032+ }
1e476835 1033+
d34d9fad
WD
1034 if (link_stat(fname, &st, keep_dirlinks) != 0) {
1035 if (f != -1) {
1036 io_error |= IOERR_GENERAL;
147a9095
WD
1037--- orig/loadparm.c 2005-01-01 21:11:00
1038+++ loadparm.c 2005-01-16 19:48:52
1039@@ -133,6 +133,7 @@ typedef struct
1040 char *auth_users;
1041 char *secrets_file;
1042 BOOL strict_modes;
1043+ char *filter;
1044 char *exclude;
1045 char *exclude_from;
1046 char *include;
1047@@ -175,6 +176,7 @@ static service sDefault =
1048 NULL, /* auth users */
1049 NULL, /* secrets file */
1050 True, /* strict modes */
1051+ NULL, /* filter */
1052 NULL, /* exclude */
1053 NULL, /* exclude from */
1054 NULL, /* include */
1055@@ -294,6 +296,7 @@ static struct parm_struct parm_table[] =
1056 {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
1057 {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
1058 {"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes,NULL, 0},
1059+ {"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL, 0},
1060 {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0},
1061 {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0},
1062 {"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0},
1063@@ -378,6 +381,7 @@ FN_LOCAL_STRING(lp_hosts_deny, hosts_den
1064 FN_LOCAL_STRING(lp_auth_users, auth_users)
1065 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
1066 FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
1067+FN_LOCAL_STRING(lp_filter, filter)
1068 FN_LOCAL_STRING(lp_exclude, exclude)
1069 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
1070 FN_LOCAL_STRING(lp_include, include)
6e313719 1071--- orig/options.c 2005-01-15 21:23:15
147a9095 1072+++ options.c 2005-01-16 23:34:15
6e313719
WD
1073@@ -144,6 +144,7 @@ int list_only = 0;
1074 char *batch_name = NULL;
1075
1076 static int daemon_opt; /* sets am_daemon after option error-reporting */
147a9095 1077+static int F_option_cnt = 0;
6e313719
WD
1078 static int modify_window_set;
1079 static char *dest_option = NULL;
1080 static char *max_size_arg;
147a9095
WD
1081@@ -291,6 +292,9 @@ void usage(enum logcode F)
1082 rprintf(F," -P equivalent to --partial --progress\n");
1083 rprintf(F," -z, --compress compress file data\n");
1084 rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
1085+ rprintf(F," -f, --filter=RULE add a file-filtering RULE\n");
1086+ rprintf(F," -F same as --filter=': /.rsync-rules'\n");
1087+ rprintf(F," repeated: --filter='- .rsync-rules'\n");
1088 rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n");
6e313719 1089 rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n");
40e20a69 1090 rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n");
147a9095
WD
1091@@ -320,7 +324,7 @@ void usage(enum logcode F)
1092 }
1093
1094 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
1095- OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED,
1096+ OPT_FILTER, OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED,
1097 OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST,
1098 OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
1099 OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
1100@@ -343,6 +347,7 @@ static struct poptOption long_options[]
1101 {"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED, 0, 0 },
1102 {"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 },
1103 {"numeric-ids", 0, POPT_ARG_NONE, &numeric_ids, 0, 0, 0 },
1104+ {"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
1105 {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
1106 {"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 },
1107 {"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 },
1108@@ -393,6 +398,7 @@ static struct poptOption long_options[]
d34d9fad
WD
1109 {"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
1110 {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
1111 {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
147a9095 1112+ {0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 },
5388f859 1113 {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
37da98ae 1114 {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
5388f859 1115 {"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 },
147a9095
WD
1116@@ -622,10 +628,15 @@ int parse_arguments(int *argc, const cha
1117 delete_mode = 1;
1118 break;
1119
1120- case OPT_EXCLUDE:
1121+ case OPT_FILTER:
1122 add_exclude(&exclude_list, poptGetOptArg(pc), 0);
1123 break;
1124
1125+ case OPT_EXCLUDE:
1126+ add_exclude(&exclude_list, poptGetOptArg(pc),
1127+ XFLG_DEF_EXCLUDE);
1128+ break;
1129+
1130 case OPT_INCLUDE:
1131 add_exclude(&exclude_list, poptGetOptArg(pc),
1132 XFLG_DEF_INCLUDE);
1133@@ -643,8 +654,8 @@ int parse_arguments(int *argc, const cha
1134 goto options_rejected;
1135 }
1136 add_exclude_file(&exclude_list, arg, XFLG_FATAL_ERRORS
1137- | (opt == OPT_INCLUDE_FROM
1138- ? XFLG_DEF_INCLUDE : 0));
1139+ | (opt == OPT_INCLUDE_FROM ? XFLG_DEF_INCLUDE
1140+ : XFLG_DEF_EXCLUDE));
1141 break;
1142
1143 case 'h':
1144@@ -668,6 +679,19 @@ int parse_arguments(int *argc, const cha
d34d9fad
WD
1145 am_sender = 1;
1146 break;
1147
147a9095
WD
1148+ case 'F':
1149+ switch (++F_option_cnt) {
6e313719
WD
1150+ case 1:
1151+ add_exclude(&exclude_list,
147a9095 1152+ ": /.rsync-rules", 0);
6e313719
WD
1153+ break;
1154+ case 2:
1155+ add_exclude(&exclude_list,
147a9095 1156+ "- .rsync-rules", 0);
6e313719
WD
1157+ break;
1158+ }
d34d9fad 1159+ break;
1e476835 1160+
d34d9fad
WD
1161 case 'P':
1162 do_progress = 1;
1163 keep_partial = 1;
147a9095
WD
1164@@ -972,7 +996,7 @@ int parse_arguments(int *argc, const cha
1165 partial_dir = NULL;
1166 else if (*partial_dir != '/') {
1167 add_exclude(&exclude_list, partial_dir,
1168- XFLG_DIRECTORY);
1169+ XFLG_DIRECTORY | XFLG_DEF_EXCLUDE);
1170 }
1171 keep_partial = 1;
1172 }
6e313719 1173--- orig/rsync.h 2005-01-15 21:18:09
147a9095
WD
1174+++ rsync.h 2005-01-17 00:16:04
1175@@ -62,7 +62,7 @@
1176 #define FLAG_MOUNT_POINT (1<<2) /* sender only */
1177
1178 /* update this if you make incompatible changes */
1179-#define PROTOCOL_VERSION 28
1180+#define PROTOCOL_VERSION 29
1181
1182 /* We refuse to interoperate with versions that are not in this range.
1183 * Note that we assume we'll work with later versions: the onus is on
1184@@ -108,9 +108,11 @@
1185
1186 #define XFLG_FATAL_ERRORS (1<<0)
1187 #define XFLG_DEF_INCLUDE (1<<1)
1188-#define XFLG_WORDS_ONLY (1<<2)
1189+#define XFLG_NO_PREFIXES (1<<2)
40e20a69 1190 #define XFLG_WORD_SPLIT (1<<3)
a60267ab
WD
1191 #define XFLG_DIRECTORY (1<<4)
1192+#define XFLG_ABS_PATH (1<<5)
147a9095 1193+#define XFLG_DEF_EXCLUDE (1<<6)
40e20a69
WD
1194
1195 #define PERMS_REPORT (1<<0)
1196 #define PERMS_SKIP_MTIME (1<<1)
147a9095 1197@@ -512,11 +514,21 @@ struct map_struct {
0c7d1fd8
WD
1198 #define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
1199 #define MATCHFLG_DIRECTORY (1<<5) /* this matches only directories */
1200 #define MATCHFLG_CLEAR_LIST (1<<6) /* this item is the "!" token */
524989ae 1201+#define MATCHFLG_MERGE_FILE (1<<7) /* specifies a file to merge */
147a9095 1202+#define MATCHFLG_NO_INHERIT (1<<8) /* don't inherit these rules */
40e20a69
WD
1203+#define MATCHFLG_PERDIR_MERGE (1<<9) /* merge-file is searched per-dir */
1204+#define MATCHFLG_FINISH_SETUP (1<<10)/* per-dir merge file needs setup */
6e313719 1205+#define MATCHFLG_EXCLUDE_SELF (1<<11)/* merge-file name should be excluded */
147a9095
WD
1206+#define MATCHFLG_NO_PREFIXES (1<<12)/* parse no prefixes from patterns */
1207+#define MATCHFLG_WORD_SPLIT (1<<13)/* spilt on whitespace */
a55d21aa
WD
1208 struct exclude_struct {
1209 struct exclude_struct *next;
1210 char *pattern;
0c7d1fd8 1211 unsigned int match_flags;
bc95f62b 1212- int slash_cnt;
bc95f62b
WD
1213+ union {
1214+ int slash_cnt;
eabda998 1215+ struct exclude_list_struct *mergelist;
bc95f62b 1216+ } u;
a55d21aa
WD
1217 };
1218
1219 struct exclude_list_struct {
2e064775 1220--- orig/rsync.yo 2005-01-15 04:36:32
147a9095
WD
1221+++ rsync.yo 2005-01-16 22:49:57
1222@@ -361,6 +361,9 @@ verb(
1223 -P equivalent to --partial --progress
1224 -z, --compress compress file data
1225 -C, --cvs-exclude auto ignore files in the same way CVS does
1226+ -f, --filter=RULE add a file-filtering RULE
1227+ -F same as --filter=': /.rsync-rules'
1228+ repeated: --filter='- .rsync-rules'
1229 --exclude=PATTERN exclude files matching PATTERN
6e313719 1230 --exclude-from=FILE exclude patterns listed in FILE
1e476835 1231 --include=PATTERN don't exclude files matching PATTERN
147a9095
WD
1232@@ -754,14 +757,41 @@ Finally, any file is ignored if it is in
1233 .cvsignore file and matches one of the patterns listed therein.
1234 See the bf(cvs(1)) manual for more information.
1235
1236-dit(bf(--exclude=PATTERN)) This option allows you to selectively exclude
1237-certain files from the list of files to be transferred. This is most
1238-useful in combination with a recursive transfer.
1239+dit(bf(-f, --filter=RULE)) This option allows you to add rules to selectively
1240+exclude certain files from the list of files to be transferred. This is
1241+most useful in combination with a recursive transfer.
6e313719 1242
147a9095
WD
1243-You may use as many --exclude options on the command line as you like
1244+You may use as many --filter options on the command line as you like
1245 to build up the list of files to exclude.
1246
1247-See the EXCLUDE PATTERNS section for detailed information on this option.
1248+See the FILTER RULES section for detailed information on this option.
1249+
1250+dit(bf(-F)) The -F option is a shorthand for adding two --filter rules to
6e313719
WD
1251+your command. The first time it is used is a shorthand for this rule:
1252+
1253+verb(
147a9095 1254+ --filter=': /.rsync-rules'
6e313719
WD
1255+)
1256+
147a9095
WD
1257+This tells rsync to look for per-directory .rsync-rules files that have
1258+been sprinkled through the hierarchy and use their rules to filter the
1259+files in the transfer. If -F is repeated, it is a shorthand for this
1260+rule:
6e313719
WD
1261+
1262+verb(
147a9095 1263+ --filter='- .rsync-rules'
6e313719
WD
1264+)
1265+
147a9095 1266+This filters out the .rsync-rules files themselves from the transfer.
6e313719 1267+
147a9095
WD
1268+See the FILTER RULES section for detailed information on how these options
1269+work.
1270+
1271+dit(bf(--exclude=PATTERN)) This option is a simplified form of the
1272+--filter option that defaults to an exclude rule and does not allow
1273+the full rule-parsing syntax of normal filter rules.
1274+
1275+See the FILTER RULES section for detailed information on this option.
1276
1277 dit(bf(--exclude-from=FILE)) This option is similar to the --exclude
1278 option, but instead it adds all exclude patterns listed in the file
1279@@ -769,11 +799,11 @@ FILE to the exclude list. Blank lines i
1280 ';' or '#' are ignored.
1281 If em(FILE) is bf(-) the list will be read from standard input.
5f98a4b1 1282
147a9095
WD
1283-dit(bf(--include=PATTERN)) This option tells rsync to not exclude the
1284-specified pattern of filenames. This is useful as it allows you to
1285-build up quite complex exclude/include rules.
1286+dit(bf(--include=PATTERN)) This option is a simplified form of the
1287+--filter option that defaults to an include rule and does not allow
1288+the full rule-parsing syntax of normal filter rules.
1289
1290-See the EXCLUDE PATTERNS section for detailed information on this option.
1291+See the FILTER RULES section for detailed information on this option.
1292
1293 dit(bf(--include-from=FILE)) This specifies a list of include patterns
1294 from a file.
1295@@ -818,7 +848,8 @@ was located on the remote "src" host.
1296
1297 dit(bf(-0, --from0)) This tells rsync that the filenames it reads from a
1298 file are terminated by a null ('\0') character, not a NL, CR, or CR+LF.
1299-This affects --exclude-from, --include-from, and --files-from.
1300+This affects --exclude-from, --include-from, --files-from, and any
1301+merged files specified in a --filter rule.
1302 It does not affect --cvs-exclude (since all names read from a .cvsignore
1303 file are split on whitespace).
1304
1305@@ -957,8 +988,8 @@ If the partial-dir value is not an absol
1306 will prevent partial-dir files from being transferred and also prevent the
1307 untimely deletion of partial-dir items on the receiving side. An example:
1308 the above --partial-dir option would add an "--exclude=.rsync-partial/"
1309-rule at the end of any other include/exclude rules. Note that if you are
1310-supplying your own include/exclude rules, you may need to manually insert a
1311+rule at the end of any other filter rules. Note that if you are
1312+supplying your own filter rules, you may need to manually insert a
1313 rule for this directory exclusion somewhere higher up in the list so that
1314 it has a high enough priority to be effective (e.g., if your rules specify
1315 a trailing --exclude=* rule, the auto-added rule will be ineffective).
1316@@ -1108,30 +1139,310 @@ page describing the options available fo
1317
1318 enddit()
1319
1320-manpagesection(EXCLUDE PATTERNS)
1321-
1322-The exclude and include patterns specified to rsync allow for flexible
1323-selection of which files to transfer and which files to skip.
1324+manpagesection(FILTER RULES)
1325
1326-Rsync builds an ordered list of include/exclude options as specified on
5f98a4b1
WD
1327-the command line. Rsync checks each file and directory
1328-name against each exclude/include pattern in turn. The first matching
147a9095
WD
1329-pattern is acted on. If it is an exclude pattern, then that file is
1330-skipped. If it is an include pattern then that filename is not
1331-skipped. If no matching include/exclude pattern is found then the
1332+The filter rules allow for flexible selection of which files to transfer
1333+(include) and which files to skip (exclude). The rules either directly
1334+specify include/exclude patterns or they specify a way to acquire more
1335+include/exclude patterns (e.g. to read them from a file).
5f98a4b1
WD
1336+
1337+As the list of files/directories to transfer is built, rsync checks each
147a9095
WD
1338+name to be transferred against the list of include/exclude patterns in
1339+turn, and t first matching pattern is acted on: if it is an exclude
1340+pattern, then that file is skipped; if it is an include pattern then that
1341+filename is not skipped; if no matching pattern is found, then the
5f98a4b1
WD
1342 filename is not skipped.
1343
1344-The filenames matched against the exclude/include patterns are relative
1345-to the "root of the transfer". If you think of the transfer as a
85c7c40a
WD
1346-subtree of names that are being sent from sender to receiver, the root
1347-is where the tree starts to be duplicated in the destination directory.
1348-This root governs where patterns that start with a / match (see below).
147a9095
WD
1349+Rsync builds an ordered list of filter rules as specified on the
1350+command-line. Filter rules have the following syntax:
1351+
1352+itemize(
1353+ it() x RULE
1354+ it() x=RULE
1355+ it() xMODIFIERS RULE
1356+ it() xMODIFIERS=RULE
1357+ it() !
1358+)
1359+
1360+The 'x' is a single-letter that specifies the kind of rule to create. It
1361+can have trailing options, and is separated from the RULE by either a
1362+single space or an equal-sign. Here are the available rules:
1363+
1364+verb(
1365+ - specifies an exclude pattern.
1366+ + specifies an include pattern.
1367+ . specifies a merge-file to read for more rules.
1368+ : specifies a per-directory merge-file.
1369+ ! clears the current include/exclude list
1370+)
1371+
1372+Note that the include/exclude command-line options do not allow the full
1373+range of rule parsing as described above -- they only allow the
1374+specification of include/exclude patterns and the "!" token (not to
1375+mention the comment lines when reading rules from a file). If a pattern
1376+does not begin with "- " (dash, space) or "+ " (plus, space), then the
1377+rule will be interpreted as if "+ " (for an include option) or "- " (for
1378+an exclude option) were prefixed to the string, and the resulting rule
1379+passed to the --filter option.
1380+
1381+Note also that the --filter, --include, and --exclude options take one
1382+rule/pattern each. To add multiple ones, you can repeat the options on
1383+the command-line, use the merge-file syntax of the --filter option, or
1384+the --include-from/--exclude-from options.
1385+
1386+manpagesection(INCLUDE/EXCLUDE PATTERN RULES)
1387+
1388+You can include and exclude files by specifing patterns using the "+" and
1389+"-" filter rules (as introduced in the FILTER RULES section above). These
1390+rules specify a pattern that is matched against the names of the files
1391+that are going to be transferred. These patterns can take several forms:
1392+
1393+itemize(
1394+
5f98a4b1
WD
1395+ it() if the pattern starts with a / then it is anchored to a
1396+ particular spot in the hierarchy of files, otherwise it is matched
1397+ against the end of the pathname. This is similar to a leading ^ in
1398+ regular expressions.
1399+ Thus "/foo" would match a file called "foo" at either the "root of the
85c7c40a 1400+ transfer" (for a global rule) or in the merge-file's directory (for a
5f98a4b1
WD
1401+ per-directory rule).
1402+ An unqualified "foo" would match any file or directory named "foo"
147a9095 1403+ anywhere in the tree because the algorithm is applied recursively from
5f98a4b1 1404+ the
147a9095 1405+ top down; it behaves as if each path component gets a turn at being the
5f98a4b1
WD
1406+ end of the file name. Even the unanchored "sub/foo" would match at
1407+ any point in the hierarchy where a "foo" was found within a directory
147a9095
WD
1408+ named "sub". See the section on ANCHORING INCLUDE/EXCLUDE PATTERNS for
1409+ a full discussion of how to specify a pattern that matches at the root
1410+ of the transfer.
2e064775 1411+
147a9095
WD
1412+ it() if the pattern ends with a / then it will only match a
1413+ directory, not a file, link, or device.
2e064775 1414+
147a9095
WD
1415+ it() if the pattern contains a wildcard character from the set
1416+ *?[ then expression matching is applied using the shell filename
1417+ matching rules. Otherwise a simple string match is used.
2e064775 1418+
147a9095
WD
1419+ it() the double asterisk pattern "**" will match slashes while a
1420+ single asterisk pattern "*" will stop at slashes.
2e064775 1421+
147a9095
WD
1422+ it() if the pattern contains a / (not counting a trailing /) or a "**"
1423+ then it is matched against the full pathname, including any leading
1424+ directories. If the pattern doesn't contain a / or a "**", then it is
1425+ matched only against the final component of the filename. Again,
1426+ remember that the algorithm is applied recursively so "full filename" can
1427+ actually be any portion of a path below the starting directory.
2e064775 1428+
147a9095 1429+)
2e064775 1430+
147a9095
WD
1431+Note that, when using the --recursive (-r) option (which is implied by
1432+-a), every subcomponent of every path is visited from the top down, so
1433+include/exclude patterns get applied recursively to each subcomponent.
1434+The exclude patterns actually short-circuit the directory traversal stage
1435+when rsync finds the files to send. If a pattern excludes a particular
1436+parent directory, it can render a deeper include pattern ineffectual
1437+because rsync did not descend through that excluded section of the
1438+hierarchy. This is particularly important when using a trailing '*' rule.
1439+For instance, this won't work:
6e313719 1440+
147a9095
WD
1441+verb(
1442+ + /some/path/this-file-will-not-be-found
1443+ + /file-is-included
1444+ - *
1445+)
6e313719 1446+
147a9095
WD
1447+This fails because the parent directory "some" is excluded by the '*'
1448+rule, so rsync never visits any of the files in the "some" or "some/path"
1449+directories. One solution is to ask for all directories in the hierarchy
1450+to be included by using a single rule: "+ */" (put it somewhere before the
1451+"- *" rule). Another solution is to add specific include rules for all
1452+the parent dirs that need to be visited. For instance, this set of rules
1453+works fine:
2e064775 1454+
147a9095
WD
1455+verb(
1456+ + /some/
1457+ + /some/path/
1458+ + /some/path/this-file-is-found
1459+ + /file-also-included
1460+ - *
1461+)
6e313719 1462+
147a9095
WD
1463+Here are some examples of exclude/include matching:
1464+
1465+itemize(
1466+ it() "- *.o" would exclude all filenames matching *.o
1467+ it() "- /foo" would exclude a file called foo in the transfer-root directory
1468+ it() "- foo/" would exclude any directory called foo
1469+ it() "- /foo/*/bar" would exclude any file called bar two
1470+ levels below a directory called foo in the transfer-root directory
1471+ it() "- /foo/**/bar" would exclude any file called bar two
1472+ or more levels below a directory called foo in the transfer-root directory
1473+ it() The combination of "+ */", "+ *.c", and "- *" would include all
1474+ directories and C source files but nothing else.
1475+ it() The combination of "+ foo/", "+ foo/bar.c", and "- *" would include
5f98a4b1
WD
1476+ only the foo directory and foo/bar.c (the foo directory must be
1477+ explicitly included or it would be excluded by the "*")
1478+)
1479+
147a9095
WD
1480+manpagesection(MERGE-FILE FILTER RULES)
1481+
1482+You can merge whole files into your filter rules by specifying either a
1483+"." or a ":" filter rule (as introduced in the FILTER RULES section
1484+above).
524989ae 1485+
147a9095
WD
1486+There are two kinds of merged files -- single-instance ('.') and
1487+per-directory (':'). A single-instance merge file is read one time, and
1488+its rules are incorporated into the filter list in the place of the "."
1489+rule. For per-directory merge files, rsync will scan every directory that
1490+it traverses for the named file, merging its contents when the file exists
1491+into the current list of inherited rules. These per-directory rule files
1492+must be created on the sending side because it is the sending side that is
1493+being scanned for the available files to transfer. These rule files may
1494+also need to be transferred to the receiving side if you want them to
1495+affect what files don't get deleted (see PER-DIRECTORY RULES AND DELETE
1496+below).
1497+
1498+Some examples:
d34d9fad 1499+
2e064775 1500+verb(
147a9095
WD
1501+ . /etc/rsync/default.rules
1502+ : .per-dir-rules
1503+ :n- .non-inherited-per-dir-excludes
2e064775 1504+)
d34d9fad 1505+
147a9095 1506+The following modifiers are accepted after the "." or ":":
5f98a4b1 1507+
147a9095
WD
1508+itemize(
1509+ it() A "-" or "+" specifies that the file should consist of only
1510+ exclude (-) or include (+) patterns, with no other rule-parsing except
1511+ for the list-clearing token ("!").
1512+
1513+ it() A "C" is a shorthand for the modifiers "sn-", which makes the
1514+ parsing compatible with the way CVS parses their exclude files. If no
1515+ filename is specified, ".cvsignore" is assumed.
85c7c40a 1516+
147a9095
WD
1517+ it() A "e" will exclude the merge-file from the transfer; e.g.
1518+ ":e\ .rules" is like ":\ .rules" and "-\ .rules".
1519+
1520+ it() An "n" specifies that the rules are not inherited by subdirectories.
1521+
1522+ it() An "s" specifies that the rules are split on all whitespace instead
1523+ of the normal line-splitting. It also turns off comments.
1524+)
85c7c40a 1525+
147a9095
WD
1526+Per-directory rules are inherited in all subdirectories of the directory
1527+where the merge-file was found unless the 'n' modifier was used. Each
1528+subdirectory's rules are prefixed to the inherited per-directory rules
1529+from its parents, which gives the newest rules a higher priority than the
1530+inherited rules. The entire set of per-dir rules is grouped together in
1531+the spot where the merge-file was specified, so it is possible to override
1532+per-dir rules via a rule that got specified earlier in the list of global
1533+rules. When the list-clearing rule ("!") is read from a per-directory
1534+file, it only clears the inherited rules for the current merge file.
1535+
1536+Another way to prevent a single per-dir rule from being inherited is to
1537+anchor it with a leading slash. Anchored rules in a per-directory
1538+merge-file are relative to the merge-file's directory, so a pattern "/foo"
1539+would only match the file "foo" in the directory where the per-dir filter
1540+file was found.
1541+
1542+Here's an example filter file which you'd specify via --filter=". file":
524989ae
WD
1543+
1544+verb(
147a9095
WD
1545+ . /home/user/.global-rules
1546+ - *.gz
1547+ : .rules
524989ae 1548+ + *.[ch]
147a9095 1549+ - *.o
3d3aaf9f
WD
1550+)
1551+
147a9095
WD
1552+This will merge the contents of the /home/user/.global-rules file at the
1553+start of the list and also turns the ".rules" filename into a per-directory
1554+filter file. All rules read-in prior to the start of the directory scan
2e064775
WD
1555+follow the global anchoring rules (i.e. a leading slash matches at the root
1556+of the transfer).
524989ae 1557+
5f98a4b1 1558+If a per-directory merge-file is specified with a path that is a parent
d34d9fad
WD
1559+directory of the first transfer directory, rsync will scan all the parent
1560+dirs from that starting point to the transfer directory for the indicated
147a9095 1561+per-directory file. For instance, here is a common filter (see -F):
d34d9fad
WD
1562+
1563+verb(
147a9095 1564+ --filter=': /.rsync-rules'
d34d9fad
WD
1565+)
1566+
147a9095 1567+That rule tells rsync to scan for the file .rsync-rules in all
6e313719
WD
1568+directories from the root down through the parent directory of the
1569+transfer prior to the start of the normal directory scan of the file in
1570+the directories that are sent as a part of the transfer. (Note: for an
1571+rsync daemon, the root is always the same as the module's "path".)
41ebea83
WD
1572+
1573+Some examples of this pre-scanning for per-directory files:
d34d9fad
WD
1574+
1575+verb(
147a9095
WD
1576+ rsync -avF /src/path/ /dest/dir
1577+ rsync -av --filter=': ../../.rsync-rules' /src/path/ /dest/dir
1578+ rsync -av --fitler=': .rsync-rules' /src/path/ /dest/dir
d34d9fad 1579+)
1e476835 1580+
147a9095 1581+The first two commands above will look for ".rsync-rules" in "/" and
41ebea83 1582+"/src" before the normal scan begins looking for the file in "/src/path"
5f98a4b1 1583+and its subdirectories. The last command avoids the parent-dir scan
147a9095 1584+and only looks for the ".rsync-rules" files in each directory that is
5f98a4b1
WD
1585+a part of the transfer.
1586+
147a9095
WD
1587+If you want to include the contents of a ".cvsignore" in your patterns,
1588+you should use the rule ":C" -- this is a short-hand for the rule
1589+":sn-\ .cvsignore", and ensures that the .cvsignore file's contents are
1590+interpreted according to the same parsing rules that CVS uses. You can
1591+use this to affect where the --cvs-exclude (-C) option's inclusion of the
1592+per-directory .cvsignore file gets placed into your rules by putting a
1593+":C" wherever you like in your filter rules. Without this, rsync would
1594+add the per-dir rule for the .cvignore file at the end of all your other
1595+rules (giving it a lower priority than your command-line rules). For
1596+example:
5f98a4b1
WD
1597+
1598+verb(
147a9095 1599+ cat <<EOT | rsync -avC --filter='. -' a/ b
6e313719 1600+ + foo.o
147a9095
WD
1601+ :C
1602+ - *.old
1603+ EOT
6e313719 1604+
147a9095 1605+ rsync -avC --include=foo.o -f :C --exclude='*.old' a/ b
5f98a4b1
WD
1606+)
1607+
6e313719
WD
1608+Both of the above rsync commands are identical. Each one will merge all
1609+the per-directory .cvsignore rules in the middle of the list rather than
1610+at the end. This allows their dir-specific rules to supersede the rules
147a9095 1611+that follow the :C instead of being subservient to all your rules. (The
6e313719 1612+global rules taken from the $HOME/.cvsignore file and from $CVSIGNORE are
147a9095
WD
1613+not repositioned from their spot at the end of your rules, however -- feel
1614+free to manually include $HOME/.cvsignore elsewhere in your rules.)
524989ae 1615+
147a9095 1616+manpagesection(LIST-CLEARING FILTER RULE)
3d3aaf9f 1617+
147a9095
WD
1618+You can clear the current include/exclude list by using the "!" filter
1619+rule (as introduced in the FILTER RULES section above). The "current"
1620+list is either the global list of rules (if the rule is encountered while
1621+parsing the filter options) or a set of per-directory rules (which are
1622+inherited in their own sub-list, so a subdirectory can use this to clear
1623+out the parent's rules).
1624+
1625+manpagesection(ANCHORING INCLUDE/EXCLUDE PATTERNS)
3d3aaf9f 1626+
147a9095
WD
1627+As mentioned earlier, global include/exclude patterns are anchored at the
1628+"root of the transfer" (as opposed to per-directory patterns, which are
1629+anchored at the merge-file's directory). If you think of the transfer as
1630+a subtree of names that are being sent from sender to receiver, the
1631+transfer-root is where the tree starts to be duplicated in the destination
1632+directory. This root governs where patterns that start with a / match.
1633
1634 Because the matching is relative to the transfer-root, changing the
1635 trailing slash on a source path or changing your use of the --relative
1636 option affects the path you need to use in your matching (in addition to
1637 changing how much of the file tree is duplicated on the destination
1638-system). The following examples demonstrate this.
1639+host). The following examples demonstrate this.
1640
1641 Let's say that we want to match two source files, one with an absolute
1642 path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz".
1643@@ -1163,114 +1474,59 @@ verb(
1644 Target file: /dest/you/bar/baz
1645 )
1646
1647-The easiest way to see what name you should include/exclude is to just
1648+The easiest way to see what name you should filter is to just
1649 look at the output when using --verbose and put a / in front of the name
1650 (use the --dry-run option if you're not yet ready to copy any files).
1651
1652-Note that, when using the --recursive (-r) option (which is implied by -a),
1653-every subcomponent of
1654-every path is visited from the top down, so include/exclude patterns get
1655-applied recursively to each subcomponent.
1656-The exclude patterns actually short-circuit the directory traversal stage
1657-when rsync finds the files to send. If a pattern excludes a particular
1658-parent directory, it can render a deeper include pattern ineffectual
1659-because rsync did not descend through that excluded section of the
1660-hierarchy.
1661-
1662-Note also that the --include and --exclude options take one pattern
1663-each. To add multiple patterns use the --include-from and
1664---exclude-from options or multiple --include and --exclude options.
1665-
1666-The patterns can take several forms. The rules are:
1667-
1668-itemize(
1669-
1670- it() if the pattern starts with a / then it is matched against the
1671- start of the filename, otherwise it is matched against the end of
1672- the filename.
1673- This is the equivalent of a leading ^ in regular expressions.
1674- Thus "/foo" would match a file called "foo" at the transfer-root
1675- (see above for how this is different from the filesystem-root).
1676- On the other hand, "foo" would match any file called "foo"
1677- anywhere in the tree because the algorithm is applied recursively from
1678- top down; it behaves as if each path component gets a turn at being the
1679- end of the file name.
1680-
1681- it() if the pattern ends with a / then it will only match a
1682- directory, not a file, link, or device.
1683-
1684- it() if the pattern contains a wildcard character from the set
1685- *?[ then expression matching is applied using the shell filename
1686- matching rules. Otherwise a simple string match is used.
1687+manpagesection(PER-DIRECTORY RULES AND DELETE)
1688
1689- it() the double asterisk pattern "**" will match slashes while a
1690- single asterisk pattern "*" will stop at slashes.
1691+Without a delete option, per-directory rules are only relevant on the
1692+sending side, so you can feel free to exclude the merge files themselves
1693+without affecting the transfer. To make this easy, the 'e' modifier adds
1694+this exclude for you, as seen in these two equivalent commands:
1695
1696- it() if the pattern contains a / (not counting a trailing /) or a "**"
1697- then it is matched against the full filename, including any leading
1698- directory. If the pattern doesn't contain a / or a "**", then it is
1699- matched only against the final component of the filename. Again,
1700- remember that the algorithm is applied recursively so "full filename" can
1701- actually be any portion of a path below the starting directory.
3d3aaf9f 1702+verb(
147a9095
WD
1703+ rsync -av --filter=': .excl' --exclude=.excl host:src/dir /dest
1704+ rsync -av --filter=':e .excl' host:src/dir /dest
3d3aaf9f 1705+)
147a9095
WD
1706
1707- it() if the pattern starts with "+ " (a plus followed by a space)
1708- then it is always considered an include pattern, even if specified as
1709- part of an exclude option. The prefix is discarded before matching.
1710-
1711- it() if the pattern starts with "- " (a minus followed by a space)
1712- then it is always considered an exclude pattern, even if specified as
1713- part of an include option. The prefix is discarded before matching.
1714-
1715- it() if the pattern is a single exclamation mark ! then the current
1716- include/exclude list is reset, removing all previously defined patterns.
1717-)
1718-
1719-The +/- rules are most useful in a list that was read from a file, allowing
1720-you to have a single exclude list that contains both include and exclude
1721-options in the proper order.
1722-
1723-Remember that the matching occurs at every step in the traversal of the
1724-directory hierarchy, so you must be sure that all the parent directories of
1725-the files you want to include are not excluded. This is particularly
1726-important when using a trailing '*' rule. For instance, this won't work:
3d3aaf9f
WD
1727+However, if you want to do a delete on the receiving side AND you want some
1728+files to be excluded from being deleted, you'll need to be sure that the
1729+receiving side knows what files to exclude. The easiest way is to include
147a9095 1730+the per-directory merge files in the transfer and use --delete-after,
3d3aaf9f
WD
1731+because this ensures that the receiving side gets all the same exclude
1732+rules as the sending side before it tries to delete anything:
147a9095
WD
1733
1734 verb(
1735- + /some/path/this-file-will-not-be-found
1736- + /file-is-included
1737- - *
1738+ rsync -avF --delete-after host:src/dir /dest
1739 )
1740
1741-This fails because the parent directory "some" is excluded by the '*' rule,
1742-so rsync never visits any of the files in the "some" or "some/path"
1743-directories. One solution is to ask for all directories in the hierarchy
1744-to be included by using a single rule: --include='*/' (put it somewhere
1745-before the --exclude='*' rule). Another solution is to add specific
1746-include rules for all the parent dirs that need to be visited. For
1747-instance, this set of rules works fine:
6e313719
WD
1748+However, if the merge files are not a part of the transfer, you'll need to
1749+either specify some global exclude rules (i.e. specified on the command
1750+line), or you'll need to maintain your own per-directory merge files on
1751+the receiving side. An example of the first is this (assume that the
147a9095
WD
1752+remote .rules files exclude themselves):
1753
1754 verb(
1755- + /some/
1756- + /some/path/
1757- + /some/path/this-file-is-found
1758- + /file-also-included
1759- - *
1760+ rsync -av --filter=': .rules' --filter='. /my/extra.rules'
3d3aaf9f 1761+ --delete host:src/dir /dest
147a9095
WD
1762 )
1763
1764-Here are some examples of exclude/include matching:
3d3aaf9f 1765+In the above example the extra.rules file can affect both sides of the
147a9095
WD
1766+transfer, but (on the sending side) the rules are subservient to the rules
1767+merged from the .rules files because they were specified after the
1768+per-directory merge rule.
3d3aaf9f 1769+
147a9095
WD
1770+In one final example, the remote side is excluding the .rsync-rules
1771+files from the transfer, but we want to use our own .rsync-rules files
3d3aaf9f
WD
1772+to control what gets deleted on the receiving side. To do this we must
1773+specifically exclude the per-directory merge files (so that they don't get
1774+deleted) and then put rules into the local files to control what else
6e313719 1775+should not get deleted. Like one of these commands:
147a9095
WD
1776
1777-itemize(
1778- it() --exclude "*.o" would exclude all filenames matching *.o
1779- it() --exclude "/foo" would exclude a file called foo in the transfer-root directory
1780- it() --exclude "foo/" would exclude any directory called foo
1781- it() --exclude "/foo/*/bar" would exclude any file called bar two
1782- levels below a directory called foo in the transfer-root directory
1783- it() --exclude "/foo/**/bar" would exclude any file called bar two
1784- or more levels below a directory called foo in the transfer-root directory
1785- it() --include "*/" --include "*.c" --exclude "*" would include all
1786- directories and C source files
1787- it() --include "foo/" --include "foo/bar.c" --exclude "*" would include
1788- only foo/bar.c (the foo/ directory must be explicitly included or
1789- it would be excluded by the "*")
3d3aaf9f 1790+verb(
147a9095
WD
1791+ rsync -av --filter=':e /.rsync-rules' --delete host:src/dir /dest
1792+ rsync -avFF --delete host:src/dir /dest
3d3aaf9f 1793 )
524989ae 1794
3d3aaf9f 1795 manpagesection(BATCH MODE)
147a9095
WD
1796@@ -1439,7 +1695,7 @@ it. The most common cause is incorrectly
1797 scripts (such as .cshrc or .profile) that contain output statements
1798 for non-interactive logins.
1799
1800-If you are having trouble debugging include and exclude patterns, then
1801+If you are having trouble debugging filter patterns, then
1802 try specifying the -vv option. At this level of verbosity rsync will
1803 show why each individual file is included or excluded.
1804
13bed3dd 1805--- orig/testsuite/exclude.test 2004-05-29 21:25:45
147a9095 1806+++ testsuite/exclude.test 2005-01-17 00:15:40
c4e46f36 1807@@ -23,19 +23,47 @@ export HOME CVSIGNORE
7d31425d
WD
1808 makepath "$fromdir/foo/down/to/you"
1809 makepath "$fromdir/bar/down/to/foo/too"
1810 makepath "$fromdir/mid/for/foo/and/that/is/who"
c4e46f36 1811+cat >"$fromdir/.excl" <<EOF
147a9095
WD
1812+- .excl
1813+- *.bak
1814+- *.old
1815+- *.junk
c4e46f36 1816+EOF
7d31425d
WD
1817 echo kept >"$fromdir/foo/file1"
1818 echo removed >"$fromdir/foo/file2"
1819 echo cvsout >"$fromdir/foo/file2.old"
c4e46f36 1820+cat >"$fromdir/foo/.excl" <<EOF
7d31425d
WD
1821++ .excl
1822+- file1
c4e46f36
WD
1823+EOF
1824+cat >"$fromdir/bar/.excl" <<EOF
147a9095
WD
1825+- home-cvs-exclude
1826+: .excl2
7d31425d 1827++ to
c4e46f36 1828+EOF
7d31425d 1829 echo cvsout >"$fromdir/bar/down/to/home-cvs-exclude"
c4e46f36 1830+cat >"$fromdir/bar/down/to/.excl2" <<EOF
147a9095 1831+- .excl2
c4e46f36 1832+EOF
7d31425d
WD
1833 echo keeper >"$fromdir/bar/down/to/foo/file1"
1834 echo cvsout >"$fromdir/bar/down/to/foo/file1.bak"
1835 echo gone >"$fromdir/bar/down/to/foo/file3"
1836 echo lost >"$fromdir/bar/down/to/foo/file4"
1837 echo cvsout >"$fromdir/bar/down/to/foo/file4.junk"
1838 echo smashed >"$fromdir/bar/down/to/foo/to"
c4e46f36 1839+cat >"$fromdir/bar/down/to/foo/.excl2" <<EOF
7d31425d 1840++ *.junk
c4e46f36 1841+EOF
7d31425d 1842+# This one should be ineffectual
c4e46f36 1843+cat >"$fromdir/mid/.excl2" <<EOF
147a9095 1844+- extra
c4e46f36 1845+EOF
7d31425d
WD
1846 echo cvsout >"$fromdir/mid/one-in-one-out"
1847 echo one-in-one-out >"$fromdir/mid/.cvsignore"
1848 echo cvsin >"$fromdir/mid/one-for-all"
c4e46f36 1849+cat >"$fromdir/mid/.excl" <<EOF
147a9095 1850+:C
c4e46f36 1851+EOF
7d31425d
WD
1852 echo cvsin >"$fromdir/mid/for/one-in-one-out"
1853 echo expunged >"$fromdir/mid/for/foo/extra"
1854 echo retained >"$fromdir/mid/for/foo/keep"
6e313719
WD
1855@@ -97,7 +125,26 @@ $RSYNC -av --existing --include='*/' --e
1856 # Now, test if rsync excludes the same files, this time with --cvs-exclude
1857 # and --delete-excluded.
1858
1859-checkit "$RSYNC -avvC --exclude-from=\"$excl\" \
147a9095 1860+checkit "$RSYNC -avvC --filter=\". $excl\" \
6e313719
WD
1861+ --delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
1862+
7d31425d
WD
1863+# Modify the chk dir for our merge-exclude test and then tweak the dir times.
1864+
1865+rm "$chkdir"/.excl
1866+rm "$chkdir"/foo/file1
1867+rm "$chkdir"/bar/.excl
1868+rm "$chkdir"/bar/down/to/.excl2
1869+rm "$chkdir"/bar/down/to/foo/.excl2
1870+rm "$chkdir"/mid/.excl
1871+cp -p "$fromdir"/bar/down/to/foo/*.junk "$chkdir"/bar/down/to/foo
1872+cp -p "$fromdir"/bar/down/to/foo/to "$chkdir"/bar/down/to/foo
1873+
1874+$RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$chkdir/"
1875+
1876+# Now, test if rsync excludes the same files, this time with a merge-exclude
1877+# file.
1878+
147a9095 1879+checkit "$RSYNC -avv --filter=': .excl' --filter=\". $excl\" \
6e313719
WD
1880 --delete-excluded \"$fromdir/\" \"$todir/\"" "$chkdir" "$todir"
1881
7d31425d 1882 # The script would have aborted on error, so getting here means we've won.