rprintf(FERROR, "backup filename too long\n");
return NULL;
-@@ -352,3 +364,13 @@ int make_backup(const char *fname, BOOL prefer_rename)
+@@ -353,3 +365,13 @@ int make_backup(const char *fname, BOOL prefer_rename)
rprintf(FINFO, "backed up %s to %s\n", fname, buf);
return ret;
}
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
-@@ -157,10 +157,14 @@ int no_detach
+@@ -166,10 +166,14 @@ int no_detach
int write_batch = 0;
int read_batch = 0;
int backup_dir_len = 0;
char *tmpdir = NULL;
char *partial_dir = NULL;
char *basis_dir[MAX_BASIS_DIRS+1];
-@@ -173,7 +177,9 @@ char *password_file = NULL;
+@@ -182,7 +186,9 @@ char *password_file = NULL;
char *early_input_file = NULL;
char *rsync_path = RSYNC_PATH;
char *backup_dir = NULL;
char *sockopts = NULL;
char *usermap = NULL;
char *groupmap = NULL;
-@@ -770,7 +776,9 @@ static struct poptOption long_options[] = {
+@@ -780,7 +786,9 @@ static struct poptOption long_options[] = {
{"backup-deleted", 0, POPT_ARG_VAL, &make_backups, 1, 0, 0 },
{"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 },
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
{"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
{"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
{"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
-@@ -2187,6 +2195,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2253,6 +2261,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
if (backup_dir)
backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
}
if (daemon_filter_list.head && !am_sender) {
filter_rule_list *elp = &daemon_filter_list;
-@@ -2208,6 +2218,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2274,6 +2284,14 @@ int parse_arguments(int *argc_p, const char ***argv_p)
if (check_filter(elp, FLOG, dir, 1) < 0)
goto options_rejected;
}
}
if (!backup_suffix)
-@@ -2219,6 +2237,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2285,6 +2303,20 @@ int parse_arguments(int *argc_p, const char ***argv_p)
backup_suffix);
- return 0;
+ goto cleanup;
}
+ /* --suffix-dels defaults to --suffix, or empty for a client given an
+ * explicit --backup-dir-dels (just as --suffix defaults to empty when
if (backup_dir) {
size_t len;
make_backups = 1; /* --backup-dir implies --backup */
-@@ -2255,6 +2287,34 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+@@ -2321,6 +2353,34 @@ int parse_arguments(int *argc_p, const char ***argv_p)
"P *%s", backup_suffix);
parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0);
}
+ parse_filter_str(&filter_list, backup_dir_dels_buf, rule_template(0), 0);
+ }
- if (preserve_times) {
- preserve_times = PRESERVE_FILE_TIMES;
-@@ -2662,6 +2722,10 @@ void server_options(char **args, int *argc_p)
+ if (make_backups && !backup_dir)
+ omit_dir_times = -1; /* Implied, so avoid -O to sender. */
+@@ -2790,11 +2850,20 @@ void server_options(char **args, int *argc_p)
args[ac++] = "--backup-dir";
- args[ac++] = backup_dir;
+ args[ac++] = safe_arg("", backup_dir);
}
+ if (backup_dir_dels && backup_dir_dels != backup_dir) {
+ args[ac++] = "--backup-dir-dels";
+ }
/* Only send --suffix if it specifies a non-default value. */
- if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
-@@ -2670,6 +2734,14 @@ void server_options(char **args, int *argc_p)
- goto oom;
- args[ac++] = arg;
- }
+ if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0)
+ args[ac++] = safe_arg("--suffix", backup_suffix);
+
+ /* Only send --suffix-dels if it specifies a value different from the
+ * --suffix value, which would normally be used for deletions too. */
-+ if (strcmp(backup_suffix_dels, backup_suffix) != 0) {
-+ /* We use the following syntax to avoid weirdness with '~'. */
-+ if (asprintf(&arg, "--suffix-dels=%s", backup_suffix_dels) < 0)
-+ goto oom;
-+ args[ac++] = arg;
-+ }
++ if (strcmp(backup_suffix_dels, backup_suffix) != 0)
++ args[ac++] = safe_arg("--suffix-dels", backup_suffix_dels);
++
+ if (checksum_choice)
+ args[ac++] = safe_arg("--checksum-choice", checksum_choice);
- if (checksum_choice) {
- if (asprintf(&arg, "--checksum-choice=%s", checksum_choice) < 0)
diff --git a/rsync.1.md b/rsync.1.md
--- a/rsync.1.md
+++ b/rsync.1.md
-@@ -346,7 +346,9 @@ detailed description below for a complete description.
+@@ -430,7 +430,9 @@ has its own detailed description later in this manpage.
--backup, -b make backups (see --suffix & --backup-dir)
--backup-deleted make backups only of deleted files
--backup-dir=DIR make backups into hierarchy based in DIR
--update, -u skip files that are newer on the receiver
--inplace update destination files in-place
--append append data onto shorter files
+@@ -1028,6 +1030,11 @@ expand it.
+ daemon is the receiver, the backup dir cannot go outside the module's path
+ hierarchy, so take extra care not to delete it or copy into it.
+
++0. `--backup-dir-dels=DIR`
++
++ Works like [`--backup-dir`](#opt) except for deleted files in conjunction
++ with the [`--backup-deleted`](#opt) option.
++
+ 0. `--suffix=SUFFIX`
+
+ This option allows you to override the default backup suffix used with the