diff --git a/atom/browser/relauncher.cc b/atom/browser/relauncher.cc index 5362a7b78aef..9610d80693b1 100644 --- a/atom/browser/relauncher.cc +++ b/atom/browser/relauncher.cc @@ -12,7 +12,6 @@ #include "base/logging.h" #include "base/path_service.h" #include "base/process/launch.h" -#include "base/strings/string_util.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" @@ -100,7 +99,7 @@ bool RelaunchAppWithHelper(const base::FilePath& helper, base::Process process = base::LaunchProcess(relaunch_argv, options); #elif defined(OS_WIN) base::Process process = base::LaunchProcess( - base::JoinString(relaunch_argv, L" "), options); + internal::ArgvToCommandLineString(relaunch_argv), options); #endif if (!process.IsValid()) { LOG(ERROR) << "base::LaunchProcess failed"; diff --git a/atom/browser/relauncher.h b/atom/browser/relauncher.h index c19557b330c9..10f2e5128795 100644 --- a/atom/browser/relauncher.h +++ b/atom/browser/relauncher.h @@ -100,6 +100,8 @@ extern const CharType* kRelauncherArgSeparator; #if defined(OS_WIN) StringType GetWaitEventName(base::ProcessId pid); + +StringType ArgvToCommandLineString(const StringVector& argv); #endif // In the relauncher process, performs the necessary synchronization steps diff --git a/atom/browser/relauncher_win.cc b/atom/browser/relauncher_win.cc index 1a122782a246..1aebb515ecf0 100644 --- a/atom/browser/relauncher_win.cc +++ b/atom/browser/relauncher_win.cc @@ -7,7 +7,6 @@ #include #include "base/process/launch.h" -#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/win/scoped_handle.h" #include "sandbox/win/src/nt_internals.h" @@ -43,12 +42,64 @@ HANDLE GetParentProcessHandle(base::ProcessHandle handle) { pbi.InheritedFromUniqueProcessId); } +StringType AddQuoteForArg(const StringType& arg) { + // We follow the quoting rules of CommandLineToArgvW. + // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx + std::wstring quotable_chars(L" \\\""); + if (arg.find_first_of(quotable_chars) == std::wstring::npos) { + // No quoting necessary. + return arg; + } + + std::wstring out; + out.push_back(L'"'); + for (size_t i = 0; i < arg.size(); ++i) { + if (arg[i] == '\\') { + // Find the extent of this run of backslashes. + size_t start = i, end = start + 1; + for (; end < arg.size() && arg[end] == '\\'; ++end) {} + size_t backslash_count = end - start; + + // Backslashes are escapes only if the run is followed by a double quote. + // Since we also will end the string with a double quote, we escape for + // either a double quote or the end of the string. + if (end == arg.size() || arg[end] == '"') { + // To quote, we need to output 2x as many backslashes. + backslash_count *= 2; + } + for (size_t j = 0; j < backslash_count; ++j) + out.push_back('\\'); + + // Advance i to one before the end to balance i++ in loop. + i = end - 1; + } else if (arg[i] == '"') { + out.push_back('\\'); + out.push_back('"'); + } else { + out.push_back(arg[i]); + } + } + out.push_back('"'); + + return out; +} + } // namespace StringType GetWaitEventName(base::ProcessId pid) { return base::StringPrintf(L"%s-%d", kWaitEventName, static_cast(pid)); } +StringType ArgvToCommandLineString(const StringVector& argv) { + StringType command_line; + for (const StringType& arg : argv) { + if (!command_line.empty()) + command_line += L' '; + command_line += AddQuoteForArg(arg); + } + return command_line; +} + void RelauncherSynchronizeWithParent() { base::Process process = base::Process::Current(); base::win::ScopedHandle parent_process( @@ -68,7 +119,7 @@ int LaunchProgram(const StringVector& relauncher_args, const StringVector& argv) { base::LaunchOptions options; base::Process process = - base::LaunchProcess(base::JoinString(argv, L" "), options); + base::LaunchProcess(ArgvToCommandLineString(argv), options); return process.IsValid() ? 0 : 1; }