Bazel client: simplify ReadDirectorySymlink

This is a bugfixed version of
https://cr.bazel.build/9520 which broke some
Google-internal tests.

This change allows removing duplicate code:
ReadDirectorySymlink was implemented on Windows as
a junction resolver, which is also implemented in
file_windows.cc. Now it uses the JunctionResolver.

RELNOTES: none

PiperOrigin-RevId: 151691895
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index 1457587..30692da 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -1065,7 +1065,8 @@
   string installation_path =
       blaze_util::JoinPath(globals->options->output_base, "install");
   string prev_installation;
-  bool ok = ReadDirectorySymlink(installation_path, &prev_installation);
+  bool ok =
+      blaze_util::ReadDirectorySymlink(installation_path, &prev_installation);
   if (!ok || !CompareAbsolutePaths(prev_installation,
                                    globals->options->install_base)) {
     if (server->Connected()) {
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index f158b58..afb8c2d 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -143,11 +143,6 @@
 // Implemented via junctions on Windows.
 bool SymlinkDirectories(const std::string& target, const std::string& link);
 
-// Reads which directory a symlink points to. Puts the target of the symlink
-// in ``result`` and returns if the operation was successful. Will not work on
-// symlinks that don't point to directories on Windows.
-bool ReadDirectorySymlink(const std::string& symlink, std::string* result);
-
 // Compares two absolute paths. Necessary because the same path can have
 // multiple different names under msys2: "C:\foo\bar" or "C:/foo/bar"
 // (Windows-style) and "/c/foo/bar" (msys2 style). Returns if the paths are
diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc
index dab5f0a..67d52fe 100644
--- a/src/main/cpp/blaze_util_posix.cc
+++ b/src/main/cpp/blaze_util_posix.cc
@@ -345,18 +345,6 @@
   return ReadJvmVersion(version_string);
 }
 
-bool ReadDirectorySymlink(const string &name, string* result) {
-  char buf[PATH_MAX + 1];
-  int len = readlink(name.c_str(), buf, PATH_MAX);
-  if (len < 0) {
-    return false;
-  }
-
-  buf[len] = 0;
-  *result = buf;
-  return true;
-}
-
 bool CompareAbsolutePaths(const string& a, const string& b) {
   return a == b;
 }
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index 8e1d329..9eb11d7 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -964,35 +964,6 @@
 #endif  // COMPILER_MSVC
 }
 
-static string ConvertPathToPosix(const string& win_path) {
-#ifdef COMPILER_MSVC
-  // TODO(bazel-team) 2016-11-18: verify that this function is not needed on
-  // Windows.
-  return win_path;
-#else   // not COMPILER_MSVC
-  char* posix_path = static_cast<char*>(cygwin_create_path(
-      CCP_WIN_A_TO_POSIX, static_cast<const void*>(win_path.c_str())));
-  string result(posix_path);
-  free(posix_path);
-  return result;
-#endif  // COMPILER_MSVC
-}
-
-// Cribbed from ntifs.h, not present in windows.h
-
-#define REPARSE_MOUNTPOINT_HEADER_SIZE   8
-
-typedef struct {
-  DWORD ReparseTag;
-  WORD ReparseDataLength;
-  WORD Reserved;
-  WORD SubstituteNameOffset;
-  WORD SubstituteNameLength;
-  WORD PrintNameOffset;
-  WORD PrintNameLength;
-  WCHAR PathBuffer[ANYSIZE_ARRAY];
-} REPARSE_MOUNTPOINT_DATA_BUFFER, *PREPARSE_MOUNTPOINT_DATA_BUFFER;
-
 bool SymlinkDirectories(const string &posix_target, const string &posix_name) {
   wstring name;
   wstring target;
@@ -1015,69 +986,6 @@
   return true;
 }
 
-// TODO(laszlocsomor): use JunctionResolver in file_windows.cc
-bool ReadDirectorySymlink(const string &posix_name, string* result) {
-  string name = ConvertPath(posix_name);
-  wstring wname;
-
-  if (!blaze_util::AsWindowsPathWithUncPrefix(name, &wname)) {
-    PrintError("ReadDirectorySymlink: AsWindowsPathWithUncPrefix(" + name +
-               ")");
-    return false;
-  }
-
-  HANDLE directory = windows_util::OpenDirectory(wname.c_str(), false);
-  if (directory == INVALID_HANDLE_VALUE) {
-    return false;
-  }
-
-  char reparse_buffer_bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
-  REPARSE_MOUNTPOINT_DATA_BUFFER* reparse_buffer =
-      reinterpret_cast<REPARSE_MOUNTPOINT_DATA_BUFFER *>(reparse_buffer_bytes);
-  memset(reparse_buffer_bytes, 0, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
-
-  reparse_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
-  DWORD bytes_returned;
-  bool ok = ::DeviceIoControl(
-      directory,
-      FSCTL_GET_REPARSE_POINT,
-      NULL,
-      0,
-      reparse_buffer,
-      MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
-      &bytes_returned,
-      NULL);
-  if (!ok) {
-    PrintError("DeviceIoControl(FSCTL_GET_REPARSE_POINT, " + name + ")");
-  }
-
-  CloseHandle(directory);
-  if (!ok) {
-    return false;
-  }
-
-  std::vector<char> print_name(reparse_buffer->PrintNameLength * sizeof(WCHAR) +
-                               1);
-  int count = ::WideCharToMultiByte(
-      CP_UTF8,
-      0,
-      reparse_buffer->PathBuffer +
-         (reparse_buffer->PrintNameOffset / sizeof(WCHAR)),
-      reparse_buffer->PrintNameLength,
-      &print_name[0],
-      print_name.size(),
-      NULL,
-      NULL);
-  if (count == 0) {
-    PrintError("WideCharToMultiByte()");
-    *result = "";
-    return false;
-  } else {
-    *result = ConvertPathToPosix(&print_name[0]);
-    return true;
-  }
-}
-
 bool CompareAbsolutePaths(const string& a, const string& b) {
   return ConvertPath(a) == ConvertPath(b);
 }
diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h
index 50b75de..31a0d1c 100644
--- a/src/main/cpp/util/file_platform.h
+++ b/src/main/cpp/util/file_platform.h
@@ -130,6 +130,11 @@
 // Returns one of the RenameDirectoryResult enum values.
 int RenameDirectory(const std::string &old_name, const std::string &new_name);
 
+// Reads which directory a symlink points to. Puts the target of the symlink
+// in ``result`` and returns if the operation was successful. Will not work on
+// symlinks that don't point to directories on Windows.
+bool ReadDirectorySymlink(const std::string &symlink, std::string *result);
+
 // Unlinks the file given by 'file_path'.
 // Returns true on success. In case of failure sets errno.
 bool UnlinkPath(const std::string &file_path);
diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc
index 076bff2..daa465a 100644
--- a/src/main/cpp/util/file_posix.cc
+++ b/src/main/cpp/util/file_posix.cc
@@ -251,6 +251,18 @@
   }
 }
 
+bool ReadDirectorySymlink(const string &name, string *result) {
+  char buf[PATH_MAX + 1];
+  int len = readlink(name.c_str(), buf, PATH_MAX);
+  if (len < 0) {
+    return false;
+  }
+
+  buf[len] = 0;
+  *result = buf;
+  return true;
+}
+
 bool UnlinkPath(const string &file_path) {
   return unlink(file_path.c_str()) == 0;
 }
diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc
index c2e0fd7..af6ed4f 100644
--- a/src/main/cpp/util/file_windows.cc
+++ b/src/main/cpp/util/file_windows.cc
@@ -863,6 +863,21 @@
   return Resolve(path, result, kMaximumJunctionDepth);
 }
 
+bool ReadDirectorySymlink(const string& name, string* result) {
+  wstring wname;
+  if (!AsWindowsPathWithUncPrefix(name, &wname)) {
+    PrintError("ReadDirectorySymlink: AsWindowsPathWithUncPrefix(%s)",
+               name.c_str());
+    return false;
+  }
+  unique_ptr<WCHAR[]> result_ptr;
+  if (!JunctionResolver().Resolve(wname.c_str(), &result_ptr)) {
+    return false;
+  }
+  *result = WstringToCstring(RemoveUncPrefixMaybe(result_ptr.get())).get();
+  return true;
+}
+
 bool PathExists(const string& path) {
   if (path.empty()) {
     return false;