The branch, master has been updated
       via  2f84a6bd Add support for negotiated checksum names.
      from  eda15d52 Make xxh64 the "main_name" for the current xxhash.

https://git.samba.org/?p=rsync.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 2f84a6bd73e1a6e2081b1bcb965049ef83b2ce45
Author: Wayne Davison <wa...@opencoder.net>
Date:   Sun May 24 12:56:00 2020 -0700

    Add support for negotiated checksum names.

-----------------------------------------------------------------------

Summary of changes:
 checksum.c | 209 +++++++--------------------------------------
 compat.c   | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 io.c       |   2 +-
 options.c  |   5 +-
 rsync.h    |  21 ++++-
 5 files changed, 310 insertions(+), 211 deletions(-)


Changeset truncated at 500 lines:

diff --git a/checksum.c b/checksum.c
index 1be17522..60e0b55f 100644
--- a/checksum.c
+++ b/checksum.c
@@ -52,26 +52,19 @@ extern char *checksum_choice;
 #define CSUM_MD5 5
 #define CSUM_XXH64 6
 
-#define CSUM_COUNT 7
-
-struct csum_struct {
-       int num;
-       const char *name, *main_name;
-} valid_checksums[] = {
+struct name_num_obj valid_checksums = {
+       "checksum", NULL, NULL, 0, 0, {
 #ifdef SUPPORT_XXHASH
-       { CSUM_XXH64, "xxh64", NULL },
-       { CSUM_XXH64, "xxhash", NULL },
+               { CSUM_XXH64, "xxh64", NULL },
+               { CSUM_XXH64, "xxhash", NULL },
 #endif
-       { CSUM_MD5, "md5", NULL },
-       { CSUM_MD4, "md4", NULL },
-       { CSUM_NONE, "none", NULL },
-       { 0, NULL, NULL }
+               { CSUM_MD5, "md5", NULL },
+               { CSUM_MD4, "md4", NULL },
+               { CSUM_NONE, "none", "" }, /* The "" prevents us from listing 
this name by default */
+               { 0, NULL, NULL }
+       }
 };
 
-struct csum_struct auto_cs = { 0, "auto", NULL };
-
-#define MAX_CHECKSUM_LIST 1024
-
 #ifndef USE_OPENSSL
 #define MD5_CTX md_context
 #define MD5_Init md5_begin
@@ -81,74 +74,59 @@ struct csum_struct auto_cs = { 0, "auto", NULL };
 
 int xfersum_type = 0; /* used for the file transfer checksums */
 int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
-const char *negotiated_csum_name = NULL;
 
-static struct csum_struct *parse_csum_name(const char *name, int len, int 
allow_auto)
+static int parse_csum_name(const char *name, int len)
 {
-       struct csum_struct *cs;
+       struct name_num_item *nni;
 
        if (len < 0 && name)
                len = strlen(name);
 
-       if (!name || (allow_auto && len == 4 && strncasecmp(name, "auto", 4) == 
0)) {
-               cs = &auto_cs;
+       if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
                if (protocol_version >= 30)
-                       cs->num = CSUM_MD5;
-               else if (protocol_version >= 27)
-                       cs->num = CSUM_MD4_OLD;
-               else if (protocol_version >= 21)
-                       cs->num = CSUM_MD4_BUSTED;
-               else
-                       cs->num = CSUM_MD4_ARCHAIC;
-               return cs;
+                       return CSUM_MD5;
+               if (protocol_version >= 27)
+                       return CSUM_MD4_OLD;
+               if (protocol_version >= 21)
+                       return CSUM_MD4_BUSTED;
+               return CSUM_MD4_ARCHAIC;
        }
 
-       for (cs = valid_checksums; cs->name; cs++) {
-               if (strncasecmp(name, cs->name, len) == 0 && cs->name[len] == 
'\0')
-                       return cs;
-       }
+       nni = get_nni_by_name(&valid_checksums, name, len);
 
-       if (allow_auto) {
+       if (!nni) {
                rprintf(FERROR, "unknown checksum name: %s\n", name);
                exit_cleanup(RERR_UNSUPPORTED);
        }
 
-       return NULL;
+       return nni->num;
 }
 
 static const char *checksum_name(int num)
 {
-       struct csum_struct *cs;
-
-       for (cs = valid_checksums; cs->name; cs++) {
-               if (num == cs->num)
-                       return cs->name;
-       }
+       struct name_num_item *nni = get_nni_by_num(&valid_checksums, num);
 
-       if (num < CSUM_MD4)
-               return "MD4";
-
-       return "UNKNOWN"; /* IMPOSSIBLE */
+       return nni ? nni->name : num < CSUM_MD4 ? "MD4" : "UNKNOWN";
 }
 
 void parse_checksum_choice(int final_call)
 {
-       if (!negotiated_csum_name) {
+       if (!valid_checksums.negotiated_name) {
                char *cp = checksum_choice ? strchr(checksum_choice, ',') : 
NULL;
                if (cp) {
-                       xfersum_type = parse_csum_name(checksum_choice, cp - 
checksum_choice, 1)->num;
-                       checksum_type = parse_csum_name(cp+1, -1, 1)->num;
+                       xfersum_type = parse_csum_name(checksum_choice, cp - 
checksum_choice);
+                       checksum_type = parse_csum_name(cp+1, -1);
                } else
-                       xfersum_type = checksum_type = 
parse_csum_name(checksum_choice, -1, 1)->num;
+                       xfersum_type = checksum_type = 
parse_csum_name(checksum_choice, -1);
        }
 
        if (xfersum_type == CSUM_NONE)
                whole_file = 1;
 
-       if (final_call && DEBUG_GTE(CSUM, am_server ? 2 : 1)) {
+       if (final_call && DEBUG_GTE(NSTR, am_server ? 2 : 1)) {
                const char *c_s = am_server ? "Server" : "Client";
-               if (negotiated_csum_name)
-                       rprintf(FINFO, "%s negotiated checksum: %s\n", c_s, 
negotiated_csum_name);
+               if (valid_checksums.negotiated_name)
+                       rprintf(FINFO, "%s negotiated checksum: %s\n", c_s, 
valid_checksums.negotiated_name);
                else if (xfersum_type == checksum_type) {
                        rprintf(FINFO, "%s %s checksum: %s\n", c_s,
                                checksum_choice ? "chosen" : "protocol-based",
@@ -162,128 +140,6 @@ void parse_checksum_choice(int final_call)
        }
 }
 
-static int parse_checksum_list(const char *from, char *sumbuf, int sumbuf_len, 
uchar *saw)
-{
-       char *to = sumbuf, *tok = NULL;
-       int cnt = 0;
-
-       while (1) {
-               if (*from == ' ' || !*from) {
-                       if (tok) {
-                               struct csum_struct *cs = parse_csum_name(tok, 
to - tok, 0);
-                               if (cs && !saw[cs->num]) {
-                                       saw[cs->num] = ++cnt;
-                                       if (cs->main_name) {
-                                               to = tok + strlcpy(tok, 
cs->main_name, sumbuf_len - (tok - sumbuf));
-                                               if (to - sumbuf >= sumbuf_len) {
-                                                       to = tok - 1;
-                                                       break;
-                                               }
-                                       }
-                               } else
-                                       to = tok - (tok != sumbuf);
-                               tok = NULL;
-                       }
-                       if (!*from++)
-                               break;
-                       continue;
-               }
-               if (!tok) {
-                       if (to != sumbuf)
-                               *to++ = ' ';
-                       tok = to;
-               }
-               if (to - sumbuf >= sumbuf_len - 1) {
-                       to = tok - (tok != sumbuf);
-                       break;
-               }
-               *to++ = *from++;
-       }
-       *to = '\0';
-
-       return to - sumbuf;
-}
-
-void negotiate_checksum(int f_in, int f_out, const char *csum_list, int 
fail_if_empty)
-{
-       char *tok, sumbuf[MAX_CHECKSUM_LIST];
-       uchar saw[CSUM_COUNT];
-       struct csum_struct *cs;
-       int len;
-
-       memset(saw, 0, sizeof saw);
-       for (len = 1, cs = valid_checksums; cs->name; len++, cs++) {
-               assert(len <= CSUM_COUNT);
-               if (saw[cs->num])
-                       cs->main_name = valid_checksums[saw[cs->num]-1].name;
-               else
-                       saw[cs->num] = len;
-       }
-       memset(saw, 0, sizeof saw);
-
-       /* Simplify the user-provided string so that it contains valid
-        * checksum names without any duplicates. The client side also
-        * makes use of the saw values when scanning the server's list. */
-       if (csum_list && *csum_list && (!am_server || local_server)) {
-               len = parse_checksum_list(csum_list, sumbuf, sizeof sumbuf, 
saw);
-               if (fail_if_empty && !len)
-                       len = strlcpy(sumbuf, "FAIL", sizeof sumbuf);
-               csum_list = sumbuf;
-       } else
-               csum_list = NULL;
-
-       if (!csum_list || !*csum_list) {
-               int cnt = 0;
-               for (cs = valid_checksums, len = 0; cs->name; cs++) {
-                       if (cs->num == CSUM_NONE || cs->main_name)
-                               continue;
-                       if (len)
-                               sumbuf[len++]= ' ';
-                       len += strlcpy(sumbuf+len, cs->name, sizeof sumbuf - 
len);
-                       if (len >= (int)sizeof sumbuf - 1)
-                               exit_cleanup(RERR_UNSUPPORTED); /* 
IMPOSSIBLE... */
-                       saw[cs->num] = ++cnt;
-               }
-       }
-
-       if (!am_server && DEBUG_GTE(CSUM, 2))
-               rprintf(FINFO, "Client checksum list: %s\n", sumbuf);
-
-       /* Each side sends their list of valid checksum 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 (!local_server)
-               write_vstring(f_out, sumbuf, len);
-
-       if (!local_server || read_batch)
-               len = read_vstring(f_in, sumbuf, sizeof sumbuf);
-
-       if (!am_server && DEBUG_GTE(CSUM, 2))
-               rprintf(FINFO, "Server checksum list: %s\n", sumbuf);
-
-       if (len > 0) {
-               int best = CSUM_COUNT+1; /* We want best == 1 from the client 
list, so start with a big number. */
-               if (am_server)
-                       memset(saw, 1, sizeof saw); /* Since we're parsing 
client names, anything we parse first is #1. */
-               for (tok = strtok(sumbuf, " \t"); tok; tok = strtok(NULL, " 
\t")) {
-                       cs = parse_csum_name(tok, -1, 0);
-                       if (!cs || !saw[cs->num] || best <= saw[cs->num])
-                               continue;
-                       xfersum_type = checksum_type = cs->num;
-                       negotiated_csum_name = cs->main_name ? cs->main_name : 
cs->name;
-                       best = saw[cs->num];
-                       if (best == 1)
-                               break;
-               }
-               if (negotiated_csum_name)
-                       return;
-       }
-
-       if (!am_server)
-               rprintf(FERROR, "Failed to negotiate a common checksum\n");
-       exit_cleanup(RERR_UNSUPPORTED);
-}
-
 int csum_len_for_type(int cst, BOOL flist_csum)
 {
        switch (cst) {
@@ -525,7 +381,8 @@ void file_checksum(const char *fname, const STRUCT_STAT 
*st_p, char *sum)
          }
 #endif
          default:
-               rprintf(FERROR, "invalid checksum-choice for the --checksum 
option (%d)\n", checksum_type);
+               rprintf(FERROR, "Invalid checksum-choice for --checksum: %s 
(%d)\n",
+                       checksum_name(checksum_type), checksum_type);
                exit_cleanup(RERR_UNSUPPORTED);
        }
 
@@ -551,7 +408,7 @@ void sum_init(int csum_type, int seed)
        char s[4];
 
        if (csum_type < 0)
-               csum_type = parse_csum_name(NULL, 0, 1)->num;
+               csum_type = parse_csum_name(NULL, 0);
        cursum_type = csum_type;
 
        switch (csum_type) {
diff --git a/compat.c b/compat.c
index 8c77ea69..04d8b8ef 100644
--- a/compat.c
+++ b/compat.c
@@ -21,15 +21,6 @@
 
 #include "rsync.h"
 
-int remote_protocol = 0;
-int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
-int inc_recurse = 0;
-int compat_flags = 0;
-int use_safe_inc_flist = 0;
-int want_xattr_optim = 0;
-int proper_seed_order = 0;
-int inplace_partial = 0;
-
 extern int am_server;
 extern int am_sender;
 extern int local_server;
@@ -56,19 +47,33 @@ extern int preserve_xattrs;
 extern int xfer_flags_as_varint;
 extern int need_messages_from_generator;
 extern int delete_mode, delete_before, delete_during, delete_after;
+extern int xfersum_type;
+extern int checksum_type;
+extern int do_compression;
 extern char *shell_cmd;
 extern char *partial_dir;
 extern char *dest_option;
 extern char *files_from;
 extern char *filesfrom_host;
 extern char *checksum_choice;
+extern char *compress_choice;
 extern filter_rule_list filter_list;
 extern int need_unsorted_flist;
 #ifdef ICONV_OPTION
 extern iconv_t ic_send, ic_recv;
 extern char *iconv_opt;
 #endif
-extern const char *negotiated_csum_name;
+extern struct name_num_obj valid_checksums;
+
+int remote_protocol = 0;
+int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
+int inc_recurse = 0;
+int compat_flags = 0;
+int use_safe_inc_flist = 0;
+int want_xattr_optim = 0;
+int proper_seed_order = 0;
+int inplace_partial = 0;
+int do_negotiated_strings = 0;
 
 /* These index values are for the file-list's extra-attribute array. */
 int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, 
xattrs_ndx, unsort_ndx;
@@ -80,6 +85,19 @@ int sender_symlink_iconv = 0;        /* sender should 
convert symlink content */
 int filesfrom_convert = 0;
 #endif
 
+#define MAX_NSTR_STRLEN 256
+
+#define CPRES_NONE 0
+#define CPRES_ZLIB 1
+
+struct name_num_obj valid_compressions = {
+       "compress", NULL, NULL, 0, 0, {
+               { CPRES_ZLIB, "zlib", NULL },
+               { CPRES_NONE, "none", "" }, /* The "" prevents us from listing 
this name by default */
+               { 0, NULL, NULL }
+       }
+};
+
 #define CF_INC_RECURSE  (1<<0)
 #define CF_SYMLINK_TIMES (1<<1)
 #define CF_SYMLINK_ICONV (1<<2)
@@ -142,10 +160,227 @@ void set_allow_inc_recurse(void)
                allow_inc_recurse = 0;
 }
 
-void setup_protocol(int f_out,int f_in)
+struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char 
*name, int len)
+{
+       struct name_num_item *nni;
+
+       if (len < 0)
+               len = strlen(name);
+
+       for (nni = nno->list; nni->name; nni++) {
+               if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == 
'\0')
+                       return nni;
+       }
+
+       return NULL;
+}
+
+struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num)
+{
+       struct name_num_item *nni;
+
+       for (nni = nno->list; nni->name; nni++) {
+               if (num == nni->num)
+                       return nni;
+       }
+
+       return NULL;
+}
+
+static void init_nno_saw(struct name_num_obj *nno, int val)
+{
+       struct name_num_item *nni;
+       int cnt;
+
+       if (!nno->saw_len) {
+               for (nni = nno->list; nni->name; nni++) {
+                       if (nni->num >= nno->saw_len)
+                               nno->saw_len = nni->num + 1;
+               }
+       }
+
+       if (!nno->saw) {
+               if (!(nno->saw = new_array0(uchar, nno->saw_len)))
+                       out_of_memory("init_nno_saw");
+
+               /* We'll take this opportunity to make sure that the main_name 
values are set right. */
+               for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) {
+                       if (nno->saw[nni->num])
+                               nni->main_name = 
nno->list[nno->saw[nni->num]-1].name;
+                       else
+                               nno->saw[nni->num] = cnt;
+               }
+       }
+
+       memset(nno->saw, val, nno->saw_len);
+}
+
+/* Simplify the user-provided string so that it contains valid names without 
any duplicates.
+ * It also sets the "saw" flags to a 1-relative count of which name was seen 
first. */
+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;
+
+       while (1) {
+               if (*from == ' ' || !*from) {
+                       if (tok) {
+                               struct name_num_item *nni = 
get_nni_by_name(nno, tok, to - tok);
+                               if (nni && !nno->saw[nni->num]) {
+                                       nno->saw[nni->num] = ++cnt;
+                                       if (nni->main_name && *nni->main_name) {
+                                               to = tok + strlcpy(tok, 
nni->main_name, tobuf_len - (tok - tobuf));
+                                               if (to - tobuf >= tobuf_len) {
+                                                       to = tok - 1;
+                                                       break;
+                                               }
+                                       } else
+                                               nni->main_name = NULL; /* 
Override a "" entry */
+                               } else
+                                       to = tok - (tok != tobuf);
+                               tok = NULL;
+                       }
+                       if (!*from++)
+                               break;
+                       continue;
+               }
+               if (!tok) {
+                       if (to != tobuf)
+                               *to++ = ' ';
+                       tok = to;
+               }
+               if (to - tobuf >= tobuf_len - 1) {
+                       to = tok - (tok != tobuf);
+                       break;
+               }
+               *to++ = *from++;
+       }
+       *to = '\0';
+
+       return to - tobuf;
+}
+
+static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char 
*tmpbuf, int len)
+{
+       struct name_num_item *ret = NULL;
+
+       if (len < 0)
+               len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
+
+       if (DEBUG_GTE(NSTR, am_server ? 4 : 2))
+               rprintf(FINFO, "Server %s list: %s%s\n", nno->type, tmpbuf, 
am_server ? " (on server)" : "");
+
+       if (len > 0) {
+               int best = nno->saw_len; /* We want best == 1 from the client 
list, so start with a big number. */
+               char *tok;
+               if (am_server)
+                       init_nno_saw(nno, 1); /* Since we're parsing client 
names, anything we parse first is #1. */
+               for (tok = strtok(tmpbuf, " \t"); tok; tok = strtok(NULL, " 
\t")) {
+                       struct name_num_item *nni = get_nni_by_name(nno, tok, 
-1);
+                       if (!nni || !nno->saw[nni->num] || best <= 
nno->saw[nni->num])
+                               continue;
+                       ret = nni;
+                       best = nno->saw[nni->num];
+                       if (best == 1)
+                               break;
+               }
+               if (ret) {
+                       free(nno->saw);
+                       nno->saw = NULL;
+                       nno->negotiated_name = ret->main_name ? ret->main_name 
: ret->name;
+                       nno->negotiated_num = ret->num;
+                       return;
+               }
+       }
+
+       if (!am_server)
+               rprintf(FERROR, "Failed to negotiate a common %s\n", nno->type);
+       exit_cleanup(RERR_UNSUPPORTED);


-- 
The rsync repository.

_______________________________________________
rsync-cvs mailing list
rsync-cvs@lists.samba.org
https://lists.samba.org/mailman/listinfo/rsync-cvs

Reply via email to