Improved grepping of patch output.
[rsync/rsync-patches.git] / filter.diff
CommitLineData
a55d21aa
WD
1This patch adds the ability to use ". INSERT" files in excludes and
2includes. If you specify a name without slashes, that filename will be
3looked for in every directory and its rules will effect that directory
4and its subdirectories. Insert rules found inside a per-directory
5include file are always just read in (they don't create any new per-dir
6include/exclude files).
7
8For example:
9
10 rsync -av --exclude='. .excl' from/ to
11
12The above will look for a file named ".excl" in every directory of the
13sender and will exclude (by default) files based on the rules found
14therein. If a file contains this:
15
16 + *.c
17 . another.file
18 - *.o
19
20Then the file "another.file" will also be read (from that one dir) and
21its rules inserted in between the surrounding lines.
22
23Additionally, you can affect where the -C option's inclusion of the
24.cvsignore file gets inserted into your rules by mentioning it as an
25insertion. For instance, specifying this:
26
27 rsync -avC --include=foo --exclude='. .cvsignore' --include='*.c' a/ b
28
29This will insert all the .cvsignore rules in the middle of your rules
30rather than at the end. This allows their dir-specific rules to
31supersede your general rules instead of being subservient to them.
32
33..wayne..
34
35--- exclude.c 22 Apr 2004 22:17:15 -0000 1.71
36+++ exclude.c 22 Apr 2004 23:45:51 -0000
37@@ -30,31 +30,60 @@ extern int verbose;
38 extern int eol_nulls;
39 extern int list_only;
40 extern int recurse;
41+extern int io_error;
42+extern int sanitize_paths;
43
44 extern char curr_dir[];
45
46-struct exclude_list_struct exclude_list = { 0, 0, "" };
47-struct exclude_list_struct local_exclude_list = { 0, 0, "local-cvsignore " };
48-struct exclude_list_struct server_exclude_list = { 0, 0, "server " };
49+struct exclude_list_struct exclude_list = { 0, 0, 0, 0, "" };
50+struct exclude_list_struct server_exclude_list = { 0, 0, 0, 0, "server " };
51 char *exclude_path_prefix = NULL;
52
53+static struct exclude_list_struct *local_exclude_lists;
54+static int local_exclude_list_cnt;
55+static char dirbuf[MAXPATHLEN];
56+static unsigned int dirbuf_offset = 0;
57+
58+static void clear_exclude_list(struct exclude_list_struct *listp,
59+ struct exclude_struct *extra)
60+{
61+ listp->head = listp->extra = extra;
62+ listp->tail = NULL;
63+}
64+
65 /** Build an exclude structure given a exclude pattern */
66 static void make_exclude(struct exclude_list_struct *listp, const char *pattern,
67- int pat_len, int include)
68+ unsigned int pat_len, int mflags)
69 {
70 struct exclude_struct *ret;
71 const char *cp;
72- int ex_len;
73+ unsigned int ex_len;
74+
75+ if (mflags & MATCHFLG_INSERT_FILE) {
76+ struct exclude_struct *ex;
77+ /* If the local include file was already mentioned, don't
78+ * insert it again. */
79+ for (ex = listp->head; ex; ex = ex->next) {
80+ if ((ex->match_flags & MATCHFLG_INSERT_FILE)
81+ && strlen(ex->pattern) == pat_len
82+ && strncmp(ex->pattern, pattern, pat_len) == 0)
83+ return;
84+ }
85+ if (pat_len == 10 && strncmp(pattern, ".cvsignore", 10) == 0) {
86+ mflags |= MATCHFLG_CVSIGNORE;
87+ mflags &= ~MATCHFLG_INCLUDE;
88+ } else
89+ mflags &= ~MATCHFLG_CVSIGNORE;
90+ }
91
92 ret = new(struct exclude_struct);
93 if (!ret)
94 out_of_memory("make_exclude");
95
96 memset(ret, 0, sizeof ret[0]);
97- ret->include = include;
98
99 if (exclude_path_prefix)
100- ret->match_flags |= MATCHFLG_ABS_PATH;
101+ mflags |= MATCHFLG_ABS_PATH;
102 if (exclude_path_prefix && *pattern == '/')
103 ex_len = strlen(exclude_path_prefix);
104 else
105@@ -68,29 +97,49 @@ static void make_exclude(struct exclude_
106 pat_len += ex_len;
107
108 if (strpbrk(ret->pattern, "*[?")) {
109- ret->match_flags |= MATCHFLG_WILD;
110+ mflags |= MATCHFLG_WILD;
111 if ((cp = strstr(ret->pattern, "**")) != NULL) {
112- ret->match_flags |= MATCHFLG_WILD2;
113+ mflags |= MATCHFLG_WILD2;
114 /* If the pattern starts with **, note that. */
115 if (cp == ret->pattern)
116- ret->match_flags |= MATCHFLG_WILD2_PREFIX;
117+ mflags |= MATCHFLG_WILD2_PREFIX;
118 }
119 }
120
121 if (pat_len > 1 && ret->pattern[pat_len-1] == '/') {
122 ret->pattern[pat_len-1] = 0;
123- ret->directory = 1;
124+ mflags |= MATCHFLG_DIRECTORY;
125 }
126
127 for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
128 ret->slash_cnt++;
129
130+ ret->next = listp->extra;
131+
132 if (!listp->tail)
133 listp->head = listp->tail = ret;
134 else {
135 listp->tail->next = ret;
136 listp->tail = ret;
137 }
138+
139+ if (mflags & MATCHFLG_INSERT_FILE) {
140+ struct exclude_list_struct *lp;
141+ int ndx = local_exclude_list_cnt++;
142+ local_exclude_lists = realloc_array(local_exclude_lists,
143+ struct exclude_list_struct, local_exclude_list_cnt);
144+ if (!local_exclude_lists)
145+ out_of_memory("make_exclude");
146+ lp = &local_exclude_lists[ndx];
147+ clear_exclude_list(lp, NULL);
148+ if (asprintf(&lp->debug_type, "local %s ",
149+ ret->pattern) < 0)
150+ out_of_memory("make_exclude");
151+ lp->parent = ret;
152+ ret->slash_cnt = ndx;
153+ }
154+
155+ ret->match_flags = mflags;
156 }
157
158 static void free_exclude(struct exclude_struct *ex)
159@@ -99,7 +148,7 @@ static void free_exclude(struct exclude_
160 free(ex);
161 }
162
163-void free_exclude_list(struct exclude_list_struct *listp)
164+static void free_exclude_list(struct exclude_list_struct *listp)
165 {
166 struct exclude_struct *ent, *next;
167
168@@ -108,12 +157,72 @@ void free_exclude_list(struct exclude_li
169 who_am_i(), listp->debug_type);
170 }
171
172+ if (listp->extra) {
173+ if (listp->tail)
174+ listp->tail->next = NULL;
175+ else
176+ listp->head = NULL;
177+ }
178+
179 for (ent = listp->head; ent; ent = next) {
180 next = ent->next;
181 free_exclude(ent);
182 }
183
184- listp->head = listp->tail = NULL;
185+ clear_exclude_list(listp, NULL);
186+}
187+
188+void *push_local_excludes(char *fname, unsigned int offset)
189+{
190+ int i;
191+ struct exclude_list_struct *mem = new_array(struct exclude_list_struct,
192+ local_exclude_list_cnt);
193+ if (!mem)
194+ out_of_memory("push_local_excludes");
195+
196+ memcpy(mem, local_exclude_lists,
197+ sizeof (struct exclude_list_struct) * local_exclude_list_cnt);
198+
199+ memcpy(dirbuf, fname, offset);
200+ dirbuf_offset = offset;
201+
202+ for (i = 0; i < local_exclude_list_cnt; i++) {
203+ struct exclude_list_struct *listp = &local_exclude_lists[i];
204+ struct exclude_struct *extra;
205+ char *file = listp->parent->pattern;
206+ int flags;
207+ if (listp->parent->match_flags & MATCHFLG_CVSIGNORE) {
208+ flags = XFLG_WORD_SPLIT | XFLG_NO_PREFIXES;
209+ extra = NULL;
210+ } else {
211+ flags = 0;
212+ extra = listp->head; /* subdirs inherit our rules */
213+ }
214+ clear_exclude_list(listp, extra);
215+ if (strlcpy(fname + offset, file, MAXPATHLEN - offset)
216+ < MAXPATHLEN - offset) {
217+ add_exclude_file(listp, fname, flags);
218+ } else {
219+ io_error |= IOERR_GENERAL;
220+ rprintf(FINFO,
221+ "cannot add local excludes in long-named directory %s\n",
222+ full_fname(fname));
223+ }
224+ }
225+
226+ return (void *) mem;
227+}
228+
229+void pop_local_excludes(void *mem)
230+{
231+ int i;
232+ for (i = 0; i < local_exclude_list_cnt; i++) {
233+ struct exclude_list_struct *listp = &local_exclude_lists[i];
234+ free_exclude_list(listp);
235+ }
236+ memcpy(local_exclude_lists, mem,
237+ sizeof (struct exclude_list_struct) * local_exclude_list_cnt);
238+ free(mem);
239 }
240
241 static int check_one_exclude(char *name, struct exclude_struct *ex,
242@@ -139,7 +248,8 @@ static int check_one_exclude(char *name,
243
244 if (!name[0]) return 0;
245
246- if (ex->directory && !name_is_dir) return 0;
247+ if ((ex->match_flags & MATCHFLG_DIRECTORY) && !name_is_dir)
248+ return 0;
249
250 if (*pattern == '/') {
251 match_start = 1;
252@@ -206,9 +316,11 @@ static void report_exclude_result(char c
253
254 if (verbose >= 2) {
255 rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n",
256- who_am_i(), ent->include ? "in" : "ex",
257+ who_am_i(),
258+ ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex",
259 name_is_dir ? "directory" : "file", name, type,
260- ent->pattern, ent->directory ? "/" : "");
261+ ent->pattern,
262+ ent->match_flags & MATCHFLG_DIRECTORY ? "/" : "");
263 }
264 }
265
266@@ -223,10 +335,18 @@ int check_exclude(struct exclude_list_st
267 struct exclude_struct *ent;
268
269 for (ent = listp->head; ent; ent = ent->next) {
270+ if (ent->match_flags & MATCHFLG_INSERT_FILE) {
271+ struct exclude_list_struct *lp
272+ = &local_exclude_lists[ent->slash_cnt];
273+ int rc = check_exclude(lp, name, name_is_dir);
274+ if (rc)
275+ return rc;
276+ continue;
277+ }
278 if (check_one_exclude(name, ent, name_is_dir)) {
279 report_exclude_result(name, ent, name_is_dir,
280 listp->debug_type);
281- return ent->include ? 1 : -1;
282+ return (ent->match_flags & MATCHFLG_INCLUDE) ? 1 : -1;
283 }
284 }
285
286@@ -242,11 +362,11 @@ int check_exclude(struct exclude_list_st
287 * *incl_ptr value will be 1 for an include, 0 for an exclude, and -1 for
288 * the list-clearing "!" token.
289 */
290-static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr,
291+static const char *get_exclude_tok(const char *p, int *len_ptr, int *flag_ptr,
292 int xflags)
293 {
294 const unsigned char *s = (const unsigned char *)p;
295- int len;
296+ int len, mflags = 0;
297
298 if (xflags & XFLG_WORD_SPLIT) {
299 /* Skip over any initial whitespace. */
300@@ -256,13 +376,19 @@ static const char *get_exclude_tok(const
301 p = (const char *)s;
302 }
303
304- /* Is this a '+' or '-' followed by a space (not whitespace)? */
305+ /* Is this a +/-/. followed by a space (not whitespace)? */
306 if (!(xflags & XFLG_NO_PREFIXES)
307- && (*s == '-' || *s == '+') && s[1] == ' ') {
308- *incl_ptr = *s == '+';
309+ && (*s == '-' || *s == '+' || *s == '.') && s[1] == ' ') {
310+ if (*s == '+')
311+ mflags |= MATCHFLG_INCLUDE;
312+ else if (*s == '.') {
313+ mflags |= MATCHFLG_INSERT_FILE;
314+ if (xflags & XFLG_DEF_INCLUDE)
315+ mflags |= MATCHFLG_INCLUDE;
316+ }
317 s += 2;
318- } else
319- *incl_ptr = xflags & XFLG_DEF_INCLUDE;
320+ } else if (xflags & XFLG_DEF_INCLUDE)
321+ mflags |= MATCHFLG_INCLUDE;
322
323 if (xflags & XFLG_WORD_SPLIT) {
324 const unsigned char *cp = s;
325@@ -274,9 +400,10 @@ static const char *get_exclude_tok(const
326 len = strlen(s);
327
328 if (*p == '!' && len == 1 && !(xflags & XFLG_NO_PREFIXES))
329- *incl_ptr = -1;
330+ mflags |= MATCHFLG_CLEAR_LIST;
331
332 *len_ptr = len;
333+ *flag_ptr = mflags;
334 return (const char *)s;
335 }
336
337@@ -284,7 +411,7 @@ static const char *get_exclude_tok(const
338 void add_exclude(struct exclude_list_struct *listp, const char *pattern,
339 int xflags)
340 {
341- int pat_len, incl;
342+ int pat_len, mflags;
343 const char *cp;
344
345 if (!pattern)
346@@ -293,22 +420,44 @@ void add_exclude(struct exclude_list_str
347 cp = pattern;
348 pat_len = 0;
349 while (1) {
350- cp = get_exclude_tok(cp + pat_len, &pat_len, &incl, xflags);
351+ cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags);
352 if (!pat_len)
353 break;
354 /* If we got the special "!" token, clear the list. */
355- if (incl < 0)
356+ if (mflags & MATCHFLG_CLEAR_LIST) {
357 free_exclude_list(listp);
358- else {
359- make_exclude(listp, cp, pat_len, incl);
360-
361- if (verbose > 2) {
362- rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s)\n",
363- who_am_i(), pat_len, cp,
364- listp->debug_type,
365- incl ? "include" : "exclude");
366+ continue;
367+ }
368+ if (mflags & MATCHFLG_INSERT_FILE) {
369+ char name[MAXPATHLEN];
370+ if ((unsigned) pat_len >= sizeof name)
371+ continue; // XXX complain?
372+ strlcpy(name, cp, pat_len+1);
373+ if (listp->parent || strchr(name, '/') != NULL) {
374+ if (sanitize_paths)
375+ sanitize_path(name, curr_dir);
376+ if (*name == '/')
377+ cp = name;
378+ else {
379+ if (strlcpy(dirbuf + dirbuf_offset,
380+ name, MAXPATHLEN - dirbuf_offset)
381+ >= MAXPATHLEN - dirbuf_offset)
382+ continue; // XXX complain?
383+ cp = dirbuf;
384+ }
385+ add_exclude_file(listp, cp,
386+ xflags | XFLG_FATAL_ERRORS);
387+ continue;
388 }
389 }
390+ make_exclude(listp, cp, pat_len, mflags);
391+
392+ if (verbose > 2) {
393+ rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s%sclude)\n",
394+ who_am_i(), pat_len, cp, listp->debug_type,
395+ mflags & MATCHFLG_INSERT_FILE ? "FILE " : "",
396+ mflags & MATCHFLG_INCLUDE ? "in" : "ex");
397+ }
398 }
399 }
400
401@@ -384,15 +533,19 @@ void send_exclude_list(int f)
402 l = strlcpy(p, ent->pattern, sizeof p);
403 if (l == 0 || l >= MAXPATHLEN)
404 continue;
405- if (ent->directory) {
406+ if (ent->match_flags & MATCHFLG_DIRECTORY) {
407 p[l++] = '/';
408 p[l] = '\0';
409 }
410
411- if (ent->include) {
412+ if (ent->match_flags & MATCHFLG_INCLUDE) {
413 write_int(f, l + 2);
414 write_buf(f, "+ ", 2);
415- } else if ((*p == '-' || *p == '+') && p[1] == ' ') {
416+ } else if (ent->match_flags & MATCHFLG_INSERT_FILE) {
417+ write_int(f, l + 2);
418+ write_buf(f, ". ", 2);
419+ } else if ((*p == '-' || *p == '+' || *p == '.')
420+ && p[1] == ' ') {
421 write_int(f, l + 2);
422 write_buf(f, "- ", 2);
423 } else
424@@ -433,6 +586,7 @@ void add_cvs_excludes(void)
425 char fname[MAXPATHLEN];
426 char *p;
427
428+ add_exclude(&exclude_list, ". .cvsignore", 0);
429 add_exclude(&exclude_list, default_cvsignore,
430 XFLG_WORD_SPLIT | XFLG_NO_PREFIXES);
431
432--- flist.c 22 Apr 2004 22:17:15 -0000 1.216
433+++ flist.c 22 Apr 2004 23:45:51 -0000
434@@ -39,8 +39,6 @@ extern int module_id;
435 extern int ignore_errors;
436 extern int numeric_ids;
437
438-extern int cvs_exclude;
439-
440 extern int recurse;
441 extern char curr_dir[MAXPATHLEN];
442 extern char *files_from;
443@@ -66,7 +64,6 @@ extern int write_batch;
444
445 extern struct exclude_list_struct exclude_list;
446 extern struct exclude_list_struct server_exclude_list;
447-extern struct exclude_list_struct local_exclude_list;
448
449 int io_error;
450
451@@ -211,8 +208,6 @@ int link_stat(const char *path, STRUCT_S
452 */
453 static int check_exclude_file(char *fname, int is_dir, int exclude_level)
454 {
455- int rc;
456-
457 #if 0 /* This currently never happens, so avoid a useless compare. */
458 if (exclude_level == NO_EXCLUDES)
459 return 0;
460@@ -234,10 +229,7 @@ static int check_exclude_file(char *fnam
461 if (exclude_level != ALL_EXCLUDES)
462 return 0;
463 if (exclude_list.head
464- && (rc = check_exclude(&exclude_list, fname, is_dir)) != 0)
465- return rc < 0;
466- if (local_exclude_list.head
467- && check_exclude(&local_exclude_list, fname, is_dir) < 0)
468+ && check_exclude(&exclude_list, fname, is_dir) < 0)
469 return 1;
470 return 0;
471 }
472@@ -946,11 +938,7 @@ void send_file_name(int f, struct file_l
473
474 if (recursive && S_ISDIR(file->mode)
475 && !(file->flags & FLAG_MOUNT_POINT)) {
476- struct exclude_list_struct last_list = local_exclude_list;
477- local_exclude_list.head = local_exclude_list.tail = NULL;
478 send_directory(f, flist, f_name_to(file, fbuf));
479- free_exclude_list(&local_exclude_list);
480- local_exclude_list = last_list;
481 }
482 }
483
484@@ -961,6 +949,7 @@ static void send_directory(int f, struct
485 struct dirent *di;
486 char fname[MAXPATHLEN];
487 unsigned int offset;
488+ void *save_excludes;
489 char *p;
490
491 d = opendir(dir);
492@@ -985,18 +974,7 @@ static void send_directory(int f, struct
493 offset++;
494 }
495
496- if (cvs_exclude) {
497- if (strlcpy(p, ".cvsignore", MAXPATHLEN - offset)
498- < MAXPATHLEN - offset) {
499- add_exclude_file(&local_exclude_list, fname,
500- XFLG_WORD_SPLIT | XFLG_NO_PREFIXES);
501- } else {
502- io_error |= IOERR_GENERAL;
503- rprintf(FINFO,
504- "cannot cvs-exclude in long-named directory %s\n",
505- full_fname(fname));
506- }
507- }
508+ save_excludes = push_local_excludes(fname, offset);
509
510 for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) {
511 char *dname = d_name(di);
512@@ -1017,6 +995,8 @@ static void send_directory(int f, struct
513 rprintf(FERROR, "readdir(%s): (%d) %s\n",
514 dir, errno, strerror(errno));
515 }
516+
517+ pop_local_excludes(save_excludes);
518
519 closedir(d);
520 }
521--- proto.h 22 Apr 2004 09:58:09 -0000 1.189
522+++ proto.h 22 Apr 2004 23:45:51 -0000
523@@ -51,7 +51,8 @@ int start_daemon(int f_in, int f_out);
524 int daemon_main(void);
525 void setup_protocol(int f_out,int f_in);
526 int claim_connection(char *fname,int max_connections);
527-void free_exclude_list(struct exclude_list_struct *listp);
528+void *push_local_excludes(char *fname, unsigned int offset);
529+void pop_local_excludes(void *mem);
530 int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir);
531 void add_exclude(struct exclude_list_struct *listp, const char *pattern,
532 int xflags);
533--- rsync.h 22 Apr 2004 09:58:24 -0000 1.198
534+++ rsync.h 22 Apr 2004 23:45:52 -0000
535@@ -490,18 +490,21 @@ struct map_struct {
536 #define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */
537 #define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with '**' */
538 #define MATCHFLG_ABS_PATH (1<<3) /* path-match on absolute path */
539+#define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */
540+#define MATCHFLG_CLEAR_LIST (1<<5) /* this item is the "!" token */
541+#define MATCHFLG_DIRECTORY (1<<6) /* this matches only directories */
542+#define MATCHFLG_INSERT_FILE (1<<7) /* specifies a file to insert */
543+#define MATCHFLG_CVSIGNORE (1<<8) /* parse this as a .cvsignore file */
544 struct exclude_struct {
545 struct exclude_struct *next;
546 char *pattern;
547 int match_flags;
548- int include;
549- int directory;
550 int slash_cnt;
551 };
552
553 struct exclude_list_struct {
554- struct exclude_struct *head;
555- struct exclude_struct *tail;
556+ struct exclude_struct *head, *tail;
557+ struct exclude_struct *extra, *parent;
558 char *debug_type;
559 };
560