From: Karsten Blees Date: Wed, 17 Dec 2025 14:08:51 +0000 (+0000) Subject: mingw: implement basic `symlink()` functionality (file symlinks only) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3aeb1cd126f338e23415885b3021c7f248f9ca0a;p=thirdparty%2Fgit.git mingw: implement basic `symlink()` functionality (file symlinks only) Implement `symlink()`. This implementation always creates _file_ symlinks (remember: Windows discerns between symlinks pointing to directories and those pointing to files). Support for directory symlinks will be added in a subseqeuent commit. This implementation fails with `ENOSYS` if symlinks are disabled or unsupported. Signed-off-by: Karsten Blees Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff --git a/compat/mingw-posix.h b/compat/mingw-posix.h index 896aa976b1..2d989fd762 100644 --- a/compat/mingw-posix.h +++ b/compat/mingw-posix.h @@ -121,8 +121,6 @@ struct utsname { * trivial stubs */ -static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED) { errno = ENOSYS; return -1; } #ifndef __MINGW64_VERSION_MAJOR @@ -195,6 +193,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); /* diff --git a/compat/mingw.c b/compat/mingw.c index b407a2ac07..8d366794c4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2698,6 +2698,34 @@ int link(const char *oldpath, const char *newpath) return 0; } +int symlink(const char *target, const char *link) +{ + wchar_t wtarget[MAX_PATH], wlink[MAX_PATH]; + int len; + + /* fail if symlinks are disabled or API is not supported (WinXP) */ + if (!has_symlinks) { + errno = ENOSYS; + return -1; + } + + if ((len = xutftowcs_path(wtarget, target)) < 0 + || xutftowcs_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; +} + int readlink(const char *path, char *buf, size_t bufsiz) { WCHAR wpath[MAX_PATH];