Skip to content

Commit 2b6c9d6

Browse files
kbleesdscho
authored andcommitted
Win32: implement basic symlink() functionality (file symlinks only)
Implement symlink() that always creates file symlinks. Fails with ENOSYS if symlinks are disabled or unsupported. Note: CreateSymbolicLinkW() was introduced with symlink support in Windows Vista. For compatibility with Windows XP, we need to load it dynamically and fail gracefully if it isnt's available. Signed-off-by: Karsten Blees <[email protected]>
1 parent 7530275 commit 2b6c9d6

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

compat/mingw.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ static int retry_ask_yes_no(int *tries, const char *format, ...)
230230
return result;
231231
}
232232

233+
234+
DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateSymbolicLinkW, LPCWSTR, LPCWSTR, DWORD);
235+
233236
/* Normalizes NT paths as returned by some low-level APIs. */
234237
static wchar_t *normalize_ntpath(wchar_t *wbuf)
235238
{
@@ -2079,6 +2082,34 @@ int link(const char *oldpath, const char *newpath)
20792082
return 0;
20802083
}
20812084

2085+
int symlink(const char *target, const char *link)
2086+
{
2087+
wchar_t wtarget[MAX_LONG_PATH], wlink[MAX_LONG_PATH];
2088+
int len;
2089+
2090+
/* fail if symlinks are disabled or API is not supported (WinXP) */
2091+
if (!has_symlinks || !INIT_PROC_ADDR(CreateSymbolicLinkW)) {
2092+
errno = ENOSYS;
2093+
return -1;
2094+
}
2095+
2096+
if ((len = xutftowcs_long_path(wtarget, target)) < 0
2097+
|| xutftowcs_long_path(wlink, link) < 0)
2098+
return -1;
2099+
2100+
/* convert target dir separators to backslashes */
2101+
while (len--)
2102+
if (wtarget[len] == '/')
2103+
wtarget[len] = '\\';
2104+
2105+
/* create file symlink */
2106+
if (!CreateSymbolicLinkW(wlink, wtarget, 0)) {
2107+
errno = err_win_to_posix(GetLastError());
2108+
return -1;
2109+
}
2110+
return 0;
2111+
}
2112+
20822113
#ifndef _WINNT_H
20832114
/*
20842115
* The REPARSE_DATA_BUFFER structure is defined in the Windows DDK (in

compat/mingw.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,6 @@ struct utsname {
110110
* trivial stubs
111111
*/
112112

113-
static inline int symlink(const char *oldpath, const char *newpath)
114-
{ errno = ENOSYS; return -1; }
115113
static inline int fchmod(int fildes, mode_t mode)
116114
{ errno = ENOSYS; return -1; }
117115
#ifndef __MINGW64_VERSION_MAJOR
@@ -203,6 +201,7 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out);
203201
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
204202
int link(const char *oldpath, const char *newpath);
205203
int uname(struct utsname *buf);
204+
int symlink(const char *target, const char *link);
206205
int readlink(const char *path, char *buf, size_t bufsiz);
207206

208207
/*

0 commit comments

Comments
 (0)