Sorry for the long absence, there are lot of other things to be done. Still I'm trying to participate, though, as I can. Recently I've found that there is no symlink function for Windows, though Windows has CreateSymbolicLink function. I've tried to implement my own. I don't know C or C++ really well, but fix seemed to be trivial enough. MinGW doesn't support symlinks, though reports success.
diff --git a/lib/symlink.c b/lib/symlink.c
index d3c9f21..903ae6a 100644
--- a/lib/symlink.c
+++ b/lib/symlink.c
@@ -45,7 +45,12 @@ rpl_symlink (char const *contents, char const *name)
#else /* !HAVE_SYMLINK */
-/* The system does not support symlinks. */
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+# include <windows.h>
+
+# if defined __MINGW32__
+/* MinGW does not support symlinks. */
int
symlink (char const *contents _GL_UNUSED,
char const *name _GL_UNUSED)
@@ -54,4 +59,141 @@ symlink (char const *contents _GL_UNUSED,
return -1;
}
+# else /* !defined __MINGW32__ */
+
+# if !defined SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+# endif
+
+/* CreateSymbolicLink was introduced only in Windows Vista.
+ Also on Windows it is necessary to get special privileges. */
+typedef BOOL (WINAPI * CreateSymbolicLinkFuncType) (LPCTSTR lpSymlinkFileName,
+ LPCTSTR lpTargetFileName,
+ DWORD dwFlags);
+static CreateSymbolicLinkFuncType CreateSymbolicLinkFunc = NULL;
+static BOOL initialized = FALSE;
+
+static void
+initialize (void)
+{
+ HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
+ if (kernel32 != NULL)
+ {
+ CreateSymbolicLinkFunc =
+ (CreateSymbolicLinkFuncType) GetProcAddress (kernel32, "CreateSymbolicLinkA");
+ }
+ initialized = TRUE;
+}
+
+int
+symlink (const char *file1, const char *file2)
+{
+ /* Enable privileges for symbolic link creation. */
+ HANDLE token;
+ struct stat st;
+ TOKEN_PRIVILEGES tp;
+ if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
+ goto error;
+ if (!LookupPrivilegeValueA (NULL, "SeCreateSymbolicLinkPrivilege", &tp.Privileges[0].Luid))
+ goto error;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ tp.PrivilegeCount = 1;
+ if (!AdjustTokenPrivileges (token, false, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
+ goto error;
+ CloseHandle(token);
+
+ /* Initialize symbolic link function. */
+ size_t len1 = strlen (file1);
+ size_t len2 = strlen (file2);
+ if (!initialized)
+ initialize ();
+
+ if (CreateSymbolicLinkFunc == NULL)
+ goto error;
+
+ /* Reject trailing slashes on non-directories. */
+ if ((len1 && (file1[len1 - 1] == '/' || file1[len1 - 1] == '\\'))
+ || (len2 && (file2[len2 - 1] == '/' || file2[len2 - 1] == '\\')))
+ {
+ if (stat (file1, &st) == 0 && S_ISDIR (st.st_mode))
+ errno = EPERM;
+ else
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ DWORD flags;
+ if (stat (file2, &st) == 0 && S_ISDIR (st.st_mode))
+ isdir |= SYMBOLIC_LINK_FLAG_DIRECTORY;
+ /* Create symbolic link. */
+ if (CreateSymbolicLinkFunc (file2, file1, flags) == 0)
+ {
+ /* Convert error codes from Windows to Unix. */
+ DWORD err = GetLastError ();
+ switch (err)
+ {
+ case ERROR_ACCESS_DENIED:
+ errno = EACCES;
+ break;
+
+ case ERROR_INVALID_FUNCTION:
+ errno = EPERM;
+ break;
+
+ case ERROR_NOT_SAME_DEVICE:
+ errno = EXDEV;
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_FILE_NOT_FOUND:
+ errno = ENOENT;
+ break;
+
+ case ERROR_INVALID_PARAMETER:
+ errno = ENAMETOOLONG;
+ break;
+
+ case ERROR_TOO_MANY_LINKS:
+ errno = EMLINK;
+ break;
+
+ case ERROR_ALREADY_EXISTS:
+ errno = EEXIST;
+ break;
+
+ default:
+ errno = EIO;
+ }
+ return -1;
+ }
+
+ /* MinGW doesn't report errors, though really fails. */
+ if (stat (file1, &st) != 0)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+ return 0;
+
+error:
+ CloseHandle(token);
+ errno = EPERM;
+ return -1;
+
+}
+
+# endif /* !defined __MINGW32__ */
+
+# else
+/* The system does not support symlinks. */
+int
+symlink (char const *contents _GL_UNUSED,
+ char const *name _GL_UNUSED)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+# endif
+
#endif /* !HAVE_SYMLINK */
--
With best regards,
Dmitry Selyutin
Phone: +7(985)334-07-70