Commit | Line | Data |
---|---|---|
8a529471 WD |
1 | After applying this patch and running configure, you MUST run this |
2 | command before "make": | |
3 | ||
4 | make proto | |
5 | ||
524989ae WD |
6 | This patch adds the ability to merge rules into your excludes/includes |
7 | using a ". FILE" idiom. If you specify a name without slashes, that | |
8 | filename will be looked for in every subdirectory that rsync visits, | |
9 | and its rules will affect the current directory and its subdirectories. | |
a55d21aa WD |
10 | |
11 | For example: | |
12 | ||
13 | rsync -av --exclude='. .excl' from/ to | |
14 | ||
15 | The above will look for a file named ".excl" in every directory of the | |
524989ae WD |
16 | hierarchy that rsync visits, and it will exclude (by default) names |
17 | based on the rules found therein. If one of the .excl files contains | |
18 | this: | |
a55d21aa WD |
19 | |
20 | + *.c | |
524989ae WD |
21 | . .excl2 |
22 | . ./.excl3 | |
23 | *.o | |
a55d21aa | 24 | |
524989ae WD |
25 | Then the file ".excl2" will also be read in the current dir, and all |
26 | subdirs of the current dir. The file ".excl3" would just be read in | |
27 | for the current dir because its name contained a slash. | |
a55d21aa WD |
28 | |
29 | ..wayne.. | |
30 | ||
7cb7ae4e WD |
31 | --- exclude.c 14 May 2004 21:23:41 -0000 1.76 |
32 | +++ exclude.c 15 May 2004 00:36:36 -0000 | |
33 | @@ -30,32 +30,58 @@ extern int verbose; | |
a55d21aa WD |
34 | extern int eol_nulls; |
35 | extern int list_only; | |
36 | extern int recurse; | |
37 | +extern int io_error; | |
38 | +extern int sanitize_paths; | |
39 | ||
40 | extern char curr_dir[]; | |
41 | ||
42 | -struct exclude_list_struct exclude_list = { 0, 0, "" }; | |
524989ae | 43 | -struct exclude_list_struct local_exclude_list = { 0, 0, "per-dir .cvsignore " }; |
a55d21aa | 44 | -struct exclude_list_struct server_exclude_list = { 0, 0, "server " }; |
7cb7ae4e WD |
45 | +struct exclude_list_struct exclude_list = { 0, 0, 0, "" }; |
46 | +struct exclude_list_struct server_exclude_list = { 0, 0, 0, "server " }; | |
a55d21aa WD |
47 | char *exclude_path_prefix = NULL; |
48 | ||
524989ae WD |
49 | +struct exclude_list_root { |
50 | + struct exclude_list_struct *head; | |
51 | + int cnt; | |
52 | +} local_lists; | |
53 | + | |
a55d21aa WD |
54 | +static char dirbuf[MAXPATHLEN]; |
55 | +static unsigned int dirbuf_offset = 0; | |
a55d21aa WD |
56 | + |
57 | /** Build an exclude structure given a exclude pattern */ | |
524989ae | 58 | -static void make_exclude(struct exclude_list_struct *listp, const char *pattern, |
a55d21aa | 59 | - int pat_len, int include) |
524989ae | 60 | +static void make_exclude(struct exclude_list_struct *listp, const char *pat, |
a55d21aa WD |
61 | + unsigned int pat_len, int mflags) |
62 | { | |
63 | struct exclude_struct *ret; | |
64 | const char *cp; | |
65 | - int ex_len; | |
66 | + unsigned int ex_len; | |
67 | + | |
524989ae | 68 | + if (mflags & MATCHFLG_MERGE_FILE) { |
a55d21aa WD |
69 | + struct exclude_struct *ex; |
70 | + /* If the local include file was already mentioned, don't | |
524989ae | 71 | + * add it again. */ |
a55d21aa | 72 | + for (ex = listp->head; ex; ex = ex->next) { |
524989ae | 73 | + if ((ex->match_flags & MATCHFLG_MERGE_FILE) |
a55d21aa | 74 | + && strlen(ex->pattern) == pat_len |
524989ae | 75 | + && strncmp(ex->pattern, pat, pat_len) == 0) |
a55d21aa WD |
76 | + return; |
77 | + } | |
524989ae WD |
78 | + if ((pat_len == 10 || (pat_len > 10 && pat[pat_len-11] == '/')) |
79 | + && strncmp(pat+pat_len-10, ".cvsignore", 10) == 0) { | |
a55d21aa WD |
80 | + mflags |= MATCHFLG_CVSIGNORE; |
81 | + mflags &= ~MATCHFLG_INCLUDE; | |
82 | + } else | |
83 | + mflags &= ~MATCHFLG_CVSIGNORE; | |
84 | + } | |
85 | ||
86 | ret = new(struct exclude_struct); | |
87 | if (!ret) | |
88 | out_of_memory("make_exclude"); | |
89 | ||
90 | memset(ret, 0, sizeof ret[0]); | |
91 | - ret->include = include; | |
92 | ||
93 | if (exclude_path_prefix) | |
94 | - ret->match_flags |= MATCHFLG_ABS_PATH; | |
524989ae | 95 | - if (exclude_path_prefix && *pattern == '/') |
a55d21aa | 96 | + mflags |= MATCHFLG_ABS_PATH; |
524989ae | 97 | + if (exclude_path_prefix && *pat == '/') |
a55d21aa WD |
98 | ex_len = strlen(exclude_path_prefix); |
99 | else | |
524989ae | 100 | ex_len = 0; |
7cb7ae4e | 101 | @@ -64,33 +90,51 @@ static void make_exclude(struct exclude_ |
524989ae WD |
102 | out_of_memory("make_exclude"); |
103 | if (ex_len) | |
104 | memcpy(ret->pattern, exclude_path_prefix, ex_len); | |
105 | - strlcpy(ret->pattern + ex_len, pattern, pat_len + 1); | |
106 | + strlcpy(ret->pattern + ex_len, pat, pat_len + 1); | |
a55d21aa WD |
107 | pat_len += ex_len; |
108 | ||
109 | if (strpbrk(ret->pattern, "*[?")) { | |
110 | - ret->match_flags |= MATCHFLG_WILD; | |
111 | + mflags |= MATCHFLG_WILD; | |
112 | if ((cp = strstr(ret->pattern, "**")) != NULL) { | |
113 | - ret->match_flags |= MATCHFLG_WILD2; | |
114 | + mflags |= MATCHFLG_WILD2; | |
115 | /* If the pattern starts with **, note that. */ | |
116 | if (cp == ret->pattern) | |
117 | - ret->match_flags |= MATCHFLG_WILD2_PREFIX; | |
118 | + mflags |= MATCHFLG_WILD2_PREFIX; | |
119 | } | |
120 | } | |
121 | ||
122 | if (pat_len > 1 && ret->pattern[pat_len-1] == '/') { | |
123 | ret->pattern[pat_len-1] = 0; | |
124 | - ret->directory = 1; | |
125 | + mflags |= MATCHFLG_DIRECTORY; | |
126 | } | |
127 | ||
128 | for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++) | |
129 | ret->slash_cnt++; | |
130 | ||
7cb7ae4e WD |
131 | - if (!listp->tail) |
132 | + if (!listp->tail) { | |
133 | + ret->next = listp->head; | |
a55d21aa | 134 | listp->head = listp->tail = ret; |
7cb7ae4e WD |
135 | - else { |
136 | - listp->tail->next = ret; | |
137 | - listp->tail = ret; | |
138 | + } else { | |
139 | + ret->next = listp->tail->next; | |
140 | + listp->tail->next = listp->tail = ret; | |
141 | + } | |
a55d21aa | 142 | + |
524989ae | 143 | + if (mflags & MATCHFLG_MERGE_FILE) { |
a55d21aa | 144 | + struct exclude_list_struct *lp; |
524989ae WD |
145 | + int ndx = local_lists.cnt++; |
146 | + local_lists.head = realloc_array(local_lists.head, | |
147 | + struct exclude_list_struct, local_lists.cnt); | |
148 | + if (!local_lists.head) | |
a55d21aa | 149 | + out_of_memory("make_exclude"); |
524989ae | 150 | + lp = &local_lists.head[ndx]; |
7cb7ae4e | 151 | + lp->head = lp->tail = NULL; |
524989ae | 152 | + if (asprintf(&lp->debug_type, "per-dir %s ", ret->pattern) < 0) |
a55d21aa WD |
153 | + out_of_memory("make_exclude"); |
154 | + lp->parent = ret; | |
155 | + ret->slash_cnt = ndx; | |
7cb7ae4e | 156 | } |
a55d21aa WD |
157 | + |
158 | + ret->match_flags = mflags; | |
159 | } | |
160 | ||
161 | static void free_exclude(struct exclude_struct *ex) | |
7cb7ae4e | 162 | @@ -99,18 +143,90 @@ static void free_exclude(struct exclude_ |
a55d21aa WD |
163 | free(ex); |
164 | } | |
165 | ||
166 | -void free_exclude_list(struct exclude_list_struct *listp) | |
167 | +static void free_exclude_list(struct exclude_list_struct *listp) | |
168 | { | |
7cb7ae4e WD |
169 | - struct exclude_struct *ent, *next; |
170 | - | |
171 | - for (ent = listp->head; ent; ent = next) { | |
172 | - next = ent->next; | |
173 | - free_exclude(ent); | |
174 | + if (listp->tail) { | |
175 | + struct exclude_struct *ent, *next; | |
176 | + /* Truncate any extra parent items from local list. */ | |
177 | + listp->tail->next = NULL; | |
178 | + for (ent = listp->head; ent; ent = next) { | |
179 | + next = ent->next; | |
180 | + free_exclude(ent); | |
181 | + } | |
524989ae WD |
182 | } |
183 | ||
7cb7ae4e WD |
184 | listp->head = listp->tail = NULL; |
185 | } | |
a55d21aa | 186 | |
a55d21aa WD |
187 | +void *push_local_excludes(char *fname, unsigned int offset) |
188 | +{ | |
189 | + int i; | |
524989ae WD |
190 | + struct exclude_list_root *push = new_array(struct exclude_list_root, 1); |
191 | + | |
192 | + if (!push) | |
a55d21aa WD |
193 | + out_of_memory("push_local_excludes"); |
194 | + | |
524989ae WD |
195 | + push->cnt = local_lists.cnt; |
196 | + push->head = new_array(struct exclude_list_struct, local_lists.cnt); | |
197 | + if (!push->head) | |
198 | + out_of_memory("push_local_excludes"); | |
a55d21aa | 199 | + |
524989ae WD |
200 | + memcpy(push->head, local_lists.head, |
201 | + sizeof (struct exclude_list_struct) * local_lists.cnt); | |
202 | + | |
203 | + /* Make it easy to construct the full path for a merge that has | |
204 | + * a relative path by saving it off. */ | |
a55d21aa WD |
205 | + memcpy(dirbuf, fname, offset); |
206 | + dirbuf_offset = offset; | |
207 | + | |
524989ae WD |
208 | + for (i = 0; i < local_lists.cnt; i++) { |
209 | + struct exclude_list_struct *listp = &local_lists.head[i]; | |
a55d21aa WD |
210 | + char *file = listp->parent->pattern; |
211 | + int flags; | |
524989ae WD |
212 | + |
213 | + if (verbose > 2) { | |
214 | + rprintf(FINFO, "[%s] pushing %sexclude list\n", | |
215 | + who_am_i(), listp->debug_type); | |
216 | + } | |
a55d21aa | 217 | + if (listp->parent->match_flags & MATCHFLG_CVSIGNORE) { |
ee1af13c | 218 | + flags = XFLG_WORD_SPLIT | XFLG_WORDS_ONLY; |
7cb7ae4e | 219 | + listp->head = NULL; /* Subdirs don't get our rules. */ |
a55d21aa | 220 | + } else { |
524989ae WD |
221 | + flags = listp->parent->match_flags & MATCHFLG_INCLUDE |
222 | + ? XFLG_DEF_INCLUDE : 0; | |
a55d21aa | 223 | + } |
7cb7ae4e | 224 | + listp->tail = NULL; |
a55d21aa | 225 | + if (strlcpy(fname + offset, file, MAXPATHLEN - offset) |
524989ae | 226 | + < MAXPATHLEN - offset) |
a55d21aa | 227 | + add_exclude_file(listp, fname, flags); |
524989ae | 228 | + else { |
a55d21aa WD |
229 | + io_error |= IOERR_GENERAL; |
230 | + rprintf(FINFO, | |
231 | + "cannot add local excludes in long-named directory %s\n", | |
232 | + full_fname(fname)); | |
233 | + } | |
234 | + } | |
235 | + | |
524989ae | 236 | + return (void*)push; |
a55d21aa WD |
237 | +} |
238 | + | |
239 | +void pop_local_excludes(void *mem) | |
240 | +{ | |
241 | + int i; | |
524989ae WD |
242 | + |
243 | + for (i = 0; i < local_lists.cnt; i++) { | |
244 | + struct exclude_list_struct *listp = &local_lists.head[i]; | |
245 | + if (verbose > 2) { | |
246 | + rprintf(FINFO, "[%s] popping %sexclude list\n", | |
247 | + who_am_i(), listp->debug_type); | |
248 | + } | |
a55d21aa WD |
249 | + free_exclude_list(listp); |
250 | + } | |
524989ae WD |
251 | + free(local_lists.head); |
252 | + local_lists = *(struct exclude_list_root*)mem; | |
a55d21aa | 253 | + free(mem); |
7cb7ae4e WD |
254 | +} |
255 | + | |
a55d21aa | 256 | static int check_one_exclude(char *name, struct exclude_struct *ex, |
7cb7ae4e WD |
257 | int name_is_dir) |
258 | { | |
259 | @@ -134,7 +250,8 @@ static int check_one_exclude(char *name, | |
a55d21aa WD |
260 | |
261 | if (!name[0]) return 0; | |
262 | ||
263 | - if (ex->directory && !name_is_dir) return 0; | |
264 | + if ((ex->match_flags & MATCHFLG_DIRECTORY) && !name_is_dir) | |
265 | + return 0; | |
266 | ||
267 | if (*pattern == '/') { | |
268 | match_start = 1; | |
7cb7ae4e | 269 | @@ -201,9 +318,11 @@ static void report_exclude_result(char c |
a55d21aa WD |
270 | |
271 | if (verbose >= 2) { | |
272 | rprintf(FINFO, "[%s] %scluding %s %s because of %spattern %s%s\n", | |
273 | - who_am_i(), ent->include ? "in" : "ex", | |
274 | + who_am_i(), | |
275 | + ent->match_flags & MATCHFLG_INCLUDE ? "in" : "ex", | |
276 | name_is_dir ? "directory" : "file", name, type, | |
277 | - ent->pattern, ent->directory ? "/" : ""); | |
278 | + ent->pattern, | |
279 | + ent->match_flags & MATCHFLG_DIRECTORY ? "/" : ""); | |
280 | } | |
281 | } | |
282 | ||
7cb7ae4e | 283 | @@ -217,10 +336,18 @@ int check_exclude(struct exclude_list_st |
a55d21aa WD |
284 | struct exclude_struct *ent; |
285 | ||
286 | for (ent = listp->head; ent; ent = ent->next) { | |
524989ae | 287 | + if (ent->match_flags & MATCHFLG_MERGE_FILE) { |
a55d21aa | 288 | + struct exclude_list_struct *lp |
524989ae | 289 | + = &local_lists.head[ent->slash_cnt]; |
a55d21aa WD |
290 | + int rc = check_exclude(lp, name, name_is_dir); |
291 | + if (rc) | |
292 | + return rc; | |
293 | + continue; | |
294 | + } | |
295 | if (check_one_exclude(name, ent, name_is_dir)) { | |
296 | report_exclude_result(name, ent, name_is_dir, | |
297 | listp->debug_type); | |
298 | - return ent->include ? 1 : -1; | |
299 | + return (ent->match_flags & MATCHFLG_INCLUDE) ? 1 : -1; | |
300 | } | |
301 | } | |
302 | ||
7cb7ae4e | 303 | @@ -236,11 +363,11 @@ int check_exclude(struct exclude_list_st |
a55d21aa WD |
304 | * *incl_ptr value will be 1 for an include, 0 for an exclude, and -1 for |
305 | * the list-clearing "!" token. | |
306 | */ | |
307 | -static const char *get_exclude_tok(const char *p, int *len_ptr, int *incl_ptr, | |
308 | +static const char *get_exclude_tok(const char *p, int *len_ptr, int *flag_ptr, | |
309 | int xflags) | |
310 | { | |
311 | const unsigned char *s = (const unsigned char *)p; | |
312 | - int len; | |
313 | + int len, mflags = 0; | |
314 | ||
315 | if (xflags & XFLG_WORD_SPLIT) { | |
316 | /* Skip over any initial whitespace. */ | |
7cb7ae4e | 317 | @@ -250,13 +377,19 @@ static const char *get_exclude_tok(const |
a55d21aa WD |
318 | p = (const char *)s; |
319 | } | |
320 | ||
321 | - /* Is this a '+' or '-' followed by a space (not whitespace)? */ | |
322 | + /* Is this a +/-/. followed by a space (not whitespace)? */ | |
ee1af13c | 323 | if (!(xflags & XFLG_WORDS_ONLY) |
a55d21aa WD |
324 | - && (*s == '-' || *s == '+') && s[1] == ' ') { |
325 | - *incl_ptr = *s == '+'; | |
326 | + && (*s == '-' || *s == '+' || *s == '.') && s[1] == ' ') { | |
327 | + if (*s == '+') | |
328 | + mflags |= MATCHFLG_INCLUDE; | |
329 | + else if (*s == '.') { | |
524989ae | 330 | + mflags |= MATCHFLG_MERGE_FILE; |
a55d21aa WD |
331 | + if (xflags & XFLG_DEF_INCLUDE) |
332 | + mflags |= MATCHFLG_INCLUDE; | |
333 | + } | |
334 | s += 2; | |
335 | - } else | |
336 | - *incl_ptr = xflags & XFLG_DEF_INCLUDE; | |
337 | + } else if (xflags & XFLG_DEF_INCLUDE) | |
338 | + mflags |= MATCHFLG_INCLUDE; | |
339 | ||
340 | if (xflags & XFLG_WORD_SPLIT) { | |
341 | const unsigned char *cp = s; | |
7cb7ae4e | 342 | @@ -268,9 +401,10 @@ static const char *get_exclude_tok(const |
a55d21aa WD |
343 | len = strlen(s); |
344 | ||
ee1af13c | 345 | if (*p == '!' && len == 1 && !(xflags & XFLG_WORDS_ONLY)) |
a55d21aa WD |
346 | - *incl_ptr = -1; |
347 | + mflags |= MATCHFLG_CLEAR_LIST; | |
348 | ||
349 | *len_ptr = len; | |
350 | + *flag_ptr = mflags; | |
351 | return (const char *)s; | |
352 | } | |
353 | ||
7cb7ae4e | 354 | @@ -278,7 +412,7 @@ static const char *get_exclude_tok(const |
a55d21aa WD |
355 | void add_exclude(struct exclude_list_struct *listp, const char *pattern, |
356 | int xflags) | |
357 | { | |
358 | - int pat_len, incl; | |
359 | + int pat_len, mflags; | |
360 | const char *cp; | |
361 | ||
362 | if (!pattern) | |
7cb7ae4e | 363 | @@ -287,27 +421,49 @@ void add_exclude(struct exclude_list_str |
a55d21aa WD |
364 | cp = pattern; |
365 | pat_len = 0; | |
366 | while (1) { | |
367 | - cp = get_exclude_tok(cp + pat_len, &pat_len, &incl, xflags); | |
368 | + cp = get_exclude_tok(cp + pat_len, &pat_len, &mflags, xflags); | |
369 | if (!pat_len) | |
370 | break; | |
524989ae | 371 | - /* If we got the special "!" token, clear the list. */ |
7cb7ae4e | 372 | - if (incl < 0) { |
524989ae WD |
373 | + if (mflags & MATCHFLG_CLEAR_LIST) { |
374 | if (verbose > 2) { | |
7cb7ae4e WD |
375 | rprintf(FINFO, |
376 | "[%s] clearing %sexclude list\n", | |
377 | who_am_i(), listp->debug_type); | |
378 | } | |
379 | free_exclude_list(listp); | |
380 | - } else { | |
381 | - make_exclude(listp, cp, pat_len, incl); | |
382 | - | |
383 | - if (verbose > 2) { | |
a55d21aa WD |
384 | - rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s)\n", |
385 | - who_am_i(), pat_len, cp, | |
386 | - listp->debug_type, | |
387 | - incl ? "include" : "exclude"); | |
388 | + continue; | |
389 | + } | |
524989ae | 390 | + if (mflags & MATCHFLG_MERGE_FILE) { |
a55d21aa WD |
391 | + char name[MAXPATHLEN]; |
392 | + if ((unsigned) pat_len >= sizeof name) | |
524989ae | 393 | + continue; /* XXX complain? */ |
a55d21aa | 394 | + strlcpy(name, cp, pat_len+1); |
524989ae | 395 | + if (strchr(name, '/') != NULL) { |
a55d21aa WD |
396 | + if (sanitize_paths) |
397 | + sanitize_path(name, curr_dir); | |
398 | + if (*name == '/') | |
399 | + cp = name; | |
400 | + else { | |
401 | + if (strlcpy(dirbuf + dirbuf_offset, | |
402 | + name, MAXPATHLEN - dirbuf_offset) | |
403 | + >= MAXPATHLEN - dirbuf_offset) | |
524989ae | 404 | + continue; /* XXX complain? */ |
a55d21aa WD |
405 | + cp = dirbuf; |
406 | + } | |
407 | + add_exclude_file(listp, cp, | |
408 | + xflags | XFLG_FATAL_ERRORS); | |
409 | + continue; | |
410 | } | |
411 | } | |
524989ae | 412 | + |
a55d21aa WD |
413 | + make_exclude(listp, cp, pat_len, mflags); |
414 | + | |
415 | + if (verbose > 2) { | |
416 | + rprintf(FINFO, "[%s] add_exclude(%.*s, %s%s%sclude)\n", | |
417 | + who_am_i(), pat_len, cp, listp->debug_type, | |
524989ae | 418 | + mflags & MATCHFLG_MERGE_FILE ? "FILE " : "", |
a55d21aa WD |
419 | + mflags & MATCHFLG_INCLUDE ? "in" : "ex"); |
420 | + } | |
421 | } | |
422 | } | |
423 | ||
7cb7ae4e | 424 | @@ -383,15 +539,19 @@ void send_exclude_list(int f) |
a55d21aa WD |
425 | l = strlcpy(p, ent->pattern, sizeof p); |
426 | if (l == 0 || l >= MAXPATHLEN) | |
427 | continue; | |
428 | - if (ent->directory) { | |
429 | + if (ent->match_flags & MATCHFLG_DIRECTORY) { | |
430 | p[l++] = '/'; | |
431 | p[l] = '\0'; | |
432 | } | |
433 | ||
434 | - if (ent->include) { | |
435 | + if (ent->match_flags & MATCHFLG_INCLUDE) { | |
436 | write_int(f, l + 2); | |
437 | write_buf(f, "+ ", 2); | |
438 | - } else if ((*p == '-' || *p == '+') && p[1] == ' ') { | |
524989ae | 439 | + } else if (ent->match_flags & MATCHFLG_MERGE_FILE) { |
a55d21aa WD |
440 | + write_int(f, l + 2); |
441 | + write_buf(f, ". ", 2); | |
442 | + } else if ((*p == '-' || *p == '+' || *p == '.') | |
443 | + && p[1] == ' ') { | |
444 | write_int(f, l + 2); | |
445 | write_buf(f, "- ", 2); | |
446 | } else | |
7cb7ae4e | 447 | @@ -432,6 +592,7 @@ void add_cvs_excludes(void) |
a55d21aa WD |
448 | char fname[MAXPATHLEN]; |
449 | char *p; | |
450 | ||
451 | + add_exclude(&exclude_list, ". .cvsignore", 0); | |
452 | add_exclude(&exclude_list, default_cvsignore, | |
ee1af13c | 453 | XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); |
a55d21aa | 454 | |
7cb7ae4e WD |
455 | --- flist.c 14 May 2004 21:23:41 -0000 1.222 |
456 | +++ flist.c 15 May 2004 00:36:36 -0000 | |
a55d21aa WD |
457 | @@ -39,8 +39,6 @@ extern int module_id; |
458 | extern int ignore_errors; | |
459 | extern int numeric_ids; | |
460 | ||
461 | -extern int cvs_exclude; | |
462 | - | |
463 | extern int recurse; | |
464 | extern char curr_dir[MAXPATHLEN]; | |
465 | extern char *files_from; | |
7cb7ae4e | 466 | @@ -65,7 +63,6 @@ extern int write_batch; |
a55d21aa WD |
467 | |
468 | extern struct exclude_list_struct exclude_list; | |
469 | extern struct exclude_list_struct server_exclude_list; | |
470 | -extern struct exclude_list_struct local_exclude_list; | |
471 | ||
472 | int io_error; | |
473 | ||
7cb7ae4e | 474 | @@ -210,8 +207,6 @@ int link_stat(const char *path, STRUCT_S |
a55d21aa WD |
475 | */ |
476 | static int check_exclude_file(char *fname, int is_dir, int exclude_level) | |
477 | { | |
478 | - int rc; | |
479 | - | |
480 | #if 0 /* This currently never happens, so avoid a useless compare. */ | |
481 | if (exclude_level == NO_EXCLUDES) | |
482 | return 0; | |
7cb7ae4e | 483 | @@ -233,10 +228,7 @@ static int check_exclude_file(char *fnam |
a55d21aa WD |
484 | if (exclude_level != ALL_EXCLUDES) |
485 | return 0; | |
486 | if (exclude_list.head | |
487 | - && (rc = check_exclude(&exclude_list, fname, is_dir)) != 0) | |
488 | - return rc < 0; | |
489 | - if (local_exclude_list.head | |
490 | - && check_exclude(&local_exclude_list, fname, is_dir) < 0) | |
491 | + && check_exclude(&exclude_list, fname, is_dir) < 0) | |
492 | return 1; | |
493 | return 0; | |
494 | } | |
7cb7ae4e | 495 | @@ -946,15 +938,7 @@ void send_file_name(int f, struct file_l |
a55d21aa WD |
496 | |
497 | if (recursive && S_ISDIR(file->mode) | |
498 | && !(file->flags & FLAG_MOUNT_POINT)) { | |
499 | - struct exclude_list_struct last_list = local_exclude_list; | |
500 | - local_exclude_list.head = local_exclude_list.tail = NULL; | |
501 | send_directory(f, flist, f_name_to(file, fbuf)); | |
7cb7ae4e WD |
502 | - if (verbose > 2) { |
503 | - rprintf(FINFO, "[%s] popping %sexclude list\n", | |
504 | - who_am_i(), local_exclude_list.debug_type); | |
505 | - } | |
a55d21aa WD |
506 | - free_exclude_list(&local_exclude_list); |
507 | - local_exclude_list = last_list; | |
508 | } | |
509 | } | |
510 | ||
7cb7ae4e | 511 | @@ -965,6 +949,7 @@ static void send_directory(int f, struct |
a55d21aa WD |
512 | struct dirent *di; |
513 | char fname[MAXPATHLEN]; | |
514 | unsigned int offset; | |
515 | + void *save_excludes; | |
516 | char *p; | |
517 | ||
518 | d = opendir(dir); | |
7cb7ae4e | 519 | @@ -989,18 +974,7 @@ static void send_directory(int f, struct |
a55d21aa WD |
520 | offset++; |
521 | } | |
522 | ||
523 | - if (cvs_exclude) { | |
524 | - if (strlcpy(p, ".cvsignore", MAXPATHLEN - offset) | |
525 | - < MAXPATHLEN - offset) { | |
526 | - add_exclude_file(&local_exclude_list, fname, | |
ee1af13c | 527 | - XFLG_WORD_SPLIT | XFLG_WORDS_ONLY); |
a55d21aa WD |
528 | - } else { |
529 | - io_error |= IOERR_GENERAL; | |
530 | - rprintf(FINFO, | |
531 | - "cannot cvs-exclude in long-named directory %s\n", | |
532 | - full_fname(fname)); | |
533 | - } | |
534 | - } | |
535 | + save_excludes = push_local_excludes(fname, offset); | |
536 | ||
537 | for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { | |
538 | char *dname = d_name(di); | |
7cb7ae4e | 539 | @@ -1021,6 +995,8 @@ static void send_directory(int f, struct |
a55d21aa WD |
540 | rprintf(FERROR, "readdir(%s): (%d) %s\n", |
541 | dir, errno, strerror(errno)); | |
542 | } | |
543 | + | |
544 | + pop_local_excludes(save_excludes); | |
545 | ||
546 | closedir(d); | |
547 | } | |
7cb7ae4e WD |
548 | --- rsync.h 13 May 2004 18:51:22 -0000 1.203 |
549 | +++ rsync.h 15 May 2004 00:36:36 -0000 | |
550 | @@ -493,18 +493,21 @@ struct map_struct { | |
a55d21aa WD |
551 | #define MATCHFLG_WILD2 (1<<1) /* pattern has '**' */ |
552 | #define MATCHFLG_WILD2_PREFIX (1<<2) /* pattern starts with '**' */ | |
553 | #define MATCHFLG_ABS_PATH (1<<3) /* path-match on absolute path */ | |
554 | +#define MATCHFLG_INCLUDE (1<<4) /* this is an include, not an exclude */ | |
555 | +#define MATCHFLG_CLEAR_LIST (1<<5) /* this item is the "!" token */ | |
556 | +#define MATCHFLG_DIRECTORY (1<<6) /* this matches only directories */ | |
524989ae | 557 | +#define MATCHFLG_MERGE_FILE (1<<7) /* specifies a file to merge */ |
a55d21aa WD |
558 | +#define MATCHFLG_CVSIGNORE (1<<8) /* parse this as a .cvsignore file */ |
559 | struct exclude_struct { | |
560 | struct exclude_struct *next; | |
561 | char *pattern; | |
562 | int match_flags; | |
563 | - int include; | |
564 | - int directory; | |
565 | int slash_cnt; | |
566 | }; | |
567 | ||
568 | struct exclude_list_struct { | |
569 | - struct exclude_struct *head; | |
570 | - struct exclude_struct *tail; | |
571 | + struct exclude_struct *head, *tail; | |
7cb7ae4e | 572 | + struct exclude_struct *parent; |
a55d21aa WD |
573 | char *debug_type; |
574 | }; | |
575 | ||
ea238f1c | 576 | --- rsync.yo 7 May 2004 00:18:37 -0000 1.169 |
7cb7ae4e | 577 | +++ rsync.yo 15 May 2004 00:36:37 -0000 |
ea238f1c | 578 | @@ -1075,6 +1075,72 @@ itemize( |
524989ae WD |
579 | it would be excluded by the "*") |
580 | ) | |
581 | ||
582 | +manpagesection(MERGING EXCLUDE FILES) | |
583 | + | |
584 | +You can merge whole files into an exclude file using a rule that starts | |
585 | +with a ". " (a dot followed by a space) and has a filename in place of the | |
586 | +pattern. There are two types of merge rules, single-instance and | |
587 | +per-directory: | |
588 | + | |
589 | +itemize( | |
590 | + it() If the filename has no slashes in it, it is a per-directory merge; | |
591 | + rsync scans every directory that is traversed and merges the named file's | |
592 | + contents (when it exists), putting the contents of each subdirectory's | |
593 | + file at the start of this per-directory sub-list (so subdirectories | |
594 | + inherit the contents of their parent directories by default, but each | |
595 | + subdirectory's rules have precedence over the parent's rules). | |
596 | + | |
597 | + it() If a filename has a slash in it, it is a single-instance merge; the | |
598 | + named file's contents will be merged into the current exclude file, | |
599 | + replacing the merge rule. Thus, you should use the name ./foo instead of | |
600 | + foo if you don't want to scan for "foo" in all the subdirectories of the | |
601 | + current directory. | |
602 | +) | |
603 | + | |
604 | +Note also that you can eliminate all the inherited rules for the current | |
605 | +per-directory ruleset by putting the list-clearing token (!) in the file. | |
606 | +This clears only the rules of the current per-directory sub-list (up | |
607 | +through the token) and only for the current directory and its | |
608 | +subdirectories. | |
609 | + | |
610 | +Here's an example. Specify the file that holds this set of rules via a | |
611 | +normal --exclude-from option: | |
612 | + | |
613 | +verb( | |
614 | + . /home/user/.global_excludes | |
615 | + - *.gz | |
616 | + . .excl | |
617 | + + *.[ch] | |
618 | + - *.o | |
619 | +) | |
620 | + | |
621 | +This will merge the contents of the /home/user/.global_excludes file at the | |
622 | +start of the list and also turns the ".excl" filename into a per-directory | |
623 | +exclude file whose local contents will be merged into the list in place of | |
624 | +the .excl line. | |
625 | + | |
626 | +Additionally, you can affect where the --cvs-exclude (-C) option's | |
627 | +inclusion of a per-directory .cvsignore file gets placed into your rules by | |
628 | +adding an explicit a merge rule for ".cvsignore". For instance, specifying | |
629 | +this: | |
630 | + | |
631 | +verb( | |
632 | + rsync -avC --exclude='. .cvsignore' --exclude-from=foo a/ b | |
633 | +) | |
634 | + | |
635 | +will merge all the per-directory .cvsignore rules at the start of your list | |
636 | +rather than at the end. This allows their dir-specific rules to supersede | |
637 | +your rules instead of being subservient to them. (The global rules taken | |
638 | +from the $HOME/.cvsignore file and from $CVSIGNORE are not affected by | |
639 | +this.) | |
640 | + | |
641 | +Note also that the parsing of any merge-file named ".cvsignore" is always | |
642 | +done in a CVS-compatible manner (even if -C wasn't specified) -- i.e. the | |
643 | +rules are always exclude rules (even when specified by an include option), | |
644 | +they are split on whitespace, no special prefixes or list-clearing tokens | |
645 | +are honored, and (for per-directory files) subdirectories don't inherit the | |
646 | +parent directory's rules. | |
647 | + | |
648 | manpagesection(BATCH MODE) | |
649 | ||
650 | bf(Note:) Batch mode should be considered experimental in this version |