Skip to content

Commit

Permalink
Win32: implement basic symlink() functionality (file symlinks only)
Browse files Browse the repository at this point in the history
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 <blees@dcon.de>
  • Loading branch information
kblees authored and dscho committed Aug 26, 2017
1 parent 0106fd7 commit 27384fd
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
30 changes: 30 additions & 0 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ int mingw_core_config(const char *var, const char *value)
return 0;
}

DECLARE_PROC_ADDR(kernel32.dll, BOOLEAN, CreateSymbolicLinkW, LPCWSTR, LPCWSTR, DWORD);

/* Normalizes NT paths as returned by some low-level APIs. */
static wchar_t *normalize_ntpath(wchar_t *wbuf)
{
Expand Down Expand Up @@ -2123,6 +2125,34 @@ int link(const char *oldpath, const char *newpath)
return 0;
}

int symlink(const char *target, const char *link)
{
wchar_t wtarget[MAX_LONG_PATH], wlink[MAX_LONG_PATH];
int len;

/* fail if symlinks are disabled or API is not supported (WinXP) */
if (!has_symlinks || !INIT_PROC_ADDR(CreateSymbolicLinkW)) {
errno = ENOSYS;
return -1;
}

if ((len = xutftowcs_long_path(wtarget, target)) < 0
|| xutftowcs_long_path(wlink, link) < 0)
return -1;

/* convert target dir separators to backslashes */
while (len--)
if (wtarget[len] == '/')
wtarget[len] = '\\';

/* create file symlink */
if (!CreateSymbolicLinkW(wlink, wtarget, 0)) {
errno = err_win_to_posix(GetLastError());
return -1;
}
return 0;
}

#ifndef _WINNT_H
/*
* The REPARSE_DATA_BUFFER structure is defined in the Windows DDK (in
Expand Down
3 changes: 1 addition & 2 deletions compat/mingw.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,6 @@ struct utsname {
* trivial stubs
*/

static inline int symlink(const char *oldpath, const char *newpath)
{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
#ifndef __MINGW64_VERSION_MAJOR
Expand Down Expand Up @@ -216,6 +214,7 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
int link(const char *oldpath, const char *newpath);
int uname(struct utsname *buf);
int symlink(const char *target, const char *link);
int readlink(const char *path, char *buf, size_t bufsiz);

/*
Expand Down

0 comments on commit 27384fd

Please sign in to comment.