Commit c6e26210520663b4de07102b8b3035dd7675ef08

Edward Thomson 2014-10-13T16:52:44

Merge pull request #2615 from ethomson/mount_points Mount points

diff --git a/src/path.c b/src/path.c
index 21b6e18..143c564 100644
--- a/src/path.c
+++ b/src/path.c
@@ -515,23 +515,33 @@ bool git_path_is_empty_dir(const char *path)
 		WIN32_FIND_DATAW findData;
 		HANDLE hFind = FindFirstFileW(filter_w, &findData);
 
+		/* FindFirstFile will fail if there are no children to the given
+		 * path, which can happen if the given path is a file (and obviously
+		 * has no children) or if the given path is an empty mount point.
+		 * (Most directories have at least directory entries '.' and '..',
+		 * but ridiculously another volume mounted in another drive letter's
+		 * path space do not, and thus have nothing to enumerate.)  If
+		 * FindFirstFile fails, check if this is a directory-like thing
+		 * (a mount point).
+		 */
+		if (hFind == INVALID_HANDLE_VALUE)
+			return git_path_isdir(path);
+
 		/* If the find handle was created successfully, then it's a directory */
-		if (hFind != INVALID_HANDLE_VALUE) {
-			empty = true;
-
-			do {
-				/* Allow the enumeration to return . and .. and still be considered
-				 * empty. In the special case of drive roots (i.e. C:\) where . and
-				 * .. do not occur, we can still consider the path to be an empty
-				 * directory if there's nothing there. */
-				if (!git_path_is_dot_or_dotdotW(findData.cFileName)) {
-					empty = false;
-					break;
-				}
-			} while (FindNextFileW(hFind, &findData));
-
-			FindClose(hFind);
-		}
+		empty = true;
+
+		do {
+			/* Allow the enumeration to return . and .. and still be considered
+			 * empty. In the special case of drive roots (i.e. C:\) where . and
+			 * .. do not occur, we can still consider the path to be an empty
+			 * directory if there's nothing there. */
+			if (!git_path_is_dot_or_dotdotW(findData.cFileName)) {
+				empty = false;
+				break;
+			}
+		} while (FindNextFileW(hFind, &findData));
+
+		FindClose(hFind);
 	}
 
 	return empty;
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 0023f95..7b45557 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);