| 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-05 06:48:21 |
| 36 | +++ exclude.c 2005-02-05 06:56:47 |
| 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 | @@ -667,6 +668,14 @@ static const char *parse_rule_tok(const |
| 48 | case '-': |
| 49 | mods = MODIFIERS_INCL_EXCL; |
| 50 | break; |
| 51 | + case 'H': |
| 52 | + new_mflags |= MATCHFLG_SENDER_SIDE; |
| 53 | + mods = MODIFIERS_HIDE_PROTECT; |
| 54 | + break; |
| 55 | + case 'P': |
| 56 | + new_mflags |= MATCHFLG_RECEIVER_SIDE; |
| 57 | + mods = MODIFIERS_HIDE_PROTECT; |
| 58 | + break; |
| 59 | case '!': |
| 60 | new_mflags |= MATCHFLG_CLEAR_LIST; |
| 61 | mods = NULL; |
| 62 | @@ -719,6 +728,12 @@ static const char *parse_rule_tok(const |
| 63 | case 'n': |
| 64 | new_mflags |= MATCHFLG_NO_INHERIT; |
| 65 | break; |
| 66 | + case 'r': |
| 67 | + new_mflags |= MATCHFLG_RECEIVER_SIDE; |
| 68 | + break; |
| 69 | + case 's': |
| 70 | + new_mflags |= MATCHFLG_SENDER_SIDE; |
| 71 | + break; |
| 72 | case 'w': |
| 73 | new_mflags |= MATCHFLG_WORD_SPLIT; |
| 74 | break; |
| 75 | @@ -973,6 +988,11 @@ char *get_rule_prefix(int match_flags, c |
| 76 | } |
| 77 | if (match_flags & MATCHFLG_EXCLUDE_SELF) |
| 78 | *op++ = 'e'; |
| 79 | + if (match_flags & MATCHFLG_SENDER_SIDE && !for_xfer) |
| 80 | + *op++ = 's'; |
| 81 | + if (match_flags & MATCHFLG_RECEIVER_SIDE |
| 82 | + && (!for_xfer || delete_excluded)) |
| 83 | + *op++ = 'r'; |
| 84 | if (legal_len) |
| 85 | *op++ = ' '; |
| 86 | if (op - buf > legal_len) |
| 87 | @@ -985,19 +1005,37 @@ char *get_rule_prefix(int match_flags, c |
| 88 | |
| 89 | static void send_rules(int f_out, struct filter_list_struct *flp) |
| 90 | { |
| 91 | - struct filter_struct *ent; |
| 92 | + struct filter_struct *ent, *prev = NULL; |
| 93 | |
| 94 | for (ent = flp->head; ent; ent = ent->next) { |
| 95 | unsigned int len, plen, dlen; |
| 96 | + int elide = 0; |
| 97 | char *p; |
| 98 | |
| 99 | + if (ent->match_flags & MATCHFLG_SENDER_SIDE) |
| 100 | + elide = am_sender ? 1 : -1; |
| 101 | + if (ent->match_flags & MATCHFLG_RECEIVER_SIDE) |
| 102 | + elide = elide ? 0 : am_sender ? -1 : 1; |
| 103 | + else if (delete_excluded) |
| 104 | + elide = am_sender ? 1 : -1; |
| 105 | + if (elide < 0) { |
| 106 | + if (prev) |
| 107 | + prev->next = ent->next; |
| 108 | + else |
| 109 | + flp->head = ent->next; |
| 110 | + } else |
| 111 | + prev = ent; |
| 112 | + if (elide > 0) |
| 113 | + continue; |
| 114 | if (ent->match_flags & MATCHFLG_CVS_IGNORE |
| 115 | && !(ent->match_flags & MATCHFLG_MERGE_FILE)) { |
| 116 | - if (am_sender || protocol_version < 29) { |
| 117 | - send_rules(f_out, &cvs_filter_list); |
| 118 | + int f = am_sender || protocol_version < 29 ? f_out : -1; |
| 119 | + send_rules(f, &cvs_filter_list); |
| 120 | + if (f >= 0) |
| 121 | continue; |
| 122 | - } |
| 123 | } |
| 124 | + if (f_out < 0) |
| 125 | + continue; |
| 126 | p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen); |
| 127 | if (!p) { |
| 128 | rprintf(FERROR, |
| 129 | @@ -1015,12 +1053,13 @@ static void send_rules(int f_out, struct |
| 130 | if (dlen) |
| 131 | write_byte(f_out, '/'); |
| 132 | } |
| 133 | + flp->tail = prev; |
| 134 | } |
| 135 | |
| 136 | /* This is only called by the client. */ |
| 137 | void send_filter_list(int f_out) |
| 138 | { |
| 139 | - int receiver_wants_list = delete_mode && !delete_excluded; |
| 140 | + int receiver_wants_list = delete_mode && delete_excluded != 1; |
| 141 | |
| 142 | if (local_server || (am_sender && !receiver_wants_list)) |
| 143 | f_out = -1; |
| 144 | @@ -1035,10 +1074,10 @@ void send_filter_list(int f_out) |
| 145 | if (list_only == 1 && !recurse) |
| 146 | parse_rule(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0); |
| 147 | |
| 148 | - if (f_out >= 0) { |
| 149 | - send_rules(f_out, &filter_list); |
| 150 | + send_rules(f_out, &filter_list); |
| 151 | + |
| 152 | + if (f_out >= 0) |
| 153 | write_int(f_out, 0); |
| 154 | - } |
| 155 | |
| 156 | if (cvs_exclude) { |
| 157 | if (!am_sender || protocol_version < 29) |
| 158 | @@ -1054,7 +1093,7 @@ void recv_filter_list(int f_in) |
| 159 | char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */ |
| 160 | int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES; |
| 161 | unsigned int len; |
| 162 | - int receiver_wants_list = delete_mode && !delete_excluded; |
| 163 | + int receiver_wants_list = delete_mode && delete_excluded != 1; |
| 164 | |
| 165 | if (!local_server && (am_sender || receiver_wants_list)) { |
| 166 | while ((len = read_int(f_in)) != 0) { |
| 167 | @@ -1071,4 +1110,7 @@ void recv_filter_list(int f_in) |
| 168 | if (local_server || am_sender) |
| 169 | parse_rule(&filter_list, "-C", 0, 0); |
| 170 | } |
| 171 | + |
| 172 | + if (local_server) /* filter out any rules that aren't for us. */ |
| 173 | + send_rules(-1, &filter_list); |
| 174 | } |
| 175 | --- orig/flist.c 2005-02-03 19:23:55 |
| 176 | +++ flist.c 2005-02-05 05:31:09 |
| 177 | @@ -979,7 +979,7 @@ void send_file_name(int f, struct file_l |
| 178 | |
| 179 | /* f is set to -1 when calculating deletion file list */ |
| 180 | file = make_file(fname, flist, |
| 181 | - f == -1 && delete_excluded? SERVER_FILTERS : ALL_FILTERS); |
| 182 | + f == -1 && delete_excluded == 1 ? SERVER_FILTERS : ALL_FILTERS); |
| 183 | |
| 184 | if (!file) |
| 185 | return; |
| 186 | --- orig/rsync.h 2005-02-04 22:28:09 |
| 187 | +++ rsync.h 2005-02-05 05:31:10 |
| 188 | @@ -565,9 +565,12 @@ struct map_struct { |
| 189 | #define MATCHFLG_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */ |
| 190 | #define MATCHFLG_NEGATE (1<<14)/* rule matches when pattern does not */ |
| 191 | #define MATCHFLG_CVS_IGNORE (1<<15)/* rule was -C or :C */ |
| 192 | +#define MATCHFLG_SENDER_SIDE (1<<16)/* rule applies to the sender side */ |
| 193 | +#define MATCHFLG_RECEIVER_SIDE (1<<17)/* rule applies to the receiver side */ |
| 194 | |
| 195 | #define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \ |
| 196 | - | MATCHFLG_DIRECTORY | MATCHFLG_NEGATE) |
| 197 | + | MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \ |
| 198 | + | MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE) |
| 199 | |
| 200 | struct filter_struct { |
| 201 | struct filter_struct *next; |
| 202 | --- orig/rsync.yo 2005-02-06 07:24:23 |
| 203 | +++ rsync.yo 2005-02-06 07:21:31 |
| 204 | @@ -678,7 +678,9 @@ send the whole directory (e.g. "dir" or |
| 205 | for the directory's contents (e.g. "dir/*") since the wildcard is expanded |
| 206 | by the shell and rsync thus gets a request to transfer individual files, not |
| 207 | the files' parent directory. Files that are excluded from transfer are |
| 208 | -excluded from being deleted unless you use bf(--delete-excluded). |
| 209 | +also excluded from being deleted unless you use the bf(--delete-excluded) |
| 210 | +option or mark the rules as only matching on the sending side (see the |
| 211 | +include/exclude modifiers in the FILTER RULES section). |
| 212 | |
| 213 | This option has no effect unless directory recursion is enabled. |
| 214 | |
| 215 | @@ -725,6 +727,9 @@ See bf(--delete) (which is implied) for |
| 216 | dit(bf(--delete-excluded)) In addition to deleting the files on the |
| 217 | receiving side that are not on the sending side, this tells rsync to also |
| 218 | delete any files on the receiving side that are excluded (see bf(--exclude)). |
| 219 | +See the FILTER RULES section for a way to make individual exclusions behave |
| 220 | +this way on the receiver, and for a way to protect files from |
| 221 | +bf(--delete-excluded). |
| 222 | See bf(--delete) (which is implied) for more details on file-deletion. |
| 223 | |
| 224 | dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files |
| 225 | @@ -1241,6 +1246,8 @@ bf(-) specifies an exclude pattern. nl() |
| 226 | bf(+) specifies an include pattern. nl() |
| 227 | bf(.) specifies a merge-file to read for more rules. nl() |
| 228 | bf(:) specifies a per-directory merge-file. nl() |
| 229 | +bf(H) specifies a pattern for hiding files from the transfer. nl() |
| 230 | +bf(P) specifies a pattern for protecting files from deletion. nl() |
| 231 | bf(!) clears the current include/exclude list (takes no arg) nl() |
| 232 | ) |
| 233 | |
| 234 | @@ -1263,8 +1270,13 @@ comment lines that start with a "#". |
| 235 | |
| 236 | manpagesection(INCLUDE/EXCLUDE PATTERN RULES) |
| 237 | |
| 238 | -You can include and exclude files by specifying patterns using the "+" and |
| 239 | -"-" filter rules (as introduced in the FILTER RULES section above). |
| 240 | +You can include and exclude files by specifying patterns using the "+", |
| 241 | +"-", "H", and "P" filter rules (as introduced in the FILTER RULES section |
| 242 | +above). |
| 243 | +Note that the "H" (hide) rule is just a more intuitive way to specify a "-" |
| 244 | +rule with an "s" modifier (a sender-only exclusion) and "P" (protect) is |
| 245 | +just a more intuitive way to specify a "-" rule with an "r" modifier (a |
| 246 | +receiver-only exclusion). See the modifiers below for more information. |
| 247 | |
| 248 | The include/exclude rules each specify a pattern that is matched against |
| 249 | the names of the files that are going to be transferred. These patterns |
| 250 | @@ -1402,7 +1414,9 @@ itemize( |
| 251 | specified to turn off the parsing of prefixes). |
| 252 | it() You may also specify any of the modifiers for "+" or "-" to have the |
| 253 | rules that are read-in default to having that option set. For instance, |
| 254 | - ".-/_.excl" would treat the contents of .excl as absolute-path excludes. |
| 255 | + ".-/_.excl" would treat the contents of .excl as absolute-path excludes, |
| 256 | + while ":s_.filt" and ":Cs" would each make all their per-directory |
| 257 | + rules apply only on the server side. |
| 258 | ) |
| 259 | |
| 260 | The following modifiers are accepted after a "+" or "-": |
| 261 | @@ -1418,6 +1432,16 @@ itemize( |
| 262 | it() A bf(C) is used to indicate that all the global CVS-exclude rules |
| 263 | should be inserted as excludes in place of the "-C". No arg should |
| 264 | follow. |
| 265 | + it() An bf(s) is used to indicate that the rule applies to the sending |
| 266 | + side. When a rule affects the sending side it, prevents files from |
| 267 | + being transferred. The default is for a rule to affect both sides |
| 268 | + unless bf(--delete-excluded) was specified, in which case default rules |
| 269 | + become sender-side only. See also the "H" (hide) rule, which is an |
| 270 | + alias for the "-" rule with the "s" modifer. |
| 271 | + it() An bf(r) is used to indicate that the rule applies to the receiving |
| 272 | + side. When a rule affects the receiving side it, prevents files from |
| 273 | + being deleted. See the bf(s) modifier for more info. See also the "P" |
| 274 | + (protect) rule, which is an alias for the "-" rule with the "r" modifier. |
| 275 | ) |
| 276 | |
| 277 | Per-directory rules are inherited in all subdirectories of the directory |