Skip to content

Commit cc4f4cb

Browse files
authored
Merge pull request libgit2#5355 from pks-t/pks/win32-relative-symlink-across-dirs
win32: fix relative symlinks pointing into dirs
2 parents d548233 + 7d55bee commit cc4f4cb

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

src/win32/posix_w32.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,16 @@ int p_symlink(const char *target, const char *path)
439439
git_win32_path target_w, path_w;
440440
DWORD dwFlags;
441441

442+
/*
443+
* Convert both target and path to Windows-style paths. Note that we do
444+
* not want to use `git_win32_path_from_utf8` for converting the target,
445+
* as that function will automatically pre-pend the current working
446+
* directory in case the path is not absolute. As Git will instead use
447+
* relative symlinks, this is not someting we want.
448+
*/
442449
if (git_win32_path_from_utf8(path_w, path) < 0 ||
443-
git__utf8_to_16(target_w, MAX_PATH, target) < 0)
450+
git__utf8_to_16(target_w, MAX_PATH, target) < 0 ||
451+
git_win32_path_canonicalize(target_w) < 0)
444452
return -1;
445453

446454
dwFlags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;

tests/core/posix.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,30 @@ void test_core_posix__symlink_resolves_to_correct_type(void)
189189

190190
git_buf_dispose(&contents);
191191
}
192+
193+
void test_core_posix__symlink_to_file_across_dirs(void)
194+
{
195+
git_buf contents = GIT_BUF_INIT;
196+
197+
if (!git_path_supports_symlinks(clar_sandbox_path()))
198+
clar__skip();
199+
200+
/*
201+
* Create a relative symlink that points into another
202+
* directory. This used to not work on Win32, where we
203+
* forgot to convert directory separators to
204+
* Windows-style ones.
205+
*/
206+
cl_must_pass(git_futils_mkdir("dir", 0777, 0));
207+
cl_git_mkfile("dir/target", "symlink target");
208+
cl_git_pass(p_symlink("dir/target", "link"));
209+
210+
cl_git_pass(git_futils_readbuffer(&contents, "dir/target"));
211+
cl_assert_equal_s(contents.ptr, "symlink target");
212+
213+
cl_must_pass(p_unlink("dir/target"));
214+
cl_must_pass(p_unlink("link"));
215+
cl_must_pass(p_rmdir("dir"));
216+
217+
git_buf_dispose(&contents);
218+
}

0 commit comments

Comments
 (0)