--backup leaves window where file doesn't exist.
Wayne Davison
wayned at samba.org
Thu Sep 15 17:15:51 GMT 2005
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..
-------------- next part --------------
--- 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);
More information about the rsync
mailing list