]> git.ipfire.org Git - thirdparty/rsync.git/commitdiff
Negotation env lists can specify "client & server"
authorWayne Davison <wayne@opencoder.net>
Fri, 26 Jun 2020 23:51:30 +0000 (16:51 -0700)
committerWayne Davison <wayne@opencoder.net>
Sat, 27 Jun 2020 00:56:57 +0000 (17:56 -0700)
NEWS.md
batch.c
compat.c
rsync.1.md

diff --git a/NEWS.md b/NEWS.md
index 2d81eb66d8e8d818b92adf2d88de00ba0b4f23eb..d579b955bde2b98ecb92528f428208e8889273e7 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -17,7 +17,8 @@ Protocol: 31 (unchanged)
 ### ENHANCEMENTS:
 
  - Allow the server side to restrict checksum & compression choices via
-   the same environment variables the client uses.
+   the same environment variables the client uses.  Allow the env vars
+   to be divided into "client list & server list" by the "`&`" char.
 
  - Simplify how the negotiation environment variables apply to older rsync
    versions.
diff --git a/batch.c b/batch.c
index 805acc6fe2aab15422a3e6dcca77f24bf261cb4c..582c8c161d83158ba2f235194e6d99acc6ff3292 100644 (file)
--- a/batch.c
+++ b/batch.c
@@ -269,14 +269,6 @@ void write_batch_shell_file(void)
                        err |= write_opt("--exclude-from", "-");
        }
 
-       /* We need to make sure that any protocol-based or negotiated choices get accurately
-        * reflected in the options we save AND that we avoid any need for --read-batch to
-        * do a string-based negotiation (since we don't write them into the file). */
-       if (do_compression)
-               err |= write_opt("--compress-choice", compress_choice);
-       if (strchr(checksum_choice, ',') || xfersum_type != parse_csum_name(NULL, -1))
-               err |= write_opt("--checksum-choice", checksum_choice);
-
        /* Elide the filename args from the option list, but scan for them in reverse. */
        for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) {
                if (strcmp(raw_argv[i], cooked_argv[j]) == 0) {
index ba14a8c52c17722aa22b40b12828663462767c4d..bf0b4e6d149f2179112887ed0f375c092fade02a 100644 (file)
--- a/compat.c
+++ b/compat.c
@@ -20,6 +20,7 @@
  */
 
 #include "rsync.h"
+#include "itypes.h"
 
 extern int am_server;
 extern int am_sender;
@@ -109,6 +110,9 @@ struct name_num_obj valid_compressions = {
 #define CF_INPLACE_PARTIAL_DIR (1<<6)
 #define CF_VARINT_FLIST_FLAGS (1<<7)
 
+#define ENV_CHECKSUM 0
+#define ENV_COMPRESS 1
+
 static const char *client_info;
 
 /* The server makes sure that if either side only supports a pre-release
@@ -262,10 +266,14 @@ static void init_nno_saw(struct name_num_obj *nno, int val)
 static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len)
 {
        char *to = tobuf, *tok = NULL;
-       int cnt = 0;
+       int saw_tok = 0, cnt = 0;
 
        while (1) {
-               if (*from == ' ' || !*from) {
+               int at_space = isSpace(from);
+               char ch = *from++;
+               if (ch == '&')
+                       ch = '\0';
+               if (!ch || at_space) {
                        if (tok) {
                                struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok);
                                if (nni && !nno->saw[nni->num]) {
@@ -279,9 +287,10 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
                                        }
                                } else
                                        to = tok - (tok != tobuf);
+                               saw_tok = 1;
                                tok = NULL;
                        }
-                       if (!*from++)
+                       if (!ch)
                                break;
                        continue;
                }
@@ -294,10 +303,13 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
                        to = tok - (tok != tobuf);
                        break;
                }
-               *to++ = *from++;
+               *to++ = ch;
        }
        *to = '\0';
 
+       if (saw_tok && to == tobuf)
+               return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN);
+
        return to - tobuf;
 }
 
@@ -349,14 +361,36 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf,
        exit_cleanup(RERR_UNSUPPORTED);
 }
 
+static const char *getenv_nstr(int etype)
+{
+       const char *env_str = getenv(etype == ENV_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
+
+       /* When writing a batch file, we always negotiate an old-style choice. */
+       if (write_batch) 
+               env_str = etype == ENV_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4";
+
+       if (am_server && env_str) {
+               char *cp = strchr(env_str, '&');
+               if (cp)
+                       env_str = cp + 1;
+       }
+
+       return env_str;
+}
+
 /* If num2 < 0 then the caller is checking compress values, otherwise checksum values. */
 void validate_choice_vs_env(int num1, int num2)
 {
        struct name_num_obj *nno = num2 < 0 ? &valid_compressions : &valid_checksums;
-       const char *list_str = getenv(num2 < 0 ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
+       const char *list_str = getenv_nstr(num2 < 0 ? ENV_COMPRESS : ENV_CHECKSUM);
        char tmpbuf[MAX_NSTR_STRLEN];
 
-       if (!list_str || !*list_str)
+       if (!list_str)
+               return;
+
+       while (isSpace(list_str)) list_str++;
+
+       if (!*list_str)
                return;
 
        init_nno_saw(nno, 0);
@@ -422,17 +456,15 @@ int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len,
        return len;
 }
 
-static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *env_name)
+static void send_negotiate_str(int f_out, struct name_num_obj *nno, int etype)
 {
        char tmpbuf[MAX_NSTR_STRLEN];
-       const char *list_str = getenv(env_name);
+       const char *list_str = getenv_nstr(etype);
        int len;
 
        if (list_str && *list_str) {
                init_nno_saw(nno, 0);
                len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
-               if (!len)
-                       len = strlcpy(tmpbuf, "FAIL", MAX_NSTR_STRLEN);
                list_str = tmpbuf;
        } else
                list_str = NULL;
@@ -447,15 +479,10 @@ static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *
                        rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf);
        }
 
-       if (local_server) {
-               /* A local server doesn't bother to send/recv the strings, it just constructs
-                * and parses the same string on both sides. */
-               recv_negotiate_str(-1, nno, tmpbuf, len);
-       } else if (do_negotiated_strings) {
-               /* Each side sends their list of valid names to the other side and then both sides
-                * pick the first name in the client's list that is also in the server's list. */
+       /* Each side sends their list of valid names to the other side and then both sides
+        * pick the first name in the client's list that is also in the server's list. */
+       if (do_negotiated_strings)
                write_vstring(f_out, tmpbuf, len);
-       }
 }
 
 static void negotiate_the_strings(int f_in, int f_out)
@@ -463,10 +490,10 @@ static void negotiate_the_strings(int f_in, int f_out)
        /* We send all the negotiation strings before we start to read them to help avoid a slow startup. */
 
        if (!checksum_choice)
-               send_negotiate_str(f_out, &valid_checksums, "RSYNC_CHECKSUM_LIST");
+               send_negotiate_str(f_out, &valid_checksums, ENV_CHECKSUM);
 
        if (do_compression && !compress_choice)
-               send_negotiate_str(f_out, &valid_compressions, "RSYNC_COMPRESS_LIST");
+               send_negotiate_str(f_out, &valid_compressions, ENV_COMPRESS);
 
        if (valid_checksums.saw) {
                char tmpbuf[MAX_NSTR_STRLEN];
@@ -645,10 +672,8 @@ void setup_protocol(int f_out,int f_in)
                        if (local_server || strchr(client_info, 'I') != NULL)
                                compat_flags |= CF_INPLACE_PARTIAL_DIR;
                        if (local_server || strchr(client_info, 'v') != NULL) {
-                               if (!write_batch || protocol_version >= 30) {
-                                       do_negotiated_strings = 1;
-                                       compat_flags |= CF_VARINT_FLIST_FLAGS;
-                               }
+                               do_negotiated_strings = 1;
+                               compat_flags |= CF_VARINT_FLIST_FLAGS;
                        }
                        if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
                                if (!write_batch)
@@ -697,6 +722,9 @@ void setup_protocol(int f_out,int f_in)
 #endif
        }
 
+       if (read_batch)
+               do_negotiated_strings = 0;
+
        if (need_unsorted_flist && (!am_sender || inc_recurse))
                unsort_ndx = ++file_extra_cnt;
 
index f58cedfffa154c63923edacdb71394960ff94902..3708e1e1eb7ae310fbe9c5efbe784eed5afbf294 100644 (file)
@@ -1506,7 +1506,10 @@ your home directory (remove the '=' for that).
     transfer checksum separately from the pre-transfer checksum, and it ignores
     "auto" and all unknown checksum names.  If the remote rsync is not new
     enough to handle a checksum negotiation list, its list is assumed to
-    consist of a single "md5" or "md4" item based on the protocol version.
+    consist of a single "md5" or "md4" item based on the protocol version.  If
+    the environment variable contains a "`&`" character, the string is
+    separated into the client list & server list, either one of which can be
+    empty (giving that side the default list).
 
     The use of the `--checksum-choice` option overrides this environment list.
 
@@ -2295,11 +2298,14 @@ your home directory (remove the '=' for that).
 
     When both sides of the transfer are at least 3.2.0, rsync chooses the first
     algorithm in the client's list of choices that is also in the server's list
-    of choices.  Your default order can be customized by setting the environment
+    of choices.  The default order can be customized by setting the environment
     variable RSYNC_COMPRESS_LIST to a space-separated list of acceptable
     compression names.  If no common compress choice is found, the client exits
-    with an error.  If the remote rsync is too old to support checksum negotiation,
-    its list is assumed to be "zlib".
+    with an error.  If the remote rsync is too old to support checksum
+    negotiation, its list is assumed to be "zlib".  If the environment variable
+    contains a "`&`" character, the string is separated into the client list &
+    server list, either one of which can be empty (giving that side the default
+    list).
 
     There are some older rsync versions that were configured to reject a `-z`
     option and require the use of `-zz` because their compression library was
@@ -3104,6 +3110,11 @@ your home directory (remove the '=' for that).
     with `--read-batch`.  See the "BATCH MODE" section for details, and also
     the `--only-write-batch` option.
 
+    This option overrides the negotiated checksum & compress lists and always
+    negotiates a choice based on old-school md5/md4/zlib choices.  If you want
+    a more modern choice, use the `--checksum-choice` (`--cc`) and/or
+    `--compress-choice` (`--zc`) options.
+
 0.  `--only-write-batch=FILE`
 
     Works like `--write-batch`, except that no updates are made on the