+ flist_sort_and_clean(flist, CLEAN_KEEP_LAST);
+ }
+
++void set_cached_checksum(struct file_list *file_flist, struct file_struct *file)
++{
++ int j;
++ FILE *out_fp;
++ STRUCT_STAT st;
++ char fbuf[MAXPATHLEN];
++ const char *fn = f_name(file, NULL);
++ struct file_list *flist = csum_cache[0].flist;
++
++ if (dry_run && !(checksum_files & CSF_AFFECT_DRYRUN))
++ return;
++
++ if (stat(fn, &st) < 0)
++ return;
++
++ checksum_filename(0, file->dirname, fbuf);
++
++ if (file_flist != flist->next) {
++ const char *cp = F_SUM(file);
++ const char *end = cp + checksum_len;
++
++ if (!(out_fp = fopen(fbuf, "a")))
++ return;
++
++ if (protocol_version >= 30) {
++ for (j = 0; j < checksum_len; j++)
++ fputs("==", out_fp);
++ fputc(' ', out_fp);
++ }
++ do {
++ fprintf(out_fp, "%02x", (int)CVAL(cp, 0));
++ } while (++cp != end);
++ if (protocol_version < 30) {
++ fputc(' ', out_fp);
++ for (j = 0; j < checksum_len; j++)
++ fputs("==", out_fp);
++ }
++ fprintf(out_fp, " %10.0f %10.0f %10lu %10lu %s\n",
++ (double)st.st_size, (double)st.st_mtime,
++ (long)(uint32)st.st_ctime, (long)(uint32)st.st_ino,
++ file->basename);
++
++ fclose(out_fp);
++ return;
++ }
++
++ if ((j = flist_find(flist, file)) >= 0) {
++ struct file_struct *fp = flist->sorted[j];
++ int inc = 0;
++ if (F_LENGTH(fp) != st.st_size) {
++ fp->len32 = (uint32)st.st_size;
++ if (st.st_size > 0xFFFFFFFFu) {
++ OPT_EXTRA(fp, 0)->unum = (uint32)(st.st_size >> 32);
++ fp->flags |= FLAG_LENGTH64;
++ } else
++ fp->flags &= FLAG_LENGTH64;
++ inc = 1;
++ }
++ if (fp->modtime != st.st_mtime) {
++ fp->modtime = st.st_mtime;
++ inc = 1;
++ }
++ if (F_CTIME(fp) != (uint32)st.st_ctime) {
++ F_CTIME(fp) = (uint32)st.st_ctime;
++ inc = 1;
++ }
++ if (F_INODE(fp) != (uint32)st.st_ino) {
++ F_INODE(fp) = (uint32)st.st_ino;
++ inc = 1;
++ }
++ memcpy(F_SUM(fp), F_SUM(file), MAX_DIGEST_LEN);
++ csum_cache[0].checksum_updates += inc;
++ fp->flags &= ~FLAG_SUM_MISSING;
++ fp->flags |= FLAG_SUM_KEEP;
++ return;
++ }
++
++ csum_cache[0].checksum_updates +=
++ add_checksum(flist, file->dirname, file->basename, strlen(file->basename) + 1,
++ st.st_size, (uint32)st.st_mtime, (uint32)st.st_ctime,
++ st.st_ino, F_SUM(file), NULL, FLAG_SUM_KEEP);
++}
++
+ void get_cached_checksum(int slot, const char *fname, struct file_struct *file,
+- STRUCT_STAT *stp, char *sum_buf)
++ int basename_len, STRUCT_STAT *stp, char *sum_buf)
+ {
+ struct file_list *flist = csum_cache[slot].flist;
+ int j;
+
+ if (!flist->next) {
+ flist->next = cur_flist; /* next points from checksum flist to file flist */
++ csum_cache[slot].dirname = file->dirname;
+ read_checksums(slot, flist, file->dirname);
+ }
+
+@@ -575,12 +767,31 @@ void get_cached_checksum(int slot, const char *fname, struct file_struct *file,
+ && (checksum_files & CSF_LAX
+ || (F_CTIME(fp) == (uint32)stp->st_ctime
+ && F_INODE(fp) == (uint32)stp->st_ino))) {
+- memcpy(sum_buf, F_SUM(fp), MAX_DIGEST_LEN);
++ if (fp->flags & FLAG_SUM_MISSING) {
++ fp->flags &= ~FLAG_SUM_MISSING;
++ csum_cache[slot].checksum_updates++;
++ file_checksum(fname, stp->st_size, sum_buf);
++ memcpy(F_SUM(fp), sum_buf, MAX_DIGEST_LEN);
++ } else {
++ csum_cache[slot].checksum_matches++;
++ memcpy(sum_buf, F_SUM(fp), MAX_DIGEST_LEN);
++ }
++ fp->flags |= FLAG_SUM_KEEP;
+ return;
+ }
++ clear_file(fp);
+ }
+
+ file_checksum(fname, stp->st_size, sum_buf);
++
++ if (checksum_files & CSF_UPDATE) {
++ if (basename_len < 0)
++ basename_len = strlen(file->basename) + 1;
++ csum_cache[slot].checksum_updates +=
++ add_checksum(flist, file->dirname, file->basename, basename_len,
++ stp->st_size, stp->st_mtime, (uint32)stp->st_ctime,
++ (uint32)stp->st_ino, sum_buf, NULL, FLAG_SUM_KEEP);
++ }
+ }
+
+ /* Call this with EITHER (1) "file, NULL, 0" to chdir() to the file's
+@@ -1364,6 +1575,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+ if (excl_ret) {