c557f954c54c72176d76c2a4566dcaa964a1c8de
[rsync-patches.git] / source-backup.diff
1 This patch adds a --source-backup option that backs up source files
2 removed due to --remove-source-files.
3
4 To use this patch, run these commands for a successful build:
5
6     patch -p1 <patches/source-backup.diff
7     ./configure                         (optional if already run)
8     make
9
10 -- Matt McCutchen <hashproduct@gmail.com>
11
12 based-on: 9a06b2edb0ea1a226bcc642682c07bacd2ea47d3
13 diff --git a/options.c b/options.c
14 --- a/options.c
15 +++ b/options.c
16 @@ -34,6 +34,7 @@ extern filter_rule_list filter_list;
17  extern filter_rule_list daemon_filter_list;
18  
19  int make_backups = 0;
20 +int make_source_backups = 0;
21  
22  /**
23   * If 1, send the whole file as literal data rather than trying to
24 @@ -777,6 +778,7 @@ static struct poptOption long_options[] = {
25    {"bwlimit",          0,  POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 },
26    {"no-bwlimit",       0,  POPT_ARG_VAL,    &bwlimit, 0, 0, 0 },
27    {"backup",          'b', POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
28 +  {"source-backup",    0,  POPT_ARG_NONE,   &make_source_backups, 0, 0, 0},
29    {"no-backup",        0,  POPT_ARG_VAL,    &make_backups, 0, 0, 0 },
30    {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
31    {"suffix",           0,  POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
32 @@ -2838,6 +2840,8 @@ void server_options(char **args, int *argc_p)
33         } else {
34                 if (skip_compress)
35                         args[ac++] = safe_arg("--skip-compress", skip_compress);
36 +               if (make_source_backups)
37 +                       args[ac++] = "--source-backup";
38         }
39  
40         if (max_alloc_arg && max_alloc != DEFAULT_MAX_ALLOC)
41 diff --git a/rsync.1.md b/rsync.1.md
42 --- a/rsync.1.md
43 +++ b/rsync.1.md
44 @@ -477,6 +477,7 @@ has its own detailed description later in this manpage.
45  --existing               skip creating new files on receiver
46  --ignore-existing        skip updating files that exist on receiver
47  --remove-source-files    sender removes synchronized files (non-dir)
48 +--source-backup          ... and backs up those files
49  --del                    an alias for --delete-during
50  --delete                 delete extraneous files from dest dirs
51  --delete-before          receiver deletes before xfer, not during
52 @@ -1893,6 +1894,17 @@ expand it.
53      not remove a file the receiver just verified, such as when the user
54      accidentally makes the source and destination directory the same path.
55  
56 +0.  `--source-backup`
57 +
58 +    Makes the sender back up the source files it removes due to
59 +    [`--remove-source-files`](#opt).  This option is independent of
60 +    [`--backup`](#opt) but uses the same [`--backup-dir`](#opt) and
61 +    [`--suffix`](#opt) settings, if any.  With [`--backup-dir`](#opt), rsync
62 +    looks for each file's backup dir relative to the source argument the file
63 +    came from.  Consequently, if the [`--backup-dir`](#opt) path is relative,
64 +    each source argument gets a separate backup dir at that path relative to
65 +    the argument.
66 +
67  0.  `--delete`
68  
69      This tells rsync to delete extraneous files from the receiving side (ones
70 diff --git a/sender.c b/sender.c
71 --- a/sender.c
72 +++ b/sender.c
73 @@ -44,6 +44,7 @@ extern int protocol_version;
74  extern int remove_source_files;
75  extern int updating_basis_file;
76  extern int make_backups;
77 +extern int make_source_backups;
78  extern int inplace;
79  extern int inplace_partial;
80  extern int batch_fd;
81 @@ -131,6 +132,7 @@ void successful_send(int ndx)
82         struct file_struct *file;
83         struct file_list *flist;
84         STRUCT_STAT st;
85 +       int result;
86  
87         if (!remove_source_files)
88                 return;
89 @@ -162,7 +164,11 @@ void successful_send(int ndx)
90                 return;
91         }
92  
93 -       if (do_unlink(fname) < 0) {
94 +       if (make_source_backups)
95 +               result = !make_backup(fname, True);
96 +       else
97 +               result = do_unlink(fname);
98 +       if (result < 0) {
99                 failed_op = "remove";
100           failed:
101                 if (errno == ENOENT)