*/
#include "rsync.h"
+#ifdef SUPPORT_XXHASH
+#include "xxhash.h"
+#endif
extern int am_server;
extern int local_server;
#define CSUM_MD4_OLD 3
#define CSUM_MD4 4
#define CSUM_MD5 5
+#define CSUM_XXHASH 6
#define CSUM_SAW_BUFLEN 10
int num;
const char *name;
} valid_checksums[] = {
+#ifdef SUPPORT_XXHASH
+ { CSUM_XXHASH, "xxhash" },
+#endif
{ CSUM_MD5, "md5" },
{ CSUM_MD4, "md4" },
{ CSUM_NONE, "none" },
return MD4_DIGEST_LEN;
case CSUM_MD5:
return MD5_DIGEST_LEN;
+#ifdef SUPPORT_XXHASH
+ case CSUM_XXHASH:
+ return sizeof (XXH64_hash_t);
+#endif
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
mdfour_result(&m, (uchar *)sum);
break;
}
+#ifdef SUPPORT_XXHASH
+ case CSUM_XXHASH:
+ SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
+ break;
+#endif
default: /* paranoia to prevent missing case values */
exit_cleanup(RERR_UNSUPPORTED);
}
mdfour_result(&m, (uchar *)sum);
break;
+#ifdef SUPPORT_XXHASH
+ case CSUM_XXHASH: {
+ XXH64_state_t* state = XXH64_createState();
+ if (state == NULL)
+ out_of_memory("file_checksum xx64");
+
+ if (XXH64_reset(state, 0) == XXH_ERROR) {
+ rprintf(FERROR, "error resetting XXH64 seed");
+ exit_cleanup(RERR_STREAMIO);
+ }
+
+ for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
+ XXH_errorcode const updateResult =
+ XXH64_update(state, (uchar *)map_ptr(buf, i, CSUM_CHUNK), CSUM_CHUNK);
+ if (updateResult == XXH_ERROR) {
+ rprintf(FERROR, "error computing XX64 hash");
+ exit_cleanup(RERR_STREAMIO);
+ }
+ }
+ remainder = (int32)(len - i);
+ if (remainder > 0)
+ XXH64_update(state, (uchar *)map_ptr(buf, i, CSUM_CHUNK), remainder);
+ SIVAL64(sum, 0, XXH64_digest(state));
+
+ XXH64_freeState(state);
+ break;
+ }
+#endif
default:
rprintf(FERROR, "invalid checksum-choice for the --checksum option (%d)\n", checksum_type);
exit_cleanup(RERR_UNSUPPORTED);
static int32 sumresidue;
static md_context md;
static int cursum_type;
+#ifdef SUPPORT_XXHASH
+XXH64_state_t* xxh64_state = NULL;
+#endif
void sum_init(int csum_type, int seed)
{
SIVAL(s, 0, seed);
sum_update(s, 4);
break;
+#ifdef SUPPORT_XXHASH
+ case CSUM_XXHASH:
+ if (xxh64_state == NULL) {
+ xxh64_state = XXH64_createState();
+ if (xxh64_state == NULL)
+ out_of_memory("sum_init xxh64");
+ }
+ if (XXH64_reset(xxh64_state, 0) == XXH_ERROR) {
+ rprintf(FERROR, "error resetting XXH64 state");
+ exit_cleanup(RERR_STREAMIO);
+ }
+ break;
+#endif
case CSUM_NONE:
break;
default: /* paranoia to prevent missing case values */
if (sumresidue)
memcpy(md.buffer, p, sumresidue);
break;
+#ifdef SUPPORT_XXHASH
+ case CSUM_XXHASH:
+ if (XXH64_update(xxh64_state, p, len) == XXH_ERROR) {
+ rprintf(FERROR, "error computing XX64 hash");
+ exit_cleanup(RERR_STREAMIO);
+ }
+ break;
+#endif
case CSUM_NONE:
break;
default: /* paranoia to prevent missing case values */
mdfour_update(&md, (uchar *)md.buffer, sumresidue);
mdfour_result(&md, (uchar *)sum);
break;
+#ifdef SUPPORT_XXHASH
+ case CSUM_XXHASH:
+ SIVAL64(sum, 0, XXH64_digest(xxh64_state));
+ break;
+#endif
case CSUM_NONE:
*sum = '\0';
break;
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netinet/ip.h \
- zlib.h)
+ zlib.h xxhash.h)
AC_HEADER_MAJOR_FIXED
+dnl Do you want to disable use of xxhash checksums
+AC_ARG_ENABLE([xxhash],
+ AS_HELP_STRING([--disable-xxhash],[disable xxhash checksums]))
+AH_TEMPLATE([SUPPORT_XXHASH],
+[Undefine if you do not want xxhash checksums. By default this is defined.])
+if test x"$enable_xxhash" != x"no"; then
+ if test x"$ac_cv_header_xxhash_h" = x"yes"; then
+ AC_SEARCH_LIBS(XXH64_createState, xxhash)
+ AC_DEFINE(SUPPORT_XXHASH)
+ fi
+fi
+
AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <sys/types.h>
char const *iconv = "no ";
char const *ipv6 = "no ";
char const *simd = "no ";
+ char const *xxhash = "no ";
STRUCT_STAT *dumstat;
#if SUBPROTOCOL_VERSION != 0
#ifdef HAVE_SIMD
simd = "";
#endif
+#ifdef SUPPORT_XXHASH
+ xxhash = "";
+#endif
rprintf(f, "%s version %s protocol version %d%s\n",
RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
(int)(sizeof (int64) * 8));
rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n",
got_socketpair, hardlinks, links, ipv6, have_inplace);
- rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc, %sSIMD\n",
- have_inplace, acls, xattrs, iconv, symtimes, prealloc, simd);
+ rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc, %sSIMD, %sxxhash\n",
+ have_inplace, acls, xattrs, iconv, symtimes, prealloc, simd, xxhash);
#ifdef MAINTAINER_MODE
rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
comma-separated names are supplied, the first name affects the transfer
checksums, and the second name affects the pre-transfer checksums (bf(-c)).
-The algorithm choices are "auto", "MD5", "MD4", and "none".
+The algorithm choices are "auto", "xxhash", "MD5", "MD4", and "none".
If "none" is specified for the first (or only) name, the bf(--whole-file) option
is forced on and no checksum verification is performed on the transferred data.
If both the client and the server are at least version 3.2.0, they will
exchange a list of checksum names and choose the first one in the list that
they have in common.
-This typically means that they will choose MD5.
+This typically means that they will choose xxhash if they both support it
+and fall back to MD5.
If one side of the transfer is not new enough to support this checksum
negotation, then a value is chosen based on the protocol version (which
chooses between MD5 and various flavors of MD4 based on protocol age).