From 7587b56c10a4d11fe434e3eaa51212113f09ec10 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 12 Feb 2021 14:11:01 +0000 Subject: win32: implement symlink(2) Provide an implementation of symlink(2). Calls to symlink(2) will fail in default Windows installations unless running with elevated privileges. Failure to create a symlink when extracting files from an archive is therefore treated as a non-fatal error. There are two ways to permit the creation of symlinks: - Edit security policy to give users the 'Create symbolic links' privilege. Unfortunately this doesn't work for users who are an Administrator. - Enable developer mode, which is available in later versions of Windows 10. The ability to create symlinks is not available in Windows XP or ReactOS. --- win32/mingw.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'win32') diff --git a/win32/mingw.c b/win32/mingw.c index 41dba9857..a6362333d 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -1063,6 +1063,41 @@ int link(const char *oldpath, const char *newpath) return 0; } +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +# define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1) +#endif +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2) +#endif + +int symlink(const char *target, const char *linkpath) +{ + DWORD flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + struct stat st; + DECLARE_PROC_ADDR(BOOL, CreateSymbolicLinkA, LPCSTR, LPCSTR, DWORD); + + if (!INIT_PROC_ADDR(kernel32.dll, CreateSymbolicLinkA)) { + return -1; + } + + if (stat(target, &st) != -1 && S_ISDIR(st.st_mode)) + flag |= SYMBOLIC_LINK_FLAG_DIRECTORY; + + retry: + if (!CreateSymbolicLinkA(linkpath, target, flag)) { + /* Old Windows versions see 'UNPRIVILEGED_CREATE' as an invalid + * parameter. Retry without it. */ + if ((flag & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) && + GetLastError() == ERROR_INVALID_PARAMETER) { + flag &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + goto retry; + } + errno = err_win_to_posix(); + return -1; + } + return 0; +} + static char *normalize_ntpathA(char *buf) { /* fix absolute path prefixes */ -- cgit v1.2.3-55-g6feb