+ return 1;
+ }
+@@ -271,13 +276,18 @@ static void do_delayed_deletions(char *delbuf)
+ * all the --delete-WHEN options. Note that the fbuf pointer must point to a
+ * MAXPATHLEN buffer with the name of the directory in it (the functions we
+ * call will append names onto the end, but the old dir value will be restored
+- * on exit). */
+-static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
++ * on exit).
++ *
++ * Note: --detect-rename may use this routine with DEL_NO_DELETIONS set!
++ */
++static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev,
++ int del_flags)
+ {
+ static int already_warned = 0;
+ struct file_list *dirlist;
+- char delbuf[MAXPATHLEN];
+- int dlen, i;
++ char *p, delbuf[MAXPATHLEN];
++ unsigned remainder;
++ int dlen, i, restore_dot = 0;
+ int save_uid_ndx = uid_ndx;
+
+ if (!fbuf) {
+@@ -292,17 +302,22 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
+ maybe_send_keepalive(time(NULL), True);
+
+ if (io_error && !ignore_errors) {
+- if (already_warned)
++ if (!already_warned) {
++ rprintf(FINFO,
++ "IO error encountered -- skipping file deletion\n");
++ already_warned = 1;
++ }
++ if (!detect_renamed)
+ return;
+- rprintf(FINFO,
+- "IO error encountered -- skipping file deletion\n");
+- already_warned = 1;
+- return;
++ del_flags |= DEL_NO_DELETIONS;
+ }
+
+ dlen = strlen(fbuf);
+ change_local_filter_dir(fbuf, dlen, F_DEPTH(file));
+
++ if (detect_renamed)
++ unexplored_dirs--;
++
+ if (one_file_system) {
+ if (file->flags & FLAG_TOP_DIR)
+ filesystem_dev = *fs_dev;
+@@ -315,6 +330,14 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
+
+ dirlist = get_dirlist(fbuf, dlen, 0);
+
++ p = fbuf + dlen;
++ if (dlen == 1 && *fbuf == '.') {
++ restore_dot = 1;
++ p = fbuf;
++ } else if (dlen != 1 || *fbuf != '/')
++ *p++ = '/';
++ remainder = MAXPATHLEN - (p - fbuf);
++
+ /* If an item in dirlist is not found in flist, delete it
+ * from the filesystem. */
+ for (i = dirlist->used; i--; ) {
+@@ -327,6 +350,10 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
+ f_name(fp, NULL));
+ continue;
+ }
++ if (detect_renamed && S_ISREG(fp->mode)) {
++ strlcpy(p, fp->basename, remainder);
++ look_for_rename(fp, fbuf);
++ }
+ /* Here we want to match regardless of file type. Replacement
+ * of a file with one of another type is handled separately by
+ * a delete_item call with a DEL_MAKE_ROOM flag. */
+@@ -335,14 +362,19 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
+ if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
+ flags |= DEL_NO_UID_WRITE;
+ f_name(fp, delbuf);
+- if (delete_during == 2) {
+- if (!remember_delete(fp, delbuf, flags))
++ if (delete_during == 2 && !(del_flags & DEL_NO_DELETIONS)) {
++ if (!remember_delete(fp, delbuf, del_flags | flags))
+ break;
+ } else
+- delete_item(delbuf, fp->mode, flags);
+- }
++ delete_item(delbuf, fp->mode, del_flags | flags);
++ } else if (detect_renamed && S_ISDIR(fp->mode))
++ unexplored_dirs++;
+ }
+
++ if (restore_dot)
++ fbuf[0] = '.';
++ fbuf[dlen] = '\0';
++
+ flist_free(dirlist);