From 8d45b4691c81d2d1cde7a1b2f828dedd55315b3f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Sat, 11 Oct 2014 14:34:24 -0400 Subject: [PATCH] p_lstat win32: don't canonicalize volume mounts A reparse point that is an IO_REPARSE_TAG_MOUNT_POINT could be a junction or an actual filesystem mount point. (Who knew?) If it's the latter, its reparse point will report the actual volume information \??\Volume{GUID}\ and we should not attempt to dereference that further, instead readlink should report EINVAL since it's not a symlink / junction and its original path was canonical. Yes, really. --- src/win32/posix_w32.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 0023f95ff..7b4555719 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -131,6 +131,11 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } +static bool path_is_volume(wchar_t *target, size_t target_len) +{ + return (target_len && wcsncmp(target, L"\\??\\Volume{", 11) == 0); +} + /* On success, returns the length, in characters, of the path stored in dest. * On failure, returns a negative value. */ static int readlink_w( @@ -177,7 +182,13 @@ static int readlink_w( goto on_error; } - if (target_len) { + if (path_is_volume(target, target_len)) { + /* This path is a reparse point that represents another volume mounted + * at this location, it is not a symbolic link our input was canonical. + */ + errno = EINVAL; + error = -1; + } else if (target_len) { /* The path may need to have a prefix removed. */ target_len = git_win32__canonicalize_path(target, target_len);