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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 | 52 |
| 53 // This structure passes data back and forth for the processing | 53 // This structure passes data back and forth for the processing |
| 54 // of resource callbacks. | 54 // of resource callbacks. |
| 55 struct Context { | 55 struct Context { |
| 56 // Input to the call back method. Specifies the dir to save resources. | 56 // Input to the call back method. Specifies the dir to save resources. |
| 57 const wchar_t* base_path; | 57 const wchar_t* base_path; |
| 58 // First output from call back method. Full path of Chrome archive. | 58 // First output from call back method. Full path of Chrome archive. |
| 59 PathString* chrome_resource_path; | 59 PathString* chrome_resource_path; |
| 60 // Second output from call back method. Full path of Setup archive/exe. | 60 // Second output from call back method. Full path of Setup archive/exe. |
| 61 PathString* setup_resource_path; | 61 PathString* setup_resource_path; |
| 62 #if defined(SYZYASAN) | |
| 63 PathString* syzyasan_resource_path; | |
| 64 #endif | |
| 62 }; | 65 }; |
| 63 | 66 |
| 64 // TODO(grt): Frame this in terms of whether or not the brand supports | 67 // TODO(grt): Frame this in terms of whether or not the brand supports |
| 65 // integation with Omaha, where Google Update is the Google-specific fork of | 68 // integation with Omaha, where Google Update is the Google-specific fork of |
| 66 // the open-source Omaha project. | 69 // the open-source Omaha project. |
| 67 #if defined(GOOGLE_CHROME_BUILD) | 70 #if defined(GOOGLE_CHROME_BUILD) |
| 68 // Opens the Google Update ClientState key. If |binaries| is false, opens the | 71 // Opens the Google Update ClientState key. If |binaries| is false, opens the |
| 69 // key for Google Chrome or Chrome SxS (canary). If |binaries| is true and an | 72 // key for Google Chrome or Chrome SxS (canary). If |binaries| is true and an |
| 70 // existing multi-install Chrome is being updated, opens the key for the | 73 // existing multi-install Chrome is being updated, opens the key for the |
| 71 // multi-install binaries; otherwise, returns false. | 74 // multi-install binaries; otherwise, returns false. |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 284 !full_path.append(name) || | 287 !full_path.append(name) || |
| 285 !resource.WriteToDisk(full_path.get())) | 288 !resource.WriteToDisk(full_path.get())) |
| 286 return FALSE; | 289 return FALSE; |
| 287 | 290 |
| 288 if (StrStartsWith(name, kChromeArchivePrefix)) { | 291 if (StrStartsWith(name, kChromeArchivePrefix)) { |
| 289 if (!ctx->chrome_resource_path->assign(full_path.get())) | 292 if (!ctx->chrome_resource_path->assign(full_path.get())) |
| 290 return FALSE; | 293 return FALSE; |
| 291 } else if (StrStartsWith(name, kSetupPrefix)) { | 294 } else if (StrStartsWith(name, kSetupPrefix)) { |
| 292 if (!ctx->setup_resource_path->assign(full_path.get())) | 295 if (!ctx->setup_resource_path->assign(full_path.get())) |
| 293 return FALSE; | 296 return FALSE; |
| 297 #if defined(SYZYASAN) | |
| 298 } else if (StrStartsWith(name, kSyzyAsanRuntimePrefix)) { | |
| 299 if (!ctx->syzyasan_resource_path->assign(full_path.get())) | |
| 300 return FALSE; | |
| 301 #endif | |
| 294 } else { | 302 } else { |
| 295 // Resources should either start with 'chrome' or 'setup'. We don't handle | 303 // Resources should either start with 'chrome' or 'setup'. We don't handle |
| 296 // anything else. | 304 // anything else. |
| 297 return FALSE; | 305 return FALSE; |
| 298 } | 306 } |
| 299 | 307 |
| 300 return TRUE; | 308 return TRUE; |
| 301 } | 309 } |
| 302 | 310 |
| 303 #if defined(COMPONENT_BUILD) | 311 #if defined(COMPONENT_BUILD) || defined(SYZYASAN) |
| 304 // An EnumResNameProc callback that writes the resource |name| to disk in the | 312 // An EnumResNameProc callback that writes the resource |name| to disk in the |
| 305 // directory |base_path_ptr| (which must end with a path separator). | 313 // directory |base_path_ptr| (which must end with a path separator). |
| 306 BOOL CALLBACK WriteResourceToDirectory(HMODULE module, | 314 BOOL CALLBACK WriteResourceToDirectory(HMODULE module, |
| 307 const wchar_t* type, | 315 const wchar_t* type, |
| 308 wchar_t* name, | 316 wchar_t* name, |
| 309 LONG_PTR base_path_ptr) { | 317 LONG_PTR base_path_ptr) { |
| 310 const wchar_t* base_path = reinterpret_cast<const wchar_t*>(base_path_ptr); | 318 const wchar_t* base_path = reinterpret_cast<const wchar_t*>(base_path_ptr); |
| 311 PathString full_path; | 319 PathString full_path; |
| 312 | 320 |
| 313 PEResource resource(name, type, module); | 321 PEResource resource(name, type, module); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 324 // - Resource type 'B7', compressed using LZMA (*.7z) | 332 // - Resource type 'B7', compressed using LZMA (*.7z) |
| 325 // - Resource type 'BL', compressed using LZ (*.ex_) | 333 // - Resource type 'BL', compressed using LZ (*.ex_) |
| 326 // - Resource type 'BN', uncompressed (*.exe) | 334 // - Resource type 'BN', uncompressed (*.exe) |
| 327 // If setup.exe is present in more than one form, the precedence order is | 335 // If setup.exe is present in more than one form, the precedence order is |
| 328 // BN < BL < B7 | 336 // BN < BL < B7 |
| 329 // For more details see chrome/tools/build/win/create_installer_archive.py. | 337 // For more details see chrome/tools/build/win/create_installer_archive.py. |
| 330 // For component builds (where setup.ex_ is always used), all files stored as | 338 // For component builds (where setup.ex_ is always used), all files stored as |
| 331 // uncompressed 'BN' resources are also extracted. This is generally the set of | 339 // uncompressed 'BN' resources are also extracted. This is generally the set of |
| 332 // DLLs/resources needed by setup.exe to run. | 340 // DLLs/resources needed by setup.exe to run. |
| 333 ProcessExitResult UnpackBinaryResources(const Configuration& configuration, | 341 ProcessExitResult UnpackBinaryResources(const Configuration& configuration, |
| 334 HMODULE module, const wchar_t* base_path, | 342 HMODULE module, |
| 335 PathString* archive_path, | 343 Context* context) { |
| 336 PathString* setup_path) { | |
| 337 // Generate the setup.exe path where we patch/uncompress setup resource. | 344 // Generate the setup.exe path where we patch/uncompress setup resource. |
| 338 PathString setup_dest_path; | 345 PathString setup_dest_path; |
| 339 if (!setup_dest_path.assign(base_path) || | 346 if (!setup_dest_path.assign(context->base_path) || |
| 340 !setup_dest_path.append(kSetupExe)) | 347 !setup_dest_path.append(kSetupExe)) |
| 341 return ProcessExitResult(PATH_STRING_OVERFLOW); | 348 return ProcessExitResult(PATH_STRING_OVERFLOW); |
| 342 | 349 |
| 343 // Prepare the input to OnResourceFound method that needs a location where | |
| 344 // it will write all the resources. | |
| 345 Context context = { | |
| 346 base_path, | |
| 347 archive_path, | |
| 348 setup_path, | |
| 349 }; | |
| 350 | |
| 351 // Get the resources of type 'B7' (7zip archive). | 350 // Get the resources of type 'B7' (7zip archive). |
| 352 // We need a chrome archive to do the installation. So if there | 351 // We need a chrome archive to do the installation. So if there |
| 353 // is a problem in fetching B7 resource, just return an error. | 352 // is a problem in fetching B7 resource, just return an error. |
| 354 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, | 353 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, |
| 355 reinterpret_cast<LONG_PTR>(&context))) { | 354 reinterpret_cast<LONG_PTR>(context))) { |
| 356 return ProcessExitResult(UNABLE_TO_EXTRACT_CHROME_ARCHIVE, | 355 return ProcessExitResult(UNABLE_TO_EXTRACT_CHROME_ARCHIVE, |
| 357 ::GetLastError()); | 356 ::GetLastError()); |
| 358 } | 357 } |
| 359 if (archive_path->length() == 0) { | 358 if (context->chrome_resource_path->length() == 0) { |
| 360 return ProcessExitResult(UNABLE_TO_EXTRACT_CHROME_ARCHIVE); | 359 return ProcessExitResult(UNABLE_TO_EXTRACT_CHROME_ARCHIVE); |
| 361 } | 360 } |
| 362 | 361 |
| 363 ProcessExitResult exit_code = ProcessExitResult(SUCCESS_EXIT_CODE); | 362 ProcessExitResult exit_code = ProcessExitResult(SUCCESS_EXIT_CODE); |
| 364 | 363 |
| 365 // If we found setup 'B7' resource (used for differential updates), handle | 364 // If we found setup 'B7' resource (used for differential updates), handle |
| 366 // it. Note that this is only for Chrome; Chromium installs are always | 365 // it. Note that this is only for Chrome; Chromium installs are always |
| 367 // "full" installs. | 366 // "full" installs. |
| 368 if (setup_path->length() > 0) { | 367 if (context->setup_resource_path->length() > 0) { |
| 369 CommandString cmd_line; | 368 CommandString cmd_line; |
| 370 PathString exe_path; | 369 PathString exe_path; |
| 371 // Get the path to setup.exe first. | 370 // Get the path to setup.exe first. |
| 372 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), | 371 exit_code = GetPreviousSetupExePath(configuration, exe_path.get(), |
| 373 exe_path.capacity()); | 372 exe_path.capacity()); |
| 374 if (exit_code.IsSuccess()) { | 373 if (exit_code.IsSuccess()) { |
| 375 if (!cmd_line.append(exe_path.get()) || | 374 if (!cmd_line.append(exe_path.get()) || !cmd_line.append(L" --") || |
| 376 !cmd_line.append(L" --") || | 375 !cmd_line.append(kCmdUpdateSetupExe) || !cmd_line.append(L"=\"") || |
| 377 !cmd_line.append(kCmdUpdateSetupExe) || | 376 !cmd_line.append(context->setup_resource_path->get()) || |
| 378 !cmd_line.append(L"=\"") || | 377 !cmd_line.append(L"\" --") || !cmd_line.append(kCmdNewSetupExe) || |
| 379 !cmd_line.append(setup_path->get()) || | 378 !cmd_line.append(L"=\"") || !cmd_line.append(setup_dest_path.get()) || |
| 380 !cmd_line.append(L"\" --") || | |
| 381 !cmd_line.append(kCmdNewSetupExe) || | |
| 382 !cmd_line.append(L"=\"") || | |
| 383 !cmd_line.append(setup_dest_path.get()) || | |
| 384 !cmd_line.append(L"\"")) { | 379 !cmd_line.append(L"\"")) { |
| 385 exit_code = ProcessExitResult(COMMAND_STRING_OVERFLOW); | 380 exit_code = ProcessExitResult(COMMAND_STRING_OVERFLOW); |
| 386 } | 381 } |
| 387 } | 382 } |
| 388 | 383 |
| 389 // Get any command line option specified for mini_installer and pass them | 384 // Get any command line option specified for mini_installer and pass them |
| 390 // on to setup.exe. | 385 // on to setup.exe. |
| 391 AppendCommandLineFlags(configuration.command_line(), &cmd_line); | 386 AppendCommandLineFlags(configuration.command_line(), &cmd_line); |
| 392 | 387 |
| 393 if (exit_code.IsSuccess()) | 388 if (exit_code.IsSuccess()) |
| 394 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); | 389 exit_code = RunProcessAndWait(exe_path.get(), cmd_line.get()); |
| 395 | 390 |
| 396 if (!exit_code.IsSuccess()) | 391 if (!exit_code.IsSuccess()) |
| 397 DeleteFile(setup_path->get()); | 392 DeleteFile(context->setup_resource_path->get()); |
| 398 else if (!setup_path->assign(setup_dest_path.get())) | 393 else if (!context->setup_resource_path->assign(setup_dest_path.get())) |
| 399 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); | 394 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); |
| 400 | 395 |
| 401 return exit_code; | 396 return exit_code; |
| 402 } | 397 } |
| 403 | 398 |
| 404 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' | 399 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' |
| 405 // (compressed setup). | 400 // (compressed setup). |
| 406 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, | 401 if (!::EnumResourceNames(module, kLZCResourceType, OnResourceFound, |
| 407 reinterpret_cast<LONG_PTR>(&context))) { | 402 reinterpret_cast<LONG_PTR>(context))) { |
| 408 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_BL, ::GetLastError()); | 403 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_BL, ::GetLastError()); |
| 409 } | 404 } |
| 410 if (setup_path->length() == 0) { | 405 if (context->setup_resource_path->length() == 0) { |
| 411 // Neither setup_patch.packed.7z nor setup.ex_ was found. | 406 // Neither setup_patch.packed.7z nor setup.ex_ was found. |
| 412 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP); | 407 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP); |
| 413 } | 408 } |
| 414 | 409 |
| 415 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' | 410 // Uncompress LZ compressed resource. Setup is packed with 'MSCF' |
| 416 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. | 411 // as opposed to old DOS way of 'SZDD'. Hence we don't use LZCopy. |
| 417 bool success = | 412 bool success = mini_installer::Expand(context->setup_resource_path->get(), |
| 418 mini_installer::Expand(setup_path->get(), setup_dest_path.get()); | 413 setup_dest_path.get()); |
| 419 ::DeleteFile(setup_path->get()); | 414 ::DeleteFile(context->setup_resource_path->get()); |
| 420 if (success) { | 415 if (success) { |
| 421 if (!setup_path->assign(setup_dest_path.get())) { | 416 if (!context->setup_resource_path->assign(setup_dest_path.get())) { |
| 422 ::DeleteFile(setup_dest_path.get()); | 417 ::DeleteFile(setup_dest_path.get()); |
| 423 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); | 418 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); |
| 424 } | 419 } |
| 425 } else { | 420 } else { |
| 426 exit_code = ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_EXE); | 421 exit_code = ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_EXE); |
| 427 } | 422 } |
| 428 | 423 |
| 424 #if defined(SYZYASAN) | |
| 425 PathString syzyasan_dest_path; | |
| 426 if (!syzyasan_dest_path.assign(context->base_path) || | |
| 427 !syzyasan_dest_path.append(L"syzyasan_rtl.dll")) { | |
| 428 return ProcessExitResult(PATH_STRING_OVERFLOW); | |
| 429 } | |
| 430 success = mini_installer::Expand(context->syzyasan_resource_path->get(), | |
|
Sébastien Marchand
2017/04/05 21:07:02
This probably could be moved into a function, not
| |
| 431 syzyasan_dest_path.get()); | |
| 432 ::DeleteFile(context->syzyasan_resource_path->get()); | |
| 433 if (success) { | |
| 434 if (!context->syzyasan_resource_path->assign(syzyasan_dest_path.get())) { | |
| 435 ::DeleteFile(syzyasan_dest_path.get()); | |
| 436 exit_code = ProcessExitResult(PATH_STRING_OVERFLOW); | |
| 437 } | |
| 438 } else { | |
| 439 // TODO(sebmarchand): Add a new exit code for syzyasan_rtl.dll? | |
| 440 exit_code = ProcessExitResult(UNABLE_TO_EXTRACT_SETUP_EXE); | |
| 441 } | |
| 442 #endif | |
| 443 | |
| 429 #if defined(COMPONENT_BUILD) | 444 #if defined(COMPONENT_BUILD) |
| 430 if (exit_code.IsSuccess()) { | 445 if (exit_code.IsSuccess()) { |
| 431 // Extract the (uncompressed) modules required by setup.exe. | 446 // Extract the (uncompressed) modules required by setup.exe. |
| 432 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, | 447 if (!::EnumResourceNames(module, kBinResourceType, WriteResourceToDirectory, |
| 433 reinterpret_cast<LONG_PTR>(base_path))) { | 448 reinterpret_cast<LONG_PTR>(base_path))) { |
| 434 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); | 449 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); |
| 435 } | 450 } |
| 436 } | 451 } |
| 437 #endif | 452 #endif |
| 438 | 453 |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 837 // Set the magic suffix in registry to try full installer next time. We ignore | 852 // Set the magic suffix in registry to try full installer next time. We ignore |
| 838 // any errors here and we try to set the suffix for user level unless | 853 // any errors here and we try to set the suffix for user level unless |
| 839 // GoogleUpdateIsMachine=1 is present in the environment or --system-level is | 854 // GoogleUpdateIsMachine=1 is present in the environment or --system-level is |
| 840 // on the command line in which case we set it for system level instead. This | 855 // on the command line in which case we set it for system level instead. This |
| 841 // only applies to the Google Chrome distribution. | 856 // only applies to the Google Chrome distribution. |
| 842 SetInstallerFlags(configuration); | 857 SetInstallerFlags(configuration); |
| 843 #endif | 858 #endif |
| 844 | 859 |
| 845 PathString archive_path; | 860 PathString archive_path; |
| 846 PathString setup_path; | 861 PathString setup_path; |
| 847 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), | 862 #if defined(SYZYASAN) |
| 848 &archive_path, &setup_path); | 863 PathString syzyasan_rtl_path; |
| 864 #endif | |
| 865 Context context = { | |
| 866 base_path.get(), | |
| 867 &archive_path, | |
| 868 &setup_path, | |
| 869 #if defined(SYZYASAN) | |
| 870 &syzyasan_rtl_path, | |
| 871 #endif | |
| 872 }; | |
| 873 exit_code = UnpackBinaryResources(configuration, module, &context); | |
| 849 | 874 |
| 850 // While unpacking the binaries, we paged in a whole bunch of memory that | 875 // While unpacking the binaries, we paged in a whole bunch of memory that |
| 851 // we don't need anymore. Let's give it back to the pool before running | 876 // we don't need anymore. Let's give it back to the pool before running |
| 852 // setup. | 877 // setup. |
| 853 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); | 878 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); |
| 854 | 879 |
| 855 if (exit_code.IsSuccess()) | 880 if (exit_code.IsSuccess()) |
| 856 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); | 881 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); |
| 857 | 882 |
| 858 if (ShouldDeleteExtractedFiles()) | 883 if (ShouldDeleteExtractedFiles()) |
| 859 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 884 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
| 860 | 885 |
| 861 #if defined(GOOGLE_CHROME_BUILD) | 886 #if defined(GOOGLE_CHROME_BUILD) |
| 862 WriteInstallResults(configuration, exit_code); | 887 WriteInstallResults(configuration, exit_code); |
| 863 #endif | 888 #endif |
| 864 | 889 |
| 865 return exit_code; | 890 return exit_code; |
| 866 } | 891 } |
| 867 | 892 |
| 868 } // namespace mini_installer | 893 } // namespace mini_installer |
| OLD | NEW |