The patches for 3.0.0pre7.
[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
109@@ -94,6 +94,9 @@ extern mode_t orig_umask;
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
WD
118
119@@ -128,10 +131,14 @@ enum delret {
87d0091c 120 static enum delret delete_dir_contents(char *fname, int flags);
52f25864 121
e20f0bda 122
d608ca23 123+/* Function now compares both backup_suffix and backup_suffix_dels. */
52f25864
WD
124 static int is_backup_file(char *fn)
125 {
126 int k = strlen(fn) - backup_suffix_len;
127- return k > 0 && strcmp(fn+k, backup_suffix) == 0;
128+ if (k > 0 && strcmp(fn+k, backup_suffix) == 0)
129+ return 1;
19a778eb
WD
130+ k += backup_suffix_len - backup_suffix_dels_len;
131+ return k > 0 && strcmp(fn+k, backup_suffix_dels) == 0;
52f25864
WD
132 }
133
87d0091c 134 /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
cc3e685d 135@@ -167,9 +174,9 @@ static enum delret delete_item(char *fbuf, int mode, char *replace, int flags)
87d0091c
WD
136 if (S_ISDIR(mode)) {
137 what = "rmdir";
f813befd 138 ok = do_rmdir(fbuf) == 0;
fc068916
WD
139- } else if (make_backups > 0 && (backup_dir || !is_backup_file(fbuf))) {
140+ } else if (make_backups > 0 && (backup_dir_dels || !is_backup_file(fbuf))) {
87d0091c 141 what = "make_backup";
f813befd
WD
142- ok = make_backup(fbuf);
143+ ok = safe_delete(fbuf);
87d0091c
WD
144 } else {
145 what = "unlink";
f813befd 146 ok = robust_unlink(fbuf) == 0;
cc3e685d
WD
147diff --git a/options.c b/options.c
148--- a/options.c
149+++ b/options.c
f2863bc0 150@@ -149,10 +149,14 @@ int no_detach
8af83008
WD
151 int write_batch = 0;
152 int read_batch = 0;
153 int backup_dir_len = 0;
19a778eb 154+int backup_dir_dels_len = 0;
8af83008 155 int backup_suffix_len;
19a778eb 156+int backup_suffix_dels_len;
8af83008 157 unsigned int backup_dir_remainder;
19a778eb 158+unsigned int backup_dir_dels_remainder;
8af83008
WD
159
160 char *backup_suffix = NULL;
19a778eb 161+char *backup_suffix_dels = NULL;
8af83008
WD
162 char *tmpdir = NULL;
163 char *partial_dir = NULL;
daceaa67 164 char *basis_dir[MAX_BASIS_DIRS+1];
f2863bc0 165@@ -164,7 +168,9 @@ char *stdout_format = NULL;
e0e47893 166 char *password_file = NULL;
8af83008
WD
167 char *rsync_path = RSYNC_PATH;
168 char *backup_dir = NULL;
19a778eb 169+char *backup_dir_dels = NULL;
8af83008 170 char backup_dir_buf[MAXPATHLEN];
19a778eb 171+char backup_dir_dels_buf[MAXPATHLEN];
4a65fe72 172 char *sockopts = NULL;
daceaa67 173 int rsync_port = 0;
c59d6641 174 int compare_dest = 0;
f2863bc0 175@@ -320,6 +326,8 @@ void usage(enum logcode F)
8af83008 176 rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n");
79f132a1
WD
177 rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n");
178 rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
19a778eb
WD
179+ rprintf(F," --backup-dir-dels make backups of removed files into current dir\n");
180+ rprintf(F," --suffix-dels=SUFFIX set removed-files suffix (defaults to --suffix)\n");
79f132a1 181 rprintf(F," -u, --update skip files that are newer on the receiver\n");
0b2fb126 182 rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n");
489b0a72 183 rprintf(F," --append append data onto shorter files\n");
f2863bc0 184@@ -591,7 +599,9 @@ static struct poptOption long_options[] = {
a54a2c4d
WD
185 {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 },
186 {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 },
8af83008 187 {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
19a778eb 188+ {"backup-dir-dels", 0, POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
489b0a72
WD
189 {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
190+ {"suffix-dels", 0, POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
191 {"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
57e73b72
WD
192 {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
193 {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
f2863bc0 194@@ -1404,6 +1414,8 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
cc3e685d 195 tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
60a8bf36 196 if (backup_dir)
cc3e685d 197 backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
60a8bf36 198+ if (backup_dir_dels)
cc3e685d 199+ backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0);
8af83008 200 }
def2ace9
WD
201 if (server_filter_list.head && !am_sender) {
202 struct filter_list_struct *elp = &server_filter_list;
f2863bc0
WD
203@@ -1425,6 +1437,14 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
204 if (check_filter(elp, dir, 1) < 0)
fb11cdd7 205 goto options_rejected;
8af83008 206 }
19a778eb
WD
207+ /* Clean backup_dir_dels same as for backup_dir */
208+ if (backup_dir_dels) {
def2ace9
WD
209+ if (!*backup_dir_dels)
210+ goto options_rejected;
19a778eb
WD
211+ clean_fname(backup_dir_dels, 1);
212+ if (check_filter(elp, backup_dir_dels, 1) < 0)
8af83008
WD
213+ goto options_rejected;
214+ }
215 }
def2ace9
WD
216
217 if (!backup_suffix)
f2863bc0 218@@ -1436,6 +1456,16 @@ int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
8af83008
WD
219 backup_suffix);
220 return 0;
221 }
19a778eb
WD
222+ /* if backup_suffix_dels not supplied, default to backup_suffix */
223+ if (!backup_suffix_dels)
224+ backup_suffix_dels = backup_dir_dels ? "" : backup_suffix;
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;
f2863bc0 235@@ -1459,6 +1489,31 @@ 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 }
19a778eb
WD
239+ /* If backup_dir_dels not supplied default to backup_dir if it has been supplied */
240+ if (backup_dir && !backup_dir_dels) {
241+ backup_dir_dels = backup_dir;
242+ backup_dir_dels_len = backup_dir_len;
243+ backup_dir_dels_remainder = backup_dir_remainder;
244+ strlcpy(backup_dir_dels_buf, backup_dir_buf, sizeof backup_dir_buf);
245+ } else if (backup_dir_dels) {
246+ backup_dir_dels_len = strlcpy(backup_dir_dels_buf, backup_dir_dels, sizeof backup_dir_dels_buf);
247+ backup_dir_dels_remainder = sizeof backup_dir_dels_buf - backup_dir_dels_len;
248+ if (backup_dir_dels_remainder < 32) {
8af83008 249+ snprintf(err_buf, sizeof err_buf,
19a778eb 250+ "the --backup-dir-dels path is WAY too long.\n");
8af83008
WD
251+ return 0;
252+ }
19a778eb
WD
253+ if (backup_dir_dels_buf[backup_dir_dels_len - 1] != '/') {
254+ backup_dir_dels_buf[backup_dir_dels_len++] = '/';
255+ backup_dir_dels_buf[backup_dir_dels_len] = '\0';
8af83008
WD
256+ }
257+ if (verbose > 1 && !am_sender)
19a778eb
WD
258+ rprintf(FINFO, "backup_dir_dels is %s\n", backup_dir_dels_buf);
259+ } else if (!backup_suffix_dels_len && (!am_server || !am_sender)) {
8af83008 260+ snprintf(err_buf, sizeof err_buf,
19a778eb 261+ "--suffix-dels cannot be a null string without --backup-dir-dels\n");
8af83008
WD
262+ return 0;
263+ }
264
a54a2c4d
WD
265 if (make_backups && !backup_dir) {
266 omit_dir_times = 0; /* Implied, so avoid -O to sender. */
f2863bc0 267@@ -1852,6 +1907,10 @@ void server_options(char **args, int *argc_p)
8af83008
WD
268 args[ac++] = "--backup-dir";
269 args[ac++] = backup_dir;
270 }
37d900d6 271+ if (backup_dir_dels && backup_dir_dels != backup_dir) {
19a778eb
WD
272+ args[ac++] = "--backup-dir-dels";
273+ args[ac++] = backup_dir_dels;
8af83008
WD
274+ }
275
276 /* Only send --suffix if it specifies a non-default value. */
277 if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
f2863bc0 278@@ -1860,7 +1919,13 @@ void server_options(char **args, int *argc_p)
8af83008
WD
279 goto oom;
280 args[ac++] = arg;
281 }
282-
19a778eb
WD
283+ /* Only send --suffix-dels if it specifies a non-default value. */
284+ if (strcmp(backup_suffix_dels, backup_dir_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)