+ }
++ upcoming_whole_dir = file->flags & FLAG_CONTENT_DIR && f_out != -1 ? 1 : 0;
+ goto cleanup;
+ }
+
+@@ -1791,6 +1794,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);
++ 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
+@@ -2205,6 +2210,7 @@ void generate_files(int f_out, const char *local_name)
+ } else
+ change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp));
+ }
++ upcoming_whole_dir = fp->flags & FLAG_CONTENT_DIR ? 1 : 0;
+ }
+ for (i = cur_flist->low; i <= cur_flist->high; i++) {
+ struct file_struct *file = cur_flist->sorted[i];
+@@ -2285,6 +2291,9 @@ void generate_files(int f_out, const char *local_name)
+ wait_for_receiver();
+ }
+
++ if (checksum_files)
++ reset_checksum_cache(started_whole_dir);
++
+ do_progress = save_do_progress;
+ if (delete_during == 2)
+ do_delayed_deletions(fbuf);
+diff --git a/io.c b/io.c
+--- a/io.c
++++ b/io.c
+@@ -50,6 +50,7 @@ extern int read_batch;
+ extern int csum_length;
+ extern int protect_args;
+ extern int checksum_seed;
++extern int checksum_files;
+ extern int protocol_version;
+ extern int remove_source_files;
+ extern int preserve_hard_links;
+@@ -205,6 +206,9 @@ static void got_flist_entry_status(enum festatus status, const char *buf)
+ flist_ndx_push(&hlink_list, ndx);
+ flist->in_progress++;
+ }
++ } else if (checksum_files & CSF_UPDATE) {
++ struct file_struct *file = flist->files[ndx - flist->ndx_start];
++ set_cached_checksum(flist, file);
+ }
+ break;
+ case FES_REDO:
+diff --git a/loadparm.c b/loadparm.c
+--- a/loadparm.c
++++ b/loadparm.c
+@@ -300,6 +300,10 @@ static struct enum_list enum_csum_modes[] = {
+ { CSF_IGNORE_FILES, "none" },
+ { CSF_LAX_MODE, "lax" },
+ { CSF_STRICT_MODE, "strict" },
++ { CSF_LAX_MODE|CSF_UPDATE, "+lax" },
++ { CSF_STRICT_MODE|CSF_UPDATE, "+strict" },
++ { CSF_LAX_MODE|CSF_UPDATE|CSF_AFFECT_DRYRUN, "++lax" },
++ { CSF_STRICT_MODE|CSF_UPDATE|CSF_AFFECT_DRYRUN, "++strict" },
+ { -1, NULL }
+ };
+
+diff --git a/options.c b/options.c
+--- a/options.c
++++ b/options.c
+@@ -1233,7 +1233,15 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+
+ case OPT_SUMFILES:
+ arg = poptGetOptArg(pc);
+- checksum_files = 0;
++ if (*arg == '+') {
++ arg++;
++ checksum_files = CSF_UPDATE;
++ if (*arg == '+') {
++ arg++;
++ checksum_files |= CSF_AFFECT_DRYRUN;
++ }
++ } else
++ checksum_files = 0;
+ if (strcmp(arg, "lax") == 0)
+ checksum_files |= CSF_LAX_MODE;
+ else if (strcmp(arg, "strict") == 0)
+diff --git a/receiver.c b/receiver.c
+--- a/receiver.c
++++ b/receiver.c
+@@ -47,6 +47,7 @@ extern int append_mode;
+ extern int sparse_files;
+ extern int keep_partial;
+ extern int checksum_seed;
++extern int checksum_files;
+ extern int inplace;
+ extern int delay_updates;
+ extern mode_t orig_umask;
+@@ -339,7 +340,7 @@ 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 || checksum_files & CSF_UPDATE
+ || (preserve_hard_links && F_IS_HLINKED(file)))
+ send_msg_int(MSG_SUCCESS, ndx);
+ handle_partial_dir(partialptr, PDIR_DELETE);
+@@ -716,7 +717,7 @@ int recv_files(int f_in, char *local_name)
+
+ switch (recv_ok) {
+ case 1:
+- if (remove_source_files || inc_recurse
++ if (remove_source_files || inc_recurse || checksum_files & CSF_UPDATE
+ || (preserve_hard_links && F_IS_HLINKED(file)))
+ send_msg_int(MSG_SUCCESS, ndx);
+ break;
+diff --git a/rsync.h b/rsync.h
+--- a/rsync.h
++++ b/rsync.h
+@@ -866,6 +866,8 @@ typedef struct {
+
+ #define CSF_ENABLE (1<<1)
+ #define CSF_LAX (1<<2)
++#define CSF_UPDATE (1<<3)
++#define CSF_AFFECT_DRYRUN (1<<4)
+
+ #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
+@@ -544,9 +544,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
+@@ -284,13 +284,15 @@ The default is tt(/var/run/rsyncd.lock).
+ dit(bf(checksum files)) 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 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.