|
|
78df90 |
diff --git a/exclude.c b/exclude.c
|
|
|
78df90 |
index e095744..7906caa 100644
|
|
|
78df90 |
--- a/exclude.c
|
|
|
78df90 |
+++ b/exclude.c
|
|
|
78df90 |
@@ -25,18 +25,26 @@
|
|
|
78df90 |
|
|
|
78df90 |
extern int am_server;
|
|
|
78df90 |
extern int am_sender;
|
|
|
78df90 |
+extern int am_generator;
|
|
|
78df90 |
extern int eol_nulls;
|
|
|
78df90 |
extern int io_error;
|
|
|
78df90 |
+extern int xfer_dirs;
|
|
|
78df90 |
+extern int recurse;
|
|
|
78df90 |
extern int local_server;
|
|
|
78df90 |
extern int prune_empty_dirs;
|
|
|
78df90 |
extern int ignore_perishable;
|
|
|
78df90 |
+extern int old_style_args;
|
|
|
78df90 |
+extern int relative_paths;
|
|
|
78df90 |
extern int delete_mode;
|
|
|
78df90 |
extern int delete_excluded;
|
|
|
78df90 |
extern int cvs_exclude;
|
|
|
78df90 |
extern int sanitize_paths;
|
|
|
78df90 |
extern int protocol_version;
|
|
|
78df90 |
+extern int read_batch;
|
|
|
78df90 |
+extern int list_only;
|
|
|
78df90 |
extern int module_id;
|
|
|
78df90 |
|
|
|
78df90 |
+extern char *filesfrom_host;
|
|
|
78df90 |
extern char curr_dir[MAXPATHLEN];
|
|
|
78df90 |
extern unsigned int curr_dir_len;
|
|
|
78df90 |
extern unsigned int module_dirlen;
|
|
|
78df90 |
@@ -44,8 +51,10 @@ extern unsigned int module_dirlen;
|
|
|
78df90 |
filter_rule_list filter_list = { .debug_type = "" };
|
|
|
78df90 |
filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };
|
|
|
78df90 |
filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
|
|
|
78df90 |
+filter_rule_list implied_filter_list = { .debug_type = " [implied]" };
|
|
|
78df90 |
|
|
|
78df90 |
int saw_xattr_filter = 0;
|
|
|
78df90 |
+int trust_sender_filter = 0;
|
|
|
78df90 |
|
|
|
78df90 |
/* Need room enough for ":MODS " prefix plus some room to grow. */
|
|
|
78df90 |
#define MAX_RULE_PREFIX (16)
|
|
|
78df90 |
@@ -288,6 +297,233 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
|
|
|
78df90 |
}
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
+/* If the wildcards failed, the remote shell might give us a file matching the literal
|
|
|
78df90 |
+ * wildcards. Since "*" & "?" already match themselves, this just needs to deal with
|
|
|
78df90 |
+ * failed "[foo]" idioms.
|
|
|
78df90 |
+ */
|
|
|
78df90 |
+static void maybe_add_literal_brackets_rule(filter_rule const *based_on, int arg_len)
|
|
|
78df90 |
+{
|
|
|
78df90 |
+ filter_rule *rule;
|
|
|
78df90 |
+ const char *arg = based_on->pattern, *cp;
|
|
|
78df90 |
+ char *p;
|
|
|
78df90 |
+ int cnt = 0;
|
|
|
78df90 |
+
|
|
|
78df90 |
+ if (arg_len < 0)
|
|
|
78df90 |
+ arg_len = strlen(arg);
|
|
|
78df90 |
+
|
|
|
78df90 |
+ for (cp = arg; *cp; cp++) {
|
|
|
78df90 |
+ if (*cp == '\\' && cp[1]) {
|
|
|
78df90 |
+ cp++;
|
|
|
78df90 |
+ } else if (*cp == '[')
|
|
|
78df90 |
+ cnt++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (!cnt)
|
|
|
78df90 |
+ return;
|
|
|
78df90 |
+
|
|
|
78df90 |
+ rule = new0(filter_rule);
|
|
|
78df90 |
+ rule->rflags = based_on->rflags;
|
|
|
78df90 |
+ rule->u.slash_cnt = based_on->u.slash_cnt;
|
|
|
78df90 |
+ p = rule->pattern = new_array(char, arg_len + cnt + 1);
|
|
|
78df90 |
+ for (cp = arg; *cp; ) {
|
|
|
78df90 |
+ if (*cp == '\\' && cp[1]) {
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ } else if (*cp == '[')
|
|
|
78df90 |
+ *p++ = '\\';
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ *p++ = '\0';
|
|
|
78df90 |
+
|
|
|
78df90 |
+ rule->next = implied_filter_list.head;
|
|
|
78df90 |
+ implied_filter_list.head = rule;
|
|
|
78df90 |
+ if (DEBUG_GTE(FILTER, 3)) {
|
|
|
78df90 |
+ rprintf(FINFO, "[%s] add_implied_include(%s%s)\n", who_am_i(), rule->pattern,
|
|
|
78df90 |
+ rule->rflags & FILTRULE_DIRECTORY ? "/" : "");
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+}
|
|
|
78df90 |
+
|
|
|
78df90 |
+static char *partial_string_buf = NULL;
|
|
|
78df90 |
+static int partial_string_len = 0;
|
|
|
78df90 |
+void implied_include_partial_string(const char *s_start, const char *s_end)
|
|
|
78df90 |
+{
|
|
|
78df90 |
+ partial_string_len = s_end - s_start;
|
|
|
78df90 |
+ if (partial_string_len <= 0 || partial_string_len >= MAXPATHLEN) { /* too-large should be impossible... */
|
|
|
78df90 |
+ partial_string_len = 0;
|
|
|
78df90 |
+ return;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (!partial_string_buf)
|
|
|
78df90 |
+ partial_string_buf = new_array(char, MAXPATHLEN);
|
|
|
78df90 |
+ memcpy(partial_string_buf, s_start, partial_string_len);
|
|
|
78df90 |
+}
|
|
|
78df90 |
+
|
|
|
78df90 |
+void free_implied_include_partial_string()
|
|
|
78df90 |
+{
|
|
|
78df90 |
+ if (partial_string_buf) {
|
|
|
78df90 |
+ free(partial_string_buf);
|
|
|
78df90 |
+ partial_string_buf = NULL;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ partial_string_len = 0; /* paranoia */
|
|
|
78df90 |
+}
|
|
|
78df90 |
+
|
|
|
78df90 |
+/* Each arg the client sends to the remote sender turns into an implied include
|
|
|
78df90 |
+ * that the receiver uses to validate the file list from the sender. */
|
|
|
78df90 |
+void add_implied_include(const char *arg, int skip_daemon_module)
|
|
|
78df90 |
+{
|
|
|
78df90 |
+ filter_rule *rule;
|
|
|
78df90 |
+ int arg_len, saw_wild = 0, saw_live_open_brkt = 0, backslash_cnt = 0;
|
|
|
78df90 |
+ int slash_cnt = 1; /* We know we're adding a leading slash. */
|
|
|
78df90 |
+ const char *cp;
|
|
|
78df90 |
+ char *p;
|
|
|
78df90 |
+ if (am_server || old_style_args || list_only || read_batch || filesfrom_host != NULL)
|
|
|
78df90 |
+ return;
|
|
|
78df90 |
+ if (partial_string_len) {
|
|
|
78df90 |
+ arg_len = strlen(arg);
|
|
|
78df90 |
+ if (partial_string_len + arg_len >= MAXPATHLEN) {
|
|
|
78df90 |
+ partial_string_len = 0;
|
|
|
78df90 |
+ return; /* Should be impossible... */
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ memcpy(partial_string_buf + partial_string_len, arg, arg_len + 1);
|
|
|
78df90 |
+ partial_string_len = 0;
|
|
|
78df90 |
+ arg = partial_string_buf;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (skip_daemon_module) {
|
|
|
78df90 |
+ if ((cp = strchr(arg, '/')) != NULL)
|
|
|
78df90 |
+ arg = cp + 1;
|
|
|
78df90 |
+ else
|
|
|
78df90 |
+ arg = "";
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (relative_paths) {
|
|
|
78df90 |
+ if ((cp = strstr(arg, "/./")) != NULL)
|
|
|
78df90 |
+ arg = cp + 3;
|
|
|
78df90 |
+ } else if ((cp = strrchr(arg, '/')) != NULL) {
|
|
|
78df90 |
+ arg = cp + 1;
|
|
|
78df90 |
+ if (*arg == '.' && arg[1] == '\0')
|
|
|
78df90 |
+ arg++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ arg_len = strlen(arg);
|
|
|
78df90 |
+ if (arg_len) {
|
|
|
78df90 |
+ if (strpbrk(arg, "*[?")) {
|
|
|
78df90 |
+ /* We need to add room to escape backslashes if wildcard chars are present. */
|
|
|
78df90 |
+ for (cp = arg; (cp = strchr(cp, '\\')) != NULL; cp++)
|
|
|
78df90 |
+ arg_len++;
|
|
|
78df90 |
+ saw_wild = 1;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ arg_len++; /* Leave room for the prefixed slash */
|
|
|
78df90 |
+ rule = new0(filter_rule);
|
|
|
78df90 |
+ if (!implied_filter_list.head)
|
|
|
78df90 |
+ implied_filter_list.head = implied_filter_list.tail = rule;
|
|
|
78df90 |
+ else {
|
|
|
78df90 |
+ rule->next = implied_filter_list.head;
|
|
|
78df90 |
+ implied_filter_list.head = rule;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0);
|
|
|
78df90 |
+ p = rule->pattern = new_array(char, arg_len + 1);
|
|
|
78df90 |
+ *p++ = '/';
|
|
|
78df90 |
+ for (cp = arg; *cp; ) {
|
|
|
78df90 |
+ switch (*cp) {
|
|
|
78df90 |
+ case '\\':
|
|
|
78df90 |
+ if (cp[1] == ']') {
|
|
|
78df90 |
+ if (!saw_wild)
|
|
|
78df90 |
+ cp++; /* A \] in a non-wild filter causes a problem, so drop the \ . */
|
|
|
78df90 |
+ } else if (!strchr("*[?", cp[1])) {
|
|
|
78df90 |
+ backslash_cnt++;
|
|
|
78df90 |
+ if (saw_wild)
|
|
|
78df90 |
+ *p++ = '\\';
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+ case '/':
|
|
|
78df90 |
+ if (p[-1] == '/') { /* This is safe because of the initial slash. */
|
|
|
78df90 |
+ cp++;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (relative_paths) {
|
|
|
78df90 |
+ filter_rule const *ent;
|
|
|
78df90 |
+ int found = 0;
|
|
|
78df90 |
+ *p = '\0';
|
|
|
78df90 |
+ for (ent = implied_filter_list.head; ent; ent = ent->next) {
|
|
|
78df90 |
+ if (ent != rule && strcmp(ent->pattern, rule->pattern) == 0) {
|
|
|
78df90 |
+ found = 1;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (!found) {
|
|
|
78df90 |
+ filter_rule *R_rule = new0(filter_rule);
|
|
|
78df90 |
+ R_rule->rflags = FILTRULE_INCLUDE | FILTRULE_DIRECTORY;
|
|
|
78df90 |
+ /* Check if our sub-path has wildcards or escaped backslashes */
|
|
|
78df90 |
+ if (saw_wild && strpbrk(rule->pattern, "*[?\\"))
|
|
|
78df90 |
+ R_rule->rflags |= FILTRULE_WILD;
|
|
|
78df90 |
+ R_rule->pattern = strdup(rule->pattern);
|
|
|
78df90 |
+ R_rule->u.slash_cnt = slash_cnt;
|
|
|
78df90 |
+ R_rule->next = implied_filter_list.head;
|
|
|
78df90 |
+ implied_filter_list.head = R_rule;
|
|
|
78df90 |
+ if (DEBUG_GTE(FILTER, 3)) {
|
|
|
78df90 |
+ rprintf(FINFO, "[%s] add_implied_include(%s/)\n",
|
|
|
78df90 |
+ who_am_i(), R_rule->pattern);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (saw_live_open_brkt)
|
|
|
78df90 |
+ maybe_add_literal_brackets_rule(R_rule, -1);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ slash_cnt++;
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+ case '[':
|
|
|
78df90 |
+ saw_live_open_brkt = 1;
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+ default:
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ *p = '\0';
|
|
|
78df90 |
+ rule->u.slash_cnt = slash_cnt;
|
|
|
78df90 |
+ arg = rule->pattern;
|
|
|
78df90 |
+ arg_len = p - arg; /* We recompute it due to backslash weirdness. */
|
|
|
78df90 |
+ if (DEBUG_GTE(FILTER, 3))
|
|
|
78df90 |
+ rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern);
|
|
|
78df90 |
+ if (saw_live_open_brkt)
|
|
|
78df90 |
+ maybe_add_literal_brackets_rule(rule, arg_len);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+
|
|
|
78df90 |
+ if (recurse || xfer_dirs) {
|
|
|
78df90 |
+ /* Now create a rule with an added "/" & "**" or "*" at the end */
|
|
|
78df90 |
+ rule = new0(filter_rule);
|
|
|
78df90 |
+ rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD;
|
|
|
78df90 |
+ if (recurse)
|
|
|
78df90 |
+ rule->rflags |= FILTRULE_WILD2;
|
|
|
78df90 |
+ /* We must leave enough room for / * * \0. */
|
|
|
78df90 |
+ if (!saw_wild && backslash_cnt) {
|
|
|
78df90 |
+ /* We are appending a wildcard, so now the backslashes need to be escaped. */
|
|
|
78df90 |
+ p = rule->pattern = new_array(char, arg_len + backslash_cnt + 3 + 1);
|
|
|
78df90 |
+ for (cp = arg; *cp; ) {
|
|
|
78df90 |
+ if (*cp == '\\')
|
|
|
78df90 |
+ *p++ = '\\';
|
|
|
78df90 |
+ *p++ = *cp++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ } else {
|
|
|
78df90 |
+ p = rule->pattern = new_array(char, arg_len + 3 + 1);
|
|
|
78df90 |
+ if (arg_len) {
|
|
|
78df90 |
+ memcpy(p, arg, arg_len);
|
|
|
78df90 |
+ p += arg_len;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (p[-1] != '/')
|
|
|
78df90 |
+ *p++ = '/';
|
|
|
78df90 |
+ *p++ = '*';
|
|
|
78df90 |
+ if (recurse)
|
|
|
78df90 |
+ *p++ = '*';
|
|
|
78df90 |
+ *p = '\0';
|
|
|
78df90 |
+ rule->u.slash_cnt = slash_cnt + 1;
|
|
|
78df90 |
+ rule->next = implied_filter_list.head;
|
|
|
78df90 |
+ implied_filter_list.head = rule;
|
|
|
78df90 |
+ if (DEBUG_GTE(FILTER, 3))
|
|
|
78df90 |
+ rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern);
|
|
|
78df90 |
+ if (saw_live_open_brkt)
|
|
|
78df90 |
+ maybe_add_literal_brackets_rule(rule, p - rule->pattern);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+}
|
|
|
78df90 |
+
|
|
|
78df90 |
/* This frees any non-inherited items, leaving just inherited items on the list. */
|
|
|
78df90 |
static void pop_filter_list(filter_rule_list *listp)
|
|
|
78df90 |
{
|
|
|
78df90 |
@@ -702,11 +938,12 @@ static void report_filter_result(enum logcode code, char const *name,
|
|
|
78df90 |
filter_rule const *ent,
|
|
|
78df90 |
int name_flags, const char *type)
|
|
|
78df90 |
{
|
|
|
78df90 |
+ int log_level = am_sender || am_generator ? 1 : 3;
|
|
|
78df90 |
+
|
|
|
78df90 |
/* If a trailing slash is present to match only directories,
|
|
|
78df90 |
* then it is stripped out by add_rule(). So as a special
|
|
|
78df90 |
- * case we add it back in here. */
|
|
|
78df90 |
-
|
|
|
78df90 |
- if (DEBUG_GTE(FILTER, 1)) {
|
|
|
78df90 |
+ * case we add it back in the log output. */
|
|
|
78df90 |
+ if (DEBUG_GTE(FILTER, log_level)) {
|
|
|
78df90 |
static char *actions[2][2]
|
|
|
78df90 |
= { {"show", "hid"}, {"risk", "protect"} };
|
|
|
78df90 |
const char *w = who_am_i();
|
|
|
78df90 |
@@ -714,7 +951,7 @@ static void report_filter_result(enum logcode code, char const *name,
|
|
|
78df90 |
: name_flags & NAME_IS_DIR ? "directory"
|
|
|
78df90 |
: "file";
|
|
|
78df90 |
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
|
|
|
78df90 |
- w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],
|
|
|
78df90 |
+ w, actions[*w=='g'][!(ent->rflags & FILTRULE_INCLUDE)],
|
|
|
78df90 |
t, name, ent->pattern,
|
|
|
78df90 |
ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);
|
|
|
78df90 |
}
|
|
|
78df90 |
@@ -886,6 +1123,7 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
|
|
|
78df90 |
}
|
|
|
78df90 |
switch (ch) {
|
|
|
78df90 |
case ':':
|
|
|
78df90 |
+ trust_sender_filter = 1;
|
|
|
78df90 |
rule->rflags |= FILTRULE_PERDIR_MERGE
|
|
|
78df90 |
| FILTRULE_FINISH_SETUP;
|
|
|
78df90 |
/* FALL THROUGH */
|
|
|
78df90 |
diff --git a/flist.c b/flist.c
|
|
|
78df90 |
index 5a1e424..4e9dd10 100644
|
|
|
78df90 |
--- a/flist.c
|
|
|
78df90 |
+++ b/flist.c
|
|
|
78df90 |
@@ -72,6 +72,7 @@ extern int need_unsorted_flist;
|
|
|
78df90 |
extern int sender_symlink_iconv;
|
|
|
78df90 |
extern int output_needs_newline;
|
|
|
78df90 |
extern int sender_keeps_checksum;
|
|
|
78df90 |
+extern int trust_sender_filter;
|
|
|
78df90 |
extern int unsort_ndx;
|
|
|
78df90 |
extern uid_t our_uid;
|
|
|
78df90 |
extern struct stats stats;
|
|
|
78df90 |
@@ -82,8 +83,7 @@ extern char curr_dir[MAXPATHLEN];
|
|
|
78df90 |
|
|
|
78df90 |
extern struct chmod_mode_struct *chmod_modes;
|
|
|
78df90 |
|
|
|
78df90 |
-extern filter_rule_list filter_list;
|
|
|
78df90 |
-extern filter_rule_list daemon_filter_list;
|
|
|
78df90 |
+extern filter_rule_list filter_list, implied_filter_list, daemon_filter_list;
|
|
|
78df90 |
|
|
|
78df90 |
#ifdef ICONV_OPTION
|
|
|
78df90 |
extern int filesfrom_convert;
|
|
|
78df90 |
@@ -971,6 +971,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
|
|
|
78df90 |
exit_cleanup(RERR_UNSUPPORTED);
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
+ if (*thisname != '.' || thisname[1] != '\0') {
|
|
|
78df90 |
+ int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE;
|
|
|
78df90 |
+ if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */
|
|
|
78df90 |
+ && filter_list.head && check_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
|
|
|
78df90 |
+ rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname);
|
|
|
78df90 |
+ exit_cleanup(RERR_PROTOCOL);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (implied_filter_list.head && check_filter(&implied_filter_list, FINFO, thisname, filt_flags) <= 0) {
|
|
|
78df90 |
+ rprintf(FERROR, "ERROR: rejecting unrequested file-list name: %s\n", thisname);
|
|
|
78df90 |
+ exit_cleanup(RERR_PROTOCOL);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+
|
|
|
78df90 |
if (inc_recurse && S_ISDIR(mode)) {
|
|
|
78df90 |
if (one_file_system) {
|
|
|
78df90 |
/* Room to save the dir's device for -x */
|
|
|
78df90 |
diff --git a/io.c b/io.c
|
|
|
78df90 |
index b50a066..6d0a389 100644
|
|
|
78df90 |
--- a/io.c
|
|
|
78df90 |
+++ b/io.c
|
|
|
78df90 |
@@ -373,6 +373,7 @@ static void forward_filesfrom_data(void)
|
|
|
78df90 |
free_xbuf(&ff_xb);
|
|
|
78df90 |
if (ff_reenable_multiplex >= 0)
|
|
|
78df90 |
io_start_multiplex_out(ff_reenable_multiplex);
|
|
|
78df90 |
+ free_implied_include_partial_string();
|
|
|
78df90 |
}
|
|
|
78df90 |
return;
|
|
|
78df90 |
}
|
|
|
78df90 |
@@ -414,6 +415,7 @@ static void forward_filesfrom_data(void)
|
|
|
78df90 |
while (s != eob) {
|
|
|
78df90 |
if (*s++ == '\0') {
|
|
|
78df90 |
ff_xb.len = s - sob - 1;
|
|
|
78df90 |
+ add_implied_include(sob, 0);
|
|
|
78df90 |
if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0)
|
|
|
78df90 |
exit_cleanup(RERR_PROTOCOL); /* impossible? */
|
|
|
78df90 |
write_buf(iobuf.out_fd, s-1, 1); /* Send the '\0'. */
|
|
|
78df90 |
@@ -429,6 +431,7 @@ static void forward_filesfrom_data(void)
|
|
|
78df90 |
ff_lastchar = '\0';
|
|
|
78df90 |
else {
|
|
|
78df90 |
/* Handle a partial string specially, saving any incomplete chars. */
|
|
|
78df90 |
+ implied_include_partial_string(sob, s);
|
|
|
78df90 |
flags &= ~ICB_INCLUDE_INCOMPLETE;
|
|
|
78df90 |
if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0) {
|
|
|
78df90 |
if (errno == E2BIG)
|
|
|
78df90 |
@@ -445,13 +448,17 @@ static void forward_filesfrom_data(void)
|
|
|
78df90 |
char *f = ff_xb.buf + ff_xb.pos;
|
|
|
78df90 |
char *t = ff_xb.buf;
|
|
|
78df90 |
char *eob = f + len;
|
|
|
78df90 |
+ char *cur = t;
|
|
|
78df90 |
/* Eliminate any multi-'\0' runs. */
|
|
|
78df90 |
while (f != eob) {
|
|
|
78df90 |
if (!(*t++ = *f++)) {
|
|
|
78df90 |
+ add_implied_include(cur, 0);
|
|
|
78df90 |
+ cur = t;
|
|
|
78df90 |
while (f != eob && *f == '\0')
|
|
|
78df90 |
f++;
|
|
|
78df90 |
}
|
|
|
78df90 |
}
|
|
|
78df90 |
+ implied_include_partial_string(cur, t);
|
|
|
78df90 |
ff_lastchar = f[-1];
|
|
|
78df90 |
if ((len = t - ff_xb.buf) != 0) {
|
|
|
78df90 |
/* This will not circle back to perform_io() because we only get
|
|
|
78df90 |
diff --git a/main.c b/main.c
|
|
|
78df90 |
index 46b97b5..f124a2d 100644
|
|
|
78df90 |
--- a/main.c
|
|
|
78df90 |
+++ b/main.c
|
|
|
78df90 |
@@ -48,6 +48,7 @@ extern int called_from_signal_handler;
|
|
|
78df90 |
extern int need_messages_from_generator;
|
|
|
78df90 |
extern int kluge_around_eof;
|
|
|
78df90 |
extern int got_xfer_error;
|
|
|
78df90 |
+extern int old_style_args;
|
|
|
78df90 |
extern int msgs2stderr;
|
|
|
78df90 |
extern int module_id;
|
|
|
78df90 |
extern int read_only;
|
|
|
78df90 |
@@ -87,6 +88,7 @@ extern BOOL shutting_down;
|
|
|
78df90 |
extern int backup_dir_len;
|
|
|
78df90 |
extern int basis_dir_cnt;
|
|
|
78df90 |
extern int default_af_hint;
|
|
|
78df90 |
+extern int trust_sender_filter;
|
|
|
78df90 |
extern struct stats stats;
|
|
|
78df90 |
extern char *stdout_format;
|
|
|
78df90 |
extern char *logfile_format;
|
|
|
78df90 |
@@ -102,7 +104,7 @@ extern char curr_dir[MAXPATHLEN];
|
|
|
78df90 |
extern char backup_dir_buf[MAXPATHLEN];
|
|
|
78df90 |
extern char *basis_dir[MAX_BASIS_DIRS+1];
|
|
|
78df90 |
extern struct file_list *first_flist;
|
|
|
78df90 |
-extern filter_rule_list daemon_filter_list;
|
|
|
78df90 |
+extern filter_rule_list daemon_filter_list, implied_filter_list;
|
|
|
78df90 |
|
|
|
78df90 |
uid_t our_uid;
|
|
|
78df90 |
gid_t our_gid;
|
|
|
78df90 |
@@ -611,11 +613,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
|
|
78df90 |
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
|
|
78df90 |
exit_cleanup(RERR_SYNTAX);
|
|
|
78df90 |
}
|
|
|
78df90 |
- if (**remote_argv == '-') {
|
|
|
78df90 |
- if (asprintf(args + argc++, "./%s", *remote_argv++) < 0)
|
|
|
78df90 |
- out_of_memory("do_cmd");
|
|
|
78df90 |
- } else
|
|
|
78df90 |
- args[argc++] = *remote_argv++;
|
|
|
78df90 |
+ args[argc++] = safe_arg(NULL, *remote_argv++);
|
|
|
78df90 |
remote_argc--;
|
|
|
78df90 |
}
|
|
|
78df90 |
}
|
|
|
78df90 |
@@ -642,6 +640,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
|
|
|
78df90 |
#ifdef ICONV_CONST
|
|
|
78df90 |
setup_iconv();
|
|
|
78df90 |
#endif
|
|
|
78df90 |
+ trust_sender_filter = 1;
|
|
|
78df90 |
} else if (local_server) {
|
|
|
78df90 |
/* If the user didn't request --[no-]whole-file, force
|
|
|
78df90 |
* it on, but only if we're not batch processing. */
|
|
|
78df90 |
@@ -1080,6 +1079,7 @@ static int do_recv(int f_in, int f_out, char *local_name)
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
am_generator = 1;
|
|
|
78df90 |
+ implied_filter_list.head = implied_filter_list.tail = NULL;
|
|
|
78df90 |
flist_receiving_enabled = True;
|
|
|
78df90 |
|
|
|
78df90 |
io_end_multiplex_in(MPLX_SWITCHING);
|
|
|
78df90 |
@@ -1475,6 +1475,10 @@ static int start_client(int argc, char *argv[])
|
|
|
78df90 |
rsync_port = 0;
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
+ /* A local transfer doesn't unbackslash anything, so leave the args alone. */
|
|
|
78df90 |
+ if (local_server)
|
|
|
78df90 |
+ old_style_args = 2;
|
|
|
78df90 |
+
|
|
|
78df90 |
if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */
|
|
|
78df90 |
*remote_argv = ".";
|
|
|
78df90 |
|
|
|
78df90 |
@@ -1500,6 +1504,8 @@ static int start_client(int argc, char *argv[])
|
|
|
78df90 |
char *dummy_host;
|
|
|
78df90 |
int dummy_port = rsync_port;
|
|
|
78df90 |
int i;
|
|
|
78df90 |
+ if (filesfrom_fd < 0)
|
|
|
78df90 |
+ add_implied_include(remote_argv[0], daemon_connection);
|
|
|
78df90 |
/* For remote source, any extra source args must have either
|
|
|
78df90 |
* the same hostname or an empty hostname. */
|
|
|
78df90 |
for (i = 1; i < remote_argc; i++) {
|
|
|
78df90 |
@@ -1523,6 +1529,7 @@ static int start_client(int argc, char *argv[])
|
|
|
78df90 |
if (!rsync_port && !*arg) /* Turn an empty arg into a dot dir. */
|
|
|
78df90 |
arg = ".";
|
|
|
78df90 |
remote_argv[i] = arg;
|
|
|
78df90 |
+ add_implied_include(arg, daemon_connection);
|
|
|
78df90 |
}
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
diff --git a/receiver.c b/receiver.c
|
|
|
78df90 |
index 9df603f..3182e2d 100644
|
|
|
78df90 |
--- a/receiver.c
|
|
|
78df90 |
+++ b/receiver.c
|
|
|
78df90 |
@@ -584,10 +584,13 @@ int recv_files(int f_in, int f_out, char *local_name)
|
|
|
78df90 |
if (DEBUG_GTE(RECV, 1))
|
|
|
78df90 |
rprintf(FINFO, "recv_files(%s)\n", fname);
|
|
|
78df90 |
|
|
|
78df90 |
- if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')
|
|
|
78df90 |
- && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
|
|
|
78df90 |
- rprintf(FERROR, "attempt to hack rsync failed.\n");
|
|
|
78df90 |
- exit_cleanup(RERR_PROTOCOL);
|
|
|
78df90 |
+ if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')) {
|
|
|
78df90 |
+ int filt_flags = S_ISDIR(file->mode) ? NAME_IS_DIR : NAME_IS_FILE;
|
|
|
78df90 |
+ if (check_filter(&daemon_filter_list, FLOG, fname, filt_flags) < 0) {
|
|
|
78df90 |
+ rprintf(FERROR, "ERROR: rejecting file transfer request for daemon excluded file: %s\n",
|
|
|
78df90 |
+ fname);
|
|
|
78df90 |
+ exit_cleanup(RERR_PROTOCOL);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
#ifdef SUPPORT_XATTRS
|
|
|
78df90 |
diff --git a/options.c b/options.c
|
|
|
78df90 |
index 3e530c2..7582236 100644
|
|
|
78df90 |
--- a/options.c
|
|
|
78df90 |
+++ b/options.c
|
|
|
78df90 |
@@ -99,6 +99,7 @@ int filesfrom_fd = -1;
|
|
|
78df90 |
char *filesfrom_host = NULL;
|
|
|
78df90 |
int eol_nulls = 0;
|
|
|
78df90 |
int protect_args = -1;
|
|
|
78df90 |
+int old_style_args = -1;
|
|
|
78df90 |
int human_readable = 1;
|
|
|
78df90 |
int recurse = 0;
|
|
|
78df90 |
int mkpath_dest_arg = 0;
|
|
|
78df90 |
@@ -287,7 +288,7 @@ static struct output_struct debug_words[COUNT_DEBUG+1] = {
|
|
|
78df90 |
DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"),
|
|
|
78df90 |
DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"),
|
|
|
78df90 |
DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"),
|
|
|
78df90 |
- DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"),
|
|
|
78df90 |
+ DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-3)"),
|
|
|
78df90 |
DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"),
|
|
|
78df90 |
DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"),
|
|
|
78df90 |
DEBUG_WORD(GENR, W_REC, "Debug generator functions"),
|
|
|
78df90 |
@@ -575,7 +576,7 @@ enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
|
|
|
78df90 |
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
|
|
|
78df90 |
OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_BLOCK_SIZE,
|
|
|
78df90 |
OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR,
|
|
|
78df90 |
- OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS,
|
|
|
78df90 |
+ OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS, OPT_OLD_ARGS,
|
|
|
78df90 |
OPT_STOP_AFTER, OPT_STOP_AT,
|
|
|
78df90 |
OPT_REFUSED_BASE = 9000};
|
|
|
78df90 |
|
|
|
78df90 |
@@ -779,6 +780,8 @@ static struct poptOption long_options[] = {
|
|
|
78df90 |
{"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 },
|
|
|
78df90 |
{"from0", '0', POPT_ARG_VAL, &eol_nulls, 1, 0, 0},
|
|
|
78df90 |
{"no-from0", 0, POPT_ARG_VAL, &eol_nulls, 0, 0, 0},
|
|
|
78df90 |
+ {"old-args", 0, POPT_ARG_NONE, 0, OPT_OLD_ARGS, 0, 0},
|
|
|
78df90 |
+ {"no-old-args", 0, POPT_ARG_VAL, &old_style_args, 0, 0, 0},
|
|
|
78df90 |
{"protect-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0},
|
|
|
78df90 |
{"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
|
|
|
78df90 |
{"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
|
|
|
78df90 |
@@ -1605,6 +1608,13 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
|
|
78df90 |
compress_choice = NULL;
|
|
|
78df90 |
break;
|
|
|
78df90 |
|
|
|
78df90 |
+ case OPT_OLD_ARGS:
|
|
|
78df90 |
+ if (old_style_args <= 0)
|
|
|
78df90 |
+ old_style_args = 1;
|
|
|
78df90 |
+ else
|
|
|
78df90 |
+ old_style_args++;
|
|
|
78df90 |
+ break;
|
|
|
78df90 |
+
|
|
|
78df90 |
case 'M':
|
|
|
78df90 |
arg = poptGetOptArg(pc);
|
|
|
78df90 |
if (*arg != '-') {
|
|
|
78df90 |
@@ -1914,6 +1924,21 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
|
|
78df90 |
max_alloc = size;
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
+ if (old_style_args < 0) {
|
|
|
78df90 |
+ if (!am_server && protect_args <= 0 && (arg = getenv("RSYNC_OLD_ARGS")) != NULL && *arg) {
|
|
|
78df90 |
+ protect_args = 0;
|
|
|
78df90 |
+ old_style_args = atoi(arg);
|
|
|
78df90 |
+ } else
|
|
|
78df90 |
+ old_style_args = 0;
|
|
|
78df90 |
+ } else if (old_style_args) {
|
|
|
78df90 |
+ if (protect_args > 0) {
|
|
|
78df90 |
+ snprintf(err_buf, sizeof err_buf,
|
|
|
78df90 |
+ "--protect-args conflicts with --old-args.\n");
|
|
|
78df90 |
+ return 0;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ protect_args = 0;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+
|
|
|
78df90 |
if (protect_args < 0) {
|
|
|
78df90 |
if (am_server)
|
|
|
78df90 |
protect_args = 0;
|
|
|
78df90 |
@@ -2451,6 +2476,71 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
|
|
|
78df90 |
+static char SPLIT_ARG_WHEN_OLD[1];
|
|
|
78df90 |
+
|
|
|
78df90 |
+/**
|
|
|
78df90 |
+ * Do backslash quoting of any weird chars in "arg", append the resulting
|
|
|
78df90 |
+ * string to the end of the "opt" (which gets a "=" appended if it is not
|
|
|
78df90 |
+ * an empty or NULL string), and return the (perhaps malloced) result.
|
|
|
78df90 |
+ * If opt is NULL, arg is considered a filename arg that allows wildcards.
|
|
|
78df90 |
+ * If it is "" or any other value, it is considered an option.
|
|
|
78df90 |
+ **/
|
|
|
78df90 |
+char *safe_arg(const char *opt, const char *arg)
|
|
|
78df90 |
+{
|
|
|
78df90 |
+#define SHELL_CHARS "!#$&;|<>(){}\"' \t\\"
|
|
|
78df90 |
+#define WILD_CHARS "*?[]" /* We don't allow remote brace expansion */
|
|
|
78df90 |
+ BOOL is_filename_arg = !opt;
|
|
|
78df90 |
+ char *escapes = is_filename_arg ? SHELL_CHARS : WILD_CHARS SHELL_CHARS;
|
|
|
78df90 |
+ BOOL escape_leading_dash = is_filename_arg && *arg == '-';
|
|
|
78df90 |
+ BOOL escape_leading_tilde = 0;
|
|
|
78df90 |
+ int len1 = opt && *opt ? strlen(opt) + 1 : 0;
|
|
|
78df90 |
+ int len2 = strlen(arg);
|
|
|
78df90 |
+ int extras = escape_leading_dash ? 2 : 0;
|
|
|
78df90 |
+ char *ret;
|
|
|
78df90 |
+ if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) {
|
|
|
78df90 |
+ const char *f;
|
|
|
78df90 |
+ if (!old_style_args && *arg == '~' && (relative_paths || !strchr(arg, '/'))) {
|
|
|
78df90 |
+ extras++;
|
|
|
78df90 |
+ escape_leading_tilde = 1;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ for (f = arg; *f; f++) {
|
|
|
78df90 |
+ if (strchr(escapes, *f))
|
|
|
78df90 |
+ extras++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (!len1 && !extras)
|
|
|
78df90 |
+ return (char*)arg;
|
|
|
78df90 |
+ ret = new_array(char, len1 + len2 + extras + 1);
|
|
|
78df90 |
+ if (len1) {
|
|
|
78df90 |
+ memcpy(ret, opt, len1-1);
|
|
|
78df90 |
+ ret[len1-1] = '=';
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (escape_leading_dash) {
|
|
|
78df90 |
+ ret[len1++] = '.';
|
|
|
78df90 |
+ ret[len1++] = '/';
|
|
|
78df90 |
+ extras -= 2;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (!extras)
|
|
|
78df90 |
+ memcpy(ret + len1, arg, len2);
|
|
|
78df90 |
+ else {
|
|
|
78df90 |
+ const char *f = arg;
|
|
|
78df90 |
+ char *t = ret + len1;
|
|
|
78df90 |
+ if (escape_leading_tilde)
|
|
|
78df90 |
+ *t++ = '\\';
|
|
|
78df90 |
+ while (*f) {
|
|
|
78df90 |
+ if (*f == '\\') {
|
|
|
78df90 |
+ if (!is_filename_arg || !strchr(WILD_CHARS, f[1]))
|
|
|
78df90 |
+ *t++ = '\\';
|
|
|
78df90 |
+ } else if (strchr(escapes, *f))
|
|
|
78df90 |
+ *t++ = '\\';
|
|
|
78df90 |
+ *t++ = *f++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ ret[len1+len2+extras] = '\0';
|
|
|
78df90 |
+ return ret;
|
|
|
78df90 |
+}
|
|
|
78df90 |
+
|
|
|
78df90 |
+
|
|
|
78df90 |
/**
|
|
|
78df90 |
* Construct a filtered list of options to pass through from the
|
|
|
78df90 |
* client to the server.
|
|
|
78df90 |
@@ -2633,9 +2723,7 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
set++;
|
|
|
78df90 |
else
|
|
|
78df90 |
set = iconv_opt;
|
|
|
78df90 |
- if (asprintf(&arg, "--iconv=%s", set) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
+ args[ac++] = safe_arg("--iconv", set);
|
|
|
78df90 |
}
|
|
|
78df90 |
#endif
|
|
|
78df90 |
|
|
|
78df90 |
@@ -2701,33 +2789,24 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
if (backup_dir) {
|
|
|
78df90 |
+ /* This split idiom allows for ~/path expansion via the shell. */
|
|
|
78df90 |
args[ac++] = "--backup-dir";
|
|
|
78df90 |
- args[ac++] = backup_dir;
|
|
|
78df90 |
+ args[ac++] = safe_arg("", backup_dir);
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
/* Only send --suffix if it specifies a non-default value. */
|
|
|
78df90 |
- if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
|
|
|
78df90 |
- /* We use the following syntax to avoid weirdness with '~'. */
|
|
|
78df90 |
- if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--suffix", backup_suffix);
|
|
|
78df90 |
|
|
|
78df90 |
- if (checksum_choice) {
|
|
|
78df90 |
- if (asprintf(&arg, "--checksum-choice=%s", checksum_choice) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (checksum_choice)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--checksum-choice", checksum_choice);
|
|
|
78df90 |
|
|
|
78df90 |
if (do_compression == CPRES_ZLIBX)
|
|
|
78df90 |
args[ac++] = "--new-compress";
|
|
|
78df90 |
else if (compress_choice && do_compression == CPRES_ZLIB)
|
|
|
78df90 |
args[ac++] = "--old-compress";
|
|
|
78df90 |
- else if (compress_choice) {
|
|
|
78df90 |
- if (asprintf(&arg, "--compress-choice=%s", compress_choice) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ else if (compress_choice)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--compress-choice", compress_choice);
|
|
|
78df90 |
|
|
|
78df90 |
if (am_sender) {
|
|
|
78df90 |
if (max_delete > 0) {
|
|
|
78df90 |
@@ -2736,14 +2815,10 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
args[ac++] = arg;
|
|
|
78df90 |
} else if (max_delete == 0)
|
|
|
78df90 |
args[ac++] = "--max-delete=-1";
|
|
|
78df90 |
- if (min_size >= 0) {
|
|
|
78df90 |
- args[ac++] = "--min-size";
|
|
|
78df90 |
- args[ac++] = min_size_arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
- if (max_size >= 0) {
|
|
|
78df90 |
- args[ac++] = "--max-size";
|
|
|
78df90 |
- args[ac++] = max_size_arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (min_size >= 0)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--min-size", min_size_arg);
|
|
|
78df90 |
+ if (max_size >= 0)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--max-size", max_size_arg);
|
|
|
78df90 |
if (delete_before)
|
|
|
78df90 |
args[ac++] = "--delete-before";
|
|
|
78df90 |
else if (delete_during == 2)
|
|
|
78df90 |
@@ -2767,17 +2842,12 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
if (do_stats)
|
|
|
78df90 |
args[ac++] = "--stats";
|
|
|
78df90 |
} else {
|
|
|
78df90 |
- if (skip_compress) {
|
|
|
78df90 |
- if (asprintf(&arg, "--skip-compress=%s", skip_compress) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (skip_compress)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--skip-compress", skip_compress);
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
- if (max_alloc_arg && max_alloc != DEFAULT_MAX_ALLOC) {
|
|
|
78df90 |
- args[ac++] = "--max-alloc";
|
|
|
78df90 |
- args[ac++] = max_alloc_arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (max_alloc_arg && max_alloc != DEFAULT_MAX_ALLOC)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--max-alloc", max_alloc_arg);
|
|
|
78df90 |
|
|
|
78df90 |
/* --delete-missing-args needs the cooperation of both sides, but
|
|
|
78df90 |
* the sender can handle --ignore-missing-args by itself. */
|
|
|
78df90 |
@@ -2802,7 +2872,7 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
if (partial_dir && am_sender) {
|
|
|
78df90 |
if (partial_dir != tmp_partialdir) {
|
|
|
78df90 |
args[ac++] = "--partial-dir";
|
|
|
78df90 |
- args[ac++] = partial_dir;
|
|
|
78df90 |
+ args[ac++] = safe_arg("", partial_dir);
|
|
|
78df90 |
}
|
|
|
78df90 |
if (delay_updates)
|
|
|
78df90 |
args[ac++] = "--delay-updates";
|
|
|
78df90 |
@@ -2825,17 +2895,11 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
args[ac++] = "--use-qsort";
|
|
|
78df90 |
|
|
|
78df90 |
if (am_sender) {
|
|
|
78df90 |
- if (usermap) {
|
|
|
78df90 |
- if (asprintf(&arg, "--usermap=%s", usermap) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (usermap)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--usermap", usermap);
|
|
|
78df90 |
|
|
|
78df90 |
- if (groupmap) {
|
|
|
78df90 |
- if (asprintf(&arg, "--groupmap=%s", groupmap) < 0)
|
|
|
78df90 |
- goto oom;
|
|
|
78df90 |
- args[ac++] = arg;
|
|
|
78df90 |
- }
|
|
|
78df90 |
+ if (groupmap)
|
|
|
78df90 |
+ args[ac++] = safe_arg("--groupmap", groupmap);
|
|
|
78df90 |
|
|
|
78df90 |
if (ignore_existing)
|
|
|
78df90 |
args[ac++] = "--ignore-existing";
|
|
|
78df90 |
@@ -2846,7 +2910,7 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
|
|
|
78df90 |
if (tmpdir) {
|
|
|
78df90 |
args[ac++] = "--temp-dir";
|
|
|
78df90 |
- args[ac++] = tmpdir;
|
|
|
78df90 |
+ args[ac++] = safe_arg("", tmpdir);
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
if (basis_dir[0]) {
|
|
|
78df90 |
@@ -2856,7 +2920,7 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
*/
|
|
|
78df90 |
for (i = 0; i < basis_dir_cnt; i++) {
|
|
|
78df90 |
args[ac++] = alt_dest_opt(0);
|
|
|
78df90 |
- args[ac++] = basis_dir[i];
|
|
|
78df90 |
+ args[ac++] = safe_arg("", basis_dir[i]);
|
|
|
78df90 |
}
|
|
|
78df90 |
}
|
|
|
78df90 |
}
|
|
|
78df90 |
@@ -2877,7 +2941,7 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
if (files_from && (!am_sender || filesfrom_host)) {
|
|
|
78df90 |
if (filesfrom_host) {
|
|
|
78df90 |
args[ac++] = "--files-from";
|
|
|
78df90 |
- args[ac++] = files_from;
|
|
|
78df90 |
+ args[ac++] = safe_arg("", files_from);
|
|
|
78df90 |
if (eol_nulls)
|
|
|
78df90 |
args[ac++] = "--from0";
|
|
|
78df90 |
} else {
|
|
|
78df90 |
@@ -2923,7 +2987,7 @@ void server_options(char **args, int *argc_p)
|
|
|
78df90 |
exit_cleanup(RERR_SYNTAX);
|
|
|
78df90 |
}
|
|
|
78df90 |
for (j = 1; j <= remote_option_cnt; j++)
|
|
|
78df90 |
- args[ac++] = (char*)remote_options[j];
|
|
|
78df90 |
+ args[ac++] = safe_arg(SPLIT_ARG_WHEN_OLD, remote_options[j]);
|
|
|
78df90 |
}
|
|
|
78df90 |
|
|
|
78df90 |
*argc_p = ac;
|
|
|
78df90 |
diff --git a/clientserver.c b/clientserver.c
|
|
|
78df90 |
index 48c15a6..feca9c8 100644
|
|
|
78df90 |
--- a/clientserver.c
|
|
|
78df90 |
+++ b/clientserver.c
|
|
|
78df90 |
@@ -47,6 +47,7 @@ extern int protocol_version;
|
|
|
78df90 |
extern int io_timeout;
|
|
|
78df90 |
extern int no_detach;
|
|
|
78df90 |
extern int write_batch;
|
|
|
78df90 |
+extern int old_style_args;
|
|
|
78df90 |
extern int default_af_hint;
|
|
|
78df90 |
extern int logfile_format_has_i;
|
|
|
78df90 |
extern int logfile_format_has_o_or_i;
|
|
|
78df90 |
@@ -288,20 +289,45 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
|
|
|
78df90 |
|
|
|
78df90 |
sargs[sargc++] = ".";
|
|
|
78df90 |
|
|
|
78df90 |
+ if (!old_style_args)
|
|
|
78df90 |
+ snprintf(line, sizeof line, " %.*s/", modlen, modname);
|
|
|
78df90 |
+
|
|
|
78df90 |
while (argc > 0) {
|
|
|
78df90 |
if (sargc >= MAX_ARGS - 1) {
|
|
|
78df90 |
arg_overflow:
|
|
|
78df90 |
rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
|
|
|
78df90 |
exit_cleanup(RERR_SYNTAX);
|
|
|
78df90 |
}
|
|
|
78df90 |
- if (strncmp(*argv, modname, modlen) == 0
|
|
|
78df90 |
- && argv[0][modlen] == '\0')
|
|
|
78df90 |
+ if (strncmp(*argv, modname, modlen) == 0 && argv[0][modlen] == '\0')
|
|
|
78df90 |
sargs[sargc++] = modname; /* we send "modname/" */
|
|
|
78df90 |
- else if (**argv == '-') {
|
|
|
78df90 |
- if (asprintf(sargs + sargc++, "./%s", *argv) < 0)
|
|
|
78df90 |
- out_of_memory("start_inband_exchange");
|
|
|
78df90 |
- } else
|
|
|
78df90 |
- sargs[sargc++] = *argv;
|
|
|
78df90 |
+ else {
|
|
|
78df90 |
+ char *arg = *argv;
|
|
|
78df90 |
+ int extra_chars = *arg == '-' ? 2 : 0; /* a leading dash needs a "./" prefix. */
|
|
|
78df90 |
+ /* If --old-args was not specified, make sure that the arg won't split at a mod name! */
|
|
|
78df90 |
+ if (!old_style_args && (p = strstr(arg, line)) != NULL) {
|
|
|
78df90 |
+ do {
|
|
|
78df90 |
+ extra_chars += 2;
|
|
|
78df90 |
+ } while ((p = strstr(p+1, line)) != NULL);
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ if (extra_chars) {
|
|
|
78df90 |
+ char *f = arg;
|
|
|
78df90 |
+ char *t = arg = new_array(char, strlen(arg) + extra_chars + 1);
|
|
|
78df90 |
+ if (*f == '-') {
|
|
|
78df90 |
+ *t++ = '.';
|
|
|
78df90 |
+ *t++ = '/';
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ while (*f) {
|
|
|
78df90 |
+ if (*f == ' ' && strncmp(f, line, modlen+2) == 0) {
|
|
|
78df90 |
+ *t++ = '[';
|
|
|
78df90 |
+ *t++ = *f++;
|
|
|
78df90 |
+ *t++ = ']';
|
|
|
78df90 |
+ } else
|
|
|
78df90 |
+ *t++ = *f++;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ *t = '\0';
|
|
|
78df90 |
+ }
|
|
|
78df90 |
+ sargs[sargc++] = arg;
|
|
|
78df90 |
+ }
|
|
|
78df90 |
argv++;
|
|
|
78df90 |
argc--;
|
|
|
78df90 |
}
|
|
|
78df90 |
diff --git a/rsync.1 b/rsync.1
|
|
|
78df90 |
index e0e13cf..e363827 100644
|
|
|
78df90 |
--- a/rsync.1
|
|
|
78df90 |
+++ b/rsync.1
|
|
|
78df90 |
@@ -194,32 +194,27 @@ the hostname omitted. For instance, all these work:
|
|
|
78df90 |
.nf
|
|
|
78df90 |
rsync -av host:file1 :file2 host:file{3,4} /dest/
|
|
|
78df90 |
rsync -av host::modname/file{1,2} host::modname/file3 /dest/
|
|
|
78df90 |
-rsync -av host::modname/file1 ::modname/file{3,4}
|
|
|
78df90 |
+rsync -av host::modname/file1 ::modname/file{3,4} /dest/
|
|
|
78df90 |
.fi
|
|
|
78df90 |
.RE
|
|
|
78df90 |
.P
|
|
|
78df90 |
-Older versions of rsync required using quoted spaces in the SRC, like these
|
|
|
78df90 |
-examples:
|
|
|
78df90 |
+Starting this version of rsync, filenames are passed to a remote shell
|
|
|
78df90 |
+in such a way as to preserve the characters you give it.
|
|
|
78df90 |
+Thus, if you ask for a file with spaces in the name, that's what the
|
|
|
78df90 |
+remote rsync looks for:
|
|
|
78df90 |
.RS 4
|
|
|
78df90 |
.P
|
|
|
78df90 |
.nf
|
|
|
78df90 |
-rsync -av host:'dir1/file1 dir2/file2' /dest
|
|
|
78df90 |
-rsync host::'modname/dir1/file1 modname/dir2/file2' /dest
|
|
|
78df90 |
+rsync -aiv host:'a simple file.pdf' /dest/
|
|
|
78df90 |
.fi
|
|
|
78df90 |
.RE
|
|
|
78df90 |
.P
|
|
|
78df90 |
-This word-splitting still works (by default) in the latest rsync, but is not as
|
|
|
78df90 |
-easy to use as the first method.
|
|
|
78df90 |
-.P
|
|
|
78df90 |
-If you need to transfer a filename that contains whitespace, you can either
|
|
|
78df90 |
-specify the \fB\-\-protect-args\fP (\fB\-s\fP) option, or you'll need to escape the
|
|
|
78df90 |
-whitespace in a way that the remote shell will understand. For instance:
|
|
|
78df90 |
-.RS 4
|
|
|
78df90 |
-.P
|
|
|
78df90 |
-.nf
|
|
|
78df90 |
-rsync -av host:'file\\ name\\ with\\ spaces' /dest
|
|
|
78df90 |
-.fi
|
|
|
78df90 |
-.RE
|
|
|
78df90 |
+If you use scripts that have been written to manually apply extra quoting to
|
|
|
78df90 |
+the remote rsync args (or to require remote arg splitting), you can ask rsync
|
|
|
78df90 |
+to let your script handle the extra escaping. This is done by either adding
|
|
|
78df90 |
+the \fB\-\-old\-args\fP option to the rsync runs in the script (which requires
|
|
|
78df90 |
+a new rsync) or exporting \fBRSYNC_OLD_ARGS\fP=1 and \fBRSYNC_PROTECT_ARGS\fP=0
|
|
|
78df90 |
+(which works with old or new rsync versions).
|
|
|
78df90 |
.P
|
|
|
78df90 |
.SH "CONNECTING TO AN RSYNC DAEMON"
|
|
|
78df90 |
.P
|
|
|
78df90 |
@@ -427,6 +422,7 @@ detailed description below for a complete description.
|
|
|
78df90 |
--append append data onto shorter files
|
|
|
78df90 |
--append-verify --append w/old data in file checksum
|
|
|
78df90 |
--dirs, -d transfer directories without recursing
|
|
|
78df90 |
+--old-dirs, --old-d works like --dirs when talking to old rsync
|
|
|
78df90 |
--mkpath create the destination's path component
|
|
|
78df90 |
--links, -l copy symlinks as symlinks
|
|
|
78df90 |
--copy-links, -L transform symlink into referent file/dir
|
|
|
78df90 |
@@ -515,6 +511,7 @@ detailed description below for a complete description.
|
|
|
78df90 |
--include-from=FILE read include patterns from FILE
|
|
|
78df90 |
--files-from=FILE read list of source-file names from FILE
|
|
|
78df90 |
--from0, -0 all *-from/filter files are delimited by 0s
|
|
|
78df90 |
+--old-args disable the modern arg-protection idiom
|
|
|
78df90 |
--protect-args, -s no space-splitting; wildcard chars only
|
|
|
78df90 |
--copy-as=USER[:GROUP] specify user & optional group for the copy
|
|
|
78df90 |
--address=ADDRESS bind address for outgoing socket to daemon
|
|
|
78df90 |
@@ -1950,11 +1947,10 @@ Be cautious using this, as it is possible to toggle an option that will
|
|
|
78df90 |
cause rsync to have a different idea about what data to expect next over
|
|
|
78df90 |
the socket, and that will make it fail in a cryptic fashion.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
-Note that it is best to use a separate \fB\-\-remote-option\fP for each option
|
|
|
78df90 |
-you want to pass. This makes your usage compatible with the
|
|
|
78df90 |
-\fB\-\-protect-args\fP option. If that option is off, any spaces in your remote
|
|
|
78df90 |
-options will be split by the remote shell unless you take steps to protect
|
|
|
78df90 |
-them.
|
|
|
78df90 |
+Note that you should use a separate \fB\-M\fP for each remote option you
|
|
|
78df90 |
+want to pass. On older rsync versions, the presence of any spaces in the
|
|
|
78df90 |
+remote-option arg could cause it to be split into separate remote args, but
|
|
|
78df90 |
+this requires the use of \fB\-\-old\-args\fP in this version of rsync.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
When performing a local transfer, the "local" side is the sender and the
|
|
|
78df90 |
"remote" side is the receiver.
|
|
|
78df90 |
@@ -2169,26 +2165,64 @@ terminated by a null ('\\0') character, not a NL, CR, or CR+LF. This
|
|
|
78df90 |
affects \fB\-\-exclude-from\fP, \fB\-\-include-from\fP, \fB\-\-files-from\fP, and any merged
|
|
|
78df90 |
files specified in a \fB\-\-filter\fP rule. It does not affect \fB\-\-cvs-exclude\fP
|
|
|
78df90 |
(since all names read from a .cvsignore file are split on whitespace).
|
|
|
78df90 |
+.IP "\fB\-\-old\-args\fP"
|
|
|
78df90 |
+This option tells rsync to stop trying to protect the arg values from
|
|
|
78df90 |
+unintended word-splitting or other misinterpretation by using its new
|
|
|
78df90 |
+backslash-escape idiom. The newest default is for remote filenames to only
|
|
|
78df90 |
+allow wildcards characters to be interpretated by the shell while
|
|
|
78df90 |
+protecting other shell-interpreted characters (and the args of options get
|
|
|
78df90 |
+even wildcards escaped). The only active wildcard characters on the remote
|
|
|
78df90 |
+side are: `*`, `?`, `[`, & `]`.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+If you have a script that wants to use old-style arg splitting in the
|
|
|
78df90 |
+filenames, specify this option once. If the remote shell has a problem
|
|
|
78df90 |
+with any backslash escapes, specify the option twice.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+You may also control this setting via the RSYNC_OLD_ARGS environment
|
|
|
78df90 |
+variable. If it has the value "1", rsync will default to a single-option
|
|
|
78df90 |
+setting. If it has the value "2" (or more), rsync will default to a
|
|
|
78df90 |
+repeated-option setting. If it is "0", you'll get the default escaping
|
|
|
78df90 |
+behavior. The environment is always overridden by manually specified
|
|
|
78df90 |
+positive or negative options (the negative is \fB\-\-no\-old\-args\fP).
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+Note that this option also disables the extra safety check added in this
|
|
|
78df90 |
+version of rsync,
|
|
|
78df90 |
+that ensures that a remote sender isn't including extra top-level items in
|
|
|
78df90 |
+the file-list that you didn't request. This side-effect is necessary
|
|
|
78df90 |
+because we can't know for sure what names to expect when the remote shell
|
|
|
78df90 |
+is interpreting the args.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+This option conflicts with the \fB\-\-protect\-args\fP option.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
.IP "\fB\-\-protect-args\fP, \fB\-s\fP"
|
|
|
78df90 |
This option sends all filenames and most options to the remote rsync
|
|
|
78df90 |
-without allowing the remote shell to interpret them. This means that
|
|
|
78df90 |
-spaces are not split in names, and any non-wildcard special characters are
|
|
|
78df90 |
-not translated (such as \fB~\fP, \fB$\fP, \fB;\fP, \fB&\fP, etc.). Wildcards are expanded
|
|
|
78df90 |
-on the remote host by rsync (instead of the shell doing it).
|
|
|
78df90 |
+without allowing the remote shell to interpret them. Wildcards are
|
|
|
78df90 |
+expanded on the remote host by rsync instead of the shell doing it.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+This is similar to the new-style backslash-escaping of args that was added
|
|
|
78df90 |
+in this version of rsync, but supports some extra features and doesn't
|
|
|
78df90 |
+rely on backslash escaping in the remote shell.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
If you use this option with \fB\-\-iconv\fP, the args related to the remote side
|
|
|
78df90 |
will also be translated from the local to the remote character-set. The
|
|
|
78df90 |
translation happens before wild-cards are expanded. See also the
|
|
|
78df90 |
\fB\-\-files-from\fP option.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
-You may also control this option via the RSYNC_PROTECT_ARGS environment
|
|
|
78df90 |
-variable. If this variable has a non-zero value, this option will be
|
|
|
78df90 |
-enabled by default, otherwise it will be disabled by default. Either state
|
|
|
78df90 |
+You may also control this setting via the RSYNC_PROTECT_ARGS environment
|
|
|
78df90 |
+variable. If it has a non-zero value, this setting will be enabled
|
|
|
78df90 |
+by default, otherwise it will be disabled by default. Either state
|
|
|
78df90 |
is overridden by a manually specified positive or negative version of this
|
|
|
78df90 |
option (note that \fB\-\-no-s\fP and \fB\-\-no-protect-args\fP are the negative
|
|
|
78df90 |
-versions). Since this option was first introduced in 3.0.0, you'll need to
|
|
|
78df90 |
-make sure it's disabled if you ever need to interact with a remote rsync
|
|
|
78df90 |
-that is older than that.
|
|
|
78df90 |
+versions). This environment variable is also superseded by a non-zero
|
|
|
78df90 |
+\fBRSYNC_OLD_ARGS\fP export.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+You may need to disable this option when interacting with an older rsync
|
|
|
78df90 |
+(one prior to 3.0.0).
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+This option conflicts with the \fB\-\-old\-args\fP option.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+Note that this option is incompatible with the use of the restricted rsync
|
|
|
78df90 |
+script (`rrsync`) since it hides options from the script's inspection.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
Rsync can also be configured (at build time) to have this option enabled by
|
|
|
78df90 |
default (with is overridden by both the environment and the command-line).
|
|
|
78df90 |
@@ -2675,7 +2708,10 @@ super-user (see also the \fB\-\-fake-super\fP option). For the \fB\-\-groupmap\
|
|
|
78df90 |
option to have any effect, the \fB\-g\fP (\fB\-\-groups\fP) option must be used (or
|
|
|
78df90 |
implied), and the receiver will need to have permissions to set that group.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
-If your shell complains about the wildcards, use \fB\-\-protect-args\fP (\fB\-s\fP).
|
|
|
78df90 |
+An older rsync client may need to use \fB\-\-protect\-args\fP (\fB\-s\fP)
|
|
|
78df90 |
+to avoid a complaint about wildcard characters, but a modern rsync handles
|
|
|
78df90 |
+this automatically.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
.IP "\fB\-\-chown=USER:GROUP\fP"
|
|
|
78df90 |
This option forces all files to be owned by USER with group GROUP. This is
|
|
|
78df90 |
a simpler interface than using \fB\-\-usermap\fP and \fB\-\-groupmap\fP directly, but
|
|
|
78df90 |
@@ -2685,8 +2721,11 @@ will occur. If GROUP is empty, the trailing colon may be omitted, but if
|
|
|
78df90 |
USER is empty, a leading colon must be supplied.
|
|
|
78df90 |
.IP
|
|
|
78df90 |
If you specify "\fB\-\-chown=foo:bar\fP", this is exactly the same as specifying
|
|
|
78df90 |
-"\fB\-\-usermap=*:foo\ \-\-groupmap=*:bar\fP", only easier. If your shell complains
|
|
|
78df90 |
-about the wildcards, use \fB\-\-protect-args\fP (\fB\-s\fP).
|
|
|
78df90 |
+"\fB\-\-usermap=*:foo\ \-\-groupmap=*:bar\fP", only easier.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+An older rsync client may need to use \fB\-\-protect\-args\fP (\fB\-s\fP) to avoid a
|
|
|
78df90 |
+complaint about wildcard characters, but a modern rsync handles this
|
|
|
78df90 |
+automatically.
|
|
|
78df90 |
.IP "\fB\-\-timeout=SECONDS\fP"
|
|
|
78df90 |
This option allows you to set a maximum I/O timeout in seconds. If no data
|
|
|
78df90 |
is transferred for the specified time then rsync will exit. The default is
|
|
|
78df90 |
@@ -4233,10 +4272,24 @@ The CVSIGNORE environment variable supplements any ignore patterns in
|
|
|
78df90 |
.IP "\fBRSYNC_ICONV\fP"
|
|
|
78df90 |
Specify a default \fB\-\-iconv\fP setting using this environment variable. (First
|
|
|
78df90 |
supported in 3.0.0.)
|
|
|
78df90 |
+.IP "\fBRSYNC_OLD_ARGS\fP"
|
|
|
78df90 |
+Specify a "1" if you want the \fB\-\-old\-args\fP option to be enabled by default,
|
|
|
78df90 |
+a "2" (or more) if you want it to be enabled in the option-repeated state,
|
|
|
78df90 |
+or a "0" to make sure that it is disabled by default. When this environment
|
|
|
78df90 |
+variable is set to a non-zero value, it supersedes the \fBRSYNC_PROTECT_ARGS\fP
|
|
|
78df90 |
+variable.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+This variable is ignored if \fB\-\-old\-args\fP, \fB\-\-no\-old\-args\fP, or
|
|
|
78df90 |
+\fB\-\-protect\-args\fP is specified on the command line.
|
|
|
78df90 |
.IP "\fBRSYNC_PROTECT_ARGS\fP"
|
|
|
78df90 |
Specify a non-zero numeric value if you want the \fB\-\-protect-args\fP option to
|
|
|
78df90 |
be enabled by default, or a zero value to make sure that it is disabled by
|
|
|
78df90 |
default. (First supported in 3.1.0.)
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+This variable is ignored if \fB\-\-protect\-args\fP, \fB\-\-no\-protect\-args\fP,
|
|
|
78df90 |
+or \fB\-\-old\-args\fP is specified on the command line.
|
|
|
78df90 |
+.IP
|
|
|
78df90 |
+This variable is ignored if \fBRSYNC_OLD_ARGS\fP is set to a non-zero value.
|
|
|
78df90 |
.IP "\fBRSYNC_RSH\fP"
|
|
|
78df90 |
The RSYNC_RSH environment variable allows you to override the default shell
|
|
|
78df90 |
used as the transport for rsync. Command line options are permitted after
|