Hello everyone! 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 E-mail: ghostma...@gmail.com Phone: +7(985)334-07-70