./configure (optional if already run)
make
+based-on: 7c8f180900432e646c0a4bd02e2c4033068dbb7c
diff --git a/checksum.c b/checksum.c
-index 811b5b6..f418dc2 100644
--- a/checksum.c
+++ b/checksum.c
@@ -98,7 +98,7 @@ void get_checksum2(char *buf, int32 len, char *sum)
struct map_struct *buf;
OFF_T i, len = size;
diff --git a/clientserver.c b/clientserver.c
-index b6afe00..2681f33 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -42,6 +42,8 @@ extern int numeric_ids;
extern int io_timeout;
extern int no_detach;
extern int write_batch;
-@@ -868,6 +870,9 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
+@@ -911,6 +913,9 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
} else if (am_root < 0) /* Treat --fake-super from client as --super. */
am_root = 2;
filesfrom_fd = f_in;
diff --git a/flist.c b/flist.c
-index 09b4fc5..8a42d80 100644
--- a/flist.c
+++ b/flist.c
@@ -22,6 +22,7 @@
extern int module_id;
extern int ignore_errors;
extern int numeric_ids;
-@@ -61,6 +63,7 @@ extern int file_extra_cnt;
+@@ -58,6 +60,7 @@ extern int implied_dirs;
extern int ignore_perishable;
extern int non_perishable_cnt;
extern int prune_empty_dirs;
extern int copy_links;
extern int copy_unsafe_links;
extern int protocol_version;
-@@ -71,6 +74,7 @@ extern int sender_symlink_iconv;
+@@ -69,6 +72,7 @@ extern int sender_symlink_iconv;
extern int output_needs_newline;
extern int sender_keeps_checksum;
extern int unsort_ndx;
+extern char *basis_dir[];
+ extern uid_t our_uid;
extern struct stats stats;
extern char *filesfrom_host;
- extern char *usermap, *groupmap;
-@@ -87,6 +91,12 @@ extern int filesfrom_convert;
+@@ -86,6 +90,20 @@ extern int filesfrom_convert;
extern iconv_t ic_send, ic_recv;
#endif
++#ifdef HAVE_UTIMENSAT
++#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
++#define ST_MTIME_NSEC st_mtim.tv_nsec
++#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
++#define ST_MTIME_NSEC st_mtimensec
++#endif
++#endif
++
+#define RSYNCSUMS_FILE ".rsyncsums"
+#define RSYNCSUMS_LEN (sizeof RSYNCSUMS_FILE-1)
+
#define PTR_SIZE (sizeof (struct file_struct *))
int io_error;
-@@ -127,7 +137,11 @@ static char tmp_sum[MAX_DIGEST_LEN];
+@@ -127,7 +145,11 @@ static char tmp_sum[MAX_DIGEST_LEN];
static char empty_sum[MAX_DIGEST_LEN];
static int flist_count_offset; /* for --delete --progress */
static void output_flist(struct file_list *flist);
void init_flist(void)
-@@ -342,6 +356,238 @@ static void flist_done_allocating(struct file_list *flist)
+@@ -342,6 +364,238 @@ static void flist_done_allocating(struct file_list *flist)
flist->pool_boundary = ptr;
}
/* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's
* F_PATHNAME(), or (2) "NULL, dir, dirlen" to chdir() to the supplied dir,
* with dir == NULL taken to be the starting directory, and dirlen < 0
-@@ -1105,7 +1351,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1135,7 +1389,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
STRUCT_STAT *stp, int flags, int filter_level)
{
static char *lastdir;
struct file_struct *file;
char thisname[MAXPATHLEN];
char linkname[MAXPATHLEN];
-@@ -1251,9 +1497,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1281,9 +1535,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
memcpy(lastdir, thisname, len);
lastdir[len] = '\0';
lastdir_len = len;
basename_len = strlen(basename) + 1; /* count the '\0' */
#ifdef SUPPORT_LINKS
-@@ -1267,11 +1520,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1301,11 +1562,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
extra_len += EXTRA_LEN;
#endif
#if EXTRA_ROUNDING > 0
if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
-@@ -1347,8 +1597,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1390,8 +1648,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
return NULL;
}
if (unsort_ndx)
F_NDX(file) = stats.num_dirs;
-@@ -2462,7 +2718,7 @@ struct file_list *recv_file_list(int f)
- flist_eof = 1;
+@@ -2548,7 +2812,7 @@ struct file_list *recv_file_list(int f)
+ rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
}
- flist_sort_and_clean(flist, relative_paths);
if (protocol_version < 30) {
/* Recv the io_error flag */
-@@ -2683,7 +2939,7 @@ void flist_free(struct file_list *flist)
+@@ -2771,7 +3035,7 @@ void flist_free(struct file_list *flist)
/* This routine ensures we don't have any duplicate names in our file list.
* duplicate names can cause corruption because of the pipelining. */
{
char fbuf[MAXPATHLEN];
int i, prev_i;
-@@ -2734,7 +2990,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
+@@ -2822,7 +3086,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
/* If one is a dir and the other is not, we want to
* keep the dir because it might have contents in the
* list. Otherwise keep the first one. */
struct file_struct *fp = flist->sorted[j];
if (!S_ISDIR(fp->mode))
keep = i, drop = j;
-@@ -2750,8 +3006,8 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
+@@ -2838,8 +3102,8 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
} else
keep = j, drop = i;
rprintf(FINFO,
"removing duplicate name %s from file list (%d)\n",
f_name(file, fbuf), drop + flist->ndx_start);
-@@ -2773,7 +3029,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
+@@ -2861,7 +3125,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
}
flist->high = prev_i;
* paths, but this must be done _after_ the sorting phase. */
for (i = flist->low; i <= flist->high; i++) {
diff --git a/generator.c b/generator.c
-index 12007a1..48a5062 100644
--- a/generator.c
+++ b/generator.c
-@@ -53,6 +53,7 @@ extern int delete_after;
+@@ -51,6 +51,7 @@ extern int delete_after;
extern int missing_args;
extern int msgdone_cnt;
extern int ignore_errors;
extern int remove_source_files;
extern int delay_updates;
extern int update_only;
-@@ -522,7 +523,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
+@@ -564,7 +565,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
/* Perform our quick-check heuristic for determining if a file is unchanged. */
{
if (st->st_size != F_LENGTH(file))
return 0;
-@@ -531,7 +532,10 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
+@@ -573,7 +574,10 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st)
of the file time to determine whether to sync */
if (always_checksum > 0 && S_ISREG(st->st_mode)) {
char sum[MAX_DIGEST_LEN];
return memcmp(sum, F_SUM(file), checksum_len) == 0;
}
-@@ -795,7 +799,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
+@@ -843,7 +847,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
match_level = 1;
/* FALL THROUGH */
case 1:
continue;
best_match = j;
match_level = 2;
-@@ -1074,7 +1078,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1129,7 +1133,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
* --ignore-non-existing, daemon exclude, or mkdir failure. */
static struct file_struct *skip_dir = NULL;
static struct file_list *fuzzy_dirlist = NULL;
struct file_struct *fuzzy_file = NULL;
int fd = -1, f_copy = -1;
stat_x sx, real_sx;
-@@ -1158,8 +1162,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1213,8 +1217,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
flist_free(fuzzy_dirlist);
fuzzy_dirlist = NULL;
}
#ifdef SUPPORT_ACLS
if (!preserve_perms)
dflt_perms = default_perms_for_dir(dn);
-@@ -1167,10 +1171,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1222,10 +1226,15 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
parent_dirname = dn;
- if (need_fuzzy_dirlist && S_ISREG(file->mode)) {
- strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
-- fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1);
+- fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
- need_fuzzy_dirlist = 0;
+ if (need_new_dirscan && S_ISREG(file->mode)) {
+ if (fuzzy_basis) {
+ strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf);
-+ fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1);
++ fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES);
+ }
+ if (checksum_files) {
+ reset_checksum_cache();
}
statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
-@@ -1612,7 +1621,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1663,7 +1672,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
;
else if (fnamecmp_type == FNAMECMP_FUZZY)
;
do_unlink(partialptr);
handle_partial_dir(partialptr, PDIR_DELETE);
diff --git a/hlink.c b/hlink.c
-index c9eb33a..6109266 100644
--- a/hlink.c
+++ b/hlink.c
-@@ -413,7 +413,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
+@@ -410,7 +410,7 @@ int hard_link_check(struct file_struct *file, int ndx, char *fname,
}
break;
}
statret = 1;
if (unchanged_attrs(cmpbuf, file, &alt_sx))
diff --git a/itypes.h b/itypes.h
-index df34140..1bdf506 100644
--- a/itypes.h
+++ b/itypes.h
@@ -23,6 +23,12 @@ isDigit(const char *ptr)
{
return isprint(*(unsigned char *)ptr);
diff --git a/loadparm.c b/loadparm.c
-index 8e48e6d..899d2b5 100644
--- a/loadparm.c
+++ b/loadparm.c
-@@ -132,6 +132,7 @@ typedef struct {
+@@ -134,6 +134,7 @@ typedef struct {
/* NOTE: update this macro if the last char* variable changes! */
#define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
int max_connections;
int max_verbosity;
int syslog_facility;
-@@ -204,6 +205,7 @@ static const all_vars Defaults = {
+@@ -208,6 +209,7 @@ static const all_vars Defaults = {
/* temp_dir; */ NULL,
/* uid; */ NULL,
/* max_connections; */ 0,
/* max_verbosity; */ 1,
/* syslog_facility; */ LOG_DAEMON,
-@@ -305,6 +307,13 @@ static struct enum_list enum_facilities[] = {
+@@ -310,6 +312,13 @@ static struct enum_list enum_facilities[] = {
{ -1, NULL }
};
static struct parm_struct parm_table[] =
{
{"address", P_STRING, P_GLOBAL,&Vars.g.bind_address, NULL,0},
-@@ -315,6 +324,7 @@ static struct parm_struct parm_table[] =
+@@ -321,6 +330,7 @@ static struct parm_struct parm_table[] =
{"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0},
{"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0},
{"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0},
{"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0},
{"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0},
-@@ -419,6 +429,7 @@ FN_LOCAL_STRING(lp_secrets_file, secrets_file)
+@@ -477,6 +487,7 @@ FN_LOCAL_STRING(lp_secrets_file, secrets_file)
FN_LOCAL_STRING(lp_temp_dir, temp_dir)
FN_LOCAL_STRING(lp_uid, uid)
FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
diff --git a/options.c b/options.c
-index e7c6c61..2e110f3 100644
--- a/options.c
+++ b/options.c
-@@ -112,6 +112,7 @@ size_t bwlimit_writemax = 0;
+@@ -113,6 +113,7 @@ size_t bwlimit_writemax = 0;
int ignore_existing = 0;
int ignore_non_existing = 0;
int need_messages_from_generator = 0;
int max_delete = INT_MIN;
OFF_T max_size = 0;
OFF_T min_size = 0;
-@@ -661,6 +662,7 @@ void usage(enum logcode F)
+@@ -669,6 +670,7 @@ void usage(enum logcode F)
rprintf(F," -q, --quiet suppress non-error messages\n");
rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n");
rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n");
rprintf(F," -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)\n");
rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n");
rprintf(F," -r, --recursive recurse into directories\n");
-@@ -798,7 +800,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
+@@ -811,7 +813,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
+ OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
- OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG,
-- OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN,
-+ OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_SUMFILES,
+- OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG,
++ OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_SUMFILES,
+ OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT,
OPT_SERVER, OPT_REFUSED_BASE = 9000};
- static struct poptOption long_options[] = {
-@@ -933,6 +935,7 @@ static struct poptOption long_options[] = {
+@@ -951,6 +953,7 @@ static struct poptOption long_options[] = {
{"checksum", 'c', POPT_ARG_VAL, &always_checksum, 1, 0, 0 },
{"no-checksum", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
{"no-c", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
{"block-size", 'B', POPT_ARG_LONG, &block_size, 0, 0, 0 },
{"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
{"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
-@@ -1630,6 +1633,23 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -1669,6 +1672,23 @@ int parse_arguments(int *argc_p, const char ***argv_p)
}
break;
case OPT_INFO:
arg = poptGetOptArg(pc);
parse_output_words(info_words, info_levels, arg, USER_PRIORITY);
-@@ -1830,6 +1850,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -1883,6 +1903,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
}
#endif
snprintf(err_buf, sizeof err_buf,
"--write-batch and --read-batch can not be used together\n");
diff --git a/rsync.h b/rsync.h
-index be7cf8a..ba8f3db 100644
--- a/rsync.h
+++ b/rsync.h
-@@ -712,6 +712,10 @@ extern int xattrs_ndx;
- #define F_SUM(f) ((char*)OPT_EXTRA(f, LEN64_BUMP(f) + HLINK_BUMP(f) \
+@@ -771,6 +771,10 @@ extern int xattrs_ndx;
+ #define F_SUM(f) ((char*)OPT_EXTRA(f, START_BUMP(f) + HLINK_BUMP(f) \
+ SUM_EXTRA_CNT - 1))
+/* These are only valid on an entry read from a checksum file. */
/* Some utility defines: */
#define F_IS_ACTIVE(f) (f)->basename[0]
#define F_IS_HLINKED(f) ((f)->flags & FLAG_HLINKED)
-@@ -902,6 +906,13 @@ typedef struct {
+@@ -967,6 +971,13 @@ typedef struct {
char fname[1]; /* has variable size */
} relnamecache;
#include "lib/mdigest.h"
#include "lib/wildmatch.h"
diff --git a/rsync.yo b/rsync.yo
-index 941f7a5..7aa62cf 100644
--- a/rsync.yo
+++ b/rsync.yo
-@@ -323,6 +323,7 @@ to the detailed description below for a complete description. verb(
+@@ -337,6 +337,7 @@ to the detailed description below for a complete description. verb(
-q, --quiet suppress non-error messages
--no-motd suppress daemon-mode MOTD (see caveat)
-c, --checksum skip based on checksum, not mod-time & size
-a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)
--no-OPTION turn off an implied OPTION (e.g. --no-D)
-r, --recursive recurse into directories
-@@ -568,9 +569,9 @@ uses a "quick check" that (by default) checks if each file's size and time
+@@ -600,9 +601,9 @@ uses a "quick check" that (by default) checks if each file's size and time
of last modification match between the sender and receiver. This option
- changes this to compare a 128-bit MD4 checksum for each file that has a
+ changes this to compare a 128-bit checksum for each file that has a
matching size. Generating the checksums means that both sides will expend
-a lot of disk I/O reading all the data in the files in the transfer (and
-this is prior to any reading that will be done to transfer changed files),
The sending side generates its checksums while it is doing the file-system
scan that builds the list of the available files. The receiver generates
-@@ -578,12 +579,44 @@ its checksums when it is scanning for changed files, and will checksum any
+@@ -610,6 +611,8 @@ its checksums when it is scanning for changed files, and will checksum any
file that has the same size as the corresponding sender's file: files with
either a changed size or a changed checksum are selected for transfer.
Note that rsync always verifies that each em(transferred) file was
correctly reconstructed on the receiving side by checking a whole-file
checksum that is generated as the file is transferred, but that
- automatic after-the-transfer verification has nothing to do with this
- option's before-the-transfer "Does this file need to be updated?" check.
+@@ -619,6 +622,36 @@ option's before-the-transfer "Does this file need to be updated?" check.
+ For protocol 30 and beyond (first supported in 3.0.0), the checksum used is
+ MD5. For older protocols, the checksum used is MD4.
+dit(bf(--sumfiles=MODE)) This option tells rsync to make use of any cached
+checksum information it finds in per-directory .rsyncsums files when the
way of saying you want recursion and want to preserve almost
everything (with -H being a notable omission).
diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
-index d4978cd..0fc98fd 100644
--- a/rsyncd.conf.yo
+++ b/rsyncd.conf.yo
-@@ -292,6 +292,17 @@ locking on this file to ensure that the max connections limit is not
+@@ -323,6 +323,17 @@ locking on this file to ensure that the max connections limit is not
exceeded for the modules sharing the lock file.
The default is tt(/var/run/rsyncd.lock).
attempted uploads will fail. If "read only" is false then uploads will
diff --git a/support/rsyncsums b/support/rsyncsums
new file mode 100755
-index 0000000..ce03c80
--- /dev/null
+++ b/support/rsyncsums
@@ -0,0 +1,201 @@