| OLD | NEW |
| (Empty) |
| 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/component_updater/component_patcher_operation.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/files/file_util.h" | |
| 12 #include "base/files/memory_mapped_file.h" | |
| 13 #include "base/location.h" | |
| 14 #include "base/strings/string_number_conversions.h" | |
| 15 #include "components/component_updater/component_patcher.h" | |
| 16 #include "components/component_updater/component_updater_service.h" | |
| 17 #include "courgette/courgette.h" | |
| 18 #include "courgette/third_party/bsdiff.h" | |
| 19 #include "crypto/secure_hash.h" | |
| 20 #include "crypto/sha2.h" | |
| 21 #include "crypto/signature_verifier.h" | |
| 22 | |
| 23 using crypto::SecureHash; | |
| 24 | |
| 25 namespace component_updater { | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 const char kOutput[] = "output"; | |
| 30 const char kSha256[] = "sha256"; | |
| 31 | |
| 32 // The integer offset disambiguates between overlapping error ranges. | |
| 33 const int kCourgetteErrorOffset = 300; | |
| 34 const int kBsdiffErrorOffset = 600; | |
| 35 | |
| 36 } // namespace | |
| 37 | |
| 38 const char kOp[] = "op"; | |
| 39 const char kBsdiff[] = "bsdiff"; | |
| 40 const char kCourgette[] = "courgette"; | |
| 41 const char kInput[] = "input"; | |
| 42 const char kPatch[] = "patch"; | |
| 43 | |
| 44 DeltaUpdateOp* CreateDeltaUpdateOp( | |
| 45 const std::string& operation, | |
| 46 scoped_refptr<OutOfProcessPatcher> out_of_process_patcher) { | |
| 47 if (operation == "copy") { | |
| 48 return new DeltaUpdateOpCopy(); | |
| 49 } else if (operation == "create") { | |
| 50 return new DeltaUpdateOpCreate(); | |
| 51 } else if (operation == "bsdiff" || operation == "courgette") { | |
| 52 return new DeltaUpdateOpPatch(operation, out_of_process_patcher); | |
| 53 } | |
| 54 return NULL; | |
| 55 } | |
| 56 | |
| 57 DeltaUpdateOp::DeltaUpdateOp() { | |
| 58 } | |
| 59 | |
| 60 DeltaUpdateOp::~DeltaUpdateOp() { | |
| 61 } | |
| 62 | |
| 63 void DeltaUpdateOp::Run(const base::DictionaryValue* command_args, | |
| 64 const base::FilePath& input_dir, | |
| 65 const base::FilePath& unpack_dir, | |
| 66 ComponentInstaller* installer, | |
| 67 const ComponentUnpacker::Callback& callback, | |
| 68 scoped_refptr<base::SequencedTaskRunner> task_runner) { | |
| 69 callback_ = callback; | |
| 70 task_runner_ = task_runner; | |
| 71 std::string output_rel_path; | |
| 72 if (!command_args->GetString(kOutput, &output_rel_path) || | |
| 73 !command_args->GetString(kSha256, &output_sha256_)) { | |
| 74 DoneRunning(ComponentUnpacker::kDeltaBadCommands, 0); | |
| 75 return; | |
| 76 } | |
| 77 | |
| 78 output_abs_path_ = | |
| 79 unpack_dir.Append(base::FilePath::FromUTF8Unsafe(output_rel_path)); | |
| 80 ComponentUnpacker::Error parse_result = | |
| 81 DoParseArguments(command_args, input_dir, installer); | |
| 82 if (parse_result != ComponentUnpacker::kNone) { | |
| 83 DoneRunning(parse_result, 0); | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 const base::FilePath parent = output_abs_path_.DirName(); | |
| 88 if (!base::DirectoryExists(parent)) { | |
| 89 if (!base::CreateDirectory(parent)) { | |
| 90 DoneRunning(ComponentUnpacker::kIoError, 0); | |
| 91 return; | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 DoRun(base::Bind(&DeltaUpdateOp::DoneRunning, | |
| 96 scoped_refptr<DeltaUpdateOp>(this))); | |
| 97 } | |
| 98 | |
| 99 void DeltaUpdateOp::DoneRunning(ComponentUnpacker::Error error, | |
| 100 int extended_error) { | |
| 101 if (error == ComponentUnpacker::kNone) | |
| 102 error = CheckHash(); | |
| 103 task_runner_->PostTask(FROM_HERE, | |
| 104 base::Bind(callback_, error, extended_error)); | |
| 105 callback_.Reset(); | |
| 106 } | |
| 107 | |
| 108 // Uses the hash as a checksum to confirm that the file now residing in the | |
| 109 // output directory probably has the contents it should. | |
| 110 ComponentUnpacker::Error DeltaUpdateOp::CheckHash() { | |
| 111 std::vector<uint8_t> expected_hash; | |
| 112 if (!base::HexStringToBytes(output_sha256_, &expected_hash) || | |
| 113 expected_hash.size() != crypto::kSHA256Length) | |
| 114 return ComponentUnpacker::kDeltaVerificationFailure; | |
| 115 | |
| 116 base::MemoryMappedFile output_file_mmapped; | |
| 117 if (!output_file_mmapped.Initialize(output_abs_path_)) | |
| 118 return ComponentUnpacker::kDeltaVerificationFailure; | |
| 119 | |
| 120 uint8_t actual_hash[crypto::kSHA256Length] = {0}; | |
| 121 const scoped_ptr<SecureHash> hasher(SecureHash::Create(SecureHash::SHA256)); | |
| 122 hasher->Update(output_file_mmapped.data(), output_file_mmapped.length()); | |
| 123 hasher->Finish(actual_hash, sizeof(actual_hash)); | |
| 124 if (memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash))) | |
| 125 return ComponentUnpacker::kDeltaVerificationFailure; | |
| 126 | |
| 127 return ComponentUnpacker::kNone; | |
| 128 } | |
| 129 | |
| 130 scoped_refptr<base::SequencedTaskRunner> DeltaUpdateOp::GetTaskRunner() { | |
| 131 return task_runner_; | |
| 132 } | |
| 133 | |
| 134 DeltaUpdateOpCopy::DeltaUpdateOpCopy() { | |
| 135 } | |
| 136 | |
| 137 DeltaUpdateOpCopy::~DeltaUpdateOpCopy() { | |
| 138 } | |
| 139 | |
| 140 ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( | |
| 141 const base::DictionaryValue* command_args, | |
| 142 const base::FilePath& input_dir, | |
| 143 ComponentInstaller* installer) { | |
| 144 std::string input_rel_path; | |
| 145 if (!command_args->GetString(kInput, &input_rel_path)) | |
| 146 return ComponentUnpacker::kDeltaBadCommands; | |
| 147 | |
| 148 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) | |
| 149 return ComponentUnpacker::kDeltaMissingExistingFile; | |
| 150 | |
| 151 return ComponentUnpacker::kNone; | |
| 152 } | |
| 153 | |
| 154 void DeltaUpdateOpCopy::DoRun(const ComponentUnpacker::Callback& callback) { | |
| 155 if (!base::CopyFile(input_abs_path_, output_abs_path_)) | |
| 156 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0); | |
| 157 else | |
| 158 callback.Run(ComponentUnpacker::kNone, 0); | |
| 159 } | |
| 160 | |
| 161 DeltaUpdateOpCreate::DeltaUpdateOpCreate() { | |
| 162 } | |
| 163 | |
| 164 DeltaUpdateOpCreate::~DeltaUpdateOpCreate() { | |
| 165 } | |
| 166 | |
| 167 ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( | |
| 168 const base::DictionaryValue* command_args, | |
| 169 const base::FilePath& input_dir, | |
| 170 ComponentInstaller* installer) { | |
| 171 std::string patch_rel_path; | |
| 172 if (!command_args->GetString(kPatch, &patch_rel_path)) | |
| 173 return ComponentUnpacker::kDeltaBadCommands; | |
| 174 | |
| 175 patch_abs_path_ = | |
| 176 input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path)); | |
| 177 | |
| 178 return ComponentUnpacker::kNone; | |
| 179 } | |
| 180 | |
| 181 void DeltaUpdateOpCreate::DoRun(const ComponentUnpacker::Callback& callback) { | |
| 182 if (!base::Move(patch_abs_path_, output_abs_path_)) | |
| 183 callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0); | |
| 184 else | |
| 185 callback.Run(ComponentUnpacker::kNone, 0); | |
| 186 } | |
| 187 | |
| 188 DeltaUpdateOpPatch::DeltaUpdateOpPatch( | |
| 189 const std::string& operation, | |
| 190 scoped_refptr<OutOfProcessPatcher> out_of_process_patcher) | |
| 191 : operation_(operation), out_of_process_patcher_(out_of_process_patcher) { | |
| 192 DCHECK(operation == kBsdiff || operation == kCourgette); | |
| 193 } | |
| 194 | |
| 195 DeltaUpdateOpPatch::~DeltaUpdateOpPatch() { | |
| 196 } | |
| 197 | |
| 198 ComponentUnpacker::Error DeltaUpdateOpPatch::DoParseArguments( | |
| 199 const base::DictionaryValue* command_args, | |
| 200 const base::FilePath& input_dir, | |
| 201 ComponentInstaller* installer) { | |
| 202 std::string patch_rel_path; | |
| 203 std::string input_rel_path; | |
| 204 if (!command_args->GetString(kPatch, &patch_rel_path) || | |
| 205 !command_args->GetString(kInput, &input_rel_path)) | |
| 206 return ComponentUnpacker::kDeltaBadCommands; | |
| 207 | |
| 208 if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) | |
| 209 return ComponentUnpacker::kDeltaMissingExistingFile; | |
| 210 | |
| 211 patch_abs_path_ = | |
| 212 input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path)); | |
| 213 | |
| 214 return ComponentUnpacker::kNone; | |
| 215 } | |
| 216 | |
| 217 void DeltaUpdateOpPatch::DoRun(const ComponentUnpacker::Callback& callback) { | |
| 218 if (out_of_process_patcher_.get()) { | |
| 219 out_of_process_patcher_->Patch( | |
| 220 operation_, | |
| 221 GetTaskRunner(), | |
| 222 input_abs_path_, | |
| 223 patch_abs_path_, | |
| 224 output_abs_path_, | |
| 225 base::Bind(&DeltaUpdateOpPatch::DonePatching, this, callback)); | |
| 226 return; | |
| 227 } | |
| 228 | |
| 229 if (operation_ == kBsdiff) { | |
| 230 DonePatching(callback, | |
| 231 courgette::ApplyBinaryPatch( | |
| 232 input_abs_path_, patch_abs_path_, output_abs_path_)); | |
| 233 } else if (operation_ == kCourgette) { | |
| 234 DonePatching( | |
| 235 callback, | |
| 236 courgette::ApplyEnsemblePatch(input_abs_path_.value().c_str(), | |
| 237 patch_abs_path_.value().c_str(), | |
| 238 output_abs_path_.value().c_str())); | |
| 239 } else { | |
| 240 NOTREACHED(); | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 void DeltaUpdateOpPatch::DonePatching( | |
| 245 const ComponentUnpacker::Callback& callback, | |
| 246 int result) { | |
| 247 if (operation_ == kBsdiff) { | |
| 248 if (result == courgette::OK) { | |
| 249 callback.Run(ComponentUnpacker::kNone, 0); | |
| 250 } else { | |
| 251 callback.Run(ComponentUnpacker::kDeltaOperationFailure, | |
| 252 result + kBsdiffErrorOffset); | |
| 253 } | |
| 254 } else if (operation_ == kCourgette) { | |
| 255 if (result == courgette::C_OK) { | |
| 256 callback.Run(ComponentUnpacker::kNone, 0); | |
| 257 } else { | |
| 258 callback.Run(ComponentUnpacker::kDeltaOperationFailure, | |
| 259 result + kCourgetteErrorOffset); | |
| 260 } | |
| 261 } else { | |
| 262 NOTREACHED(); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 } // namespace component_updater | |
| OLD | NEW |