Blob Blame History Raw
This patches adds the --backup-deleted option, as proposed by Jonathan
Kames in bug 7889.

To use this patch, run these commands for a successful build:

    patch -p1 <patches/backup-deleted.diff
    ./configure                                 (optional if already run)
    make

based-on: d73762eea3f15f2c56bb3fa9394ad1883c25c949
diff --git a/generator.c b/generator.c
--- a/generator.c
+++ b/generator.c
@@ -1800,7 +1800,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 		goto notify_others;
 
 	if (read_batch || whole_file) {
-		if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
+		if (inplace && make_backups > 1 && fnamecmp_type == FNAMECMP_FNAME) {
 			if (!(backupptr = get_backup_name(fname)))
 				goto cleanup;
 			if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
@@ -1836,7 +1836,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 		goto notify_others;
 	}
 
-	if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
+	if (inplace && make_backups > 1 && fnamecmp_type == FNAMECMP_FNAME) {
 		if (!(backupptr = get_backup_name(fname))) {
 			close(fd);
 			goto cleanup;
@@ -1960,7 +1960,7 @@ int atomic_create(struct file_struct *file, char *fname, const char *slnk, const
 		skip_atomic = 0;
 
 	if (del_for_flag) {
-		if (make_backups > 0 && !dir_in_the_way) {
+		if (make_backups > 1 && !dir_in_the_way) {
 			if (!make_backup(fname, skip_atomic))
 				return 0;
 		} else if (skip_atomic) {
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
@@ -678,6 +678,7 @@ void usage(enum logcode F)
   rprintf(F," -R, --relative              use relative path names\n");
   rprintf(F,"     --no-implied-dirs       don't send implied dirs with --relative\n");
   rprintf(F," -b, --backup                make backups (see --suffix & --backup-dir)\n");
+  rprintf(F,"     --backup-deleted        make backups only of deleted files\n");
   rprintf(F,"     --backup-dir=DIR        make backups into hierarchy based in DIR\n");
   rprintf(F,"     --suffix=SUFFIX         set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
   rprintf(F," -u, --update                skip files that are newer on the receiver\n");
@@ -994,7 +995,8 @@ static struct poptOption long_options[] = {
   {"no-i",             0,  POPT_ARG_VAL,    &itemize_changes, 0, 0, 0 },
   {"bwlimit",          0,  POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 },
   {"no-bwlimit",       0,  POPT_ARG_VAL,    &bwlimit, 0, 0, 0 },
-  {"backup",          'b', POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
+  {"backup",          'b', POPT_ARG_VAL,    &make_backups, 2, 0, 0 },
+  {"backup-deleted",   0,  POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
   {"no-backup",        0,  POPT_ARG_VAL,    &make_backups, 0, 0, 0 },
   {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
   {"suffix",           0,  POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
@@ -2632,6 +2634,10 @@ void server_options(char **args, int *argc_p)
 	}
 
 	if (am_sender) {
+		/* A remote sender just needs the above -b option.
+		 * A remote receiver will override that with this option. */
+		if (make_backups == 1)
+			args[ac++] = "--backup-deleted";
 		if (max_delete > 0) {
 			if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
 				goto oom;
diff --git a/receiver.c b/receiver.c
--- a/receiver.c
+++ b/receiver.c
@@ -416,7 +416,7 @@ static void handle_delayed_updates(char *local_name)
 		struct file_struct *file = cur_flist->files[ndx];
 		fname = local_name ? local_name : f_name(file, NULL);
 		if ((partialptr = partial_dir_fname(fname)) != NULL) {
-			if (make_backups > 0 && !make_backup(fname, False))
+			if (make_backups > 1 && !make_backup(fname, False))
 				continue;
 			if (DEBUG_GTE(RECV, 1)) {
 				rprintf(FINFO, "renaming %s to %s\n",
@@ -729,7 +729,7 @@ int recv_files(int f_in, int f_out, char *local_name)
 		} else {
 			/* Reminder: --inplace && --partial-dir are never
 			 * enabled at the same time. */
-			if (inplace && make_backups > 0) {
+			if (inplace && make_backups > 1) {
 				if (!(fnamecmp = get_backup_name(fname)))
 					fnamecmp = fname;
 				else
diff --git a/rsync.c b/rsync.c
--- a/rsync.c
+++ b/rsync.c
@@ -662,7 +662,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
 		goto do_set_file_attrs;
 	}
 
-	if (make_backups > 0 && overwriting_basis) {
+	if (make_backups > 1 && overwriting_basis) {
 		int ok = make_backup(fname, False);
 		if (!ok)
 			exit_cleanup(RERR_FILEIO);
diff --git a/rsync.yo b/rsync.yo
--- a/rsync.yo
+++ b/rsync.yo
@@ -346,6 +346,7 @@ to the detailed description below for a complete description.  verb(
  -R, --relative              use relative path names
      --no-implied-dirs       don't send implied dirs with --relative
  -b, --backup                make backups (see --suffix & --backup-dir)
+     --backup-deleted        make backups only of deleted files
      --backup-dir=DIR        make backups into hierarchy based in DIR
      --suffix=SUFFIX         backup suffix (default ~ w/o --backup-dir)
  -u, --update                skip files that are newer on the receiver
@@ -792,6 +793,11 @@ in the list so that it has a high enough priority to be effective (e.g., if
 your rules specify a trailing inclusion/exclusion of '*', the auto-added
 rule would never be reached).
 
+dit(bf(--backup-deleted)) With this option, deleted destination files are
+renamed, while modified destination files are not. Otherwise, this option
+behaves the same as bf(--backup), described above.  Note that if bf(--backup)
+is also specified, whichever option is specified last takes precedence.
+
 dit(bf(--backup-dir=DIR)) In combination with the bf(--backup) option, this
 tells rsync to store all backups in the specified directory on the receiving
 side.  This can be used for incremental backups.  You can additionally
diff -Nurp a/rsync.1 b/rsync.1
--- a/rsync.1
+++ b/rsync.1
@@ -422,6 +422,7 @@ to the detailed description below for a
  \-R, \-\-relative              use relative path names
      \-\-no\-implied\-dirs       don'\&t send implied dirs with \-\-relative
  \-b, \-\-backup                make backups (see \-\-suffix & \-\-backup\-dir)
+     \-\-backup\-deleted        make backups only of deleted files
      \-\-backup\-dir=DIR        make backups into hierarchy based in DIR
      \-\-suffix=SUFFIX         backup suffix (default ~ w/o \-\-backup\-dir)
  \-u, \-\-update                skip files that are newer on the receiver
@@ -914,6 +915,12 @@ in the list so that it has a high enough
 your rules specify a trailing inclusion/exclusion of \(cq\&*\(cq\&, the auto\-added
 rule would never be reached).
 .IP 
+.IP "\fB\-\-backup\-deleted\fP"
+With this option, deleted destination files are
+renamed, while modified destination files are not. Otherwise, this option
+behaves the same as \fB\-\-backup\fP, described above.  Note that if \fB\-\-backup\fP
+is also specified, whichever option is specified last takes precedence.
+.IP 
 .IP "\fB\-\-backup\-dir=DIR\fP"
 In combination with the \fB\-\-backup\fP option, this
 tells rsync to store all backups in the specified directory on the receiving