[SCM] The rsync repository. - branch master updated

Rsync CVS commit messages rsync-cvs at lists.samba.org
Sun May 24 20:25:22 UTC 2020


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 <wayne at 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.



More information about the rsync-cvs mailing list