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