Windows, JNI: allow empty cwd for processes
More specifically, change windows_util.AsShortPath
to accept empty inputs, as well as paths with
forward slashes.
Also output more accurate error messages for bad
input paths than before.
This fixes //src/test/java/com/google/devtools/build/lib:windows-tests
but not //src/test/java/com/google/devtools/build/lib:standalone-tests
--
PiperOrigin-RevId: 149399449
MOS_MIGRATED_REVID=149399449
diff --git a/src/main/native/windows_util.cc b/src/main/native/windows_util.cc
index cc0d029..7d82002 100644
--- a/src/main/native/windows_util.cc
+++ b/src/main/native/windows_util.cc
@@ -16,6 +16,7 @@
#include <stdlib.h>
#include <windows.h>
+#include <algorithm>
#include <functional>
#include <memory>
#include <string>
@@ -64,32 +65,44 @@
*result = string("\"") + path + "\"";
}
-string AsShortPath(const string& path, function<wstring()> path_as_wstring,
+static bool IsSeparator(char c) { return c == '/' || c == '\\'; }
+
+static bool HasSeparator(const string& s) {
+ return s.find_first_of('/') != string::npos ||
+ s.find_first_of('\\') != string::npos;
+}
+
+static bool Contains(const string& s, const char* substr) {
+ return s.find(substr) != string::npos;
+}
+
+string AsShortPath(string path, function<wstring()> path_as_wstring,
string* result) {
if (path.empty()) {
- return string("argv[0] should not be empty");
+ result->clear();
+ return "";
}
if (path[0] == '"') {
- return string("argv[0] should not be quoted");
+ return string("path should not be quoted");
}
- if (path[0] == '\\' || // absolute, but without drive letter
- path.find("/") != string::npos || // has "/"
- path.find("\\.\\") != string::npos || // not normalized
- path.find("\\..\\") != string::npos || // not normalized
- // at least MAX_PATH long, but just a file name
- (path.size() >= MAX_PATH && path.find_first_of('\\') == string::npos) ||
- // not just a file name, but also not absolute
- (path.find_first_of('\\') != string::npos &&
- !(isalpha(path[0]) && path[1] == ':' && path[2] == '\\'))) {
- return string("argv[0]='" + path +
- "'; should have been either an absolute, "
- "normalized, Windows-style path with drive letter (e.g. "
- "'c:\\foo\\bar.exe'), or just a file name (e.g. "
- "'cmd.exe') shorter than MAX_PATH.");
+ if (IsSeparator(path[0])) {
+ return string("path='") + path + "' is absolute";
+ }
+ if (Contains(path, "/./") || Contains(path, "\\.\\") ||
+ Contains(path, "/..") || Contains(path, "\\..")) {
+ return string("path='") + path + "' is not normalized";
+ }
+ if (path.size() >= MAX_PATH && !HasSeparator(path)) {
+ return string("path='") + path + "' is just a file name but too long";
+ }
+ if (HasSeparator(path) &&
+ !(isalpha(path[0]) && path[1] == ':' && IsSeparator(path[2]))) {
+ return string("path='") + path + "' is not an absolute path";
}
// At this point we know the path is either just a file name (shorter than
// MAX_PATH), or an absolute, normalized, Windows-style path (of any length).
+ std::replace(path.begin(), path.end(), '/', '\\');
// Fast-track: the path is already short.
if (path.size() < MAX_PATH) {
*result = path;
@@ -142,6 +155,9 @@
string AsExecutablePathForCreateProcess(const string& path,
function<wstring()> path_as_wstring,
string* result) {
+ if (path.empty()) {
+ return string("path should not be empty");
+ }
string error = AsShortPath(path, path_as_wstring, result);
if (error.empty()) {
// Quote the path in case it's something like "c:\foo\app name.exe".
diff --git a/src/main/native/windows_util.h b/src/main/native/windows_util.h
index ea632e7..d34211f 100644
--- a/src/main/native/windows_util.h
+++ b/src/main/native/windows_util.h
@@ -49,7 +49,7 @@
string GetLastErrorString(const string& cause);
// Same as `AsExecutablePathForCreateProcess` except it won't quote the result.
-string AsShortPath(const string& path, function<wstring()> path_as_wstring,
+string AsShortPath(string path, function<wstring()> path_as_wstring,
string* result);
// Computes a path suitable as the executable part in CreateProcessA's cmdline.