1 This patch fixes various issues with the checksum code, such as:
3 - changing the xattr code's hashing to obey the transfer checksum choice
4 - size the objects to hold the active checksum size instead of the max
5 - add a negotiated hash method to the daemon auth code.
7 To use this patch, run these commands for a successful build:
9 patch -p1 <patches/fix-checksums.diff
10 ./configure (optional if already run)
13 based-on: 9cb7529ba60cd59519489ad0fc7fbb69ced6411f
14 diff --git a/authenticate.c b/authenticate.c
20 extern char *password_file;
21 +extern struct name_num_obj valid_auth_checksums;
23 /***************************************************************************
24 encode a buffer using base64 - simple and slow algorithm. null terminates
25 @@ -72,9 +73,9 @@ static void gen_challenge(const char *addr, char *challenge)
26 SIVAL(input, 20, tv.tv_usec);
27 SIVAL(input, 24, getpid());
30 + len = sum_init(valid_auth_checksums.negotiated_num, 0);
31 sum_update(input, sizeof input);
32 - len = sum_end(digest);
35 base64_encode(digest, len, challenge, 0);
37 @@ -86,10 +87,10 @@ static void generate_hash(const char *in, const char *challenge, char *out)
38 char buf[MAX_DIGEST_LEN];
42 + len = sum_init(valid_auth_checksums.negotiated_num, 0);
43 sum_update(in, strlen(in));
44 sum_update(challenge, strlen(challenge));
48 base64_encode(buf, len, out, 0);
50 @@ -238,6 +239,7 @@ char *auth_server(int f_in, int f_out, int module, const char *host,
51 if (!users || !*users)
54 + negotiate_daemon_auth(f_out);
55 gen_challenge(addr, challenge);
57 io_printf(f_out, "%s%s\n", leader, challenge);
58 @@ -368,6 +370,7 @@ void auth_client(int fd, const char *user, const char *challenge)
62 + negotiate_daemon_auth(-1);
63 generate_hash(pass, challenge, pass2);
64 io_printf(fd, "%s %s\n", user, pass2);
66 diff --git a/checksum.c b/checksum.c
69 @@ -59,8 +59,18 @@ struct name_num_obj valid_checksums = {
73 -int xfersum_type = 0; /* used for the file transfer checksums */
74 -int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
75 +struct name_num_obj valid_auth_checksums = {
76 + "daemon auth checksum", NULL, NULL, 0, 0, {
77 + { CSUM_MD5, "md5", NULL },
78 + { CSUM_MD4, "md4", NULL },
83 +int xfer_sum_type = 0; /* used for the file transfer checksums */
84 +int xfer_sum_len = 0;
85 +int file_sum_type = 0; /* used for the pre-transfer (--checksum) checksums */
86 +int file_sum_len = 0;
88 int parse_csum_name(const char *name, int len)
90 @@ -99,26 +109,28 @@ static const char *checksum_name(int num)
91 void parse_checksum_choice(int final_call)
93 if (valid_checksums.negotiated_name)
94 - xfersum_type = checksum_type = valid_checksums.negotiated_num;
95 + xfer_sum_type = file_sum_type = valid_checksums.negotiated_num;
97 char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
99 - xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
100 - checksum_type = parse_csum_name(cp+1, -1);
101 + xfer_sum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
102 + file_sum_type = parse_csum_name(cp+1, -1);
104 - xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1);
105 + xfer_sum_type = file_sum_type = parse_csum_name(checksum_choice, -1);
106 if (am_server && checksum_choice)
107 - validate_choice_vs_env(NSTR_CHECKSUM, xfersum_type, checksum_type);
108 + validate_choice_vs_env(NSTR_CHECKSUM, xfer_sum_type, file_sum_type);
110 + xfer_sum_len = csum_len_for_type(xfer_sum_type, 0);
111 + file_sum_len = csum_len_for_type(file_sum_type, 0);
113 - if (xfersum_type == CSUM_NONE)
114 + if (xfer_sum_type == CSUM_NONE)
117 /* Snag the checksum name for both write_batch's option output & the following debug output. */
118 if (valid_checksums.negotiated_name)
119 checksum_choice = valid_checksums.negotiated_name;
120 else if (checksum_choice == NULL)
121 - checksum_choice = checksum_name(xfersum_type);
122 + checksum_choice = checksum_name(xfer_sum_type);
124 if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
125 rprintf(FINFO, "%s%s checksum: %s\n",
126 @@ -204,7 +216,7 @@ uint32 get_checksum1(char *buf1, int32 len)
128 void get_checksum2(char *buf, int32 len, char *sum)
130 - switch (xfersum_type) {
131 + switch (xfer_sum_type) {
132 #ifdef SUPPORT_XXHASH
134 SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
135 @@ -288,7 +300,7 @@ void get_checksum2(char *buf, int32 len, char *sum)
136 * are multiples of 64. This is fixed by calling mdfour_update()
137 * even when there are no more bytes.
139 - if (len - i > 0 || xfersum_type > CSUM_MD4_BUSTED)
140 + if (len - i > 0 || xfer_sum_type > CSUM_MD4_BUSTED)
141 mdfour_update(&m, (uchar *)(buf1+i), len-i);
143 mdfour_result(&m, (uchar *)sum);
144 @@ -306,7 +318,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
148 - memset(sum, 0, MAX_DIGEST_LEN);
149 + memset(sum, 0, file_sum_len);
151 fd = do_open(fname, O_RDONLY, 0);
153 @@ -314,7 +326,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
155 buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);
157 - switch (checksum_type) {
158 + switch (file_sum_type) {
159 #ifdef SUPPORT_XXHASH
161 static XXH64_state_t* state = NULL;
162 @@ -421,7 +433,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
163 * are multiples of 64. This is fixed by calling mdfour_update()
164 * even when there are no more bytes. */
165 remainder = (int32)(len - i);
166 - if (remainder > 0 || checksum_type > CSUM_MD4_BUSTED)
167 + if (remainder > 0 || file_sum_type > CSUM_MD4_BUSTED)
168 mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
170 mdfour_result(&m, (uchar *)sum);
171 @@ -429,7 +441,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
174 rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n",
175 - checksum_name(checksum_type), checksum_type);
176 + checksum_name(file_sum_type), file_sum_type);
177 exit_cleanup(RERR_UNSUPPORTED);
180 @@ -452,14 +464,16 @@ static XXH64_state_t* xxh64_state;
181 static XXH3_state_t* xxh3_state;
183 static int cursum_type;
184 +static int cursum_len;
186 -void sum_init(int csum_type, int seed)
187 +int sum_init(int csum_type, int seed)
192 csum_type = parse_csum_name(NULL, 0);
193 cursum_type = csum_type;
194 + cursum_len = csum_len_for_type(cursum_type, 0);
197 #ifdef SUPPORT_XXHASH
198 @@ -505,6 +519,8 @@ void sum_init(int csum_type, int seed)
199 default: /* paranoia to prevent missing case values */
200 exit_cleanup(RERR_UNSUPPORTED);
207 @@ -573,11 +589,11 @@ void sum_update(const char *p, int32 len)
211 -/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is
212 - * MAX_DIGEST_LEN in size, so even if the csum-len is shorter than that (i.e.
213 - * CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write
214 - * into the "sum" buffer. */
215 -int sum_end(char *sum)
216 +/* The sum buffer only needs to be as long as the current checksum's digest
217 + * len, not MAX_DIGEST_LEN. Note that for CSUM_MD4_ARCHAIC that is the full
218 + * MD4_DIGEST_LEN even if the file-list code is going to ignore all but the
219 + * first 2 bytes of it. */
220 +void sum_end(char *sum)
222 switch (cursum_type) {
223 #ifdef SUPPORT_XXHASH
224 @@ -620,6 +636,4 @@ int sum_end(char *sum)
225 default: /* paranoia to prevent missing case values */
226 exit_cleanup(RERR_UNSUPPORTED);
229 - return csum_len_for_type(cursum_type, 0);
231 diff --git a/clientserver.c b/clientserver.c
234 @@ -67,6 +67,7 @@ extern uid_t our_uid;
235 extern gid_t our_gid;
238 +char *daemon_auth_choices;
241 int pid_file_fd = -1;
242 @@ -149,13 +150,9 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[],
243 static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client)
246 -#if SUBPROTOCOL_VERSION != 0
247 - int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
251 + int our_sub = get_subprotocol_version();
253 - io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub);
254 + output_daemon_greeting(f_out);
256 char *motd = lp_motd_file();
258 @@ -197,6 +194,14 @@ static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int
262 + daemon_auth_choices = strchr(buf + 9, ' ');
263 + if (daemon_auth_choices) {
265 + daemon_auth_choices = strdup(daemon_auth_choices + 1);
266 + if ((cp = strchr(daemon_auth_choices, '\n')) != NULL)
270 if (protocol_version > remote_protocol) {
271 protocol_version = remote_protocol;
273 diff --git a/compat.c b/compat.c
276 @@ -54,19 +54,21 @@ extern int do_compression;
277 extern int do_compression_level;
278 extern int saw_stderr_opt;
279 extern int msgs2stderr;
280 +extern int xfer_sum_type;
281 extern char *shell_cmd;
282 extern char *partial_dir;
283 extern char *files_from;
284 extern char *filesfrom_host;
285 extern const char *checksum_choice;
286 extern const char *compress_choice;
287 +extern char *daemon_auth_choices;
288 extern filter_rule_list filter_list;
289 extern int need_unsorted_flist;
291 extern iconv_t ic_send, ic_recv;
292 extern char *iconv_opt;
294 -extern struct name_num_obj valid_checksums;
295 +extern struct name_num_obj valid_checksums, valid_auth_checksums;
297 int remote_protocol = 0;
298 int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
299 @@ -78,6 +80,8 @@ int proper_seed_order = 0;
300 int inplace_partial = 0;
301 int do_negotiated_strings = 0;
302 int xmit_id0_names = 0;
303 +int xattr_sum_type = 0;
304 +int xattr_sum_len = 0;
306 /* These index values are for the file-list's extra-attribute array. */
307 int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
308 @@ -115,6 +119,7 @@ struct name_num_obj valid_compressions = {
309 #define CF_INPLACE_PARTIAL_DIR (1<<6)
310 #define CF_VARINT_FLIST_FLAGS (1<<7)
311 #define CF_ID0_NAMES (1<<8)
312 +#define CF_XATTR_SUM_CHOICE (1<<9)
314 static const char *client_info;
316 @@ -125,11 +130,7 @@ static void check_sub_protocol(void)
319 int their_protocol, their_sub;
320 -#if SUBPROTOCOL_VERSION != 0
321 - int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
325 + int our_sub = get_subprotocol_version();
327 /* client_info starts with VER.SUB string if client is a pre-release. */
328 if (!(their_protocol = atoi(client_info))
329 @@ -321,13 +322,45 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
333 +static int parse_negotiate_str(struct name_num_obj *nno, char *tmpbuf)
335 + struct name_num_item *nni, *ret = NULL;
336 + int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
337 + char *space, *tok = tmpbuf;
339 + while (*tok == ' ') tok++; /* Should be unneeded... */
342 + if ((space = strchr(tok, ' ')) != NULL)
344 + nni = get_nni_by_name(nno, tok, -1);
350 + if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
353 + best = nno->saw[nni->num];
354 + if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */
360 + nno->negotiated_name = ret->main_name ? ret->main_name : ret->name;
361 + nno->negotiated_num = ret->num;
367 /* This routine is always called with a tmpbuf of MAX_NSTR_STRLEN length, but the
368 * buffer may be pre-populated with a "len" length string to use OR a len of -1
369 * to tell us to read a string from the fd. */
370 static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len)
372 - struct name_num_item *ret = NULL;
375 len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
377 @@ -338,37 +371,8 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf,
378 rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf);
382 - struct name_num_item *nni;
383 - int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */
384 - char *space, *tok = tmpbuf;
386 - while (*tok == ' ') tok++; /* Should be unneeded... */
389 - if ((space = strchr(tok, ' ')) != NULL)
391 - nni = get_nni_by_name(nno, tok, -1);
397 - if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num])
400 - best = nno->saw[nni->num];
401 - if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */
407 - nno->negotiated_name = ret->main_name ? ret->main_name : ret->name;
408 - nno->negotiated_num = ret->num;
412 + if (len > 0 && parse_negotiate_str(nno, tmpbuf))
415 if (!am_server || !do_negotiated_strings) {
417 @@ -716,6 +720,8 @@ void setup_protocol(int f_out,int f_in)
418 do_negotiated_strings = 1;
419 compat_flags |= CF_VARINT_FLIST_FLAGS;
421 + if (strchr(client_info, 'X') != NULL)
422 + compat_flags |= CF_XATTR_SUM_CHOICE;
423 if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
425 compat_flags |= CF_VARINT_FLIST_FLAGS;
426 @@ -801,11 +807,66 @@ void setup_protocol(int f_out,int f_in)
427 checksum_seed = read_int(f_in);
430 - parse_checksum_choice(1); /* Sets checksum_type & xfersum_type */
431 + parse_checksum_choice(1); /* Sets file_sum_type & xfer_sum_type */
432 parse_compress_choice(1); /* Sets do_compression */
434 + if (compat_flags & CF_XATTR_SUM_CHOICE)
435 + xattr_sum_type = xfer_sum_type;
437 + xattr_sum_type = parse_csum_name(NULL, 0);
438 + xattr_sum_len = csum_len_for_type(xattr_sum_type, 0);
440 if (write_batch && !am_server)
441 write_batch_shell_file();
446 +void output_daemon_greeting(int f_out)
448 + char tmpbuf[MAX_NSTR_STRLEN];
449 + int our_sub = get_subprotocol_version();
451 + get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0');
453 + io_printf(f_out, "@RSYNCD: %d.%d %s\n", protocol_version, our_sub, tmpbuf);
456 +void negotiate_daemon_auth(int f_out)
458 + char tmpbuf[MAX_NSTR_STRLEN];
459 + int save_am_server = am_server;
460 + int md4_is_old = 0;
465 + if (daemon_auth_choices)
466 + strlcpy(tmpbuf, daemon_auth_choices, MAX_NSTR_STRLEN);
468 + strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN);
473 + if (!parse_negotiate_str(&valid_auth_checksums, tmpbuf)) {
474 + get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0');
475 + io_printf(f_out, "@ERROR: your client does not support one of our daemon-auth checksums: %s\n",
477 + exit_cleanup(RERR_UNSUPPORTED);
480 + recv_negotiate_str(-1, &valid_auth_checksums, tmpbuf, strlen(tmpbuf));
481 + am_server = save_am_server;
482 + if (md4_is_old && valid_auth_checksums.negotiated_num == CSUM_MD4)
483 + valid_auth_checksums.negotiated_num = CSUM_MD4_OLD;
486 +int get_subprotocol_version()
488 +#if SUBPROTOCOL_VERSION != 0
489 + return protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION;
494 diff --git a/flist.c b/flist.c
497 @@ -33,7 +33,7 @@ extern int am_sender;
498 extern int am_generator;
499 extern int inc_recurse;
500 extern int always_checksum;
501 -extern int checksum_type;
502 +extern int file_sum_type;
503 extern int module_id;
504 extern int ignore_errors;
505 extern int numeric_ids;
506 @@ -145,7 +145,8 @@ void init_flist(void)
507 rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
508 (int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
510 - flist_csum_len = csum_len_for_type(checksum_type, 1);
511 + /* Note that this isn't identical to file_sum_len in the case of CSUM_MD4_ARCHAIC: */
512 + flist_csum_len = csum_len_for_type(file_sum_type, 1);
514 show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
516 diff --git a/log.c b/log.c
519 @@ -36,8 +36,8 @@ extern int protocol_version;
520 extern int always_checksum;
521 extern int preserve_mtimes;
522 extern int msgs2stderr;
523 -extern int xfersum_type;
524 -extern int checksum_type;
525 +extern int xfer_sum_type;
526 +extern int file_sum_type;
527 extern int stdout_format_has_i;
528 extern int stdout_format_has_o_or_i;
529 extern int logfile_format_has_i;
530 @@ -680,12 +680,12 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
532 if (S_ISREG(file->mode)) {
534 - n = sum_as_hex(checksum_type, F_SUM(file), 1);
535 + n = sum_as_hex(file_sum_type, F_SUM(file), 1);
536 else if (iflags & ITEM_TRANSFER)
537 - n = sum_as_hex(xfersum_type, sender_file_sum, 0);
538 + n = sum_as_hex(xfer_sum_type, sender_file_sum, 0);
541 - int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type,
542 + int sum_len = csum_len_for_type(always_checksum ? file_sum_type : xfer_sum_type,
544 memset(buf2, ' ', sum_len*2);
545 buf2[sum_len*2] = '\0';
546 diff --git a/match.c b/match.c
551 extern int checksum_seed;
552 extern int append_mode;
553 -extern int xfersum_type;
554 +extern int xfer_sum_type;
555 +extern int xfer_sum_len;
557 int updating_basis_file;
558 char sender_file_sum[MAX_DIGEST_LEN];
559 @@ -356,15 +357,13 @@ static void hash_search(int f,struct sum_struct *s,
561 void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
571 - sum_init(xfersum_type, checksum_seed);
572 + sum_init(xfer_sum_type, checksum_seed);
574 if (append_mode > 0) {
575 if (append_mode == 2) {
576 @@ -405,22 +404,22 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
577 matched(f, s, buf, len, -1);
580 - sum_len = sum_end(sender_file_sum);
581 + sum_end(sender_file_sum);
583 /* If we had a read error, send a bad checksum. We use all bits
584 * off as long as the checksum doesn't happen to be that, in
585 * which case we turn the last 0 bit into a 1. */
586 if (buf && buf->status != 0) {
588 - for (i = 0; i < sum_len && sender_file_sum[i] == 0; i++) {}
589 - memset(sender_file_sum, 0, sum_len);
591 + for (i = 0; i < xfer_sum_len && sender_file_sum[i] == 0; i++) {}
592 + memset(sender_file_sum, 0, xfer_sum_len);
593 + if (i == xfer_sum_len)
594 sender_file_sum[i-1]++;
597 if (DEBUG_GTE(DELTASUM, 2))
598 rprintf(FINFO,"sending file_sum\n");
599 - write_buf(f, sender_file_sum, sum_len);
600 + write_buf(f, sender_file_sum, xfer_sum_len);
602 if (DEBUG_GTE(DELTASUM, 2)) {
603 rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
604 diff --git a/options.c b/options.c
607 @@ -3006,6 +3006,7 @@ int maybe_add_e_option(char *buf, int buf_len)
608 buf[x++] = 'I'; /* support inplace_partial behavior */
609 buf[x++] = 'v'; /* use varint for flist & compat flags; negotiate checksum */
610 buf[x++] = 'u'; /* include name of uid 0 & gid 0 in the id map */
611 + buf[x++] = 'X'; /* xattr checksums use negotiated checksum not protocol default */
613 /* NOTE: Avoid using 'V' -- it was represented with the high bit of a write_byte() that became a write_varint(). */
615 diff --git a/receiver.c b/receiver.c
618 @@ -56,7 +56,8 @@ extern int inplace;
619 extern int inplace_partial;
620 extern int allowed_lull;
621 extern int delay_updates;
622 -extern int xfersum_type;
623 +extern int xfer_sum_type;
624 +extern int xfer_sum_len;
625 extern BOOL want_progress_now;
626 extern mode_t orig_umask;
627 extern struct stats stats;
628 @@ -240,7 +241,6 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
629 static char file_sum1[MAX_DIGEST_LEN];
630 struct map_struct *mapbuf;
631 struct sum_struct sum;
634 OFF_T total_size = F_LENGTH(file);
636 @@ -280,7 +280,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
640 - sum_init(xfersum_type, checksum_seed);
641 + sum_init(xfer_sum_type, checksum_seed);
643 if (append_mode > 0) {
645 @@ -393,7 +393,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
646 if (INFO_GTE(PROGRESS, 1))
647 end_progress(total_size);
649 - sum_len = sum_end(file_sum1);
650 + sum_end(file_sum1);
652 if (do_fsync && fd != -1 && fsync(fd) != 0) {
653 rsyserr(FERROR, errno, "fsync failed on %s", full_fname(fname));
654 @@ -403,10 +403,10 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
658 - read_buf(f_in, sender_file_sum, sum_len);
659 + read_buf(f_in, sender_file_sum, xfer_sum_len);
660 if (DEBUG_GTE(DELTASUM, 2))
661 rprintf(FINFO,"got file_sum\n");
662 - if (fd != -1 && memcmp(file_sum1, sender_file_sum, sum_len) != 0)
663 + if (fd != -1 && memcmp(file_sum1, sender_file_sum, xfer_sum_len) != 0)
667 diff --git a/rsync.h b/rsync.h
670 @@ -826,6 +826,7 @@ extern int uid_ndx;
673 extern int xattrs_ndx;
674 +extern int file_sum_len;
676 #ifdef USE_FLEXIBLE_ARRAY
677 #define FILE_STRUCT_LEN (sizeof (struct file_struct))
678 @@ -836,7 +837,7 @@ extern int xattrs_ndx;
679 #define DEV_EXTRA_CNT 2
680 #define DIRNODE_EXTRA_CNT 3
681 #define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN)
682 -#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
683 +#define SUM_EXTRA_CNT ((file_sum_len + EXTRA_LEN - 1) / EXTRA_LEN)
685 #define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx))
686 #define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
687 diff --git a/xattrs.c b/xattrs.c
690 @@ -38,6 +38,8 @@ extern int preserve_devices;
691 extern int preserve_specials;
692 extern int checksum_seed;
693 extern int saw_xattr_filter;
694 +extern int xattr_sum_type;
695 +extern int xattr_sum_len;
697 #define RSYNC_XAL_INITIAL 5
698 #define RSYNC_XAL_LIST_INITIAL 100
699 @@ -270,7 +272,7 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
700 if (datum_len > MAX_FULL_DATUM) {
701 /* For large datums, we store a flag and a checksum. */
702 name_offset = 1 + MAX_DIGEST_LEN;
703 - sum_init(-1, checksum_seed);
704 + sum_init(xattr_sum_type, checksum_seed);
705 sum_update(ptr, datum_len);
708 @@ -382,7 +384,7 @@ static int64 xattr_lookup_hash(const item_list *xalp)
709 for (i = 0; i < xalp->count; i++) {
710 key += hashlittle(rxas[i].name, rxas[i].name_len);
711 if (rxas[i].datum_len > MAX_FULL_DATUM)
712 - key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN);
713 + key += hashlittle(rxas[i].datum, xattr_sum_len);
715 key += hashlittle(rxas[i].datum, rxas[i].datum_len);
717 @@ -435,7 +437,7 @@ static int find_matching_xattr(const item_list *xalp)
718 if (rxas1[j].datum_len > MAX_FULL_DATUM) {
719 if (memcmp(rxas1[j].datum + 1,
721 - MAX_DIGEST_LEN) != 0)
722 + xattr_sum_len) != 0)
725 if (memcmp(rxas1[j].datum, rxas2[j].datum,
726 @@ -535,7 +537,7 @@ int send_xattr(int f, stat_x *sxp)
728 write_buf(f, name, name_len);
729 if (rxa->datum_len > MAX_FULL_DATUM)
730 - write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
731 + write_buf(f, rxa->datum + 1, xattr_sum_len);
733 write_bigbuf(f, rxa->datum, rxa->datum_len);
735 @@ -588,7 +590,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
736 else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
737 same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
738 && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
739 - MAX_DIGEST_LEN) == 0;
740 + xattr_sum_len) == 0;
741 /* Flag unrequested items that we need. */
742 if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
743 snd_rxa->datum[0] = XSTATE_TODO;
744 @@ -797,7 +799,7 @@ void receive_xattr(int f, struct file_struct *file)
746 size_t name_len = read_varint(f);
747 size_t datum_len = read_varint(f);
748 - size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
749 + size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + (size_t)xattr_sum_len : datum_len;
750 size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
751 if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len)
752 overflow_exit("receive_xattr");
753 @@ -812,7 +814,7 @@ void receive_xattr(int f, struct file_struct *file)
754 read_buf(f, ptr, dget_len);
756 *ptr = XSTATE_ABBREV;
757 - read_buf(f, ptr + 1, MAX_DIGEST_LEN);
758 + read_buf(f, ptr + 1, xattr_sum_len);
761 if (saw_xattr_filter) {
762 @@ -958,7 +960,6 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
765 if (XATTR_ABBREV(rxas[i])) {
767 /* See if the fnamecmp version is identical. */
768 len = name_len = rxas[i].name_len;
769 if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) {
770 @@ -975,10 +976,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
774 - sum_init(-1, checksum_seed);
775 + sum_init(xattr_sum_type, checksum_seed);
776 sum_update(ptr, len);
777 - sum_len = sum_end(sum);
778 - if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) {
780 + if (memcmp(sum, rxas[i].datum + 1, xattr_sum_len) != 0) {