blob: c72feacdb76d72cc6131ae0ba6ac7bfdefe8cb78 [file] [log] [blame]
[email protected]de0fdca22014-08-19 05:26:091// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]e3e696d32013-06-21 20:41:362// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
sorin52ac0882015-01-24 01:15:005#include "components/update_client/component_patcher_operation.h"
[email protected]e3e696d32013-06-21 20:41:366
sorin5cb1f5492014-09-23 04:07:447#include <stdint.h>
[email protected]e3e696d32013-06-21 20:41:368#include <vector>
9
[email protected]94a481b2014-03-28 19:41:5510#include "base/bind.h"
thestig819adcc82014-09-10 22:24:5311#include "base/files/file_util.h"
[email protected]e3e696d32013-06-21 20:41:3612#include "base/files/memory_mapped_file.h"
[email protected]e260af72014-08-05 07:52:3913#include "base/location.h"
[email protected]e3e696d32013-06-21 20:41:3614#include "base/strings/string_number_conversions.h"
sorin52ac0882015-01-24 01:15:0015#include "components/update_client/update_client.h"
sorin74e70672016-02-03 03:13:1016#include "components/update_client/utils.h"
[email protected]94a481b2014-03-28 19:41:5517#include "courgette/courgette.h"
altimin979ea2e12016-05-18 16:16:2418#include "courgette/third_party/bsdiff/bsdiff.h"
[email protected]e3e696d32013-06-21 20:41:3619
sorin52ac0882015-01-24 01:15:0020namespace update_client {
[email protected]055981f2014-01-17 20:22:3221
[email protected]e3e696d32013-06-21 20:41:3622namespace {
23
[email protected]e3e696d32013-06-21 20:41:3624const char kOutput[] = "output";
[email protected]e3e696d32013-06-21 20:41:3625const char kSha256[] = "sha256";
26
[email protected]94a481b2014-03-28 19:41:5527// The integer offset disambiguates between overlapping error ranges.
28const int kCourgetteErrorOffset = 300;
29const int kBsdiffErrorOffset = 600;
30
[email protected]e3e696d32013-06-21 20:41:3631} // namespace
32
[email protected]e260af72014-08-05 07:52:3933const char kOp[] = "op";
34const char kBsdiff[] = "bsdiff";
35const char kCourgette[] = "courgette";
36const char kInput[] = "input";
37const char kPatch[] = "patch";
[email protected]94a481b2014-03-28 19:41:5538
[email protected]e260af72014-08-05 07:52:3939DeltaUpdateOp* CreateDeltaUpdateOp(
40 const std::string& operation,
bauerb810e60f42015-02-05 01:09:1041 const scoped_refptr<OutOfProcessPatcher>& out_of_process_patcher) {
[email protected]94a481b2014-03-28 19:41:5542 if (operation == "copy") {
[email protected]e3e696d32013-06-21 20:41:3643 return new DeltaUpdateOpCopy();
[email protected]94a481b2014-03-28 19:41:5544 } else if (operation == "create") {
[email protected]e3e696d32013-06-21 20:41:3645 return new DeltaUpdateOpCreate();
[email protected]e260af72014-08-05 07:52:3946 } else if (operation == "bsdiff" || operation == "courgette") {
47 return new DeltaUpdateOpPatch(operation, out_of_process_patcher);
[email protected]94a481b2014-03-28 19:41:5548 }
[email protected]e3e696d32013-06-21 20:41:3649 return NULL;
50}
51
[email protected]e260af72014-08-05 07:52:3952DeltaUpdateOp::DeltaUpdateOp() {
[email protected]d0c8b8b42014-05-06 05:11:4553}
[email protected]e3e696d32013-06-21 20:41:3654
[email protected]d0c8b8b42014-05-06 05:11:4555DeltaUpdateOp::~DeltaUpdateOp() {
56}
[email protected]e3e696d32013-06-21 20:41:3657
bauerb810e60f42015-02-05 01:09:1058void DeltaUpdateOp::Run(
59 const base::DictionaryValue* command_args,
60 const base::FilePath& input_dir,
61 const base::FilePath& unpack_dir,
sorin9797aba2015-04-17 17:15:0362 const scoped_refptr<CrxInstaller>& installer,
sorincbb7c092016-10-27 01:39:2063 const ComponentPatcher::Callback& callback,
bauerb810e60f42015-02-05 01:09:1064 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
[email protected]94a481b2014-03-28 19:41:5565 callback_ = callback;
[email protected]94a481b2014-03-28 19:41:5566 task_runner_ = task_runner;
[email protected]e3e696d32013-06-21 20:41:3667 std::string output_rel_path;
68 if (!command_args->GetString(kOutput, &output_rel_path) ||
[email protected]94a481b2014-03-28 19:41:5569 !command_args->GetString(kSha256, &output_sha256_)) {
70 DoneRunning(ComponentUnpacker::kDeltaBadCommands, 0);
71 return;
72 }
[email protected]e3e696d32013-06-21 20:41:3673
[email protected]d0c8b8b42014-05-06 05:11:4574 output_abs_path_ =
75 unpack_dir.Append(base::FilePath::FromUTF8Unsafe(output_rel_path));
76 ComponentUnpacker::Error parse_result =
77 DoParseArguments(command_args, input_dir, installer);
[email protected]94a481b2014-03-28 19:41:5578 if (parse_result != ComponentUnpacker::kNone) {
79 DoneRunning(parse_result, 0);
80 return;
81 }
[email protected]e3e696d32013-06-21 20:41:3682
83 const base::FilePath parent = output_abs_path_.DirName();
[email protected]dcd16612013-07-15 20:18:0984 if (!base::DirectoryExists(parent)) {
[email protected]94a481b2014-03-28 19:41:5585 if (!base::CreateDirectory(parent)) {
86 DoneRunning(ComponentUnpacker::kIoError, 0);
87 return;
88 }
[email protected]e3e696d32013-06-21 20:41:3689 }
90
[email protected]94a481b2014-03-28 19:41:5591 DoRun(base::Bind(&DeltaUpdateOp::DoneRunning,
92 scoped_refptr<DeltaUpdateOp>(this)));
93}
[email protected]e3e696d32013-06-21 20:41:3694
[email protected]94a481b2014-03-28 19:41:5595void DeltaUpdateOp::DoneRunning(ComponentUnpacker::Error error,
96 int extended_error) {
97 if (error == ComponentUnpacker::kNone)
98 error = CheckHash();
99 task_runner_->PostTask(FROM_HERE,
100 base::Bind(callback_, error, extended_error));
101 callback_.Reset();
[email protected]e3e696d32013-06-21 20:41:36102}
103
104// Uses the hash as a checksum to confirm that the file now residing in the
105// output directory probably has the contents it should.
106ComponentUnpacker::Error DeltaUpdateOp::CheckHash() {
sorin74e70672016-02-03 03:13:10107 return VerifyFileHash256(output_abs_path_, output_sha256_)
108 ? ComponentUnpacker::kNone
109 : ComponentUnpacker::kDeltaVerificationFailure;
[email protected]e3e696d32013-06-21 20:41:36110}
111
[email protected]87da10b2014-04-02 04:13:14112scoped_refptr<base::SequencedTaskRunner> DeltaUpdateOp::GetTaskRunner() {
113 return task_runner_;
114}
115
[email protected]d0c8b8b42014-05-06 05:11:45116DeltaUpdateOpCopy::DeltaUpdateOpCopy() {
117}
[email protected]e3e696d32013-06-21 20:41:36118
[email protected]d0c8b8b42014-05-06 05:11:45119DeltaUpdateOpCopy::~DeltaUpdateOpCopy() {
120}
[email protected]94a481b2014-03-28 19:41:55121
[email protected]e3e696d32013-06-21 20:41:36122ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments(
[email protected]94a481b2014-03-28 19:41:55123 const base::DictionaryValue* command_args,
[email protected]e3e696d32013-06-21 20:41:36124 const base::FilePath& input_dir,
sorin9797aba2015-04-17 17:15:03125 const scoped_refptr<CrxInstaller>& installer) {
[email protected]e3e696d32013-06-21 20:41:36126 std::string input_rel_path;
127 if (!command_args->GetString(kInput, &input_rel_path))
128 return ComponentUnpacker::kDeltaBadCommands;
129
130 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
131 return ComponentUnpacker::kDeltaMissingExistingFile;
132
133 return ComponentUnpacker::kNone;
134}
135
sorincbb7c092016-10-27 01:39:20136void DeltaUpdateOpCopy::DoRun(const ComponentPatcher::Callback& callback) {
[email protected]f0ff2ad2013-07-09 17:42:26137 if (!base::CopyFile(input_abs_path_, output_abs_path_))
[email protected]94a481b2014-03-28 19:41:55138 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0);
139 else
140 callback.Run(ComponentUnpacker::kNone, 0);
[email protected]e3e696d32013-06-21 20:41:36141}
142
[email protected]d0c8b8b42014-05-06 05:11:45143DeltaUpdateOpCreate::DeltaUpdateOpCreate() {
144}
[email protected]e3e696d32013-06-21 20:41:36145
[email protected]d0c8b8b42014-05-06 05:11:45146DeltaUpdateOpCreate::~DeltaUpdateOpCreate() {
147}
[email protected]94a481b2014-03-28 19:41:55148
[email protected]e3e696d32013-06-21 20:41:36149ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments(
[email protected]94a481b2014-03-28 19:41:55150 const base::DictionaryValue* command_args,
[email protected]e3e696d32013-06-21 20:41:36151 const base::FilePath& input_dir,
sorin9797aba2015-04-17 17:15:03152 const scoped_refptr<CrxInstaller>& installer) {
[email protected]e3e696d32013-06-21 20:41:36153 std::string patch_rel_path;
154 if (!command_args->GetString(kPatch, &patch_rel_path))
155 return ComponentUnpacker::kDeltaBadCommands;
156
[email protected]d0c8b8b42014-05-06 05:11:45157 patch_abs_path_ =
158 input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path));
[email protected]e3e696d32013-06-21 20:41:36159
160 return ComponentUnpacker::kNone;
161}
162
sorincbb7c092016-10-27 01:39:20163void DeltaUpdateOpCreate::DoRun(const ComponentPatcher::Callback& callback) {
[email protected]5553d5b2013-07-01 23:07:36164 if (!base::Move(patch_abs_path_, output_abs_path_))
[email protected]94a481b2014-03-28 19:41:55165 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0);
166 else
167 callback.Run(ComponentUnpacker::kNone, 0);
[email protected]e3e696d32013-06-21 20:41:36168}
169
[email protected]94a481b2014-03-28 19:41:55170DeltaUpdateOpPatch::DeltaUpdateOpPatch(
[email protected]e260af72014-08-05 07:52:39171 const std::string& operation,
172 scoped_refptr<OutOfProcessPatcher> out_of_process_patcher)
173 : operation_(operation), out_of_process_patcher_(out_of_process_patcher) {
174 DCHECK(operation == kBsdiff || operation == kCourgette);
[email protected]94a481b2014-03-28 19:41:55175}
176
177DeltaUpdateOpPatch::~DeltaUpdateOpPatch() {
178}
179
180ComponentUnpacker::Error DeltaUpdateOpPatch::DoParseArguments(
181 const base::DictionaryValue* command_args,
[email protected]e3e696d32013-06-21 20:41:36182 const base::FilePath& input_dir,
sorin9797aba2015-04-17 17:15:03183 const scoped_refptr<CrxInstaller>& installer) {
[email protected]e3e696d32013-06-21 20:41:36184 std::string patch_rel_path;
185 std::string input_rel_path;
186 if (!command_args->GetString(kPatch, &patch_rel_path) ||
187 !command_args->GetString(kInput, &input_rel_path))
188 return ComponentUnpacker::kDeltaBadCommands;
189
190 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
191 return ComponentUnpacker::kDeltaMissingExistingFile;
192
[email protected]d0c8b8b42014-05-06 05:11:45193 patch_abs_path_ =
194 input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path));
[email protected]e3e696d32013-06-21 20:41:36195
196 return ComponentUnpacker::kNone;
197}
198
sorincbb7c092016-10-27 01:39:20199void DeltaUpdateOpPatch::DoRun(const ComponentPatcher::Callback& callback) {
[email protected]e260af72014-08-05 07:52:39200 if (out_of_process_patcher_.get()) {
201 out_of_process_patcher_->Patch(
sorin52ac0882015-01-24 01:15:00202 operation_, GetTaskRunner(), input_abs_path_, patch_abs_path_,
[email protected]e260af72014-08-05 07:52:39203 output_abs_path_,
204 base::Bind(&DeltaUpdateOpPatch::DonePatching, this, callback));
[email protected]94a481b2014-03-28 19:41:55205 return;
206 }
[email protected]e260af72014-08-05 07:52:39207
208 if (operation_ == kBsdiff) {
209 DonePatching(callback,
huangs7054b5a22016-07-26 21:46:13210 bsdiff::ApplyBinaryPatch(input_abs_path_, patch_abs_path_,
211 output_abs_path_));
[email protected]e260af72014-08-05 07:52:39212 } else if (operation_ == kCourgette) {
sorin52ac0882015-01-24 01:15:00213 DonePatching(callback, courgette::ApplyEnsemblePatch(
214 input_abs_path_.value().c_str(),
215 patch_abs_path_.value().c_str(),
216 output_abs_path_.value().c_str()));
[email protected]e260af72014-08-05 07:52:39217 } else {
218 NOTREACHED();
219 }
[email protected]e3e696d32013-06-21 20:41:36220}
221
[email protected]e260af72014-08-05 07:52:39222void DeltaUpdateOpPatch::DonePatching(
sorincbb7c092016-10-27 01:39:20223 const ComponentPatcher::Callback& callback,
[email protected]e260af72014-08-05 07:52:39224 int result) {
225 if (operation_ == kBsdiff) {
huangs7054b5a22016-07-26 21:46:13226 if (result == bsdiff::OK) {
[email protected]e260af72014-08-05 07:52:39227 callback.Run(ComponentUnpacker::kNone, 0);
228 } else {
229 callback.Run(ComponentUnpacker::kDeltaOperationFailure,
230 result + kBsdiffErrorOffset);
231 }
232 } else if (operation_ == kCourgette) {
233 if (result == courgette::C_OK) {
234 callback.Run(ComponentUnpacker::kNone, 0);
235 } else {
236 callback.Run(ComponentUnpacker::kDeltaOperationFailure,
237 result + kCourgetteErrorOffset);
238 }
239 } else {
240 NOTREACHED();
[email protected]94a481b2014-03-28 19:41:55241 }
[email protected]e3e696d32013-06-21 20:41:36242}
243
sorin52ac0882015-01-24 01:15:00244} // namespace update_client