./configure (optional if already run)
make
-based-on: a2b630c0bb586c9761fd5fc53dc4c212b6dd25df
+based-on: ed4b3448be243b1bdb30a5da811f1e217f5a0601
diff --git a/clientserver.c b/clientserver.c
--- a/clientserver.c
+++ b/clientserver.c
extern int io_timeout;
extern int no_detach;
extern int write_batch;
-@@ -1067,6 +1069,9 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
+@@ -1106,6 +1108,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;
extern int inc_recurse;
extern int always_checksum;
+extern int basis_dir_cnt;
- extern int checksum_type;
extern int module_id;
extern int ignore_errors;
+ extern int numeric_ids;
@@ -62,6 +64,7 @@ extern int implied_dirs;
extern int ignore_perishable;
extern int non_perishable_cnt;
extern int copy_links;
extern int copy_unsafe_links;
extern int protocol_version;
-@@ -73,6 +76,7 @@ extern int sender_symlink_iconv;
- extern int output_needs_newline;
+@@ -74,6 +77,7 @@ extern int output_needs_newline;
extern int sender_keeps_checksum;
+ extern int trust_sender_filter;
extern int unsort_ndx;
+extern char *basis_dir[];
extern uid_t our_uid;
extern struct stats stats;
extern char *filesfrom_host;
-@@ -90,6 +94,20 @@ extern int filesfrom_convert;
+@@ -92,6 +96,20 @@ extern int filesfrom_convert;
extern iconv_t ic_send, ic_recv;
#endif
#define PTR_SIZE (sizeof (struct file_struct *))
int io_error;
-@@ -134,8 +152,12 @@ static char empty_sum[MAX_DIGEST_LEN];
+@@ -136,8 +154,12 @@ static char empty_sum[MAX_DIGEST_LEN];
static int flist_count_offset; /* for --delete --progress */
static int show_filelist_progress;
static void output_flist(struct file_list *flist);
void init_flist(void)
-@@ -326,6 +348,235 @@ static void flist_done_allocating(struct file_list *flist)
+@@ -329,6 +351,235 @@ static void flist_done_allocating(struct file_list *flist)
flist->pool_boundary = ptr;
}
+
+ while (fgets(line, sizeof line, fp)) {
+ cp = line;
-+ if (checksum_type == 5) {
++ if (file_sum_nni->num == CSUM_MD5) {
+ char *alt_sum = cp;
+ if (*cp == '=')
+ while (*++cp == '=') {}
+ break;
+ while (*++cp == ' ') {}
+
-+ if (checksum_type != 5) {
++ if (file_sum_nni->num < CSUM_MD5) {
+ char *alt_sum = cp;
+ if (*cp == '=')
+ while (*++cp == '=') {}
/* 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
-@@ -1203,7 +1454,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1231,7 +1482,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];
-@@ -1349,9 +1600,16 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1377,9 +1628,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
-@@ -1369,11 +1627,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1409,11 +1667,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))
-@@ -1462,8 +1717,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1502,8 +1757,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
return NULL;
}
if (unsort_ndx)
F_NDX(file) = stats.num_dirs;
-@@ -2680,7 +2941,7 @@ struct file_list *recv_file_list(int f, int dir_ndx)
+@@ -2720,7 +2981,7 @@ struct file_list *recv_file_list(int f, int dir_ndx)
/* The --relative option sends paths with a leading slash, so we need
* to specify the strip_root option here. We rejected leading slashes
* for a non-relative transfer in recv_file_entry(). */
if (protocol_version < 30) {
/* Recv the io_error flag */
-@@ -2925,7 +3186,7 @@ void flist_free(struct file_list *flist)
+@@ -2965,7 +3226,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;
-@@ -2976,7 +3237,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
+@@ -3016,7 +3277,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;
-@@ -2992,8 +3253,8 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
+@@ -3032,8 +3293,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);
-@@ -3015,7 +3276,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
+@@ -3055,7 +3316,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
}
flist->high = prev_i;
return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
}
-@@ -953,7 +957,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
+@@ -956,7 +960,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
best_match = j;
match_level = 1;
}
continue;
if (match_level == 1) {
best_match = j;
-@@ -1212,7 +1216,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1079,7 +1083,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
+ match_level = 1;
+ best_match = j;
+ }
+- if (!quick_check_ok(ftype, cmpbuf, file, &sxp->st))
++ if (!quick_check_ok(ftype, cmpbuf, file, &sxp->st, j+1))
+ continue;
+ if (match_level < 2) {
+ match_level = 2;
+@@ -1215,7 +1219,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[MAX_BASIS_DIRS+1];
struct file_struct *fuzzy_file = NULL;
int fd = -1, f_copy = -1;
stat_x sx, real_sx;
-@@ -1329,8 +1333,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1332,8 +1336,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fuzzy_dirlist[i] = NULL;
}
}
#ifdef SUPPORT_ACLS
if (!preserve_perms)
dflt_perms = default_perms_for_dir(dn);
-@@ -1338,6 +1343,24 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1341,6 +1346,24 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
parent_dirname = dn;
statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
stat_errno = errno;
}
-@@ -1749,22 +1772,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1387,7 +1410,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+ if (INFO_GTE(SKIP, 2)) {
+ if (ftype != stype)
+ suf = " (type change)";
+- else if (!quick_check_ok(ftype, fname, file, &sx.st))
++ else if (!quick_check_ok(ftype, fname, file, &sx.st, 0))
+ suf = always_checksum ? " (sum change)" : " (file change)";
+ else if (!unchanged_attrs(fname, file, &sx))
+ suf = " (attr change)";
+@@ -1558,7 +1581,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+ goto cleanup;
+ }
+ if (statret == 0) {
+- if (stype == FT_SYMLINK && quick_check_ok(stype, fname, file, &sx.st)) {
++ if (stype == FT_SYMLINK && quick_check_ok(stype, fname, file, &sx.st, 0)) {
+ /* The link is pointing to the right place. */
+ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
+ if (itemizing)
+@@ -1627,7 +1650,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+ if (statret == 0) {
+ if (ftype != stype)
+ statret = -1;
+- else if (quick_check_ok(ftype, fname, file, &sx.st)) {
++ else if (quick_check_ok(ftype, fname, file, &sx.st, 0)) {
+ /* The device or special file is identical. */
+ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
+ if (itemizing)
+@@ -1752,22 +1775,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
partialptr = NULL;
if (statret != 0 && fuzzy_basis) {
/* Sets fnamecmp_type to FNAMECMP_FUZZY or above. */
fuzzy_file = find_fuzzy(file, fuzzy_dirlist, &fnamecmp_type);
if (fuzzy_file) {
-@@ -1797,7 +1804,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1806,7 +1813,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
;
else if (fnamecmp_type >= FNAMECMP_FUZZY)
;
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
-@@ -120,6 +120,7 @@ size_t bwlimit_writemax = 0;
+@@ -126,6 +126,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 = -1;
OFF_T min_size = -1;
-@@ -575,7 +576,7 @@ enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
+@@ -581,7 +582,7 @@ enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
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_BLOCK_SIZE,
- OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR,
+ OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR, OPT_SUMFILES,
- OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS,
+ OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS, OPT_OLD_ARGS,
OPT_STOP_AFTER, OPT_STOP_AT,
OPT_REFUSED_BASE = 9000};
-@@ -731,6 +732,7 @@ static struct poptOption long_options[] = {
+@@ -738,6 +739,7 @@ static struct poptOption long_options[] = {
{"no-c", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
{"checksum-choice", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 },
{"cc", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 },
{"block-size", 'B', POPT_ARG_STRING, 0, OPT_BLOCK_SIZE, 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 },
-@@ -1725,6 +1727,23 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -1746,6 +1748,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);
-@@ -2059,6 +2078,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2099,6 +2118,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
}
#endif
diff --git a/rsync.1.md b/rsync.1.md
--- a/rsync.1.md
+++ b/rsync.1.md
-@@ -338,6 +338,7 @@ detailed description below for a complete description.
+@@ -386,6 +386,7 @@ has its own detailed description later in this manpage.
--quiet, -q suppress non-error messages
--no-motd suppress daemon-mode MOTD
--checksum, -c skip based on checksum, not mod-time & size
--archive, -a archive mode is -rlptgoD (no -A,-X,-U,-N,-H)
--no-OPTION turn off an implied OPTION (e.g. --no-D)
--recursive, -r recurse into directories
-@@ -703,6 +704,8 @@ your home directory (remove the '=' for that).
+@@ -778,6 +779,8 @@ expand it.
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.
-+ See also the `--sumfiles` option for a way to use cached checksum data.
++ See also the [`--sumfiles`](#opt) option for a way to use cached checksum data.
+
Note that rsync always verifies that each _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
-@@ -713,6 +716,38 @@ your home directory (remove the '=' for that).
- can be overridden using either the `--checksum-choice` (`--cc`) option or an
- environment variable that is discussed in that option's section.
+@@ -789,6 +792,38 @@ expand it.
+ option or an environment variable that is discussed in that option's
+ section.
+0. `--sumfiles=MODE`
+
+ This option tells rsync to make use of any cached checksum information it
+ finds in per-directory .rsyncsums files when the current transfer is using
-+ the `--checksum` option. If the checksum data is up-to-date, it is used
-+ instead of recomputing it, saving both disk I/O and CPU time. If the
++ the [`--checksum`](#opt) option. If the checksum data is up-to-date, it is
++ used instead of recomputing it, saving both disk I/O and CPU time. If the
+ checksum data is missing or outdated, the checksum is computed just as it
+ would be if `--sumfiles` was not specified.
+
+ or update these files, but there is a perl script in the support directory
+ named "rsyncsums" that can be used for that.
+
-+ This option has no effect unless `--checksum`, `-c` was also specified. It
-+ also only affects the current side of the transfer, so if you want the
-+ remote side to parse its own .rsyncsums files, specify the option via
-+ `--remote-option` (`-M`) (e.g. "`-M--sumfiles=lax`").
++ This option has no effect unless [`--checksum`](#opt) (`-c`) was also
++ specified. It also only affects the current side of the transfer, so if
++ you want the remote side to parse its own .rsyncsums files, specify the
++ option via [`--remote-option`](#opt) (`-M`) (e.g. "`-M--sumfiles=lax`").
+
+ To avoid transferring the system's checksum files, you can use an exclude
-+ (e.g. `--exclude=.rsyncsums`). To make this easier to type, you can use a
-+ popt alias. For instance, adding the following line in your ~/.popt file
-+ defines a `--cs` option that enables lax checksum files and excludes the
-+ checksum files:
++ (e.g. [`--exclude=.rsyncsums`](#opt)). To make this easier to type, you
++ can use a popt alias. For instance, adding the following line in your
++ ~/.popt file defines a `--cs` option that enables lax checksum files and
++ excludes the checksum files:
+
+ > rsync alias --cs -c --sumfiles=lax -M--sumfiles=lax -f-_.rsyncsums
+
diff --git a/rsync.h b/rsync.h
--- a/rsync.h
+++ b/rsync.h
-@@ -901,6 +901,10 @@ extern int xattrs_ndx;
+@@ -903,6 +903,10 @@ extern int file_sum_extra_cnt;
#define F_SUM(f) ((char*)OPT_EXTRA(f, START_BUMP(f) + HLINK_BUMP(f) \
+ SUM_EXTRA_CNT - 1))
/* Some utility defines: */
#define F_IS_ACTIVE(f) (f)->basename[0]
#define F_IS_HLINKED(f) ((f)->flags & FLAG_HLINKED)
-@@ -1114,6 +1118,13 @@ typedef struct {
+@@ -1117,6 +1121,13 @@ typedef struct {
#define RELNAMECACHE_LEN (offsetof(relnamecache, fname))
#endif
diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md
--- a/rsyncd.conf.5.md
+++ b/rsyncd.conf.5.md
-@@ -419,6 +419,19 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
+@@ -449,6 +449,19 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
the max connections limit is not exceeded for the modules sharing the lock
file. The default is `/var/run/rsyncd.lock`.