1 // Copyright 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.
5 #include "chrome/browser/component_updater/component_patcher_operation.h"
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.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"
25 using crypto::SecureHash
;
27 namespace component_updater
{
31 const char kInput
[] = "input";
32 const char kOp
[] = "op";
33 const char kOutput
[] = "output";
34 const char kPatch
[] = "patch";
35 const char kSha256
[] = "sha256";
39 DeltaUpdateOp
* CreateDeltaUpdateOp(base::DictionaryValue
* command
) {
40 std::string operation
;
41 if (!command
->GetString(kOp
, &operation
))
43 if (operation
== "copy")
44 return new DeltaUpdateOpCopy();
45 else if (operation
== "create")
46 return new DeltaUpdateOpCreate();
47 else if (operation
== "bsdiff")
48 return new DeltaUpdateOpPatchBsdiff();
49 else if (operation
== "courgette")
50 return new DeltaUpdateOpPatchCourgette();
54 DeltaUpdateOp::DeltaUpdateOp() {}
56 DeltaUpdateOp::~DeltaUpdateOp() {}
58 ComponentUnpacker::Error
DeltaUpdateOp::Run(base::DictionaryValue
* command_args
,
59 const base::FilePath
& input_dir
,
60 const base::FilePath
& unpack_dir
,
61 ComponentPatcher
* patcher
,
62 ComponentInstaller
* installer
,
64 std::string output_rel_path
;
65 if (!command_args
->GetString(kOutput
, &output_rel_path
) ||
66 !command_args
->GetString(kSha256
, &output_sha256_
))
67 return ComponentUnpacker::kDeltaBadCommands
;
69 output_abs_path_
= unpack_dir
.Append(
70 base::FilePath::FromUTF8Unsafe(output_rel_path
));
71 ComponentUnpacker::Error parse_result
= DoParseArguments(
72 command_args
, input_dir
, installer
);
73 if (parse_result
!= ComponentUnpacker::kNone
)
76 const base::FilePath parent
= output_abs_path_
.DirName();
77 if (!base::DirectoryExists(parent
)) {
78 if (!base::CreateDirectory(parent
))
79 return ComponentUnpacker::kIoError
;
82 ComponentUnpacker::Error run_result
= DoRun(patcher
, error
);
83 if (run_result
!= ComponentUnpacker::kNone
)
89 // Uses the hash as a checksum to confirm that the file now residing in the
90 // output directory probably has the contents it should.
91 ComponentUnpacker::Error
DeltaUpdateOp::CheckHash() {
92 std::vector
<uint8
> expected_hash
;
93 if (!base::HexStringToBytes(output_sha256_
, &expected_hash
) ||
94 expected_hash
.size() != crypto::kSHA256Length
)
95 return ComponentUnpacker::kDeltaVerificationFailure
;
97 base::MemoryMappedFile output_file_mmapped
;
98 if (!output_file_mmapped
.Initialize(output_abs_path_
))
99 return ComponentUnpacker::kDeltaVerificationFailure
;
101 uint8 actual_hash
[crypto::kSHA256Length
] = {0};
102 const scoped_ptr
<SecureHash
> hasher(SecureHash::Create(SecureHash::SHA256
));
103 hasher
->Update(output_file_mmapped
.data(), output_file_mmapped
.length());
104 hasher
->Finish(actual_hash
, sizeof(actual_hash
));
105 if (memcmp(actual_hash
, &expected_hash
[0], sizeof(actual_hash
)))
106 return ComponentUnpacker::kDeltaVerificationFailure
;
108 return ComponentUnpacker::kNone
;
111 DeltaUpdateOpCopy::DeltaUpdateOpCopy() {}
113 ComponentUnpacker::Error
DeltaUpdateOpCopy::DoParseArguments(
114 base::DictionaryValue
* command_args
,
115 const base::FilePath
& input_dir
,
116 ComponentInstaller
* installer
) {
117 std::string input_rel_path
;
118 if (!command_args
->GetString(kInput
, &input_rel_path
))
119 return ComponentUnpacker::kDeltaBadCommands
;
121 if (!installer
->GetInstalledFile(input_rel_path
, &input_abs_path_
))
122 return ComponentUnpacker::kDeltaMissingExistingFile
;
124 return ComponentUnpacker::kNone
;
127 ComponentUnpacker::Error
DeltaUpdateOpCopy::DoRun(ComponentPatcher
*,
130 if (!base::CopyFile(input_abs_path_
, output_abs_path_
))
131 return ComponentUnpacker::kDeltaOperationFailure
;
133 return ComponentUnpacker::kNone
;
136 DeltaUpdateOpCreate::DeltaUpdateOpCreate() {}
138 ComponentUnpacker::Error
DeltaUpdateOpCreate::DoParseArguments(
139 base::DictionaryValue
* command_args
,
140 const base::FilePath
& input_dir
,
141 ComponentInstaller
* installer
) {
142 std::string patch_rel_path
;
143 if (!command_args
->GetString(kPatch
, &patch_rel_path
))
144 return ComponentUnpacker::kDeltaBadCommands
;
146 patch_abs_path_
= input_dir
.Append(
147 base::FilePath::FromUTF8Unsafe(patch_rel_path
));
149 return ComponentUnpacker::kNone
;
152 ComponentUnpacker::Error
DeltaUpdateOpCreate::DoRun(ComponentPatcher
*,
155 if (!base::Move(patch_abs_path_
, output_abs_path_
))
156 return ComponentUnpacker::kDeltaOperationFailure
;
158 return ComponentUnpacker::kNone
;
161 DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {}
163 ComponentUnpacker::Error
DeltaUpdateOpPatchBsdiff::DoParseArguments(
164 base::DictionaryValue
* command_args
,
165 const base::FilePath
& input_dir
,
166 ComponentInstaller
* installer
) {
167 std::string patch_rel_path
;
168 std::string input_rel_path
;
169 if (!command_args
->GetString(kPatch
, &patch_rel_path
) ||
170 !command_args
->GetString(kInput
, &input_rel_path
))
171 return ComponentUnpacker::kDeltaBadCommands
;
173 if (!installer
->GetInstalledFile(input_rel_path
, &input_abs_path_
))
174 return ComponentUnpacker::kDeltaMissingExistingFile
;
176 patch_abs_path_
= input_dir
.Append(
177 base::FilePath::FromUTF8Unsafe(patch_rel_path
));
179 return ComponentUnpacker::kNone
;
182 ComponentUnpacker::Error
DeltaUpdateOpPatchBsdiff::DoRun(
183 ComponentPatcher
* patcher
,
186 return patcher
->Patch(ComponentPatcher::kPatchTypeBsdiff
,
193 DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {}
195 ComponentUnpacker::Error
DeltaUpdateOpPatchCourgette::DoParseArguments(
196 base::DictionaryValue
* command_args
,
197 const base::FilePath
& input_dir
,
198 ComponentInstaller
* installer
) {
199 std::string patch_rel_path
;
200 std::string input_rel_path
;
201 if (!command_args
->GetString(kPatch
, &patch_rel_path
) ||
202 !command_args
->GetString(kInput
, &input_rel_path
))
203 return ComponentUnpacker::kDeltaBadCommands
;
205 if (!installer
->GetInstalledFile(input_rel_path
, &input_abs_path_
))
206 return ComponentUnpacker::kDeltaMissingExistingFile
;
208 patch_abs_path_
= input_dir
.Append(
209 base::FilePath::FromUTF8Unsafe(patch_rel_path
));
211 return ComponentUnpacker::kNone
;
214 ComponentUnpacker::Error
DeltaUpdateOpPatchCourgette::DoRun(
215 ComponentPatcher
* patcher
,
218 return patcher
->Patch(ComponentPatcher::kPatchTypeCourgette
,
225 } // namespace component_updater