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.
5 #include "chrome/browser/component_updater/component_patcher_win.h"
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"
19 namespace component_updater
{
23 std::string
PatchTypeToCommandLineSwitch(
24 ComponentPatcher::PatchType patch_type
) {
25 if (patch_type
== ComponentPatcher::kPatchTypeCourgette
)
26 return std::string(installer::kCourgette
);
27 else if (patch_type
== ComponentPatcher::kPatchTypeBsdiff
)
28 return std::string(installer::kBsdiff
);
33 // Finds the path to the setup.exe. First, it looks for the program in the
34 // "installer" directory. If the program is not found there, it tries to find it
35 // in the directory where chrome.dll lives. Returns the path to the setup.exe,
36 // if the path exists, otherwise it returns an an empty path.
37 base::FilePath
FindSetupProgram() {
38 base::FilePath exe_dir
;
39 if (!PathService::Get(base::DIR_MODULE
, &exe_dir
))
40 return base::FilePath();
42 const std::string
installer_dir(WideToASCII(installer::kInstallerDir
));
43 const std::string
setup_exe(WideToASCII(installer::kSetupExe
));
45 base::FilePath setup_path
= exe_dir
;
46 setup_path
= setup_path
.AppendASCII(installer_dir
);
47 setup_path
= setup_path
.AppendASCII(setup_exe
);
48 if (base::PathExists(setup_path
))
52 setup_path
= setup_path
.AppendASCII(setup_exe
);
53 if (base::PathExists(setup_path
))
56 return base::FilePath();
61 // Applies the patch to the input file. Returns kNone if the patch was
62 // successfully applied, kDeltaOperationFailure if the patch operation
63 // encountered errors, and kDeltaPatchProcessFailure if there was an error
64 // when running the patch code out of process. In the error case, detailed error
65 // information could be returned in the error parameter.
66 ComponentUnpacker::Error
ComponentPatcherWin::Patch(
68 const base::FilePath
& input_file
,
69 const base::FilePath
& patch_file
,
70 const base::FilePath
& output_file
,
74 const base::FilePath exe_path
= FindSetupProgram();
76 return ComponentUnpacker::kDeltaPatchProcessFailure
;
78 const std::string
patch_type_str(PatchTypeToCommandLineSwitch(patch_type
));
80 CommandLine
cl(CommandLine::NO_PROGRAM
);
81 cl
.AppendSwitchASCII(installer::switches::kPatch
, patch_type_str
.c_str());
82 cl
.AppendSwitchPath(installer::switches::kInputFile
, input_file
);
83 cl
.AppendSwitchPath(installer::switches::kPatchFile
, patch_file
);
84 cl
.AppendSwitchPath(installer::switches::kOutputFile
, output_file
);
86 // Create the child process in a job object. The job object prevents leaving
87 // child processes around when the parent process exits, either gracefully or
89 base::win::ScopedHandle
job(CreateJobObject(NULL
, NULL
));
91 !base::SetJobObjectLimitFlags(job
, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
)) {
92 *error
= GetLastError();
93 return ComponentUnpacker::kDeltaPatchProcessFailure
;
96 base::LaunchOptions launch_options
;
97 launch_options
.wait
= true;
98 launch_options
.job_handle
= job
;
99 launch_options
.start_hidden
= true;
100 CommandLine
setup_path(exe_path
);
101 setup_path
.AppendArguments(cl
, false);
103 // |ph| is closed by WaitForExitCode.
104 base::ProcessHandle ph
= base::kNullProcessHandle
;
106 if (!base::LaunchProcess(setup_path
, launch_options
, &ph
) ||
107 !base::WaitForExitCode(ph
, &exit_code
)) {
108 *error
= GetLastError();
109 return ComponentUnpacker::kDeltaPatchProcessFailure
;
113 return *error
? ComponentUnpacker::kDeltaOperationFailure
:
114 ComponentUnpacker::kNone
;
117 } // namespace component_updater