Skip to content

Commit ec9ce13

Browse files
committed
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 e357424 commit ec9ce13

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
@@ -231,6 +231,9 @@ static int retry_ask_yes_no(int *tries, const char *format, ...)
231231
return result;
232232
}
233233

234+
235+
DECLARE_PROC_ADDR(kernel32.dll, BOOL, CreateSymbolicLinkW, LPCWSTR, LPCWSTR, DWORD);
236+
234237
/* Normalizes NT paths as returned by some low-level APIs. */
235238
static wchar_t *normalize_ntpath(wchar_t *wbuf)
236239
{
@@ -2012,6 +2015,34 @@ int link(const char *oldpath, const char *newpath)
20122015
return 0;
20132016
}
20142017

2018+
int symlink(const char *target, const char *link)
2019+
{
2020+
wchar_t wtarget[MAX_LONG_PATH], wlink[MAX_LONG_PATH];
2021+
int len;
2022+
2023+
/* fail if symlinks are disabled or API is not supported (WinXP) */
2024+
if (!has_symlinks || !INIT_PROC_ADDR(CreateSymbolicLinkW)) {
2025+
errno = ENOSYS;
2026+
return -1;
2027+
}
2028+
2029+
if ((len = xutftowcs_long_path(wtarget, target)) < 0
2030+
|| xutftowcs_long_path(wlink, link) < 0)
2031+
return -1;
2032+
2033+
/* convert target dir separators to backslashes */
2034+
while (len--)
2035+
if (wtarget[len] == '/')
2036+
wtarget[len] = '\\';
2037+
2038+
/* create file symlink */
2039+
if (!CreateSymbolicLinkW(wlink, wtarget, 0)) {
2040+
errno = err_win_to_posix(GetLastError());
2041+
return -1;
2042+
}
2043+
return 0;
2044+
}
2045+
20152046
/*
20162047
* The REPARSE_DATA_BUFFER structure is only defined in the Windows DDK (in
20172048
* Ntifs.h), so we have to define it ourselves.

compat/mingw.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ struct itimerval {
9393
* trivial stubs
9494
*/
9595

96-
static inline int symlink(const char *oldpath, const char *newpath)
97-
{ errno = ENOSYS; return -1; }
9896
static inline int fchmod(int fildes, mode_t mode)
9997
{ errno = ENOSYS; return -1; }
10098
#ifndef __MINGW64_VERSION_MAJOR
@@ -180,6 +178,7 @@ struct passwd *getpwuid(uid_t uid);
180178
int setitimer(int type, struct itimerval *in, struct itimerval *out);
181179
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
182180
int link(const char *oldpath, const char *newpath);
181+
int symlink(const char *target, const char *link);
183182
int readlink(const char *path, char *buf, size_t bufsiz);
184183

185184
/*

0 commit comments

Comments
 (0)