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