Add full support for Windows symlinks
I wanted to use KWSys to help port a Linux application to Windows, and was dismayed to find out that while it had nice symlink wrapper calls, it lacked support for using symlinks on Windows. Only one thing to do: add in that support!
This MR adds full support for NTFS symlinks to SystemTools::FileIsSymlink
, SystemTools::CreateSymlink
, and SystemTools::ReadSymlink
, so that these functions can create and read symlinks exactly like they do on Linux. To do this, I used the strategies Raymond Chen outlined in his post here.
-
FileIsSymlink
attempted to support symlinks previously, but was somewhat broken as it would just check if the file was a reparse point, not specifically a symlink. This means it would return false positives for other types of reparse points, such as WSL files with extra attributes. I have now amended it to actually check that the file is a symlink reparse point. -
CreateSymlink
is very straightforward and just calls through to Windows'CreateSymbolicLinkW()
. -
ReadSymlink
was a bit trickier because Windows lacks a native readlink function. Instead, I used Raymond Chen's strategy of opening the file and then usingGetFinalPathNameByHandleW
to find its location. - Note: all functions support long paths and UTF-8 unicode characters
One tricky thing about this change is that it uses functions and constants introduced in fairly recent versions of Windows. To get access to these, I just added the _WIN32_WINNT
define at the top, and hopefully that will work fine. However, I don't have access to computers running older versions of Windows, so hopefully your CI servers can establish whether it works or not. If not, we might have to introduce some extra logic into CMakeLists.txt to check the Windows SDK version and disable things accordingly.
Also, I have no idea why, but Microsoft decided to restrict symlink creation to administrator users only unless people enable Developer Mode in Windows Settings (see here). I added a warning about it in the source code but I'm not sure if there's somewhere else we should note that so users of KWSys would notice the requirement. I thought about just having it print an error, but I wasn't able to find any programmatic way of detecting whether developer mode is enabled.