summaryrefslogtreecommitdiff
path: root/src/win32
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-11-15 09:17:51 +0000
committerGitHub <noreply@github.com>2018-11-15 09:17:51 +0000
commit7321cff05df927c8d00755ef21289ec00d125c9c (patch)
treecbc8f816d196c6e5642886bb632d524eecbfa137 /src/win32
parent9189a66a9eb99f13ee81da5913ade3a1ff64262a (diff)
parentda500cc607f1f30cea822087f3aaeb6b6727ff74 (diff)
downloadlibgit2-7321cff05df927c8d00755ef21289ec00d125c9c.tar.gz
Merge pull request #4713 from libgit2/ethomson/win_symlinks
Support symlinks on Windows when core.symlinks=true
Diffstat (limited to 'src/win32')
-rw-r--r--src/win32/posix_w32.c54
1 files changed, 18 insertions, 36 deletions
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 8c321ef3c..5d144936b 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -29,15 +29,16 @@
#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
#endif
+#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x02
+#endif
+
/* Allowable mode bits on Win32. Using mode bits that are not supported on
* Win32 (eg S_IRWXU) is generally ignored, but Wine warns loudly about it
* so we simply remove them.
*/
#define WIN32_MODE_MASK (_S_IREAD | _S_IWRITE)
-/* GetFinalPathNameByHandleW signature */
-typedef DWORD(WINAPI *PFGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD);
-
unsigned long git_win32__createfile_sharemode =
FILE_SHARE_READ | FILE_SHARE_WRITE;
int git_win32__retries = 10;
@@ -393,12 +394,20 @@ int p_readlink(const char *path, char *buf, size_t bufsiz)
return (int)bufsiz;
}
-int p_symlink(const char *old, const char *new)
+int p_symlink(const char *target, const char *path)
{
- /* Real symlinks on NTFS require admin privileges. Until this changes,
- * libgit2 just creates a text file with the link target in the contents.
- */
- return git_futils_fake_symlink(old, new);
+ git_win32_path target_w, path_w;
+ wchar_t *target_p;
+
+ if (git_win32_path_from_utf8(path_w, path) < 0 ||
+ git__utf8_to_16(target_w, MAX_PATH, target) < 0)
+ return -1;
+
+ if (!CreateSymbolicLinkW(path_w, target_w,
+ SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
+ return -1;
+
+ return 0;
}
struct open_opts {
@@ -598,40 +607,13 @@ int p_getcwd(char *buffer_out, size_t size)
return 0;
}
-/*
- * Returns the address of the GetFinalPathNameByHandleW function.
- * This function is available on Windows Vista and higher.
- */
-static PFGetFinalPathNameByHandleW get_fpnbyhandle(void)
-{
- static PFGetFinalPathNameByHandleW pFunc = NULL;
- PFGetFinalPathNameByHandleW toReturn = pFunc;
-
- if (!toReturn) {
- HMODULE hModule = GetModuleHandleW(L"kernel32");
-
- if (hModule)
- toReturn = (PFGetFinalPathNameByHandleW)GetProcAddress(hModule, "GetFinalPathNameByHandleW");
-
- pFunc = toReturn;
- }
-
- assert(toReturn);
-
- return toReturn;
-}
-
static int getfinalpath_w(
git_win32_path dest,
const wchar_t *path)
{
- PFGetFinalPathNameByHandleW pgfp = get_fpnbyhandle();
HANDLE hFile;
DWORD dwChars;
- if (!pgfp)
- return -1;
-
/* Use FILE_FLAG_BACKUP_SEMANTICS so we can open a directory. Do not
* specify FILE_FLAG_OPEN_REPARSE_POINT; we want to open a handle to the
* target of the link. */
@@ -642,7 +624,7 @@ static int getfinalpath_w(
return -1;
/* Call GetFinalPathNameByHandle */
- dwChars = pgfp(hFile, dest, GIT_WIN_PATH_UTF16, FILE_NAME_NORMALIZED);
+ dwChars = GetFinalPathNameByHandleW(hFile, dest, GIT_WIN_PATH_UTF16, FILE_NAME_NORMALIZED);
CloseHandle(hFile);
if (!dwChars || dwChars >= GIT_WIN_PATH_UTF16)