From 2d5707c7479eacb3b1ad98e01b53f56a88f8fb78 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 18:14:31 +0200 Subject: Adding upstream version 3.2.7. Signed-off-by: Daniel Baumann --- testsuite/00-hello.test | 61 +++++ testsuite/README.testsuite | 28 ++ testsuite/acls-default.test | 66 +++++ testsuite/acls.test | 62 +++++ testsuite/alt-dest.test | 68 +++++ testsuite/atimes.test | 19 ++ testsuite/backup.test | 63 +++++ testsuite/batch-mode.test | 51 ++++ testsuite/chgrp.test | 29 +++ testsuite/chmod-option.test | 71 +++++ testsuite/chmod-temp-dir.test | 41 +++ testsuite/chmod.test | 30 +++ testsuite/chown.test | 86 +++++++ testsuite/crtimes.test | 26 ++ testsuite/daemon-gzip-download.test | 37 +++ testsuite/daemon-gzip-upload.test | 31 +++ testsuite/daemon.test | 90 +++++++ testsuite/delay-updates.test | 21 ++ testsuite/delete.test | 57 +++++ testsuite/devices.test | 171 +++++++++++++ testsuite/dir-sgid.test | 48 ++++ testsuite/duplicates.test | 44 ++++ testsuite/exclude-lsh.test | 1 + testsuite/exclude.test | 252 ++++++++++++++++++ testsuite/executability.test | 47 ++++ testsuite/files-from.test | 45 ++++ testsuite/fuzzy.test | 24 ++ testsuite/hands.test | 38 +++ testsuite/hardlinks.test | 81 ++++++ testsuite/itemize.test | 246 ++++++++++++++++++ testsuite/longdir.test | 26 ++ testsuite/merge.test | 57 +++++ testsuite/missing.test | 34 +++ testsuite/mkpath.test | 47 ++++ testsuite/protected-regular.test | 31 +++ testsuite/relative.test | 60 +++++ testsuite/rsync.fns | 498 ++++++++++++++++++++++++++++++++++++ testsuite/ssh-basic.test | 34 +++ testsuite/symlink-ignore.test | 34 +++ testsuite/trimslash.test | 26 ++ testsuite/unsafe-byname.test | 58 +++++ testsuite/unsafe-links.test | 65 +++++ testsuite/wildmatch.test | 23 ++ testsuite/xattrs.test | 239 +++++++++++++++++ 44 files changed, 3166 insertions(+) create mode 100644 testsuite/00-hello.test create mode 100644 testsuite/README.testsuite create mode 100644 testsuite/acls-default.test create mode 100644 testsuite/acls.test create mode 100644 testsuite/alt-dest.test create mode 100644 testsuite/atimes.test create mode 100644 testsuite/backup.test create mode 100644 testsuite/batch-mode.test create mode 100644 testsuite/chgrp.test create mode 100644 testsuite/chmod-option.test create mode 100644 testsuite/chmod-temp-dir.test create mode 100644 testsuite/chmod.test create mode 100644 testsuite/chown.test create mode 100644 testsuite/crtimes.test create mode 100644 testsuite/daemon-gzip-download.test create mode 100644 testsuite/daemon-gzip-upload.test create mode 100644 testsuite/daemon.test create mode 100644 testsuite/delay-updates.test create mode 100644 testsuite/delete.test create mode 100644 testsuite/devices.test create mode 100644 testsuite/dir-sgid.test create mode 100644 testsuite/duplicates.test create mode 120000 testsuite/exclude-lsh.test create mode 100644 testsuite/exclude.test create mode 100644 testsuite/executability.test create mode 100644 testsuite/files-from.test create mode 100644 testsuite/fuzzy.test create mode 100644 testsuite/hands.test create mode 100644 testsuite/hardlinks.test create mode 100644 testsuite/itemize.test create mode 100644 testsuite/longdir.test create mode 100644 testsuite/merge.test create mode 100644 testsuite/missing.test create mode 100644 testsuite/mkpath.test create mode 100644 testsuite/protected-regular.test create mode 100644 testsuite/relative.test create mode 100644 testsuite/rsync.fns create mode 100644 testsuite/ssh-basic.test create mode 100644 testsuite/symlink-ignore.test create mode 100644 testsuite/trimslash.test create mode 100644 testsuite/unsafe-byname.test create mode 100644 testsuite/unsafe-links.test create mode 100644 testsuite/wildmatch.test create mode 100644 testsuite/xattrs.test (limited to 'testsuite') diff --git a/testsuite/00-hello.test b/testsuite/00-hello.test new file mode 100644 index 0000000..ebd0683 --- /dev/null +++ b/testsuite/00-hello.test @@ -0,0 +1,61 @@ +#!/bin/sh + +# Test some foundational things. + +. "$suitedir/rsync.fns" + +RSYNC_RSH="$scratchdir/src/support/lsh.sh" +export RSYNC_RSH + +echo $0 running + +$RSYNC --version || test_fail '--version output failed' + +$RSYNC --info=help || test_fail '--info=help output failed' + +$RSYNC --debug=help || test_fail '--debug=help output failed' + +weird_name="A weird)name" + +mkdir "$fromdir" +mkdir "$fromdir/$weird_name" + +append_line() { + echo "$1" + echo "$1" >>"$fromdir/$weird_name/file" +} + +append_line test1 +checkit "$RSYNC -ai '$fromdir/' '$todir/'" "$fromdir" "$todir" + +copy_weird() { + checkit "$RSYNC $1 --rsync-path='$RSYNC' '$2$fromdir/$weird_name/' '$3$todir/$weird_name'" "$fromdir" "$todir" +} + +append_line test2 +copy_weird '-ai' 'lh:' '' + +append_line test3 +copy_weird '-ai' '' 'lh:' + +append_line test4 +copy_weird '-ais' 'lh:' '' + +append_line test5 +copy_weird '-ais' '' 'lh:' + +echo test6 + +touch "$fromdir/one" "$fromdir/two" +(cd "$fromdir" && $RSYNC -ai --old-args --rsync-path="$RSYNC" lh:'one two' "$todir/") +if [ ! -f "$todir/one" ] || [ ! -f "$todir/two" ]; then + test_fail "old-args copy of 'one two' failed" +fi + +echo test7 + +rm "$todir/one" "$todir/two" +(cd "$fromdir" && RSYNC_OLD_ARGS=1 $RSYNC -ai --rsync-path="$RSYNC" lh:'one two' "$todir/") + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/README.testsuite b/testsuite/README.testsuite new file mode 100644 index 0000000..782cb1c --- /dev/null +++ b/testsuite/README.testsuite @@ -0,0 +1,28 @@ +automatic testsuite for rsync -*- text -*- + +We're trying to develop some more substantial tests to prevent rsync +regressions. Ideally, all code changes or bug reports would come with +an appropriate test suite. + +You can run these tests by typing "make check" in the build directory. +The tests will run using the rsync binary in the build directory, so +you do not need to do "make install" first. Indeed, you probably +should not install rsync before running the tests. + +If you instead type "make installcheck" then the suite will test the +rsync binary from its installed location (e.g. /usr/local/bin/rsync). +You can use this to test a distribution build, or perhaps to run a new +test suite against an old version of rsync. Note that in accordance +with the GNU Standards, installcheck does not look for rsync on the +path. + +If the tests pass, you should see a report to that effect. Some tests +require being root or some other precondition, and so will normally not +be checked -- look at the test scripts for more information. + +If the tests fail, you will see rather more output. The scratch +directory will remain in the build directory. It would be useful if +you could include the log messages when reporting a failure. + +These tests also run automatically on the build farm, and you can see +the results on http://build.samba.org/. diff --git a/testsuite/acls-default.test b/testsuite/acls-default.test new file mode 100644 index 0000000..d8fba7f --- /dev/null +++ b/testsuite/acls-default.test @@ -0,0 +1,66 @@ +#!/bin/sh + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that rsync obeys default ACLs. -- Matt McCutchen + +. $suitedir/rsync.fns + +$RSYNC -VV | grep '"ACLs": true' >/dev/null || test_skipped "Rsync is configured without ACL support" + +case "$setfacl_nodef" in +true) test_skipped "I don't know how to use your setfacl command" ;; +*-k*) opts='-dm u::7,g::5,o:5' ;; +*) opts='-m d:u::7,d:g::5,d:o:5' ;; +esac +setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled" + +# Call as: testit +testit() { + todir="$scratchdir/$1" + mkdir "$todir" + $setfacl_nodef "$todir" + if [ -n "$2" ]; then + case "$setfacl_nodef" in + *-k*) opts="-dm $2" ;; + *) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`" + esac + setfacl $opts "$todir" + fi + # Make sure we obey ACLs when creating a directory to hold multiple transferred files, + # even though the directory itself is outside the transfer + $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/" + check_perms "$todir/to" $4 "Target $1" + check_perms "$todir/to/dir" $4 "Target $1" + check_perms "$todir/to/file" $3 "Target $1" + check_perms "$todir/to/program" $4 "Target $1" + # Make sure get_local_name doesn't mess us up when transferring only one file + $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile" + check_perms "$todir/to/anotherfile" $3 "Target $1" + # Make sure we obey default ACLs when not transferring a regular file + $RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/" + check_perms "$todir/to/anotherdir" $4 "Target $1" +} + +mkdir "$scratchdir/dir" +echo "File!" >"$scratchdir/file" +echo "#!/bin/sh" >"$scratchdir/program" +chmod 777 "$scratchdir/dir" +chmod 666 "$scratchdir/file" +chmod 777 "$scratchdir/program" + +# Test some target directories +umask 0077 +testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx +testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x +testit da750 u::7,g::5,o:0 rw-r----- rwxr-x--- +testit da750mask u::7,u:0:7,g::7,m:5,o:0 rw-r----- rwxr-x--- +testit noda1 '' rw------- rwx------ +umask 0000 +testit noda2 '' rw-rw-rw- rwxrwxrwx +umask 0022 +testit noda3 '' rw-r--r-- rwxr-xr-x + +# Hooray +exit 0 diff --git a/testsuite/acls.test b/testsuite/acls.test new file mode 100644 index 0000000..693da66 --- /dev/null +++ b/testsuite/acls.test @@ -0,0 +1,62 @@ +#!/bin/sh + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that rsync handles basic ACL preservation. + +. $suitedir/rsync.fns + +$RSYNC -VV | grep '"ACLs": true' >/dev/null || test_skipped "Rsync is configured without ACL support" + +makepath "$fromdir/foo" +echo something >"$fromdir/file1" +echo else >"$fromdir/file2" + +files='foo file1 file2' + +case "$setfacl_nodef" in +true) + if ! chmod --help 2>&1 | grep -F +a >/dev/null; then + test_skipped "I don't know how to use setfacl or chmod for ACLs" + fi + chmod +a "root allow read,write,execute" "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled" + chmod +a "root allow read,execute" "$fromdir/file1" + chmod +a "admin allow read" "$fromdir/file1" + chmod +a "daemon allow read,write" "$fromdir/file1" + chmod +a "root allow read,execute" "$fromdir/file2" + + see_acls() { + ls -le "${@}" + } + ;; +*) + setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled" + setfacl -m g:1:5 "$fromdir/foo" + setfacl -m g:2:1 "$fromdir/foo" + setfacl -m g:0:7 "$fromdir/foo" + setfacl -m u:2:1 "$fromdir/foo" + setfacl -m u:1:5 "$fromdir/foo" + + setfacl -m u:0:5 "$fromdir/file1" + setfacl -m g:0:4 "$fromdir/file1" + setfacl -m u:1:6 "$fromdir/file1" + + setfacl -m u:0:5 "$fromdir/file2" + + see_acls() { + getfacl "${@}" + } + ;; +esac + +cd "$fromdir" +$RSYNC -avvA $files "$todir/" + +see_acls $files >"$scratchdir/acls.txt" + +cd "$todir" +see_acls $files | diff $diffopt "$scratchdir/acls.txt" - + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/alt-dest.test b/testsuite/alt-dest.test new file mode 100644 index 0000000..d2fb5a1 --- /dev/null +++ b/testsuite/alt-dest.test @@ -0,0 +1,68 @@ +#!/bin/sh + +# Copyright (C) 2004-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync handling of --compare-dest and similar options. + +. "$suitedir/rsync.fns" + +alt1dir="$tmpdir/alt1" +alt2dir="$tmpdir/alt2" +alt3dir="$tmpdir/alt3" + +SSH="$scratchdir/src/support/lsh.sh" + +# Build some files/dirs/links to copy + +hands_setup + +# Setup the alt and chk dirs +$RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$alt1dir/" +$RSYNC -av --include=etc-ltr-list --include='*/' --exclude='*' "$fromdir/" "$alt2dir/" + +# Create a side dir where there is a candidate destfile of the same name as a sourcefile +echo "This is a test file" >"$fromdir/likely" + +mkdir "$alt3dir" +echo "This is a test file" >"$alt3dir/likely" + +sleep 1 +touch "$fromdir/dir/text" "$fromdir/likely" + +$RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/" + +# Let's do it! +checkit "$RSYNC -avv --no-whole-file \ + --compare-dest='$alt1dir' --compare-dest='$alt2dir' \ + '$fromdir/' '$todir/'" "$chkdir" "$todir" + +rm -rf "$todir" +checkit "$RSYNC -avv --no-whole-file \ + --copy-dest='$alt1dir' --copy-dest='$alt2dir' \ + '$fromdir/' '$todir/'" "$fromdir" "$todir" + +# Test that copy_file() works correctly with tmpfiles +for maybe_inplace in '' --inplace; do + rm -rf "$todir" + checkit "$RSYNC -av $maybe_inplace --copy-dest='$alt3dir' \ + '$fromdir/' '$todir/'" "$fromdir" "$todir" + + for srchost in '' 'localhost:'; do + if [ -z "$srchost" ]; then + desthost='localhost:' + else + desthost='' + fi + + rm -rf "$todir" + checkit "$RSYNC -ave '$SSH' --rsync-path='$RSYNC' $maybe_inplace \ + --copy-dest='$alt3dir' '$srchost$fromdir/' '$desthost$todir/'" \ + "$fromdir" "$todir" + done +done + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/atimes.test b/testsuite/atimes.test new file mode 100644 index 0000000..4d46eb0 --- /dev/null +++ b/testsuite/atimes.test @@ -0,0 +1,19 @@ +#!/bin/sh + +# Test rsync copying atimes + +. "$suitedir/rsync.fns" + +$RSYNC -VV | grep '"atimes": true' >/dev/null || test_skipped "Rsync is configured without atimes support" + +mkdir "$fromdir" + +touch "$fromdir/foo" +touch -a -t 200102031717.42 "$fromdir/foo" + +TLS_ARGS=--atimes + +checkit "$RSYNC -rtUgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/backup.test b/testsuite/backup.test new file mode 100644 index 0000000..4de3867 --- /dev/null +++ b/testsuite/backup.test @@ -0,0 +1,63 @@ +#!/bin/sh + +# Copyright (C) 2004-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that the --backup option works right. + +. "$suitedir/rsync.fns" + +bakdir="$tmpdir/bak" + +makepath "$fromdir/deep" "$bakdir/dname" +name1="$fromdir/deep/name1" +name2="$fromdir/deep/name2" + +cat "$srcdir"/[gr]*.[ch] > "$name1" +cat "$srcdir"/[et]*.[ch] > "$name2" + +checkit "$RSYNC -ai --info=backup '$fromdir/' '$todir/'" "$fromdir" "$todir" + +checkit "$RSYNC -ai --info=backup '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir" +cat "$srcdir"/[fgpr]*.[ch] > "$name1" +cat "$srcdir"/[etw]*.[ch] > "$name2" + +checktee "$RSYNC -ai --info=backup --no-whole-file --backup '$fromdir/' '$todir/'" +for fn in deep/name1 deep/name2; do + grep "backed up $fn to $fn~" "$outfile" >/dev/null || test_fail "no backup message output for $fn" + diff $diffopt "$fromdir/$fn" "$todir/$fn" || test_fail "copy of $fn failed" + diff $diffopt "$chkdir/$fn" "$todir/$fn~" || test_fail "backup of $fn to $fn~ failed" + mv "$todir/$fn~" "$todir/$fn" +done + +echo deleted-file >"$todir/dname" +cp_touch "$todir/dname" "$chkdir" + +checkit "$RSYNC -ai --info=backup --no-whole-file --delete-delay \ + --backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \ + | tee "$outfile" + +for fn in deep/name1 deep/name2; do + grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn" +done +diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus" +rm "$bakdir/dname" + +checkit "$RSYNC -ai --info=backup --del '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir" +cat "$srcdir"/[efgr]*.[ch] > "$name1" +cat "$srcdir"/[ew]*.[ch] > "$name2" + +checkit "$RSYNC -ai --info=backup --inplace --no-whole-file --backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \ + | tee "$outfile" + +for fn in deep/name1 deep/name2; do + grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn" +done +diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus" + +checkit "$RSYNC -ai --info=backup --inplace --no-whole-file '$fromdir/' '$bakdir/'" "$fromdir" "$bakdir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/batch-mode.test b/testsuite/batch-mode.test new file mode 100644 index 0000000..cf4e94d --- /dev/null +++ b/testsuite/batch-mode.test @@ -0,0 +1,51 @@ +#!/bin/sh + +# Copyright (C) 2004 by Chris Shoemaker + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync's --write-batch and --read-batch options + +. "$suitedir/rsync.fns" + +hands_setup + +cd "$tmpdir" + +# Build chkdir for the daemon tests using a normal rsync and an --exclude. +$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/" + +$RSYNC -av --only-write-batch=BATCH --exclude=foobar.baz "$fromdir/" "$todir/missing/" +test -d "$todir/missing" && test_fail "--only-write-batch should not have created destination dir" + +runtest "--read-batch (only)" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"' + +rm -rf "$todir" BATCH* +runtest "local --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"' + +rm -rf "$todir" +runtest "--read-batch" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$fromdir" "$todir"' + +build_rsyncd_conf + +RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" +export RSYNC_CONNECT_PROG + +rm -rf "$todir" +runtest "daemon sender --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH rsync://localhost/test-from/ \"$todir\"" "$chkdir" "$todir"' + +rm -rf "$todir" +runtest "--read-batch from daemon" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"' + +rm -rf "$todir" +runtest "BATCH.sh use of --read-batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"' + +runtest "do-nothing re-run of batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"' + +rm -rf "$todir" +mkdir "$todir" || test_fail "failed to restore empty destination directory" +runtest "daemon recv --write-batch" 'checkit "\"$ignore23\" $RSYNC -av --write-batch=BATCH \"$fromdir/\" rsync://localhost/test-to" "$chkdir" "$todir"' + +# The script would have aborted on error, so getting here means we pass. +exit 0 diff --git a/testsuite/chgrp.test b/testsuite/chgrp.test new file mode 100644 index 0000000..467d402 --- /dev/null +++ b/testsuite/chgrp.test @@ -0,0 +1,29 @@ +#!/bin/sh + +# Copyright (C) 2002 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that rsync with -gr will preserve groups when the user running +# the test is a member of them. Hopefully they're in at least one +# test. + +. "$suitedir/rsync.fns" + +# Build some hardlinks + +mygrps="`rsync_getgroups`" || test_fail "Can't get groups" +mkdir "$fromdir" + +for g in $mygrps; do + name="$fromdir/foo-$g" + date > "$name" + chgrp "$g" "$name" || test_fail "Can't chgrp" +done +sleep 2 + +checkit "$RSYNC -rtgpvvv '$fromdir/' '$todir/'" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/chmod-option.test b/testsuite/chmod-option.test new file mode 100644 index 0000000..ddf764c --- /dev/null +++ b/testsuite/chmod-option.test @@ -0,0 +1,71 @@ +#!/bin/sh + +# Copyright (C) 2002 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that the --chmod option functions correctly. + +. $suitedir/rsync.fns + +# Build some files + +fromdir="$scratchdir/from" +todir="$scratchdir/to" +checkdir="$scratchdir/check" + +mkdir "$fromdir" +name1="$fromdir/name1" +name2="$fromdir/name2" +dir1="$fromdir/dir1" +dir2="$fromdir/dir2" +echo "This is the file" > "$name1" +echo "This is the other file" > "$name2" +mkdir "$dir1" "$dir2" + +chmod 4700 "$name1" || test_skipped "Can't chmod" +chmod 700 "$dir1" +chmod 770 "$dir2" + +# Copy the files we've created over to another directory +checkit "$RSYNC -avv '$fromdir/' '$checkdir/'" "$fromdir" "$checkdir" + +# And then manually make the changes which should occur +umask 002 +chmod ug-s,a+rX "$checkdir"/* +chmod +w "$checkdir" "$checkdir"/dir* + +checkit "$RSYNC -avv --chmod ug-s,a+rX,D+w '$fromdir/' '$todir/'" "$checkdir" "$todir" + +rm -r "$fromdir" "$checkdir" "$todir" +makepath "$todir" "$fromdir/foo" +touch "$fromdir/bar" + +checkit "$RSYNC -avv '$fromdir/' '$checkdir/'" "$fromdir" "$checkdir" +chmod o+x "$fromdir"/bar + +checkit "$RSYNC -avv --chmod=Fo-x '$fromdir/' '$todir/'" "$checkdir" "$todir" + +# Tickle a bug in rsync 2.6.8: if you push a new directory with --perms off to +# a daemon with an incoming chmod, the daemon pretends the directory is a file +# for the purposes of the second application of the incoming chmod. + +build_rsyncd_conf +cat >>"$scratchdir/test-rsyncd.conf" < + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that when rsync is running as root and has -a it correctly sets +# the ownership of the destination. + +# We don't know what users will be present on this system, so we just +# use random numeric uids and gids. + +. "$suitedir/rsync.fns" + +case $0 in +*fake*) + $RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" + RSYNC="$RSYNC --fake-super" + TLS_ARGS="$TLS_ARGS --fake-super" + case "$HOST_OS" in + darwin*) + chown() { + own=$1 + shift + xattr -s 'rsync.%stat' "100644 0,0 $own" "${@}" + } + ;; + solaris*) + chown() { + own=$1 + shift + for fn in "${@}"; do + runat "$fn" "$SHELL_PATH" < rsync.%stat +EOF + done + } + ;; + freebsd*) + chown() { + own=$1 + shift + setextattr -h user "rsync.%stat" "100644 0,0 $own" "${@}" + } + ;; + *) + chown() { + own=$1 + shift + setfattr -n 'user.rsync.%stat' -v "100644 0,0 $own" "${@}" + } + ;; + esac + ;; +*) + RSYNC="$RSYNC --super" + my_uid=`get_testuid` + root_uid=`get_rootuid` + if test x"$my_uid" = x; then + : # If "id" failed, try to continue... + elif test x"$my_uid" != x"$root_uid"; then + if [ -e "$FAKEROOT_PATH" ]; then + echo "Let's try re-running the script under fakeroot..." + exec "$FAKEROOT_PATH" "$SHELL_PATH" "$0" + fi + fi + ;; +esac + +# Build some hardlinks + +mkdir "$fromdir" +name1="$fromdir/name1" +name2="$fromdir/name2" +echo "This is the file" > "$name1" +echo "This is the other file" > "$name2" + +chown 5000:5002 "$name1" || test_skipped "Can't chown (probably need root)" +chown 5001:5003 "$name2" || test_skipped "Can't chown (probably need root)" + +cd "$fromdir/.." +checkit "$RSYNC -aHvv from/ to/" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/crtimes.test b/testsuite/crtimes.test new file mode 100644 index 0000000..456f0a5 --- /dev/null +++ b/testsuite/crtimes.test @@ -0,0 +1,26 @@ +#!/bin/sh + +# Test rsync copying create times + +. "$suitedir/rsync.fns" + +$RSYNC -VV | grep '"crtimes": true' >/dev/null || test_skipped "Rsync is configured without crtimes support" + +# Setting an older time via touch sets the create time to the mtime. +# Setting it to a newer time affects just the mtime. + +mkdir "$fromdir" +echo hiho >"$fromdir/foo" + +touch -t 200101011111.11 "$fromdir" +touch -t 200202022222.22 "$fromdir" + +touch -t 200111111111.11 "$fromdir/foo" +touch -t 200212122222.22 "$fromdir/foo" + +TLS_ARGS=--crtimes + +checkit "$RSYNC -rtgvvv --crtimes \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/daemon-gzip-download.test b/testsuite/daemon-gzip-download.test new file mode 100644 index 0000000..57dd820 --- /dev/null +++ b/testsuite/daemon-gzip-download.test @@ -0,0 +1,37 @@ +#!/bin/sh + +# Copyright (C) 2001, 2002 by Martin Pool + +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +# This test tries to download a tree over a compressed connection from +# the server. This ought to exercise (exorcise?) a bug in 2.5.3. + +. "$suitedir/rsync.fns" + +build_rsyncd_conf + +RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" +export RSYNC_CONNECT_PROG + +hands_setup + +# Build chkdir with a normal rsync and an --exclude. +$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/" + +checkit "$RSYNC -avvvvzz localhost::test-from/ '$todir/'" "$chkdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/daemon-gzip-upload.test b/testsuite/daemon-gzip-upload.test new file mode 100644 index 0000000..b2110ea --- /dev/null +++ b/testsuite/daemon-gzip-upload.test @@ -0,0 +1,31 @@ +#!/bin/sh + +# Copyright (C) 2001, 2002 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING) + +# We don't really want to start the server listening, because that +# might interfere with the security or operation of the test machine. +# Instead we use the fake-connect feature to dynamically assign a pair +# of ports. + +# This test tries to upload a file over a compressed connection to the +# server. This ought to exercise (exorcise?) a bug in 2.5.3. + +. "$suitedir/rsync.fns" + +build_rsyncd_conf + +RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" +export RSYNC_CONNECT_PROG + +hands_setup + +# Build chkdir with a normal rsync and an --exclude. +$RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/" + +checkit "'$ignore23' $RSYNC -avvvvzz '$fromdir/' localhost::test-to/" "$chkdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/daemon.test b/testsuite/daemon.test new file mode 100644 index 0000000..60aa334 --- /dev/null +++ b/testsuite/daemon.test @@ -0,0 +1,90 @@ +#!/bin/sh + +# Copyright (C) 2001 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING) + +# We don't really want to start the server listening, because that +# might interfere with the security or operation of the test machine. +# Instead we use the fake-connect feature to dynamically assign a pair +# of ports. + +# Having started the server we try some basic operations against it: + +# getting a list of module +# listing files in a module +# retrieving a module +# uploading to a module +# checking the log file +# password authentication + +. "$suitedir/rsync.fns" + +SSH="src/support/lsh.sh --no-cd" +FILE_REPL='s/^\([^d][^ ]*\) *\(..........[0-9]\) /\1 \2 /' +DIR_REPL='s/^\(d[^ ]*\) *[0-9][.,0-9]* /\1 DIR /' +LS_REPL='s;[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ;####/##/## ##:##:## ;g' + +build_rsyncd_conf + +makepath "$fromdir/foo" "$fromdir/bar/baz" +makepath "$todir" +echo one >"$fromdir/foo/one" +echo two >"$fromdir/bar/two" +echo three >"$fromdir/bar/baz/three" + +cd "$scratchdir" + +ln -s test-rsyncd.conf rsyncd.conf + +my_uid=`get_testuid` +root_uid=`get_rootuid` +confopt='' +if test x"$my_uid" = x"$root_uid"; then + # Root needs to specify the config file, or it uses /etc/rsyncd.conf. + echo "Forcing --config=$conf" + confopt=" --config=$conf" +fi + +# These have a space-padded 15-char name, then a tab, then a comment. +sed 's/NOCOMMENT//' <"$chkfile" +test-from r/o +test-to r/w +test-scratch NOCOMMENT +EOT + +checkdiff2 "$RSYNC -ve '$SSH' --rsync-path='$RSYNC$confopt' localhost::" +echo '====' + +RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" +export RSYNC_CONNECT_PROG + +checkdiff2 "$RSYNC -v localhost::" +echo '====' + +checkdiff "$RSYNC -r localhost::test-hidden" \ + "sed -e '$FILE_REPL' -e '$DIR_REPL' -e '$LS_REPL'" </dev/null; then + checkdiff "$RSYNC -rU localhost::test-from/f*" \ + "sed -e '$FILE_REPL' -e '$DIR_REPL' -e '$LS_REPL'" < "$fromdir/foo" + +checkit "$RSYNC -aiv --delay-updates \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" + +mkdir "$todir/.~tmp~" +echo 2 > "$todir/.~tmp~/foo" +touch -r .. "$todir/.~tmp~/foo" "$todir/foo" +echo 3 > "$fromdir/foo" + +checkit "$RSYNC -aiv --delay-updates \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/delete.test b/testsuite/delete.test new file mode 100644 index 0000000..2a9df7c --- /dev/null +++ b/testsuite/delete.test @@ -0,0 +1,57 @@ +#!/bin/sh + +# Copyright (C) 2005-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync handling of various delete directives. + +. "$suitedir/rsync.fns" + +hands_setup + +makepath "$chkdir" "$todir/extradir" "$todir/emptydir/subdir" + +echo extra >"$todir"/remove1 +echo extra >"$todir"/remove2 +echo extra >"$todir"/extradir/remove3 +echo extra >"$todir"/emptydir/subdir/remove4 + +# Create two chk dirs, one with a copy of the source files, and one with +# what we expect to be left behind by the copy using --remove-source-files. +# Also, make sure that --dry-run --del doesn't output anything extraneous. +$RSYNC -av "$fromdir/" "$chkdir/copy/" >"$tmpdir/copy.out" 2>&1 +cat "$tmpdir/copy.out" +grep -E -v '^(created directory|sent|total size) ' "$tmpdir/copy.out" >"$tmpdir/copy.new" +mv "$tmpdir/copy.new" "$tmpdir/copy.out" + +$RSYNC -avn --del "$fromdir/" "$chkdir/copy2/" >"$tmpdir/copy2.out" 2>&1 || true +cat "$tmpdir/copy2.out" +grep -E -v '^(created directory|sent|total size) ' "$tmpdir/copy2.out" >"$tmpdir/copy2.new" +mv "$tmpdir/copy2.new" "$tmpdir/copy2.out" + +diff $diffopt "$tmpdir/copy.out" "$tmpdir/copy2.out" + +$RSYNC -av -f 'exclude,! */' "$fromdir/" "$chkdir/empty/" + +checkit "$RSYNC -avv --del --remove-source-files '$fromdir/' '$todir/'" "$chkdir/copy" "$todir" + +diff -r "$chkdir/empty" "$fromdir" + +# Make sure that "P" but not "-" per-dir merge-file filters take effect with +# --delete-excluded. +cat >"$todir/filters" < + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync handling of devices. This can only run if you're root. + +. "$suitedir/rsync.fns" + +# Build some hardlinks + +case $0 in +*fake*) + $RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" + RSYNC="$RSYNC --fake-super" + TLS_ARGS="$TLS_ARGS --fake-super" + case "$HOST_OS" in + darwin*) + mknod() { + fn="$1" + case "$2" in + p) mode=10644 ;; + c) mode=20644 ;; + b) mode=60644 ;; + esac + maj="${3:-0}" + min="${4:-0}" + touch "$fn" + xattr -s 'rsync.%stat' "$mode $maj,$min 0:0" "$fn" + } + ;; + solaris*) + mknod() { + fn="$1" + case "$2" in + p) mode=10644 ;; + c) mode=20644 ;; + b) mode=60644 ;; + esac + maj="${3:-0}" + min="${4:-0}" + touch "$fn" + runat "$fn" "$SHELL_PATH" < rsync.%stat +EOF + } + ;; + freebsd*) + mknod() { + fn="$1" + case "$2" in + p) mode=10644 ;; + c) mode=20644 ;; + b) mode=60644 ;; + esac + maj="${3:-0}" + min="${4:-0}" + touch "$fn" + setextattr -h user "rsync.%stat" "$mode $maj,$min 0:0" "$fn" + } + ;; + *) + mknod() { + fn="$1" + case "$2" in + p) mode=10644 ;; + c) mode=20644 ;; + b) mode=60644 ;; + esac + maj="${3:-0}" + min="${4:-0}" + touch "$fn" + setfattr -n 'user.rsync.%stat' -v "$mode $maj,$min 0:0" "$fn" + } + ;; + esac + ;; +*) + my_uid=`get_testuid` + root_uid=`get_rootuid` + if test x"$my_uid" = x; then + : # If "id" failed, try to continue... + elif test x"$my_uid" != x"$root_uid"; then + if [ -e "$FAKEROOT_PATH" ]; then + echo "Let's try re-running the script under fakeroot..." + exec "$FAKEROOT_PATH" "$SHELL_PATH" $RUNSHFLAGS "$0" + fi + test_skipped "Rsync needs root/fakeroot for device tests" + fi + ;; +esac + +# TODO: Need to test whether hardlinks are possible on this OS/filesystem + +$RSYNC -VV | grep '"hardlink_specials": true' >/dev/null && CAN_HLINK_SPECIAL=yes || CAN_HLINK_SPECIAL=no + +mkdir "$fromdir" +mkdir "$todir" +mknod "$fromdir/char" c 41 67 || test_skipped "Can't create char device node" +mknod "$fromdir/char2" c 42 68 || test_skipped "Can't create char device node" +mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node" +mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node" +mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node" +mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node" +if test "$CAN_HLINK_SPECIAL" = yes; then + ln "$fromdir/block3" "$fromdir/block3.5" +else + echo "Skipping hard-linked device test..." +fi +mkfifo "$fromdir/fifo" || mknod "$fromdir/fifo" p || test_skipped "Can't run mkfifo" +# Work around time rounding/truncating issue by touching both files. +touch -r "$fromdir/block" "$fromdir/block" "$fromdir/block2" + +checkdiff "$RSYNC -ai '$fromdir/block' '$todir/block2'" <"$chkfile" < block3 +cD$all_plus char +cD$all_plus char2 +cD$all_plus char3 +cS$all_plus fifo +EOT +if test "$CAN_HLINK_SPECIAL" = no; then + grep -v block3.5 <"$chkfile" >"$chkfile.new" + mv "$chkfile.new" "$chkfile" +fi + +checkdiff2 "$RSYNC -aiHvv '$fromdir/' '$todir/'" v_filt + +echo "check how the directory listings compare with diff:" +echo "" +( cd "$fromdir" && rsync_ls_lR . ) > "$tmpdir/ls-from" +( cd "$todir" && rsync_ls_lR . ) > "$tmpdir/ls-to" +diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" + +if test "$CAN_HLINK_SPECIAL" = yes; then + set -x + checkdiff "$RSYNC -aii --link-dest='$todir' '$fromdir/' '$chkdir/'" < +testit() { + todir="$scratchdir/$1" + mkdir "$todir" + chmod $2 "$todir" + # Make sure we obey directory setgid when creating a directory to hold multiple transferred files, + # even though the directory itself is outside the transfer + $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/" + check_perms "$todir/to" $5 "Target $1" + check_perms "$todir/to/dir" $5 "Target $1" + check_perms "$todir/to/file" $3 "Target $1" + check_perms "$todir/to/program" $4 "Target $1" +} + +mkdir "$scratchdir/dir" +# Cygwin has a persistent default dir ACL that ruins this test. +case `getfacl "$scratchdir/dir" 2>/dev/null || true` in +*default:user::*) test_skipped "The default ACL mode interferes with this test" ;; +esac + +echo "File!" >"$scratchdir/file" +echo "#!/bin/sh" >"$scratchdir/program" + +chmod u=rwx,g=rw,g+s,o=r "$scratchdir/dir" || test_skipped "Can't chmod" +chmod 664 "$scratchdir/file" +chmod 775 "$scratchdir/program" + +[ -g "$scratchdir/dir" ] || test_skipped "The directory setgid bit vanished!" +mkdir "$scratchdir/dir/blah" +[ -g "$scratchdir/dir/blah" ] || test_skipped "Your filesystem doesn't use directory setgid; maybe it's BSD." + +# Test some target directories +testit setgid-off 700 rw------- rwx------ rwx------ +testit setgid-on u=rwx,g=rw,g+s,o-rwx rw------- rwx------ rwx--S--- + +# Hooray +exit 0 diff --git a/testsuite/duplicates.test b/testsuite/duplicates.test new file mode 100644 index 0000000..3317e72 --- /dev/null +++ b/testsuite/duplicates.test @@ -0,0 +1,44 @@ +#!/bin/sh + +# Copyright (C) 2002 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync handling of duplicate filenames. + +# It's quite possible that the user might specify the same source file +# more than once on the command line, perhaps through shell variables +# or wildcard expansions. It might cause problems for rsync if the +# same name occurred more than once in the file list, because we might +# be trying to update the first copy and generate checksums for the +# second copy at the same time. See clean_flist() for the implementation. + +# We don't need to worry about hardlinks or symlinks. Because we +# always rename-and-replace the new copy, they can't affect us. + +# This test is not great, because it is a timing-dependent bug. + +. "$suitedir/rsync.fns" + +# Build some hardlinks + +mkdir "$fromdir" +name1="$fromdir/name1" +name2="$fromdir/name2" +echo "This is the file" > "$name1" +ln -s "$name1" "$name2" || test_fail "can't create symlink" + +checkit "$RSYNC -avv '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$todir/'" "$fromdir" "$todir" \ + | tee "$outfile" + +# Make sure each file was only copied once... +if [ `grep -c '^name1$' "$outfile"` != 1 ]; then + test_fail "name1 was not copied exactly once" +fi +if [ `grep -c '^name2 -> ' "$outfile"` != 1 ]; then + test_fail "name2 was not copied exactly once" +fi + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/exclude-lsh.test b/testsuite/exclude-lsh.test new file mode 120000 index 0000000..84bc98a --- /dev/null +++ b/testsuite/exclude-lsh.test @@ -0,0 +1 @@ +exclude.test \ No newline at end of file diff --git a/testsuite/exclude.test b/testsuite/exclude.test new file mode 100644 index 0000000..56b68b8 --- /dev/null +++ b/testsuite/exclude.test @@ -0,0 +1,252 @@ +#!/bin/sh + +# Copyright (C) 2003-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync handling of exclude/include directives. + +# Test some of the more obscure wildcard handling of exclude/include +# processing. + +. "$suitedir/rsync.fns" + +CVSIGNORE='*.junk' +export CVSIGNORE + +case $0 in +*-lsh.*) + RSYNC_RSH="$scratchdir/src/support/lsh.sh" + export RSYNC_RSH + rpath=" --rsync-path='$RSYNC'" + host='lh:' + ;; +*) + rpath='' + host='' + ;; +esac + +# Build some files/dirs/links to copy + +makepath "$fromdir/foo/down/to/you" +makepath "$fromdir/foo/sub" +makepath "$fromdir/bar/down/to/foo/too" +makepath "$fromdir/bar/down/to/bar/baz" +makepath "$fromdir/mid/for/foo/and/that/is/who" +makepath "$fromdir/new/keep/this" +makepath "$fromdir/new/lose/this" +cat >"$fromdir/.filt" <"$fromdir/foo/file1" +echo removed >"$fromdir/foo/file2" +echo cvsout >"$fromdir/foo/file2.old" +cat >"$fromdir/foo/.filt" <"$fromdir/foo/sub/file1" +cat >"$fromdir/bar/.filt" <"$fromdir/bar/down/to/home-cvs-exclude" +cat >"$fromdir/bar/down/to/.filt2" <"$fromdir/bar/down/to/foo/.filt2" <"$fromdir/bar/down/to/foo/file1" +echo cvsout >"$fromdir/bar/down/to/foo/file1.bak" +echo gone >"$fromdir/bar/down/to/foo/file3" +echo lost >"$fromdir/bar/down/to/foo/file4" +echo weird >"$fromdir/bar/down/to/foo/+ file3" +echo cvsout-but-filtin >"$fromdir/bar/down/to/foo/file4.junk" +echo smashed >"$fromdir/bar/down/to/foo/to" +cat >"$fromdir/bar/down/to/bar/.filt2" <"$fromdir/bar/down/to/bar/baz/file5.deep" +# This one should be ineffectual +cat >"$fromdir/mid/.filt2" <"$fromdir/mid/one-in-one-out" +echo one-in-one-out >"$fromdir/mid/.cvsignore" +echo cvsin >"$fromdir/mid/one-for-all" +cat >"$fromdir/mid/.filt" <"$fromdir/mid/for/one-in-one-out" +echo expunged >"$fromdir/mid/for/foo/extra" +echo retained >"$fromdir/mid/for/foo/keep" + +# Setup our test exclude/include files. + +excl="$scratchdir/exclude-from" +cat >"$excl" <"$scratchdir/.cvsignore" <"$todir"/bar/down/to/bar/baz/nodel.deep +cp_touch "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz + +$RSYNC -av --rsync-path="$RSYNC" --existing --filter='-! */' "$host$fromdir/" "$chkdir/" + +# Now, test if rsync excludes the same files, this time with a merge-exclude +# file. + +checkit "sed '/!/d' '$excl' | + $RSYNC -avv$rpath -f dir-merge_.filt -f merge_- \ + --delete-during '$host$fromdir/' '$todir/'" "$chkdir" "$todir" + +# Remove the files that will be deleted. + +rm "$chkdir"/.filt +rm "$chkdir"/bar/.filt +rm "$chkdir"/bar/down/to/.filt2 +rm "$chkdir"/bar/down/to/foo/.filt2 +rm "$chkdir"/bar/down/to/bar/.filt2 +rm "$chkdir"/mid/.filt + +$RSYNC -av --rsync-path="$RSYNC" --existing --include='*/' --exclude='*' "$host$fromdir/" "$chkdir/" + +# Now, try the prior command with --delete-before and some side-specific +# rules. + +checkit "sed '/!/d' '$excl' | + $RSYNC -avv$rpath -f :s_.filt -f .s_- -f P_nodel.deep \ + --delete-before '$host$fromdir/' '$todir/'" "$chkdir" "$todir" + +# Next, we'll test some rule-restricted filter files. + +cat >"$fromdir/bar/down/.excl" <"$fromdir/bar/down/to/foo/.excl" <f$all_plus extra-src +.f$allspace same-newness +>f..t.$dots src-newness +EOT + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/executability.test b/testsuite/executability.test new file mode 100644 index 0000000..8f09d8f --- /dev/null +++ b/testsuite/executability.test @@ -0,0 +1,47 @@ +#!/bin/sh + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test the --executability or -E option. -- Matt McCutchen + +. $suitedir/rsync.fns + +# Put some files in the From directory +mkdir "$fromdir" +cat <"$fromdir/1" +#!/bin/sh +echo 'Program One!' +EOF +cat <"$fromdir/2" +#!/bin/sh +echo 'Program Two!' +EOF + +chmod 1700 "$fromdir/1" || test_skipped "Can't chmod" +chmod 600 "$fromdir/2" + +$RSYNC -rvv "$fromdir/" "$todir/" + +check_perms "$todir/1" rwx------ 1 +check_perms "$todir/2" rw------- 1 + +# Mix up the permissions a bit +chmod 600 "$fromdir/1" +chmod 601 "$fromdir/2" +chmod 604 "$todir/2" + +$RSYNC -rvv "$fromdir/" "$todir/" + +# No -E, so nothing should have changed +check_perms "$todir/1" rwx------ 2 +check_perms "$todir/2" rw----r-- 2 + +$RSYNC -rvvE "$fromdir/" "$todir/" + +# Now things should have happened! +check_perms "$todir/1" rw------- 3 +check_perms "$todir/2" rwx---r-x 3 + +# Hooray +exit 0 diff --git a/testsuite/files-from.test b/testsuite/files-from.test new file mode 100644 index 0000000..207eab5 --- /dev/null +++ b/testsuite/files-from.test @@ -0,0 +1,45 @@ +#!/bin/sh + +# Copyright (C) 2008-2020 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test that --files-from=FILE works right. + +. "$suitedir/rsync.fns" + +SSH="$scratchdir/src/support/lsh.sh" + +hands_setup + +# This list of files skips the contents of "subsubdir" but includes +# the contents of "subsubdir2" due to its trailing slash. +cat >"$scratchdir/filelist" < +# Copyright (C) 2001, 2002 by Martin Pool +# +# This program is distributable under the terms of the GNU GPL (see COPYING) + +. "$suitedir/rsync.fns" + +hands_setup + +DEBUG_OPTS="--debug=all0,deltasum0" + +# Main script starts here + +runtest "basic operation" 'checkit "$RSYNC -av \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' + +ln "$fromdir/filelist" "$fromdir/dir" +runtest "hard links" 'checkit "$RSYNC -avH --bwlimit=0 $DEBUG_OPTS \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' + +rm "$todir/text" +runtest "one file" 'checkit "$RSYNC -avH $DEBUG_OPTS \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' + +echo "extra line" >> "$todir/text" +runtest "extra data" 'checkit "$RSYNC -avH $DEBUG_OPTS --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' + +cp "$fromdir/text" "$todir/ThisShouldGo" +runtest " --delete" 'checkit "$RSYNC --delete -avH $DEBUG_OPTS \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' + +cd "$tmpdir" +rm -rf to from/*dir + +# Do the real copy, touch up the parent-dir's time, and then check the copy. +$RSYNC -av from/* to/ +checkit "$RSYNC -av --exclude='*' from/ to/" "$fromdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/hardlinks.test b/testsuite/hardlinks.test new file mode 100644 index 0000000..af2ea40 --- /dev/null +++ b/testsuite/hardlinks.test @@ -0,0 +1,81 @@ +#!/bin/sh + +# Copyright (C) 2002 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync handling of hardlinks. By default, rsync does not detect +# hard links and they get sent as separate files. If you specify -H, +# then hard links are detected and linked together on the receiver. + +. "$suitedir/rsync.fns" + +SSH="$scratchdir/src/support/lsh.sh" + +# Build some hardlinks + +fromdir="$scratchdir/from" +todir="$scratchdir/to" + +# TODO: Need to test whether hardlinks are possible on this OS/filesystem + +mkdir "$fromdir" +name1="$fromdir/name1" +name2="$fromdir/name2" +name3="$fromdir/name3" +name4="$fromdir/name4" +echo "This is the file" > "$name1" +ln "$name1" "$name2" || test_skipped "Can't create hardlink" +ln "$name2" "$name3" || test_fail "Can't create hardlink" +cp "$name2" "$name4" || test_fail "Can't copy file" +cat $srcdir/*.c >"$fromdir/text" + +checkit "$RSYNC -aHivv --debug=HLINK5 '$fromdir/' '$todir/'" "$fromdir" "$todir" + +echo "extra extra" >>"$todir/name1" + +checkit "$RSYNC -aHivv --debug=HLINK5 --no-whole-file '$fromdir/' '$todir/'" "$fromdir" "$todir" + +# Add a new link in a new subdirectory to test that we don't try to link +# the files before the directory gets created. We also create a bunch of +# extra files to ensure that an incremental-recursion transfer works across +# distant files. +makepath "$fromdir/subdir/down/deep" + +files='' +for x in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9; do + for y in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9; do + files="$files $x$y" + done +done +(cd "$fromdir/subdir"; touch $files) + +ln "$name1" "$fromdir/subdir/down/deep/new-file" +rm "$todir/text" + +checkit "$RSYNC -aHivve '$SSH' --debug=HLINK5 --rsync-path='$RSYNC' '$fromdir/' localhost:'$todir/'" "$fromdir" "$todir" + +# Do some duplicate copies using --link-dest and --copy-dest to test that +# we hard-link all locally-inherited items. +checkit "$RSYNC -aHivv --debug=HLINK5 --link-dest='$todir' '$fromdir/' '$chkdir/'" "$todir" "$chkdir" + +rm -rf "$chkdir" +checkit "$RSYNC -aHivv --debug=HLINK5 --copy-dest='$todir' '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir" + +# Create a hard link that has only one part in the hierarchy. +echo "This is another file" >"$fromdir/solo" +ln "$fromdir/solo" "$chkdir/solo" || test_fail "Can't create hardlink" + +# Make sure that the checksum data doesn't slide due to an HLINK_BUMP() change. +checktee "$RSYNC -aHivc --debug=HLINK5 '$fromdir/' '$chkdir/'" +grep solo "$outfile" && test_fail "Erroneous copy of solo file occurred!" + +# Make sure there's nothing wrong with sending a single file with -H +# enabled (this has broken twice so far, so we need this test). +rm -rf "$todir" +$RSYNC -aHivv --debug=HLINK5 "$name1" "$todir/" +diff $diffopt "$name1" "$todir" || test_fail "solo copy of name1 failed" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/itemize.test b/testsuite/itemize.test new file mode 100644 index 0000000..c1c57c5 --- /dev/null +++ b/testsuite/itemize.test @@ -0,0 +1,246 @@ +#!/bin/sh + +# Copyright (C) 2005-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test the output of various copy commands to ensure itemized output +# and double-verbose output is correct. + +. "$suitedir/rsync.fns" + +to2dir="$tmpdir/to2" + +makepath "$fromdir/foo" +makepath "$fromdir/bar/baz" +cp_p "$srcdir/configure.ac" "$fromdir/foo/config1" +cp_p "$srcdir/config.sub" "$fromdir/foo/config2" +cp_p "$srcdir/rsync.h" "$fromdir/bar/baz/rsync" +chmod 600 "$fromdir"/foo/config? "$fromdir/bar/baz/rsync" +umask 0 +ln -s ../bar/baz/rsync "$fromdir/foo/sym" +umask 022 +ln "$fromdir/foo/config1" "$fromdir/foo/extra" +rm -f "$to2dir" + +# Check if rsync is set to hard-link symlinks. +if $RSYNC -VV | grep '"hardlink_symlinks": true' >/dev/null; then + L=hL + sym_dots="$allspace" + L_sym_dots=".L$allspace" + is_uptodate='is uptodate' + touch "$chkfile.extra" +else + L=cL + sym_dots="c.t.$dots" + L_sym_dots="cL$sym_dots" + is_uptodate='-> ../bar/baz/rsync' + echo "cL$sym_dots foo/sym $is_uptodate" >"$chkfile.extra" +fi + +# Check if rsync can preserve time on symlinks +case "$RSYNC" in +*protocol=2*) + T=.T + ;; +*) + if $RSYNC -VV | grep '"symtimes": true' >/dev/null; then + T=.t + else + T=.T + fi + ;; +esac + +checkdiff "$RSYNC -iplr '$fromdir/' '$todir/'" <f$all_plus bar/baz/rsync +cd$all_plus foo/ +>f$all_plus foo/config1 +>f$all_plus foo/config2 +>f$all_plus foo/extra +cL$all_plus foo/sym -> ../bar/baz/rsync +EOT + +# Ensure there are no accidental directory-time problems. +$RSYNC -a -f '-! */' "$fromdir/" "$todir" + +cp_p "$srcdir/configure.ac" "$fromdir/foo/config2" +chmod 601 "$fromdir/foo/config2" +checkdiff "$RSYNC -iplrH '$fromdir/' '$todir/'" <f..T.$dots bar/baz/rsync +>f..T.$dots foo/config1 +>f.sTp$dots foo/config2 +hf..T.$dots foo/extra => foo/config1 +EOT + +$RSYNC -a -f '-! */' "$fromdir/" "$todir" +cp_p "$srcdir/config.sub" "$fromdir/foo/config2" +sleep 1 # For directory mod below to ensure time difference +rm "$todir/foo/sym" +umask 0 +ln -s ../bar/baz "$todir/foo/sym" +umask 022 +chmod 600 "$fromdir/foo/config2" +chmod 777 "$todir/bar/baz/rsync" + +checkdiff "$RSYNC -iplrtc '$fromdir/' '$todir/'" <fcstp$dots foo/config2 +cLc$T.$dots foo/sym -> ../bar/baz/rsync +EOT + +cp_p "$srcdir/configure.ac" "$fromdir/foo/config2" +chmod 600 "$fromdir/foo/config2" +# Lack of -t is for unchanged hard-link stress-test! +checkdiff "$RSYNC -vvplrH '$fromdir/' '$todir/'" \ + v_filt <f..t.$dots foo/config2 +hf$allspace foo/extra +.L$allspace foo/sym -> ../bar/baz/rsync +EOT + +chmod 757 "$todir/foo/config1" +touch "$todir/foo/config2" +checkdiff "$RSYNC -vplrtH '$fromdir/' '$todir/'" \ + v_filt <f..t.$dots foo/config2 +EOT + +checkdiff "$RSYNC -ivvplrtH --copy-dest=../to '$fromdir/' '$to2dir/'" \ + v_filt < foo/config1 +cL$sym_dots foo/sym -> ../bar/baz/rsync +EOT + +rm -rf "$to2dir" +cat - "$chkfile.extra" <"$chkfile" +created directory $to2dir +hf$allspace foo/extra => foo/config1 +EOT +checkdiff2 "$RSYNC -iplrtH --copy-dest=../to '$fromdir/' '$to2dir/'" + +rm -rf "$to2dir" +checkdiff "$RSYNC -vvplrtH --copy-dest='$todir' '$fromdir/' '$to2dir/'" \ + v_filt < foo/config1 +EOT + +rm -rf "$to2dir" +checkdiff "$RSYNC -ivvplrtH --link-dest='$todir' '$fromdir/' '$to2dir/'" \ + v_filt < foo/config1 +$L$sym_dots foo/sym -> ../bar/baz/rsync +EOT + +rm -rf "$to2dir" +cat - "$chkfile.extra" <"$chkfile" +created directory $to2dir +EOT +checkdiff2 "$RSYNC -iplrtH --dry-run --link-dest=../to '$fromdir/' '$to2dir/'" + +rm -rf "$to2dir" +checkdiff2 "$RSYNC -iplrtH --link-dest=../to '$fromdir/' '$to2dir/'" + +rm -rf "$to2dir" +checkdiff "$RSYNC -vvplrtH --link-dest='$todir' '$fromdir/' '$to2dir/'" \ + v_filt < ../bar/baz/rsync +EOT + +rm -rf "$to2dir" +cat - "$chkfile.extra" <"$chkfile" +created directory $to2dir +EOT +checkdiff2 "$RSYNC -iplrtH --compare-dest='$todir' '$fromdir/' '$to2dir/'" + +rm -rf "$to2dir" +checkdiff "$RSYNC -vvplrtH --compare-dest='$todir' '$fromdir/' '$to2dir/'" \ + v_filt < +# Copyright (C) 2001 by Martin Pool +# +# This program is distributable under the terms of the GNU GPL (see COPYING) + +. "$suitedir/rsync.fns" + +hands_setup + +longname=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job +longdir="$fromdir/$longname/$longname/$longname" + +makepath "$longdir" || test_skipped "unable to create long directory" +touch "$longdir/1" || test_skipped "unable to create files in long directory" +date > "$longdir/1" +if [ -r /etc ]; then + ls -la /etc >"$longdir/2" +else + ls -la / >"$longdir/2" +fi +checkit "$RSYNC --delete -avH '$fromdir/' '$todir'" "$fromdir/" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/merge.test b/testsuite/merge.test new file mode 100644 index 0000000..17050a1 --- /dev/null +++ b/testsuite/merge.test @@ -0,0 +1,57 @@ +#!/bin/sh + +# Copyright (C) 2004-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Make sure we can merge files from multiple directories into one. + +. "$suitedir/rsync.fns" + +# Build some files/dirs/links to copy + +# Use local dirnames to better exercise the arg-parsing code. +cd "$tmpdir" + +mkdir from1 from2 from3 deep +mkdir from2/sub1 from3/sub1 +mkdir from3/sub2 from1/dir-and-not-dir +mkdir chk chk/sub1 chk/sub2 chk/dir-and-not-dir +echo "one" >from1/one +cp_touch from1/one from2/one +cp_touch from1/one from3/one +echo "two" >from1/two +echo "three" >from2/three +echo "four" >from3/four +echo "five" >from1/five +echo "six" >from3/six +echo "sub1" >from2/sub1/uno +cp_touch from2/sub1/uno from3/sub1/uno +echo "sub2" >from3/sub1/dos +echo "sub3" >from2/sub1/tres +echo "subby" >from3/sub2/subby +echo "extra" >from1/dir-and-not-dir/inside +echo "not-dir" >from3/dir-and-not-dir +echo "arg-test" >deep/arg-test +echo "shallow" >shallow + +cp_touch from1/one from1/two from2/three from3/four from1/five from3/six chk +cp_touch deep/arg-test shallow chk +cp_touch from1/dir-and-not-dir/inside chk/dir-and-not-dir +cp_touch from2/sub1/uno from3/sub1/dos from2/sub1/tres chk/sub1 +cp_touch from3/sub2/subby chk/sub2 + +# Make sure that time has moved on. +sleep 1 + +# Get rid of any directory-time differences +$RSYNC -av --existing -f 'exclude,! */' from1/ from2/ +$RSYNC -av --existing -f 'exclude,! */' from2/ from3/ +$RSYNC -av --existing -f 'exclude,! */' from1/ chk/ +$RSYNC -av --existing -f 'exclude,! */' from3/ chk/ + +checkit "$RSYNC -avv deep/arg-test shallow from1/ from2/ from3/ to/" "$chkdir" "$todir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/missing.test b/testsuite/missing.test new file mode 100644 index 0000000..2fbf461 --- /dev/null +++ b/testsuite/missing.test @@ -0,0 +1,34 @@ +#!/bin/sh + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test three bugs fixed by my redoing of the missing_below logic. + +. $suitedir/rsync.fns + +makepath "$fromdir/subdir" "$todir" +echo data >"$fromdir/subdir/file" +echo data >"$todir/other" + +# Test 1: Too much "not creating new..." output on a dry run +$RSYNC -n -r --ignore-non-existing -vv "$fromdir/" "$todir/" | tee "$scratchdir/out" +if grep 'not creating new.*subdir/file' "$scratchdir/out" >/dev/null; then + test_fail 'test 1 failed' +fi + +case "$RSYNC" in +*protocol=29*) # FIXME can we get past the new flist sanity check in protocol 29? + echo "Skipped test 2 for protocol 29." + ;; +*) + # Test 2: Attempt to make a fuzzy dirlist for a dir not created on a dry run + $RSYNC -n -r -R --no-implied-dirs -y "$fromdir/./subdir/file" "$todir/" \ + || test_fail 'test 2 failed' + ;; +esac + +# Test 3: --delete-after pass skipped when last dir is dry-missing +$RSYNC -n -r --delete-after -i "$fromdir/" "$todir/" | tee "$scratchdir/out" +grep '^\*deleting * other' "$scratchdir/out" >/dev/null \ + || test_fail 'test 3 failed' diff --git a/testsuite/mkpath.test b/testsuite/mkpath.test new file mode 100644 index 0000000..8046345 --- /dev/null +++ b/testsuite/mkpath.test @@ -0,0 +1,47 @@ +#!/bin/sh + +. "$suitedir/rsync.fns" + +makepath "$fromdir" +makepath "$todir" + +cp_p "$srcdir/rsync.h" "$fromdir/text" +cp_p "$srcdir/configure.ac" "$fromdir/extra" + +cd "$tmpdir" + +deep_dir=to/foo/bar/baz/down/deep + +# Check that we can create several levels of dest dir +$RSYNC -aiv --mkpath from/text $deep_dir/new +test -f $deep_dir/new || test_fail "'new' file not found in $deep_dir dir" +rm -rf to/foo + +$RSYNC -aiv --mkpath from/text $deep_dir/ +test -f $deep_dir/text || test_fail "'text' file not found in $deep_dir dir" +rm $deep_dir/text + +# Make sure we can handle an existing path +mkdir $deep_dir/new +$RSYNC -aiv --mkpath from/text $deep_dir/new +test -f $deep_dir/new/text || test_fail "'text' file not found in $deep_dir/new dir" + +# ... and an existing path when an alternate dest filename is specified +$RSYNC -aiv --mkpath from/text $deep_dir/new/text2 +test -f $deep_dir/new/text2 || test_fail "'text2' file not found in $deep_dir/new dir" +rm -rf to/foo + +# Try the tests again with multiple source args +$RSYNC -aiv --mkpath from/ $deep_dir +test -f $deep_dir/extra || test_fail "'extra' file not found in $deep_dir dir" +rm -rf to/foo + +$RSYNC -aiv --mkpath from/ $deep_dir/ +test -f $deep_dir/text || test_fail "'text' file not found in $deep_dir dir" + +# Make sure that we can handle no path +$RSYNC -aiv --mkpath from/text to_text +test -f to_text || test_fail "'to_text' file not found in current dir" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/protected-regular.test b/testsuite/protected-regular.test new file mode 100644 index 0000000..40416b0 --- /dev/null +++ b/testsuite/protected-regular.test @@ -0,0 +1,31 @@ +#!/bin/sh + +# Copyright (C) 2021 by Achim Leitner +# This program is distributable under the terms of the GNU GPL (see COPYING) +# +# Modern linux systems have the protected_regular feature set to 1 or 2 +# See https://www.kernel.org/doc/Documentation/sysctl/fs.txt +# Make sure we can still write these files in --inplace mode + +. "$suitedir/rsync.fns" + +test -f /proc/sys/fs/protected_regular || test_skipped "Can't find protected_regular setting (only available on Linux)" +pr_lvl=`cat /proc/sys/fs/protected_regular 2>/dev/null` || test_skipped "Can't check if fs.protected_regular is enabled (probably need root)" +test "$pr_lvl" != 0 || test_skipped "fs.protected_regular is not enabled" + +workdir="$tmpdir/files" +mkdir "$workdir" +chmod 1777 "$workdir" + +echo "Source" > "$workdir/src" +echo "" > "$workdir/dst" +chown 5001 "$workdir/dst" || test_skipped "Can't chown (probably need root)" + +# Output is only shown in case of an error +echo "Contents of $workdir:" +ls -al "$workdir" + +$RSYNC --inplace "$workdir/src" "$workdir/dst" || test_fail + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/relative.test b/testsuite/relative.test new file mode 100644 index 0000000..5546291 --- /dev/null +++ b/testsuite/relative.test @@ -0,0 +1,60 @@ +#!/bin/sh + +# Copyright (C) 2005-2020 Wayne Davison +# +# This program is distributable under the terms of the GNU GPL (see COPYING) + +. "$suitedir/rsync.fns" + +deepstr='down/3/deep' +deepdir="$fromdir/$deepstr" +extradir="$fromdir/extra" +makepath "$deepdir" "$extradir/$deepstr" "$chkdir" + +fromdir="$deepdir" +hands_setup +fromdir="$tmpdir/from" + +extrafile="$extradir/./$deepstr/extra.added.value" +echo wowza >"$extrafile" + +$RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$extradir/" + +cd "$fromdir" + +# Main script starts here + +$RSYNC -ai --include=/down/ --exclude='/*' "$fromdir/" "$chkdir/" + +sleep 1 +runtest "basic relative" 'checkit "$RSYNC -avR ./$deepstr \"$todir\"" "$chkdir" "$todir"' + +ln $deepstr/filelist $deepstr/dir +ln ../chk/$deepstr/filelist ../chk/$deepstr/dir +# Work around time rounding/truncating issue by touching both dirs. +touch -r $deepstr/dir $deepstr/dir ../chk/$deepstr/dir +runtest "hard links" 'checkit "$RSYNC -avHR ./$deepstr/ \"$todir\"" "$chkdir" "$todir"' + +cp "$deepdir/text" "$todir/$deepstr/ThisShouldGo" +cp "$deepdir/text" "$todir/$deepstr/dir/ThisShouldGoToo" +runtest "deletion" 'checkit "$RSYNC -avHR --del ./$deepstr/ \"$todir\"" "$chkdir" "$todir"' + +runtest "non-deletion" 'checkit "$RSYNC -aiHR --del ./$deepstr/ \"$todir\"" "$chkdir" "$todir"' \ + | tee "$outfile" + +# Make sure no files were deleted +grep 'deleting ' "$outfile" && test_fail "Erroneous deletions occurred!" + +# Relative with merging. +$RSYNC -ai "$extradir/down" "$chkdir/" + +checkit "$RSYNC -aiR $deepstr '$extrafile' '$todir'" "$chkdir" "$todir" + +checkit "$RSYNC -aiR --del $deepstr '$extrafile' '$todir'" "$chkdir" "$todir" \ + | tee "$outfile" + +# Make sure no files were deleted +grep 'deleting ' "$outfile" && test_fail "Erroneous deletions occurred! (2)" + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/rsync.fns b/testsuite/rsync.fns new file mode 100644 index 0000000..2ab97b6 --- /dev/null +++ b/testsuite/rsync.fns @@ -0,0 +1,498 @@ +#!/bin/sh + +# Copyright (C) 2001 by Martin Pool + +# General-purpose test functions for rsync. + +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +tmpdir="$scratchdir" +fromdir="$tmpdir/from" +todir="$tmpdir/to" +chkdir="$tmpdir/chk" + +chkfile="$scratchdir/rsync.chk" +outfile="$scratchdir/rsync.out" + +# For itemized output: +all_plus='+++++++++' +allspace=' ' +dots='.....' # trailing dots after changes +tab_ch=' ' # a single tab character + +# Berkley's nice. +PATH="$PATH:/usr/ucb" + +if diff -u "$suitedir/rsync.fns" "$suitedir/rsync.fns" >/dev/null 2>&1; then + diffopt="-u" +else + diffopt="-c" +fi + +HOME="$scratchdir" +export HOME + +runtest() { + echo $ECHO_N "Test $1: $ECHO_C" + if eval "$2"; then + echo "$ECHO_T done." + return 0 + else + echo "$ECHO_T failed!" + return 1 + fi +} + +set_cp_destdir() { + while test $# -gt 1; do + shift + done + destdir="$1" +} + +# Perform a "cp -p", making sure that timestamps are really the same, +# even if the copy rounded microsecond times on the destination file. +cp_touch() { + cp_p "${@}" + if test $# -gt 2 || test -d "$2"; then + set_cp_destdir "${@}" # sets destdir var + while test $# -gt 1; do + destname="$destdir/`basename $1`" + touch -r "$destname" "$1" "$destname" + shift + done + else + touch -r "$2" "$1" "$2" + fi +} + +# Call this if you want to filter (stdin -> stdout) verbose messages (-v or +# -vv) from an rsync run (whittling the output down to just the file messages). +# This isn't needed if you use -i without -v. +v_filt() { + sed -e '/^building file list /d' \ + -e '/^sending incremental file list/d' \ + -e '/^created directory /d' \ + -e '/^done$/d' \ + -e '/ --whole-file$/d' \ + -e '/^total: /d' \ + -e '/^client charset: /d' \ + -e '/^server charset: /d' \ + -e '/^$/,$d' +} + +printmsg() { + echo "$1" +} + +rsync_ls_lR() { + find "$@" -name .git -prune -o -name auto-build-save -prune -o -print | \ + sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" $TLS_ARGS +} + +get_testuid() { + uid=`id -u 2>/dev/null || true` + case "$uid" in + [0-9]*) echo "$uid" ;; + *) id 2>/dev/null | sed 's/^[^0-9]*\([0-9][0-9]*\).*/\1/' ;; + esac +} + +get_rootuid() { + uid=`id -u root 2>/dev/null || true` + case "$uid" in + [0-9]*) echo "$uid" ;; + *) echo 0 ;; + esac +} + +get_rootgid() { + gid=`id -g root 2>/dev/null || true` + case "$gid" in + [0-9]*) echo "$gid" ;; + *) echo 0 ;; + esac +} + +# When copying via "cp -p", we want to ensure that a non-root user does not +# preserve ownership (we want our files to be created as the testing user). +# For instance, a Cygwin CI run might have git files owned by a different +# user than the (admin) user running the tests. +cp_cmd="cp -p" +if test x`get_testuid` != x0; then + case `cp --help 2>/dev/null` in + *--no-preserve=*) cp_cmd="cp -p --no-preserve=ownership" ;; + esac +fi +cp_p() { + $cp_cmd "${@}" || test_fail "$cp_cmd failed" +} + +check_perms() { + perms=`"$TOOLDIR/tls" "$1" | sed 's/^[-d]\(.........\).*/\1/'` + if test $perms = $2; then + return 0 + fi + echo "permissions: $perms on $1" + echo "should be: $2" + test_fail "failed test $3" +} + +rsync_getgroups() { + "$TOOLDIR/getgroups" +} + + +#################### +# Build test directories $todir and $fromdir, with $fromdir full of files. + +hands_setup() { + # Clean before creation + rm -rf "$fromdir" + rm -rf "$todir" + + [ -d "$tmpdir" ] || mkdir "$tmpdir" + [ -d "$fromdir" ] || mkdir "$fromdir" + [ -d "$todir" ] || mkdir "$todir" + + # On some BSD systems, the umask affects the mode of created + # symlinks, even though the mode apparently has no effect on how + # the links behave in the future, and it cannot be changed using + # chmod! rsync always sets its umask to 000 so that it can + # accurately recreate permissions, but this script is probably run + # with a different umask. + + # This causes a little problem that "ls -l" of the two will not be + # the same. So, we need to set our umask before doing any creations. + + # set up test data + touch "$fromdir/empty" + mkdir "$fromdir/emptydir" + + # a hundred lines of text or so + rsync_ls_lR "$srcdir" > "$fromdir/filelist" + + echo $ECHO_N "This file has no trailing lf$ECHO_C" > "$fromdir/nolf" + umask 0 + ln -s nolf "$fromdir/nolf-symlink" + umask 022 + + cat "$srcdir"/*.c > "$fromdir/text" + mkdir "$fromdir/dir" + cp "$fromdir/text" "$fromdir/dir" + mkdir "$fromdir/dir/subdir" + echo some data > "$fromdir/dir/subdir/foobar.baz" + mkdir "$fromdir/dir/subdir/subsubdir" + if [ -r /etc ]; then + ls -ltr /etc > "$fromdir/dir/subdir/subsubdir/etc-ltr-list" + else + ls -ltr / > "$fromdir/dir/subdir/subsubdir/etc-ltr-list" + fi + mkdir "$fromdir/dir/subdir/subsubdir2" + if [ -r /bin ]; then + ls -lt /bin > "$fromdir/dir/subdir/subsubdir2/bin-lt-list" + else + ls -lt / > "$fromdir/dir/subdir/subsubdir2/bin-lt-list" + fi + +# echo testing head: +# ls -lR "$srcdir" | head -10 || echo failed +} + + +#################### +# Many machines do not have "mkdir -p", so we have to build up long paths. +# How boring. +makepath() { + for p in "${@}"; do + (echo " makepath $p" + + # Absolute Unix path. + if echo $p | grep '^/' >/dev/null; then + cd / + fi + + # This will break if $p contains a space. + for c in `echo $p | tr '/' ' '`; do + if [ -d "$c" ] || mkdir "$c"; then + cd "$c" || return $? + else + echo "failed to create $c" >&2; return $? + fi + done) + done +} + + +########################### +# Run a test (in '$1') then compare directories $2 and $3 to see if +# there are any difference. If there are, explain them. + +# So normally basically $1 should be an rsync command, and $2 and $3 +# the source and destination directories. This is only good when you +# expect to transfer the whole directory exactly as is. If some files +# should be excluded, you might need to use something else. + +checkit() { + failed= + + # We can just write everything to stdout/stderr, because the + # wrapper hides it unless there is a problem. + + case "x$TLS_ARGS" in + *--atimes*) + ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" + ;; + *) + ;; + esac + + echo "Running: \"$1\"" + eval "$1" + status=$? + if [ $status != 0 ]; then + failed="$failed status=$status" + fi + + case "x$TLS_ARGS" in + *--atimes*) + ;; + *) + ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" + ;; + esac + + echo "-------------" + echo "check how the directory listings compare with diff:" + echo "" + ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to" + diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed="$failed dir-diff" + + echo "-------------" + echo "check how the files compare with diff:" + echo "" + if [ "x$4" != x ]; then + echo " === Skipping (as directed) ===" + else + diff -r $diffopt "$2" "$3" || failed="$failed file-diff" + fi + + echo "-------------" + if [ -z "$failed" ]; then + return 0 + fi + + echo "Failed: $failed" + return 1 +} + + +# Run a test in $1 and make sure it has a zero exit status. Capture the +# output into $outfile and echo it to stdout. +checktee() { + echo "Running: \"$1\"" + eval "$1" >"$outfile" + status=$? + cat "$outfile" + if [ $status != 0 ]; then + echo "Failed: status=$status" + return 1 + fi + return 0 +} + + +# Slurp stdin into $chkfile and then call checkdiff2(). +checkdiff() { + cat >"$chkfile" # Save off stdin + checkdiff2 "${@}" +} + + +# Run a test in $1 and make sure it has a zero exit status. Capture the output +# into $outfile. If $2 is set, use it to filter the outfile. If resulting +# outfile differs from the chkfile data, fail with an error. +checkdiff2() { + failed= + + echo "Running: \"$1\"" + eval "$1" >"$outfile" + status=$? + cat "$outfile" + if [ $status != 0 ]; then + failed="$failed status=$status" + fi + + if [ -n "$2" ]; then + eval "cat '$outfile' | $2 >'$outfile.new'" + mv "$outfile.new" "$outfile" + fi + + diff $diffopt "$chkfile" "$outfile" || failed="$failed output differs" + + if [ -n "$failed" ]; then + echo "Failed:$failed" + return 1 + fi + return 0 +} + + +build_rsyncd_conf() { + # Build an appropriate configuration file + conf="$scratchdir/test-rsyncd.conf" + echo "building configuration $conf" + + port=2612 + pidfile="$scratchdir/rsyncd.pid" + logfile="$scratchdir/rsyncd.log" + hostname=`uname -n` + + my_uid=`get_testuid` + root_uid=`get_rootuid` + root_gid=`get_rootgid` + + uid_setting="uid = $root_uid" + gid_setting="gid = $root_gid" + + if test x"$my_uid" != x"$root_uid"; then + # Non-root cannot specify uid & gid settings + uid_setting="#$uid_setting" + gid_setting="#$gid_setting" + fi + + cat >"$conf" <"$ignore23" <<'EOT' +if "${@}"; then + exit +fi + +ret=$? + +if test $ret = 23; then + exit +fi + +exit $ret +EOT +chmod +x "$ignore23" +} + + +build_symlinks() { + mkdir "$fromdir" + date >"$fromdir/referent" + ln -s referent "$fromdir/relative" + ln -s "$fromdir/referent" "$fromdir/absolute" + ln -s nonexistent "$fromdir/dangling" + ln -s "$srcdir/rsync.c" "$fromdir/unsafe" +} + +test_fail() { + echo "$@" >&2 + exit 1 +} + +test_skipped() { + echo "$@" >&2 + echo "$@" > "$tmpdir/whyskipped" + exit 77 +} + +# It failed, but we expected that. Don't dump out error logs, +# because most users won't want to see them. But do leave +# the working directory around. +test_xfail() { + echo "$@" >&2 + exit 78 +} + +# Determine what shell command will appropriately test for links. +ln -s foo "$scratchdir/testlink" +for cmd in test /bin/test /usr/bin/test /usr/ucb/bin/test /usr/ucb/test; do + for switch in -h -L; do + if $cmd $switch "$scratchdir/testlink" 2>/dev/null; then + # how nice + TEST_SYMLINK_CMD="$cmd $switch" + # i wonder if break 2 is portable? + break 2 + fi + done +done +# ok, now get rid of it +rm "$scratchdir/testlink" + + +if [ "x$TEST_SYMLINK_CMD" = 'x' ]; then + test_fail "Couldn't determine how to test for symlinks" +else + echo "Testing for symlinks using '$TEST_SYMLINK_CMD'" +fi + + +# Test whether something is a link, allowing for shell peculiarities +is_a_link() { + # note the variable contains the first option and therefore is not quoted + $TEST_SYMLINK_CMD "$1" +} + + +# We need to set the umask to be reproducible. Note also that when we +# do some daemon tests as root, we will setuid() and therefore the +# directory has to be writable by the nobody user in some cases. The +# best thing is probably to explicitly chmod those directories after +# creation. + +umask 022 diff --git a/testsuite/ssh-basic.test b/testsuite/ssh-basic.test new file mode 100644 index 0000000..1559ca2 --- /dev/null +++ b/testsuite/ssh-basic.test @@ -0,0 +1,34 @@ +#!/bin/sh + +# Copyright (C) 1998,1999 Philip Hands +# Copyright (C) 2001 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING) + +# This script tests ssh, if possible. It's called by runtests.sh + +. "$suitedir/rsync.fns" + +SSH="$scratchdir/src/support/lsh.sh" + +if test x"$rsync_enable_ssh_tests" = xyes; then + if type ssh >/dev/null; then + SSH=ssh + fi +fi + +if [ "`$SSH -o'BatchMode yes' localhost echo yes`" != "yes" ]; then + test_skipped "Skipping SSH tests because ssh connection to localhost not authorised" +fi + +echo "Using remote shell: $SSH" + +# Create some files for rsync to copy +hands_setup + +runtest "ssh: basic test" 'checkit "$RSYNC -avH -e \"$SSH\" --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' + +mv "$todir/text" "$todir/ThisShouldGo" + +runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e \"$SSH\" --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' diff --git a/testsuite/symlink-ignore.test b/testsuite/symlink-ignore.test new file mode 100644 index 0000000..7055a92 --- /dev/null +++ b/testsuite/symlink-ignore.test @@ -0,0 +1,34 @@ +#!/bin/sh + +# Copyright (C) 2001 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test rsync's somewhat over-featured symlink control: the default +# behaviour is that symlinks should not be copied at all. + +. "$suitedir/rsync.fns" + +build_symlinks || test_fail "failed to build symlinks" + +# Copy recursively, but without -l or -L or -a, and all the symlinks +# should be missing. +$RSYNC -r "$fromdir/" "$todir" || test_fail "$RSYNC returned $?" + +[ -f "$todir/referent" ] || test_fail "referent was not copied" +[ -d "$todir/from" ] && test_fail "extra level of directories" +if is_a_link "$todir/dangling"; then + test_fail "dangling symlink was copied" +fi + +if is_a_link "$todir/relative"; then + test_fail "relative symlink was copied" +fi + +if is_a_link "$todir/absolute"; then + test_fail "absolute symlink was copied" +fi + +# The script would have aborted on error, so getting here means we've won. +exit 0 diff --git a/testsuite/trimslash.test b/testsuite/trimslash.test new file mode 100644 index 0000000..2efaa07 --- /dev/null +++ b/testsuite/trimslash.test @@ -0,0 +1,26 @@ +#!/bin/sh + +# Copyright (C) 2002 by Martin Pool + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test tiny function to trim trailing slashes. + +. "$suitedir/rsync.fns" + +"$TOOLDIR/trimslash" "/usr/local/bin" "/usr/local/bin/" "/usr/local/bin///" \ + "//a//" "////" \ + "/Users/Weird Macintosh Name/// Ooh, translucent plastic/" \ + > "$scratchdir/slash.out" +diff $diffopt "$scratchdir/slash.out" - < + +. "$suitedir/rsync.fns" + +test_symlink() { + is_a_link "$1" || test_fail "File $1 is not a symlink" +} + +test_regular() { + if [ ! -f "$1" ]; then + test_fail "File $1 is not regular file or not exists" + fi +} + +cd "$tmpdir" + +mkdir from + +mkdir "from/safe" +mkdir "from/unsafe" + +mkdir "from/safe/files" +mkdir "from/safe/links" + +touch "from/safe/files/file1" +touch "from/safe/files/file2" +touch "from/unsafe/unsafefile" + +ln -s ../files/file1 "from/safe/links/" +ln -s ../files/file2 "from/safe/links/" +ln -s ../../unsafe/unsafefile "from/safe/links/" + +echo "rsync with relative path and just -a" +$RSYNC -avv from/safe/ to +test_symlink to/links/file1 +test_symlink to/links/file2 +test_symlink to/links/unsafefile + +echo "rsync with relative path and -a --copy-links" +$RSYNC -avv --copy-links from/safe/ to +test_regular to/links/file1 +test_regular to/links/file2 +test_regular to/links/unsafefile + +echo "rsync with relative path and --copy-unsafe-links" +$RSYNC -avv --copy-unsafe-links from/safe/ to +test_symlink to/links/file1 +test_symlink to/links/file2 +test_regular to/links/unsafefile + +rm -rf to +echo "rsync with relative2 path" +(cd from; $RSYNC -avv --copy-unsafe-links safe/ ../to) +test_symlink to/links/file1 +test_symlink to/links/file2 +test_regular to/links/unsafefile + +rm -rf to +echo "rsync with absolute path" +$RSYNC -avv --copy-unsafe-links `pwd`/from/safe/ to +test_symlink to/links/file1 +test_symlink to/links/file2 +test_regular to/links/unsafefile diff --git a/testsuite/wildmatch.test b/testsuite/wildmatch.test new file mode 100644 index 0000000..cfe7584 --- /dev/null +++ b/testsuite/wildmatch.test @@ -0,0 +1,23 @@ +#!/bin/sh + +# Copyright (C) 2003-2022 Wayne Davison + +# This program is distributable under the terms of the GNU GPL (see +# COPYING). + +# Test the wildmatch functionality + +. "$suitedir/rsync.fns" + +# This test exercises the wildmatch() function (with no options) and the +# wildmatch_join() function (using -x and/or -e). +for opts in "" -x1 "-x1 -e1" "-x1 -e1se" -x2 "-x2 -ese" -x3 "-x3 -e1" -x4 "-x4 -e2e" -x5 "-x5 -es"; do + echo Running wildtest with "$opts" + "$TOOLDIR/wildtest" $opts "$srcdir/wildtest.txt" >"$scratchdir/wild.out" + diff $diffopt "$scratchdir/wild.out" - </dev/null || test_skipped "Rsync is configured without xattr support" + +case "$HOST_OS" in +darwin*) + xset() { + xnam="$1" + xval="$2" + shift 2 + xattr -s "$xnam" "$xval" "${@}" + } + xls() { + xattr -l "${@}" | sed "s/^[ $tab_ch]*//" + } + RSYNC_PREFIX='rsync' + RUSR='rsync.nonuser' + ;; +solaris*) + xset() { + xnam="$1" + xval="$2" + shift 2 + for fn in "${@}"; do + runat "$fn" "$SHELL_PATH" < "${xnam}" +EOF + done + } + xls() { + for fn in "${@}"; do + runat "$fn" "$SHELL_PATH" <"$fromdir/file0" +echo something >"$fromdir/file1" +echo else >"$fromdir/file2" +echo deep >"$fromdir/foo/file3" +echo normal >"$fromdir/file4" +echo deeper >"$fromdir/foo/bar/file5" + +makepath "$chkdir/foo" +echo wow >"$chkdir/file1" +cp_touch "$fromdir/foo/file3" "$chkdir/foo" + +dirs='foo foo/bar' +files='file0 file1 file2 foo/file3 file4 foo/bar/file5' + +uid_gid=`"$TOOLDIR/tls" "$fromdir/foo" | sed 's/^.* \([0-9][0-9]*\)\.\([0-9][0-9]*\) .*/\1:\2/'` + +cd "$fromdir" + +xset user.foo foo file0 2>/dev/null || test_skipped "Unable to set an xattr" +xset user.bar bar file0 + +xset user.short 'this is short' file1 +xset user.long 'this is a long attribute that will be truncated in the initial data send' file1 +xset user.good 'this is good' file1 +xset user.nice 'this is nice' file1 + +xset user.foo foo file2 +xset user.bar bar file2 +xset user.long 'a long attribute for our new file that tests to ensure that this works' file2 + +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" + +XFILT='-f-x_system.* -f-x_security.*' + +# OK, let's try a simple xattr copy. +checkit "$RSYNC -avX $XFILT $dashH --super . '$chkdir/'" "$fromdir" "$chkdir" + +cd "$chkdir" +xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - + +cd "$fromdir" + +if [ -n "$dashH" ]; then + for fn in $files; do + name=`basename $fn` + ln $fn ../lnk/$name + done +fi + +checkit "$RSYNC -aiX $XFILT $dashH --super $altDest=../chk . ../to" "$fromdir" "$todir" + +cd "$todir" +xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - + +[ -n "$dashH" ] && rm -rf "$lnkdir" + +cd "$fromdir" +rm -rf "$todir" + +xset user.nice 'this is nice, but different' file1 + +xls $dirs $files >"$scratchdir/xattrs.txt" + +checkit "$RSYNC -aiX $XFILT $dashH --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir" + +cd "$todir" +xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - + +sed -n -e '/^[^d ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff-all" +grep -F -v './file1' "$scratchdir/ls-diff-all" >"$scratchdir/ls-diff" || : +if [ -s "$scratchdir/ls-diff" ]; then + echo "Missing hard links on:" + cat "$scratchdir/ls-diff" + exit 1 +fi +if [ ! -s "$scratchdir/ls-diff-all" ]; then + echo "Too many hard links on file1!" + exit 1 +fi + +cd "$chkdir" +chmod go-rwx . $dirs $files + +xset user.nice 'this is nice, but different' file1 +xset $RSYNC_PREFIX.%stat "40000 0,0 $uid_gid" $dirs +xset $RSYNC_PREFIX.%stat "100000 0,0 $uid_gid" $files + +xls $dirs $files >"$scratchdir/xattrs.txt" + +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 $XFILT $dashH --fake-super --chmod=a= . ../to" "$chkdir" "$todir" # 2>"$scratchdir/errors.txt" + +cd "$todir" +xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - + +cd "$fromdir" +rm -rf "$todir" "$chkdir" + +$RSYNC -aX file1 file2 +$RSYNC -aX file1 file2 ../chk/ +$RSYNC -aX --del ../chk/ . +$RSYNC -aX file1 ../lnk/ +[ -n "$dashH" ] && ln "$chkdir/file1" ../lnk/extra-link + +xls file1 file2 >"$scratchdir/xattrs.txt" + +checkit "$RSYNC -aiiX $XFILT $dashH $altDest=../lnk . ../to" "$chkdir" "$todir" + +[ -n "$dashH" ] && rm ../lnk/extra-link + +cd "$todir" +xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" - + +cd "$fromdir" +rm "$todir/file2" + +echo extra >file1 +$RSYNC -aX . ../chk/ + +checkit "$RSYNC -aiiX $XFILT . ../to" "$chkdir" "$todir" + +cd "$todir" +xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" - + +# The script would have aborted on error, so getting here means we've won. +exit 0 -- cgit v1.2.3