diff options
author | 2017-01-10 10:41:26 +0000 | |
---|---|---|
committer | 2017-01-10 11:51:20 +0000 | |
commit | 44ecf9a0c7c25496a43f59f1c8f20df9527e12cb (patch) | |
tree | c7580369cd3b0e7426b569d9638addaec4c00b0d | |
parent | 12bf5ba34f70200eccc9e5f9b2f27d91d4514d77 (diff) |
Windows: implement and use AsShortWindowsPath
Because CreateProcessW doesn't support long paths,
not even with the "\\?\" prefix [1], we need to
convert long paths to short ones to spawn
processes. This change implements the
corresponding function and uses it in
blaze_util_windows.
[1] https://github.com/bazelbuild/bazel/issues/2181#issuecomment-270696173
See https://github.com/bazelbuild/bazel/issues/2107
See https://github.com/bazelbuild/bazel/issues/2181
--
PiperOrigin-RevId: 144062404
MOS_MIGRATED_REVID=144062404
-rw-r--r-- | src/main/cpp/blaze_util_windows.cc | 24 | ||||
-rw-r--r-- | src/main/cpp/util/file_platform.h | 4 | ||||
-rw-r--r-- | src/main/cpp/util/file_windows.cc | 27 | ||||
-rw-r--r-- | src/test/cpp/util/file_windows_test.cc | 19 |
4 files changed, 65 insertions, 9 deletions
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc index 12aa3e3721..0595de6bcf 100644 --- a/src/main/cpp/blaze_util_windows.cc +++ b/src/main/cpp/blaze_util_windows.cc @@ -373,6 +373,12 @@ struct CmdLine { static void CreateCommandLine(CmdLine* result, const string& exe, const vector<string>& args_vector) { std::ostringstream cmdline; + string short_exe; + if (!blaze_util::AsShortWindowsPath(exe + ".exe", &short_exe)) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "CreateCommandLine: AsShortWindowsPath(%s.exe) failed, err=%d", + exe.c_str(), GetLastError()); + } bool first = true; for (const auto& s : args_vector) { if (first) { @@ -456,23 +462,23 @@ string GetJvmVersion(const string& java_exe) { } PROCESS_INFORMATION processInfo = {0}; - STARTUPINFOW startupInfo = {0}; + STARTUPINFOA startupInfo = {0}; startupInfo.hStdError = pipe_write; startupInfo.hStdOutput = pipe_write; startupInfo.dwFlags |= STARTF_USESTDHANDLES; - wstring wjava_exe; - if (!blaze_util::AsWindowsPath(java_exe, &wjava_exe)) { + string win_java_exe; + if (!blaze_util::AsShortWindowsPath(java_exe + ".exe", &win_java_exe)) { CloseHandle(pipe_read); CloseHandle(pipe_write); - pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "AsWindowsPath(%s)", - java_exe); + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "GetJvmVersion: AsWindowsPath(%s.exe)", java_exe.c_str()); } - wjava_exe = wstring(L"\"") + wjava_exe + L".exe\" -version"; + win_java_exe = string("\"") + win_java_exe + "\" -version"; - WCHAR cmdline[MAX_CMDLINE_LENGTH]; - wcscpy(cmdline, wjava_exe.c_str()); - BOOL ok = CreateProcessW( + char cmdline[MAX_CMDLINE_LENGTH]; + strncpy(cmdline, win_java_exe.c_str(), win_java_exe.size() + 1); + BOOL ok = CreateProcessA( /* lpApplicationName */ NULL, /* lpCommandLine */ cmdline, /* lpProcessAttributes */ NULL, diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h index 9c95468e4b..91fc086627 100644 --- a/src/main/cpp/util/file_platform.h +++ b/src/main/cpp/util/file_platform.h @@ -133,6 +133,10 @@ void ForEachDirectoryEntry(const std::string &path, // prepend the UNC prefix in case they need to pass it to a WinAPI function // (some require the prefix, some don't), or to quote the path if necessary. bool AsWindowsPath(const std::string &path, std::wstring *result); + +// Same as `AsWindowsPath`, but returns a lowercase 8dot3 style shortened path. +// Result will never have a UNC prefix. +bool AsShortWindowsPath(const std::string &path, std::string *result); #endif // defined(COMPILER_MSVC) || defined(__CYGWIN__) } // namespace blaze_util diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc index 75555bba89..3fa01a445b 100644 --- a/src/main/cpp/util/file_windows.cc +++ b/src/main/cpp/util/file_windows.cc @@ -308,6 +308,8 @@ bool AsWindowsPath(const string& path, wstring* result) { static bool AsWindowsPathWithUncPrefix(const string& path, wstring* wpath) { if (!AsWindowsPath(path, wpath)) { + PrintError("AsWindowsPathWithUncPrefix(%s): AsWindowsPath failed, err=%d\n", + path.c_str(), GetLastError()); return false; } if (!IsAbsolute(path)) { @@ -317,6 +319,31 @@ static bool AsWindowsPathWithUncPrefix(const string& path, wstring* wpath) { return true; } +bool AsShortWindowsPath(const string& path, string* result) { + result->clear(); + wstring wpath; + if (!AsWindowsPathWithUncPrefix(path, &wpath)) { + return false; + } + DWORD size = ::GetShortPathNameW(wpath.c_str(), nullptr, 0); + if (size == 0) { + return false; + } + + unique_ptr<WCHAR[]> wshort(new WCHAR[size]); // size includes null-terminator + if (size - 1 != ::GetShortPathNameW(wpath.c_str(), wshort.get(), size)) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "AsShortWindowsPath(%s): GetShortPathNameW(%S) failed, err=%d", + path.c_str(), wpath.c_str(), GetLastError()); + } + // GetShortPathNameW may preserve the UNC prefix in the result, so strip it. + WCHAR* result_ptr = wshort.get() + (HasUncPrefix(wshort.get()) ? 4 : 0); + + result->assign(WstringToCstring(result_ptr).get()); + ToLower(result); + return true; +} + bool ReadFile(const string& filename, string* content, int max_size) { if (filename.empty()) { return false; diff --git a/src/test/cpp/util/file_windows_test.cc b/src/test/cpp/util/file_windows_test.cc index 983763aeaf..1cf49d88c5 100644 --- a/src/test/cpp/util/file_windows_test.cc +++ b/src/test/cpp/util/file_windows_test.cc @@ -178,6 +178,25 @@ TEST(FileTest, TestAsWindowsPath) { ASSERT_EQ(wlongpath, actual); } +TEST(FileTest, TestAsShortWindowsPath) { + string tmpdir(GetTestTmpDir()); + ASSERT_LT(0, tmpdir.size()); + + string short_tmpdir; + ASSERT_TRUE(AsShortWindowsPath(tmpdir, &short_tmpdir)); + ASSERT_LT(0, short_tmpdir.size()); + ASSERT_TRUE(PathExists(short_tmpdir)); + + string dirname(JoinPath(short_tmpdir, "LONGpathNAME")); + ASSERT_EQ(0, mkdir(dirname.c_str())); + ASSERT_TRUE(PathExists(dirname)); + + string actual; + ASSERT_TRUE(AsShortWindowsPath(dirname, &actual)); + ASSERT_EQ(short_tmpdir + "\\longpa~1", actual); + ASSERT_EQ(0, rmdir(dirname.c_str())); +} + TEST(FileTest, TestMsysRootRetrieval) { wstring actual; |