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