Changed the option's name to perdir-exclude-from.
[rsync/rsync-patches.git] / perdir-exclude-from.diff
1 --- exclude.c   17 Apr 2004 17:55:45 -0000      1.68
2 +++ exclude.c   17 Apr 2004 18:13:35 -0000
3 @@ -27,6 +27,7 @@
4  #include "rsync.h"
5  
6  extern int verbose;
7 +extern int protocol_version;
8  extern int eol_nulls;
9  extern int list_only;
10  extern int recurse;
11 @@ -34,6 +35,7 @@ extern int recurse;
12  extern char curr_dir[];
13  
14  struct exclude_list_struct exclude_list;
15 +struct exclude_list_struct perdir_exclude_list;
16  struct exclude_list_struct local_exclude_list;
17  struct exclude_list_struct server_exclude_list;
18  char *exclude_path_prefix = NULL;
19 @@ -85,6 +87,8 @@ static void make_exclude(struct exclude_
20         for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
21                 ret->slash_cnt++;
22  
23 +       ret->next = listp->extra;
24 +
25         if (!listp->tail)
26                 listp->head = listp->tail = ret;
27         else {
28 @@ -106,6 +110,13 @@ void free_exclude_list(struct exclude_li
29         if (verbose > 2)
30                 rprintf(FINFO, "[%s] clearing exclude list\n", who_am_i());
31  
32 +       if (listp->extra) {
33 +               if (listp->tail)
34 +                       listp->tail->next = NULL;
35 +               else
36 +                       listp->head = NULL;
37 +       }
38 +
39         for (ent = listp->head; ent; ent = next) {
40                 next = ent->next;
41                 free_exclude(ent);
42 @@ -114,6 +125,13 @@ void free_exclude_list(struct exclude_li
43         memset(listp, 0, sizeof listp[0]);
44  }
45  
46 +void clear_exclude_list(struct exclude_list_struct *listp,
47 +                       struct exclude_struct *extra)
48 +{
49 +       listp->head = listp->extra = extra;
50 +       listp->tail = NULL;
51 +}
52 +
53  static int check_one_exclude(char *name, struct exclude_struct *ex,
54                               int name_is_dir)
55  {
56 @@ -213,21 +231,24 @@ static void report_exclude_result(char c
57  
58  /*
59   * Return true if file NAME is defined to be excluded by the specified
60 - * exclude list.
61 + * exclude list.  Returns -1 for exclude, 0 for normal include, or 1
62 + * for super include.
63   */
64  int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir,
65 -                 const char *type)
66 +                 const char *type, int current_exclusion)
67  {
68         struct exclude_struct *ent;
69  
70         for (ent = listp->head; ent; ent = ent->next) {
71 +               if (current_exclusion < 0 && ent->include < 2)
72 +                       continue;
73                 if (check_one_exclude(name, ent, name_is_dir)) {
74                         report_exclude_result(name, ent, name_is_dir, type);
75 -                       return !ent->include;
76 +                       return ent->include - 1;
77                 }
78         }
79  
80 -       return 0;
81 +       return current_exclusion;
82  }
83  
84  
85 @@ -253,10 +274,10 @@ static const char *get_exclude_tok(const
86                 p = (const char *)s;
87         }
88  
89 -       /* Is this a '+' or '-' followed by a space (not whitespace)? */
90 +       /* Is this a +/-/& followed by a space (not whitespace)? */
91         if (!(xflags & XFLG_NO_PREFIXES)
92 -           && (*s == '-' || *s == '+') && s[1] == ' ') {
93 -               *incl_ptr = *s == '+';
94 +           && (*s == '-' || *s == '+' || *s == '&') && s[1] == ' ') {
95 +               *incl_ptr = *s == '+' ? 1 : *s == '&' ? 2 : 0;
96                 s += 2;
97         } else
98                 *incl_ptr = xflags & XFLG_DEF_INCLUDE;
99 @@ -387,8 +408,12 @@ void send_exclude_list(int f)
100  
101                 if (ent->include) {
102                         write_int(f, l + 2);
103 -                       write_buf(f, "+ ", 2);
104 -               } else if ((*p == '-' || *p == '+') && p[1] == ' ') {
105 +                       if (ent->include > 1 && protocol_version >= 28)
106 +                               write_buf(f, "& ", 2);
107 +                       else
108 +                               write_buf(f, "+ ", 2);
109 +               } else if ((*p == '-' || *p == '+' || *p == '&')
110 +                   && p[1] == ' ') {
111                         write_int(f, l + 2);
112                         write_buf(f, "- ", 2);
113                 } else
114 --- flist.c     17 Apr 2004 17:14:12 -0000      1.214
115 +++ flist.c     17 Apr 2004 18:13:36 -0000
116 @@ -40,6 +40,7 @@ extern int ignore_errors;
117  extern int numeric_ids;
118  
119  extern int cvs_exclude;
120 +extern const char *perdir_exclude_from;
121  
122  extern int recurse;
123  extern char curr_dir[MAXPATHLEN];
124 @@ -66,6 +67,7 @@ extern int write_batch;
125  
126  extern struct exclude_list_struct exclude_list;
127  extern struct exclude_list_struct server_exclude_list;
128 +extern struct exclude_list_struct perdir_exclude_list;
129  extern struct exclude_list_struct local_exclude_list;
130  
131  int io_error;
132 @@ -211,6 +213,12 @@ int link_stat(const char *path, STRUCT_S
133   */
134  static int check_exclude_file(char *fname, int is_dir, int exclude_level)
135  {
136 +       static struct exclude_list_struct *elist[] = {
137 +           &exclude_list, &perdir_exclude_list, &local_exclude_list, NULL };
138 +       static char *edesc[] = {
139 +           "pattern", "perdir-exclude", "local-ignore" };
140 +       int i, rc;
141 +
142  #if 0 /* This currently never happens, so avoid a useless compare. */
143         if (exclude_level == NO_EXCLUDES)
144                 return 0;
145 @@ -228,18 +236,18 @@ static int check_exclude_file(char *fnam
146         }
147         if (server_exclude_list.head
148          && check_exclude(&server_exclude_list, fname, is_dir,
149 -                         "server pattern"))
150 +                         "server pattern", 0) < 0)
151                 return 1;
152         if (exclude_level != ALL_EXCLUDES)
153                 return 0;
154 -       if (exclude_list.head
155 -           && check_exclude(&exclude_list, fname, is_dir, "pattern"))
156 -               return 1;
157 -       if (local_exclude_list.head
158 -           && check_exclude(&local_exclude_list, fname, is_dir,
159 -                            "local-cvsignore"))
160 -               return 1;
161 -       return 0;
162 +       for (i = 0, rc = 0; elist[i]; i++) {
163 +               if (!elist[i]->head)
164 +                       continue;
165 +               rc = check_exclude(elist[i], fname, is_dir, edesc[i], rc);
166 +               if (rc > 0)
167 +                       return 0;
168 +       }
169 +       return rc < 0;
170  }
171  
172  /* used by the one_file_system code */
173 @@ -947,8 +955,12 @@ void send_file_name(int f, struct file_l
174         if (recursive && S_ISDIR(file->mode)
175             && !(file->flags & FLAG_MOUNT_POINT)) {
176                 struct exclude_list_struct last_list = local_exclude_list;
177 -               memset(&local_exclude_list, 0, sizeof local_exclude_list);
178 +               struct exclude_list_struct sub_list = perdir_exclude_list;
179 +               clear_exclude_list(&local_exclude_list, NULL);
180 +               clear_exclude_list(&perdir_exclude_list, sub_list.head);
181                 send_directory(f, flist, f_name_to(file, fbuf));
182 +               free_exclude_list(&perdir_exclude_list);
183 +               perdir_exclude_list = sub_list;
184                 free_exclude_list(&local_exclude_list);
185                 local_exclude_list = last_list;
186         }
187 @@ -994,6 +1006,18 @@ static void send_directory(int f, struct
188                         io_error |= IOERR_GENERAL;
189                         rprintf(FINFO,
190                                 "cannot cvs-exclude in long-named directory %s\n",
191 +                               full_fname(fname));
192 +               }
193 +       }
194 +
195 +       if (perdir_exclude_from) {
196 +               if (strlcpy(p, perdir_exclude_from, MAXPATHLEN - offset)
197 +                   < MAXPATHLEN - offset)
198 +                       add_exclude_file(&perdir_exclude_list, fname, 0);
199 +               else {
200 +                       io_error |= IOERR_GENERAL;
201 +                       rprintf(FINFO,
202 +                               "cannot perdir-exclude in long-named directory %s\n",
203                                 full_fname(fname));
204                 }
205         }
206 --- options.c   17 Apr 2004 17:07:23 -0000      1.147
207 +++ options.c   17 Apr 2004 18:13:36 -0000
208 @@ -70,6 +70,7 @@ int am_server = 0;
209  int am_sender = 0;
210  int am_generator = 0;
211  char *files_from = NULL;
212 +char *perdir_exclude_from = NULL;
213  int filesfrom_fd = -1;
214  char *remote_filesfrom_file = NULL;
215  int eol_nulls = 0;
216 @@ -273,6 +274,7 @@ void usage(enum logcode F)
217    rprintf(F,"     --exclude-from=FILE     exclude patterns listed in FILE\n");
218    rprintf(F,"     --include=PATTERN       don't exclude files matching PATTERN\n");
219    rprintf(F,"     --include-from=FILE     don't exclude patterns listed in FILE\n");
220 +  rprintf(F,"     --perdir-exclude-from=F look in each dir for exclude-file F\n");
221    rprintf(F,"     --files-from=FILE       read FILE for list of source-file names\n");
222    rprintf(F," -0  --from0                 all *-from file lists are delimited by nulls\n");
223    rprintf(F,"     --version               print version number\n");
224 @@ -335,6 +337,7 @@ static struct poptOption long_options[] 
225    {"dry-run",         'n', POPT_ARG_NONE,   &dry_run, 0, 0, 0 },
226    {"sparse",          'S', POPT_ARG_NONE,   &sparse_files, 0, 0, 0 },
227    {"cvs-exclude",     'C', POPT_ARG_NONE,   &cvs_exclude, 0, 0, 0 },
228 +  {"perdir-exclude-from",0,POPT_ARG_STRING, &perdir_exclude_from, 0, 0, 0 },
229    {"update",          'u', POPT_ARG_NONE,   &update_only, 0, 0, 0 },
230    {"links",           'l', POPT_ARG_NONE,   &preserve_links, 0, 0, 0 },
231    {"copy-links",      'L', POPT_ARG_NONE,   &copy_links, 0, 0, 0 },
232 --- proto.h     14 Apr 2004 23:33:30 -0000      1.188
233 +++ proto.h     17 Apr 2004 18:13:36 -0000
234 @@ -52,8 +52,10 @@ int daemon_main(void);
235  void setup_protocol(int f_out,int f_in);
236  int claim_connection(char *fname,int max_connections);
237  void free_exclude_list(struct exclude_list_struct *listp);
238 +void clear_exclude_list(struct exclude_list_struct *listp,
239 +                       struct exclude_struct *extra);
240  int check_exclude(struct exclude_list_struct *listp, char *name, int name_is_dir,
241 -                 const char *type);
242 +                 const char *type, int current_exclusion);
243  void add_exclude(struct exclude_list_struct *listp, const char *pattern,
244                  int xflags);
245  void add_exclude_file(struct exclude_list_struct *listp, const char *fname,
246 --- rsync.h     17 Apr 2004 17:14:16 -0000      1.197
247 +++ rsync.h     17 Apr 2004 18:13:36 -0000
248 @@ -502,6 +502,7 @@ struct exclude_struct {
249  struct exclude_list_struct {
250         struct exclude_struct *head;
251         struct exclude_struct *tail;
252 +       struct exclude_struct *extra;
253  };
254  
255  struct stats {
256 --- rsync.yo    17 Apr 2004 18:12:33 -0000      1.158
257 +++ rsync.yo    17 Apr 2004 18:13:37 -0000
258 @@ -331,6 +331,7 @@ verb(
259       --exclude-from=FILE     exclude patterns listed in FILE
260       --include=PATTERN       don't exclude files matching PATTERN
261       --include-from=FILE     don't exclude patterns listed in FILE
262 +     --perdir-exclude-from=F look in each dir for exclude file F
263       --files-from=FILE       read FILE for list of source-file names
264   -0  --from0                 all file lists are delimited by nulls
265       --version               print version number
266 @@ -672,6 +673,15 @@ dit(bf(--include-from=FILE)) This specif
267  from a file.
268  If em(FILE) is bf(-) the list will be read from standard input.
269  
270 +dit(bf(--perdir-exclude-from=FILE)) In any given directory, patterns
271 +listed in FILE (one per line) are excluded from the file lists
272 +associated with that directory and all of its subdirectories. Rules
273 +specified in a subdir take precedence over rules evaluated in a parent
274 +dir (think of each file's rules being prefixed to the prior rules).  If
275 +you don't want to inherit the parent-dir rules, start the FILE with a
276 +single exclamation mark ! to clear them out. You may prefix names with
277 +an explicit exclude, include, or super-include prefix (see below).
278 +
279  dit(bf(--files-from=FILE)) Using this option allows you to specify the
280  exact list of files to transfer (as read from the specified FILE or "-"
281  for stdin).  It also tweaks the default behavior of rsync to make
282 @@ -711,7 +721,8 @@ was located on the remote "src" host.
283  
284  dit(bf(-0, --from0)) This tells rsync that the filenames it reads from a
285  file are terminated by a null ('\0') character, not a NL, CR, or CR+LF.
286 -This affects --exclude-from, --include-from, and --files-from.
287 +This affects --exclude-from, --include-from, --perdir-exclude-from,
288 +and --files-from.
289  It does not affect --cvs-exclude (since all names read from a .cvsignore
290  file are split on whitespace).
291  
292 @@ -998,6 +1009,12 @@ itemize(
293    it() if the pattern starts with "- " (a minus followed by a space)
294    then it is always considered an exclude pattern, even if specified as
295    part of an include option. The prefix is discarded before matching.
296 +
297 +  it() if the pattern starts with "& " (an ampersand followed by a space)
298 +  then it is considered a super-include pattern.  A super-include will
299 +  override an exclude from another exclude list (a normal include only
300 +  overrides an exclusion from further down in the same list).  The
301 +  prefix is discarded before matching.
302  
303    it() if the pattern is a single exclamation mark ! then the current
304    include/exclude list is reset, removing all previously defined patterns.
305 --- util.c      17 Apr 2004 17:06:03 -0000      1.136
306 +++ util.c      17 Apr 2004 18:13:37 -0000
307 @@ -477,7 +477,7 @@ static int exclude_server_path(char *arg
308                 for (s = arg; (s = strchr(s, '/')) != NULL; ) {
309                         *s = '\0';
310                         if (check_exclude(&server_exclude_list, arg, 1,
311 -                           "server pattern")) {
312 +                                         "server pattern", 0) < 0) {
313                                 /* We must leave arg truncated! */
314                                 return 1;
315                         }