1 // Copyright 2014 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 "components/update_client/component_patcher.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_file_value_serializer.h"
15 #include "base/location.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/threading/sequenced_task_runner_handle.h"
18 #include "base/values.h"
19 #include "components/update_client/component_patcher_operation.h"
20 #include "components/update_client/patcher.h"
21 #include "components/update_client/update_client.h"
22 #include "components/update_client/update_client_errors.h"
23
24 namespace update_client {
25
26 namespace {
27
28 // Deserialize the commands file (present in delta update packages). The top
29 // level must be a list.
ReadCommands(const base::FilePath & unpack_path)30 base::ListValue* ReadCommands(const base::FilePath& unpack_path) {
31 const base::FilePath commands =
32 unpack_path.Append(FILE_PATH_LITERAL("commands.json"));
33 if (!base::PathExists(commands))
34 return nullptr;
35
36 JSONFileValueDeserializer deserializer(commands);
37 std::unique_ptr<base::Value> root =
38 deserializer.Deserialize(nullptr, nullptr);
39
40 return (root.get() && root->is_list())
41 ? static_cast<base::ListValue*>(root.release())
42 : nullptr;
43 }
44
45 } // namespace
46
ComponentPatcher(const base::FilePath & input_dir,const base::FilePath & unpack_dir,scoped_refptr<CrxInstaller> installer,scoped_refptr<Patcher> patcher)47 ComponentPatcher::ComponentPatcher(const base::FilePath& input_dir,
48 const base::FilePath& unpack_dir,
49 scoped_refptr<CrxInstaller> installer,
50 scoped_refptr<Patcher> patcher)
51 : input_dir_(input_dir),
52 unpack_dir_(unpack_dir),
53 installer_(installer),
54 patcher_(patcher) {}
55
56 ComponentPatcher::~ComponentPatcher() = default;
57
Start(Callback callback)58 void ComponentPatcher::Start(Callback callback) {
59 callback_ = std::move(callback);
60 base::SequencedTaskRunnerHandle::Get()->PostTask(
61 FROM_HERE, base::BindOnce(&ComponentPatcher::StartPatching,
62 scoped_refptr<ComponentPatcher>(this)));
63 }
64
StartPatching()65 void ComponentPatcher::StartPatching() {
66 commands_.reset(ReadCommands(input_dir_));
67 if (!commands_) {
68 DonePatching(UnpackerError::kDeltaBadCommands, 0);
69 } else {
70 next_command_ = commands_->begin();
71 PatchNextFile();
72 }
73 }
74
PatchNextFile()75 void ComponentPatcher::PatchNextFile() {
76 if (next_command_ == commands_->end()) {
77 DonePatching(UnpackerError::kNone, 0);
78 return;
79 }
80 const base::DictionaryValue* command_args;
81 if (!next_command_->GetAsDictionary(&command_args)) {
82 DonePatching(UnpackerError::kDeltaBadCommands, 0);
83 return;
84 }
85
86 std::string operation;
87 if (command_args->GetString(kOp, &operation)) {
88 current_operation_ = CreateDeltaUpdateOp(operation, patcher_);
89 }
90
91 if (!current_operation_) {
92 DonePatching(UnpackerError::kDeltaUnsupportedCommand, 0);
93 return;
94 }
95 current_operation_->Run(
96 command_args, input_dir_, unpack_dir_, installer_,
97 base::BindOnce(&ComponentPatcher::DonePatchingFile,
98 scoped_refptr<ComponentPatcher>(this)));
99 }
100
DonePatchingFile(UnpackerError error,int extended_error)101 void ComponentPatcher::DonePatchingFile(UnpackerError error,
102 int extended_error) {
103 if (error != UnpackerError::kNone) {
104 DonePatching(error, extended_error);
105 } else {
106 ++next_command_;
107 PatchNextFile();
108 }
109 }
110
DonePatching(UnpackerError error,int extended_error)111 void ComponentPatcher::DonePatching(UnpackerError error, int extended_error) {
112 current_operation_ = nullptr;
113 base::SequencedTaskRunnerHandle::Get()->PostTask(
114 FROM_HERE, base::BindOnce(std::move(callback_), error, extended_error));
115 }
116
117 } // namespace update_client
118