blob: f3fa282c13c418ef8d491eb3fa8309c49876bb94 [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"
sorin7b8650522016-11-02 18:23:4116#include "components/update_client/update_client_errors.h"
sorin74e70672016-02-03 03:13:1017#include "components/update_client/utils.h"
[email protected]94a481b2014-03-28 19:41:5518#include "courgette/courgette.h"
altimin979ea2e12016-05-18 16:16:2419#include "courgette/third_party/bsdiff/bsdiff.h"
[email protected]e3e696d32013-06-21 20:41:3620
sorin52ac0882015-01-24 01:15:0021namespace update_client {
[email protected]055981f2014-01-17 20:22:3222
[email protected]e3e696d32013-06-21 20:41:3623namespace {
24
[email protected]e3e696d32013-06-21 20:41:3625const char kOutput[] = "output";
[email protected]e3e696d32013-06-21 20:41:3626const char kSha256[] = "sha256";
27
[email protected]94a481b2014-03-28 19:41:5528// The integer offset disambiguates between overlapping error ranges.
29const int kCourgetteErrorOffset = 300;
30const int kBsdiffErrorOffset = 600;
31
[email protected]e3e696d32013-06-21 20:41:3632} // namespace
33
[email protected]e260af72014-08-05 07:52:3934const char kOp[] = "op";
35const char kBsdiff[] = "bsdiff";
36const char kCourgette[] = "courgette";
37const char kInput[] = "input";
38const char kPatch[] = "patch";
[email protected]94a481b2014-03-28 19:41:5539
[email protected]e260af72014-08-05 07:52:3940DeltaUpdateOp* CreateDeltaUpdateOp(
41 const std::string& operation,
bauerb810e60f42015-02-05 01:09:1042 const scoped_refptr<OutOfProcessPatcher>& out_of_process_patcher) {
[email protected]94a481b2014-03-28 19:41:5543 if (operation == "copy") {
[email protected]e3e696d32013-06-21 20:41:3644 return new DeltaUpdateOpCopy();
[email protected]94a481b2014-03-28 19:41:5545 } else if (operation == "create") {
[email protected]e3e696d32013-06-21 20:41:3646 return new DeltaUpdateOpCreate();
[email protected]e260af72014-08-05 07:52:3947 } else if (operation == "bsdiff" || operation == "courgette") {
48 return new DeltaUpdateOpPatch(operation, out_of_process_patcher);
[email protected]94a481b2014-03-28 19:41:5549 }
[email protected]e3e696d32013-06-21 20:41:3650 return NULL;
51}
52
[email protected]e260af72014-08-05 07:52:3953DeltaUpdateOp::DeltaUpdateOp() {
[email protected]d0c8b8b42014-05-06 05:11:4554}
[email protected]e3e696d32013-06-21 20:41:3655
[email protected]d0c8b8b42014-05-06 05:11:4556DeltaUpdateOp::~DeltaUpdateOp() {
57}
[email protected]e3e696d32013-06-21 20:41:3658
bauerb810e60f42015-02-05 01:09:1059void DeltaUpdateOp::Run(
60 const base::DictionaryValue* command_args,
61 const base::FilePath& input_dir,
62 const base::FilePath& unpack_dir,
sorin9797aba2015-04-17 17:15:0363 const scoped_refptr<CrxInstaller>& installer,
sorincbb7c092016-10-27 01:39:2064 const ComponentPatcher::Callback& callback,
bauerb810e60f42015-02-05 01:09:1065 const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
[email protected]94a481b2014-03-28 19:41:5566 callback_ = callback;
[email protected]94a481b2014-03-28 19:41:5567 task_runner_ = task_runner;
[email protected]e3e696d32013-06-21 20:41:3668 std::string output_rel_path;
69 if (!command_args->GetString(kOutput, &output_rel_path) ||
[email protected]94a481b2014-03-28 19:41:5570 !command_args->GetString(kSha256, &output_sha256_)) {
sorin7b8650522016-11-02 18:23:4171 DoneRunning(UnpackerError::kDeltaBadCommands, 0);
[email protected]94a481b2014-03-28 19:41:5572 return;
73 }
[email protected]e3e696d32013-06-21 20:41:3674
[email protected]d0c8b8b42014-05-06 05:11:4575 output_abs_path_ =
76 unpack_dir.Append(base::FilePath::FromUTF8Unsafe(output_rel_path));
sorin7b8650522016-11-02 18:23:4177 UnpackerError parse_result =
[email protected]d0c8b8b42014-05-06 05:11:4578 DoParseArguments(command_args, input_dir, installer);
sorin7b8650522016-11-02 18:23:4179 if (parse_result != UnpackerError::kNone) {
[email protected]94a481b2014-03-28 19:41:5580 DoneRunning(parse_result, 0);
81 return;
82 }
[email protected]e3e696d32013-06-21 20:41:3683
84 const base::FilePath parent = output_abs_path_.DirName();
[email protected]dcd16612013-07-15 20:18:0985 if (!base::DirectoryExists(parent)) {
[email protected]94a481b2014-03-28 19:41:5586 if (!base::CreateDirectory(parent)) {
sorin7b8650522016-11-02 18:23:4187 DoneRunning(UnpackerError::kIoError, 0);
[email protected]94a481b2014-03-28 19:41:5588 return;
89 }
[email protected]e3e696d32013-06-21 20:41:3690 }
91
[email protected]94a481b2014-03-28 19:41:5592 DoRun(base::Bind(&DeltaUpdateOp::DoneRunning,
93 scoped_refptr<DeltaUpdateOp>(this)));
94}
[email protected]e3e696d32013-06-21 20:41:3695
sorin7b8650522016-11-02 18:23:4196void DeltaUpdateOp::DoneRunning(UnpackerError error, int extended_error) {
97 if (error == UnpackerError::kNone)
[email protected]94a481b2014-03-28 19:41:5598 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.
sorin7b8650522016-11-02 18:23:41106UnpackerError DeltaUpdateOp::CheckHash() {
sorin74e70672016-02-03 03:13:10107 return VerifyFileHash256(output_abs_path_, output_sha256_)
sorin7b8650522016-11-02 18:23:41108 ? UnpackerError::kNone
109 : UnpackerError::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
sorin7b8650522016-11-02 18:23:41122UnpackerError 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))
sorin7b8650522016-11-02 18:23:41128 return UnpackerError::kDeltaBadCommands;
[email protected]e3e696d32013-06-21 20:41:36129
130 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
sorin7b8650522016-11-02 18:23:41131 return UnpackerError::kDeltaMissingExistingFile;
[email protected]e3e696d32013-06-21 20:41:36132
sorin7b8650522016-11-02 18:23:41133 return UnpackerError::kNone;
[email protected]e3e696d32013-06-21 20:41:36134}
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_))
sorin7b8650522016-11-02 18:23:41138 callback.Run(UnpackerError::kDeltaOperationFailure, 0);
[email protected]94a481b2014-03-28 19:41:55139 else
sorin7b8650522016-11-02 18:23:41140 callback.Run(UnpackerError::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
sorin7b8650522016-11-02 18:23:41149UnpackerError 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))
sorin7b8650522016-11-02 18:23:41155 return UnpackerError::kDeltaBadCommands;
[email protected]e3e696d32013-06-21 20:41:36156
[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
sorin7b8650522016-11-02 18:23:41160 return UnpackerError::kNone;
[email protected]e3e696d32013-06-21 20:41:36161}
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_))
sorin7b8650522016-11-02 18:23:41165 callback.Run(UnpackerError::kDeltaOperationFailure, 0);
[email protected]94a481b2014-03-28 19:41:55166 else
sorin7b8650522016-11-02 18:23:41167 callback.Run(UnpackerError::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
sorin7b8650522016-11-02 18:23:41180UnpackerError DeltaUpdateOpPatch::DoParseArguments(
[email protected]94a481b2014-03-28 19:41:55181 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))
sorin7b8650522016-11-02 18:23:41188 return UnpackerError::kDeltaBadCommands;
[email protected]e3e696d32013-06-21 20:41:36189
190 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
sorin7b8650522016-11-02 18:23:41191 return UnpackerError::kDeltaMissingExistingFile;
[email protected]e3e696d32013-06-21 20:41:36192
[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
sorin7b8650522016-11-02 18:23:41196 return UnpackerError::kNone;
[email protected]e3e696d32013-06-21 20:41:36197}
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) {
sorin7b8650522016-11-02 18:23:41227 callback.Run(UnpackerError::kNone, 0);
[email protected]e260af72014-08-05 07:52:39228 } else {
sorin7b8650522016-11-02 18:23:41229 callback.Run(UnpackerError::kDeltaOperationFailure,
[email protected]e260af72014-08-05 07:52:39230 result + kBsdiffErrorOffset);
231 }
232 } else if (operation_ == kCourgette) {
233 if (result == courgette::C_OK) {
sorin7b8650522016-11-02 18:23:41234 callback.Run(UnpackerError::kNone, 0);
[email protected]e260af72014-08-05 07:52:39235 } else {
sorin7b8650522016-11-02 18:23:41236 callback.Run(UnpackerError::kDeltaOperationFailure,
[email protected]e260af72014-08-05 07:52:39237 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