Windows, JNI, refactor: move a method
This change moves AsExecutablePathForCreateProcess
to windows_util. This is a follow-up to
unknown commit.
--
PiperOrigin-RevId: 144623760
MOS_MIGRATED_REVID=144623760
diff --git a/src/main/native/windows_processes.cc b/src/main/native/windows_processes.cc
index 35eea00..97f22b4 100644
--- a/src/main/native/windows_processes.cc
+++ b/src/main/native/windows_processes.cc
@@ -156,120 +156,9 @@
static jlong PtrAsJlong(void* p) { return reinterpret_cast<jlong>(p); }
-static void QuotePath(const std::string& path, std::string* result) {
- *result = std::string("\"") + path + "\"";
-}
-
-// Computes a path suitable as the executable part in CreateProcessA's cmdline.
-//
-// The null-terminated executable path for CreateProcessA has to fit into
-// MAX_PATH, therefore the limit for the executable's path is MAX_PATH - 1
-// (not including null terminator). This method attempts to convert the input
-// `path` to a short format to fit it into the MAX_PATH - 1 limit.
-//
-// `path` must be either an absolute, normalized, Windows-style path with drive
-// letter (e.g. "c:\foo\bar.exe", but no "\foo\bar.exe"), or must be just a file
-// name (e.g. "cmd.exe") that's shorter than MAX_PATH (without null-terminator).
-// In both cases, `path` must be unquoted.
-//
-// `path_as_wstring` must be a function that retrieves `path` as (or converts it
-// to) a wstring, without performing any transformations on the path.
-//
-// If this function succeeds, it returns an empty string (indicating no error),
-// and sets `result` to the resulting path, which is always quoted, and is
-// always at most MAX_PATH + 1 long (MAX_PATH - 1 without null terminator, plus
-// two quotes). If there's any error, this function returns the error message.
-//
-// If `path` is at most MAX_PATH - 1 long (not including null terminator), the
-// result will be that (plus quotes).
-// Otherwise this method attempts to compute an 8dot3 style short name for
-// `path`, and if that succeeds and the result is at most MAX_PATH - 1 long (not
-// including null terminator), then that will be the result (plus quotes).
-// Otherwise this function fails and returns an error message.
-static std::string AsExecutablePathForCreateProcess(
- const std::string& path, std::function<std::wstring()> path_as_wstring,
- std::string* result) {
- if (path.empty()) {
- return std::string("argv[0] should not be empty");
- }
- if (path[0] == '"') {
- return std::string("argv[0] should not be quoted");
- }
- if (path[0] == '\\' || // absolute, but without drive letter
- path.find("/") != std::string::npos || // has "/"
- path.find("\\.\\") != std::string::npos || // not normalized
- path.find("\\..\\") != std::string::npos || // not normalized
- // at least MAX_PATH long, but just a file name
- (path.size() >= MAX_PATH &&
- path.find_first_of('\\') == std::string::npos) ||
- // not just a file name, but also not absolute
- (path.find_first_of('\\') != std::string::npos &&
- !(isalpha(path[0]) && path[1] == ':' && path[2] == '\\'))) {
- return std::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.");
- }
- // 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).
-
- // Fast-track: the path is already short.
- if (path.size() < MAX_PATH) {
- // Quote the path in case it's something like "c:\foo\app name.exe".
- // Do this unconditionally, there's no harm in quoting. Quotes are not
- // allowed inside paths so we don't need to escape quotes.
- QuotePath(path, result);
- return "";
- }
- // At this point we know that the path is at least MAX_PATH long and that it's
- // absolute, normalized, and Windows-style.
-
- // Retrieve string as UTF-16 path, add "\\?\" prefix.
- std::wstring wlong = std::wstring(L"\\\\?\\") + path_as_wstring();
-
- // Experience shows that:
- // - GetShortPathNameW's result has a "\\?\" prefix if and only if the input
- // did too (though this behavior is not documented on MSDN)
- // - CreateProcess{A,W} only accept an executable of MAX_PATH - 1 length
- // Therefore for our purposes the acceptable shortened length is
- // MAX_PATH + 4 (null-terminated). That is, MAX_PATH - 1 for the shortened
- // path, plus a potential "\\?\" prefix that's only there if `wlong` also had
- // it and which we'll omit from `result`, plus a null terminator.
- static const size_t kMaxShortPath = MAX_PATH + 4;
-
- WCHAR wshort[kMaxShortPath];
- DWORD wshort_size = ::GetShortPathNameW(wlong.c_str(), NULL, 0);
- if (wshort_size == 0) {
- return windows_util::GetLastErrorString(
- std::string("GetShortPathName failed (path=") + path + ")");
- }
-
- if (wshort_size >= kMaxShortPath) {
- return windows_util::GetLastErrorString(
- std::string(
- "GetShortPathName would not shorten the path enough (path=") +
- path + ")");
- }
-
- // Convert the result to UTF-8.
- char mbs_short[MAX_PATH];
- size_t mbs_size = wcstombs(
- mbs_short,
- wshort + 4, // we know it has a "\\?\" prefix, because `wlong` also did
- MAX_PATH);
- if (mbs_size < 0 || mbs_size >= MAX_PATH) {
- return std::string("wcstombs failed (path=") + path + ")";
- }
- mbs_short[mbs_size - 1] = 0;
-
- QuotePath(mbs_short, result);
- return "";
-}
-
static std::string AsExecutableForCreateProcess(JNIEnv* env, jstring path,
std::string* result) {
- return AsExecutablePathForCreateProcess(
+ return windows_util::AsExecutablePathForCreateProcess(
GetJavaUTFString(env, path),
[env, path]() { return GetJavaWstring(env, path); }, result);
}
diff --git a/src/main/native/windows_util.cc b/src/main/native/windows_util.cc
index 53ca6ae..051290d 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 <functional>
#include <memory>
#include <string>
@@ -23,8 +24,10 @@
namespace windows_util {
+using std::function;
using std::string;
using std::unique_ptr;
+using std::wstring;
string GetLastErrorString(const string& cause) {
DWORD last_error = GetLastError();
@@ -57,4 +60,87 @@
return cause + ": " + result;
}
+static void QuotePath(const string& path, string* result) {
+ *result = string("\"") + path + "\"";
+}
+
+string AsExecutablePathForCreateProcess(const string& path,
+ function<wstring()> path_as_wstring,
+ string* result) {
+ if (path.empty()) {
+ return string("argv[0] should not be empty");
+ }
+ if (path[0] == '"') {
+ return string("argv[0] 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.");
+ }
+ // 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).
+
+ // Fast-track: the path is already short.
+ if (path.size() < MAX_PATH) {
+ // Quote the path in case it's something like "c:\foo\app name.exe".
+ // Do this unconditionally, there's no harm in quoting. Quotes are not
+ // allowed inside paths so we don't need to escape quotes.
+ QuotePath(path, result);
+ return "";
+ }
+ // At this point we know that the path is at least MAX_PATH long and that it's
+ // absolute, normalized, and Windows-style.
+
+ // Retrieve string as UTF-16 path, add "\\?\" prefix.
+ wstring wlong = wstring(L"\\\\?\\") + path_as_wstring();
+
+ // Experience shows that:
+ // - GetShortPathNameW's result has a "\\?\" prefix if and only if the input
+ // did too (though this behavior is not documented on MSDN)
+ // - CreateProcess{A,W} only accept an executable of MAX_PATH - 1 length
+ // Therefore for our purposes the acceptable shortened length is
+ // MAX_PATH + 4 (null-terminated). That is, MAX_PATH - 1 for the shortened
+ // path, plus a potential "\\?\" prefix that's only there if `wlong` also had
+ // it and which we'll omit from `result`, plus a null terminator.
+ static const size_t kMaxShortPath = MAX_PATH + 4;
+
+ WCHAR wshort[kMaxShortPath];
+ DWORD wshort_size = ::GetShortPathNameW(wlong.c_str(), NULL, 0);
+ if (wshort_size == 0) {
+ return windows_util::GetLastErrorString(
+ string("GetShortPathName failed (path=") + path + ")");
+ }
+
+ if (wshort_size >= kMaxShortPath) {
+ return windows_util::GetLastErrorString(
+ string("GetShortPathName would not shorten the path enough (path=") +
+ path + ")");
+ }
+
+ // Convert the result to UTF-8.
+ char mbs_short[MAX_PATH];
+ size_t mbs_size = wcstombs(
+ mbs_short,
+ wshort + 4, // we know it has a "\\?\" prefix, because `wlong` also did
+ MAX_PATH);
+ if (mbs_size < 0 || mbs_size >= MAX_PATH) {
+ return string("wcstombs failed (path=") + path + ")";
+ }
+ mbs_short[mbs_size - 1] = 0;
+
+ QuotePath(mbs_short, result);
+ return "";
+}
+
} // namespace windows_util
diff --git a/src/main/native/windows_util.h b/src/main/native/windows_util.h
index 8af07bb..127bb97 100644
--- a/src/main/native/windows_util.h
+++ b/src/main/native/windows_util.h
@@ -19,16 +19,49 @@
#include <jni.h>
+#include <functional>
#include <memory>
#include <string>
namespace windows_util {
+using std::function;
using std::string;
using std::unique_ptr;
+using std::wstring;
string GetLastErrorString(const string& cause);
+// Computes a path suitable as the executable part in CreateProcessA's cmdline.
+//
+// The null-terminated executable path for CreateProcessA has to fit into
+// MAX_PATH, therefore the limit for the executable's path is MAX_PATH - 1
+// (not including null terminator). This method attempts to convert the input
+// `path` to a short format to fit it into the MAX_PATH - 1 limit.
+//
+// `path` must be either an absolute, normalized, Windows-style path with drive
+// letter (e.g. "c:\foo\bar.exe", but no "\foo\bar.exe"), or must be just a file
+// name (e.g. "cmd.exe") that's shorter than MAX_PATH (without null-terminator).
+// In both cases, `path` must be unquoted.
+//
+// `path_as_wstring` must be a function that retrieves `path` as (or converts it
+// to) a wstring, without performing any transformations on the path.
+//
+// If this function succeeds, it returns an empty string (indicating no error),
+// and sets `result` to the resulting path, which is always quoted, and is
+// always at most MAX_PATH + 1 long (MAX_PATH - 1 without null terminator, plus
+// two quotes). If there's any error, this function returns the error message.
+//
+// If `path` is at most MAX_PATH - 1 long (not including null terminator), the
+// result will be that (plus quotes).
+// Otherwise this method attempts to compute an 8dot3 style short name for
+// `path`, and if that succeeds and the result is at most MAX_PATH - 1 long (not
+// including null terminator), then that will be the result (plus quotes).
+// Otherwise this function fails and returns an error message.
+string AsExecutablePathForCreateProcess(const string& path,
+ function<wstring()> path_as_wstring,
+ string* result);
+
} // namespace windows_util
#endif // BAZEL_SRC_MAIN_NATIVE_WINDOWS_UTIL_H__