From 66b47d422743f991410f9b1c571277961673991f Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 5 Feb 2005 07:25:54 +0000 Subject: [PATCH] A patch that makes it possible to write filter rules that affect the sender, the receiver, or both (the latter can protect against the deleting power of --delete-excluded). --- sender-receiver-excludes.diff | 297 ++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 sender-receiver-excludes.diff diff --git a/sender-receiver-excludes.diff b/sender-receiver-excludes.diff new file mode 100644 index 0000000..ee42f25 --- /dev/null +++ b/sender-receiver-excludes.diff @@ -0,0 +1,297 @@ +This patch adds two modifiers to the filter rule prefixes that allow a +rule to be marked as sender-side (s), receiver-side (r), or both ("sr" +or omitted). Sender-side rules prevent files from being transferred, +while receiver-side rules prevent files from being deleted. The default +for an unmodified include/exclude rule is to affect both sides, but a +rule that is explicitly marked as affecting both sides will remain +unaffected by the --delete-excluded option (that option changes any +unmodified rules into server-side only rules). + +See the updated manpage for the details. + +--- orig/compat.c 2005-02-01 10:39:22 ++++ compat.c 2005-02-05 05:31:06 +@@ -31,6 +31,7 @@ extern int verbose; + extern int am_server; + extern int am_sender; + extern int read_batch; ++extern int delete_excluded; + extern int checksum_seed; + extern int protocol_version; + +@@ -74,6 +75,12 @@ void setup_protocol(int f_out,int f_in) + exit_cleanup(RERR_PROTOCOL); + } + ++ /* In newer protocols, --delete-excluded does not avoid the exclude- ++ * list transfer to the receiver, so mark a modern --delete-excluded ++ * conversation with a 2 instead of a 1. */ ++ if (protocol_version >= 29 && delete_excluded) ++ delete_excluded = 2; ++ + if (am_server) { + if (!checksum_seed) + checksum_seed = time(NULL); +--- orig/exclude.c 2005-02-05 06:48:21 ++++ exclude.c 2005-02-05 06:56:47 +@@ -53,7 +53,8 @@ struct filter_list_struct server_filter_ + #define MAX_RULE_PREFIX (16) + + #define MODIFIERS_MERGE_FILE "-+Cenw" +-#define MODIFIERS_INCL_EXCL "/!C" ++#define MODIFIERS_INCL_EXCL "/!Crs" ++#define MODIFIERS_HIDE_PROTECT "/!" + + /* The dirbuf is set by push_local_filters() to the current subdirectory + * relative to curr_dir that is being processed. The path always has a +@@ -667,6 +668,14 @@ static const char *parse_rule_tok(const + case '-': + mods = MODIFIERS_INCL_EXCL; + break; ++ case 'H': ++ new_mflags |= MATCHFLG_SENDER_SIDE; ++ mods = MODIFIERS_HIDE_PROTECT; ++ break; ++ case 'P': ++ new_mflags |= MATCHFLG_RECEIVER_SIDE; ++ mods = MODIFIERS_HIDE_PROTECT; ++ break; + case '!': + new_mflags |= MATCHFLG_CLEAR_LIST; + mods = NULL; +@@ -719,6 +728,12 @@ static const char *parse_rule_tok(const + case 'n': + new_mflags |= MATCHFLG_NO_INHERIT; + break; ++ case 'r': ++ new_mflags |= MATCHFLG_RECEIVER_SIDE; ++ break; ++ case 's': ++ new_mflags |= MATCHFLG_SENDER_SIDE; ++ break; + case 'w': + new_mflags |= MATCHFLG_WORD_SPLIT; + break; +@@ -973,6 +988,11 @@ char *get_rule_prefix(int match_flags, c + } + if (match_flags & MATCHFLG_EXCLUDE_SELF) + *op++ = 'e'; ++ if (match_flags & MATCHFLG_SENDER_SIDE && !for_xfer) ++ *op++ = 's'; ++ if (match_flags & MATCHFLG_RECEIVER_SIDE ++ && (!for_xfer || delete_excluded)) ++ *op++ = 'r'; + if (legal_len) + *op++ = ' '; + if (op - buf > legal_len) +@@ -985,19 +1005,37 @@ char *get_rule_prefix(int match_flags, c + + static void send_rules(int f_out, struct filter_list_struct *flp) + { +- struct filter_struct *ent; ++ struct filter_struct *ent, *prev = NULL; + + for (ent = flp->head; ent; ent = ent->next) { + unsigned int len, plen, dlen; ++ int elide = 0; + char *p; + ++ if (ent->match_flags & MATCHFLG_SENDER_SIDE) ++ elide = am_sender ? 1 : -1; ++ if (ent->match_flags & MATCHFLG_RECEIVER_SIDE) ++ elide = elide ? 0 : am_sender ? -1 : 1; ++ else if (delete_excluded) ++ elide = am_sender ? 1 : -1; ++ if (elide < 0) { ++ if (prev) ++ prev->next = ent->next; ++ else ++ flp->head = ent->next; ++ } else ++ prev = ent; ++ if (elide > 0) ++ continue; + if (ent->match_flags & MATCHFLG_CVS_IGNORE + && !(ent->match_flags & MATCHFLG_MERGE_FILE)) { +- if (am_sender || protocol_version < 29) { +- send_rules(f_out, &cvs_filter_list); ++ int f = am_sender || protocol_version < 29 ? f_out : -1; ++ send_rules(f, &cvs_filter_list); ++ if (f >= 0) + continue; +- } + } ++ if (f_out < 0) ++ continue; + p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen); + if (!p) { + rprintf(FERROR, +@@ -1015,12 +1053,13 @@ static void send_rules(int f_out, struct + if (dlen) + write_byte(f_out, '/'); + } ++ flp->tail = prev; + } + + /* This is only called by the client. */ + void send_filter_list(int f_out) + { +- int receiver_wants_list = delete_mode && !delete_excluded; ++ int receiver_wants_list = delete_mode && delete_excluded != 1; + + if (local_server || (am_sender && !receiver_wants_list)) + f_out = -1; +@@ -1035,10 +1074,10 @@ void send_filter_list(int f_out) + if (list_only == 1 && !recurse) + parse_rule(&filter_list, "/*/*", MATCHFLG_NO_PREFIXES, 0); + +- if (f_out >= 0) { +- send_rules(f_out, &filter_list); ++ send_rules(f_out, &filter_list); ++ ++ if (f_out >= 0) + write_int(f_out, 0); +- } + + if (cvs_exclude) { + if (!am_sender || protocol_version < 29) +@@ -1054,7 +1093,7 @@ void recv_filter_list(int f_in) + char line[MAXPATHLEN+MAX_RULE_PREFIX+1]; /* +1 for trailing slash. */ + int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES; + unsigned int len; +- int receiver_wants_list = delete_mode && !delete_excluded; ++ int receiver_wants_list = delete_mode && delete_excluded != 1; + + if (!local_server && (am_sender || receiver_wants_list)) { + while ((len = read_int(f_in)) != 0) { +@@ -1071,4 +1110,7 @@ void recv_filter_list(int f_in) + if (local_server || am_sender) + parse_rule(&filter_list, "-C", 0, 0); + } ++ ++ if (local_server) /* filter out any rules that aren't for us. */ ++ send_rules(-1, &filter_list); + } +--- orig/flist.c 2005-02-03 19:23:55 ++++ flist.c 2005-02-05 05:31:09 +@@ -979,7 +979,7 @@ void send_file_name(int f, struct file_l + + /* f is set to -1 when calculating deletion file list */ + file = make_file(fname, flist, +- f == -1 && delete_excluded? SERVER_FILTERS : ALL_FILTERS); ++ f == -1 && delete_excluded == 1 ? SERVER_FILTERS : ALL_FILTERS); + + if (!file) + return; +--- orig/rsync.h 2005-02-04 22:28:09 ++++ rsync.h 2005-02-05 05:31:10 +@@ -565,9 +565,12 @@ struct map_struct { + #define MATCHFLG_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */ + #define MATCHFLG_NEGATE (1<<14)/* rule matches when pattern does not */ + #define MATCHFLG_CVS_IGNORE (1<<15)/* rule was -C or :C */ ++#define MATCHFLG_SENDER_SIDE (1<<16)/* rule applies to the sender side */ ++#define MATCHFLG_RECEIVER_SIDE (1<<17)/* rule applies to the receiver side */ + + #define MATCHFLGS_FROM_CONTAINER (MATCHFLG_ABS_PATH | MATCHFLG_INCLUDE \ +- | MATCHFLG_DIRECTORY | MATCHFLG_NEGATE) ++ | MATCHFLG_DIRECTORY | MATCHFLG_SENDER_SIDE \ ++ | MATCHFLG_NEGATE | MATCHFLG_RECEIVER_SIDE) + + struct filter_struct { + struct filter_struct *next; +--- orig/rsync.yo 2005-02-05 01:23:49 ++++ rsync.yo 2005-02-05 05:31:11 +@@ -678,7 +678,9 @@ send the whole directory (e.g. "dir" or + for the directory's contents (e.g. "dir/*") since the wildcard is expanded + by the shell and rsync thus gets a request to transfer individual files, not + the files' parent directory. Files that are excluded from transfer are +-excluded from being deleted unless you use bf(--delete-excluded). ++also excluded from being deleted unless you use the bf(--delete-excluded) ++option or mark the rules as only matching on the sending side (see the ++include/exclude modifiers in the FILTER RULES section). + + This option has no effect unless directory recursion is enabled. + +@@ -725,6 +727,9 @@ See bf(--delete) (which is implied) for + dit(bf(--delete-excluded)) In addition to deleting the files on the + receiving side that are not on the sending side, this tells rsync to also + delete any files on the receiving side that are excluded (see bf(--exclude)). ++See the FILTER RULES section for a way to make individual exclusions behave ++this way on the receiver, and for a way to protect files from ++bf(--delete-excluded). + See bf(--delete) (which is implied) for more details on file-deletion. + + dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files +@@ -1241,6 +1246,8 @@ bf(-) specifies an exclude pattern. nl() + bf(+) specifies an include pattern. nl() + bf(.) specifies a merge-file to read for more rules. nl() + bf(:) specifies a per-directory merge-file. nl() ++bf(H) specifies a pattern for hiding files from the transfer. nl() ++bf(P) specifies a pattern for protecting files from deletion. nl() + bf(!) clears the current include/exclude list (takes no arg) nl() + ) + +@@ -1263,10 +1270,17 @@ comment lines that start with a "#". + + manpagesection(INCLUDE/EXCLUDE PATTERN RULES) + +-You can include and exclude files by specifying patterns using the "+" and +-"-" filter rules (as introduced in the FILTER RULES section above). These +-rules specify a pattern that is matched against the names of the files +-that are going to be transferred. These patterns can take several forms: ++You can include and exclude files by specifying patterns using the "+", ++"-", "H", and "P" filter rules (as introduced in the FILTER RULES section ++above). ++Note that the "H" (hide) rule is just a more intuitive way to specify a "-" ++rule with an "s" modifier (a sender-only exclusion) and "P" (protect) is ++just a more intuitive way to specify a "-" rule with an "r" modifier (a ++receiver-only exclusion). See the modifiers below for more information. ++ ++The include/exclude rules each specify a pattern that is matched against ++the names of the files that are going to be transferred. These patterns ++can take several forms: + + itemize( + it() if the pattern starts with a / then it is anchored to a +@@ -1398,6 +1412,9 @@ itemize( + space that separates the prefix from the rule is treated specially, so + "- foo + bar" is parsed as two rules (assuming that bf(-) or bf(+) was not + specified to turn off the parsing of prefixes). ++ it() You may also specify any of the modifiers for "+" or "-" to have the ++ rules that are read-in default to having that option set. For instance, ++ ":s_.excl" would make all the rules in .excl server-side only. + ) + + The following modifiers are accepted after a "+" or "-": +@@ -1413,6 +1430,16 @@ itemize( + it() A bf(C) is used to indicate that all the global CVS-exclude rules + should be inserted as excludes in place of the "-C". No arg should + follow. ++ it() An bf(s) is used to indicate that the rule applies to the sending ++ side. When a rule affects the sending side it, prevents files from ++ being transferred. The default is for a rule to affect both sides ++ unless bf(--delete-excluded) was specified, in which case default rules ++ become sender-side only. See also the "H" (hide) rule, which is an ++ alias for the "-" rule with the "s" modifer. ++ it() An bf(r) is used to indicate that the rule applies to the receiving ++ side. When a rule affects the receiving side it, prevents files from ++ being deleted. See the bf(s) modifier for more info. See also the "P" ++ (protect) rule, which is an alias for the "-" rule with the "r" modifier. + ) + + Per-directory rules are inherited in all subdirectories of the directory +@@ -1706,10 +1733,10 @@ error. + When reading a batch file, rsync will force the value of certain options + to match the data in the batch file if you didn't set them to the same + as the batch-writing command. Other options can (and should) be changed. +-For instance +-bf(--write-batch) changes to bf(--read-batch), bf(--files-from) is dropped, and the +-bf(--filter)/bf(--include)/bf(--exclude) options are not needed unless one of the +-bf(--delete) options is specified without bf(--delete-excluded). ++For instance bf(--write-batch) changes to bf(--read-batch), ++bf(--files-from) is dropped, and the ++bf(--filter)/bf(--include)/bf(--exclude) options are not needed unless ++one of the bf(--delete) options is specified. + + The code that creates the BATCH.sh file transforms any filter/include/exclude + options into a single list that is appended as a "here" document to the -- 2.34.1