diff --git a/INSTALL.md b/INSTALL.md
index 5b23ed0e..1605ab43 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -26,7 +26,7 @@ build user (after installing python3's pip package):
You can test if you've got it fixed by running (from the rsync checkout):
-> ./md2man --test rsync-ssl.1.md
+> ./md-convert --test rsync-ssl.1.md
Alternately, you can avoid generating the manpages by fetching the very latest
versions (that match the latest git source) from the [generated-files][6] dir.
diff --git a/NEWS.md b/NEWS.md
index 187f2fdb..e32600c5 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,62 @@
+# NEWS for rsync 3.2.5 (14 Aug 2022)
+
+## Changes in this version:
+
+### SECURITY FIXES:
+
+- Added some file-list safety checking that helps to ensure that a rogue
+ sending rsync can't add unrequested top-level names and/or include recursive
+ names that should have been excluded by the sender. These extra safety
+ checks only require the receiver rsync to be updated. When dealing with an
+ untrusted sending host, it is safest to copy into a dedicated destination
+ directory for the remote content (i.e. don't copy into a destination
+ directory that contains files that aren't from the remote host unless you
+ trust the remote host). Fixes CVE-2022-29154.
+
+ - A fix for CVE-2022-37434 in the bundled zlib (buffer overflow issue).
+
+### BUG FIXES:
+
+- Fixed the handling of filenames specified with backslash-quoted wildcards
+ when the default remote-arg-escaping is enabled.
+
+- Fixed the configure check for signed char that was causing a host that
+ defaults to unsigned characters to generate bogus rolling checksums. This
+ made rsync send mostly literal data for a copy instead of finding matching
+ data in the receiver's basis file (for a file that contains high-bit
+ characters).
+
+- Lots of manpage improvements, including an attempt to better describe how
+ include/exclude filters work.
+
+- If rsync is compiled with an xxhash 0.8 library and then moved to a system
+ with a dynamically linked xxhash 0.7 library, we now detect this and disable
+ the XX3 hashes (since these routines didn't stabilize until 0.8).
+
+### ENHANCEMENTS:
+
+- The [`--trust-sender`](rsync.1#opt) option was added as a way to bypass the
+ extra file-list safety checking (should that be required).
+
+### PACKAGING RELATED:
+
+- A note to those wanting to patch older rsync versions: the changes in this
+ release requires the quoted argument change from 3.2.4. Then, you'll want
+ every single code change from 3.2.5 since there is no fluff in this release.
+
+- The build date that goes into the manpages is now based on the developer's
+ release date, not on the build's local-timezone interpretation of the date.
+
+### DEVELOPER RELATED:
+
+- Configure now defaults GETGROUPS_T to gid_t when cross compiling.
+
+- Configure now looks for the bsd/string.h include file in order to fix the
+ build on a host that has strlcpy() in the main libc but not defined in the
+ main string.h file.
+
+------------------------------------------------------------------------------
+
# NEWS for rsync 3.2.4 (15 Apr 2022)
## Changes in this version:
@@ -4482,6 +4541,7 @@
| RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL |
|--------------|--------|------------------|-------------|
+| 14 Aug 2022 | 3.2.5 | | 31 |
| 15 Apr 2022 | 3.2.4 | | 31 |
| 06 Aug 2020 | 3.2.3 | | 31 |
| 04 Jul 2020 | 3.2.2 | | 31 |
diff --git a/batch.c b/batch.c
index a9711c56..accc4c6e 100644
--- a/batch.c
+++ b/batch.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1999 Weiss
* Copyright (C) 2004 Chris Shoemaker
- * Copyright (C) 2004-2020 Wayne Davison
+ * Copyright (C) 2004-2022 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -194,7 +194,7 @@ static int write_opt(const char *opt, const char *arg)
{
int len = strlen(opt);
int err = write(batch_sh_fd, " ", 1) != 1;
- err = write(batch_sh_fd, opt, len) != len ? 1 : 0;
+ err = write(batch_sh_fd, opt, len) != len ? 1 : 0;
if (arg) {
err |= write(batch_sh_fd, "=", 1) != 1;
err |= write_arg(arg);
diff --git a/byteorder.h b/byteorder.h
index 525eaba0..059cc708 100644
--- a/byteorder.h
+++ b/byteorder.h
@@ -2,7 +2,7 @@
* Simple byteorder handling.
*
* Copyright (C) 1992-1995 Andrew Tridgell
- * Copyright (C) 2007-2020 Wayne Davison
+ * Copyright (C) 2007-2022 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -129,4 +129,3 @@ SIVAL(char *buf, int pos, uint32 val)
{
SIVALu((uchar*)buf, pos, val);
}
-
diff --git a/checksum.c b/checksum.c
index b723109c..fb8c0a09 100644
--- a/checksum.c
+++ b/checksum.c
@@ -62,6 +62,8 @@ struct name_num_obj valid_checksums = {
int xfersum_type = 0; /* used for the file transfer checksums */
int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
+static int initialized_choices = 0;
+
int parse_csum_name(const char *name, int len)
{
struct name_num_item *nni;
@@ -79,6 +81,9 @@ int parse_csum_name(const char *name, int len)
return CSUM_MD4_ARCHAIC;
}
+ if (!initialized_choices)
+ init_checksum_choices();
+
nni = get_nni_by_name(&valid_checksums, name, len);
if (!nni) {
@@ -574,7 +579,7 @@ void sum_update(const char *p, int32 len)
}
/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is
- * MAX_DIGEST_LEN in size, so even if the csum-len is shorter that that (i.e.
+ * MAX_DIGEST_LEN in size, so even if the csum-len is shorter than that (i.e.
* CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write
* into the "sum" buffer. */
int sum_end(char *sum)
@@ -623,3 +628,31 @@ int sum_end(char *sum)
return csum_len_for_type(cursum_type, 0);
}
+
+void init_checksum_choices()
+{
+#ifdef SUPPORT_XXH3
+ char buf[32816];
+ int j;
+ for (j = 0; j < (int)sizeof buf; j++) {
+ buf[j] = ' ' + (j % 96);
+ }
+ sum_init(CSUM_XXH3_64, 0);
+ sum_update(buf, 32816);
+ sum_update(buf, 31152);
+ sum_update(buf, 32474);
+ sum_update(buf, 9322);
+ if (XXH3_64bits_digest(xxh3_state) != 0xadbcf16d4678d1de) {
+ int t, f;
+ struct name_num_item *nni = valid_checksums.list;
+ for (t = f = 0; nni[f].name; f++) {
+ if (nni[f].num == CSUM_XXH3_64 || nni[f].num == CSUM_XXH3_128)
+ continue;
+ if (t != f)
+ nni[t++] = nni[f];
+ }
+ nni[t].name = NULL;
+ }
+#endif
+ initialized_choices = 1;
+}
diff --git a/compat.c b/compat.c
index b8967969..b46eb199 100644
--- a/compat.c
+++ b/compat.c
@@ -400,7 +400,7 @@ static const char *getenv_nstr(int ntype)
const char *env_str = getenv(ntype == NSTR_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
/* When writing a batch file, we always negotiate an old-style choice. */
- if (write_batch)
+ if (write_batch)
env_str = ntype == NSTR_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4";
if (am_server && env_str) {
@@ -433,7 +433,7 @@ void validate_choice_vs_env(int ntype, int num1, int num2)
nno->saw[CSUM_MD4_ARCHAIC] = nno->saw[CSUM_MD4_BUSTED] = nno->saw[CSUM_MD4_OLD] = nno->saw[CSUM_MD4];
if (!nno->saw[num1] || (num2 >= 0 && !nno->saw[num2])) {
- rprintf(FERROR, "Your --%s-choice value (%s) was refused by the server.\n",
+ rprintf(FERROR, "Your --%s-choice value (%s) was refused by the server.\n",
ntype == NSTR_COMPRESS ? "compress" : "checksum",
ntype == NSTR_COMPRESS ? compress_choice : checksum_choice);
exit_cleanup(RERR_UNSUPPORTED);
@@ -523,6 +523,8 @@ static void negotiate_the_strings(int f_in, int f_out)
{
/* We send all the negotiation strings before we start to read them to help avoid a slow startup. */
+ init_checksum_choices();
+
if (!checksum_choice)
send_negotiate_str(f_out, &valid_checksums, NSTR_CHECKSUM);
diff --git a/configure.ac b/configure.ac
index 24e383a9..d185b2d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -13,7 +13,8 @@ AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h mcheck.h \
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h dl.h \
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netgroup.h \
- zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h)
+ zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h \
+ bsd/string.h)
AC_CHECK_HEADERS([netinet/ip.h], [], [], [[#include ]])
AC_HEADER_MAJOR_FIXED
@@ -22,7 +23,7 @@ AC_CONFIG_SRCDIR([byteorder.h])
AC_CONFIG_HEADER(config.h)
AC_PREREQ([2.69])
-PACKAGE_VERSION=`sed 's/.*"\(.*\)".*/\1/' <$srcdir/version.h`
+PACKAGE_VERSION=`sed -n 's/.*RSYNC_VERSION.*"\(.*\)".*/\1/p' <$srcdir/version.h`
AC_MSG_NOTICE([Configuring rsync $PACKAGE_VERSION])
@@ -624,7 +625,11 @@ fi
AC_TYPE_UID_T
AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t])
-AC_TYPE_GETGROUPS
+if test "$cross_compiling" = no; then
+ AC_TYPE_GETGROUPS
+else
+ AC_DEFINE([GETGROUPS_T],[gid_t],[Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'.])
+fi
AC_CHECK_MEMBERS([struct stat.st_rdev,
struct stat.st_mtimensec,
struct stat.st_mtimespec.tv_nsec,
@@ -1117,7 +1122,7 @@ else
fi
AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = ""]])],[rsync_cv_SIGNED_CHAR_OK=yes],[rsync_cv_SIGNED_CHAR_OK=no])])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = (signed char *)""]])],[rsync_cv_SIGNED_CHAR_OK=yes],[rsync_cv_SIGNED_CHAR_OK=no])])
if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then
AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type])
fi
diff --git a/exclude.c b/exclude.c
index 39073a0c..e5774420 100644
--- a/exclude.c
+++ b/exclude.c
@@ -25,16 +25,21 @@
extern int am_server;
extern int am_sender;
+extern int am_generator;
extern int eol_nulls;
extern int io_error;
+extern int xfer_dirs;
+extern int recurse;
extern int local_server;
extern int prune_empty_dirs;
extern int ignore_perishable;
+extern int relative_paths;
extern int delete_mode;
extern int delete_excluded;
extern int cvs_exclude;
extern int sanitize_paths;
extern int protocol_version;
+extern int trust_sender_args;
extern int module_id;
extern char curr_dir[MAXPATHLEN];
@@ -44,8 +49,11 @@ extern unsigned int module_dirlen;
filter_rule_list filter_list = { .debug_type = "" };
filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" };
filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" };
+filter_rule_list implied_filter_list = { .debug_type = " [implied]" };
int saw_xattr_filter = 0;
+int trust_sender_args = 0;
+int trust_sender_filter = 0;
/* Need room enough for ":MODS " prefix plus some room to grow. */
#define MAX_RULE_PREFIX (16)
@@ -292,6 +300,233 @@ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_
}
}
+/* If the wildcards failed, the remote shell might give us a file matching the literal
+ * wildcards. Since "*" & "?" already match themselves, this just needs to deal with
+ * failed "[foo]" idioms.
+ */
+static void maybe_add_literal_brackets_rule(filter_rule const *based_on, int arg_len)
+{
+ filter_rule *rule;
+ const char *arg = based_on->pattern, *cp;
+ char *p;
+ int cnt = 0;
+
+ if (arg_len < 0)
+ arg_len = strlen(arg);
+
+ for (cp = arg; *cp; cp++) {
+ if (*cp == '\\' && cp[1]) {
+ cp++;
+ } else if (*cp == '[')
+ cnt++;
+ }
+ if (!cnt)
+ return;
+
+ rule = new0(filter_rule);
+ rule->rflags = based_on->rflags;
+ rule->u.slash_cnt = based_on->u.slash_cnt;
+ p = rule->pattern = new_array(char, arg_len + cnt + 1);
+ for (cp = arg; *cp; ) {
+ if (*cp == '\\' && cp[1]) {
+ *p++ = *cp++;
+ } else if (*cp == '[')
+ *p++ = '\\';
+ *p++ = *cp++;
+ }
+ *p++ = '\0';
+
+ rule->next = implied_filter_list.head;
+ implied_filter_list.head = rule;
+ if (DEBUG_GTE(FILTER, 3)) {
+ rprintf(FINFO, "[%s] add_implied_include(%s%s)\n", who_am_i(), rule->pattern,
+ rule->rflags & FILTRULE_DIRECTORY ? "/" : "");
+ }
+}
+
+static char *partial_string_buf = NULL;
+static int partial_string_len = 0;
+void implied_include_partial_string(const char *s_start, const char *s_end)
+{
+ partial_string_len = s_end - s_start;
+ if (partial_string_len <= 0 || partial_string_len >= MAXPATHLEN) { /* too-large should be impossible... */
+ partial_string_len = 0;
+ return;
+ }
+ if (!partial_string_buf)
+ partial_string_buf = new_array(char, MAXPATHLEN);
+ memcpy(partial_string_buf, s_start, partial_string_len);
+}
+
+void free_implied_include_partial_string()
+{
+ if (partial_string_buf) {
+ free(partial_string_buf);
+ partial_string_buf = NULL;
+ }
+ partial_string_len = 0; /* paranoia */
+}
+
+/* Each arg the client sends to the remote sender turns into an implied include
+ * that the receiver uses to validate the file list from the sender. */
+void add_implied_include(const char *arg, int skip_daemon_module)
+{
+ filter_rule *rule;
+ int arg_len, saw_wild = 0, saw_live_open_brkt = 0, backslash_cnt = 0;
+ int slash_cnt = 1; /* We know we're adding a leading slash. */
+ const char *cp;
+ char *p;
+ if (trust_sender_args)
+ return;
+ if (partial_string_len) {
+ arg_len = strlen(arg);
+ if (partial_string_len + arg_len >= MAXPATHLEN) {
+ partial_string_len = 0;
+ return; /* Should be impossible... */
+ }
+ memcpy(partial_string_buf + partial_string_len, arg, arg_len + 1);
+ partial_string_len = 0;
+ arg = partial_string_buf;
+ }
+ if (skip_daemon_module) {
+ if ((cp = strchr(arg, '/')) != NULL)
+ arg = cp + 1;
+ else
+ arg = "";
+ }
+ if (relative_paths) {
+ if ((cp = strstr(arg, "/./")) != NULL)
+ arg = cp + 3;
+ } else if ((cp = strrchr(arg, '/')) != NULL) {
+ arg = cp + 1;
+ }
+ if (*arg == '.' && arg[1] == '\0')
+ arg++;
+ arg_len = strlen(arg);
+ if (arg_len) {
+ if (strpbrk(arg, "*[?")) {
+ /* We need to add room to escape backslashes if wildcard chars are present. */
+ for (cp = arg; (cp = strchr(cp, '\\')) != NULL; cp++)
+ arg_len++;
+ saw_wild = 1;
+ }
+ arg_len++; /* Leave room for the prefixed slash */
+ rule = new0(filter_rule);
+ if (!implied_filter_list.head)
+ implied_filter_list.head = implied_filter_list.tail = rule;
+ else {
+ rule->next = implied_filter_list.head;
+ implied_filter_list.head = rule;
+ }
+ rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0);
+ p = rule->pattern = new_array(char, arg_len + 1);
+ *p++ = '/';
+ for (cp = arg; *cp; ) {
+ switch (*cp) {
+ case '\\':
+ if (cp[1] == ']') {
+ if (!saw_wild)
+ cp++; /* A \] in a non-wild filter causes a problem, so drop the \ . */
+ } else if (!strchr("*[?", cp[1])) {
+ backslash_cnt++;
+ if (saw_wild)
+ *p++ = '\\';
+ }
+ *p++ = *cp++;
+ break;
+ case '/':
+ if (p[-1] == '/') { /* This is safe because of the initial slash. */
+ cp++;
+ break;
+ }
+ if (relative_paths) {
+ filter_rule const *ent;
+ int found = 0;
+ *p = '\0';
+ for (ent = implied_filter_list.head; ent; ent = ent->next) {
+ if (ent != rule && strcmp(ent->pattern, rule->pattern) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ filter_rule *R_rule = new0(filter_rule);
+ R_rule->rflags = FILTRULE_INCLUDE | FILTRULE_DIRECTORY;
+ /* Check if our sub-path has wildcards or escaped backslashes */
+ if (saw_wild && strpbrk(rule->pattern, "*[?\\"))
+ R_rule->rflags |= FILTRULE_WILD;
+ R_rule->pattern = strdup(rule->pattern);
+ R_rule->u.slash_cnt = slash_cnt;
+ R_rule->next = implied_filter_list.head;
+ implied_filter_list.head = R_rule;
+ if (DEBUG_GTE(FILTER, 3)) {
+ rprintf(FINFO, "[%s] add_implied_include(%s/)\n",
+ who_am_i(), R_rule->pattern);
+ }
+ if (saw_live_open_brkt)
+ maybe_add_literal_brackets_rule(R_rule, -1);
+ }
+ }
+ slash_cnt++;
+ *p++ = *cp++;
+ break;
+ case '[':
+ saw_live_open_brkt = 1;
+ *p++ = *cp++;
+ break;
+ default:
+ *p++ = *cp++;
+ break;
+ }
+ }
+ *p = '\0';
+ rule->u.slash_cnt = slash_cnt;
+ arg = rule->pattern;
+ arg_len = p - arg; /* We recompute it due to backslash weirdness. */
+ if (DEBUG_GTE(FILTER, 3))
+ rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern);
+ if (saw_live_open_brkt)
+ maybe_add_literal_brackets_rule(rule, arg_len);
+ }
+
+ if (recurse || xfer_dirs) {
+ /* Now create a rule with an added "/" & "**" or "*" at the end */
+ rule = new0(filter_rule);
+ rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD;
+ if (recurse)
+ rule->rflags |= FILTRULE_WILD2;
+ /* We must leave enough room for / * * \0. */
+ if (!saw_wild && backslash_cnt) {
+ /* We are appending a wildcard, so now the backslashes need to be escaped. */
+ p = rule->pattern = new_array(char, arg_len + backslash_cnt + 3 + 1);
+ for (cp = arg; *cp; ) {
+ if (*cp == '\\')
+ *p++ = '\\';
+ *p++ = *cp++;
+ }
+ } else {
+ p = rule->pattern = new_array(char, arg_len + 3 + 1);
+ if (arg_len) {
+ memcpy(p, arg, arg_len);
+ p += arg_len;
+ }
+ }
+ if (p[-1] != '/')
+ *p++ = '/';
+ *p++ = '*';
+ if (recurse)
+ *p++ = '*';
+ *p = '\0';
+ rule->u.slash_cnt = slash_cnt + 1;
+ rule->next = implied_filter_list.head;
+ implied_filter_list.head = rule;
+ if (DEBUG_GTE(FILTER, 3))
+ rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern);
+ if (saw_live_open_brkt)
+ maybe_add_literal_brackets_rule(rule, p - rule->pattern);
+ }
+}
+
/* This frees any non-inherited items, leaving just inherited items on the list. */
static void pop_filter_list(filter_rule_list *listp)
{
@@ -706,11 +941,12 @@ static void report_filter_result(enum logcode code, char const *name,
filter_rule const *ent,
int name_flags, const char *type)
{
+ int log_level = am_sender || am_generator ? 1 : 3;
+
/* If a trailing slash is present to match only directories,
* then it is stripped out by add_rule(). So as a special
- * case we add it back in here. */
-
- if (DEBUG_GTE(FILTER, 1)) {
+ * case we add it back in the log output. */
+ if (DEBUG_GTE(FILTER, log_level)) {
static char *actions[2][2]
= { {"show", "hid"}, {"risk", "protect"} };
const char *w = who_am_i();
@@ -718,7 +954,7 @@ static void report_filter_result(enum logcode code, char const *name,
: name_flags & NAME_IS_DIR ? "directory"
: "file";
rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n",
- w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)],
+ w, actions[*w=='g'][!(ent->rflags & FILTRULE_INCLUDE)],
t, name, ent->pattern,
ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type);
}
@@ -890,6 +1126,7 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr,
}
switch (ch) {
case ':':
+ trust_sender_filter = 1;
rule->rflags |= FILTRULE_PERDIR_MERGE
| FILTRULE_FINISH_SETUP;
/* FALL THROUGH */
diff --git a/flist.c b/flist.c
index 1ba306bc..0e6bf782 100644
--- a/flist.c
+++ b/flist.c
@@ -73,6 +73,7 @@ extern int need_unsorted_flist;
extern int sender_symlink_iconv;
extern int output_needs_newline;
extern int sender_keeps_checksum;
+extern int trust_sender_filter;
extern int unsort_ndx;
extern uid_t our_uid;
extern struct stats stats;
@@ -83,8 +84,7 @@ extern char curr_dir[MAXPATHLEN];
extern struct chmod_mode_struct *chmod_modes;
-extern filter_rule_list filter_list;
-extern filter_rule_list daemon_filter_list;
+extern filter_rule_list filter_list, implied_filter_list, daemon_filter_list;
#ifdef ICONV_OPTION
extern int filesfrom_convert;
@@ -986,6 +986,19 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
exit_cleanup(RERR_UNSUPPORTED);
}
+ if (*thisname != '.' || thisname[1] != '\0') {
+ int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE;
+ if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */
+ && filter_list.head && check_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
+ rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname);
+ exit_cleanup(RERR_PROTOCOL);
+ }
+ if (implied_filter_list.head && check_filter(&implied_filter_list, FINFO, thisname, filt_flags) <= 0) {
+ rprintf(FERROR, "ERROR: rejecting unrequested file-list name: %s\n", thisname);
+ exit_cleanup(RERR_PROTOCOL);
+ }
+ }
+
if (inc_recurse && S_ISDIR(mode)) {
if (one_file_system) {
/* Room to save the dir's device for -x */
diff --git a/io.c b/io.c
index cf94cee7..3f605d74 100644
--- a/io.c
+++ b/io.c
@@ -376,6 +376,7 @@ static void forward_filesfrom_data(void)
free_xbuf(&ff_xb);
if (ff_reenable_multiplex >= 0)
io_start_multiplex_out(ff_reenable_multiplex);
+ free_implied_include_partial_string();
}
return;
}
@@ -419,6 +420,7 @@ static void forward_filesfrom_data(void)
while (s != eob) {
if (*s++ == '\0') {
ff_xb.len = s - sob - 1;
+ add_implied_include(sob, 0);
if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0)
exit_cleanup(RERR_PROTOCOL); /* impossible? */
write_buf(iobuf.out_fd, s-1, 1); /* Send the '\0'. */
@@ -434,6 +436,7 @@ static void forward_filesfrom_data(void)
ff_lastchar = '\0';
else {
/* Handle a partial string specially, saving any incomplete chars. */
+ implied_include_partial_string(sob, s);
flags &= ~ICB_INCLUDE_INCOMPLETE;
if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0) {
if (errno == E2BIG)
@@ -450,13 +453,17 @@ static void forward_filesfrom_data(void)
char *f = ff_xb.buf + ff_xb.pos;
char *t = ff_xb.buf;
char *eob = f + len;
+ char *cur = t;
/* Eliminate any multi-'\0' runs. */
while (f != eob) {
if (!(*t++ = *f++)) {
+ add_implied_include(cur, 0);
+ cur = t;
while (f != eob && *f == '\0')
f++;
}
}
+ implied_include_partial_string(cur, t);
ff_lastchar = f[-1];
if ((len = t - ff_xb.buf) != 0) {
/* This will not circle back to perform_io() because we only get
diff --git a/lib/sysacls.c b/lib/sysacls.c
index a9c3f1bd..a5abe408 100644
--- a/lib/sysacls.c
+++ b/lib/sysacls.c
@@ -2,7 +2,7 @@
* Unix SMB/CIFS implementation.
* Based on the Samba ACL support code.
* Copyright (C) Jeremy Allison 2000.
- * Copyright (C) 2007-2020 Wayne Davison
+ * Copyright (C) 2007-2022 Wayne Davison
*
* The permission functions have been changed to get/set all bits via
* one call. Some functions that rsync doesn't need were also removed.
@@ -175,7 +175,7 @@ int sys_acl_delete_def_file(const char *name)
return acl_delete_def_file(name);
}
-int sys_acl_free_acl(SMB_ACL_T the_acl)
+int sys_acl_free_acl(SMB_ACL_T the_acl)
{
return acl_free(the_acl);
}
@@ -185,7 +185,7 @@ int sys_acl_free_acl(SMB_ACL_T the_acl)
* The interface to DEC/Compaq Tru64 UNIX ACLs
* is based on Draft 13 of the POSIX spec which is
* slightly different from the Draft 16 interface.
- *
+ *
* Also, some of the permset manipulation functions
* such as acl_clear_perm() and acl_add_perm() appear
* to be broken on Tru64 so we have to manipulate
@@ -310,7 +310,7 @@ int sys_acl_delete_def_file(const char *name)
return acl_delete_def_file((char *)name);
}
-int sys_acl_free_acl(SMB_ACL_T the_acl)
+int sys_acl_free_acl(SMB_ACL_T the_acl)
{
return acl_free(the_acl);
}
@@ -457,7 +457,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
break;
}
ndefault = count - naccess;
-
+
/*
* if the caller wants the default ACL we have to copy
* the entries down to the start of the acl[] buffer
@@ -517,7 +517,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
break;
}
-
+
acl_d->count = naccess;
return acl_d;
@@ -532,7 +532,7 @@ int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *b
if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
*u_g_id_p = entry->a_id;
-
+
return 0;
}
@@ -633,7 +633,7 @@ static int acl_sort(SMB_ACL_T acl_d)
}
return 0;
}
-
+
int sys_acl_valid(SMB_ACL_T acl_d)
{
return acl_sort(acl_d);
@@ -755,11 +755,11 @@ int sys_acl_delete_def_file(const char *path)
ret = acl(path, SETACL, acl_d->count, acl_d->acl);
sys_acl_free_acl(acl_d);
-
+
return ret;
}
-int sys_acl_free_acl(SMB_ACL_T acl_d)
+int sys_acl_free_acl(SMB_ACL_T acl_d)
{
SAFE_FREE(acl_d);
return 0;
@@ -895,10 +895,10 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
int ndefault; /* # of default ACL entries */
if (hpux_acl_call_presence() == False) {
- /* Looks like we don't have the acl() system call on HPUX.
+ /* Looks like we don't have the acl() system call on HPUX.
* May be the system doesn't have the latest version of JFS.
*/
- return NULL;
+ return NULL;
}
if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
@@ -949,7 +949,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
break;
}
ndefault = count - naccess;
-
+
/*
* if the caller wants the default ACL we have to copy
* the entries down to the start of the acl[] buffer
@@ -1109,9 +1109,9 @@ struct hpux_acl_types {
* aclp - Array of ACL structures.
* acl_type_count - Pointer to acl_types structure. Should already be
* allocated.
- * Output:
+ * Output:
*
- * acl_type_count - This structure is filled up with counts of various
+ * acl_type_count - This structure is filled up with counts of various
* acl types.
*/
@@ -1123,28 +1123,28 @@ static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_type
for (i = 0; i < acl_count; i++) {
switch (aclp[i].a_type) {
- case USER:
+ case USER:
acl_type_count->n_user++;
break;
- case USER_OBJ:
+ case USER_OBJ:
acl_type_count->n_user_obj++;
break;
- case DEF_USER_OBJ:
+ case DEF_USER_OBJ:
acl_type_count->n_def_user_obj++;
break;
- case GROUP:
+ case GROUP:
acl_type_count->n_group++;
break;
- case GROUP_OBJ:
+ case GROUP_OBJ:
acl_type_count->n_group_obj++;
break;
- case DEF_GROUP_OBJ:
+ case DEF_GROUP_OBJ:
acl_type_count->n_def_group_obj++;
break;
- case OTHER_OBJ:
+ case OTHER_OBJ:
acl_type_count->n_other_obj++;
break;
- case DEF_OTHER_OBJ:
+ case DEF_OTHER_OBJ:
acl_type_count->n_def_other_obj++;
break;
case CLASS_OBJ:
@@ -1159,14 +1159,14 @@ static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_type
case DEF_GROUP:
acl_type_count->n_def_group++;
break;
- default:
+ default:
acl_type_count->n_illegal_obj++;
break;
}
}
}
-/* swap_acl_entries: Swaps two ACL entries.
+/* swap_acl_entries: Swaps two ACL entries.
*
* Inputs: aclp0, aclp1 - ACL entries to be swapped.
*/
@@ -1189,25 +1189,25 @@ static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
}
/* prohibited_duplicate_type
- * Identifies if given ACL type can have duplicate entries or
+ * Identifies if given ACL type can have duplicate entries or
* not.
*
* Inputs: acl_type - ACL Type.
*
- * Outputs:
+ * Outputs:
*
- * Return..
+ * Return..
*
* True - If the ACL type matches any of the prohibited types.
* False - If the ACL type doesn't match any of the prohibited types.
- */
+ */
static BOOL hpux_prohibited_duplicate_type(int acl_type)
{
switch (acl_type) {
case USER:
case GROUP:
- case DEF_USER:
+ case DEF_USER:
case DEF_GROUP:
return True;
default:
@@ -1217,7 +1217,7 @@ static BOOL hpux_prohibited_duplicate_type(int acl_type)
/* get_needed_class_perm
* Returns the permissions of a ACL structure only if the ACL
- * type matches one of the pre-determined types for computing
+ * type matches one of the pre-determined types for computing
* CLASS_OBJ permissions.
*
* Inputs: aclp - Pointer to ACL structure.
@@ -1226,17 +1226,17 @@ static BOOL hpux_prohibited_duplicate_type(int acl_type)
static int hpux_get_needed_class_perm(struct acl *aclp)
{
switch (aclp->a_type) {
- case USER:
- case GROUP_OBJ:
- case GROUP:
- case DEF_USER_OBJ:
+ case USER:
+ case GROUP_OBJ:
+ case GROUP:
+ case DEF_USER_OBJ:
case DEF_USER:
- case DEF_GROUP_OBJ:
+ case DEF_GROUP_OBJ:
case DEF_GROUP:
case DEF_CLASS_OBJ:
- case DEF_OTHER_OBJ:
+ case DEF_OTHER_OBJ:
return aclp->a_perm;
- default:
+ default:
return 0;
}
}
@@ -1267,15 +1267,15 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
#if !defined(HAVE_HPUX_ACLSORT)
/*
* The aclsort() system call is available on the latest HPUX General
- * Patch Bundles. So for HPUX, we developed our version of acl_sort
- * function. Because, we don't want to update to a new
+ * Patch Bundles. So for HPUX, we developed our version of acl_sort
+ * function. Because, we don't want to update to a new
* HPUX GR bundle just for aclsort() call.
*/
struct hpux_acl_types acl_obj_count;
int n_class_obj_perm = 0;
int i, j;
-
+
if (!acl_count) {
DEBUG(10, ("Zero acl count passed. Returning Success\n"));
return 0;
@@ -1290,8 +1290,8 @@ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
hpux_count_obj(acl_count, aclp, &acl_obj_count);
- /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
- * CLASS_OBJ and OTHER_OBJ
+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
+ * CLASS_OBJ and OTHER_OBJ
*/
if (acl_obj_count.n_user_obj != 1
@@ -1313,15 +1313,15 @@ or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
return -1;
}
- /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
- * structures.
+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
+ * structures.
*
* Sorting crieteria - First sort by ACL type. If there are multiple entries of
* same ACL type, sort by ACL id.
*
- * I am using the trivial kind of sorting method here because, performance isn't
+ * I am using the trivial kind of sorting method here because, performance isn't
* really effected by the ACLs feature. More over there aren't going to be more
- * than 17 entries on HPUX.
+ * than 17 entries on HPUX.
*/
for (i = 0; i < acl_count; i++) {
@@ -1390,7 +1390,7 @@ static int acl_sort(SMB_ACL_T acl_d)
}
return 0;
}
-
+
int sys_acl_valid(SMB_ACL_T acl_d)
{
return acl_sort(acl_d);
@@ -1405,11 +1405,11 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
int ret;
if (hpux_acl_call_presence() == False) {
- /* Looks like we don't have the acl() system call on HPUX.
+ /* Looks like we don't have the acl() system call on HPUX.
* May be the system doesn't have the latest version of JFS.
*/
errno=ENOSYS;
- return -1;
+ return -1;
}
if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
@@ -1538,11 +1538,11 @@ int sys_acl_delete_def_file(const char *path)
ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
sys_acl_free_acl(acl_d);
-
+
return ret;
}
-int sys_acl_free_acl(SMB_ACL_T acl_d)
+int sys_acl_free_acl(SMB_ACL_T acl_d)
{
free(acl_d);
return 0;
@@ -1723,7 +1723,7 @@ int sys_acl_delete_def_file(const char *name)
return acl_delete_def_file(name);
}
-int sys_acl_free_acl(SMB_ACL_T acl_d)
+int sys_acl_free_acl(SMB_ACL_T acl_d)
{
if (acl_d->freeaclp) {
acl_free(acl_d->aclp);
@@ -1834,12 +1834,12 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
}
/* Get the acl using statacl */
-
+
DEBUG(10, ("Entering sys_acl_get_file\n"));
DEBUG(10, ("path_p is %s\n", path_p));
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
-
+
if (file_acl == NULL) {
errno=ENOMEM;
DEBUG(0, ("Error in AIX sys_acl_get_file: %d\n", errno));
@@ -1931,9 +1931,9 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
* to be specified but, it's better than leaving it 0 */
acl_entry_link->entryp->ace_type = acl_entry->ace_type;
-
+
acl_entry_link->entryp->ace_access = acl_entry->ace_access;
-
+
memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id));
/* The access in the acl entries must be left shifted by *
@@ -1962,7 +1962,7 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
DEBUG(10, ("acl_entry = %d\n", acl_entry));
DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type));
-
+
acl_entry = acl_nxt(acl_entry);
}
} /* end of if enabled */
@@ -2014,12 +2014,12 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
new_acl_entry->ace_access = file_acl->o_access << 6;
idp->id_type = SMB_ACL_OTHER;
break;
-
+
case 1:
new_acl_entry->ace_access = file_acl->u_access << 6;
idp->id_type = SMB_ACL_USER_OBJ;
break;
-
+
default:
return NULL;
@@ -2048,7 +2048,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
int rc = 0;
/* Get the acl using fstatacl */
-
+
DEBUG(10, ("Entering sys_acl_get_fd\n"));
DEBUG(10, ("fd is %d\n", fd));
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
@@ -2095,12 +2095,12 @@ SMB_ACL_T sys_acl_get_fd(int fd)
DEBUG(10, ("acl_entry is %d\n", acl_entry));
DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl)));
-
+
/* Check if the extended acl bit is on. *
* If it isn't, do not show the *
* contents of the acl since AIX intends *
* the extended info to remain unused */
-
+
if (file_acl->acl_mode & S_IXACL){
/* while we are not pointing to the very end */
while (acl_entry < acl_last(file_acl)) {
@@ -2115,7 +2115,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
}
idp = acl_entry->ace_id;
-
+
/* Check if this is the first entry in the linked list. *
* The first entry needs to keep prevp pointing to NULL *
* and already has entryp allocated. */
@@ -2177,7 +2177,7 @@ SMB_ACL_T sys_acl_get_fd(int fd)
DEBUG(10, ("acl_entry = %d\n", acl_entry));
DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type));
-
+
acl_entry = acl_nxt(acl_entry);
}
} /* end of if enabled */
@@ -2210,43 +2210,43 @@ SMB_ACL_T sys_acl_get_fd(int fd)
}
acl_entry_link->nextp = NULL;
-
+
new_acl_entry = acl_entry_link->entryp;
idp = new_acl_entry->ace_id;
-
+
new_acl_entry->ace_len = sizeof (struct acl_entry);
new_acl_entry->ace_type = ACC_PERMIT;
idp->id_len = sizeof (struct ace_id);
DEBUG(10, ("idp->id_len = %d\n", idp->id_len));
memset(idp->id_data, 0, sizeof (uid_t));
-
+
switch (i) {
case 2:
new_acl_entry->ace_access = file_acl->g_access << 6;
idp->id_type = SMB_ACL_GROUP_OBJ;
break;
-
+
case 3:
new_acl_entry->ace_access = file_acl->o_access << 6;
idp->id_type = SMB_ACL_OTHER;
break;
-
+
case 1:
new_acl_entry->ace_access = file_acl->u_access << 6;
idp->id_type = SMB_ACL_USER_OBJ;
break;
-
+
default:
return NULL;
}
-
+
acl_entry_link_head->count++;
DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access));
}
acl_entry_link_head->count = 0;
SAFE_FREE(file_acl);
-
+
return acl_entry_link_head;
}
#endif
@@ -2274,7 +2274,7 @@ int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *b
SMB_ACL_T sys_acl_init(int count)
{
struct acl_entry_link *theacl = NULL;
-
+
if (count < 0) {
errno = EINVAL;
return NULL;
@@ -2383,9 +2383,9 @@ int sys_acl_valid(SMB_ACL_T theacl)
}
DEBUG(10, ("user_obj=%d, group_obj=%d, other_obj=%d\n", user_obj, group_obj, other_obj));
-
+
if (user_obj != 1 || group_obj != 1 || other_obj != 1)
- return -1;
+ return -1;
return 0;
}
@@ -2404,7 +2404,7 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
DEBUG(10, ("Entering sys_acl_set_file\n"));
DEBUG(10, ("File name is %s\n", name));
-
+
/* AIX has no default ACL */
if (acltype == SMB_ACL_TYPE_DEFAULT)
return 0;
@@ -2449,7 +2449,7 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
errno = ENOMEM;
DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno));
return -1;
- }
+ }
memcpy(file_acl_temp, file_acl, file_acl->acl_len);
SAFE_FREE(file_acl);
@@ -2460,15 +2460,15 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
file_acl->acl_len += sizeof (struct acl_entry);
acl_entry->ace_len = acl_entry_link->entryp->ace_len;
acl_entry->ace_access = acl_entry_link->entryp->ace_access;
-
+
/* In order to use this, we'll need to wait until we can get denies */
/* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
acl_entry->ace_type = ACC_SPECIFY; */
acl_entry->ace_type = ACC_SPECIFY;
-
+
ace_id = acl_entry->ace_id;
-
+
ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
DEBUG(10, ("The id type is %d\n", ace_id->id_type));
ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
@@ -2496,7 +2496,7 @@ int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
uint user_id;
uint acl_length;
uint rc;
-
+
DEBUG(10, ("Entering sys_acl_set_fd\n"));
acl_length = BUFSIZ;
file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
@@ -2508,7 +2508,7 @@ int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
}
memset(file_acl, 0, BUFSIZ);
-
+
file_acl->acl_len = ACL_SIZ;
file_acl->acl_mode = S_IXACL;
@@ -2550,22 +2550,22 @@ int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
file_acl->acl_len += sizeof (struct acl_entry);
acl_entry->ace_len = acl_entry_link->entryp->ace_len;
acl_entry->ace_access = acl_entry_link->entryp->ace_access;
-
+
/* In order to use this, we'll need to wait until we can get denies */
/* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
acl_entry->ace_type = ACC_SPECIFY; */
-
+
acl_entry->ace_type = ACC_SPECIFY;
-
+
ace_id = acl_entry->ace_id;
-
+
ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
DEBUG(10, ("The id type is %d\n", ace_id->id_type));
ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t));
memcpy(ace_id->id_data, &user_id, sizeof (uid_t));
}
-
+
rc = fchacl(fd, file_acl, file_acl->acl_len);
DEBUG(10, ("errno is %d\n", errno));
DEBUG(10, ("return code is %d\n", rc));
@@ -2594,7 +2594,7 @@ int sys_acl_free_acl(SMB_ACL_T posix_acl)
SAFE_FREE(acl_entry_link->prevp);
SAFE_FREE(acl_entry_link->entryp);
SAFE_FREE(acl_entry_link);
-
+
return 0;
}
diff --git a/lib/sysacls.h b/lib/sysacls.h
index 8865dae4..c0695974 100644
--- a/lib/sysacls.h
+++ b/lib/sysacls.h
@@ -3,7 +3,7 @@
* Version 2.2.x
* Portable SMB ACL interface
* Copyright (C) Jeremy Allison 2000
- * Copyright (C) 2007-2020 Wayne Davison
+ * Copyright (C) 2007-2022 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -232,7 +232,7 @@ struct new_acl_entry{
#define SMB_ACL_ENTRY_T struct new_acl_entry*
#define SMB_ACL_T struct acl_entry_link*
-
+
#define SMB_ACL_TAG_T unsigned short
#define SMB_ACL_TYPE_T int
diff --git a/main.c b/main.c
index 58920a2d..9ebfbea7 100644
--- a/main.c
+++ b/main.c
@@ -104,7 +104,7 @@ extern char curr_dir[MAXPATHLEN];
extern char backup_dir_buf[MAXPATHLEN];
extern char *basis_dir[MAX_BASIS_DIRS+1];
extern struct file_list *first_flist;
-extern filter_rule_list daemon_filter_list;
+extern filter_rule_list daemon_filter_list, implied_filter_list;
uid_t our_uid;
gid_t our_gid;
@@ -1076,6 +1076,7 @@ static int do_recv(int f_in, int f_out, char *local_name)
}
am_generator = 1;
+ implied_filter_list.head = implied_filter_list.tail = NULL;
flist_receiving_enabled = True;
io_end_multiplex_in(MPLX_SWITCHING);
@@ -1500,6 +1501,8 @@ static int start_client(int argc, char *argv[])
char *dummy_host;
int dummy_port = rsync_port;
int i;
+ if (filesfrom_fd < 0)
+ add_implied_include(remote_argv[0], daemon_connection);
/* For remote source, any extra source args must have either
* the same hostname or an empty hostname. */
for (i = 1; i < remote_argc; i++) {
@@ -1523,6 +1526,7 @@ static int start_client(int argc, char *argv[])
if (!rsync_port && !*arg) /* Turn an empty arg into a dot dir. */
arg = ".";
remote_argv[i] = arg;
+ add_implied_include(arg, daemon_connection);
}
}
diff --git a/md-convert b/md-convert
index 41a1930a..19709c8d 100755
--- a/md-convert
+++ b/md-convert
@@ -115,7 +115,8 @@ NBR_SPACE = ('\xa0', r"\ ")
FILENAME_RE = re.compile(r'^(?P(?P.+/)?(?P(?P[^/]+?)(\.(?P\d+))?)\.md)$')
ASSIGNMENT_RE = re.compile(r'^(\w+)=(.+)')
-QUOTED_RE = re.compile(r'"(.+?)"')
+VER_RE = re.compile(r'^#define\s+RSYNC_VERSION\s+"(\d.+?)"', re.M)
+TZ_RE = re.compile(r'^#define\s+MAINTAINER_TZ_OFFSET\s+(-?\d+(\.\d+)?)', re.M)
VAR_REF_RE = re.compile(r'\$\{(\w+)\}')
VERSION_RE = re.compile(r' (\d[.\d]+)[, ]')
BIN_CHARS_RE = re.compile(r'[\1-\7]+')
@@ -213,6 +214,7 @@ def find_man_substitutions():
env_subs['VERSION'] = '1.0.0'
env_subs['bindir'] = '/usr/bin'
env_subs['libdir'] = '/usr/lib/rsync'
+ tz_offset = 0
else:
for fn in (srcdir + 'version.h', 'Makefile'):
try:
@@ -224,8 +226,10 @@ def find_man_substitutions():
with open(srcdir + 'version.h', 'r', encoding='utf-8') as fh:
txt = fh.read()
- m = QUOTED_RE.search(txt)
+ m = VER_RE.search(txt)
env_subs['VERSION'] = m.group(1)
+ m = TZ_RE.search(txt) # the tzdata lib may not be installed, so we use a simple hour offset
+ tz_offset = float(m.group(1)) * 60 * 60
with open('Makefile', 'r', encoding='utf-8') as fh:
for line in fh:
@@ -241,7 +245,7 @@ def find_man_substitutions():
if var == 'srcdir':
break
- env_subs['date'] = time.strftime('%d %b %Y', time.localtime(mtime))
+ env_subs['date'] = time.strftime('%d %b %Y', time.gmtime(mtime + tz_offset)).lstrip('0')
def html_via_commonmark(txt):
@@ -605,12 +609,12 @@ def die(*msg):
if __name__ == '__main__':
- parser = argparse.ArgumentParser(description="Output html and (optionally) nroff for markdown pages.", add_help=False)
+ parser = argparse.ArgumentParser(description="Convert markdown into html and (optionally) nroff. Each input filename must have a .md suffix, which is changed to .html for the output filename. If the input filename ends with .num.md (e.g. foo.1.md) then a nroff file is also output with the input filename's .md suffix removed (e.g. foo.1).", add_help=False)
parser.add_argument('--test', action='store_true', help="Just test the parsing without outputting any files.")
- parser.add_argument('--dest', metavar='DIR', help="Put files into DIR instead of the current directory.")
+ parser.add_argument('--dest', metavar='DIR', help="Create files in DIR instead of the current directory.")
parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.')
parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.")
- parser.add_argument("mdfiles", nargs='+', help="The source .md files to convert.")
+ parser.add_argument("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.")
args = parser.parse_args()
try:
diff --git a/options.c b/options.c
index 93bdb237..4feeb7e0 100644
--- a/options.c
+++ b/options.c
@@ -27,6 +27,8 @@
extern int module_id;
extern int local_server;
extern int sanitize_paths;
+extern int trust_sender_args;
+extern int trust_sender_filter;
extern unsigned int module_dirlen;
extern filter_rule_list filter_list;
extern filter_rule_list daemon_filter_list;
@@ -64,6 +66,7 @@ int preserve_atimes = 0;
int preserve_crtimes = 0;
int omit_dir_times = 0;
int omit_link_times = 0;
+int trust_sender = 0;
int update_only = 0;
int open_noatime = 0;
int cvs_exclude = 0;
@@ -293,7 +296,7 @@ static struct output_struct debug_words[COUNT_DEBUG+1] = {
DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"),
DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"),
DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"),
- DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"),
+ DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-3)"),
DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"),
DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"),
DEBUG_WORD(GENR, W_REC, "Debug generator functions"),
@@ -788,6 +791,7 @@ static struct poptOption long_options[] = {
{"protect-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0},
{"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
{"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
+ {"trust-sender", 0, POPT_ARG_VAL, &trust_sender, 1, 0, 0},
{"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 },
{"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 },
{"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 },
@@ -2465,6 +2469,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
}
}
+ if (trust_sender || am_server || read_batch)
+ trust_sender_args = trust_sender_filter = 1;
+ else if (old_style_args || filesfrom_host != NULL)
+ trust_sender_args = 1;
+
am_starting_up = 0;
return 1;
@@ -2492,12 +2501,17 @@ char *safe_arg(const char *opt, const char *arg)
BOOL is_filename_arg = !opt;
char *escapes = is_filename_arg ? SHELL_CHARS : WILD_CHARS SHELL_CHARS;
BOOL escape_leading_dash = is_filename_arg && *arg == '-';
+ BOOL escape_leading_tilde = 0;
int len1 = opt && *opt ? strlen(opt) + 1 : 0;
int len2 = strlen(arg);
int extras = escape_leading_dash ? 2 : 0;
char *ret;
if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) {
const char *f;
+ if (!trust_sender_args && *arg == '~' && (relative_paths || !strchr(arg, '/'))) {
+ extras++;
+ escape_leading_tilde = 1;
+ }
for (f = arg; *f; f++) {
if (strchr(escapes, *f))
extras++;
@@ -2520,8 +2534,13 @@ char *safe_arg(const char *opt, const char *arg)
else {
const char *f = arg;
char *t = ret + len1;
+ if (escape_leading_tilde)
+ *t++ = '\\';
while (*f) {
- if (strchr(escapes, *f))
+ if (*f == '\\') {
+ if (!is_filename_arg || !strchr(WILD_CHARS, f[1]))
+ *t++ = '\\';
+ } else if (strchr(escapes, *f))
*t++ = '\\';
*t++ = *f++;
}
diff --git a/packaging/lsb/rsync.spec b/packaging/lsb/rsync.spec
index 0bdcd833..0959c744 100644
--- a/packaging/lsb/rsync.spec
+++ b/packaging/lsb/rsync.spec
@@ -1,6 +1,6 @@
Summary: A fast, versatile, remote (and local) file-copying tool
Name: rsync
-Version: 3.2.4
+Version: 3.2.5
%define fullversion %{version}
Release: 1
%define srcdir src
@@ -79,8 +79,8 @@ rm -rf $RPM_BUILD_ROOT
%dir /etc/rsync-ssl/certs
%changelog
-* Fri Apr 15 2022 Wayne Davison
-Released 3.2.4.
+* Sun Aug 14 2022 Wayne Davison
+Released 3.2.5.
* Fri Mar 21 2008 Wayne Davison
Added installation of /etc/xinetd.d/rsync file and some commented-out
diff --git a/packaging/release-rsync b/packaging/release-rsync
index d484628c..5e54d06e 100755
--- a/packaging/release-rsync
+++ b/packaging/release-rsync
@@ -193,7 +193,9 @@ About to:
with open(fn, 'r', encoding='utf-8') as fh:
old_txt = txt = fh.read()
if fn == 'version.h':
- txt = f'#define RSYNC_VERSION "{version}"\n'
+ x_re = re.compile(r'^(#define RSYNC_VERSION).*', re.M)
+ msg = f"Unable to update RSYNC_VERSION in {fn}"
+ txt = replace_or_die(x_re, r'\1 "%s"' % version, txt, msg)
elif '.spec' in fn:
for var, val in specvars.items():
x_re = re.compile(r'^%s .*' % re.escape(var), re.M)
diff --git a/receiver.c b/receiver.c
index b3a69da0..93cf8efd 100644
--- a/receiver.c
+++ b/receiver.c
@@ -593,10 +593,13 @@ int recv_files(int f_in, int f_out, char *local_name)
if (DEBUG_GTE(RECV, 1))
rprintf(FINFO, "recv_files(%s)\n", fname);
- if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')
- && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
- rprintf(FERROR, "attempt to hack rsync failed.\n");
- exit_cleanup(RERR_PROTOCOL);
+ if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')) {
+ int filt_flags = S_ISDIR(file->mode) ? NAME_IS_DIR : NAME_IS_FILE;
+ if (check_filter(&daemon_filter_list, FLOG, fname, filt_flags) < 0) {
+ rprintf(FERROR, "ERROR: rejecting file transfer request for daemon excluded file: %s\n",
+ fname);
+ exit_cleanup(RERR_PROTOCOL);
+ }
}
#ifdef SUPPORT_XATTRS
diff --git a/rsync-ssl.1.md b/rsync-ssl.1.md
index f3f93718..a6f1e3d3 100644
--- a/rsync-ssl.1.md
+++ b/rsync-ssl.1.md
@@ -94,6 +94,11 @@ The ssl helper scripts are affected by the following environment variables:
> rsync-ssl -aiv rsync://example.com:9874/mod/ dest
+## THE SERVER SIDE
+
+For help setting up an SSL/TLS supporting rsync, see the [instructions in
+rsyncd.conf](rsyncd.conf.5#SSL_TLS_Daemon_Setup).
+
## SEE ALSO
[**rsync**(1)](rsync.1), [**rsyncd.conf**(5)](rsyncd.conf.5)
diff --git a/rsync.1.md b/rsync.1.md
index 313025df..f29495f2 100644
--- a/rsync.1.md
+++ b/rsync.1.md
@@ -154,6 +154,47 @@ rsync daemon by leaving off the module name:
See the following section for more details.
+## SORTED TRANSFER ORDER
+
+Rsync always sorts the specified filenames into its internal transfer list.
+This handles the merging together of the contents of identically named
+directories, makes it easy to remove duplicate filenames. It can, however,
+confuse someone when the files are transferred in a different order than what
+was given on the command-line.
+
+If you need a particular file to be transferred prior to another, either
+separate the files into different rsync calls, or consider using
+[`--delay-updates`](#opt) (which doesn't affect the sorted transfer order, but
+does make the final file-updating phase happen much more rapidly).
+
+## MULTI-HOST SECURITY
+
+Rsync takes steps to ensure that the file requests that are shared in a
+transfer are protected against various security issues. Most of the potential
+problems arise on the receiving side where rsync takes steps to ensure that the
+list of files being transferred remains within the bounds of what was
+requested.
+
+Toward this end, rsync 3.1.2 and later have aborted when a file list contains
+an absolute or relative path that tries to escape out of the top of the
+transfer. Also, beginning with version 3.2.5, rsync does two more safety
+checks of the file list to (1) ensure that no extra source arguments were added
+into the transfer other than those that the client requested and (2) ensure
+that the file list obeys the exclude rules that were sent to the sender.
+
+For those that don't yet have a 3.2.5 client rsync (or those that want to be
+extra careful), it is safest to do a copy into a dedicated destination
+directory for the remote files when you don't trust the remote host. For
+example, instead of doing an rsync copy into your home directory:
+
+> rsync -aiv host1:dir1 ~
+
+Dedicate a "host1-files" dir to the remote content:
+
+> rsync -aiv host1:dir1 ~/host1-files
+
+See the [`--trust-sender`](#opt) option for additional details.
+
## ADVANCED USAGE
The syntax for requesting multiple files from a remote host is done by
@@ -164,20 +205,24 @@ the hostname omitted. For instance, all these work:
> rsync -aiv host::modname/file{1,2} host::modname/extra /dest/
> rsync -aiv host::modname/first ::modname/extra{1,2} /dest/
-In a modern rsync, you only need to quote or backslash-escape things like
-spaces from the local shell but not also from the remote shell:
+Really old versions of rsync (2.6.9 and before) only allowed specifying one
+remote-source arg, so some people have instead relied on the remote-shell
+performing space splitting to break up an arg into multiple paths. Such
+unintuitive behavior is no longer supported by default (though you can request
+it, as described below).
+
+Starting in 3.2.4, filenames are passed to a remote shell in such a way as to
+preserve the characters you give it. Thus, if you ask for a file with spaces
+in the name, that's what the remote rsync looks for:
> rsync -aiv host:'a simple file.pdf' /dest/
-Really old versions of rsync only allowed specifying one remote-source arg, so
-it required the remote side to split the args at a space. You can still get
-this old-style arg splitting by using the [`--old-args`](#opt) option:
-
-> rsync -ai --old-args host:'dir1/file1 dir2/file2' /dest
-> rsync -ai --old-args host::'modname/dir1/file1 modname/dir2/file2' /dest
-
-See that option's section for an [environment variable](#RSYNC_OLD_ARGS) that
-can be exported to help old scripts.
+If you use scripts that have been written to manually apply extra quoting to
+the remote rsync args (or to require remote arg splitting), you can ask rsync
+to let your script handle the extra escaping. This is done by either adding
+the [`--old-args`](#opt) option to the rsync runs in the script (which requires
+a new rsync) or exporting [RSYNC_OLD_ARGS](#)=1 and [RSYNC_PROTECT_ARGS](#)=0
+(which works with old or new rsync versions).
## CONNECTING TO AN RSYNC DAEMON
@@ -270,6 +315,10 @@ example that uses the short version of the [`--rsh`](#opt) option:
The "ssh-user" will be used at the ssh level; the "rsync-user" will be used to
log-in to the "module".
+In this setup, the daemon is started by the ssh command that is accessing the
+system (which can be forced via the `~/.ssh/authorized_keys` file, if desired).
+However, when accessing a daemon directly, it needs to be started beforehand.
+
## STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS
In order to connect to an rsync daemon, the remote system needs to have a
@@ -283,48 +332,18 @@ the daemon (including stand-alone and inetd configurations).
If you're using one of the remote-shell transports for the transfer, there is
no need to manually start an rsync daemon.
-## SORTED TRANSFER ORDER
-
-Rsync always sorts the specified filenames into its internal transfer list.
-This handles the merging together of the contents of identically named
-directories, makes it easy to remove duplicate filenames, and may confuse
-someone when the files are transferred in a different order than what was given
-on the command-line.
-
-If you need a particular file to be transferred prior to another, either
-separate the files into different rsync calls, or consider using
-[`--delay-updates`](#opt) (which doesn't affect the sorted transfer order, but
-does make the final file-updating phase happen much more rapidly).
-
## EXAMPLES
-Here are some examples of how I use rsync.
+Here are some examples of how rsync can be used.
-To backup my wife's home directory, which consists of large MS Word files and
-mail folders, I use a cron job that runs
+To backup a home directory, which consists of large MS Word files and mail
+folders, a per-user cron job can be used that runs this each day:
-> rsync -Cavz . arvidsjaur:backup
+> rsync -aiz . bkhost:backup/joe/
-each night over a PPP connection to a duplicate directory on my machine
-"arvidsjaur".
+To move some files from a remote host to the local host, you could run:
-To synchronize my samba source trees I use the following Makefile targets:
-
-> get:
-> rsync -avuzb --exclude '*~' samba:samba/ .
-> put:
-> rsync -Cavuzb . samba:samba/
-> sync: get put
-
-This allows me to sync with a CVS directory at the other end of the connection.
-I then do CVS operations on the remote machine, which saves a lot of time as
-the remote CVS protocol isn't very efficient.
-
-I mirror a directory between my "old" and "new" ftp sites with the command:
-
-> rsync -az -e ssh --delete ~ftp/pub/samba nimbus:"~ftp/pub/tridge"
-
-This is launched from cron every few hours.
+> rsync -aiv --remove-source-files rhost:/tmp/{file1,file2}.c ~/src/
## OPTION SUMMARY
@@ -446,6 +465,7 @@ has its own detailed description later in this manpage.
--from0, -0 all *-from/filter files are delimited by 0s
--old-args disable the modern arg-protection idiom
--protect-args, -s no space-splitting; wildcard chars only
+--trust-sender trust the remote sender's file list
--copy-as=USER[:GROUP] specify user & optional group for the copy
--address=ADDRESS bind address for outgoing socket to daemon
--port=PORT specify double-colon alternate port number
@@ -508,14 +528,22 @@ accepted:
Rsync accepts both long (double-dash + word) and short (single-dash + letter)
options. The full list of the available options are described below. If an
option can be specified in more than one way, the choices are comma-separated.
-Some options only have a long variant, not a short. If the option takes a
-parameter, the parameter is only listed after the long variant, even though it
-must also be specified for the short. When specifying a parameter, you can
-either use the form `--option=param` or replace the '=' with whitespace. The
-parameter may need to be quoted in some manner for it to survive the shell's
-command-line parsing. Keep in mind that a leading tilde (`~`) in a filename is
-substituted by your shell, so `--option=~/foo` will not change the tilde into
-your home directory (remove the '=' for that).
+Some options only have a long variant, not a short.
+
+If the option takes a parameter, the parameter is only listed after the long
+variant, even though it must also be specified for the short. When specifying
+a parameter, you can either use the form `--option=param`, `--option param`,
+`-o=param`, `-o param`, or `-oparam` (the latter choices assume that your
+option has a short variant).
+
+The parameter may need to be quoted in some manner for it to survive the
+shell's command-line parsing. Also keep in mind that a leading tilde (`~`) in
+a pathname is substituted by your shell, so make sure that you separate the
+option name from the pathname using a space if you want the local shell to
+expand it.
+
+[comment]: # (Some markup below uses a literal non-breakable space when a backtick string)
+[comment]: # (needs to contain a space since markdown strips spaces from the start/end)
[comment]: # (An OL starting at 0 is converted into a DL by the parser.)
@@ -793,7 +821,7 @@ your home directory (remove the '=' for that).
In order to make [`--delete`](#opt) compatible with incremental recursion,
rsync 3.0.0 made [`--delete-during`](#opt) the default delete mode (which
- was first first added in 2.6.4).
+ was first added in 2.6.4).
One side-effect of incremental recursion is that any missing
sub-directories inside a recursively-scanned directory are (by default)
@@ -948,9 +976,8 @@ your home directory (remove the '=' for that).
directory where the destination has a file, the transfer would occur
regardless of the timestamps.
- This option is a transfer rule, not an exclude, so it doesn't affect the
- data that goes into the file-lists, and thus it doesn't affect deletions.
- It just limits the files that the receiver requests to be transferred.
+ This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any
+ exclude side effects.
A caution for those that choose to combine [`--inplace`](#opt) with
`--update`: an interrupted transfer will leave behind a partial file on the
@@ -1169,7 +1196,7 @@ your home directory (remove the '=' for that).
transfer, the client is the sender, so specifying the option directly
unmunges symlinks while specifying it as a remote option munges symlinks.
- This option has no affect when sent to a daemon via [`--remote-option`](#opt)
+ This option has no effect when sent to a daemon via [`--remote-option`](#opt)
because the daemon configures whether it wants munged symlinks via its
"`munge symlinks`" parameter.
@@ -1478,7 +1505,7 @@ your home directory (remove the '=' for that).
This tells rsync to treat a device on the sending side as a regular file,
allowing it to be copied to a normal destination file (or another device
- if `--write-devices` was also specifed).
+ if `--write-devices` was also specified).
This option is refused by default by an rsync daemon.
@@ -1733,9 +1760,8 @@ your home directory (remove the '=' for that).
[`--ignore-existing`](#opt) option, no files will be updated (which can be
useful if all you want to do is delete extraneous files).
- This option is a transfer rule, not an exclude, so it doesn't affect the
- data that goes into the file-lists, and thus it doesn't affect deletions.
- It just limits the files that the receiver requests to be transferred.
+ This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any
+ exclude side effects.
0. `--ignore-existing`
@@ -1743,9 +1769,8 @@ your home directory (remove the '=' for that).
destination (this does _not_ ignore existing directories, or nothing would
get done). See also [`--ignore-non-existing`](#opt).
- This option is a transfer rule, not an exclude, so it doesn't affect the
- data that goes into the file-lists, and thus it doesn't affect deletions.
- It just limits the files that the receiver requests to be transferred.
+ This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any
+ exclude side effects.
This option can be useful for those doing backups using the
[`--link-dest`](#opt) option when they need to continue a backup run that
@@ -1874,13 +1899,25 @@ your home directory (remove the '=' for that).
0. `--delete-excluded`
- In addition to deleting the files on the receiving side that are not on the
- sending side, this tells rsync to also delete any files on the receiving
- side that are excluded (see [`--exclude`](#opt)). See the [FILTER
- RULES](#) section for a way to make individual exclusions behave this way
- on the receiver, and for a way to protect files from `--delete-excluded`.
- See [`--delete`](#opt) (which is implied) for more details on
- file-deletion.
+ This option turns any unqualified exclude/include rules into server-side
+ rules that do not affect the receiver's deletions.
+
+ By default, an exclude or include has both a server-side effect (to "hide"
+ and "show" files when building the server's file list) and a receiver-side
+ effect (to "protect" and "risk" files when deletions are occuring). Any
+ rule that has no modifier to specify what sides it is executed on will be
+ instead treated as if it were a server-side rule only, avoiding any
+ "protect" effects of the rules.
+
+ A rule can still apply to both sides even with this option specified if the
+ rule is given both the sender & receiver modifer letters (e.g., `-f'-sr
+ foo'`). Receiver-side protect/risk rules can also be explicitly specified
+ to limit the deletions. This saves you from having to edit a bunch of
+ `-f'- foo'` rules into `-f'-s foo'` (aka `-f'H foo'`) rules (not to mention
+ the corresponding includes).
+
+ See the [FILTER RULES](#) section for more information. See
+ [`--delete`](#opt) (which is implied) for more details on deletion.
0. `--ignore-missing-args`
@@ -1941,9 +1978,8 @@ your home directory (remove the '=' for that).
the numeric units or left unqualified to specify bytes. Feel free to use a
fractional value along with the units, such as `--max-size=1.5m`.
- This option is a transfer rule, not an exclude, so it doesn't affect the
- data that goes into the file-lists, and thus it doesn't affect deletions.
- It just limits the files that the receiver requests to be transferred.
+ This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any
+ exclude side effects.
The first letter of a units string can be `B` (bytes), `K` (kilo), `M`
(mega), `G` (giga), `T` (tera), or `P` (peta). If the string is a single
@@ -2200,8 +2236,8 @@ your home directory (remove the '=' for that).
0. `--exclude=PATTERN`
This option is a simplified form of the [`--filter`](#opt) option that
- defaults to an exclude rule and does not allow the full rule-parsing syntax
- of normal filter rules.
+ specifies an exclude rule and does not allow the full rule-parsing syntax
+ of normal filter rules. This is equivalent to specifying `-f'- PATTERN'`.
See the [FILTER RULES](#) section for detailed information on this option.
@@ -2212,13 +2248,20 @@ your home directory (remove the '=' for that).
file are ignored, as are whole-line comments that start with '`;`' or '`#`'
(filename rules that contain those characters are unaffected).
+ If a line begins with "`-Â `" (dash, space) or "`+Â `" (plus, space), then
+ the type of rule is being explicitly specified as an exclude or an include
+ (respectively). Any rules without such a prefix are taken to be an exclude.
+
+ If a line consists of just "`!`", then the current filter rules are cleared
+ before adding any further rules.
+
If _FILE_ is '`-`', the list will be read from standard input.
0. `--include=PATTERN`
This option is a simplified form of the [`--filter`](#opt) option that
- defaults to an include rule and does not allow the full rule-parsing syntax
- of normal filter rules.
+ specifies an include rule and does not allow the full rule-parsing syntax
+ of normal filter rules. This is equivalent to specifying `-f'+ PATTERN'`.
See the [FILTER RULES](#) section for detailed information on this option.
@@ -2229,6 +2272,13 @@ your home directory (remove the '=' for that).
file are ignored, as are whole-line comments that start with '`;`' or '`#`'
(filename rules that contain those characters are unaffected).
+ If a line begins with "`-Â `" (dash, space) or "`+Â `" (plus, space), then
+ the type of rule is being explicitly specified as an exclude or an include
+ (respectively). Any rules without such a prefix are taken to be an include.
+
+ If a line consists of just "`!`", then the current filter rules are cleared
+ before adding any further rules.
+
If _FILE_ is '`-`', the list will be read from standard input.
0. `--files-from=FILE`
@@ -2323,6 +2373,12 @@ your home directory (remove the '=' for that).
behavior. The environment is always overridden by manually specified
positive or negative options (the negative is `--no-old-args`).
+ Note that this option also disables the extra safety check added in 3.2.5
+ that ensures that a remote sender isn't including extra top-level items in
+ the file-list that you didn't request. This side-effect is necessary
+ because we can't know for sure what names to expect when the remote shell
+ is interpreting the args.
+
This option conflicts with the [`--protect-args`](#opt) option.
0. `--protect-args`, `-s`
@@ -2356,6 +2412,42 @@ your home directory (remove the '=' for that).
Note that this option is incompatible with the use of the restricted rsync
script (`rrsync`) since it hides options from the script's inspection.
+0. `--trust-sender`
+
+ This option disables two extra validation checks that a local client
+ performs on the file list generated by a remote sender. This option should
+ only be used if you trust the sender to not put something malicious in the
+ file list (something that could possibly be done via a modified rsync, a
+ modified shell, or some other similar manipulation).
+
+ Normally, the rsync client (as of version 3.2.5) runs two extra validation
+ checks when pulling files from a remote rsync:
+
+ - It verifies that additional arg items didn't get added at the top of the
+ transfer.
+ - It verifies that none of the items in the file list are names that should
+ have been excluded (if filter rules were specified).
+
+ Note that various options can turn off one or both of these checks if the
+ option interferes with the validation. For instance:
+
+ - Using a per-directory filter file reads filter rules that only the server
+ knows about, so the filter checking is disabled.
+ - Using the [`--old-args`](#opt) option allows the sender to manipulate the
+ requested args, so the arg checking is disabled.
+ - Reading the files-from list from the server side means that the client
+ doesn't know the arg list, so the arg checking is disabled.
+ - Using [`--read-batch`](#opt) disables both checks since the batch file's
+ contents will have been verified when it was created.
+
+ This option may help an under-powered client server if the extra pattern
+ matching is slowing things down on a huge transfer. It can also be used to
+ work around a currently-unknown bug in the verification logic for a transfer
+ from a trusted sender.
+
+ When using this option it is a good idea to specify a dedicated destination
+ directory, as discussed in the [MULTI-HOST SECURITY](#) section.
+
0. `--copy-as=USER[:GROUP]`
This option instructs rsync to use the USER and (if specified after a
@@ -3017,7 +3109,7 @@ your home directory (remove the '=' for that).
of "%i %n%L". See the [`--log-file-format`](#opt) option if you wish to
override this.
- Here's a example command that requests the remote side to log what is
+ Here's an example command that requests the remote side to log what is
happening:
> rsync -av --remote-option=--log-file=/tmp/rlog src/ dest/
@@ -3255,10 +3347,8 @@ your home directory (remove the '=' for that).
directories when the sending rsync is recursively scanning a hierarchy of
files using include/exclude/filter rules.
- Note that the use of transfer rules, such as the [`--min-size`](#opt)
- option, does not affect what goes into the file list, and thus does not
- leave directories empty, even if none of the files in a directory match the
- transfer rule.
+ This option can still leave empty directories on the receiving side if you
+ make use of [TRANSFER_RULES](#).
Because the file-list is actually being pruned, this option also affects
what directories get deleted when a delete is active. However, keep in
@@ -3394,8 +3484,8 @@ your home directory (remove the '=' for that).
include the destination.
CAUTION: keep in mind that a source arg with a wild-card is expanded by the
- shell into multiple args, so it is never safe to try to list such an arg
- without using this option. For example:
+ shell into multiple args, so it is never safe to try to specify a single
+ wild-card arg to try to infer this option. A safe example is:
> rsync -av --list-only foo* dest/
@@ -3721,27 +3811,146 @@ The options allowed when starting an rsync daemon are as follows:
## FILTER RULES
-The filter rules allow for flexible selection of which files to transfer
-(include) and which files to skip (exclude). The rules either directly specify
-include/exclude patterns or they specify a way to acquire more include/exclude
-patterns (e.g. to read them from a file).
-
-As the list of files/directories to transfer is built, rsync checks each name
-to be transferred against the list of include/exclude patterns in turn, and the
-first matching pattern is acted on: if it is an exclude pattern, then that file
-is skipped; if it is an include pattern then that filename is not skipped; if
-no matching pattern is found, then the filename is not skipped.
-
-Aside: because the interactions of filter rules can be complex, it is useful to
-use the `--debug=FILTER` option if things aren't working the way you expect.
-The level-1 output (the default if no level number is specified) mentions the
-filter rule that is first matched by each file in the transfer. It also warns
-if a filter rule has trailing whitespace. The level-2 output mentions a lot
-more filter events, including the definition of each rule and the handling of
-per-directory filter files.
-
-Rsync builds an ordered list of filter rules as specified on the command-line.
-Filter rules have the following syntax:
+The filter rules allow for custom control of several aspects of how files are
+handled:
+
+- Control which files the sending side puts into the file list that describes
+ the transfer hierarchy
+- Control which files the receiving side protects from deletion when the file
+ is not in the sender's file list
+- Control which extended attribute names are skipped when copying xattrs
+
+The rules are either directly specified via option arguments or they can be
+read in from one or more files. The filter-rule files can even be a part of
+the hierarchy of files being copied, affecting different parts of the tree in
+different ways.
+
+### SIMPLE INCLUDE/EXCLUDE RULES
+
+We will first cover the basics of how include & exclude rules affect what files
+are transferred, ignoring any deletion side-effects. Filter rules mainly
+affect the contents of directories that rsync is "recursing" into, but they can
+also affect a top-level item in the transfer that was specified as a argument.
+
+The default for any unmatched file/dir is for it to be included in the
+transfer, which puts the file/dir into the sender's file list. The use of an
+exclude rule causes one or more matching files/dirs to be left out of the
+sender's file list. An include rule can be used to limit the effect of an
+exclude rule that is matching too many files.
+
+The order of the rules is important because the first rule that matches is the
+one that takes effect. Thus, if an early rule excludes a file, no include rule
+that comes after it can have any effect. This means that you must place any
+include overrides somewhere prior to the exclude that it is intended to limit.
+
+When a directory is excluded, all its contents and sub-contents are also
+excluded. The sender doesn't scan through any of it at all, which can save a
+lot of time when skipping large unneeded sub-trees.
+
+It is also important to understand that the include/exclude rules are applied
+to every file and directory that the sender is recursing into. Thus, if you
+want a particular deep file to be included, you have to make sure that none of
+the directories that must be traversed on the way down to that file are
+excluded or else the file will never be discovered to be included. As an
+example, if the directory "`a/path`" was given as a transfer argument and you
+want to ensure that the file "`a/path/down/deep/wanted.txt`" is a part of the
+transfer, then the sender must not exclude the directories "`a/path`",
+"`a/path/down`", or "`a/path/down/deep`" as it makes it way scanning through
+the file tree.
+
+When you are working on the rules, it can be helpful to ask rsync to tell you
+what is being excluded/included and why. Specifying `--debug=FILTER` or (when
+pulling files) `-M--debug=FILTER` turns on level 1 of the FILTER debug
+information that will output a message any time that a file or directory is
+included or excluded and which rule it matched. Beginning in 3.2.4 it will
+also warn if a filter rule has trailing whitespace, since an exclude of "foo "
+(with a trailing space) will not exclude a file named "foo".
+
+Exclude and include rules can specify wildcard [PATTERN MATCHING RULES](#)
+(similar to shell wildcards) that allow you to match things like a file suffix
+or a portion of a filename.
+
+A rule can be limited to only affecting a directory by putting a trailing slash
+onto the filename.
+
+### SIMPLE INCLUDE/EXCLUDE EXAMPLE
+
+With the following file tree created on the sending side:
+
+> mkdir x/
+> touch x/file.txt
+> mkdir x/y/
+> touch x/y/file.txt
+> touch x/y/zzz.txt
+> mkdir x/z/
+> touch x/z/file.txt
+
+Then the following rsync command will transfer the file "`x/y/file.txt`" and
+the directories needed to hold it, resulting in the path "`/tmp/x/y/file.txt`"
+existing on the remote host:
+
+> rsync -ai -f'+ x/' -f'+ x/y/' -f'+ x/y/file.txt' -f'- *' x host:/tmp/
+
+Aside: this copy could also have been accomplished using the [`-R`](#opt)
+option (though the 2 commands behave differently if deletions are enabled):
+
+> rsync -aiR x/y/file.txt host:/tmp/
+
+The following command does not need an include of the "x" directory because it
+is not a part of the transfer (note the traililng slash). Running this command
+would copy just "`/tmp/x/file.txt`" because the "y" and "z" dirs get excluded:
+
+> rsync -ai -f'+ file.txt' -f'- *' x/ host:/tmp/x/
+
+This command would omit the zzz.txt file while copying "x" and everything else
+it contains:
+
+> rsync -ai -f'- zzz.txt' x host:/tmp/
+
+### FILTER RULES WHEN DELETING
+
+By default the include & exclude filter rules affect both the sender
+(as it creates its file list)
+and the receiver (as it creates its file lists for calculating deletions). If
+no delete option is in effect, the receiver skips creating the delete-related
+file lists. This two-sided default can be manually overridden so that you are
+only specifying sender rules or receiver rules, as described in the [FILTER
+RULES IN DEPTH](#) section.
+
+When deleting, an exclude protects a file from being removed on the receiving
+side while an include overrides that protection (putting the file at risk of
+deletion). The default is for a file to be at risk -- its safety depends on it
+matching a corresponding file from the sender.
+
+An example of the two-sided exclude effect can be illustrated by the copying of
+a C development directory between 2 systems. When doing a touch-up copy, you
+might want to skip copying the built executable and the `.o` files (sender
+hide) so that the receiving side can build their own and not lose any object
+files that are already correct (receiver protect). For instance:
+
+> rsync -ai --del -f'- *.o' -f'- cmd' src host:/dest/
+
+Note that using `-f'-p *.o'` is even better than `-f'- *.o'` if there is a
+chance that the directory structure may have changed. The "p" modifier is
+discussed in [FILTER RULE MODIFIERS](#).
+
+One final note, if your shell doesn't mind unexpanded wildcards, you could
+simplify the typing of the filter options by using an underscore in place of
+the space and leaving off the quotes. For instance, `-f -_*.o -f -_cmd` (and
+similar) could be used instead of the filter options above.
+
+### FILTER RULES IN DEPTH
+
+Rsync supports old-style include/exclude rules and new-style filter rules. The
+older rules are specified using [`--include`](#opt) and [`--exclude`](#opt) as
+well as the [`--include-from`](#opt) and [`--exclude-from`](#opt). These are
+limited in behavior but they don't require a "-" or "+" prefix. An old-style
+exclude rule is turned into a "`- name`" filter rule (with no modifiers) and an
+old-style include rule is turned into a "`+ name`" filter rule (with no
+modifiers).
+
+Rsync builds an ordered list of filter rules as specified on the command-line
+and/or read-in from files. New style filter rules have the following syntax:
> RULE [PATTERN_OR_FILENAME]
> RULE,MODIFIERS [PATTERN_OR_FILENAME]
@@ -3749,35 +3958,36 @@ Filter rules have the following syntax:
You have your choice of using either short or long RULE names, as described
below. If you use a short-named rule, the ',' separating the RULE from the
MODIFIERS is optional. The PATTERN or FILENAME that follows (when present)
-must come after either a single space or an underscore (\_). Here are the
-available rule prefixes:
+must come after either a single space or an underscore (\_). Any additional
+spaces and/or underscores are considered to be a part of the pattern name.
+Here are the available rule prefixes:
-0. `exclude, '-'` specifies an exclude pattern.
-0. `include, '+'` specifies an include pattern.
-0. `merge, '.'` specifies a merge-file to read for more rules.
-0. `dir-merge, ':'` specifies a per-directory merge-file.
+0. `exclude, '-'` specifies an exclude pattern that (by default) is both a
+ `hide` and a `protect`.
+0. `include, '+'` specifies an include pattern that (by default) is both a
+ `show` and a `risk`.
+0. `merge, '.'` specifies a merge-file on the client side to read for more
+ rules.
+0. `dir-merge, ':'` specifies a per-directory merge-file. Using this kind of
+ filter rule requires that you trust the sending side's filter checking, so
+ it has the side-effect mentioned under the [`--trust-sender`](#opt) option.
0. `hide, 'H'` specifies a pattern for hiding files from the transfer.
-0. `show, 'S'` files that match the pattern are not hidden.
+ Equivalent to a sender-only exclude, so `-f'H foo'` could also be specified
+ as `-f'-s foo'`.
+0. `show, 'S'` files that match the pattern are not hidden. Equivalent to a
+ sender-only include, so `-f'S foo'` could also be specified as `-f'+s
+ foo'`.
0. `protect, 'P'` specifies a pattern for protecting files from deletion.
-0. `risk, 'R'` files that match the pattern are not protected.
+ Equivalent to a receiver-only exclude, so `-f'P foo'` could also be
+ specified as `-f'-r foo'`.
+0. `risk, 'R'` files that match the pattern are not protected. Equivalent to a
+ receiver-only include, so `-f'R foo'` could also be specified as `-f'+r
+ foo'`.
0. `clear, '!'` clears the current include/exclude list (takes no arg)
-When rules are being read from a file, empty lines are ignored, as are
-whole-line comments that start with a '`#`' (filename rules that contain a hash
-are unaffected).
-
-[comment]: # (Remember that markdown strips spaces from start/end of ` ... ` sequences!)
-[comment]: # (Thus, the `x ` sequences below use a literal non-breakable space!)
-
-Note that the [`--include`](#opt) & [`--exclude`](#opt) command-line options do
-not allow the full range of rule parsing as described above -- they only allow
-the specification of include / exclude patterns plus a "`!`" token to clear the
-list (and the normal comment parsing when rules are read from a file). If a
-pattern does not begin with "`-Â `" (dash, space) or "`+Â `" (plus, space), then
-the rule will be interpreted as if "`+Â `" (for an include option) or "`-Â `"
-(for an exclude option) were prefixed to the string. A [`--filter`](#opt)
-option, on the other hand, must always contain either a short or long rule name
-at the start of the rule.
+When rules are being read from a file (using merge or dir-merge), empty lines
+are ignored, as are whole-line comments that start with a '`#`' (filename rules
+that contain a hash character are unaffected).
Note also that the [`--filter`](#opt), [`--include`](#opt), and
[`--exclude`](#opt) options take one rule/pattern each. To add multiple ones,
@@ -3785,121 +3995,90 @@ you can repeat the options on the command-line, use the merge-file syntax of
the [`--filter`](#opt) option, or the [`--include-from`](#opt) /
[`--exclude-from`](#opt) options.
-## INCLUDE/EXCLUDE PATTERN RULES
+### PATTERN MATCHING RULES
-You can include and exclude files by specifying patterns using the "+", "-",
-etc. filter rules (as introduced in the [FILTER RULES](#) section above). The
-include/exclude rules each specify a pattern that is matched against the names
-of the files that are going to be transferred. These patterns can take several
-forms:
+Most of the rules mentioned above take an argument that specifies what the rule
+should match. If rsync is recursing through a directory hierarchy, keep in
+mind that each pattern is matched against the name of every directory in the
+descent path as rsync finds the filenames to send.
-- if the pattern starts with a `/` then it is anchored to a particular spot in
- the hierarchy of files, otherwise it is matched against the end of the
- pathname. This is similar to a leading `^` in regular expressions. Thus
- `/foo` would match a name of "foo" at either the "root of the transfer" (for
- a global rule) or in the merge-file's directory (for a per-directory rule).
- An unqualified `foo` would match a name of "foo" anywhere in the tree because
- the algorithm is applied recursively from the top down; it behaves as if each
- path component gets a turn at being the end of the filename. Even the
- unanchored "sub/foo" would match at any point in the hierarchy where a "foo"
- was found within a directory named "sub". See the section on ANCHORING
- INCLUDE/EXCLUDE PATTERNS for a full discussion of how to specify a pattern
- that matches at the root of the transfer.
-- if the pattern ends with a `/` then it will only match a directory, not a
- regular file, symlink, or device.
-- rsync chooses between doing a simple string match and wildcard matching by
- checking if the pattern contains one of these three wildcard characters:
- '`*`', '`?`', and '`[`' .
-- a '`*`' matches any path component, but it stops at slashes.
-- use '`**`' to match anything, including slashes.
-- a '`?`' matches any character except a slash (`/`).
-- a '`[`' introduces a character class, such as `[a-z]` or `[[:alpha:]]`.
-- in a wildcard pattern, a backslash can be used to escape a wildcard
- character, but it is matched literally when no wildcards are present. This
- means that there is an extra level of backslash removal when a pattern
- contains wildcard characters compared to a pattern that has none. e.g. if
- you add a wildcard to "`foo\bar`" (which matches the backslash) you would
- need to use "`foo\\bar*`" to avoid the "`\b`" becoming just "b".
-- if the pattern contains a `/` (not counting a trailing /) or a "`**`", then it
- is matched against the full pathname, including any leading directories. If
- the pattern doesn't contain a `/` or a "`**`", then it is matched only against
- the final component of the filename. (Remember that the algorithm is applied
- recursively so "full filename" can actually be any portion of a path from the
- starting directory on down.)
-- a trailing "`dir_name/***`" will match both the directory (as if "dir_name/"
+The matching rules for the pattern argument take several forms:
+
+- If a pattern contains a `/` (not counting a trailing slash) or a "`**`"
+ (which can match a slash), then the pattern is matched against the full
+ pathname, including any leading directories within the transfer. If the
+ pattern doesn't contain a (non-trailing) `/` or a "`**`", then it is matched
+ only against the final component of the filename or pathname. For example,
+ `foo` means that the final path component must be "foo" while `foo/bar` would
+ match the last 2 elements of the path (as long as both elements are within
+ the transfer).
+- A pattern that ends with a `/` only matches a directory, not a regular file,
+ symlink, or device.
+- A pattern that starts with a `/` is anchored to the start of the transfer
+ path instead of the end. For example, `/foo/**` or `/foo/bar/**` match only
+ leading elements in the path. If the rule is read from a per-directory
+ filter file, the transfer path being matched will begin at the level of the
+ filter file instead of the top of the transfer. See the section on
+ [ANCHORING INCLUDE/EXCLUDE PATTERNS](#) for a full discussion of how to
+ specify a pattern that matches at the root of the transfer.
+
+Rsync chooses between doing a simple string match and wildcard matching by
+checking if the pattern contains one of these three wildcard characters: '`*`',
+'`?`', and '`[`' :
+
+- a '`?`' matches any single character except a slash (`/`).
+- a '`*`' matches zero or more non-slash characters.
+- a '`**`' matches zero or more characters, including slashes.
+- a '`[`' introduces a character class, such as `[a-z]` or `[[:alpha:]]`, that
+ must match one character.
+- a trailing `***` in the pattern is a shorthand that allows you to match a
+ directory and all its contents using a single rule. For example, specifying
+ "`dir_name/***`" will match both the "dir_name" directory (as if "`dir_name/`"
had been specified) and everything in the directory (as if "`dir_name/**`"
- had been specified). This behavior was added in version 2.6.7.
-
-Note that, when using the [`--recursive`](#opt) (`-r`) option (which is implied
-by [`-a`](#opt)), every subdir component of every path is visited left to
-right, with each directory having a chance for exclusion before its content.
-In this way include/exclude patterns are applied recursively to the pathname of
-each node in the filesystem's tree (those inside the transfer). The exclude
-patterns short-circuit the directory traversal stage as rsync finds the files
-to send.
-
-For instance, to include "`/foo/bar/baz`", the directories "`/foo`" and "`/foo/bar`"
-must not be excluded. Excluding one of those parent directories prevents the
-examination of its content, cutting off rsync's recursion into those paths and
-rendering the include for "`/foo/bar/baz`" ineffectual (since rsync can't match
-something it never sees in the cut-off section of the directory hierarchy).
-
-The concept path exclusion is particularly important when using a trailing '`*`'
-rule. For instance, this won't work:
-
-> + /some/path/this-file-will-not-be-found
-> + /file-is-included
-> - *
-
-This fails because the parent directory "some" is excluded by the '`*`' rule, so
-rsync never visits any of the files in the "some" or "some/path" directories.
-One solution is to ask for all directories in the hierarchy to be included by
-using a single rule: "`+ */`" (put it somewhere before the "`- *`" rule), and
-perhaps use the [`--prune-empty-dirs`](#opt) option. Another solution is to add
-specific include rules for all the parent dirs that need to be visited. For
-instance, this set of rules works fine:
-
-> + /some/
-> + /some/path/
-> + /some/path/this-file-is-found
-> + /file-also-included
-> - *
+ had been specified).
+- a backslash can be used to escape a wildcard character, but it is only
+ interpreted as an escape character if at least one wildcard character is
+ present in the match pattern. For instance, the pattern "`foo\bar`" matches
+ that single backslash literally, while the pattern "`foo\bar*`" would need to
+ be changed to "`foo\\bar*`" to avoid the "`\b`" becoming just "b".
Here are some examples of exclude/include matching:
-- "`- *.o`" would exclude all names matching `*.o`
-- "`- /foo`" would exclude a file (or directory) named foo in the transfer-root
- directory
-- "`- foo/`" would exclude any directory named foo
-- "`- /foo/*/bar`" would exclude any file named bar which is at two levels
- below a directory named foo in the transfer-root directory
-- "`- /foo/**/bar`" would exclude any file named bar two or more levels below a
- directory named foo in the transfer-root directory
-- The combination of "`+ */`", "`+ *.c`", and "`- *`" would include all
- directories and C source files but nothing else (see also the
- [`--prune-empty-dirs`](#opt) option)
-- The combination of "`+ foo/`", "`+ foo/bar.c`", and "`- *`" would include
- only the foo directory and foo/bar.c (the foo directory must be explicitly
- included or it would be excluded by the "`*`")
+- Option `-f'- *.o'` would exclude all filenames ending with `.o`
+- Option `-f'- /foo'` would exclude a file (or directory) named foo in the
+ transfer-root directory
+- Option `-f'- foo/'` would exclude any directory named foo
+- Option `-f'- foo/*/bar'` would exclude any file/dir named bar which is at two
+ levels below a directory named foo (if foo is in the transfer)
+- Option `-f'- /foo/**/bar'` would exclude any file/dir named bar that was two
+ or more levels below a top-level directory named foo (note that /foo/bar is
+ **not** excluded by this)
+- Options `-f'+ */' -f'+ *.c' -f'- *'` would include all directories and .c
+ source files but nothing else
+- Options `-f'+ foo/' -f'+ foo/bar.c' -f'- *'` would include only the foo
+ directory and foo/bar.c (the foo directory must be explicitly included or it
+ would be excluded by the "`- *`")
-The following modifiers are accepted after a "`+`" or "`-`":
+### FILTER RULE MODIFIERS
+
+The following modifiers are accepted after an include (+) or exclude (-) rule:
- A `/` specifies that the include/exclude rule should be matched against the
- absolute pathname of the current item. For example, "`-/ /etc/passwd`" would
- exclude the passwd file any time the transfer was sending files from the
- "/etc" directory, and "-/ subdir/foo" would always exclude "foo" when it is
- in a dir named "subdir", even if "foo" is at the root of the current
+ absolute pathname of the current item. For example, `-f'-/ /etc/passwd'`
+ would exclude the passwd file any time the transfer was sending files from
+ the "/etc" directory, and "-/ subdir/foo" would always exclude "foo" when it
+ is in a dir named "subdir", even if "foo" is at the root of the current
transfer.
- A `!` specifies that the include/exclude should take effect if the pattern
- fails to match. For instance, "`-! */`" would exclude all non-directories.
+ fails to match. For instance, `-f'-! */'` would exclude all non-directories.
- A `C` is used to indicate that all the global CVS-exclude rules should be
inserted as excludes in place of the "-C". No arg should follow.
- An `s` is used to indicate that the rule applies to the sending side. When a
- rule affects the sending side, it prevents files from being transferred. The
- default is for a rule to affect both sides unless [`--delete-excluded`](#opt)
- was specified, in which case default rules become sender-side only. See also
- the hide (H) and show (S) rules, which are an alternate way to specify
- sending-side includes/excludes.
+ rule affects the sending side, it affects what files are put into the
+ sender's file list. The default is for a rule to affect both sides unless
+ [`--delete-excluded`](#opt) was specified, in which case default rules become
+ sender-side only. See also the hide (H) and show (S) rules, which are an
+ alternate way to specify sending-side includes/excludes.
- An `r` is used to indicate that the rule applies to the receiving side. When
a rule affects the receiving side, it prevents files from being deleted. See
the `s` modifier for more info. See also the protect (P) and risk (R) rules,
@@ -3915,7 +4094,7 @@ The following modifiers are accepted after a "`+`" or "`-`":
xattr-matching rules are specified, a default xattr filtering rule is used
(see the [`--xattrs`](#opt) option).
-## MERGE-FILE FILTER RULES
+### MERGE-FILE FILTER RULES
You can merge whole files into your filter rules by specifying either a merge
(.) or a dir-merge (:) filter rule (as introduced in the [FILTER RULES](#)
@@ -4049,7 +4228,7 @@ $HOME/.cvsignore, and the value of $CVSIGNORE) you should omit the `-C`
command-line option and instead insert a "-C" rule into your filter rules; e.g.
"`--filter=-C`".
-## LIST-CLEARING FILTER RULE
+### LIST-CLEARING FILTER RULE
You can clear the current include/exclude list by using the "!" filter rule (as
introduced in the [FILTER RULES](#) section above). The "current" list is either
@@ -4057,7 +4236,7 @@ the global list of rules (if the rule is encountered while parsing the filter
options) or a set of per-directory rules (which are inherited in their own
sub-list, so a subdirectory can use this to clear out the parent's rules).
-## ANCHORING INCLUDE/EXCLUDE PATTERNS
+### ANCHORING INCLUDE/EXCLUDE PATTERNS
As mentioned earlier, global include/exclude patterns are anchored at the "root
of the transfer" (as opposed to per-directory patterns, which are anchored at
@@ -4112,7 +4291,7 @@ The easiest way to see what name you should filter is to just look at the
output when using [`--verbose`](#opt) and put a / in front of the name (use the
`--dry-run` option if you're not yet ready to copy any files).
-## PER-DIRECTORY RULES AND DELETE
+### PER-DIRECTORY RULES AND DELETE
Without a delete option, per-directory rules are only relevant on the sending
side, so you can feel free to exclude the merge files themselves without
@@ -4158,6 +4337,38 @@ one of these commands:
> rsync -avFF --delete host:src/dir /dest
> ```
+## TRANSFER RULES
+
+In addition to the [FILTER RULES](#) that affect the recursive file scans that
+generate the file list on the sending and (when deleting) receiving sides,
+there are transfer rules. These rules affect which files the generator decides
+need to be transferred without the side effects of an exclude filter rule.
+Transfer rules affect only files and never directories.
+
+Because a transfer rule does not affect what goes into the sender's (and
+receiver's) file list, it cannot have any effect on which files get deleted on
+the receiving side. For example, if the file "foo" is present in the sender's
+list but its size is such that it is omitted due to a transfer rule, the
+receiving side does not request the file. However, its presence in the file
+list means that a delete pass will not remove a matching file named "foo" on
+the receiving side. On the other hand, a server-side exclude (hide) of the
+file "foo" leaves the file out of the server's file list, and absent a
+receiver-side exclude (protect) the receiver will remove a matching file named
+"foo" if deletions are requested.
+
+Given that the files are still in the sender's file list, the
+[`--prune-empty-dirs`](#opt) option will not judge a directory as being empty
+even if it contains only files that the transfer rules omitted.
+
+Similarly, a transfer rule does not have any extra effect on which files are
+deleted on the receiving side, so setting a maximum file size for the transfer
+does not prevent big files from being deleted.
+
+Examples of transfer rules include the default "quick check" algorithm (which
+compares size & modify time), the [`--update`](#opt) option, the
+[`--max-size`](#opt) option, the [`--ignore-non-existing`](#opt) option, and a
+few others.
+
## BATCH MODE
Batch mode can be used to apply the same set of updates to many identical
@@ -4466,7 +4677,7 @@ file is included or excluded.
0. `RSYNC_SHELL`
This environment variable is mainly used in debug setups to set the program
- to use to run the program specified by [`RSYNC_CONNECT_PROG`]. See
+ to use to run the program specified by [`RSYNC_CONNECT_PROG`](#). See
[CONNECTING TO AN RSYNC DAEMON](#) for full details.
## FILES
diff --git a/rsync.c b/rsync.c
index 102e72ed..cd288f57 100644
--- a/rsync.c
+++ b/rsync.c
@@ -642,7 +642,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
#ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator
* will enable owner-writability using chmod, if necessary.
- *
+ *
* If set_acl() changes permission bits in the process of setting
* an access ACL, it changes sxp->st.st_mode so we know whether we
* need to chmod(). */
diff --git a/rsync.h b/rsync.h
index e5aacd25..1cc037c5 100644
--- a/rsync.h
+++ b/rsync.h
@@ -338,6 +338,9 @@ enum delret {
# endif
# include
#endif
+#ifdef HAVE_BSD_STRING_H
+# include
+#endif
#ifdef HAVE_STRINGS_H
# include
#endif
diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md
index c61765a7..8bcbec0a 100644
--- a/rsyncd.conf.5.md
+++ b/rsyncd.conf.5.md
@@ -1114,15 +1114,15 @@ SSL proxy.
## SSL/TLS Daemon Setup
When setting up an rsync daemon for access via SSL/TLS, you will need to
-configure a proxy (such as haproxy or nginx) as the front-end that handles the
-encryption.
+configure a TCP proxy (such as haproxy or nginx) as the front-end that handles
+the encryption.
- You should limit the access to the backend-rsyncd port to only allow the
proxy to connect. If it is on the same host as the proxy, then configuring
it to only listen on localhost is a good idea.
-- You should consider turning on the `proxy protocol` parameter if your proxy
- supports sending that information. The examples below assume that this is
- enabled.
+- You should consider turning on the `proxy protocol` rsync-daemon parameter if
+ your proxy supports sending that information. The examples below assume that
+ this is enabled.
An example haproxy setup is as follows:
@@ -1149,14 +1149,14 @@ An example nginx proxy setup is as follows:
> ssl_certificate_key /etc/letsencrypt/example.com/privkey.pem;
>
> proxy_pass localhost:873;
-> proxy_protocol on; # Requires "proxy protocol = true"
+> proxy_protocol on; # Requires rsyncd.conf "proxy protocol = true"
> proxy_timeout 1m;
> proxy_connect_timeout 5s;
> }
> }
> ```
-## EXAMPLES
+## DAEMON CONFIG EXAMPLES
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
`/home/ftp` would be:
@@ -1237,8 +1237,9 @@ Thanks to Karsten Thygesen for his many suggestions and documentation!
## AUTHOR
-Rsync was written by Andrew Tridgell and Paul Mackerras. Many people have
-later contributed to it.
+Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many
+people have later contributed to it. It is currently maintained by Wayne
+Davison.
Mailing lists for support and development are available at
.
diff --git a/support/rrsync.1.md b/support/rrsync.1.md
index 54980db0..a7365323 100644
--- a/support/rrsync.1.md
+++ b/support/rrsync.1.md
@@ -11,14 +11,16 @@ rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR
The single non-option argument specifies the restricted _DIR_ to use. It can be
relative to the user's home directory or an absolute path.
-The online version of this man page (that includes cross-linking of topics)
+The online version of this manpage (that includes cross-linking of topics)
is available at .
## DESCRIPTION
A user's ssh login can be restricted to only allow the running of an rsync
-transfer in one of two easy ways: forcing the running of the rrsync script
-or forcing the running of an rsync daemon-over-ssh command.
+transfer in one of two easy ways:
+
+* forcing the running of the rrsync script
+* forcing the running of an rsync daemon-over-ssh command.
To use the rrsync script, edit the user's `~/.ssh/authorized_keys` file and add
a prefix like one of the following (followed by a space) in front of each
@@ -47,13 +49,14 @@ ssh-key line that should be restricted:
Then, ensure that the rsyncd.conf file is created with one or more module names
with the appropriate path and option restrictions. If rsync's
[`--config`](rsync.1#dopt) option is omitted, it defaults to `~/rsyncd.conf`.
-See the `rsyncd.conf` man page for details of how to configure an rsync daemon.
+See the [**rsyncd.conf**(5)](rsyncd.conf.5) manpage for details of how to
+configure an rsync daemon.
When using rrsync, there can be just one restricted dir per authorized key. A
daemon setup, on the other hand, allows multiple module names inside the config
file, each one with its own path setting.
-The remainder of this man page is dedicated to using the rrsync script.
+The remainder of this manpage is dedicated to using the rrsync script.
## OPTIONS
@@ -119,11 +122,11 @@ The `~/.ssh/authorized_keys` file might have lines in it like this:
## SEE ALSO
-[**rsync**(1)](rsync.1)
+[**rsync**(1)](rsync.1), [**rsyncd.conf**(5)](rsyncd.conf.5)
## VERSION
-This man page is current for version @VERSION@ of rsync.
+This manpage is current for version @VERSION@ of rsync.
## CREDITS
diff --git a/uidlist.c b/uidlist.c
index 6100b503..99a34679 100644
--- a/uidlist.c
+++ b/uidlist.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2004-2020 Wayne Davison
+ * Copyright (C) 2004-2022 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -210,7 +210,7 @@ static int is_in_group(gid_t gid)
ngroups = getgroups(ngroups, gidset);
/* The default gid might not be in the list on some systems. */
for (n = 0; n < ngroups; n++) {
- if (gidset[n] == our_gid)
+ if ((gid_t)gidset[n] == our_gid)
break;
}
if (n == ngroups)
@@ -229,7 +229,7 @@ static int is_in_group(gid_t gid)
last_in = gid;
for (n = 0; n < ngroups; n++) {
- if (gidset[n] == gid)
+ if ((gid_t)gidset[n] == gid)
return last_out = 1;
}
return last_out = 0;
diff --git a/usage.c b/usage.c
index cbca83e3..df033c92 100644
--- a/usage.c
+++ b/usage.c
@@ -195,6 +195,8 @@ void print_rsync_version(enum logcode f)
print_info_flags(f);
+ init_checksum_choices();
+
rprintf(f, "Checksum list:\n");
get_default_nno_list(&valid_checksums, tmpbuf, sizeof tmpbuf, '(');
rprintf(f, " %s\n", tmpbuf);
diff --git a/version.h b/version.h
index f97bb16d..82aa78f2 100644
--- a/version.h
+++ b/version.h
@@ -1 +1,2 @@
-#define RSYNC_VERSION "3.2.4"
+#define RSYNC_VERSION "3.2.5"
+#define MAINTAINER_TZ_OFFSET -7.0
diff --git a/zlib/inflate.c b/zlib/inflate.c
index e43abd9e..e9840b67 100644
--- a/zlib/inflate.c
+++ b/zlib/inflate.c
@@ -740,8 +740,9 @@ int flush;
if (copy > have) copy = have;
if (copy) {
if (state->head != Z_NULL &&
- state->head->extra != Z_NULL) {
- len = state->head->extra_len - state->length;
+ state->head->extra != Z_NULL &&
+ (len = state->head->extra_len - state->length) <
+ state->head->extra_max) {
zmemcpy(state->head->extra + len, next,
len + copy > state->head->extra_max ?
state->head->extra_max - len : copy);
diff -upN a/config.h.in b/config.h.in
--- a/config.h.in
+++ b/config.h.in
@@ -73,6 +73,9 @@
/* Define to 1 if readdir() is broken */
#undef HAVE_BROKEN_READDIR
+/* Define to 1 if you have the header file. */
+#undef HAVE_BSD_STRING_H
+
/* Define to 1 if vsprintf has a C99-compatible return value */
#undef HAVE_C99_VSNPRINTF
diff -upN a/configure.sh b/configure.sh
--- a/configure.sh
+++ b/configure.sh
@@ -4239,7 +4239,8 @@ for ac_header in sys/fcntl.h sys/select.
netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h mcheck.h \
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h dl.h \
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netgroup.h \
- zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h
+ zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h \
+ bsd/string.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -4326,7 +4327,7 @@ ac_config_headers="$ac_config_headers co
-PACKAGE_VERSION=`sed 's/.*"\(.*\)".*/\1/' <$srcdir/version.h`
+PACKAGE_VERSION=`sed -n 's/.*RSYNC_VERSION.*"\(.*\)".*/\1/p' <$srcdir/version.h`
{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuring rsync $PACKAGE_VERSION" >&5
$as_echo "$as_me: Configuring rsync $PACKAGE_VERSION" >&6;}
@@ -7995,7 +7996,8 @@ _ACEOF
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5
+if test "$cross_compiling" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5
$as_echo_n "checking type of array argument to getgroups... " >&6; }
if ${ac_cv_type_getgroups+:} false; then :
$as_echo_n "(cached) " >&6
@@ -8062,6 +8064,11 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+else
+
+$as_echo "#define GETGROUPS_T gid_t" >>confdefs.h
+
+fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "
#ifdef HAVE_SYS_TYPES_H
#include
@@ -10089,7 +10096,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_
int
main ()
{
-signed char *s = ""
+signed char *s = (signed char *)""
;
return 0;
}
diff -upN a/rrsync.1 b/rrsync.1
--- a/rrsync.1
+++ b/rrsync.1
@@ -1,4 +1,4 @@
-.TH "rrsync" "1" "11 Apr 2022" "rrsync from rsync 3.2.4pre4" "User Commands"
+.TH "rrsync" "1" "13 Aug 2022" "rrsync from rsync 3.2.5pre2" "User Commands"
.\" prefix=/usr
.P
.SH "NAME"
@@ -14,14 +14,18 @@ rrsync [-ro|-rw] [-munge] [-no-del] [-no
The single non-option argument specifies the restricted \fIDIR\fP to use. It can be
relative to the user's home directory or an absolute path.
.P
-The online version of this man page (that includes cross-linking of topics)
+The online version of this manpage (that includes cross-linking of topics)
is available at https://download.samba.org/pub/rsync/rrsync.1.
.P
.SH "DESCRIPTION"
.P
A user's ssh login can be restricted to only allow the running of an rsync
-transfer in one of two easy ways: forcing the running of the rrsync script
-or forcing the running of an rsync daemon-over-ssh command.
+transfer in one of two easy ways:
+.P
+.IP o
+forcing the running of the rrsync script
+.IP o
+forcing the running of an rsync daemon-over-ssh command.
.P
To use the rrsync script, edit the user's \fB~/.ssh/authorized_keys\fP file and add
a prefix like one of the following (followed by a space) in front of each
@@ -54,13 +58,14 @@ command="rsync --server --daemon --confi
Then, ensure that the rsyncd.conf file is created with one or more module names
with the appropriate path and option restrictions. If rsync's
\fB\-\-config\fP option is omitted, it defaults to \fB~/rsyncd.conf\fP.
-See the \fBrsyncd.conf\fP man page for details of how to configure an rsync daemon.
+See the \fBrsyncd.conf\fP(5) manpage for details of how to
+configure an rsync daemon.
.P
When using rrsync, there can be just one restricted dir per authorized key. A
daemon setup, on the other hand, allows multiple module names inside the config
file, each one with its own path setting.
.P
-The remainder of this man page is dedicated to using the rrsync script.
+The remainder of this manpage is dedicated to using the rrsync script.
.P
.SH "OPTIONS"
.P
@@ -117,11 +122,11 @@ command="rrsync -ro results" ssh-rsa AAA
.P
.SH "SEE ALSO"
.P
-\fBrsync\fP(1)
+\fBrsync\fP(1), \fBrsyncd.conf\fP(5)
.P
.SH "VERSION"
.P
-This man page is current for version 3.2.4pre4 of rsync.
+This manpage is current for version 3.2.5pre2 of rsync.
.P
.SH "CREDITS"
.P
diff -upN a/rrsync.1.html b/rrsync.1.html
--- a/rrsync.1.html
+++ b/rrsync.1.html
@@ -38,12 +38,15 @@ dd p:first-of-type {
The single non-option argument specifies the restricted DIR to use. It can be
relative to the user's home directory or an absolute path.
-The online version of this man page (that includes cross-linking of topics)
+
The online version of this manpage (that includes cross-linking of topics)
is available at https://download.samba.org/pub/rsync/rrsync.1.
DESCRIPTION
A user's ssh login can be restricted to only allow the running of an rsync
-transfer in one of two easy ways: forcing the running of the rrsync script
-or forcing the running of an rsync daemon-over-ssh command.
+transfer in one of two easy ways:
+
+- forcing the running of the rrsync script
+- forcing the running of an rsync daemon-over-ssh command.
+
To use the rrsync script, edit the user's ~/.ssh/authorized_keys
file and add
a prefix like one of the following (followed by a space) in front of each
ssh-key line that should be restricted:
@@ -68,11 +71,12 @@ command="rsync --server --daemon --
Then, ensure that the rsyncd.conf file is created with one or more module names
with the appropriate path and option restrictions. If rsync's
--config
option is omitted, it defaults to ~/rsyncd.conf
.
-See the rsyncd.conf
man page for details of how to configure an rsync daemon.
+See the rsyncd.conf(5) manpage for details of how to
+configure an rsync daemon.
When using rrsync, there can be just one restricted dir per authorized key. A
daemon setup, on the other hand, allows multiple module names inside the config
file, each one with its own path setting.
-The remainder of this man page is dedicated to using the rrsync script.
+The remainder of this manpage is dedicated to using the rrsync script.
OPTIONS
@@ -127,9 +131,9 @@ command="rrsync -ro results" s
FILES
~/.ssh/authorized_keys
SEE ALSO
-rsync(1)
+rsync(1), rsyncd.conf(5)
VERSION
-This man page is current for version 3.2.4pre4 of rsync.
+This manpage is current for version 3.2.5pre2 of rsync.
CREDITS
rsync is distributed under the GNU General Public License. See the file
COPYING for details.
@@ -138,5 +142,5 @@ project is AUTHOR
The original rrsync perl script was written by Joe Smith. Many people have
later contributed to it. The python version was created by Wayne Davison.
-
+