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