Skip to content

Commit 687a1c1

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 8726c0c commit 687a1c1

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

compat/mingw.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ int mingw_core_config(const char *var, const char *value, void *cb)
270270
return 0;
271271
}
272272

273+
DECLARE_PROC_ADDR(kernel32.dll, BOOLEAN, CreateSymbolicLinkW, LPCWSTR, LPCWSTR, DWORD);
274+
273275
/* Normalizes NT paths as returned by some low-level APIs. */
274276
static wchar_t *normalize_ntpath(wchar_t *wbuf)
275277
{
@@ -2124,6 +2126,34 @@ int link(const char *oldpath, const char *newpath)
21242126
return 0;
21252127
}
21262128

2129+
int symlink(const char *target, const char *link)
2130+
{
2131+
wchar_t wtarget[MAX_LONG_PATH], wlink[MAX_LONG_PATH];
2132+
int len;
2133+
2134+
/* fail if symlinks are disabled or API is not supported (WinXP) */
2135+
if (!has_symlinks || !INIT_PROC_ADDR(CreateSymbolicLinkW)) {
2136+
errno = ENOSYS;
2137+
return -1;
2138+
}
2139+
2140+
if ((len = xutftowcs_long_path(wtarget, target)) < 0
2141+
|| xutftowcs_long_path(wlink, link) < 0)
2142+
return -1;
2143+
2144+
/* convert target dir separators to backslashes */
2145+
while (len--)
2146+
if (wtarget[len] == '/')
2147+
wtarget[len] = '\\';
2148+
2149+
/* create file symlink */
2150+
if (!CreateSymbolicLinkW(wlink, wtarget, 0)) {
2151+
errno = err_win_to_posix(GetLastError());
2152+
return -1;
2153+
}
2154+
return 0;
2155+
}
2156+
21272157
#ifndef _WINNT_H
21282158
/*
21292159
* 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
@@ -123,8 +123,6 @@ struct utsname {
123123
* trivial stubs
124124
*/
125125

126-
static inline int symlink(const char *oldpath, const char *newpath)
127-
{ errno = ENOSYS; return -1; }
128126
static inline int fchmod(int fildes, mode_t mode)
129127
{ errno = ENOSYS; return -1; }
130128
#ifndef __MINGW64_VERSION_MAJOR
@@ -216,6 +214,7 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out);
216214
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
217215
int link(const char *oldpath, const char *newpath);
218216
int uname(struct utsname *buf);
217+
int symlink(const char *target, const char *link);
219218
int readlink(const char *path, char *buf, size_t bufsiz);
220219

221220
/*

0 commit comments

Comments
 (0)