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:
parent
e5b7d31aba
commit
788b0795de
1 changed files with 31 additions and 14 deletions
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue