Fixed a failing hunk for the latest manpage.
[rsync/rsync-patches.git] / sender-receiver-excludes.diff
1 This patch adds two modifiers to the filter rule prefixes that allow a
2 rule to be marked as sender-side (s), receiver-side (r), or both ("sr"
3 or omitted).  Sender-side rules prevent files from being transferred,
4 while receiver-side rules prevent files from being deleted.  The default
5 for an unmodified include/exclude rule is to affect both sides, but a
6 rule that is explicitly marked as affecting both sides will remain
7 unaffected by the --delete-excluded option (that option changes any
8 unmodified rules into server-side only rules).
9
10 See the updated manpage for the details.
11
12 --- orig/compat.c       2005-02-01 10:39:22
13 +++ compat.c    2005-02-05 05:31:06
14 @@ -31,6 +31,7 @@ extern int verbose;
15  extern int am_server;
16  extern int am_sender;
17  extern int read_batch;
18 +extern int delete_excluded;
19  extern int checksum_seed;
20  extern int protocol_version;
21  
22 @@ -74,6 +75,12 @@ void setup_protocol(int f_out,int f_in)
23                 exit_cleanup(RERR_PROTOCOL);
24         }
25  
26 +       /* In newer protocols, --delete-excluded does not avoid the exclude-
27 +        * list transfer to the receiver, so mark a modern --delete-excluded
28 +        * conversation with a 2 instead of a 1. */
29 +       if (protocol_version >= 29 && delete_excluded)
30 +               delete_excluded = 2;
31 +
32         if (am_server) {
33                 if (!checksum_seed)
34                         checksum_seed = time(NULL);
35 --- orig/exclude.c      2005-02-11 10:53:14
36 +++ exclude.c   2005-02-11 22:39:37
37 @@ -53,7 +53,8 @@ struct filter_list_struct server_filter_
38  #define MAX_RULE_PREFIX (16)
39  
40  #define MODIFIERS_MERGE_FILE "-+Cenw"
41 -#define MODIFIERS_INCL_EXCL "/!C"
42 +#define MODIFIERS_INCL_EXCL "/!Crs"
43 +#define MODIFIERS_HIDE_PROTECT "/!"
44  
45  /* The dirbuf is set by push_local_filters() to the current subdirectory
46   * relative to curr_dir that is being processed.  The path always has a
47 @@ -678,6 +679,10 @@ static const char *parse_rule_tok(const 
48                         if ((s = RULE_STRCMP(s, "exclude")) != NULL)
49                                 ch = '-';
50                         break;
51 +               case 'h':
52 +                       if ((s = RULE_STRCMP(s, "hide")) != NULL)
53 +                               ch = 'H';
54 +                       break;
55                 case 'i':
56                         if ((s = RULE_STRCMP(s, "include")) != NULL)
57                                 ch = '+';
58 @@ -686,6 +691,19 @@ static const char *parse_rule_tok(const 
59                         if ((s = RULE_STRCMP(s, "merge")) != NULL)
60                                 ch = '.';
61                         break;
62 +               case 'p':
63 +                       if ((s = RULE_STRCMP(s, "protect")) != NULL)
64 +                               ch = 'P';
65 +                       break;
66 +               case 'r':
67 +                       if ((s = RULE_STRCMP(s, "risk")) != NULL)
68 +                               ch = 'R';
69 +                       break;
70 +               case 's':
71 +                       if ((s = RULE_STRCMP(s, "show")) != NULL)
72 +                               ch = 'S';
73 +                       break;
74 +
75                 default:
76                         ch = *s;
77                         if (s[1] == ',')
78 @@ -707,6 +725,20 @@ static const char *parse_rule_tok(const 
79                 case '-':
80                         mods = MODIFIERS_INCL_EXCL;
81                         break;
82 +               case 'S':
83 +                       new_mflags |= MATCHFLG_INCLUDE;
84 +                       /* FALL THROUGH */
85 +               case 'H':
86 +                       new_mflags |= MATCHFLG_SENDER_SIDE;
87 +                       mods = MODIFIERS_HIDE_PROTECT;
88 +                       break;
89 +               case 'R':
90 +                       new_mflags |= MATCHFLG_INCLUDE;
91 +                       /* FALL THROUGH */
92 +               case 'P':
93 +                       new_mflags |= MATCHFLG_RECEIVER_SIDE;
94 +                       mods = MODIFIERS_HIDE_PROTECT;
95 +                       break;
96                 case '!':
97                         new_mflags |= MATCHFLG_CLEAR_LIST;
98                         mods = NULL;
99 @@ -759,6 +791,12 @@ static const char *parse_rule_tok(const 
100                         case 'n':
101                                 new_mflags |= MATCHFLG_NO_INHERIT;
102                                 break;
103 +                       case 'r':
104 +                               new_mflags |= MATCHFLG_RECEIVER_SIDE;
105 +                               break;
106 +                       case 's':
107 +                               new_mflags |= MATCHFLG_SENDER_SIDE;
108 +                               break;
109                         case 'w':
110                                 new_mflags |= MATCHFLG_WORD_SPLIT;
111                                 break;
112 @@ -1013,6 +1051,11 @@ char *get_rule_prefix(int match_flags, c
113         }
114         if (match_flags & MATCHFLG_EXCLUDE_SELF)
115                 *op++ = 'e';
116 +       if (match_flags & MATCHFLG_SENDER_SIDE && !for_xfer)
117 +               *op++ = 's';
118 +       if (match_flags & MATCHFLG_RECEIVER_SIDE
119 +           && (!for_xfer || (delete_excluded && am_sender)))
120 +               *op++ = 'r';
121         if (legal_len)
122                 *op++ = ' ';
123         if (op - buf > legal_len)
124 @@ -1025,19 +1068,37 @@ char *get_rule_prefix(int match_flags, c
125  
126  static void send_rules(int f_out, struct filter_list_struct *flp)
127  {
128 -       struct filter_struct *ent;
129 +       struct filter_struct *ent, *prev = NULL;
130  
131         for (ent = flp->head; ent; ent = ent->next) {
132                 unsigned int len, plen, dlen;
133 +               int elide = 0;
134                 char *p;
135  
136 +               if (ent->match_flags & MATCHFLG_SENDER_SIDE)
137 +                       elide = am_sender ? 1 : -1;
138 +               if (ent->match_flags & MATCHFLG_RECEIVER_SIDE)
139 +                       elide = elide ? 0 : am_sender ? -1 : 1;
140 +               else if (delete_excluded)
141 +                       elide = am_sender ? 1 : -1;
142 +               if (elide < 0) {
143 +                       if (prev)
144 +                               prev->next = ent->next;
145 +                       else
146 +                               flp->head = ent->next;
147 +               } else
148 +                       prev = ent;
149 +               if (elide > 0)
150 +                       continue;
151                 if (ent->match_flags & MATCHFLG_CVS_IGNORE
152                     && !(ent->match_flags & MATCHFLG_MERGE_FILE)) {
153 -                       if (am_sender || protocol_version < 29) {
154 -                               send_rules(f_out, &cvs_filter_list);
155 +                       int f = am_sender || protocol_version < 29 ? f_out : -1;
156 +                       send_rules(f, &cvs_filter_list);
157 +                       if (f >= 0)
158                                 continue;
159 -                       }
160                 }
161 +               if (f_out < 0)
162 +                       continue;
163                 p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen);
164                 if (!p) {
165                         rprintf(FERROR,
166 @@ -1055,12 +1116,13 @@ static void send_rules(int f_out, struct
167                 if (dlen)
168                         write_byte(f_out, '/');
169         }
170 +       flp->tail = prev;
171  }
172  
173  /* This is only called by the client. */
174  void send_filter_list(int f_out)
175  {
176 -       int receiver_wants_list = delete_mode && !delete_excluded;
177 +       int receiver_wants_list = delete_mode && delete_excluded != 1;
178  
179         if (local_server || (am_sender && !receiver_wants_list))
180                 f_out = -1;
181 @@ -1075,10 +1137,10 @@ void send_filter_list(int f_out)
182         if (list_only == 1 && !recurse)
183                 parse_rule(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0);
184  
185 -       if (f_out >= 0) {
186 -               send_rules(f_out, &filter_list);
187 +       send_rules(f_out, &filter_list);
188 +
189 +       if (f_out >= 0)
190                 write_int(f_out, 0);
191 -       }
192  
193         if (cvs_exclude) {
194                 if (!am_sender || protocol_version < 29)
195 @@ -1094,7 +1156,7 @@ void recv_filter_list(int f_in)
196         char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */
197         int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES;
198         unsigned int len;
199 -       int receiver_wants_list = delete_mode && !delete_excluded;
200 +       int receiver_wants_list = delete_mode && delete_excluded != 1;
201  
202         if (!local_server && (am_sender || receiver_wants_list)) {
203                 while ((len = read_int(f_in)) != 0) {
204 @@ -1111,4 +1173,7 @@ void recv_filter_list(int f_in)
205                 if (local_server || am_sender)
206                         parse_rule(&filter_list, "-C", 0, 0);
207         }
208 +
209 +       if (local_server) /* filter out any rules that aren't for us. */
210 +               send_rules(-1, &filter_list);
211  }
212 --- orig/flist.c        2005-02-09 02:37:15
213 +++ flist.c     2005-02-05 05:31:09
214 @@ -978,7 +978,7 @@ void send_file_name(int f, struct file_l
215  
216         /* f is set to -1 when calculating deletion file list */
217         file = make_file(fname, flist,
218 -           f == -1 && delete_excluded? SERVER_FILTERS : ALL_FILTERS);
219 +           f == -1 && delete_excluded == 1 ? SERVER_FILTERS : ALL_FILTERS);
220  
221         if (!file)
222                 return;
223 --- orig/rsync.h        2005-02-07 20:41:57
224 +++ rsync.h     2005-02-05 05:31:10
225 @@ -565,9 +565,12 @@ struct map_struct {
226  #define MATCHFLG_FINISH_SETUP  (1<<13)/* per-dir merge file needs setup */
227  #define MATCHFLG_NEGATE        (1<<14)/* rule matches when pattern does not */
228  #define MATCHFLG_CVS_IGNORE    (1<<15)/* rule was -C or :C */
229 +#define MATCHFLG_SENDER_SIDE   (1<<16)/* rule applies to the sending side */
230 +#define MATCHFLG_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */
231  
232  #define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \
233 -                               | MATCHFLG_DIRECTORY | MATCHFLG_NEGATE)
234 +                               | MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \
235 +                               | MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE)
236  
237  struct filter_struct {
238         struct filter_struct *next;
239 --- orig/rsync.yo       2005-02-11 10:53:15
240 +++ rsync.yo    2005-02-11 22:40:50
241 @@ -679,7 +679,9 @@ send the whole directory (e.g. "dir" or 
242  for the directory's contents (e.g. "dir/*") since the wildcard is expanded
243  by the shell and rsync thus gets a request to transfer individual files, not
244  the files' parent directory.  Files that are excluded from transfer are
245 -excluded from being deleted unless you use bf(--delete-excluded).
246 +also excluded from being deleted unless you use the bf(--delete-excluded)
247 +option or mark the rules as only matching on the sending side (see the
248 +include/exclude modifiers in the FILTER RULES section).
249  
250  This option has no effect unless directory recursion is enabled.
251  
252 @@ -726,6 +728,9 @@ See bf(--delete) (which is implied) for 
253  dit(bf(--delete-excluded)) In addition to deleting the files on the
254  receiving side that are not on the sending side, this tells rsync to also
255  delete any files on the receiving side that are excluded (see bf(--exclude)).
256 +See the FILTER RULES section for a way to make individual exclusions behave
257 +this way on the receiver, and for a way to protect files from
258 +bf(--delete-excluded).
259  See bf(--delete) (which is implied) for more details on file-deletion.
260  
261  dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files
262 @@ -1255,6 +1260,10 @@ bf(exclude, -) specifies an exclude patt
263  bf(include, +) specifies an include pattern. nl()
264  bf(merge, .) specifies a merge-file to read for more rules. nl()
265  bf(dir-merge, :) specifies a per-directory merge-file. nl()
266 +bf(hide, H) specifies a pattern for hiding files from the transfer. nl()
267 +bf(show, S) files that match the pattern are not hidden. nl()
268 +bf(protect, P) specifies a pattern for protecting files from deletion. nl()
269 +bf(risk, R) files that match the pattern are not protected. nl()
270  bf(clear, !) clears the current include/exclude list (takes no arg) nl()
271  )
272  
273 @@ -1279,8 +1288,8 @@ the bf(--include-from)/bf(--exclude-from
274  
275  manpagesection(INCLUDE/EXCLUDE PATTERN RULES)
276  
277 -You can include and exclude files by specifying patterns using the "+" and
278 -"-" filter rules (as introduced in the FILTER RULES section above).
279 +You can include and exclude files by specifying patterns using the "+",
280 +"-", etc. filter rules (as introduced in the FILTER RULES section above).
281  The include/exclude rules each specify a pattern that is matched against
282  the names of the files that are going to be transferred.  These patterns
283  can take several forms:
284 @@ -1419,7 +1428,9 @@ itemize(
285    it() You may also specify any of the modifiers for the "+" or "-" rules
286    (below) in order  to have the rules that are read-in from the file
287    default to having that modifier set.  For instance, "merge,-/ .excl" would
288 -  treat the contents of .excl as absolute-path excludes.
289 +  treat the contents of .excl as absolute-path excludes,
290 +  while "dir-merge,s .filt" and ":sC" would each make all their
291 +  per-directory rules apply only on the server side.
292  )
293  
294  The following modifiers are accepted after a "+" or "-":
295 @@ -1435,7 +1446,18 @@ itemize(
296    it() A bf(C) is used to indicate that all the global CVS-exclude rules
297    should be inserted as excludes in place of the "-C".  No arg should
298    follow.
299 -  )
300 +  it() An bf(s) is used to indicate that the rule applies to the sending
301 +  side.  When a rule affects the sending side, it prevents files from
302 +  being transferred.  The default is for a rule to affect both sides
303 +  unless bf(--delete-excluded) was specified, in which case default rules
304 +  become sender-side only.  See also the hide (H) and show (S) rules,
305 +  which are an alternate way to specify server-side includes/excludes.
306 +  it() An bf(r) is used to indicate that the rule applies to the receiving
307 +  side.  When a rule affects the receiving side, it prevents files from
308 +  being deleted.  See the bf(s) modifier for more info.  See also the
309 +  protect (P) and risk (R) rules, which are an alternate way to
310 +  specify receiver-side includes/excludes.
311 +)
312  
313  Per-directory rules are inherited in all subdirectories of the directory
314  where the merge-file was found unless the 'n' modifier was used.  Each