Windows: Add support for creating symlinks as an unprivileged user
See https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/
for announcement of new flag.
This change follow the same pattern as what was done in "go":
https://github.com/golang/go/pull/24307/files#diff-b87bc12e4da2497308f9ef746086e4f0
Change-Id: If1e99fefdd3f787598e695731019c34b9bfcd1c2
diff --git a/platform_utils_win32.py b/platform_utils_win32.py
index fe76b3d..a643121 100644
--- a/platform_utils_win32.py
+++ b/platform_utils_win32.py
@@ -41,6 +41,8 @@
# Symbolic link creation flags
SYMBOLIC_LINK_FLAG_FILE = 0x00
SYMBOLIC_LINK_FLAG_DIRECTORY = 0x01
+# symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972)
+SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x02
GetFileAttributesW = kernel32.GetFileAttributesW
GetFileAttributesW.restype = DWORD
@@ -147,15 +149,21 @@
# On success, the function returns "1".
# On error, the function returns some random value (e.g. 1280).
# The best bet seems to use "GetLastError" and check for error/success.
- CreateSymbolicLinkW(link_name, source, dwFlags)
+ CreateSymbolicLinkW(link_name, source, dwFlags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
code = get_last_error()
if code != ERROR_SUCCESS:
- error_desc = FormatError(code).strip()
- if code == ERROR_PRIVILEGE_NOT_HELD:
- raise OSError(errno.EPERM, error_desc, link_name)
- _raise_winerror(
- code,
- 'Error creating symbolic link \"%s\"'.format(link_name))
+ # See https://github.com/golang/go/pull/24307/files#diff-b87bc12e4da2497308f9ef746086e4f0
+ # "the unprivileged create flag is unsupported below Windows 10 (1703, v10.0.14972).
+ # retry without it."
+ CreateSymbolicLinkW(link_name, source, dwFlags)
+ code = get_last_error()
+ if code != ERROR_SUCCESS:
+ error_desc = FormatError(code).strip()
+ if code == ERROR_PRIVILEGE_NOT_HELD:
+ raise OSError(errno.EPERM, error_desc, link_name)
+ _raise_winerror(
+ code,
+ 'Error creating symbolic link \"%s\"'.format(link_name))
def islink(path):