Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: chrome/browser/component_updater/component_patcher.cc

Issue 15908002: Differential updates for components. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Addressed most of the feedback so far. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/component_updater/component_patcher.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/file_util.h"
11 #include "base/files/memory_mapped_file.h"
12 #include "base/json/json_file_value_serializer.h"
13 #include "base/memory/scoped_handle.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "chrome/browser/component_updater/component_patcher_internal.h"
17 #include "chrome/browser/component_updater/component_updater_service.h"
18 #include "chrome/common/extensions/extension_constants.h"
19 #include "crypto/secure_hash.h"
20 #include "crypto/sha2.h"
21 #include "crypto/signature_verifier.h"
22 #include "extensions/common/crx_file.h"
23 #include "third_party/zlib/google/zip.h"
24
25 using crypto::SecureHash;
26
27 namespace {
28
29 const char kInput[] = "input";
30 const char kOp[] = "op";
31 const char kOutput[] = "output";
32 const char kPatch[] = "patch";
33 const char kSha256[] = "sha256";
34
35 DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) {
36 std::string operation;
37 if (!command->GetString(kOp, &operation))
38 return NULL;
39 if (operation == "copy")
40 return new DeltaUpdateOpCopy();
41 else if (operation == "create")
42 return new DeltaUpdateOpCreate();
43 else if (operation == "bsdiff")
44 return new DeltaUpdateOpPatchBsdiff();
45 else if (operation == "courgette")
46 return new DeltaUpdateOpPatchCourgette();
47 return NULL;
48 }
49
50 // Deserialize the commands file (present in delta update packages). The top
51 // level must be a list.
52 base::ListValue* ReadCommands(const base::FilePath& unpack_path) {
53 const base::FilePath commands =
54 unpack_path.Append(FILE_PATH_LITERAL("commands.json"));
55 if (!file_util::PathExists(commands))
56 return NULL;
57
58 JSONFileValueSerializer serializer(commands);
59 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL));
60 if (!root.get())
61 return NULL;
62
63 if (!root->IsType(base::Value::TYPE_LIST))
64 return NULL;
65
66 return static_cast<base::ListValue*>(root.release());
67 }
68
69 } // namespace.
70
71
72 // The patching support is not cross-platform at the moment.
73 ComponentPatcherCrossPlatform::ComponentPatcherCrossPlatform() {}
74
75 ComponentUnpacker::Error ComponentPatcherCrossPlatform::Patch(
76 PatchType patch_type,
77 const base::FilePath& input_file,
78 const base::FilePath& patch_file,
79 const base::FilePath& output_file,
80 int* error) {
81 return ComponentUnpacker::kDeltaUnsupportedCommand;
82 }
83
84 DeltaUpdateOp::~DeltaUpdateOp() {}
85
86 DeltaUpdateOp::DeltaUpdateOp() {}
87
88 ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args,
89 const base::FilePath& input_dir,
90 const base::FilePath& unpack_dir,
91 ComponentPatcher* patcher,
92 ComponentInstaller* installer,
93 int* error) {
94 std::string output_rel_path;
95 if (!command_args->GetString(kOutput, &output_rel_path) ||
96 !command_args->GetString(kSha256, &output_sha256_))
97 return ComponentUnpacker::kDeltaBadCommands;
98
99 output_abs_path_ = unpack_dir.Append(
100 base::FilePath::FromUTF8Unsafe(output_rel_path));
101 ComponentUnpacker::Error parse_result = DoParseArguments(
102 command_args, input_dir, installer);
103 if (parse_result != ComponentUnpacker::kNone)
104 return parse_result;
105
106 const base::FilePath parent = output_abs_path_.DirName();
107 if (!file_util::DirectoryExists(parent)) {
108 if (!file_util::CreateDirectory(parent))
109 return ComponentUnpacker::kIoError;
110 }
111
112 ComponentUnpacker::Error run_result = DoRun(patcher, error);
113 if (run_result != ComponentUnpacker::kNone)
114 return run_result;
115
116 return CheckHash();
117 }
118
119 // Uses the hash as a checksum to confirm that the file now residing in the
120 // output directory probably has the contents it should.
121 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() {
122 std::vector<uint8> expected_hash;
123 if (!base::HexStringToBytes(output_sha256_, &expected_hash) ||
124 expected_hash.size() != crypto::kSHA256Length)
125 return ComponentUnpacker::kDeltaVerificationFailure;
126
127 base::MemoryMappedFile output_file_mmapped;
128 if (!output_file_mmapped.Initialize(output_abs_path_))
129 return ComponentUnpacker::kDeltaVerificationFailure;
130
131 uint8 actual_hash[crypto::kSHA256Length] = {0};
132 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256));
133 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length());
134 hasher->Finish(actual_hash, sizeof(actual_hash));
135 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash)))
136 return ComponentUnpacker::kDeltaVerificationFailure;
137
138 return ComponentUnpacker::kNone;
139 }
140
141 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {}
142
143 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments(
144 base::DictionaryValue* command_args,
145 const base::FilePath& input_dir,
146 ComponentInstaller* installer) {
147 std::string input_rel_path;
148 if (!command_args->GetString(kInput, &input_rel_path))
149 return ComponentUnpacker::kDeltaBadCommands;
150
151 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
152 return ComponentUnpacker::kDeltaMissingExistingFile;
153
154 return ComponentUnpacker::kNone;
155 }
156
157 ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*,
158 int* error) {
159 *error = 0;
160 if (!file_util::CopyFile(input_abs_path_, output_abs_path_))
161 return ComponentUnpacker::kDeltaOperationFailure;
162
163 return ComponentUnpacker::kNone;
164 }
165
166 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {}
167
168 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments(
169 base::DictionaryValue* command_args,
170 const base::FilePath& input_dir,
171 ComponentInstaller* installer) {
172 std::string patch_rel_path;
173 if (!command_args->GetString(kPatch, &patch_rel_path))
174 return ComponentUnpacker::kDeltaBadCommands;
175
176 patch_abs_path_ = input_dir.Append(
177 base::FilePath::FromUTF8Unsafe(patch_rel_path));
178
179 return ComponentUnpacker::kNone;
180 }
181
182 ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*,
183 int* error) {
184 *error = 0;
185 if (!file_util::Move(patch_abs_path_, output_abs_path_))
186 return ComponentUnpacker::kDeltaOperationFailure;
187
188 return ComponentUnpacker::kNone;
189 }
190
191 DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {}
192
193 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments(
194 base::DictionaryValue* command_args,
195 const base::FilePath& input_dir,
196 ComponentInstaller* installer) {
197 std::string patch_rel_path;
198 std::string input_rel_path;
199 if (!command_args->GetString(kPatch, &patch_rel_path) ||
200 !command_args->GetString(kInput, &input_rel_path))
201 return ComponentUnpacker::kDeltaBadCommands;
202
203 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
204 return ComponentUnpacker::kDeltaMissingExistingFile;
205
206 patch_abs_path_ = input_dir.Append(
207 base::FilePath::FromUTF8Unsafe(patch_rel_path));
208
209 return ComponentUnpacker::kNone;
210 }
211
212 ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun(
213 ComponentPatcher* patcher,
214 int* error) {
215 *error = 0;
216 return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff,
217 input_abs_path_,
218 patch_abs_path_,
219 output_abs_path_,
220 error);
221 }
222
223 DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {}
224
225 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments(
226 base::DictionaryValue* command_args,
227 const base::FilePath& input_dir,
228 ComponentInstaller* installer) {
229 std::string patch_rel_path;
230 std::string input_rel_path;
231 if (!command_args->GetString(kPatch, &patch_rel_path) ||
232 !command_args->GetString(kInput, &input_rel_path))
233 return ComponentUnpacker::kDeltaBadCommands;
234
235 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
236 return ComponentUnpacker::kDeltaMissingExistingFile;
237
238 patch_abs_path_ = input_dir.Append(
239 base::FilePath::FromUTF8Unsafe(patch_rel_path));
240
241 return ComponentUnpacker::kNone;
242 }
243
244 ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun(
245 ComponentPatcher* patcher,
246 int* error) {
247 *error = 0;
248 return patcher->Patch(ComponentPatcher::kPatchTypeCourgette,
249 input_abs_path_,
250 patch_abs_path_,
251 output_abs_path_,
252 error);
253 }
254
255 // Takes the contents of a differential component update in input_dir
256 // and produces the contents of a full component update in unpack_dir
257 // using input_abs_path_ files that the installer knows about.
258 ComponentUnpacker::Error DifferentialUpdatePatch(
259 const base::FilePath& input_dir,
260 const base::FilePath& unpack_dir,
261 ComponentPatcher* patcher,
262 ComponentInstaller* installer,
263 int* error) {
264 *error = 0;
265 scoped_ptr<base::ListValue> commands(ReadCommands(input_dir));
266 if (!commands.get())
267 return ComponentUnpacker::kDeltaBadCommands;
268
269 for (base::ValueVector::const_iterator command = commands->begin(),
270 end = commands->end(); command != end; command++) {
271 if (!(*command)->IsType(base::Value::TYPE_DICTIONARY))
272 return ComponentUnpacker::kDeltaBadCommands;
273 base::DictionaryValue* command_args =
274 static_cast<base::DictionaryValue*>(*command);
275 scoped_ptr<DeltaUpdateOp> operation(CreateDeltaUpdateOp(command_args));
276 if (!operation)
277 return ComponentUnpacker::kDeltaUnsupportedCommand;
278
279 ComponentUnpacker::Error result = operation->Run(
280 command_args, input_dir, unpack_dir, patcher, installer, error);
281 if (result != ComponentUnpacker::kNone)
282 return result;
283 }
284
285 return ComponentUnpacker::kNone;
286 }
287
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698