1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/component_updater/component_patcher_win.h" 6 7 #include <string> 8 9 #include "base/base_paths.h" 10 #include "base/command_line.h" 11 #include "base/file_util.h" 12 #include "base/path_service.h" 13 #include "base/process/kill.h" 14 #include "base/process/launch.h" 15 #include "base/strings/string_util.h" 16 #include "base/win/scoped_handle.h" 17 #include "chrome/installer/util/util_constants.h" 18 19 namespace { 20 21 std::string PatchTypeToCommandLineSwitch( 22 ComponentPatcher::PatchType patch_type) { 23 if (patch_type == ComponentPatcher::kPatchTypeCourgette) 24 return std::string(installer::kCourgette); 25 else if (patch_type == ComponentPatcher::kPatchTypeBsdiff) 26 return std::string(installer::kBsdiff); 27 else 28 return std::string(); 29 } 30 31 // Finds the path to the setup.exe. First, it looks for the program in the 32 // "installer" directory. If the program is not found there, it tries to find it 33 // in the directory where chrome.dll lives. Returns the path to the setup.exe, 34 // if the path exists, otherwise it returns an an empty path. 35 base::FilePath FindSetupProgram() { 36 base::FilePath exe_dir; 37 if (!PathService::Get(base::DIR_MODULE, &exe_dir)) 38 return base::FilePath(); 39 40 const std::string installer_dir(WideToASCII(installer::kInstallerDir)); 41 const std::string setup_exe(WideToASCII(installer::kSetupExe)); 42 43 base::FilePath setup_path = exe_dir; 44 setup_path = setup_path.AppendASCII(installer_dir); 45 setup_path = setup_path.AppendASCII(setup_exe); 46 if (base::PathExists(setup_path)) 47 return setup_path; 48 49 setup_path = exe_dir; 50 setup_path = setup_path.AppendASCII(setup_exe); 51 if (base::PathExists(setup_path)) 52 return setup_path; 53 54 return base::FilePath(); 55 } 56 57 } // namespace 58 59 // Applies the patch to the input file. Returns kNone if the patch was 60 // successfully applied, kDeltaOperationFailure if the patch operation 61 // encountered errors, and kDeltaPatchProcessFailure if there was an error 62 // when running the patch code out of process. In the error case, detailed error 63 // information could be returned in the error parameter. 64 ComponentUnpacker::Error ComponentPatcherWin::Patch( 65 PatchType patch_type, 66 const base::FilePath& input_file, 67 const base::FilePath& patch_file, 68 const base::FilePath& output_file, 69 int* error) { 70 *error = 0; 71 72 const base::FilePath exe_path = FindSetupProgram(); 73 if (exe_path.empty()) 74 return ComponentUnpacker::kDeltaPatchProcessFailure; 75 76 const std::string patch_type_str(PatchTypeToCommandLineSwitch(patch_type)); 77 78 CommandLine cl(CommandLine::NO_PROGRAM); 79 cl.AppendSwitchASCII(installer::switches::kPatch, patch_type_str.c_str()); 80 cl.AppendSwitchPath(installer::switches::kInputFile, input_file); 81 cl.AppendSwitchPath(installer::switches::kPatchFile, patch_file); 82 cl.AppendSwitchPath(installer::switches::kOutputFile, output_file); 83 84 // Create the child process in a job object. The job object prevents leaving 85 // child processes around when the parent process exits, either gracefully or 86 // accidentally. 87 base::win::ScopedHandle job(CreateJobObject(NULL, NULL)); 88 if (!job || !base::SetJobObjectAsKillOnJobClose(job)) { 89 *error = GetLastError(); 90 return ComponentUnpacker::kDeltaPatchProcessFailure; 91 } 92 93 base::LaunchOptions launch_options; 94 launch_options.wait = true; 95 launch_options.job_handle = job; 96 launch_options.start_hidden = true; 97 CommandLine setup_path(exe_path); 98 setup_path.AppendArguments(cl, false); 99 100 // |ph| is closed by WaitForExitCode. 101 base::ProcessHandle ph = base::kNullProcessHandle; 102 int exit_code = 0; 103 if (!base::LaunchProcess(setup_path, launch_options, &ph) || 104 !base::WaitForExitCode(ph, &exit_code)) { 105 *error = GetLastError(); 106 return ComponentUnpacker::kDeltaPatchProcessFailure; 107 } 108 109 *error = exit_code; 110 return *error ? ComponentUnpacker::kDeltaOperationFailure : 111 ComponentUnpacker::kNone; 112 } 113 114