You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by jo...@apache.org on 2017/04/04 23:53:39 UTC
[11/13] mesos git commit: Windows: Stout: Reimplemented
`stringify_args`.
Windows: Stout: Reimplemented `stringify_args`.
This was an unused function that ended up being the correct place to
implement proper `argv` concatenation and escaping. It returns a
`std::wstring` for use (speifically) by `::CreateProcessW`. This brings
us a bit closer to Unicode support within Mesos.
Review: https://reviews.apache.org/r/58126/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/bce6c05c
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/bce6c05c
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/bce6c05c
Branch: refs/heads/master
Commit: bce6c05c7c84e4b93881dd9780fe724197f62520
Parents: 718d3c9
Author: Andrew Schwartzmeyer <an...@schwartzmeyer.com>
Authored: Tue Apr 4 13:25:09 2017 -0700
Committer: Joseph Wu <jo...@apache.org>
Committed: Tue Apr 4 16:45:17 2017 -0700
----------------------------------------------------------------------
.../stout/include/stout/os/windows/shell.hpp | 75 ++++++++++++++++----
1 file changed, 61 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/bce6c05c/3rdparty/stout/include/stout/os/windows/shell.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/windows/shell.hpp b/3rdparty/stout/include/stout/os/windows/shell.hpp
index fdce93c..b93f337 100644
--- a/3rdparty/stout/include/stout/os/windows/shell.hpp
+++ b/3rdparty/stout/include/stout/os/windows/shell.hpp
@@ -170,22 +170,69 @@ inline int execvpe(const char* file, char* const argv[], char* const envp[])
// Concatenates multiple command-line arguments and escapes the values.
-// If `arg` is not specified (or takes the value `0`), the function will
-// scan `argv` until a `nullptr` is encountered.
-inline std::string stringify_args(char** argv, unsigned long argc = 0)
+// NOTE: This is necessary even when using Windows APIs that "appear"
+// to take arguments as a list, because those APIs will themselves
+// concatenate command-line arguments *without* escaping them.
+//
+// This function escapes arguments with the following rules:
+// 1) Any argument with a space, tab, newline, vertical tab,
+// or double-quote must be surrounded in double-quotes.
+// 2) Backslashes at the very end of an argument must be escaped.
+// 3) Backslashes that precede a double-quote must be escaped.
+// The double-quote must also be escaped.
+//
+// NOTE: The below algorithm is adapted from Daniel Colascione's public domain
+// algorithm for quoting command line arguments on Windows for `CreateProcess`.
+//
+// https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
+// NOLINT(whitespace/line_length)
+inline std::wstring stringify_args(const std::vector<std::string>& argv)
{
- std::string arg_line = "";
- unsigned long index = 0;
- while ((argc == 0 || index < argc) && argv[index] != nullptr) {
- // TODO(dpravat): (MESOS-5522) Format these args for all cases.
- // Specifically, we need to:
- // (1) Add double quotes around arguments that contain special
- // characters, like spaces and tabs.
- // (2) Escape any existing double quotes and backslashes.
- arg_line = strings::join(" ", arg_line, argv[index++]);
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
+ std::wstring command;
+ for (auto argit = argv.cbegin(); argit != argv.cend(); ++argit) {
+ std::wstring arg = converter.from_bytes(*argit);
+ // Don't quote empty arguments or those without troublesome characters.
+ if (!arg.empty() && arg.find_first_of(L" \t\n\v\"") == arg.npos) {
+ command.append(arg);
+ } else {
+ // Beginning double quotation mark.
+ command.push_back(L'"');
+ for (auto it = arg.cbegin(); it != arg.cend(); ++it) {
+ // Count existent backslashes in argument.
+ unsigned int backslashes = 0;
+ while (it != arg.cend() && *it == L'\\') {
+ ++it;
+ ++backslashes;
+ }
+
+ if (it == arg.cend()) {
+ // Escape all backslashes, but let the terminating double quotation
+ // mark we add below be interpreted as a metacharacter.
+ command.append(backslashes * 2, L'\\');
+ break;
+ } else if (*it == L'"') {
+ // Escape all backslashes and the following double quotation mark.
+ command.append(backslashes * 2 + 1, L'\\');
+ command.push_back(*it);
+ } else {
+ // Backslashes aren't special here.
+ command.append(backslashes, L'\\');
+ command.push_back(*it);
+ }
+ }
+
+ // Terminating double quotation mark.
+ command.push_back(L'"');
+ }
+ // Space separate arguments (but don't append at end).
+ if (argit != argv.cend() - 1) {
+ command.push_back(L' ');
+ }
}
-
- return arg_line;
+ // Append final null terminating character.
+ command.push_back(L'\0');
+ return command;
}
} // namespace os {