Why is the first rsync command working perfectly creating a clone of /tmp/data to /tmp/bak using hardlinks but the second creates a clone by copying bytes instead of hardlinking?

rsync -a    --link-dest=/tmp/data  /tmp/data/  /tmp/bak/ # HARDLINKS
rsync -a -R --link-dest=/tmp/data  /tmp/data/  /tmp/bak/ # REGULAR COPIES

Steps to test/reproduce

cd /tmp/
rm -rf data bak                                                                                                                     
mkdir data bak 
echo foo > data/foo 
stat /tmp/data/foo | grep Inode
rsync -a    --link-dest=/tmp/data  /tmp/data/  /tmp/bak/
stat /tmp/bak/foo  | grep Inode                        
### Note that the inode is the same as above.

rm bak/*                       
rsync -a -R --link-dest=/tmp/data  /tmp/data/   /tmp/bak/
stat /tmp/bak/tmp/data/foo | grep Inode      
### Note that the inode is different.


When using the -R (--relative) flag, all paths become prefixed with the source path, including any --link-dest path.

Working this through with your example,

rsync -a -R --link-dest=/tmp/data /tmp/data/ /tmp/bak/

what this means is that the link-dest path becomes /tmp/data/tmp/data. (You can see this more clearly with cp -al /tmp/data /tmp/link and using strace -f rsync ... --link-dest=/tmp/link.)

The solution in this instance is to use --link-dest=/ so that the generated starting point becomes your desired --link-dest=/tmp/data

rsync -a -R --link-dest=/ /tmp/data/ /tmp/bak/
stat /tmp/bak/tmp/data/foo | grep Inode    # Same inode as source, with Links: 2
  • Good one. you can also add that : In case you work with rsync -a -R /tmp/./data/ /tmp/bak/ then the option should be until the . is: --link-dest=/tmp. – jayooin Jan 25 at 6:24
  • Thanks for the good explanation @roaima. It's a pity that rsync -vvvvvv has no hints at all about what is happening. – ndemou Jan 25 at 13:59
  • 1
    I only caught it when I changed the --link-dest source from /tmp/data to /tmp/link (as briefly described in the question), and ran strace -f rsync ... looking for (f)stat or open calls involving that alternate path. – roaima Jan 25 at 14:01

That's an interesting question.

When you use rsync -R, it will copy the tmp/data into the destination directory.

The thing is, that when rsync will copy, it will first check if the file exists in the directory given by the --link-dest:

Meaning, it will compare /tmp/bak/* with /tmp/data/*.

The problem is that, when you launch rsync -R command, the foo file will not be in a place that can be compared with /tmp/data/ to do the link, it will be in /tmp/bak/tmp/data/foo, while rsync, stupidely, would only do hardlink for it if it is a the root of the directories given (in that example, /tmp/data and /tmp/bak).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.