How does Robocopy handle file system links (symbolic links, hard links and junctions)?

Is it safe to delete a Robocopy backup? I have read that some people accidentally deleted files outside of the backup because it contained links/junctions. Can I prevent this?


Solution 1:

The Robocopy docs lists options that control Robocopy's behavior regarding file system links:

/sl Don't follow symbolic links and instead create a copy of the link.
/xj Excludes junction points, which are normally included by default.
/xjd Excludes junction points for directories.
/xjf Excludes junction points for files.

I have created a batch script to find out how Robocopy works with and without these options. It uses mlink. With mlink, you can create:

  • Symbolic links to files and directories.
  • Hard links to files. Trying to create a hard link to a directory results in an error.
  • Junctions, which are links to directories. Trying to create a junction to a file will succeed, but the junction will be broken.

Symbolic links can be relative or absolute, depending on how you pass the target parameter. Hard links and junctions are always absolute, even if you pass a relative target.

@echo off
set home=C:\my-directory
cd %home%
mkdir robocopy-source
cd robocopy-source
mkdir a
mkdir b
copy NUL b\foo.txt
cd a
mklink /j junction-dir-absolute %home%\robocopy-source\b\
mklink /d symlink-dir-absolute %home%\robocopy-source\b\
mklink /d symlink-dir-relative ..\b\
mklink /h hardlink-file-absolute %home%\robocopy-source\b\foo.txt
mklink symlink-file-absolute %home%\robocopy-source\b\foo.txt
mklink symlink-file-relative ..\b\foo.txt
cd %home%
robocopy robocopy-source robocopy-target /mir /dcopy:dat
robocopy robocopy-source robocopy-target-sl /mir /dcopy:dat /sl
robocopy robocopy-source robocopy-target-xj /mir /dcopy:dat /xj
robocopy robocopy-source robocopy-target-xjd /mir /dcopy:dat /xjd
robocopy robocopy-source robocopy-target-xjf /mir /dcopy:dat /xjf

Using the Link Shell Extension, we can now see what has happened:

Path Info
robocopy-source\a\junction-dir-absolute Links to %home%\robocopy-source\b\
robocopy-source\a\symlink-dir-absolute Links to %home%\robocopy-source\b\
robocopy-source\a\symlink-dir-relative Links to ..\b\
robocopy-source\a\hardlink-file-absolute Links to %home%\robocopy-source\b\foo.txt (and itself)
robocopy-source\a\symlink-file-absolute Links to C:\Users\Marco\Desktop\Linktest\robocopy-source\b\foo.txt
robocopy-source\a\symlink-file-relative Links to ..\b\foo.txt
robocopy-target\a\junction-dir-absolute Directory with copied content of %home%\robocopy-source\b\
robocopy-target\a\symlink-dir-absolute Directory with copied content of %home%\robocopy-source\b\
robocopy-target\a\symlink-dir-relative Directory with copied content of %home%\robocopy-source\b\
robocopy-target\a\hardlink-file-absolute Empty file
robocopy-target\a\symlink-file-absolute Empty file
robocopy-target\a\symlink-file-relative Empty file
robocopy-target-sl\a\junction-dir-absolute Directory with copied content of %home%\robocopy-source\b\
robocopy-target-sl\a\symlink-dir-absolute Links to %home%\robocopy-source\b\
robocopy-target-sl\a\symlink-dir-relative Link to ..\b\
robocopy-target-sl\a\hardlink-file-absolute Empty file
robocopy-target-sl\a\symlink-file-absolute Links to %home%\robocopy-source\b\foo.txt
robocopy-target-sl\a\symlink-file-relative Links to ..\b\foo.txt
robocopy-target-xj\a\junction-dir-absolute Does not exist
robocopy-target-xj\a\symlink-dir-absolute Does not exist
robocopy-target-xj\a\symlink-dir-relative Does not exist
robocopy-target-xj\a\hardlink-file-absolute Empty file
robocopy-target-xj\a\symlink-file-absolute Does not exist
robocopy-target-xj\a\symlink-file-relative Does not exist
robocopy-target-xjd\a\junction-dir-absolute Does not exist
robocopy-target-xjd\a\symlink-dir-absolute Does not exist
robocopy-target-xjd\a\symlink-dir-relative Does not exist
robocopy-target-xjd\a\hardlink-file-absolute Empty file
robocopy-target-xjd\a\symlink-file-absolute Empty file
robocopy-target-xjd\a\symlink-file-relative Empty file
robocopy-target-xjf\a\junction-dir-absolute Directory with copied content of %home%\robocopy-source\b\
robocopy-target-xjf\a\symlink-dir-absolute Directory with copied content of %home%\robocopy-source\b\
robocopy-target-xjf\a\symlink-dir-relative Directory with copied content of %home%\robocopy-source\b\
robocopy-target-xjf\a\hardlink-file-absolute Empty file
robocopy-target-xjf\a\symlink-file-absolute Does not exist
robocopy-target-xjf\a\symlink-file-relative Does not exist

I conclude that unless you have used the /sl option, deleting a backup created with Robocopy should be safe. If you did use the /sl option however, absolute symbolic links could get you into trouble, e.g. when using the del command.

Further observations:

  • A hard link always yields an empty file.
  • Option /xjd skips links to directories. Other than the docs imply, it does not only skip junctions, but also symbolic links!
  • Option /xjf skips links to files. Other than the docs imply, it does not skip junctions for files (which do not exist anyway), but symbolic links!
  • Option /xj combines /xjd and /xjf.

I have reported the issue with the docs.

Bonus info regarding shortcuts (.lnk files)

Shortcuts are treated by Robocopy like regular files, so they will generally point outside of your backup directory. However, they are usually treated like regular files by other command line programs, too. I have checked this for del /s /q and rmdir /s /q in the command prompt and rm -rf in the MINGW64 shell, all of which will not follow the shortcuts and thus will not lead to unintended deletions.