summaryrefslogtreecommitdiff
path: root/src/win32
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2019-07-11 15:14:42 +0200
committerPatrick Steinhardt <ps@pks.im>2019-07-20 19:11:20 +0200
commit50194dcda14a515bc3bbddee68c4092ca778d4dd (patch)
tree62523d9a308f079f24e2e25201eadb6b3960c207 /src/win32
parent93d37a1d5295b77731f2de238fffc7e01b9866b0 (diff)
downloadlibgit2-50194dcda14a515bc3bbddee68c4092ca778d4dd.tar.gz
win32: fix symlinks to relative file targets
When creating a symlink in Windows, one needs to tell Windows whether the symlink should be a file or directory symlink. To determine which flag to pass, we call `GetFileAttributesW` on the target file to see whether it is a directory and then pass the flag accordingly. The problem though is if create a symlink with a relative target path, then we will check that relative path while not necessarily being inside of the working directory where the symlink is to be created. Thus, getting its attributes will either fail or return attributes of the wrong target. Fix this by resolving the target path relative to the directory in which the symlink is to be created.
Diffstat (limited to 'src/win32')
-rw-r--r--src/win32/posix_w32.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 4de321796..078b50952 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -414,18 +414,37 @@ int p_readlink(const char *path, char *buf, size_t bufsiz)
return (int)bufsiz;
}
+static bool target_is_dir(const char *target, const char *path)
+{
+ git_buf resolved = GIT_BUF_INIT;
+ git_win32_path resolved_w;
+ bool isdir = true;
+
+ if (git_path_is_absolute(target))
+ git_win32_path_from_utf8(resolved_w, target);
+ else if (git_path_dirname_r(&resolved, path) < 0 ||
+ git_path_apply_relative(&resolved, target) < 0 ||
+ git_win32_path_from_utf8(resolved_w, resolved.ptr) < 0)
+ goto out;
+
+ isdir = GetFileAttributesW(resolved_w) & FILE_ATTRIBUTE_DIRECTORY;
+
+out:
+ git_buf_dispose(&resolved);
+ return isdir;
+}
+
int p_symlink(const char *target, const char *path)
{
git_win32_path target_w, path_w;
DWORD dwFlags;
if (git_win32_path_from_utf8(path_w, path) < 0 ||
- git__utf8_to_16(target_w, MAX_PATH, target) < 0)
+ git__utf8_to_16(target_w, MAX_PATH, target) < 0)
return -1;
dwFlags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
-
- if (GetFileAttributesW(target_w) & FILE_ATTRIBUTE_DIRECTORY)
+ if (target_is_dir(target, path))
dwFlags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
if (!CreateSymbolicLinkW(path_w, target_w, dwFlags))