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.