Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: chrome/installer/mini_installer/mini_installer.cc

Issue 2655473002: Handle spaces in the name of the mini_installer. (Closed)
Patch Set: rewrite with tests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // mini_installer.exe is the first exe that is run when chrome is being 5 // mini_installer.exe is the first exe that is run when chrome is being
6 // installed or upgraded. It is designed to be extremely small (~5KB with no 6 // installed or upgraded. It is designed to be extremely small (~5KB with no
7 // extra resources linked) and it has two main jobs: 7 // extra resources linked) and it has two main jobs:
8 // 1) unpack the resources (possibly decompressing some) 8 // 1) unpack the resources (possibly decompressing some)
9 // 2) run the real installer (setup.exe) with appropriate flags. 9 // 2) run the real installer (setup.exe) with appropriate flags.
10 // 10 //
(...skipping 23 matching lines...) Expand all
34 34
35 #include <sddl.h> 35 #include <sddl.h>
36 #include <shellapi.h> 36 #include <shellapi.h>
37 #include <stdlib.h> 37 #include <stdlib.h>
38 #include <stddef.h> 38 #include <stddef.h>
39 39
40 #include "chrome/installer/mini_installer/appid.h" 40 #include "chrome/installer/mini_installer/appid.h"
41 #include "chrome/installer/mini_installer/configuration.h" 41 #include "chrome/installer/mini_installer/configuration.h"
42 #include "chrome/installer/mini_installer/decompress.h" 42 #include "chrome/installer/mini_installer/decompress.h"
43 #include "chrome/installer/mini_installer/mini_installer_constants.h" 43 #include "chrome/installer/mini_installer/mini_installer_constants.h"
44 #include "chrome/installer/mini_installer/mini_string.h"
45 #include "chrome/installer/mini_installer/pe_resource.h" 44 #include "chrome/installer/mini_installer/pe_resource.h"
46 #include "chrome/installer/mini_installer/regkey.h" 45 #include "chrome/installer/mini_installer/regkey.h"
47 46
48 namespace mini_installer { 47 namespace mini_installer {
49 48
50 typedef StackString<MAX_PATH> PathString; 49 typedef StackString<MAX_PATH> PathString;
51 typedef StackString<MAX_PATH * 4> CommandString;
52 50
53 // This structure passes data back and forth for the processing 51 // This structure passes data back and forth for the processing
54 // of resource callbacks. 52 // of resource callbacks.
55 struct Context { 53 struct Context {
56 // Input to the call back method. Specifies the dir to save resources. 54 // Input to the call back method. Specifies the dir to save resources.
57 const wchar_t* base_path; 55 const wchar_t* base_path;
58 // First output from call back method. Full path of Chrome archive. 56 // First output from call back method. Full path of Chrome archive.
59 PathString* chrome_resource_path; 57 PathString* chrome_resource_path;
60 // Second output from call back method. Full path of Setup archive/exe. 58 // Second output from call back method. Full path of Setup archive/exe.
61 PathString* setup_resource_path; 59 PathString* setup_resource_path;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 // could return a different object but since we never spawn more than one 210 // could return a different object but since we never spawn more than one
213 // sub-process at a time that case should never happen. 211 // sub-process at a time that case should never happen.
214 return ProcessExitResult(WAIT_FOR_PROCESS_FAILED, ::GetLastError()); 212 return ProcessExitResult(WAIT_FOR_PROCESS_FAILED, ::GetLastError());
215 } 213 }
216 214
217 ::CloseHandle(pi.hProcess); 215 ::CloseHandle(pi.hProcess);
218 216
219 return ProcessExitResult(exit_code); 217 return ProcessExitResult(exit_code);
220 } 218 }
221 219
222 // Appends any command line params passed to mini_installer to the given buffer 220 void AppendCommandLineFlags(const wchar_t* command_line,
223 // so that they can be passed on to setup.exe.
224 // |buffer| is unchanged in case of error.
225 void AppendCommandLineFlags(const Configuration& configuration,
226 CommandString* buffer) { 221 CommandString* buffer) {
227 PathString full_exe_path; 222 // The program name (the first argument parsed by CommandLineToArgvW) is
228 size_t len = ::GetModuleFileName( 223 // delimited by whitespace or a double quote based on the first character of
229 NULL, full_exe_path.get(), static_cast<DWORD>(full_exe_path.capacity())); 224 // the full command line string. Use the same logic here to scan past the
230 if (!len || len >= full_exe_path.capacity()) 225 // program name in the program's command line (obtained during startup from
226 // GetCommandLine).
227 wchar_t a_char = 0;
228 if (*command_line == L'"') {
bcwhite 2017/01/27 14:52:24 Would a single-quote also be valid here?
grt (UTC plus 2) 2017/01/27 15:31:38 No.
229 // Scan forward past the closing double quote.
230 ++command_line;
231 while (true) {
232 a_char = *command_line;
233 if (!a_char)
234 break;
235 ++command_line;
236 if (a_char == L'"') {
bcwhite 2017/01/27 14:52:23 Crazy though it may be, it's valid for a user to t
grt (UTC plus 2) 2017/01/27 15:31:38 The Win32 ::CommandLineToArgvW turns that into thi
237 a_char = *command_line;
238 break;
239 }
240 } // postcondition: |a_char| contains the character at *command_line.
241 } else {
242 // Scan forward for the first space or tab character.
243 while (true) {
244 a_char = *command_line;
245 if (!a_char || a_char == L' ' || a_char == L'\t')
246 break;
247 ++command_line;
248 } // postcondition: |a_char| contains the character at *command_line.
249 }
250
251 if (!a_char)
231 return; 252 return;
232 253
233 const wchar_t* exe_name = 254 // Append a space if |command_line| doesn't begin with one.
234 GetNameFromPathExt(full_exe_path.get(), static_cast<DWORD>(len)); 255 if (a_char != ' ' && a_char != '\t' && !buffer->append(L" "))
235
236 // - configuration.program() returns the first command line argument
237 // passed into the program (that the user probably typed in this case).
238 // "mini_installer.exe"
239 // "mini_installer"
240 // "out\Release\mini_installer"
241 // - |exe_name| is the executable file of the current process.
242 // "mini_installer.exe"
243 //
244 // Note that there are three possibilities to handle here.
245 // Receive a cmdline containing:
246 // 1) executable name WITH extension
247 // 2) executable name with NO extension
248 // 3) NO executable name as part of cmdline
249 const wchar_t* cmd_to_append = L"";
250 const wchar_t* arg0 = configuration.program();
251 if (!arg0)
252 return; 256 return;
253 const wchar_t* arg0_base_name = GetNameFromPathExt(arg0, ::lstrlen(arg0)); 257 buffer->append(command_line);
254 if (!StrStartsWith(exe_name, arg0_base_name)) {
255 // State 3: NO executable name as part of cmdline.
256 buffer->append(L" ");
257 cmd_to_append = configuration.command_line();
258 } else if (configuration.argument_count() > 1) {
259 // State 1 or 2: Executable name is in cmdline.
260 // - Append everything AFTER the executable name.
261 // (Using arg0_base_name here to make sure to match with or without
262 // extension. Then move to the space following the token.)
263 const wchar_t* tmp = SearchStringI(configuration.command_line(),
264 arg0_base_name);
265 tmp = SearchStringI(tmp, L" ");
266 cmd_to_append = tmp;
267 }
268
269 buffer->append(cmd_to_append);
270 } 258 }
271 259
272
273 // Windows defined callback used in the EnumResourceNames call. For each 260 // Windows defined callback used in the EnumResourceNames call. For each
274 // matching resource found, the callback is invoked and at this point we write 261 // matching resource found, the callback is invoked and at this point we write
275 // it to disk. We expect resource names to start with 'chrome' or 'setup'. Any 262 // it to disk. We expect resource names to start with 'chrome' or 'setup'. Any
276 // other name is treated as an error. 263 // other name is treated as an error.
277 BOOL CALLBACK OnResourceFound(HMODULE module, const wchar_t* type, 264 BOOL CALLBACK OnResourceFound(HMODULE module, const wchar_t* type,
278 wchar_t* name, LONG_PTR context) { 265 wchar_t* name, LONG_PTR context) {
279 if (NULL == context) 266 if (NULL == context)
280 return FALSE; 267 return FALSE;
281 268
282 Context* ctx = reinterpret_cast<Context*>(context); 269 Context* ctx = reinterpret_cast<Context*>(context);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 !cmd_line.append(kCmdNewSetupExe) || 374 !cmd_line.append(kCmdNewSetupExe) ||
388 !cmd_line.append(L"=\"") || 375 !cmd_line.append(L"=\"") ||
389 !cmd_line.append(setup_dest_path.get()) || 376 !cmd_line.append(setup_dest_path.get()) ||
390 !cmd_line.append(L"\"")) { 377 !cmd_line.append(L"\"")) {
391 exit_code = ProcessExitResult(COMMAND_STRING_OVERFLOW); 378 exit_code = ProcessExitResult(COMMAND_STRING_OVERFLOW);
392 } 379 }
393 } 380 }
394 381
395 // Get any command line option specified for mini_installer and pass them 382 // Get any command line option specified for mini_installer and pass them
396 // on to setup.exe. 383 // on to setup.exe.
397 AppendCommandLineFlags(configuration, &cmd_line); 384 AppendCommandLineFlags(configuration.command_line(), &cmd_line);
398 385
399 if (exit_code.IsSuccess()) 386 if (exit_code.IsSuccess())
400 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); 387 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get());
401 388
402 if (!exit_code.IsSuccess()) 389 if (!exit_code.IsSuccess())
403 DeleteFile(setup_path->get()); 390 DeleteFile(setup_path->get());
404 else if (!setup_path->assign(setup_dest_path.get())) 391 else if (!setup_path->assign(setup_dest_path.get()))
405 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); 392 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW);
406 393
407 return exit_code; 394 return exit_code;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 (!cmd_line.append(L" --") || 473 (!cmd_line.append(L" --") ||
487 !cmd_line.append(kCmdPreviousVersion) || 474 !cmd_line.append(kCmdPreviousVersion) ||
488 !cmd_line.append(L"=\"") || 475 !cmd_line.append(L"=\"") ||
489 !cmd_line.append(configuration.previous_version()) || 476 !cmd_line.append(configuration.previous_version()) ||
490 !cmd_line.append(L"\""))) { 477 !cmd_line.append(L"\""))) {
491 return ProcessExitResult(COMMAND_STRING_OVERFLOW); 478 return ProcessExitResult(COMMAND_STRING_OVERFLOW);
492 } 479 }
493 480
494 // Get any command line option specified for mini_installer and pass them 481 // Get any command line option specified for mini_installer and pass them
495 // on to setup.exe 482 // on to setup.exe
496 AppendCommandLineFlags(configuration, &cmd_line); 483 AppendCommandLineFlags(configuration.command_line(), &cmd_line);
497 484
498 return RunProcessAndWait(NULL, cmd_line.get()); 485 return RunProcessAndWait(NULL, cmd_line.get());
499 } 486 }
500 487
501 // Deletes given files and working dir. 488 // Deletes given files and working dir.
502 void DeleteExtractedFiles(const wchar_t* base_path, 489 void DeleteExtractedFiles(const wchar_t* base_path,
503 const wchar_t* archive_path, 490 const wchar_t* archive_path,
504 const wchar_t* setup_path) { 491 const wchar_t* setup_path) {
505 ::DeleteFile(archive_path); 492 ::DeleteFile(archive_path);
506 ::DeleteFile(setup_path); 493 ::DeleteFile(setup_path);
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
865 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); 852 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get());
866 853
867 #if defined(GOOGLE_CHROME_BUILD) 854 #if defined(GOOGLE_CHROME_BUILD)
868 WriteInstallResults(configuration, exit_code); 855 WriteInstallResults(configuration, exit_code);
869 #endif 856 #endif
870 857
871 return exit_code; 858 return exit_code;
872 } 859 }
873 860
874 } // namespace mini_installer 861 } // namespace mini_installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698