Skip to content

Commit

Permalink
Windows: implement and use AsShortWindowsPath
Browse files Browse the repository at this point in the history
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] #2181 (comment)

See #2107
See #2181

--
PiperOrigin-RevId: 144062404
MOS_MIGRATED_REVID=144062404
  • Loading branch information
laszlocsomor authored and hlopko committed Jan 10, 2017
1 parent 12bf5ba commit 44ecf9a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 9 deletions.
24 changes: 15 additions & 9 deletions src/main/cpp/blaze_util_windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions src/main/cpp/util/file_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions src/main/cpp/util/file_windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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;
Expand Down
19 changes: 19 additions & 0 deletions src/test/cpp/util/file_windows_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 44ecf9a

Please sign in to comment.