Fixed a case where the receiver indicates a successful update when the
authorWayne Davison <wayned@samba.org>
Mon, 31 Dec 2007 18:18:22 +0000 (10:18 -0800)
committerWayne Davison <wayned@samba.org>
Mon, 31 Dec 2007 18:31:43 +0000 (10:31 -0800)
transfer succeeded, but the final rename failed.

generator.c
receiver.c
rsync.c

index 046ad95..35cbb57 100644 (file)
@@ -841,7 +841,7 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
 {
        char buf[MAXPATHLEN];
        const char *copy_to, *partialptr;
-       int fd_w;
+       int ok, fd_w;
 
        if (inplace) {
                /* Let copy_file open the destination in place. */
@@ -865,11 +865,9 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
                return -1;
        }
        partialptr = partial_dir ? partial_dir_fname(dest) : NULL;
-       if (partialptr && *partialptr == '/')
-               partialptr = NULL;
-       finish_transfer(dest, copy_to, src, partialptr, file, 1, 0);
+       ok = finish_transfer(dest, copy_to, src, partialptr, file, 1, 0);
        cleanup_disable();
-       return 0;
+       return ok ? 0 : -1;
 }
 
 /* This is only called for regular files.  We return -2 if we've finished
index 3834ce2..38eaa84 100644 (file)
@@ -688,26 +688,23 @@ int recv_files(int f_in, char *local_name)
                }
 
                if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
-                       char *temp_copy_name;
                        if (partialptr == fname)
-                               partialptr = temp_copy_name = NULL;
-                       else if (*partial_dir == '/')
-                               temp_copy_name = NULL;
-                       else
-                               temp_copy_name = partialptr;
-                       finish_transfer(fname, fnametmp, fnamecmp,
-                                       temp_copy_name, file, recv_ok, 1);
-                       if (fnamecmp == partialptr) {
+                               partialptr = NULL;
+                       if (!finish_transfer(fname, fnametmp, fnamecmp,
+                                            partialptr, file, recv_ok, 1))
+                               recv_ok = -1;
+                       else if (fnamecmp == partialptr) {
                                do_unlink(partialptr);
                                handle_partial_dir(partialptr, PDIR_DELETE);
                        }
                } else if (keep_partial && partialptr
                    && handle_partial_dir(partialptr, PDIR_CREATE)) {
-                       finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
-                                       file, recv_ok, !partial_dir);
-                       if (delay_updates && recv_ok) {
-                               bitbag_set_bit(delayed_bits, ndx);
+                       if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
+                                            file, recv_ok, !partial_dir))
                                recv_ok = -1;
+                       else if (delay_updates && recv_ok) {
+                               bitbag_set_bit(delayed_bits, ndx);
+                               recv_ok = 2;
                        }
                } else {
                        partialptr = NULL;
@@ -716,11 +713,13 @@ int recv_files(int f_in, char *local_name)
 
                cleanup_disable();
 
-               if (recv_ok > 0) {
+               switch (recv_ok) {
+               case 1:
                        if (remove_source_files || inc_recurse
                         || (preserve_hard_links && F_IS_HLINKED(file)))
                                send_msg_int(MSG_SUCCESS, ndx);
-               } else if (!recv_ok) {
+                       break;
+               case 0: {
                        enum logcode msgtype = redoing || read_batch ? FERROR : FWARNING;
                        if (msgtype == FERROR || verbose) {
                                char *errstr, *redostr, *keptstr;
@@ -746,6 +745,12 @@ int recv_files(int f_in, char *local_name)
                                file->flags |= FLAG_FILE_SENT;
                        } else if (inc_recurse)
                                send_msg_int(MSG_NO_SEND, ndx);
+                       break;
+                   }
+               case -1:
+                       if (inc_recurse)
+                               send_msg_int(MSG_NO_SEND, ndx);
+                       break;
                }
        }
        if (make_backups < 0)
diff --git a/rsync.c b/rsync.c
index 1654c30..7505c63 100644 (file)
--- a/rsync.c
+++ b/rsync.c
@@ -504,15 +504,17 @@ RETSIGTYPE sig_int(UNUSED(int val))
 }
 
 /* Finish off a file transfer: renaming the file and setting the file's
- * attributes (e.g. permissions, ownership, etc.).  If partialptr is not
- * NULL and the robust_rename() call is forced to copy the temp file, we
- * stage the file into the partial-dir and then rename it into place. */
-void finish_transfer(const char *fname, const char *fnametmp,
-                    const char *fnamecmp, const char *partialptr,
-                    struct file_struct *file, int ok_to_set_time,
-                    int overwriting_basis)
+ * attributes (e.g. permissions, ownership, etc.).  If the robust_rename()
+ * call is forced to copy the temp file and partialptr is both non-NULL and
+ * not an absolute path, we stage the file into the partial-dir and then
+ * rename it into place.  This returns 1 on succcess or 0 on failure. */
+int finish_transfer(const char *fname, const char *fnametmp,
+                   const char *fnamecmp, const char *partialptr,
+                   struct file_struct *file, int ok_to_set_time,
+                   int overwriting_basis)
 {
        int ret;
+       const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL;
 
        if (inplace) {
                if (verbose > 2)
@@ -522,7 +524,7 @@ void finish_transfer(const char *fname, const char *fnametmp,
        }
 
        if (make_backups > 0 && overwriting_basis && !make_backup(fname))
-               return;
+               return 1;
 
        /* Change permissions before putting the file into place. */
        set_file_attrs(fnametmp, file, NULL, fnamecmp,
@@ -531,34 +533,39 @@ void finish_transfer(const char *fname, const char *fnametmp,
        /* move tmp file over real file */
        if (verbose > 2)
                rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
-       ret = robust_rename(fnametmp, fname, partialptr,
+       ret = robust_rename(fnametmp, fname, temp_copy_name,
                            file->mode & INITACCESSPERMS);
        if (ret < 0) {
                rsyserr(FERROR_XFER, errno, "%s %s -> \"%s\"",
                        ret == -2 ? "copy" : "rename",
                        full_fname(fnametmp), fname);
-               do_unlink(fnametmp);
-               return;
+               if (!partialptr || (ret == -2 && temp_copy_name)
+                || robust_rename(fnametmp, partialptr, NULL,
+                                 file->mode & INITACCESSPERMS) < 0)
+                       do_unlink(fnametmp);
+               return 0;
        }
        if (ret == 0) {
                /* The file was moved into place (not copied), so it's done. */
-               return;
+               return 1;
        }
        /* The file was copied, so tweak the perms of the copied file.  If it
         * was copied to partialptr, move it into its final destination. */
-       fnametmp = partialptr ? partialptr : fname;
+       fnametmp = temp_copy_name ? temp_copy_name : fname;
 
   do_set_file_attrs:
        set_file_attrs(fnametmp, file, NULL, fnamecmp,
                       ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
 
-       if (partialptr) {
+       if (temp_copy_name) {
                if (do_rename(fnametmp, fname) < 0) {
                        rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\"",
                                full_fname(fnametmp), fname);
-               } else
-                       handle_partial_dir(partialptr, PDIR_DELETE);
+                       return 0;
+               }
+               handle_partial_dir(temp_copy_name, PDIR_DELETE);
        }
+       return 1;
 }
 
 struct file_list *flist_for_ndx(int ndx)