I've put together a nightly backup script using rsync, which you can have if you want. It basically rsyncs a dir to a dir on the remote machine, where the remote dir's name is an ISO 8601 timestamp. Today I tried to enhance this system to get a file from the repository, and since I use symlinks in the pathnames in the repository, I hit what I consider to be bugs in rsync. The attached script demonstrates what I mean. Basically, if you try to rsync a/b . were a is a symlink, it doesn't work as expected given various combinations of -R, -l, and -L options. #!/bin/zsh # rsync problems with copying from a dir that includes a symlink in the path # 2005-02-27 Dave@Yost.com setupSource() { rm -rf source/dir source/symlink mkdir -p source/dir ln -s dir source/s ln -s referent source/dir/s echo nothing > source/dir/file } setupCorrectOutput() { rm -rf correct-output mkdir correct-output cd correct-output for x in ${opts[@]} do mkdir dest${x} case $x in *R*) mkdir -p dest${x}/s case $x in *L*) cp -p ../source/dir/file dest${x}/s/file cp -p ../source/dir/file dest${x}/s/symlink ;; *l*) cp -p ../source/dir/file dest${x}/s/file ln -s referent dest${x}/s/symlink ;; *) cp -p ../source/dir/file dest${x}/s/file ;; esac ;; *) case $x in *L*) cp -p ../source/dir/file dest${x}/file cp -p ../source/dir/file dest${x}/symlink ;; *l*) cp -p ../source/dir/file dest${x}/file ln -s referent dest${x}/symlink ;; *) cp -p ../source/dir/file dest${x}/file ;; esac ;; esac done cd .. } test() { opts=$1 file=$2 dest=output/dest${opts} rm -rf $dest mkdir -p $dest cd source echo '###' rsync $opts s/$file ../$dest rsync $opts s/$file ../$dest cd .. ls -ld $(find $dest) \ | sed 's,..........................................., ,' } opts=( -r -rl -rLL # hack for for case-insensitive file systems -rR -rRl -rRLL ) testGroup() { for x in ${opts[@]} test $x $1 } setupSource setupCorrectOutput rm -rf output mkdir output testGroup file testGroup symlink dodiff() { find correct-output -type $1 | sed 's,correct-output/,,' | sed "s,$, $1," >> $c find output -type $1 | sed 's,output/,,' | sed "s,$, $1," >> $a } c=/tmp/dyRsyncBug$$-$1-correct a=/tmp/dyRsyncBug$$-$1 dodiff f dodiff l sort $c > $c-sorted sort $a > $a-sorted echo '###' This diff should produce only lines starting with '=' echo '###' diff $1 correct vs actual /usr/bin/diff --old-line-format='< %l ' --unchanged-line-format='= %l ' --new-line-format='> %l ' $c-sorted $a-sorted
Use --no-implied-dirs to have the path components of an -R source treated as generic dirs.
(In reply to comment #1) Using --no-implied-dirs fixes only one of the six failures exhibited by the test script .
Everything else is caused by bugs in your test script. (e.g. overwriting the opts array with the opts scalar, removing the destination dir that holds the copied file when copying the symlink, creating a symlink named "s" in the source dir instead of "symlink", creating a symlink to a non-existant file named "referent" instead of the actual "file", etc.)
Created attachment 992 [details] same test script but with bug fixes (In reply to comment #3) Terribly sorry to bother you with my stupid bugs. I believe I've now fixed them all, and there is still a problem with -L. This fails: rsync -L --no-implied-dirs source/s/symlink . In other words, --no-implied-dirs appears to fix the -l case but not the -L case.
Created attachment 993 [details] corrected
Your script is creating a symlink to a non-existant file, which can't be copied with -L. If you change every instance of "referent" to "file", the script will work fine.
(In reply to comment #6) I will now go crawl into a hole.