Windows: remove duplicate symlink resolution code
In this PR:
- Remove the SymlinkResolver class and the
ReadSymlinkW method from file_windows.cc, and
the declaration from file_windows.h, because
nothing in the Bazel client used these.
- Use the JNI library's ReadSymlinkOrJunction in
build-runfiles-windows.cc
Closes #7942.
PiperOrigin-RevId: 241921634
diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h
index 005257a..7457e5e 100644
--- a/src/main/cpp/util/file_platform.h
+++ b/src/main/cpp/util/file_platform.h
@@ -209,13 +209,6 @@
std::wstring GetCwdW();
bool MakeDirectoriesW(const std::wstring &path, unsigned int mode);
-// Resolve a symlink to its target.
-// If `path` is a symlink, result will contain the target it points to,
-// If `path` is a not a symlink, result will contain `path` itself.
-// If the resolving succeeds, this function returns true,
-// otherwise it returns false.
-bool ReadSymlinkW(const std::wstring &path, std::wstring *result);
-
// Check if `path` is a directory.
bool IsDirectoryW(const std::wstring &path);
diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc
index 62a19f6..cdcfa54 100644
--- a/src/main/cpp/util/file_windows.cc
+++ b/src/main/cpp/util/file_windows.cc
@@ -461,97 +461,6 @@
}
}
-class SymlinkResolver {
- public:
- SymlinkResolver();
-
- // Resolves symlink to its actual path.
- //
- // Returns true if `path` is not a symlink and it exists.
- // Returns true if `path` is a symlink and can be successfully resolved.
- // Returns false otherwise.
- //
- // If `result` is not nullptr and the method returned true, then this will be
- // reset to point to a new WCHAR buffer containing the resolved path.
- // If `path` is a symlink, this will be the resolved path, otherwise
- // it will be a copy of `path`.
- bool Resolve(const WCHAR* path, std::unique_ptr<WCHAR[]>* result);
-
- private:
- // Symbolic Link Reparse Data Buffer is described at:
- // https://msdn.microsoft.com/en-us/library/cc232006.aspx
- typedef struct _ReparseSymbolicLinkData {
- static const int kSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
- ULONG ReparseTag;
- USHORT ReparseDataLength;
- USHORT Reserved;
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- ULONG Flags;
- WCHAR PathBuffer[1];
- } ReparseSymbolicLinkData;
-
- uint8_t reparse_buffer_bytes_[ReparseSymbolicLinkData::kSize];
- ReparseSymbolicLinkData* reparse_buffer_;
-};
-
-SymlinkResolver::SymlinkResolver()
- : reparse_buffer_(
- reinterpret_cast<ReparseSymbolicLinkData*>(reparse_buffer_bytes_)) {}
-
-bool SymlinkResolver::Resolve(const WCHAR* path, unique_ptr<WCHAR[]>* result) {
- DWORD attributes = ::GetFileAttributesW(path);
- if (attributes == INVALID_FILE_ATTRIBUTES) {
- // `path` does not exist.
- return false;
- } else {
- if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
- bool is_dir = attributes & FILE_ATTRIBUTE_DIRECTORY;
- AutoHandle handle(CreateFileW(path, FILE_READ_EA, kAllShare, NULL,
- OPEN_EXISTING,
- (is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0) |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL));
- if (!handle.IsValid()) {
- // Opening the symlink failed for whatever reason. For all intents and
- // purposes we can treat this file as if it didn't exist.
- return false;
- }
- // Read out the reparse point data.
- DWORD bytes_returned;
- BOOL ok = ::DeviceIoControl(
- handle, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_buffer_,
- MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes_returned, NULL);
- if (!ok) {
- // Reading the symlink data failed. For all intents and purposes we can
- // treat this file as if it didn't exist.
- return false;
- }
- if (reparse_buffer_->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
- if (result) {
- size_t len = reparse_buffer_->SubstituteNameLength / sizeof(WCHAR);
- result->reset(new WCHAR[len + 1]);
- const WCHAR* substituteName =
- reparse_buffer_->PathBuffer +
- (reparse_buffer_->SubstituteNameOffset / sizeof(WCHAR));
- wcsncpy_s(result->get(), len + 1, substituteName, len);
- result->get()[len] = UNICODE_NULL;
- }
- return true;
- }
- }
- }
- // `path` is a normal file or directory.
- if (result) {
- size_t len = wcslen(path) + 1;
- result->reset(new WCHAR[len]);
- memcpy(result->get(), path, len * sizeof(WCHAR));
- }
- return true;
-}
-
bool ReadDirectorySymlink(const string& name, string* result) {
wstring wname;
string error;
@@ -569,23 +478,6 @@
return true;
}
-bool ReadSymlinkW(const wstring& name, wstring* result) {
- wstring wname;
- string error;
- if (!AsAbsoluteWindowsPath(name, &wname, &error)) {
- BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
- << "ReadSymlinkW(" << name
- << "): AsAbsoluteWindowsPath failed: " << error;
- return false;
- }
- unique_ptr<WCHAR[]> result_ptr;
- if (!SymlinkResolver().Resolve(wname.c_str(), &result_ptr)) {
- return false;
- }
- *result = RemoveUncPrefixMaybe(result_ptr.get());
- return true;
-}
-
bool PathExists(const string& path) {
if (path.empty()) {
return false;
diff --git a/src/main/native/windows/BUILD b/src/main/native/windows/BUILD
index b4b0f18..a0b5f4b 100644
--- a/src/main/native/windows/BUILD
+++ b/src/main/native/windows/BUILD
@@ -25,6 +25,7 @@
hdrs = ["file.h"],
visibility = [
"//src/main/cpp:__subpackages__",
+ "//src/main/tools:__pkg__",
"//src/test/cpp:__subpackages__",
"//src/test/native:__subpackages__",
"//tools/test:__pkg__",
diff --git a/src/main/tools/BUILD b/src/main/tools/BUILD
index d1b45f8..d7e518e 100644
--- a/src/main/tools/BUILD
+++ b/src/main/tools/BUILD
@@ -53,7 +53,10 @@
"//src/conditions:windows": ["build-runfiles-windows.cc"],
"//conditions:default": ["build-runfiles.cc"],
}),
- deps = ["//src/main/cpp/util:filesystem"],
+ deps = ["//src/main/cpp/util:filesystem"] + select({
+ "//src/conditions:windows": ["//src/main/native/windows:lib-file"],
+ "//conditions:default": [],
+ }),
)
cc_binary(
diff --git a/src/main/tools/build-runfiles-windows.cc b/src/main/tools/build-runfiles-windows.cc
index edb1c91..e367228 100644
--- a/src/main/tools/build-runfiles-windows.cc
+++ b/src/main/tools/build-runfiles-windows.cc
@@ -23,6 +23,7 @@
#include "src/main/cpp/util/file_platform.h"
#include "src/main/cpp/util/path_platform.h"
#include "src/main/cpp/util/strings.h"
+#include "src/main/native/windows/file.h"
using std::ifstream;
using std::string;
@@ -104,6 +105,30 @@
str.erase(str.find_last_not_of(' ') + 1);
}
+bool ReadSymlink(const wstring& abs_path, wstring* target, wstring* error) {
+ switch (bazel::windows::ReadSymlinkOrJunction(abs_path, target, error)) {
+ case bazel::windows::ReadSymlinkOrJunctionResult::kSuccess:
+ return true;
+ case bazel::windows::ReadSymlinkOrJunctionResult::kAccessDenied:
+ *error = L"access is denied";
+ break;
+ case bazel::windows::ReadSymlinkOrJunctionResult::kDoesNotExist:
+ *error = L"path does not exist";
+ break;
+ case bazel::windows::ReadSymlinkOrJunctionResult::kNotALink:
+ *error = L"path is not a link";
+ break;
+ case bazel::windows::ReadSymlinkOrJunctionResult::kUnknownLinkType:
+ *error = L"unknown link type";
+ break;
+ default:
+ // This is bazel::windows::ReadSymlinkOrJunctionResult::kError (1).
+ // The JNI code puts a custom message in 'error'.
+ break;
+ }
+ return false;
+}
+
} // namespace
class RunfilesCreator {
@@ -266,10 +291,10 @@
bool is_symlink =
(metadata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
if (is_symlink) {
- wstring target;
- if (!blaze_util::ReadSymlinkW(subpath, &target)) {
+ wstring target, werror;
+ if (!ReadSymlink(subpath, &target, &werror)) {
die(L"ReadSymlinkW failed (%s): %hs", subpath.c_str(),
- GetLastErrorString().c_str());
+ werror.c_str());
}
target = AsAbsoluteWindowsPath(target.c_str());