+/* If the "sending" flag is > 0, the prefix is made compatible with the
+ * current protocol_version (if possible) or a NULL is returned (if not
+ * possible). */
+char *get_rule_prefix(int match_flags, const char *pat, int sending,
+ unsigned int *plen_ptr)
+{
+ static char buf[MAX_RULE_PREFIX+1];
+ char *op = buf;
+ int legal_len = sending && protocol_version < 29 ? 1 : MAX_RULE_PREFIX;
+
+ if (match_flags & MATCHFLG_PERDIR_MERGE) {
+ if (legal_len == 1)
+ return NULL;
+ *op++ = ':';
+ } else if (match_flags & MATCHFLG_INCLUDE)
+ *op++ = '+';
+ else if (legal_len != 1
+ || ((*pat == '-' || *pat == '+') && pat[1] == ' '))
+ *op++ = '-';
+ else
+ legal_len = 0;
+
+ if (match_flags & MATCHFLG_EXCLUDE_SELF)
+ *op++ = 'e';
+ if (match_flags & MATCHFLG_CVS_IGNORE)
+ *op++ = 'C';
+ else {
+ if (match_flags & MATCHFLG_WORD_SPLIT)
+ *op++ = 's';
+ if (match_flags & MATCHFLG_NO_INHERIT)
+ *op++ = 'n';
+ if (match_flags & MATCHFLG_NO_PREFIXES) {
+ if (match_flags & MATCHFLG_INCLUDE)
+ *op++ = '+';
+ else
+ *op++ = '-';
+ }
+ }
+ if (op - buf > legal_len)
+ return NULL;
+ if (legal_len)
+ *op++ = ' ';
+ *op = '\0';
+ if (plen_ptr)
+ *plen_ptr = op - buf;
+ if (op - buf > MAX_RULE_PREFIX)
+ overflow("get_rule_prefix");
+ return buf;
+}
+
+static void send_rules(int f_out, struct filter_list_struct *flp)
+{
+ struct filter_struct *ent;
+
+ for (ent = flp->head; ent; ent = ent->next) {
+ unsigned int len, plen, dlen;
+ char *p;
+
+ 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);
+ continue;
+ }
+ }
+ p = get_rule_prefix(ent->match_flags, ent->pattern, 1, &plen);
+ if (!p) {
+ rprintf(FERROR,
+ "filter rules are too modern for remote rsync.\n");
+ exit_cleanup(RERR_SYNTAX);
+ }
+ len = strlen(ent->pattern);
+ dlen = ent->match_flags & MATCHFLG_DIRECTORY ? 1 : 0;
+ if (!(plen + len + dlen))
+ continue;
+ write_int(f_out, plen + len + dlen);
+ if (plen)
+ write_buf(f_out, p, plen);
+ write_buf(f_out, ent->pattern, len);
+ if (dlen)
+ write_byte(f_out, '/');
+ }
+}