On Thu, Sep 15, 2005 at 08:49:33AM -0700, Wayne Davison wrote:
> (At least, that's all the side-effects I can think of off the top of
> my head.)

At least one more was that backing up a directory without a --backup-dir
still requires using rename().

Attached is a patch that I think effects the change of using link()
instead of rename() when possible.  It is very minimally tested -- i.e.
it passes "make test".  If you choose to try it out, run "make proto"
after applying the patch.

..wayne..
--- backup.c    10 Jun 2005 17:57:18 -0000      1.45
+++ backup.c    15 Sep 2005 16:55:56 -0000
@@ -52,43 +52,6 @@ char *get_backup_name(char *fname)
        return NULL;
 }
 
-/* simple backup creates a backup with a suffix in the same directory */
-static int make_simple_backup(char *fname)
-{
-       int rename_errno;
-       char *fnamebak = get_backup_name(fname);
-
-       if (!fnamebak)
-               return 0;
-
-       while (1) {
-               if (do_rename(fname, fnamebak) == 0) {
-                       if (verbose > 1) {
-                               rprintf(FINFO, "backed up %s to %s\n",
-                                       safe_fname(fname),
-                                       safe_fname(fnamebak));
-                       }
-                       break;
-               }
-               /* cygwin (at least version b19) reports EINVAL */
-               if (errno == ENOENT || errno == EINVAL)
-                       break;
-
-               rename_errno = errno;
-               if (errno == EISDIR && do_rmdir(fnamebak) == 0)
-                       continue;
-               if (errno == ENOTDIR && do_unlink(fnamebak) == 0)
-                       continue;
-
-               rsyserr(FERROR, rename_errno, "rename %s to backup %s",
-                       safe_fname(fname), safe_fname(fnamebak));
-               errno = rename_errno;
-               return 0;
-       }
-
-       return 1;
-}
-
 
 /****************************************************************************
 Create a directory given an absolute path, perms based upon another directory
@@ -157,19 +120,75 @@ failure:
        return -1;
 }
 
-/* robustly move a file, creating new directory structures if necessary */
-static int robust_move(char *src, char *dst)
+static int do_backup(char *src, char *dst, int use_rename,
+                    int make_missing_dirs, int nlinks)
 {
-       if (robust_rename(src, dst, 0755) < 0 && (errno != ENOENT
-           || make_bak_dir(dst) < 0 || robust_rename(src, dst, 0755) < 0))
+       int backup_errno;
+
+#ifndef SUPPORT_LINKS
+       use_rename = 1;
+#endif
+
+       while (1) {
+               /* CAUTION: the calling logic must take this into account! */
+               if (use_rename) {
+                       if (do_rename(src, dst) == 0) {
+                               if (nlinks > 1) {
+                                       /* If file is hard-linked into backup 
dir,
+                                        * rename() might succeed but do 
nothing! */
+                                       robust_unlink(src); /* Just in case... 
*/
+                               }
+                               break;
+                       }
+               } else {
+#ifdef SUPPORT_LINKS
+                       robust_unlink(dst);
+                       if (do_link(src, dst) == 0)
+                               break;
+#endif
+               }
+
+               backup_errno = errno;
+
+               if (make_missing_dirs && backup_errno == ENOENT
+                && make_bak_dir(dst) == 0)
+                       continue;
+
+               /* cygwin (at least version b19) reports EINVAL */
+               if (backup_errno == ENOENT || backup_errno == EINVAL)
+                       break;
+
+               if (backup_errno == EISDIR && do_rmdir(src) == 0)
+                       continue;
+               if (backup_errno == ENOTDIR && do_unlink(src) == 0)
+                       continue;
+
+               rsyserr(FERROR, backup_errno, "backup of %s to %s",
+                       safe_fname(src), safe_fname(dst));
+               errno = backup_errno;
                return -1;
+       }
+
+       if (verbose > 1) {
+               rprintf(FINFO, "backed up %s to %s\n",
+                       safe_fname(src), safe_fname(dst));
+       }
        return 0;
 }
 
+/* simple backup creates a backup with a suffix in the same directory */
+static int make_simple_backup(char *fname, int use_rename)
+{
+       char *fnamebak = get_backup_name(fname);
+
+       if (fnamebak && do_backup(fname, fnamebak, use_rename, 0, 0) == 0)
+               return 1;
+       return 0;
+}
 
 /* If we have a --backup-dir, then we get here from make_backup().
- * We will move the file to be deleted into a parallel directory tree. */
-static int keep_backup(char *fname)
+ * We will move/link the file into a parallel directory tree. */
+static int keep_backup(char *fname, int use_rename)
 {
        STRUCT_STAT st;
        struct file_struct *file;
@@ -199,8 +218,9 @@ static int keep_backup(char *fname)
                        rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
                                safe_fname(fname));
                }
+               if (use_rename)
+                       do_unlink(fname);
                kept = 1;
-               do_unlink(fname);
        }
 
        if (!kept && S_ISDIR(file->mode)) {
@@ -212,6 +232,7 @@ static int keep_backup(char *fname)
                                full_fname(buf));
                }
 
+               /* Note: use_rename must be non-zero when hadling a dir. */
                ret_code = do_rmdir(fname);
                if (verbose > 2) {
                        rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
@@ -237,7 +258,8 @@ static int keep_backup(char *fname)
                                        full_fname(buf),
                                        safe_fname(file->u.link));
                        }
-                       do_unlink(fname);
+                       if (use_rename)
+                               do_unlink(fname);
                        kept = 1;
                }
        }
@@ -249,32 +271,20 @@ static int keep_backup(char *fname)
                return 1;
        }
 
-       /* move to keep tree if a file */
-       if (!kept) {
-               if (robust_move(fname, buf) != 0) {
-                       rsyserr(FERROR, errno, "keep_backup failed: %s -> 
\"%s\"",
-                               full_fname(fname), safe_fname(buf));
-               } else if (st.st_nlink > 1) {
-                       /* If someone has hard-linked the file into the backup
-                        * dir, rename() might return success but do nothing! */
-                       robust_unlink(fname); /* Just in case... */
-               }
-       }
+       /* If a normal file, make a backup. */
+       if (!kept)
+               do_backup(fname, buf, use_rename, 1, st.st_nlink);
        set_perms(buf, file, NULL, 0);
        free(file);
 
-       if (verbose > 1) {
-               rprintf(FINFO, "backed up %s to %s\n",
-                       safe_fname(fname), safe_fname(buf));
-       }
        return 1;
 }
 
 
 /* main backup switch routine */
-int make_backup(char *fname)
+int make_backup(char *fname, int use_rename)
 {
        if (backup_dir)
-               return keep_backup(fname);
-       return make_simple_backup(fname);
+               return keep_backup(fname, use_rename);
+       return make_simple_backup(fname, use_rename);
 }
--- generator.c 6 Sep 2005 18:12:38 -0000       1.222
+++ generator.c 15 Sep 2005 16:55:57 -0000
@@ -114,7 +114,7 @@ static int delete_item(char *fname, int 
                if (max_delete && ++deletion_count > max_delete)
                        return 0;
                if (make_backups && (backup_dir || !is_backup_file(fname)))
-                       ok = make_backup(fname);
+                       ok = make_backup(fname, 1);
                else
                        ok = robust_unlink(fname) == 0;
                if (ok) {
@@ -139,7 +139,7 @@ static int delete_item(char *fname, int 
                errno = ENOTEMPTY;
        } else if (make_backups && !backup_dir && !is_backup_file(fname)
            && !(flags & DEL_FORCE_RECURSE))
-               ok = make_backup(fname);
+               ok = make_backup(fname, 1);
        else
                ok = do_rmdir(fname) == 0;
        if (ok) {
--- hlink.c     31 Jul 2005 23:19:42 -0000      1.54
+++ hlink.c     15 Sep 2005 16:55:57 -0000
@@ -154,7 +154,7 @@ static int maybe_hard_link(struct file_s
                        return 0;
                }
                if (make_backups) {
-                       if (!make_backup(fname))
+                       if (!make_backup(fname, 1))
                                return -1;
                } else if (robust_unlink(fname)) {
                        rsyserr(FERROR, errno, "unlink %s failed",
--- receiver.c  30 Aug 2005 02:58:42 -0000      1.164
+++ receiver.c  15 Sep 2005 16:55:57 -0000
@@ -347,7 +347,7 @@ static void handle_delayed_updates(struc
                struct file_struct *file = flist->files[i];
                fname = local_name ? local_name : f_name(file);
                if ((partialptr = partial_dir_fname(fname)) != NULL) {
-                       if (make_backups && !make_backup(fname))
+                       if (make_backups && !make_backup(fname, 0))
                                continue;
                        if (verbose > 2) {
                                rprintf(FINFO, "renaming %s to %s\n",
--- rsync.c     27 Jul 2005 23:30:58 -0000      1.168
+++ rsync.c     15 Sep 2005 16:55:57 -0000
@@ -179,7 +179,7 @@ void finish_transfer(char *fname, char *
                goto do_set_perms;
        }
 
-       if (make_backups && overwriting_basis && !make_backup(fname))
+       if (make_backups && overwriting_basis && !make_backup(fname, 0))
                return;
 
        /* Change permissions before putting the file into place. */
--- t_stub.c    25 Jan 2005 10:39:14 -0000      1.10
+++ t_stub.c    15 Sep 2005 16:55:57 -0000
@@ -28,6 +28,7 @@
 
 int modify_window = 0;
 int module_id = -1;
+int make_backups = 0;
 char *partial_dir;
 struct filter_list_struct server_filter_list;
 
--- util.c      3 Aug 2005 04:51:29 -0000       1.186
+++ util.c      15 Sep 2005 17:05:33 -0000
@@ -31,6 +31,7 @@ extern int verbose;
 extern int dry_run;
 extern int module_id;
 extern int modify_window;
+extern int make_backups;
 extern char *partial_dir;
 extern struct filter_list_struct server_filter_list;
 
@@ -392,6 +393,12 @@ int robust_rename(char *from, char *to, 
                        break;
 #endif
                case EXDEV:
+#ifdef SUPPORT_LINKS
+                       if (make_backups && robust_unlink(to) != 0
+                        && errno != ENOENT)
+                               return -1;
+#endif
+
                        if (copy_file(from, to, mode) != 0)
                                return -2;
                        do_unlink(from);
-- 
To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html

Reply via email to