1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

util: make symlink() work on older Windows versions

This commit is contained in:
Bert Belder 2018-07-31 11:19:53 +02:00
parent e5b7d31aba
commit 788b0795de
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461

View file

@ -53,21 +53,38 @@ def remove_and_symlink(target, name, target_is_dir=False):
def symlink(target, name, target_is_dir=False): def symlink(target, name, target_is_dir=False):
if os.name == "nt": if os.name == "nt":
import ctypes from ctypes import WinDLL, WinError, GetLastError
CreateSymbolicLinkW = ctypes.windll.kernel32.CreateSymbolicLinkW from ctypes.wintypes import BOOLEAN, DWORD, LPCWSTR
CreateSymbolicLinkW.restype = ctypes.c_ubyte
CreateSymbolicLinkW.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p,
ctypes.c_uint32)
# Replace forward slashes by backward slashes. kernel32 = WinDLL('kernel32', use_last_error=False)
# Strangely it seems that this is only necessary for symlinks to files. CreateSymbolicLinkW = kernel32.CreateSymbolicLinkW
# Forward slashes don't cause any issues when the target is a directory. CreateSymbolicLinkW.restype = BOOLEAN
target = target.replace("/", "\\") CreateSymbolicLinkW.argtypes = (LPCWSTR, LPCWSTR, DWORD)
flags = 0x02 # SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
if (target_is_dir): # File-type symlinks can only use backslashes as separators.
flags |= 0x01 # SYMBOLIC_LINK_FLAG_DIRECTORY target = os.path.normpath(target)
if not CreateSymbolicLinkW(name, target, flags):
raise ctypes.WinError() # If the symlink points at a directory, it needs to have the appropriate
# flag set, otherwise the link will be created but it won't work.
if target_is_dir:
type_flag = 0x01 # SYMBOLIC_LINK_FLAG_DIRECTORY
else:
type_flag = 0
# Before Windows 10, creating symlinks requires admin privileges.
# As of Win 10, there is a flag that allows anyone to create them.
# Initially, try to use this flag.
unpriv_flag = 0x02 # SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
r = CreateSymbolicLinkW(name, target, type_flag | unpriv_flag)
# If it failed with ERROR_INVALID_PARAMETER, try again without the
# 'allow unprivileged create' flag.
if not r and GetLastError() == 87: # ERROR_INVALID_PARAMETER
r = CreateSymbolicLinkW(name, target, type_flag)
# Throw if unsuccessful even after the second attempt.
if not r:
raise WinError()
else: else:
os.symlink(target, name) os.symlink(target, name)