Updated to apply cleanly.
[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
4877ebcc
WD
16--- orig/backup.c 2005-02-22 02:10:16
17+++ backup.c 2005-02-22 02:11:15
8af83008
WD
18@@ -22,11 +22,17 @@
19
20 extern int verbose;
21 extern int backup_suffix_len;
19a778eb 22+extern int backup_suffix_dels_len;
8af83008 23 extern int backup_dir_len;
19a778eb 24+extern int backup_dir_dels_len;
8af83008 25 extern unsigned int backup_dir_remainder;
19a778eb 26+extern unsigned int backup_dir_dels_remainder;
8af83008 27 extern char backup_dir_buf[MAXPATHLEN];
19a778eb 28+extern char backup_dir_dels_buf[MAXPATHLEN];
8af83008 29 extern char *backup_suffix;
19a778eb 30+extern char *backup_suffix_dels;
8af83008 31 extern char *backup_dir;
19a778eb 32+extern char *backup_dir_dels;
8af83008
WD
33
34 extern int am_root;
35 extern int preserve_devices;
36@@ -35,6 +41,8 @@ extern int preserve_hard_links;
37 extern int orig_umask;
38 extern int safe_symlinks;
39
40+static int deleting;
41+
42 /* make a complete pathname for backup file */
43 char *get_backup_name(char *fname)
44 {
4877ebcc 45@@ -52,11 +60,28 @@ char *get_backup_name(char *fname)
8af83008
WD
46 return NULL;
47 }
48
49+static char *get_delete_name(char *fname)
50+{
19a778eb
WD
51+ if (backup_dir_dels) {
52+ if (stringjoin(backup_dir_dels_buf + backup_dir_dels_len, backup_dir_dels_remainder,
53+ fname, backup_suffix_dels, NULL) < backup_dir_dels_remainder)
54+ return backup_dir_dels_buf;
8af83008 55+ } else {
19a778eb
WD
56+ if (stringjoin(backup_dir_dels_buf, MAXPATHLEN,
57+ fname, backup_suffix_dels, NULL) < MAXPATHLEN)
58+ return backup_dir_dels_buf;
8af83008
WD
59+ }
60+
61+ rprintf(FERROR, "delete filename too long\n");
62+ return NULL;
63+}
64+
65 /* simple backup creates a backup with a suffix in the same directory */
66 static int make_simple_backup(char *fname)
67 {
4877ebcc 68 int rename_errno;
8af83008
WD
69- char *fnamebak = get_backup_name(fname);
70+ char *fnamebak = deleting ? get_delete_name(fname)
71+ : get_backup_name(fname);
72
73 if (!fnamebak)
74 return 0;
4877ebcc 75@@ -97,7 +122,8 @@ path
8af83008
WD
76 static int make_bak_dir(char *fullpath)
77 {
78 STRUCT_STAT st;
79- char *rel = fullpath + backup_dir_len;
19a778eb 80+ int dir_len = deleting ? backup_dir_dels_len : backup_dir_len;
8af83008
WD
81+ char *rel = fullpath + dir_len;
82 char *end = rel + strlen(rel);
83 char *p = end;
84
4877ebcc 85@@ -184,7 +210,8 @@ static int keep_backup(char *fname)
4f9b6a01 86 if (!(file = make_file(fname, NULL, NO_FILTERS)))
8af83008
WD
87 return 1; /* the file could have disappeared */
88
89- if (!(buf = get_backup_name(fname)))
90+ buf = deleting ? get_delete_name(fname) : get_backup_name(fname);
91+ if (!buf)
92 return 0;
93
57e73b72 94 /* Check to see if this is a device file, or link */
4877ebcc 95@@ -277,3 +304,13 @@ int make_backup(char *fname)
44917741
WD
96 return keep_backup(fname);
97 return make_simple_backup(fname);
98 }
8af83008 99+
79f132a1 100+/* backup switch routine called only when backing-up removed file */
8af83008
WD
101+int safe_delete(char *fname)
102+{
44917741 103+ int ret;
8af83008 104+ deleting = 1;
44917741
WD
105+ ret = make_backup(fname);
106+ deleting = 0;
107+ return ret;
108+}
f26fcad4 109--- orig/generator.c 2005-02-27 18:24:42
e20f0bda
WD
110+++ generator.c 2005-02-26 19:31:06
111@@ -82,16 +82,23 @@ extern dev_t filesystem_dev;
52f25864
WD
112 extern char *backup_dir;
113 extern char *backup_suffix;
114 extern int backup_suffix_len;
19a778eb
WD
115+extern char *backup_dir_dels;
116+extern char *backup_suffix_dels;
117+extern int backup_suffix_dels_len;
52f25864 118
e20f0bda 119 extern struct filter_list_struct server_filter_list;
52f25864
WD
120
121 static int deletion_count = 0; /* used to implement --max-delete */
122
e20f0bda 123
52f25864
WD
124+/* Function now checks if file matches backup- or delete-suffix patterns. */
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
135
e20f0bda
WD
136@@ -109,8 +116,8 @@ static int delete_item(char *fname, int
137 return -1;
138
139 if (!S_ISDIR(mode)) {
140- if (make_backups && (backup_dir || !is_backup_file(fname)))
141- ok = make_backup(fname);
142+ if (make_backups && (backup_dir_dels || !is_backup_file(fname)))
143+ ok = safe_delete(fname);
144 else
145 ok = robust_unlink(fname) == 0;
146 if (ok) {
147@@ -131,9 +138,9 @@ static int delete_item(char *fname, int
4877ebcc
WD
148 if (dry_run && zap_dir) {
149 ok = 0;
150 errno = ENOTEMPTY;
151- } else if (make_backups && !backup_dir && !is_backup_file(fname)
19a778eb 152+ } else if (make_backups && !backup_dir_dels && !is_backup_file(fname)
91e437b0 153 && !(flags & DEL_FORCE_RECURSE))
52f25864 154- ok = make_backup(fname);
52f25864
WD
155+ ok = safe_delete(fname);
156 else
157 ok = do_rmdir(fname) == 0;
4877ebcc 158 if (ok) {
e20f0bda 159--- orig/options.c 2005-02-25 18:44:31
52f25864 160+++ options.c 2005-02-21 11:02:45
e20f0bda 161@@ -127,10 +127,14 @@ int no_detach
8af83008
WD
162 int write_batch = 0;
163 int read_batch = 0;
164 int backup_dir_len = 0;
19a778eb 165+int backup_dir_dels_len = 0;
8af83008 166 int backup_suffix_len;
19a778eb 167+int backup_suffix_dels_len;
8af83008 168 unsigned int backup_dir_remainder;
19a778eb 169+unsigned int backup_dir_dels_remainder;
8af83008
WD
170
171 char *backup_suffix = NULL;
19a778eb 172+char *backup_suffix_dels = NULL;
8af83008
WD
173 char *tmpdir = NULL;
174 char *partial_dir = NULL;
daceaa67 175 char *basis_dir[MAX_BASIS_DIRS+1];
e20f0bda 176@@ -140,7 +144,9 @@ char *log_format = NULL;
8af83008
WD
177 char *password_file = NULL;
178 char *rsync_path = RSYNC_PATH;
179 char *backup_dir = NULL;
19a778eb 180+char *backup_dir_dels = NULL;
8af83008 181 char backup_dir_buf[MAXPATHLEN];
19a778eb 182+char backup_dir_dels_buf[MAXPATHLEN];
daceaa67 183 int rsync_port = 0;
c59d6641 184 int compare_dest = 0;
dc8e4919 185 int link_dest = 0;
e20f0bda 186@@ -270,6 +276,8 @@ void usage(enum logcode F)
8af83008 187 rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n");
79f132a1
WD
188 rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n");
189 rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
19a778eb
WD
190+ rprintf(F," --backup-dir-dels make backups of removed files into current dir\n");
191+ rprintf(F," --suffix-dels=SUFFIX set removed-files suffix (defaults to --suffix)\n");
79f132a1 192 rprintf(F," -u, --update skip files that are newer on the receiver\n");
0b2fb126 193 rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n");
fd0e045e 194 rprintf(F," -d, --dirs transfer directories without recursing\n");
e20f0bda 195@@ -364,6 +372,7 @@ static struct poptOption long_options[]
8af83008 196 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
57e73b72 197 {"version", 0, POPT_ARG_NONE, 0, OPT_VERSION, 0, 0},
8af83008 198 {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
19a778eb 199+ {"suffix-dels", 0, POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
8af83008
WD
200 {"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
201 {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
202 {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
e20f0bda 203@@ -443,6 +452,7 @@ static struct poptOption long_options[]
159b101f 204 {"itemize-changes", 'i', POPT_ARG_NONE, &itemize_changes, 0, 0, 0 },
8af83008 205 {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 },
8af83008 206 {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
19a778eb 207+ {"backup-dir-dels", 0, POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
8af83008 208 {"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 },
57e73b72
WD
209 {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
210 {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
e20f0bda 211@@ -1004,6 +1014,8 @@ int parse_arguments(int *argc, const cha
daceaa67 212 partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
8af83008
WD
213 if (backup_dir)
214 backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
19a778eb
WD
215+ if (backup_dir_dels)
216+ backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0);
8af83008
WD
217 if (files_from)
218 files_from = sanitize_path(NULL, files_from, NULL, 0);
219 }
e20f0bda 220@@ -1036,6 +1048,12 @@ int parse_arguments(int *argc, const cha
4f9b6a01 221 if (check_filter(elp, backup_dir, 1) < 0)
8af83008
WD
222 goto options_rejected;
223 }
19a778eb
WD
224+ /* Clean backup_dir_dels same as for backup_dir */
225+ if (backup_dir_dels) {
226+ clean_fname(backup_dir_dels, 1);
227+ if (check_filter(elp, backup_dir_dels, 1) < 0)
8af83008
WD
228+ goto options_rejected;
229+ }
230 }
4f9b6a01 231 if (server_filter_list.head && files_from) {
27a7053c 232 if (!*files_from)
e20f0bda 233@@ -1058,6 +1076,16 @@ int parse_arguments(int *argc, const cha
8af83008
WD
234 backup_suffix);
235 return 0;
236 }
19a778eb
WD
237+ /* if backup_suffix_dels not supplied, default to backup_suffix */
238+ if (!backup_suffix_dels)
239+ backup_suffix_dels = backup_dir_dels ? "" : backup_suffix;
240+ backup_suffix_dels_len = strlen(backup_suffix_dels);
241+ if (strchr(backup_suffix_dels, '/') != NULL) {
8af83008 242+ snprintf(err_buf, sizeof err_buf,
19a778eb
WD
243+ "--suffix-dels cannot contain slashes: %s\n",
244+ backup_suffix_dels);
8af83008
WD
245+ return 0;
246+ }
247 if (backup_dir) {
248 backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
249 backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
e20f0bda 250@@ -1079,6 +1107,31 @@ int parse_arguments(int *argc, const cha
8af83008
WD
251 "--suffix cannot be a null string without --backup-dir\n");
252 return 0;
253 }
19a778eb
WD
254+ /* If backup_dir_dels not supplied default to backup_dir if it has been supplied */
255+ if (backup_dir && !backup_dir_dels) {
256+ backup_dir_dels = backup_dir;
257+ backup_dir_dels_len = backup_dir_len;
258+ backup_dir_dels_remainder = backup_dir_remainder;
259+ strlcpy(backup_dir_dels_buf, backup_dir_buf, sizeof backup_dir_buf);
260+ } else if (backup_dir_dels) {
261+ backup_dir_dels_len = strlcpy(backup_dir_dels_buf, backup_dir_dels, sizeof backup_dir_dels_buf);
262+ backup_dir_dels_remainder = sizeof backup_dir_dels_buf - backup_dir_dels_len;
263+ if (backup_dir_dels_remainder < 32) {
8af83008 264+ snprintf(err_buf, sizeof err_buf,
19a778eb 265+ "the --backup-dir-dels path is WAY too long.\n");
8af83008
WD
266+ return 0;
267+ }
19a778eb
WD
268+ if (backup_dir_dels_buf[backup_dir_dels_len - 1] != '/') {
269+ backup_dir_dels_buf[backup_dir_dels_len++] = '/';
270+ backup_dir_dels_buf[backup_dir_dels_len] = '\0';
8af83008
WD
271+ }
272+ if (verbose > 1 && !am_sender)
19a778eb
WD
273+ rprintf(FINFO, "backup_dir_dels is %s\n", backup_dir_dels_buf);
274+ } else if (!backup_suffix_dels_len && (!am_server || !am_sender)) {
8af83008 275+ snprintf(err_buf, sizeof err_buf,
19a778eb 276+ "--suffix-dels cannot be a null string without --backup-dir-dels\n");
8af83008
WD
277+ return 0;
278+ }
52f25864
WD
279 if (make_backups && !backup_dir)
280 omit_dir_times = 1;
8af83008 281
e20f0bda 282@@ -1346,6 +1399,10 @@ void server_options(char **args,int *arg
8af83008
WD
283 args[ac++] = "--backup-dir";
284 args[ac++] = backup_dir;
285 }
19a778eb
WD
286+ if (backup_dir_dels) {
287+ args[ac++] = "--backup-dir-dels";
288+ args[ac++] = backup_dir_dels;
8af83008
WD
289+ }
290
291 /* Only send --suffix if it specifies a non-default value. */
292 if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
e20f0bda 293@@ -1354,7 +1411,13 @@ void server_options(char **args,int *arg
8af83008
WD
294 goto oom;
295 args[ac++] = arg;
296 }
297-
19a778eb
WD
298+ /* Only send --suffix-dels if it specifies a non-default value. */
299+ if (strcmp(backup_suffix_dels, backup_dir_dels ? "" : BACKUP_SUFFIX) != 0) {
8af83008 300+ /* We use the following syntax to avoid weirdness with '~'. */
19a778eb 301+ if (asprintf(&arg, "--suffix-dels=%s", backup_suffix_dels) < 0)
8af83008
WD
302+ goto oom;
303+ args[ac++] = arg;
304+ }
305 if (am_sender) {
306 if (delete_excluded)
307 args[ac++] = "--delete-excluded";