extern int am_root;
extern int am_server;
extern int am_daemon;
-@@ -109,6 +110,9 @@ extern iconv_t ic_send, ic_recv;
+@@ -112,6 +113,9 @@ extern iconv_t ic_send, ic_recv;
#define PTR_SIZE (sizeof (struct file_struct *))
int io_error;
int flist_csum_len;
dev_t filesystem_dev; /* used to implement -x */
-@@ -150,8 +154,13 @@ static char empty_sum[MAX_DIGEST_LEN];
+@@ -154,8 +158,13 @@ static char empty_sum[MAX_DIGEST_LEN];
static int flist_count_offset; /* for --delete --progress */
static int show_filelist_progress;
+ int checksum_updates;
} *csum_cache = NULL;
- static void flist_sort_and_clean(struct file_list *flist, int flags);
-@@ -348,7 +357,79 @@ static void flist_done_allocating(struct file_list *flist)
+ static struct file_list *flist_new(int flags, const char *msg);
+@@ -351,7 +360,79 @@ static void flist_done_allocating(struct file_list *flist)
flist->pool_boundary = ptr;
}
+ const char *alt_sum = file->basename + strlen(file->basename) + 1;
+ if (whole_dir && !(file->flags & FLAG_SUM_KEEP))
+ continue;
-+ if (checksum_type == 5)
++ if (file_sum_nni->num == CSUM_MD5)
+ fprintf(out_fp, "%s ", alt_sum);
+ if (file->flags & FLAG_SUM_MISSING) {
+ do {
+ fprintf(out_fp, "%02x", (int)CVAL(cp, 0));
+ } while (++cp != end);
+ }
-+ if (checksum_type != 5)
++ if (file_sum_nni->num < CSUM_MD5)
+ fprintf(out_fp, " %s", alt_sum);
+ fprintf(out_fp, " %10.0f %10.0f %10lu %10lu %s\n",
+ (double)F_LENGTH(file), (double)file->modtime,
@@ -458,7 +554,7 @@ static void read_checksums(int slot, struct file_list *flist, const char *dirnam
while (fgets(line, sizeof line, fp)) {
cp = line;
- if (checksum_type == 5) {
+ if (file_sum_nni->num == CSUM_MD5) {
- char *alt_sum = cp;
+ alt_sum = cp;
if (*cp == '=')
break;
while (*++cp == ' ') {}
- if (checksum_type != 5) {
+ if (file_sum_nni->num < CSUM_MD5) {
- char *alt_sum = cp;
+ alt_sum = cp;
if (*cp == '=')
+ if (!(out_fp = fopen(fbuf, "a")))
+ return;
+
-+ if (checksum_type == 5) {
++ if (file_sum_nni->num == CSUM_MD5) {
+ for (j = 0; j < flist_csum_len; j++)
+ fputs("==", out_fp);
+ fputc(' ', out_fp);
+ do {
+ fprintf(out_fp, "%02x", (int)CVAL(cp, 0));
+ } while (++cp != end);
-+ if (checksum_type != 5) {
++ if (file_sum_nni->num < CSUM_MD5) {
+ fputc(' ', out_fp);
+ for (j = 0; j < flist_csum_len; j++)
+ fputs("==", out_fp);
}
/* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's
-@@ -1504,6 +1715,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1583,6 +1794,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) {
if (ignore_perishable)
non_perishable_cnt++;
return NULL;
}
-@@ -1550,13 +1763,13 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1629,13 +1842,13 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
lastdir[len] = '\0';
lastdir_len = len;
if (checksum_files && am_sender && flist)
}
}
basename_len = strlen(basename) + 1; /* count the '\0' */
-@@ -1666,7 +1879,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+@@ -1759,7 +1972,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
if (always_checksum && am_sender && S_ISREG(st.st_mode)) {
if (flist && checksum_files)
else
file_checksum(thisname, &st, tmp_sum);
if (sender_keeps_checksum)
-@@ -2045,6 +2258,9 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
+@@ -2151,6 +2364,9 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
closedir(d);
if (f >= 0 && recurse && !divert_dirs) {
int i, end = flist->used - 1;
/* send_if_directory() bumps flist->used, so use "end". */
-@@ -2704,6 +2920,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
+@@ -2816,6 +3032,9 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
}
diff --git a/generator.c b/generator.c
--- a/generator.c
+++ b/generator.c
-@@ -112,6 +112,7 @@ static int dir_tweaking;
+@@ -113,6 +113,7 @@ static int dir_tweaking;
static int symlink_timeset_failed_flags;
static int need_retouch_dir_times;
static int need_retouch_dir_perms;
+static int started_whole_dir, upcoming_whole_dir;
static const char *solo_file = NULL;
- enum nonregtype {
-@@ -589,7 +590,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st, int slot
- if (always_checksum > 0 && S_ISREG(st->st_mode)) {
- char sum[MAX_DIGEST_LEN];
- if (checksum_files && slot >= 0)
-- get_cached_checksum(slot, fn, file, st, sum);
-+ get_cached_checksum(slot, fn, file, -1, st, sum);
- else
- file_checksum(fn, st, sum);
- return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
-@@ -1327,7 +1328,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+ /* Forward declarations. */
+@@ -627,7 +628,7 @@ int quick_check_ok(enum filetype ftype, const char *fn, struct file_struct *file
+ if (always_checksum > 0) {
+ char sum[MAX_DIGEST_LEN];
+ if (checksum_files && slot >= 0)
+- get_cached_checksum(slot, fn, file, st, sum);
++ get_cached_checksum(slot, fn, file, -1, st, sum);
+ else
+ file_checksum(fn, st, sum);
+ return memcmp(sum, F_SUM(file), flist_csum_len) == 0;
+@@ -1359,7 +1360,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
}
if (checksum_files) {
}
need_new_dirscan = 0;
}
-@@ -1501,6 +1503,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1547,6 +1549,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
else
change_local_filter_dir(fname, strlen(fname), F_DEPTH(file));
}
prior_dir_file = file;
goto cleanup;
}
-@@ -1780,6 +1783,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
+@@ -1819,6 +1822,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
handle_partial_dir(partialptr, PDIR_DELETE);
}
- set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT | maybe_ATTRS_SET_NANO);
+ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT | maybe_ATTRS_ACCURATE_TIME);
+ if (checksum_files & CSF_UPDATE)
+ set_cached_checksum(cur_flist, file);
if (itemizing)
itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL);
#ifdef SUPPORT_HARD_LINKS
-@@ -2278,6 +2283,7 @@ void generate_files(int f_out, const char *local_name)
+@@ -2311,6 +2316,7 @@ void generate_files(int f_out, const char *local_name)
} else
change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
}
}
for (i = cur_flist->low; i <= cur_flist->high; i++) {
struct file_struct *file = cur_flist->sorted[i];
-@@ -2372,6 +2378,9 @@ void generate_files(int f_out, const char *local_name)
+@@ -2405,6 +2411,9 @@ void generate_files(int f_out, const char *local_name)
wait_for_receiver();
}
diff --git a/io.c b/io.c
--- a/io.c
+++ b/io.c
-@@ -53,6 +53,7 @@ extern int read_batch;
+@@ -55,6 +55,7 @@ extern int read_batch;
extern int compat_flags;
extern int protect_args;
extern int checksum_seed;
+extern int checksum_files;
+ extern int daemon_connection;
extern int protocol_version;
extern int remove_source_files;
- extern int preserve_hard_links;
-@@ -1050,6 +1051,9 @@ static void got_flist_entry_status(enum festatus status, int ndx)
+@@ -1117,6 +1118,9 @@ static void got_flist_entry_status(enum festatus status, int ndx)
if (inc_recurse)
flist->in_progress++;
}
diff --git a/loadparm.c b/loadparm.c
--- a/loadparm.c
+++ b/loadparm.c
-@@ -393,6 +393,10 @@ static struct enum_list enum_csum_modes[] = {
+@@ -166,6 +166,10 @@ static struct enum_list enum_checksum_files[] = {
{ CSF_IGNORE_FILES, "none" },
{ CSF_LAX_MODE, "lax" },
{ CSF_STRICT_MODE, "strict" },
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
-@@ -1728,7 +1728,15 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -1750,7 +1750,15 @@ int parse_arguments(int *argc_p, const char ***argv_p)
case OPT_SUMFILES:
arg = poptGetOptArg(pc);
diff --git a/receiver.c b/receiver.c
--- a/receiver.c
+++ b/receiver.c
-@@ -50,6 +50,7 @@ extern int sparse_files;
+@@ -51,6 +51,7 @@ extern int sparse_files;
extern int preallocate_files;
extern int keep_partial;
extern int checksum_seed;
+extern int checksum_files;
extern int whole_file;
extern int inplace;
- extern int allowed_lull;
-@@ -432,7 +433,7 @@ static void handle_delayed_updates(char *local_name)
+ extern int inplace_partial;
+@@ -440,7 +441,8 @@ static void handle_delayed_updates(char *local_name)
"rename failed for %s (from %s)",
full_fname(fname), partialptr);
} else {
-- if (remove_source_files
+- if (remove_source_files || (preserve_hard_links && F_IS_HLINKED(file)))
+ if (remove_source_files || checksum_files & CSF_UPDATE
- || (preserve_hard_links && F_IS_HLINKED(file)))
- send_msg_int(MSG_SUCCESS, ndx);
++ || (preserve_hard_links && F_IS_HLINKED(file)))
+ send_msg_success(fname, ndx);
handle_partial_dir(partialptr, PDIR_DELETE);
-@@ -912,7 +913,7 @@ int recv_files(int f_in, int f_out, char *local_name)
+ }
+@@ -926,7 +928,8 @@ int recv_files(int f_in, int f_out, char *local_name)
case 2:
break;
case 1:
-- if (remove_source_files || inc_recurse
+- if (remove_source_files || inc_recurse || (preserve_hard_links && F_IS_HLINKED(file)))
+ if (remove_source_files || inc_recurse || checksum_files & CSF_UPDATE
- || (preserve_hard_links && F_IS_HLINKED(file)))
- send_msg_int(MSG_SUCCESS, ndx);
++ || (preserve_hard_links && F_IS_HLINKED(file)))
+ send_msg_success(fname, ndx);
break;
+ case 0: {
+diff --git a/rsync.1.md b/rsync.1.md
+--- a/rsync.1.md
++++ b/rsync.1.md
+@@ -803,9 +803,13 @@ expand it.
+
+ The MODE value is either "lax", for relaxed checking (which compares size
+ and mtime), "strict" (which also compares ctime and inode), or "none" to
+- ignore any .rsyncsums files ("none" is the default). Rsync does not create
+- or update these files, but there is a perl script in the support directory
+- named "rsyncsums" that can be used for that.
++ ignore any .rsyncsums files ("none" is the default).
++ If you want rsync to create and/or update these files, specify a prefixed
++ plus ("+lax" or "+strict"). Adding a second prefixed '+' causes the
++ checksum-file updates to happen even when the transfer is in [`--dry-run`](#opt)
++ mode ("++lax" or "++strict"). There is also a perl script in the support
++ directory named "rsyncsums" that can be used to update the .rsyncsums
++ files.
+
+ This option has no effect unless [`--checksum`](#opt) (`-c`) was also
+ specified. It also only affects the current side of the transfer, so if
diff --git a/rsync.h b/rsync.h
--- a/rsync.h
+++ b/rsync.h
-@@ -1027,6 +1027,8 @@ typedef struct {
+@@ -1123,6 +1123,8 @@ typedef struct {
#define CSF_ENABLE (1<<1)
#define CSF_LAX (1<<2)
#define CSF_IGNORE_FILES 0
#define CSF_LAX_MODE (CSF_ENABLE|CSF_LAX)
-diff --git a/rsync.yo b/rsync.yo
---- a/rsync.yo
-+++ b/rsync.yo
-@@ -672,9 +672,13 @@ computed just as it would be if bf(--sumfiles) was not specified.
-
- The MODE value is either "lax", for relaxed checking (which compares size
- and mtime), "strict" (which also compares ctime and inode), or "none" to
--ignore any .rsyncsums files ("none" is the default). Rsync does not create
--or update these files, but there is a perl script in the support directory
--named "rsyncsums" that can be used for that.
-+ignore any .rsyncsums files ("none" is the default).
-+If you want rsync to create and/or update these files, specify a prefixed
-+plus ("+lax" or "+strict").
-+Adding a second prefixed '+' causes the checksum-file updates to happen
-+even when the transfer is in bf(--dry-run) mode ("++lax" or "++strict").
-+There is also a perl script in the support directory named "rsyncsums"
-+that can be used to update the .rsyncsums files.
-
- This option has no effect unless bf(--checksum, -c) was also specified. It
- also only affects the current side of the transfer, so if you want the
-diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
---- a/rsyncd.conf.yo
-+++ b/rsyncd.conf.yo
-@@ -358,13 +358,15 @@ The default is tt(/var/run/rsyncd.lock).
- dit(bf(checksum files)) This parameter tells rsync to make use of any cached
- checksum information it finds in per-directory .rsyncsums files when the
- current transfer is using the bf(--checksum) option. The value can be set
--to either "lax", "strict", or "none" -- see the client's bf(--sumfiles)
--option for what these choices do.
-+to either "lax", "strict", "+lax", "+strict", "++lax", "++strict", or
-+"none". See the client's bf(--sumfiles) option for what these choices do.
-
- Note also that the client's command-line option, bf(--sumfiles), has no
- effect on a daemon. A daemon will only access checksum files if this
--config option tells it to. See also the bf(exclude) directive for a way
--to hide the .rsyncsums files from the user.
-+config option tells it to. You can configure updating of the .rsyncsums
-+files even if the module itself is configured to be read-only. See also
-+the bf(exclude) directive for a way to hide the .rsyncsums files from the
-+user.
-
- dit(bf(read only)) This parameter determines whether clients
- will be able to upload files or not. If "read only" is true then any
+diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md
+--- a/rsyncd.conf.5.md
++++ b/rsyncd.conf.5.md
+@@ -450,13 +450,15 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
+ This parameter 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. The value can be set to either "lax",
+- "strict", or "none". See the client's `--sumfiles` option for what these
+- choices do.
++ "strict", "+lax", "+strict", "++lax", "++strict", or +"none". See the
++ client's `--sumfiles` option for what these choices do.
+
+ Note also that the client's command-line option, `--sumfiles`, has no
+ effect on a daemon. A daemon will only access checksum files if this
+- config option tells it to. See also the `exclude` directive for a way to
+- hide the .rsyncsums files from the user.
++ config option tells it to. You can configure updating of the .rsyncsums
++ files even if the module itself is configured to be read-only. See also
++ the `exclude` directive for a way to hide the .rsyncsums files from the
++ user.
+
+ 0. `read only`
+