+ 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/sender.c
++++ new/sender.c
+@@ -22,6 +22,7 @@
+ #include "rsync.h"
+
+ extern int verbose;
++extern int dry_run;
+ extern int do_xfers;
+ extern int am_server;
+ extern int am_daemon;
+@@ -144,8 +145,9 @@ void successful_send(int ndx)
+ rsyserr(FERROR, errno, "sender failed to remove %s", fname);
+ }
+
+-void write_ndx_and_attrs(int f_out, int ndx, int iflags,
+- uchar fnamecmp_type, char *buf, int len)
++static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
++ const char *fname, struct file_struct *file,
++ uchar fnamecmp_type, char *buf, int len)
+ {
+ write_ndx(f_out, ndx);
+ if (protocol_version < 29)
+@@ -155,6 +157,10 @@ void write_ndx_and_attrs(int f_out, int
+ write_byte(f_out, fnamecmp_type);
+ if (iflags & ITEM_XNAME_FOLLOWS)
+ write_vstring(f_out, buf, len);
++#ifdef SUPPORT_XATTRS
++ if (iflags & ITEM_REPORT_XATTR && !dry_run)
++ send_xattr_request(fname, file, f_out);
++#endif
+ }
+
+ void send_files(int f_in, int f_out)
+@@ -183,8 +189,8 @@ void send_files(int f_in, int f_out)
+ send_extra_file_list(f_out, FILECNT_LOOKAHEAD);
+
+ /* This call also sets cur_flist. */
+- ndx = read_ndx_and_attrs(f_in, f_out, &iflags,
+- &fnamecmp_type, xname, &xlen);
++ ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
++ xname, &xlen);
+ if (ndx == NDX_DONE) {
+ if (inc_recurse && first_flist) {
+ flist_free(first_flist);
+@@ -201,6 +207,9 @@ void send_files(int f_in, int f_out)
+ continue;
+ }
+
++ if (inc_recurse)
++ send_extra_file_list(f_out, FILECNT_LOOKAHEAD);
++
+ file = cur_flist->files[ndx - cur_flist->ndx_start];
+ if (F_ROOTDIR(file)) {
+ path = F_ROOTDIR(file);
+@@ -215,8 +224,13 @@ void send_files(int f_in, int f_out)
+ if (verbose > 2)
+ rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname);
+
++ if (iflags & ITEM_REPORT_XATTR)
++ recv_xattr_request(file, f_in);
++
+ if (!(iflags & ITEM_TRANSFER)) {
+ maybe_log_item(file, iflags, itemizing, xname);
++ write_ndx_and_attrs(f_out, ndx, iflags, fname, file,
++ fnamecmp_type, xname, xlen);
+ continue;
+ }
+ if (phase == 2) {
+@@ -251,8 +265,8 @@ void send_files(int f_in, int f_out)
+
+ if (!do_xfers) { /* log the transfer */
+ log_item(FCLIENT, file, &stats, iflags, NULL);
+- write_ndx_and_attrs(f_out, ndx, iflags, fnamecmp_type,
+- xname, xlen);
++ write_ndx_and_attrs(f_out, ndx, iflags, fname, file,
++ fnamecmp_type, xname, xlen);
+ continue;
+ }
+
+@@ -305,8 +319,8 @@ void send_files(int f_in, int f_out)
+ path,slash,fname, (double)st.st_size);
+ }
+
+- write_ndx_and_attrs(f_out, ndx, iflags, fnamecmp_type,
+- xname, xlen);
++ write_ndx_and_attrs(f_out, ndx, iflags, fname, file,
++ fnamecmp_type, xname, xlen);
+ write_sum_head(f_xfer, s);
+
+ if (verbose > 2)
+--- old/testsuite/xattrs.test
++++ new/testsuite/xattrs.test
+@@ -0,0 +1,56 @@
++#! /bin/sh
++
++# This program is distributable under the terms of the GNU GPL (see
++# COPYING).
++
++# Test that rsync handles basic xattr preservation.
++
++. $srcdir/testsuite/rsync.fns
++
++$RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync is configured without xattr support"
++
++case "$RSYNC" in
++*protocol=29*) test_skipped "xattr support requires protocol 30" ;;
++esac
++
++makepath "$fromdir/foo"
++echo something >"$fromdir/file1"
++echo else >"$fromdir/file2"
++echo last >"$fromdir/foo/file3"
++
++makepath "$todir/foo"
++echo wow >"$todir/file1"
++cp -p "$fromdir/foo/file3" "$todir/foo"
++
++files='foo file1 file2 foo/file3'
++
++cd "$fromdir"
++
++setfattr -n user.short -v 'this is short' file1 2>/dev/null || test_skipped "Unable to set an xattr"
++setfattr -n user.long -v 'this is a long attribute that will be truncated in the initial data send' file1
++setfattr -n user.good -v 'this is good' file1
++setfattr -n user.nice -v 'this is nice' file1
++
++setfattr -n user.foo -v foo file2
++setfattr -n user.bar -v bar file2
++
++setfattr -n user.foo -v 'new foo' foo/file3
++setfattr -n user.bar -v 'new bar' foo/file3
++setfattr -n user.long -v 'this is also a long attribute that will be truncated in the initial data send' foo/file3
++setfattr -n user.equal -v 'this long attribute should remain the same and not need to be transferred' foo/file3
++
++setfattr -n user.short -v 'old short' "$todir/file1"
++setfattr -n user.extra -v 'remove me' "$todir/file1"
++
++setfattr -n user.foo -v 'old foo' "$todir/foo/file3"
++setfattr -n user.equal -v 'this long attribute should remain the same and not need to be transferred' "$todir/foo/file3"
++
++$RSYNC -avX . "$todir/"
++
++getfattr -d $files >"$scratchdir/xattrs.txt"
++
++cd "$todir"
++getfattr -d $files | diff $diffopt "$scratchdir/xattrs.txt" -
++
++# The script would have aborted on error, so getting here means we've won.
++exit 0
+--- old/xattrs.c
++++ new/xattrs.c
+@@ -0,0 +1,686 @@
++/*
++ * Extended Attribute support for rsync.
++ * Written by Jay Fenlason, vaguely based on the ACLs patch.
++ *
++ * Copyright (C) 2004 Red Hat, Inc.
++ * Copyright (C) 2006, 2007 Wayne Davison
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 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.
++ */