-+#ifdef SUPPORT_XATTRS
-+ xattrs = "";
-+#endif
- #ifdef SUPPORT_LINKS
- links = "";
- #endif
-@@ -233,9 +237,9 @@ static void print_rsync_version(enum log
- rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n");
- rprintf(f, "<http://rsync.samba.org/>\n");
- rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
-- "%shard links, %sACLs, %ssymlinks, batchfiles,\n",
-+ "%shard links, %sACLs, %sxattrs, %ssymlinks, batchfiles,\n",
- (int) (sizeof (OFF_T) * 8),
-- got_socketpair, hardlinks, acls, links);
-+ got_socketpair, hardlinks, acls, xattrs, links);
-
- /* Note that this field may not have type ino_t. It depends
- * on the complicated interaction between largefile feature
-@@ -284,7 +288,7 @@ void usage(enum logcode F)
- rprintf(F," -v, --verbose increase verbosity\n");
- rprintf(F," -q, --quiet suppress non-error messages\n");
- rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n");
-- rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H, -A)\n");
-+ rprintf(F," -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)\n");
- rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n");
- rprintf(F," -r, --recursive recurse into directories\n");
- rprintf(F," -R, --relative use relative path names\n");
-@@ -308,6 +312,9 @@ void usage(enum logcode F)
- #ifdef SUPPORT_ACLS
- rprintf(F," -A, --acls preserve ACLs (implies --perms)\n");
- #endif
-+#ifdef SUPPORT_XATTRS
-+ rprintf(F," -X, --xattrs preserve extended attributes (implies --perms)\n");
-+#endif
- rprintf(F," --chmod=CHMOD change destination permissions\n");
- rprintf(F," -o, --owner preserve owner (super-user only)\n");
- rprintf(F," -g, --group preserve group\n");
-@@ -428,6 +435,9 @@ static struct poptOption long_options[]
- {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
- {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
- {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
-+ {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 },
-+ {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
-+ {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
- {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
- {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
- {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
-@@ -1105,6 +1115,17 @@ int parse_arguments(int *argc, const cha
- return 0;
- #endif
-
-+ case 'X':
-+#ifdef SUPPORT_XATTRS
-+ preserve_xattrs = 1;
-+ preserve_perms = 1;
-+ break;
-+#else
-+ snprintf(err_buf,sizeof(err_buf),
-+ "extended attributes are not supported on this %s\n",
-+ am_server ? "server" : "client");
-+ return 0;
-+#endif /* SUPPORT_XATTRS */
-
- default:
- /* A large opt value means that set_refuse_options()
-@@ -1555,6 +1576,10 @@ void server_options(char **args,int *arg
- if (preserve_acls)
- argstr[x++] = 'A';
- #endif
-+#ifdef SUPPORT_XATTRS
-+ if (preserve_xattrs)
-+ argstr[x++] = 'X';
-+#endif
- if (preserve_uid)
- argstr[x++] = 'o';
- if (preserve_gid)
---- old/rsync.c
-+++ new/rsync.c
-@@ -34,6 +34,7 @@ extern int verbose;
- extern int dry_run;
- extern int logfile_format_has_i;
- extern int preserve_acls;
-+extern int preserve_xattrs;
- extern int preserve_perms;
- extern int preserve_executability;
- extern int preserve_times;
-@@ -223,6 +224,10 @@ int set_file_attrs(char *fname, struct f
- if (preserve_acls && set_acl(fname, file, sxp) == 0)
- updated = 1;
- #endif
-+#ifdef SUPPORT_XATTRS
-+ if (preserve_xattrs && set_xattr(fname, file, sxp) == 0)
-+ updated = 1;
-+#endif
-
- #ifdef HAVE_CHMOD
- if ((sxp->st.st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
---- old/rsync.h
-+++ new/rsync.h
-@@ -495,6 +495,10 @@ struct idev {
- #define ACLS_NEED_MASK 1
- #endif
-
-+#ifdef HAVE_LINUX_XATTRS
-+#define SUPPORT_XATTRS 1
-+#endif
-+
- #define GID_NONE ((gid_t)-1)
-
- #define HL_CHECK_MASTER 0
-@@ -687,6 +691,9 @@ typedef struct {
- struct rsync_acl *acc_acl; /* access ACL */
- struct rsync_acl *def_acl; /* default ACL */
- #endif
-+#ifdef SUPPORT_XATTRS
-+ item_list *xattr;
-+#endif
- } statx;
-
- #define ACL_READY(sx) ((sx).acc_acl != NULL)
---- old/rsync.yo
-+++ new/rsync.yo
-@@ -300,7 +300,7 @@ to the detailed description below for a
- -v, --verbose increase verbosity
- -q, --quiet suppress non-error messages
- -c, --checksum skip based on checksum, not mod-time & size
-- -a, --archive archive mode; same as -rlptgoD (no -H, -A)
-+ -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)
- --no-OPTION turn off an implied OPTION (e.g. --no-D)
- -r, --recursive recurse into directories
- -R, --relative use relative path names
-@@ -322,6 +322,7 @@ to the detailed description below for a
- -p, --perms preserve permissions
- -E, --executability preserve executability
- -A, --acls preserve ACLs (implies -p) [non-standard]
-+ -X, --xattrs preserve extended attrs (implies -p) [n.s.]
- --chmod=CHMOD change destination permissions
- -o, --owner preserve owner (super-user only)
- -g, --group preserve group
-@@ -811,6 +812,11 @@ version makes it incompatible with sendi
- rsync unless you double the bf(--acls) option (e.g. bf(-AA)). This
- doubling is not needed when pulling files from an older rsync.
-
-+dit(bf(-X, --xattrs)) This option causes rsync to update the remote
-+extended attributes to be the same as the local ones. This will work
-+only if the remote machine's rsync supports this option also. This is
-+a non-standard option.
-+
- dit(bf(--chmod)) This option tells rsync to apply one or more
- comma-separated "chmod" strings to the permission of the files in the
- transfer. The resulting value is treated as though it was the permissions
---- old/xattr.c
-+++ new/xattr.c
-@@ -0,0 +1,358 @@
-+/*
-+ * Extended Attribute support for rsync.
-+ * Written by Jay Fenlason, vaguely based on the ACLs patch.
-+ *
-+ * Copyright (C) 2004 Red Hat, Inc.
-+ * Copyright (C) 2006 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
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
-+ */
-+
-+#include "rsync.h"
-+#include "lib/sysxattr.h"
-+
-+#ifdef SUPPORT_XATTRS
-+
-+extern int dry_run;
-+extern unsigned int file_struct_len;
-+
-+#define RSYNC_XAL_INITIAL 5
-+#define RSYNC_XAL_LIST_INITIAL 100
-+
-+typedef struct {
-+ char *name;
-+ char *datum;
-+ size_t name_len;
-+ size_t datum_len;
-+} rsync_xa;
-+
-+static size_t namebuf_len = 0;
-+static char *namebuf = NULL;
-+
-+static size_t datumbuf_len = 0;
-+static char *datumbuf = NULL;
-+
-+static item_list empty_xattr = EMPTY_ITEM_LIST;
-+static item_list rsync_xal_l = EMPTY_ITEM_LIST;
-+
-+/* ------------------------------------------------------------------------- */
-+
-+static void rsync_xal_free(item_list *xalp)
-+{
-+ size_t i;
-+ rsync_xa *rxas = xalp->items;
-+
-+ for (i = 0; i < xalp->count; i++) {
-+ free(rxas[i].name);
-+ /* free(rxas[i].value); */
-+ }
-+ xalp->count = 0;
-+}
-+
-+void free_xattr(statx *sxp)
-+{
-+ rsync_xal_free(sxp->xattr);
-+ free(sxp->xattr);
-+ sxp->xattr = NULL;
-+}
-+
-+static int rsync_xal_compare_names(const void *x1, const void *x2)
-+{
-+ const rsync_xa *xa1 = x1;
-+ const rsync_xa *xa2 = x2;
-+ return strcmp(xa1->name, xa2->name);
-+}
-+
-+static int rsync_xal_get(const char *fname, item_list *xalp)
-+{
-+ ssize_t name_size;
-+ ssize_t datum_size;
-+ ssize_t left;
-+ char *name;
-+ size_t len;
-+ char *ptr;
-+
-+ if (!namebuf) {
-+ namebuf_len = 100;
-+ namebuf = new_array(char, namebuf_len);
-+ datumbuf_len = 100;
-+ datumbuf = new_array(char, datumbuf_len);
-+ if (!namebuf || !datumbuf)
-+ out_of_memory("rsync_xal_get");
-+ }
-+
-+ name_size = sys_llistxattr(fname, namebuf, namebuf_len);
-+ if (name_size > (ssize_t)namebuf_len) {
-+ name_size = -1;
-+ errno = ERANGE;
-+ }
-+ if (name_size < 0) {
-+ if (errno == ENOTSUP)
-+ return 0;
-+ if (errno == ERANGE) {
-+ name_size = sys_llistxattr(fname, NULL, 0);
-+ if (name_size < 0) {
-+ rsyserr(FERROR, errno, "%s: rsync_xal_get: llistxattr",
-+ fname);
-+ return -1;
-+ }
-+ namebuf = realloc_array(namebuf, char, name_size + 1);
-+ if (!namebuf)
-+ out_of_memory("rsync_xal_get");
-+ namebuf_len = name_size;
-+ name_size = sys_llistxattr(fname, namebuf, namebuf_len);
-+ if (name_size < 0) {
-+ rsyserr(FERROR, errno,
-+ "%s: rsync_xal_get: re-llistxattr failed",
-+ fname);
-+ return -1;
-+ }
-+ } else {
-+ rsyserr(FERROR, errno,
-+ "%s: rsync_xal_get: llistxattr failed:",
-+ fname);
-+ return -1;
-+ }
-+ }
-+ if (name_size == 0)
-+ return 0;
-+ for (left = name_size, name = namebuf; left > 0 ; left -= len, name += len) {
-+ rsync_xa *rxas = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
-+
-+ len = strlen(name) + 1;
-+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
-+ if (datum_size > (ssize_t)datumbuf_len) {
-+ datum_size = -1;
-+ errno = ERANGE;