blob: c54a30e19f2df73664c5282ea7e0143aba210dbc [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>
Sorin Jianua8ef73d2017-11-02 16:55:178#include <utility>
[email protected]e3e696d32013-06-21 20:41:369#include <vector>
10
[email protected]94a481b2014-03-28 19:41:5511#include "base/bind.h"
thestig819adcc82014-09-10 22:24:5312#include "base/files/file_util.h"
[email protected]e3e696d32013-06-21 20:41:3613#include "base/files/memory_mapped_file.h"
[email protected]e260af72014-08-05 07:52:3914#include "base/location.h"
[email protected]e3e696d32013-06-21 20:41:3615#include "base/strings/string_number_conversions.h"
Gabriel Charette44db1422018-08-06 11:19:3316#include "base/task/post_task.h"
Sorin Jianuebd652462017-07-23 02:00:5817#include "base/threading/sequenced_task_runner_handle.h"
Joshua Pawlickid5409e12019-04-06 00:23:1118#include "components/update_client/patcher.h"
sorin52ac0882015-01-24 01:15:0019#include "components/update_client/update_client.h"
sorin7b8650522016-11-02 18:23:4120#include "components/update_client/update_client_errors.h"
sorin74e70672016-02-03 03:13:1021#include "components/update_client/utils.h"
[email protected]94a481b2014-03-28 19:41:5522#include "courgette/courgette.h"
altimin979ea2e12016-05-18 16:16:2423#include "courgette/third_party/bsdiff/bsdiff.h"
[email protected]e3e696d32013-06-21 20:41:3624
sorin52ac0882015-01-24 01:15:0025namespace update_client {
[email protected]055981f2014-01-17 20:22:3226
[email protected]e3e696d32013-06-21 20:41:3627namespace {
28
[email protected]e3e696d32013-06-21 20:41:3629const char kOutput[] = "output";
[email protected]e3e696d32013-06-21 20:41:3630const char kSha256[] = "sha256";
31
[email protected]94a481b2014-03-28 19:41:5532// The integer offset disambiguates between overlapping error ranges.
33const int kCourgetteErrorOffset = 300;
34const int kBsdiffErrorOffset = 600;
35
[email protected]e3e696d32013-06-21 20:41:3636} // namespace
37
[email protected]e260af72014-08-05 07:52:3938const char kOp[] = "op";
39const char kBsdiff[] = "bsdiff";
40const char kCourgette[] = "courgette";
41const char kInput[] = "input";
42const char kPatch[] = "patch";
[email protected]94a481b2014-03-28 19:41:5543
Jay Civelli29f9b942017-11-08 20:07:2644DeltaUpdateOp* CreateDeltaUpdateOp(const std::string& operation,
Joshua Pawlickid5409e12019-04-06 00:23:1145 scoped_refptr<Patcher> patcher) {
[email protected]94a481b2014-03-28 19:41:5546 if (operation == "copy") {
[email protected]e3e696d32013-06-21 20:41:3647 return new DeltaUpdateOpCopy();
[email protected]94a481b2014-03-28 19:41:5548 } else if (operation == "create") {
[email protected]e3e696d32013-06-21 20:41:3649 return new DeltaUpdateOpCreate();
[email protected]e260af72014-08-05 07:52:3950 } else if (operation == "bsdiff" || operation == "courgette") {
Joshua Pawlickid5409e12019-04-06 00:23:1151 return new DeltaUpdateOpPatch(operation, patcher);
[email protected]94a481b2014-03-28 19:41:5552 }
Ivan Kotenkov75b1c3a2017-10-24 14:47:2453 return nullptr;
[email protected]e3e696d32013-06-21 20:41:3654}
55
[email protected]e260af72014-08-05 07:52:3956DeltaUpdateOp::DeltaUpdateOp() {
[email protected]d0c8b8b42014-05-06 05:11:4557}
[email protected]e3e696d32013-06-21 20:41:3658
[email protected]d0c8b8b42014-05-06 05:11:4559DeltaUpdateOp::~DeltaUpdateOp() {
60}
[email protected]e3e696d32013-06-21 20:41:3661
Sorin Jianuebd652462017-07-23 02:00:5862void DeltaUpdateOp::Run(const base::DictionaryValue* command_args,
63 const base::FilePath& input_dir,
64 const base::FilePath& unpack_dir,
Sorin Jianu49126332018-02-13 17:07:4265 scoped_refptr<CrxInstaller> installer,
Sorin Jianua8ef73d2017-11-02 16:55:1766 ComponentPatcher::Callback callback) {
67 callback_ = std::move(callback);
[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
Sorin Jianua8ef73d2017-11-02 16:55:1792 DoRun(base::BindOnce(&DeltaUpdateOp::DoneRunning,
93 scoped_refptr<DeltaUpdateOp>(this)));
[email protected]94a481b2014-03-28 19:41:5594}
[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();
Sorin Jianuebd652462017-07-23 02:00:5899 base::SequencedTaskRunnerHandle::Get()->PostTask(
Sorin Jianua8ef73d2017-11-02 16:55:17100 FROM_HERE, base::BindOnce(std::move(callback_), error, extended_error));
[email protected]e3e696d32013-06-21 20:41:36101}
102
103// Uses the hash as a checksum to confirm that the file now residing in the
104// output directory probably has the contents it should.
sorin7b8650522016-11-02 18:23:41105UnpackerError DeltaUpdateOp::CheckHash() {
sorin74e70672016-02-03 03:13:10106 return VerifyFileHash256(output_abs_path_, output_sha256_)
sorin7b8650522016-11-02 18:23:41107 ? UnpackerError::kNone
108 : UnpackerError::kDeltaVerificationFailure;
[email protected]e3e696d32013-06-21 20:41:36109}
110
[email protected]d0c8b8b42014-05-06 05:11:45111DeltaUpdateOpCopy::DeltaUpdateOpCopy() {
112}
[email protected]e3e696d32013-06-21 20:41:36113
[email protected]d0c8b8b42014-05-06 05:11:45114DeltaUpdateOpCopy::~DeltaUpdateOpCopy() {
115}
[email protected]94a481b2014-03-28 19:41:55116
sorin7b8650522016-11-02 18:23:41117UnpackerError DeltaUpdateOpCopy::DoParseArguments(
[email protected]94a481b2014-03-28 19:41:55118 const base::DictionaryValue* command_args,
[email protected]e3e696d32013-06-21 20:41:36119 const base::FilePath& input_dir,
Sorin Jianu49126332018-02-13 17:07:42120 scoped_refptr<CrxInstaller> installer) {
[email protected]e3e696d32013-06-21 20:41:36121 std::string input_rel_path;
122 if (!command_args->GetString(kInput, &input_rel_path))
sorin7b8650522016-11-02 18:23:41123 return UnpackerError::kDeltaBadCommands;
[email protected]e3e696d32013-06-21 20:41:36124
125 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
sorin7b8650522016-11-02 18:23:41126 return UnpackerError::kDeltaMissingExistingFile;
[email protected]e3e696d32013-06-21 20:41:36127
sorin7b8650522016-11-02 18:23:41128 return UnpackerError::kNone;
[email protected]e3e696d32013-06-21 20:41:36129}
130
Sorin Jianua8ef73d2017-11-02 16:55:17131void DeltaUpdateOpCopy::DoRun(ComponentPatcher::Callback callback) {
[email protected]f0ff2ad2013-07-09 17:42:26132 if (!base::CopyFile(input_abs_path_, output_abs_path_))
Sorin Jianua8ef73d2017-11-02 16:55:17133 std::move(callback).Run(UnpackerError::kDeltaOperationFailure, 0);
[email protected]94a481b2014-03-28 19:41:55134 else
Sorin Jianua8ef73d2017-11-02 16:55:17135 std::move(callback).Run(UnpackerError::kNone, 0);
[email protected]e3e696d32013-06-21 20:41:36136}
137
[email protected]d0c8b8b42014-05-06 05:11:45138DeltaUpdateOpCreate::DeltaUpdateOpCreate() {
139}
[email protected]e3e696d32013-06-21 20:41:36140
[email protected]d0c8b8b42014-05-06 05:11:45141DeltaUpdateOpCreate::~DeltaUpdateOpCreate() {
142}
[email protected]94a481b2014-03-28 19:41:55143
sorin7b8650522016-11-02 18:23:41144UnpackerError DeltaUpdateOpCreate::DoParseArguments(
[email protected]94a481b2014-03-28 19:41:55145 const base::DictionaryValue* command_args,
[email protected]e3e696d32013-06-21 20:41:36146 const base::FilePath& input_dir,
Sorin Jianu49126332018-02-13 17:07:42147 scoped_refptr<CrxInstaller> installer) {
[email protected]e3e696d32013-06-21 20:41:36148 std::string patch_rel_path;
149 if (!command_args->GetString(kPatch, &patch_rel_path))
sorin7b8650522016-11-02 18:23:41150 return UnpackerError::kDeltaBadCommands;
[email protected]e3e696d32013-06-21 20:41:36151
[email protected]d0c8b8b42014-05-06 05:11:45152 patch_abs_path_ =
153 input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path));
[email protected]e3e696d32013-06-21 20:41:36154
sorin7b8650522016-11-02 18:23:41155 return UnpackerError::kNone;
[email protected]e3e696d32013-06-21 20:41:36156}
157
Sorin Jianua8ef73d2017-11-02 16:55:17158void DeltaUpdateOpCreate::DoRun(ComponentPatcher::Callback callback) {
[email protected]5553d5b2013-07-01 23:07:36159 if (!base::Move(patch_abs_path_, output_abs_path_))
Sorin Jianua8ef73d2017-11-02 16:55:17160 std::move(callback).Run(UnpackerError::kDeltaOperationFailure, 0);
[email protected]94a481b2014-03-28 19:41:55161 else
Sorin Jianua8ef73d2017-11-02 16:55:17162 std::move(callback).Run(UnpackerError::kNone, 0);
[email protected]e3e696d32013-06-21 20:41:36163}
164
Jay Civelli29f9b942017-11-08 20:07:26165DeltaUpdateOpPatch::DeltaUpdateOpPatch(const std::string& operation,
Joshua Pawlickid5409e12019-04-06 00:23:11166 scoped_refptr<Patcher> patcher)
167 : operation_(operation), patcher_(patcher) {
[email protected]e260af72014-08-05 07:52:39168 DCHECK(operation == kBsdiff || operation == kCourgette);
[email protected]94a481b2014-03-28 19:41:55169}
170
171DeltaUpdateOpPatch::~DeltaUpdateOpPatch() {
172}
173
sorin7b8650522016-11-02 18:23:41174UnpackerError DeltaUpdateOpPatch::DoParseArguments(
[email protected]94a481b2014-03-28 19:41:55175 const base::DictionaryValue* command_args,
[email protected]e3e696d32013-06-21 20:41:36176 const base::FilePath& input_dir,
Sorin Jianu49126332018-02-13 17:07:42177 scoped_refptr<CrxInstaller> installer) {
[email protected]e3e696d32013-06-21 20:41:36178 std::string patch_rel_path;
179 std::string input_rel_path;
180 if (!command_args->GetString(kPatch, &patch_rel_path) ||
181 !command_args->GetString(kInput, &input_rel_path))
sorin7b8650522016-11-02 18:23:41182 return UnpackerError::kDeltaBadCommands;
[email protected]e3e696d32013-06-21 20:41:36183
184 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
sorin7b8650522016-11-02 18:23:41185 return UnpackerError::kDeltaMissingExistingFile;
[email protected]e3e696d32013-06-21 20:41:36186
[email protected]d0c8b8b42014-05-06 05:11:45187 patch_abs_path_ =
188 input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path));
[email protected]e3e696d32013-06-21 20:41:36189
sorin7b8650522016-11-02 18:23:41190 return UnpackerError::kNone;
[email protected]e3e696d32013-06-21 20:41:36191}
192
Sorin Jianua8ef73d2017-11-02 16:55:17193void DeltaUpdateOpPatch::DoRun(ComponentPatcher::Callback callback) {
Joshua Pawlickid5409e12019-04-06 00:23:11194 if (operation_ == kBsdiff) {
195 patcher_->PatchBsdiff(input_abs_path_, patch_abs_path_, output_abs_path_,
196 base::BindOnce(&DeltaUpdateOpPatch::DonePatching,
197 this, std::move(callback)));
198 } else {
199 patcher_->PatchCourgette(input_abs_path_, patch_abs_path_, output_abs_path_,
200 base::BindOnce(&DeltaUpdateOpPatch::DonePatching,
201 this, std::move(callback)));
202 }
[email protected]e3e696d32013-06-21 20:41:36203}
204
Sorin Jianua8ef73d2017-11-02 16:55:17205void DeltaUpdateOpPatch::DonePatching(ComponentPatcher::Callback callback,
206 int result) {
[email protected]e260af72014-08-05 07:52:39207 if (operation_ == kBsdiff) {
huangs7054b5a22016-07-26 21:46:13208 if (result == bsdiff::OK) {
Sorin Jianua8ef73d2017-11-02 16:55:17209 std::move(callback).Run(UnpackerError::kNone, 0);
[email protected]e260af72014-08-05 07:52:39210 } else {
Sorin Jianua8ef73d2017-11-02 16:55:17211 std::move(callback).Run(UnpackerError::kDeltaOperationFailure,
212 result + kBsdiffErrorOffset);
[email protected]e260af72014-08-05 07:52:39213 }
214 } else if (operation_ == kCourgette) {
215 if (result == courgette::C_OK) {
Sorin Jianua8ef73d2017-11-02 16:55:17216 std::move(callback).Run(UnpackerError::kNone, 0);
[email protected]e260af72014-08-05 07:52:39217 } else {
Sorin Jianua8ef73d2017-11-02 16:55:17218 std::move(callback).Run(UnpackerError::kDeltaOperationFailure,
219 result + kCourgetteErrorOffset);
[email protected]e260af72014-08-05 07:52:39220 }
221 } else {
222 NOTREACHED();
[email protected]94a481b2014-03-28 19:41:55223 }
[email protected]e3e696d32013-06-21 20:41:36224}
225
sorin52ac0882015-01-24 01:15:00226} // namespace update_client