Moved the EXDEV handling into robust_rename().
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index fd01283..cb47c2a 100644 (file)
--- a/util.c
+++ b/util.c
@@ -353,18 +353,33 @@ int robust_unlink(char *fname)
 #endif
 }
 
-int robust_rename(char *from, char *to)
+/* Returns 0 on success, -1 on most errors, and -2 if we got an error
+ * trying to copy the file across file systems. */
+int robust_rename(char *from, char *to, int mode)
 {
-#ifndef ETXTBSY
-       return do_rename(from, to);
-#else
-       int rc = do_rename(from, to);
-       if (rc == 0 || errno != ETXTBSY)
-               return rc;
-       if (robust_unlink(to) != 0)
-               return -1;
-       return do_rename(from, to);
+       int tries = 4;
+
+       while (tries--) {
+               if (do_rename(from, to) == 0)
+                       return 0;
+
+               switch (errno) {
+#ifdef ETXTBSY
+               case ETXTBSY:
+                       if (robust_unlink(to) != 0)
+                               return -1;
+                       break;
 #endif
+               case EXDEV:
+                       if (copy_file(from, to, mode) != 0)
+                               return -2;
+                       do_unlink(from);
+                       return 0;
+               default:
+                       return -1;
+               }
+       }
+       return -1;
 }