rsync: incorporate upstream fixes
[feed/packages.git] / net / rsync / patches / 011-fix-bug-with-validating-remote-filter-rules.patch
diff --git a/net/rsync/patches/011-fix-bug-with-validating-remote-filter-rules.patch b/net/rsync/patches/011-fix-bug-with-validating-remote-filter-rules.patch
new file mode 100644 (file)
index 0000000..a43637b
--- /dev/null
@@ -0,0 +1,122 @@
+From 950730313de994d191ba2d5be575e97690b355e8 Mon Sep 17 00:00:00 2001
+From: Wayne Davison <wayne@opencoder.net>
+Date: Mon, 12 Sep 2022 22:02:00 -0700
+Subject: [PATCH] Fix bug with validing remote filter rules.
+
+---
+ exclude.c | 35 +++++++++++++++++++++--------------
+ flist.c   |  2 +-
+ rsync.h   |  1 +
+ 3 files changed, 23 insertions(+), 15 deletions(-)
+
+--- a/exclude.c
++++ b/exclude.c
+@@ -78,6 +78,10 @@ static filter_rule **mergelist_parents;
+ static int mergelist_cnt = 0;
+ static int mergelist_size = 0;
++#define LOCAL_RULE   1
++#define REMOTE_RULE  2
++static uchar cur_elide_value = REMOTE_RULE;
++
+ /* Each filter_list_struct describes a singly-linked list by keeping track
+  * of both the head and tail pointers.  The list is slightly unusual in that
+  * a parent-dir's content can be appended to the end of the local list in a
+@@ -220,6 +224,7 @@ static void add_rule(filter_rule_list *l
+                               slash_cnt++;
+               }
+       }
++      rule->elide = 0;
+       strlcpy(rule->pattern + pre_len, pat, pat_len + 1);
+       pat_len += pre_len;
+       if (suf_len) {
+@@ -900,7 +905,7 @@ static int rule_matches(const char *fnam
+       const char *strings[16]; /* more than enough */
+       const char *name = fname + (*fname == '/');
+-      if (!*name)
++      if (!*name || ex->elide == cur_elide_value)
+               return 0;
+       if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR))
+@@ -1016,6 +1021,15 @@ int name_is_excluded(const char *fname,
+       return 0;
+ }
++int check_server_filter(filter_rule_list *listp, enum logcode code, const char *name, int name_flags)
++{
++      int ret;
++      cur_elide_value = LOCAL_RULE;
++      ret = check_filter(listp, code, name, name_flags);
++      cur_elide_value = REMOTE_RULE;
++      return ret;
++}
++
+ /* Return -1 if file "name" is defined to be excluded by the specified
+  * exclude list, 1 if it is included, and 0 if it was not matched. */
+ int check_filter(filter_rule_list *listp, enum logcode code,
+@@ -1571,7 +1585,7 @@ char *get_rule_prefix(filter_rule *rule,
+ static void send_rules(int f_out, filter_rule_list *flp)
+ {
+-      filter_rule *ent, *prev = NULL;
++      filter_rule *ent;
+       for (ent = flp->head; ent; ent = ent->next) {
+               unsigned int len, plen, dlen;
+@@ -1586,21 +1600,15 @@ static void send_rules(int f_out, filter
+                * merge files as an optimization (since they can only have
+                * include/exclude rules). */
+               if (ent->rflags & FILTRULE_SENDER_SIDE)
+-                      elide = am_sender ? 1 : -1;
++                      elide = am_sender ? LOCAL_RULE : REMOTE_RULE;
+               if (ent->rflags & FILTRULE_RECEIVER_SIDE)
+-                      elide = elide ? 0 : am_sender ? -1 : 1;
++                      elide = elide ? 0 : am_sender ? REMOTE_RULE : LOCAL_RULE;
+               else if (delete_excluded && !elide
+                && (!(ent->rflags & FILTRULE_PERDIR_MERGE)
+                 || ent->rflags & FILTRULE_NO_PREFIXES))
+-                      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)
++                      elide = am_sender ? LOCAL_RULE : REMOTE_RULE;
++              ent->elide = elide;
++              if (elide == LOCAL_RULE)
+                       continue;
+               if (ent->rflags & FILTRULE_CVS_IGNORE
+                   && !(ent->rflags & FILTRULE_MERGE_FILE)) {
+@@ -1628,7 +1636,6 @@ static void send_rules(int f_out, filter
+               if (dlen)
+                       write_byte(f_out, '/');
+       }
+-      flp->tail = prev;
+ }
+ /* This is only called by the client. */
+--- a/flist.c
++++ b/flist.c
+@@ -989,7 +989,7 @@ static struct file_struct *recv_file_ent
+       if (*thisname != '.' || thisname[1] != '\0') {
+               int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE;
+               if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */
+-               && filter_list.head && check_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
++               && filter_list.head && check_server_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
+                       rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname);
+                       exit_cleanup(RERR_PROTOCOL);
+               }
+--- a/rsync.h
++++ b/rsync.h
+@@ -1023,6 +1023,7 @@ typedef struct filter_struct {
+               int slash_cnt;
+               struct filter_list_struct *mergelist;
+       } u;
++      uchar elide;
+ } filter_rule;
+ typedef struct filter_list_struct {