From 78286a03d196efeed754aa4c1faa571f5dbea342 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 26 Mar 2011 09:59:14 -0700 Subject: [PATCH] Avoid re-setting (and sending) xattrs on a hard-linked file w/the same xattrs. Improved the xattrs testing to include hard-linking. --- .gitignore | 1 + Makefile.in | 5 ++++- NEWS | 4 ++-- generator.c | 6 ++++-- receiver.c | 6 ++++-- rsync.h | 2 +- sender.c | 6 ++++-- testsuite/hardlinks.test | 2 +- testsuite/xattrs.test | 44 ++++++++++++++++++++++++++++++++++------ 9 files changed, 59 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 805af45e..3e3bc5e4 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,5 @@ config.status /support/savetransfer /testsuite/chown-fake.test /testsuite/devices-fake.test +/testsuite/xattrs-hlink.test /patches diff --git a/Makefile.in b/Makefile.in index 055bc75e..dfb4e078 100644 --- a/Makefile.in +++ b/Makefile.in @@ -49,7 +49,7 @@ TLS_OBJ = tls.o syscall.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxa CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \ testrun$(EXEEXT) trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT) -CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test +CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test testsuite/xattrs-hlink.test # Objects for CHECK_PROGS to clean CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o @@ -256,6 +256,9 @@ testsuite/chown-fake.test: testsuite/devices-fake.test: ln -s devices.test $(srcdir)/testsuite/devices-fake.test +testsuite/xattrs-hlink.test: + ln -s xattrs.test $(srcdir)/testsuite/xattrs-hlink.test + # This does *not* depend on building or installing: you can use it to # check a version installed from a binary or some other source tree, # if you want. diff --git a/NEWS b/NEWS index 5fd125af..97b02008 100644 --- a/NEWS +++ b/NEWS @@ -95,8 +95,8 @@ Changes since 3.0.4: - When replacing a non-dir with a symlink/hard-link/device/special-file, the update should now be done in an atomic manner. - - Fixed a free of the wrong pointer in uncache_tmp_xattrs() (which only - sometimes affects an --xattr transfer when --backup is used). + - Avoid re-sending xattr info for hard-linked files w/the same xattrs + (protocol 31). - When backing up a file, try to hard-link the file into place so that the upcoming replacement of the destination file will be atomic. diff --git a/generator.c b/generator.c index d17e3b9e..e3890bb1 100644 --- a/generator.c +++ b/generator.c @@ -549,8 +549,10 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre #ifdef SUPPORT_XATTRS if (preserve_xattrs && do_xfers && iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) { - send_xattr_request(NULL, file, - iflags & ITEM_REPORT_XATTR ? sock_f_out : -1); + int fd = iflags & ITEM_REPORT_XATTR + && (protocol_version < 31 || !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)) + ? sock_f_out : -1; + send_xattr_request(NULL, file, fd); } #endif } else if (ndx >= 0) { diff --git a/receiver.c b/receiver.c index a5192475..7641b9b5 100644 --- a/receiver.c +++ b/receiver.c @@ -548,14 +548,16 @@ int recv_files(int f_in, int f_out, char *local_name) rprintf(FINFO, "recv_files(%s)\n", fname); #ifdef SUPPORT_XATTRS - if (iflags & ITEM_REPORT_XATTR && do_xfers) + if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers + && (protocol_version < 31 || !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))) recv_xattr_request(file, f_in); #endif if (!(iflags & ITEM_TRANSFER)) { maybe_log_item(file, iflags, itemizing, xname); #ifdef SUPPORT_XATTRS - if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers) + if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers + && !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)) set_file_attrs(fname, file, NULL, fname, 0); #endif if (iflags & ITEM_IS_NEW) { diff --git a/rsync.h b/rsync.h index ed600053..79402cd7 100644 --- a/rsync.h +++ b/rsync.h @@ -103,7 +103,7 @@ /* This is used when working on a new protocol version in CVS, and should * be a new non-zero value for each CVS change that affects the protocol. * It must ALWAYS be 0 when the protocol goes final (and NEVER before)! */ -#define SUBPROTOCOL_VERSION 12 +#define SUBPROTOCOL_VERSION 13 /* We refuse to interoperate with versions that are not in this range. * Note that we assume we'll work with later versions: the onus is on diff --git a/sender.c b/sender.c index 600ad847..7b6d3133 100644 --- a/sender.c +++ b/sender.c @@ -155,7 +155,8 @@ static void write_ndx_and_attrs(int f_out, int ndx, int iflags, if (iflags & ITEM_XNAME_FOLLOWS) write_vstring(f_out, buf, len); #ifdef SUPPORT_XATTRS - if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers) + if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers + && (protocol_version < 31 || !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))) send_xattr_request(fname, file, f_out); #endif } @@ -236,7 +237,8 @@ void send_files(int f_in, int f_out) rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname); #ifdef SUPPORT_XATTRS - if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers) + if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers + && (protocol_version < 31 || !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))) recv_xattr_request(file, f_in); #endif diff --git a/testsuite/hardlinks.test b/testsuite/hardlinks.test index caa08231..55131fa7 100644 --- a/testsuite/hardlinks.test +++ b/testsuite/hardlinks.test @@ -28,7 +28,7 @@ name2="$fromdir/name2" name3="$fromdir/name3" name4="$fromdir/name4" echo "This is the file" > "$name1" -ln "$name1" "$name2" || fail "Can't create hardlink" +ln "$name1" "$name2" || test_skipped "Can't create hardlink" ln "$name2" "$name3" || fail "Can't create hardlink" cp "$name2" "$name4" || fail "Can't copy file" cat $srcdir/*.c >"$fromdir/text" diff --git a/testsuite/xattrs.test b/testsuite/xattrs.test index 7200f250..9a145840 100644 --- a/testsuite/xattrs.test +++ b/testsuite/xattrs.test @@ -6,6 +6,7 @@ # Test that rsync handles basic xattr preservation. . $suitedir/rsync.fns +lnkdir="$tmpdir/lnk" $RSYNC --version | grep ", xattrs" >/dev/null || test_skipped "Rsync is configured without xattr support" @@ -38,7 +39,7 @@ case "`xattr 2>&1`" in ;; esac -makepath "$fromdir/foo/bar" +makepath "$lnkdir" "$fromdir/foo/bar" echo now >"$fromdir/file0" echo something >"$fromdir/file1" echo else >"$fromdir/file2" @@ -73,32 +74,60 @@ xset user.dir1 'need to test directory xattrs too' foo xset user.dir2 'another xattr' foo xset user.dir3 'this is one last one for the moment' foo +xset user.dir4 'another dir test' foo/bar +xset user.dir5 'one last one' foo/bar + xset user.foo 'new foo' foo/file3 foo/bar/file5 xset user.bar 'new bar' foo/file3 foo/bar/file5 xset user.long 'this is also a long attribute that will be truncated in the initial data send' foo/file3 foo/bar/file5 xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5 +xset user.dir0 'old extra value' "$chkdir/foo" +xset user.dir1 'old dir value' "$chkdir/foo" + xset user.short 'old short' "$chkdir/file1" xset user.extra 'remove me' "$chkdir/file1" xset user.foo 'old foo' "$chkdir/foo/file3" xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3" +case $0 in +*hlink*) + ln foo/bar/file5 foo/bar/file6 || test_skipped "Can't create hardlink" + files="$files foo/bar/file6" + dashH='-H' + altDest='--link-dest' + ;; +*) + dashH='' + altDest='--copy-dest' + ;; +esac + xls $dirs $files >"$scratchdir/xattrs.txt" # OK, let's try a simple xattr copy. -checkit "$RSYNC -avX --super . '$chkdir/'" "$fromdir" "$chkdir" +checkit "$RSYNC -avX $dashH --super . '$chkdir/'" "$fromdir" "$chkdir" cd "$chkdir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - cd "$fromdir" -checkit "$RSYNC -aiX --super --copy-dest=../chk . ../to" "$fromdir" "$todir" +if [ "$dashH" ]; then + for fn in $files; do + name=`basename $fn` + ln $fn ../lnk/$name + done +fi + +checkit "$RSYNC -aiX $dashH --super $altDest=../chk . ../to" "$fromdir" "$todir" cd "$todir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - +[ "$dashH" ] && rm -rf "$lnkdir" + cd "$fromdir" rm -rf "$todir" @@ -106,7 +135,7 @@ xset user.nice 'this is nice, but different' file1 xls $dirs $files >"$scratchdir/xattrs.txt" -checkit "$RSYNC -aiX --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir" +checkit "$RSYNC -aiX $dashH --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir" cd "$todir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - @@ -136,7 +165,7 @@ cd "$fromdir" rm -rf "$todir" # When run by a non-root tester, this checks if no-user-perm files/dirs can be copied. -checkit "$RSYNC -aiX --fake-super --chmod=a= . ../to" "$chkdir" "$todir" # 2>"$scratchdir/errors.txt" +checkit "$RSYNC -aiX $dashH --fake-super --chmod=a= . ../to" "$chkdir" "$todir" # 2>"$scratchdir/errors.txt" cd "$todir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - @@ -148,10 +177,13 @@ $RSYNC -aX file1 file2 $RSYNC -aX file1 file2 ../chk/ $RSYNC -aX --del ../chk/ . $RSYNC -aX file1 ../lnk/ +[ "$dashH" ] && ln "$chkdir/file1" ../lnk/extra-link xls file1 file2 >"$scratchdir/xattrs.txt" -checkit "$RSYNC -aiiX --copy-dest=../lnk . ../to" "$chkdir" "$todir" +checkit "$RSYNC -aiiX $dashH $altDest=../lnk . ../to" "$chkdir" "$todir" + +[ "$dashH" ] && rm ../lnk/extra-link cd "$todir" xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" - -- 2.34.1