This patch adds a --source-backup option that backs up source files
removed due to --remove-source-files.

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

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

-- Matt McCutchen <hashproduct@gmail.com>

based-on: 0ac7ebceef70417355f25daf9e2fd94e84c49749
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
@@ -32,6 +32,7 @@ extern filter_rule_list filter_list;
 extern filter_rule_list daemon_filter_list;
 
 int make_backups = 0;
+int make_source_backups = 0;
 
 /**
  * If 1, send the whole file as literal data rather than trying to
@@ -773,6 +774,7 @@ static struct poptOption long_options[] = {
   {"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 },
+  {"source-backup",    0,  POPT_ARG_NONE,   &make_source_backups, 0, 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 },
@@ -2795,6 +2797,8 @@ void server_options(char **args, int *argc_p)
 	} else {
 		if (skip_compress)
 			args[ac++] = safe_arg("--skip-compress", skip_compress);
+		if (make_source_backups)
+			args[ac++] = "--source-backup";
 	}
 
 	if (max_alloc_arg && max_alloc != DEFAULT_MAX_ALLOC)
diff --git a/rsync.1.md b/rsync.1.md
--- a/rsync.1.md
+++ b/rsync.1.md
@@ -397,6 +397,7 @@ has its own detailed description later in this manpage.
 --existing               skip creating new files on receiver
 --ignore-existing        skip updating files that exist on receiver
 --remove-source-files    sender removes synchronized files (non-dir)
+--source-backup          ... and backs up those files
 --del                    an alias for --delete-during
 --delete                 delete extraneous files from dest dirs
 --delete-before          receiver deletes before xfer, not during
@@ -1783,6 +1784,17 @@ your home directory (remove the '=' for that).
     Starting with 3.1.0, rsync will skip the sender-side removal (and output an
     error) if the file's size or modify time has not stayed unchanged.
 
+0.  `--source-backup`
+
+    Makes the sender back up the source files it removes due to
+    [`--remove-source-files`](#opt).  This option is independent of
+    [`--backup`](#opt) but uses the same [`--backup-dir`](#opt) and
+    [`--suffix`](#opt) settings, if any.  With [`--backup-dir`](#opt), rsync
+    looks for each file's backup dir relative to the source argument the file
+    came from.  Consequently, if the [`--backup-dir`](#opt) path is relative,
+    each source argument gets a separate backup dir at that path relative to
+    the argument.
+
 0.  `--delete`
 
     This tells rsync to delete extraneous files from the receiving side (ones
diff --git a/sender.c b/sender.c
--- a/sender.c
+++ b/sender.c
@@ -43,6 +43,7 @@ extern int protocol_version;
 extern int remove_source_files;
 extern int updating_basis_file;
 extern int make_backups;
+extern int make_source_backups;
 extern int inplace;
 extern int inplace_partial;
 extern int batch_fd;
@@ -129,6 +130,7 @@ void successful_send(int ndx)
 	struct file_struct *file;
 	struct file_list *flist;
 	STRUCT_STAT st;
+	int result;
 
 	if (!remove_source_files)
 		return;
@@ -153,7 +155,11 @@ void successful_send(int ndx)
 		return;
 	}
 
-	if (do_unlink(fname) < 0) {
+	if (make_source_backups)
+		result = !make_backup(fname, True);
+	else
+		result = do_unlink(fname);
+	if (result < 0) {
 		failed_op = "remove";
 	  failed:
 		if (errno == ENOENT)
diff -Nurp a/rsync.1 b/rsync.1
--- a/rsync.1
+++ b/rsync.1
@@ -474,6 +474,7 @@ has its own detailed description later i
 --existing               skip creating new files on receiver
 --ignore-existing        skip updating files that exist on receiver
 --remove-source-files    sender removes synchronized files (non-dir)
+--source-backup          ... and backs up those files
 --del                    an alias for --delete-during
 --delete                 delete extraneous files from dest dirs
 --delete-before          receiver deletes before xfer, not during
@@ -1846,6 +1847,15 @@ for the rsync transfer).
 .IP
 Starting with 3.1.0, rsync will skip the sender-side removal (and output an
 error) if the file's size or modify time has not stayed unchanged.
+.IP "\fB\-\-source-backup\fP"
+Makes the sender back up the source files it removes due to
+\fB\-\-remove-source-files\fP.  This option is independent of
+\fB\-\-backup\fP but uses the same \fB\-\-backup-dir\fP and
+\fB\-\-suffix\fP settings, if any.  With \fB\-\-backup-dir\fP, rsync
+looks for each file's backup dir relative to the source argument the file
+came from.  Consequently, if the \fB\-\-backup-dir\fP path is relative,
+each source argument gets a separate backup dir at that path relative to
+the argument.
 .IP "\fB\-\-delete\fP"
 This tells rsync to delete extraneous files from the receiving side (ones
 that aren't on the sending side), but only for the directories that are
diff -Nurp a/rsync.1.html b/rsync.1.html
--- a/rsync.1.html
+++ b/rsync.1.html
@@ -392,6 +392,7 @@ has its own detailed description later i
 --existing               skip creating new files on receiver
 --ignore-existing        skip updating files that exist on receiver
 --remove-source-files    sender removes synchronized files (non-dir)
+--source-backup          ... and backs up those files
 --del                    an alias for --delete-during
 --delete                 delete extraneous files from dest dirs
 --delete-before          receiver deletes before xfer, not during
@@ -1692,6 +1693,17 @@ for the rsync transfer).</p>
 error) if the file's size or modify time has not stayed unchanged.</p>
 </dd>
 
+<dt id="opt--source-backup"><code>--source-backup</code><a href="#opt--source-backup" class="tgt"></a></dt><dd>
+<p>Makes the sender back up the source files it removes due to
+<a href="#opt--remove-source-files"><code>--remove-source-files</code></a>.  This option is independent of
+<a href="#opt--backup"><code>--backup</code></a> but uses the same <a href="#opt--backup-dir"><code>--backup-dir</code></a> and
+<a href="#opt--suffix"><code>--suffix</code></a> settings, if any.  With <a href="#opt--backup-dir"><code>--backup-dir</code></a>, rsync
+looks for each file's backup dir relative to the source argument the file
+came from.  Consequently, if the <a href="#opt--backup-dir"><code>--backup-dir</code></a> path is relative,
+each source argument gets a separate backup dir at that path relative to
+the argument.</p>
+</dd>
+
 <dt id="opt--delete"><code>--delete</code><a href="#opt--delete" class="tgt"></a></dt><dd>
 <p>This tells rsync to delete extraneous files from the receiving side (ones
 that aren't on the sending side), but only for the directories that are
