Fixed misplaced hunk.
[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;
a54a2c4d 72@@ -96,7 +120,8 @@ static int make_bak_dir(char *fullpath)
8af83008 73 {
ffc18846
WD
74 statx sx;
75 struct file_struct *file;
8af83008 76- char *rel = fullpath + backup_dir_len;
19a778eb 77+ int dir_len = deleting ? backup_dir_dels_len : backup_dir_len;
8af83008
WD
78+ char *rel = fullpath + dir_len;
79 char *end = rel + strlen(rel);
80 char *p = end;
81
a54a2c4d 82@@ -212,7 +237,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 }
a54a2c4d 92@@ -327,3 +353,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+}
9a7eef96
WD
106--- old/generator.c
107+++ new/generator.c
ffc18846 108@@ -94,6 +94,9 @@ extern mode_t orig_umask;
52f25864
WD
109 extern char *backup_dir;
110 extern char *backup_suffix;
111 extern int backup_suffix_len;
19a778eb
WD
112+extern char *backup_dir_dels;
113+extern char *backup_suffix_dels;
114+extern int backup_suffix_dels_len;
fc068916 115 extern struct file_list *cur_flist, *first_flist, *dir_flist;
e20f0bda 116 extern struct filter_list_struct server_filter_list;
a54a2c4d
WD
117 #ifdef ICONV_OPTION
118@@ -131,10 +134,14 @@ enum delret {
87d0091c 119 static enum delret delete_dir_contents(char *fname, int flags);
52f25864 120
e20f0bda 121
d608ca23 122+/* Function now compares both backup_suffix and backup_suffix_dels. */
52f25864
WD
123 static int is_backup_file(char *fn)
124 {
125 int k = strlen(fn) - backup_suffix_len;
126- return k > 0 && strcmp(fn+k, backup_suffix) == 0;
127+ if (k > 0 && strcmp(fn+k, backup_suffix) == 0)
128+ return 1;
19a778eb
WD
129+ k += backup_suffix_len - backup_suffix_dels_len;
130+ return k > 0 && strcmp(fn+k, backup_suffix_dels) == 0;
52f25864
WD
131 }
132
87d0091c 133 /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
a54a2c4d 134@@ -170,9 +177,9 @@ static enum delret delete_item(char *fbu
87d0091c
WD
135 if (S_ISDIR(mode)) {
136 what = "rmdir";
f813befd 137 ok = do_rmdir(fbuf) == 0;
fc068916
WD
138- } else if (make_backups > 0 && (backup_dir || !is_backup_file(fbuf))) {
139+ } else if (make_backups > 0 && (backup_dir_dels || !is_backup_file(fbuf))) {
87d0091c 140 what = "make_backup";
f813befd
WD
141- ok = make_backup(fbuf);
142+ ok = safe_delete(fbuf);
87d0091c
WD
143 } else {
144 what = "unlink";
f813befd 145 ok = robust_unlink(fbuf) == 0;
9a7eef96
WD
146--- old/options.c
147+++ new/options.c
a54a2c4d 148@@ -145,10 +145,14 @@ int no_detach
8af83008
WD
149 int write_batch = 0;
150 int read_batch = 0;
151 int backup_dir_len = 0;
19a778eb 152+int backup_dir_dels_len = 0;
8af83008 153 int backup_suffix_len;
19a778eb 154+int backup_suffix_dels_len;
8af83008 155 unsigned int backup_dir_remainder;
19a778eb 156+unsigned int backup_dir_dels_remainder;
8af83008
WD
157
158 char *backup_suffix = NULL;
19a778eb 159+char *backup_suffix_dels = NULL;
8af83008
WD
160 char *tmpdir = NULL;
161 char *partial_dir = NULL;
daceaa67 162 char *basis_dir[MAX_BASIS_DIRS+1];
a54a2c4d 163@@ -160,7 +164,9 @@ char *stdout_format = NULL;
e0e47893 164 char *password_file = NULL;
8af83008
WD
165 char *rsync_path = RSYNC_PATH;
166 char *backup_dir = NULL;
19a778eb 167+char *backup_dir_dels = NULL;
8af83008 168 char backup_dir_buf[MAXPATHLEN];
19a778eb 169+char backup_dir_dels_buf[MAXPATHLEN];
4a65fe72 170 char *sockopts = NULL;
daceaa67 171 int rsync_port = 0;
c59d6641 172 int compare_dest = 0;
a54a2c4d 173@@ -316,6 +322,8 @@ void usage(enum logcode F)
8af83008 174 rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n");
79f132a1
WD
175 rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n");
176 rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
19a778eb
WD
177+ rprintf(F," --backup-dir-dels make backups of removed files into current dir\n");
178+ rprintf(F," --suffix-dels=SUFFIX set removed-files suffix (defaults to --suffix)\n");
79f132a1 179 rprintf(F," -u, --update skip files that are newer on the receiver\n");
0b2fb126 180 rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n");
489b0a72 181 rprintf(F," --append append data onto shorter files\n");
a54a2c4d
WD
182@@ -583,7 +591,9 @@ static struct poptOption long_options[]
183 {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 },
184 {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 },
8af83008 185 {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
19a778eb 186+ {"backup-dir-dels", 0, POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
489b0a72
WD
187 {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
188+ {"suffix-dels", 0, POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
189 {"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
57e73b72
WD
190 {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
191 {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
a54a2c4d 192@@ -1378,6 +1388,8 @@ int parse_arguments(int *argc, const cha
60a8bf36
WD
193 tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, NULL);
194 if (backup_dir)
21158bc6 195 backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, NULL);
60a8bf36 196+ if (backup_dir_dels)
21158bc6 197+ backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0, NULL);
8af83008 198 }
def2ace9
WD
199 if (server_filter_list.head && !am_sender) {
200 struct filter_list_struct *elp = &server_filter_list;
a54a2c4d 201@@ -1395,6 +1407,14 @@ int parse_arguments(int *argc, const cha
fb11cdd7
WD
202 if (check_filter(elp, backup_dir, 1) < 0)
203 goto options_rejected;
8af83008 204 }
19a778eb
WD
205+ /* Clean backup_dir_dels same as for backup_dir */
206+ if (backup_dir_dels) {
def2ace9
WD
207+ if (!*backup_dir_dels)
208+ goto options_rejected;
19a778eb
WD
209+ clean_fname(backup_dir_dels, 1);
210+ if (check_filter(elp, backup_dir_dels, 1) < 0)
8af83008
WD
211+ goto options_rejected;
212+ }
213 }
def2ace9
WD
214
215 if (!backup_suffix)
a54a2c4d 216@@ -1406,6 +1426,16 @@ int parse_arguments(int *argc, const cha
8af83008
WD
217 backup_suffix);
218 return 0;
219 }
19a778eb
WD
220+ /* if backup_suffix_dels not supplied, default to backup_suffix */
221+ if (!backup_suffix_dels)
222+ backup_suffix_dels = backup_dir_dels ? "" : backup_suffix;
223+ backup_suffix_dels_len = strlen(backup_suffix_dels);
224+ if (strchr(backup_suffix_dels, '/') != NULL) {
8af83008 225+ snprintf(err_buf, sizeof err_buf,
19a778eb
WD
226+ "--suffix-dels cannot contain slashes: %s\n",
227+ backup_suffix_dels);
8af83008
WD
228+ return 0;
229+ }
230 if (backup_dir) {
231 backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
232 backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
a54a2c4d 233@@ -1429,6 +1459,31 @@ int parse_arguments(int *argc, const cha
e0e47893 234 "P *%s", backup_suffix);
ffc18846 235 parse_rule(&filter_list, backup_dir_buf, 0, 0);
8af83008 236 }
19a778eb
WD
237+ /* If backup_dir_dels not supplied default to backup_dir if it has been supplied */
238+ if (backup_dir && !backup_dir_dels) {
239+ backup_dir_dels = backup_dir;
240+ backup_dir_dels_len = backup_dir_len;
241+ backup_dir_dels_remainder = backup_dir_remainder;
242+ strlcpy(backup_dir_dels_buf, backup_dir_buf, sizeof backup_dir_buf);
243+ } else if (backup_dir_dels) {
244+ backup_dir_dels_len = strlcpy(backup_dir_dels_buf, backup_dir_dels, sizeof backup_dir_dels_buf);
245+ backup_dir_dels_remainder = sizeof backup_dir_dels_buf - backup_dir_dels_len;
246+ if (backup_dir_dels_remainder < 32) {
8af83008 247+ snprintf(err_buf, sizeof err_buf,
19a778eb 248+ "the --backup-dir-dels path is WAY too long.\n");
8af83008
WD
249+ return 0;
250+ }
19a778eb
WD
251+ if (backup_dir_dels_buf[backup_dir_dels_len - 1] != '/') {
252+ backup_dir_dels_buf[backup_dir_dels_len++] = '/';
253+ backup_dir_dels_buf[backup_dir_dels_len] = '\0';
8af83008
WD
254+ }
255+ if (verbose > 1 && !am_sender)
19a778eb
WD
256+ rprintf(FINFO, "backup_dir_dels is %s\n", backup_dir_dels_buf);
257+ } else if (!backup_suffix_dels_len && (!am_server || !am_sender)) {
8af83008 258+ snprintf(err_buf, sizeof err_buf,
19a778eb 259+ "--suffix-dels cannot be a null string without --backup-dir-dels\n");
8af83008
WD
260+ return 0;
261+ }
262
a54a2c4d
WD
263 if (make_backups && !backup_dir) {
264 omit_dir_times = 0; /* Implied, so avoid -O to sender. */
265@@ -1816,6 +1871,10 @@ void server_options(char **args,int *arg
8af83008
WD
266 args[ac++] = "--backup-dir";
267 args[ac++] = backup_dir;
268 }
37d900d6 269+ if (backup_dir_dels && backup_dir_dels != backup_dir) {
19a778eb
WD
270+ args[ac++] = "--backup-dir-dels";
271+ args[ac++] = backup_dir_dels;
8af83008
WD
272+ }
273
274 /* Only send --suffix if it specifies a non-default value. */
275 if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
a54a2c4d 276@@ -1824,7 +1883,13 @@ void server_options(char **args,int *arg
8af83008
WD
277 goto oom;
278 args[ac++] = arg;
279 }
280-
19a778eb
WD
281+ /* Only send --suffix-dels if it specifies a non-default value. */
282+ if (strcmp(backup_suffix_dels, backup_dir_dels ? "" : BACKUP_SUFFIX) != 0) {
8af83008 283+ /* We use the following syntax to avoid weirdness with '~'. */
19a778eb 284+ if (asprintf(&arg, "--suffix-dels=%s", backup_suffix_dels) < 0)
8af83008
WD
285+ goto oom;
286+ args[ac++] = arg;
287+ }
288 if (am_sender) {
a54a2c4d
WD
289 if (max_delete > 0) {
290 if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)