The Samba-Bugzilla – Bug 11726
rsync fails to copy directory containing ancestor symlink with --copy-links
Last modified: 2016-02-11 16:06:49 UTC
If you have a directory created like so:
% mkdir -p from/dir/
% ln -s .. from/dir/loop
% rsync -a --copy-links from to
rsync: readlink_stat("/tmp/from/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop/dir/loop") failed: Too many levels of symbolic links (40)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1178) [sender=3.1.2]
For a trivial case of infinitely recursive symlinks (in other words when you go through a symlink that takes you to an ancestor), rsync should just declare "that's as far as we need to go here".
I'm working on writing a patch for this (although this is my first time looking at the rsync codebase, so it might take a while). I'll ping this thread if I'm unable to write one.
It turns out that this issue also happens even when you don't use --copy-link (albeit a different error):
% rsync -a from to
cannot delete non-empty directory: from/dir/loop
could not make way for new symlink: from/dir/loop
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1178) [sender=3.1.3dev]
Yes, if you tell rsync to copy the symlinks it does it. If you have one or more looping symlinks then you need to exclude them from the copy or not use --copy-links. As for the other error, you need to use --delete or --force to copy over a non-empty directory, as mentioned in the man page.
(In reply to Wayne Davison from comment #3)
> Yes, if you tell rsync to copy the symlinks it does it. If you have one or more looping symlinks then you need to exclude them from the copy or not use --copy-links.
That's just patently ridiculous. cp -r doesn't fail when you ask it to copy a directory that has symlink loops because "that's what you asked me to do". It literally just takes doing some fairly trivial checks before adding extra files to file_list (i.e. does the path we're adding resolve to an ancestor of a path we've already seen?).
Keep in mind that "cp -r" doesn't dereference symlinks -- that takes their -L option (similar to rsync's --copy-links). If someone is copying a file tree and turning symlinks into real files/dirs, they should really know in advance what the symlinks are in order for the copy to be safe. Yes, we could stop looping with some additional checks. It might be worth it to at least not follow '.' and "..".