Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |