The patches for 3.0.0pre10.
[rsync/rsync-patches.git] / backup-dir-dels.diff
CommitLineData
8af83008 1This patches creates two new command line options as follows:
19a778eb
WD
2 --backup-dir-dels=DIR
3 --suffix-dels=SUFFIX
8af83008 4
19a778eb 5The backup-dir-dels and suffix-dels options give the ability to store
79f132a1
WD
6backup of removed files on the receiver in different directories or with
7different suffix than the backup of files that have been changed but that
8are still on the source drive. Both commands can be combined.
8af83008
WD
9
10The default behaviour if one or both of the options are not specified
11is the previous behaviour, both backups use the same directory or
12suffix.
13
14Marc St-Onge
15
03019e41
WD
16To use this patch, run these commands for a successful build:
17
18 patch -p1 <patches/backup-dir-dels.diff
19 ./configure (optional if already run)
20 make
21
cc3e685d
WD
22diff --git a/backup.c b/backup.c
23--- a/backup.c
24+++ b/backup.c
a54a2c4d 25@@ -29,10 +29,17 @@ extern int preserve_specials;
fc068916
WD
26 extern int preserve_links;
27 extern int safe_symlinks;
8af83008 28 extern int backup_dir_len;
19a778eb 29+extern int backup_dir_dels_len;
8af83008 30 extern unsigned int backup_dir_remainder;
19a778eb 31+extern unsigned int backup_dir_dels_remainder;
8af83008 32 extern char backup_dir_buf[MAXPATHLEN];
19a778eb 33+extern char backup_dir_dels_buf[MAXPATHLEN];
8af83008 34 extern char *backup_suffix;
19a778eb 35+extern char *backup_suffix_dels;
8af83008 36 extern char *backup_dir;
19a778eb 37+extern char *backup_dir_dels;
8af83008 38+
70891d26
WD
39+static int deleting;
40
8af83008 41 /* make a complete pathname for backup file */
5e3c6c93 42 char *get_backup_name(const char *fname)
a54a2c4d 43@@ -51,11 +58,28 @@ char *get_backup_name(const char *fname)
8af83008
WD
44 return NULL;
45 }
46
5e3c6c93 47+static char *get_delete_name(const char *fname)
8af83008 48+{
19a778eb
WD
49+ if (backup_dir_dels) {
50+ if (stringjoin(backup_dir_dels_buf + backup_dir_dels_len, backup_dir_dels_remainder,
51+ fname, backup_suffix_dels, NULL) < backup_dir_dels_remainder)
52+ return backup_dir_dels_buf;
8af83008 53+ } else {
19a778eb
WD
54+ if (stringjoin(backup_dir_dels_buf, MAXPATHLEN,
55+ fname, backup_suffix_dels, NULL) < MAXPATHLEN)
56+ return backup_dir_dels_buf;
8af83008
WD
57+ }
58+
59+ rprintf(FERROR, "delete filename too long\n");
60+ return NULL;
61+}
62+
63 /* simple backup creates a backup with a suffix in the same directory */
5e3c6c93 64 static int make_simple_backup(const char *fname)
8af83008 65 {
4877ebcc 66 int rename_errno;
5e3c6c93
WD
67- const char *fnamebak = get_backup_name(fname);
68+ const char *fnamebak = deleting ? get_delete_name(fname)
69+ : get_backup_name(fname);
8af83008
WD
70
71 if (!fnamebak)
72 return 0;
cdcd2137 73@@ -96,7 +120,7 @@ int make_bak_dir(const char *fullpath)
8af83008 74 {
cdcd2137 75 char fbuf[MAXPATHLEN], *rel, *end, *p;
ffc18846 76 struct file_struct *file;
cdcd2137
WD
77- int len = backup_dir_len;
78+ int len = deleting ? backup_dir_dels_len : backup_dir_len;
52e09c4e 79 stat_x sx;
8af83008 80
cdcd2137 81 while (*fullpath == '.' && fullpath[1] == '/') {
cc3e685d 82@@ -211,7 +235,8 @@ static int keep_backup(const char *fname)
e0e47893 83 if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
8af83008
WD
84 return 1; /* the file could have disappeared */
85
70891d26 86- if (!(buf = get_backup_name(fname))) {
8af83008 87+ buf = deleting ? get_delete_name(fname) : get_backup_name(fname);
70891d26
WD
88+ if (!buf) {
89 unmake_file(file);
8af83008 90 return 0;
70891d26 91 }
cdcd2137 92@@ -326,3 +351,13 @@ int make_backup(const char *fname)
44917741
WD
93 return keep_backup(fname);
94 return make_simple_backup(fname);
95 }
8af83008 96+
79f132a1 97+/* backup switch routine called only when backing-up removed file */
8af83008
WD
98+int safe_delete(char *fname)
99+{
44917741 100+ int ret;
8af83008 101+ deleting = 1;
44917741
WD
102+ ret = make_backup(fname);
103+ deleting = 0;
104+ return ret;
105+}
cc3e685d
WD
106diff --git a/generator.c b/generator.c
107--- a/generator.c
108+++ b/generator.c
85096e5e 109@@ -97,6 +97,9 @@ extern uid_t our_uid;
52f25864
WD
110 extern char *backup_dir;
111 extern char *backup_suffix;
112 extern int backup_suffix_len;
19a778eb
WD
113+extern char *backup_dir_dels;
114+extern char *backup_suffix_dels;
115+extern int backup_suffix_dels_len;
fc068916 116 extern struct file_list *cur_flist, *first_flist, *dir_flist;
e20f0bda 117 extern struct filter_list_struct server_filter_list;
cc3e685d 118
85096e5e 119@@ -138,10 +141,15 @@ enum delret {
a5e6228a 120 /* Forward declaration for delete_item(). */
87d0091c 121 static enum delret delete_dir_contents(char *fname, int flags);
52f25864 122
a5e6228a 123+
d608ca23 124+/* Function now compares both backup_suffix and backup_suffix_dels. */
52f25864
WD
125 static int is_backup_file(char *fn)
126 {
127 int k = strlen(fn) - backup_suffix_len;
128- return k > 0 && strcmp(fn+k, backup_suffix) == 0;
129+ if (k > 0 && strcmp(fn+k, backup_suffix) == 0)
130+ return 1;
19a778eb
WD
131+ k += backup_suffix_len - backup_suffix_dels_len;
132+ return k > 0 && strcmp(fn+k, backup_suffix_dels) == 0;
52f25864
WD
133 }
134
87d0091c 135 /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
85096e5e 136@@ -180,9 +188,9 @@ static enum delret delete_item(char *fbuf, int mode, int flags)
87d0091c
WD
137 if (S_ISDIR(mode)) {
138 what = "rmdir";
f813befd 139 ok = do_rmdir(fbuf) == 0;
fc068916
WD
140- } else if (make_backups > 0 && (backup_dir || !is_backup_file(fbuf))) {
141+ } else if (make_backups > 0 && (backup_dir_dels || !is_backup_file(fbuf))) {
87d0091c 142 what = "make_backup";
f813befd
WD
143- ok = make_backup(fbuf);
144+ ok = safe_delete(fbuf);
87d0091c
WD
145 } else {
146 what = "unlink";
f813befd 147 ok = robust_unlink(fbuf) == 0;
cc3e685d
WD
148diff --git a/options.c b/options.c
149--- a/options.c
150+++ b/options.c
f2863bc0 151@@ -149,10 +149,14 @@ int no_detach
8af83008
WD
152 int write_batch = 0;
153 int read_batch = 0;
154 int backup_dir_len = 0;
19a778eb 155+int backup_dir_dels_len = 0;
8af83008 156 int backup_suffix_len;
19a778eb 157+int backup_suffix_dels_len;
8af83008 158 unsigned int backup_dir_remainder;
19a778eb 159+unsigned int backup_dir_dels_remainder;
8af83008
WD
160
161 char *backup_suffix = NULL;
19a778eb 162+char *backup_suffix_dels = NULL;
8af83008
WD
163 char *tmpdir = NULL;
164 char *partial_dir = NULL;
daceaa67 165 char *basis_dir[MAX_BASIS_DIRS+1];
f2863bc0 166@@ -164,7 +168,9 @@ char *stdout_format = NULL;
e0e47893 167 char *password_file = NULL;
8af83008
WD
168 char *rsync_path = RSYNC_PATH;
169 char *backup_dir = NULL;
19a778eb 170+char *backup_dir_dels = NULL;
8af83008 171 char backup_dir_buf[MAXPATHLEN];
19a778eb 172+char backup_dir_dels_buf[MAXPATHLEN];
4a65fe72 173 char *sockopts = NULL;
daceaa67 174 int rsync_port = 0;
c59d6641 175 int compare_dest = 0;
85096e5e 176@@ -324,6 +330,8 @@ void usage(enum logcode F)
8af83008 177 rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n");
79f132a1
WD
178 rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n");
179 rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
19a778eb
WD
180+ rprintf(F," --backup-dir-dels make backups of removed files into current dir\n");
181+ rprintf(F," --suffix-dels=SUFFIX set removed-files suffix (defaults to --suffix)\n");
79f132a1 182 rprintf(F," -u, --update skip files that are newer on the receiver\n");
0b2fb126 183 rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n");
489b0a72 184 rprintf(F," --append append data onto shorter files\n");
85096e5e 185@@ -597,7 +605,9 @@ static struct poptOption long_options[] = {
a54a2c4d
WD
186 {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 },
187 {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 },
8af83008 188 {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
19a778eb 189+ {"backup-dir-dels", 0, POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
489b0a72
WD
190 {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
191+ {"suffix-dels", 0, POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
192 {"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
57e73b72
WD
193 {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
194 {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
85096e5e 195@@ -1427,6 +1437,8 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
cc3e685d 196 tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
60a8bf36 197 if (backup_dir)
cc3e685d 198 backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
60a8bf36 199+ if (backup_dir_dels)
cc3e685d 200+ backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0);
8af83008 201 }
def2ace9
WD
202 if (server_filter_list.head && !am_sender) {
203 struct filter_list_struct *elp = &server_filter_list;
85096e5e 204@@ -1448,6 +1460,14 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
f2863bc0 205 if (check_filter(elp, dir, 1) < 0)
fb11cdd7 206 goto options_rejected;
8af83008 207 }
19a778eb
WD
208+ /* Clean backup_dir_dels same as for backup_dir */
209+ if (backup_dir_dels) {
def2ace9
WD
210+ if (!*backup_dir_dels)
211+ goto options_rejected;
19a778eb
WD
212+ clean_fname(backup_dir_dels, 1);
213+ if (check_filter(elp, backup_dir_dels, 1) < 0)
8af83008
WD
214+ goto options_rejected;
215+ }
216 }
def2ace9
WD
217
218 if (!backup_suffix)
85096e5e 219@@ -1459,6 +1479,15 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
8af83008
WD
220 backup_suffix);
221 return 0;
222 }
19a778eb 223+ if (!backup_suffix_dels)
a5e6228a 224+ backup_suffix_dels = backup_dir_dels && !am_server ? "" : backup_suffix;
19a778eb
WD
225+ backup_suffix_dels_len = strlen(backup_suffix_dels);
226+ if (strchr(backup_suffix_dels, '/') != NULL) {
8af83008 227+ snprintf(err_buf, sizeof err_buf,
19a778eb
WD
228+ "--suffix-dels cannot contain slashes: %s\n",
229+ backup_suffix_dels);
8af83008
WD
230+ return 0;
231+ }
232 if (backup_dir) {
233 backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
234 backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
85096e5e 235@@ -1482,6 +1511,30 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
e0e47893 236 "P *%s", backup_suffix);
c8a8b4a7 237 parse_rule(&filter_list, backup_dir_buf, 0, 0);
8af83008 238 }
a5e6228a 239+ if (backup_dir_dels) {
19a778eb
WD
240+ backup_dir_dels_len = strlcpy(backup_dir_dels_buf, backup_dir_dels, sizeof backup_dir_dels_buf);
241+ backup_dir_dels_remainder = sizeof backup_dir_dels_buf - backup_dir_dels_len;
242+ if (backup_dir_dels_remainder < 32) {
8af83008 243+ snprintf(err_buf, sizeof err_buf,
19a778eb 244+ "the --backup-dir-dels path is WAY too long.\n");
8af83008
WD
245+ return 0;
246+ }
19a778eb
WD
247+ if (backup_dir_dels_buf[backup_dir_dels_len - 1] != '/') {
248+ backup_dir_dels_buf[backup_dir_dels_len++] = '/';
249+ backup_dir_dels_buf[backup_dir_dels_len] = '\0';
8af83008
WD
250+ }
251+ if (verbose > 1 && !am_sender)
19a778eb 252+ rprintf(FINFO, "backup_dir_dels is %s\n", backup_dir_dels_buf);
a5e6228a
WD
253+ } else if (backup_dir) {
254+ backup_dir_dels = backup_dir;
255+ backup_dir_dels_len = backup_dir_len;
256+ backup_dir_dels_remainder = backup_dir_remainder;
257+ strlcpy(backup_dir_dels_buf, backup_dir_buf, sizeof backup_dir_buf);
19a778eb 258+ } else if (!backup_suffix_dels_len && (!am_server || !am_sender)) {
8af83008 259+ snprintf(err_buf, sizeof err_buf,
19a778eb 260+ "--suffix-dels cannot be a null string without --backup-dir-dels\n");
8af83008
WD
261+ return 0;
262+ }
263
a54a2c4d
WD
264 if (make_backups && !backup_dir) {
265 omit_dir_times = 0; /* Implied, so avoid -O to sender. */
85096e5e 266@@ -1875,6 +1928,10 @@ void server_options(char **args, int *argc_p)
8af83008
WD
267 args[ac++] = "--backup-dir";
268 args[ac++] = backup_dir;
269 }
37d900d6 270+ if (backup_dir_dels && backup_dir_dels != backup_dir) {
19a778eb
WD
271+ args[ac++] = "--backup-dir-dels";
272+ args[ac++] = backup_dir_dels;
8af83008
WD
273+ }
274
275 /* Only send --suffix if it specifies a non-default value. */
276 if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
85096e5e 277@@ -1883,7 +1940,14 @@ void server_options(char **args, int *argc_p)
8af83008
WD
278 goto oom;
279 args[ac++] = arg;
280 }
281-
a5e6228a
WD
282+ /* Only send --suffix-dels if it specifies a value different from the
283+ * --suffix value, which would normally be used for deletions too. */
284+ if (strcmp(backup_suffix_dels, backup_suffix) != 0) {
8af83008 285+ /* We use the following syntax to avoid weirdness with '~'. */
19a778eb 286+ if (asprintf(&arg, "--suffix-dels=%s", backup_suffix_dels) < 0)
8af83008
WD
287+ goto oom;
288+ args[ac++] = arg;
289+ }
290 if (am_sender) {
a54a2c4d
WD
291 if (max_delete > 0) {
292 if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)