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