ensemble_apply.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright (c) 2011 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// This file contains the code to apply a Courgette patch. 6 7#include "courgette/ensemble.h" 8 9#include "base/basictypes.h" 10#include "base/file_util.h" 11#include "base/files/memory_mapped_file.h" 12#include "base/logging.h" 13#include "courgette/crc.h" 14#include "courgette/region.h" 15#include "courgette/streams.h" 16#include "courgette/simple_delta.h" 17#include "courgette/patcher_x86_32.h" 18 19namespace courgette { 20 21// EnsemblePatchApplication is all the logic and data required to apply the 22// multi-stage patch. 23class EnsemblePatchApplication { 24 public: 25 EnsemblePatchApplication(); 26 ~EnsemblePatchApplication(); 27 28 Status ReadHeader(SourceStream* header_stream); 29 30 Status InitBase(const Region& region); 31 32 Status ValidateBase(); 33 34 Status ReadInitialParameters(SourceStream* initial_parameters); 35 36 Status PredictTransformParameters(SinkStreamSet* predicted_parameters); 37 38 Status SubpatchTransformParameters(SinkStreamSet* prediction, 39 SourceStream* correction, 40 SourceStreamSet* corrected_parameters); 41 42 Status TransformUp(SourceStreamSet* parameters, 43 SinkStreamSet* transformed_elements); 44 45 Status SubpatchTransformedElements(SinkStreamSet* elements, 46 SourceStream* correction, 47 SourceStreamSet* corrected_elements); 48 49 Status TransformDown(SourceStreamSet* transformed_elements, 50 SinkStream* basic_elements); 51 52 Status SubpatchFinalOutput(SourceStream* original, 53 SourceStream* correction, 54 SinkStream* corrected_ensemble); 55 56 private: 57 Status SubpatchStreamSets(SinkStreamSet* predicted_items, 58 SourceStream* correction, 59 SourceStreamSet* corrected_items, 60 SinkStream* corrected_items_storage); 61 62 Region base_region_; // Location of in-memory copy of 'old' version. 63 64 uint32 source_checksum_; 65 uint32 target_checksum_; 66 uint32 final_patch_input_size_prediction_; 67 68 std::vector<TransformationPatcher*> patchers_; 69 70 SinkStream corrected_parameters_storage_; 71 SinkStream corrected_elements_storage_; 72 73 DISALLOW_COPY_AND_ASSIGN(EnsemblePatchApplication); 74}; 75 76EnsemblePatchApplication::EnsemblePatchApplication() 77 : source_checksum_(0), target_checksum_(0), 78 final_patch_input_size_prediction_(0) { 79} 80 81EnsemblePatchApplication::~EnsemblePatchApplication() { 82 for (size_t i = 0; i < patchers_.size(); ++i) { 83 delete patchers_[i]; 84 } 85} 86 87Status EnsemblePatchApplication::ReadHeader(SourceStream* header_stream) { 88 uint32 magic; 89 if (!header_stream->ReadVarint32(&magic)) 90 return C_BAD_ENSEMBLE_MAGIC; 91 92 if (magic != CourgettePatchFile::kMagic) 93 return C_BAD_ENSEMBLE_MAGIC; 94 95 uint32 version; 96 if (!header_stream->ReadVarint32(&version)) 97 return C_BAD_ENSEMBLE_VERSION; 98 99 if (version != CourgettePatchFile::kVersion) 100 return C_BAD_ENSEMBLE_VERSION; 101 102 if (!header_stream->ReadVarint32(&source_checksum_)) 103 return C_BAD_ENSEMBLE_HEADER; 104 105 if (!header_stream->ReadVarint32(&target_checksum_)) 106 return C_BAD_ENSEMBLE_HEADER; 107 108 if (!header_stream->ReadVarint32(&final_patch_input_size_prediction_)) 109 return C_BAD_ENSEMBLE_HEADER; 110 111 return C_OK; 112} 113 114Status EnsemblePatchApplication::InitBase(const Region& region) { 115 base_region_.assign(region); 116 return C_OK; 117} 118 119Status EnsemblePatchApplication::ValidateBase() { 120 uint32 checksum = CalculateCrc(base_region_.start(), base_region_.length()); 121 if (source_checksum_ != checksum) 122 return C_BAD_ENSEMBLE_CRC; 123 124 return C_OK; 125} 126 127Status EnsemblePatchApplication::ReadInitialParameters( 128 SourceStream* transformation_parameters) { 129 uint32 number_of_transformations = 0; 130 if (!transformation_parameters->ReadVarint32(&number_of_transformations)) 131 return C_BAD_ENSEMBLE_HEADER; 132 133 for (size_t i = 0; i < number_of_transformations; ++i) { 134 uint32 kind; 135 if (!transformation_parameters->ReadVarint32(&kind)) 136 return C_BAD_ENSEMBLE_HEADER; 137 138 TransformationPatcher* patcher = NULL; 139 140 switch (kind) 141 { 142 case EXE_WIN_32_X86: 143 patcher = new PatcherX86_32(base_region_); 144 break; 145 case EXE_ELF_32_X86: 146 patcher = new PatcherX86_32(base_region_); 147 break; 148 case EXE_ELF_32_ARM: 149 patcher = new PatcherX86_32(base_region_); 150 break; 151 } 152 153 if (patcher) 154 patchers_.push_back(patcher); 155 else 156 return C_BAD_ENSEMBLE_HEADER; 157 } 158 159 for (size_t i = 0; i < patchers_.size(); ++i) { 160 Status status = patchers_[i]->Init(transformation_parameters); 161 if (status != C_OK) 162 return status; 163 } 164 165 // All transformation_parameters should have been consumed by the above loop. 166 if (!transformation_parameters->Empty()) 167 return C_BAD_ENSEMBLE_HEADER; 168 169 return C_OK; 170} 171 172Status EnsemblePatchApplication::PredictTransformParameters( 173 SinkStreamSet* all_predicted_parameters) { 174 for (size_t i = 0; i < patchers_.size(); ++i) { 175 SinkStreamSet single_predicted_parameters; 176 Status status = 177 patchers_[i]->PredictTransformParameters(&single_predicted_parameters); 178 if (status != C_OK) 179 return status; 180 if (!all_predicted_parameters->WriteSet(&single_predicted_parameters)) 181 return C_STREAM_ERROR; 182 } 183 return C_OK; 184} 185 186Status EnsemblePatchApplication::SubpatchTransformParameters( 187 SinkStreamSet* predicted_parameters, 188 SourceStream* correction, 189 SourceStreamSet* corrected_parameters) { 190 return SubpatchStreamSets(predicted_parameters, 191 correction, 192 corrected_parameters, 193 &corrected_parameters_storage_); 194} 195 196Status EnsemblePatchApplication::TransformUp( 197 SourceStreamSet* parameters, 198 SinkStreamSet* transformed_elements) { 199 for (size_t i = 0; i < patchers_.size(); ++i) { 200 SourceStreamSet single_parameters; 201 if (!parameters->ReadSet(&single_parameters)) 202 return C_STREAM_ERROR; 203 SinkStreamSet single_transformed_element; 204 Status status = patchers_[i]->Transform(&single_parameters, 205 &single_transformed_element); 206 if (status != C_OK) 207 return status; 208 if (!single_parameters.Empty()) 209 return C_STREAM_NOT_CONSUMED; 210 if (!transformed_elements->WriteSet(&single_transformed_element)) 211 return C_STREAM_ERROR; 212 } 213 214 if (!parameters->Empty()) 215 return C_STREAM_NOT_CONSUMED; 216 return C_OK; 217} 218 219Status EnsemblePatchApplication::SubpatchTransformedElements( 220 SinkStreamSet* predicted_elements, 221 SourceStream* correction, 222 SourceStreamSet* corrected_elements) { 223 return SubpatchStreamSets(predicted_elements, 224 correction, 225 corrected_elements, 226 &corrected_elements_storage_); 227} 228 229Status EnsemblePatchApplication::TransformDown( 230 SourceStreamSet* transformed_elements, 231 SinkStream* basic_elements) { 232 // Construct blob of original input followed by reformed elements. 233 234 if (!basic_elements->Reserve(final_patch_input_size_prediction_)) { 235 return C_STREAM_ERROR; 236 } 237 238 // The original input: 239 if (!basic_elements->Write(base_region_.start(), base_region_.length())) 240 return C_STREAM_ERROR; 241 242 for (size_t i = 0; i < patchers_.size(); ++i) { 243 SourceStreamSet single_corrected_element; 244 if (!transformed_elements->ReadSet(&single_corrected_element)) 245 return C_STREAM_ERROR; 246 Status status = patchers_[i]->Reform(&single_corrected_element, 247 basic_elements); 248 if (status != C_OK) 249 return status; 250 if (!single_corrected_element.Empty()) 251 return C_STREAM_NOT_CONSUMED; 252 } 253 254 if (!transformed_elements->Empty()) 255 return C_STREAM_NOT_CONSUMED; 256 // We have totally consumed transformed_elements, so can free the 257 // storage to which it referred. 258 corrected_elements_storage_.Retire(); 259 260 return C_OK; 261} 262 263Status EnsemblePatchApplication::SubpatchFinalOutput( 264 SourceStream* original, 265 SourceStream* correction, 266 SinkStream* corrected_ensemble) { 267 Status delta_status = ApplySimpleDelta(original, correction, 268 corrected_ensemble); 269 if (delta_status != C_OK) 270 return delta_status; 271 272 if (CalculateCrc(corrected_ensemble->Buffer(), 273 corrected_ensemble->Length()) != target_checksum_) 274 return C_BAD_ENSEMBLE_CRC; 275 276 return C_OK; 277} 278 279Status EnsemblePatchApplication::SubpatchStreamSets( 280 SinkStreamSet* predicted_items, 281 SourceStream* correction, 282 SourceStreamSet* corrected_items, 283 SinkStream* corrected_items_storage) { 284 SinkStream linearized_predicted_items; 285 if (!predicted_items->CopyTo(&linearized_predicted_items)) 286 return C_STREAM_ERROR; 287 288 SourceStream prediction; 289 prediction.Init(linearized_predicted_items); 290 291 Status status = ApplySimpleDelta(&prediction, 292 correction, 293 corrected_items_storage); 294 if (status != C_OK) 295 return status; 296 297 if (!corrected_items->Init(corrected_items_storage->Buffer(), 298 corrected_items_storage->Length())) 299 return C_STREAM_ERROR; 300 301 return C_OK; 302} 303 304Status ApplyEnsemblePatch(SourceStream* base, 305 SourceStream* patch, 306 SinkStream* output) { 307 Status status; 308 EnsemblePatchApplication patch_process; 309 310 status = patch_process.ReadHeader(patch); 311 if (status != C_OK) 312 return status; 313 314 status = patch_process.InitBase(Region(base->Buffer(), base->Remaining())); 315 if (status != C_OK) 316 return status; 317 318 status = patch_process.ValidateBase(); 319 if (status != C_OK) 320 return status; 321 322 // The rest of the patch stream is a StreamSet. 323 SourceStreamSet patch_streams; 324 patch_streams.Init(patch); 325 326 SourceStream* transformation_descriptions = patch_streams.stream(0); 327 SourceStream* parameter_correction = patch_streams.stream(1); 328 SourceStream* transformed_elements_correction = patch_streams.stream(2); 329 SourceStream* ensemble_correction = patch_streams.stream(3); 330 331 status = patch_process.ReadInitialParameters(transformation_descriptions); 332 if (status != C_OK) 333 return status; 334 335 SinkStreamSet predicted_parameters; 336 status = patch_process.PredictTransformParameters(&predicted_parameters); 337 if (status != C_OK) 338 return status; 339 340 SourceStreamSet corrected_parameters; 341 status = patch_process.SubpatchTransformParameters(&predicted_parameters, 342 parameter_correction, 343 &corrected_parameters); 344 if (status != C_OK) 345 return status; 346 347 SinkStreamSet transformed_elements; 348 status = patch_process.TransformUp(&corrected_parameters, 349 &transformed_elements); 350 if (status != C_OK) 351 return status; 352 353 SourceStreamSet corrected_transformed_elements; 354 status = patch_process.SubpatchTransformedElements( 355 &transformed_elements, 356 transformed_elements_correction, 357 &corrected_transformed_elements); 358 if (status != C_OK) 359 return status; 360 361 SinkStream original_ensemble_and_corrected_base_elements; 362 status = patch_process.TransformDown( 363 &corrected_transformed_elements, 364 &original_ensemble_and_corrected_base_elements); 365 if (status != C_OK) 366 return status; 367 368 SourceStream final_patch_prediction; 369 final_patch_prediction.Init(original_ensemble_and_corrected_base_elements); 370 status = patch_process.SubpatchFinalOutput(&final_patch_prediction, 371 ensemble_correction, output); 372 if (status != C_OK) 373 return status; 374 375 return C_OK; 376} 377 378Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name, 379 const base::FilePath::CharType* patch_file_name, 380 const base::FilePath::CharType* new_file_name) { 381 // First read enough of the patch file to validate the header is well-formed. 382 // A few varint32 numbers should fit in 100. 383 base::FilePath patch_file_path(patch_file_name); 384 base::MemoryMappedFile patch_file; 385 if (!patch_file.Initialize(patch_file_path)) 386 return C_READ_OPEN_ERROR; 387 388 // 'Dry-run' the first step of the patch process to validate format of header. 389 SourceStream patch_header_stream; 390 patch_header_stream.Init(patch_file.data(), patch_file.length()); 391 EnsemblePatchApplication patch_process; 392 Status status = patch_process.ReadHeader(&patch_header_stream); 393 if (status != C_OK) 394 return status; 395 396 // Read the old_file. 397 base::FilePath old_file_path(old_file_name); 398 base::MemoryMappedFile old_file; 399 if (!old_file.Initialize(old_file_path)) 400 return C_READ_ERROR; 401 402 // Apply patch on streams. 403 SourceStream old_source_stream; 404 SourceStream patch_source_stream; 405 old_source_stream.Init(old_file.data(), old_file.length()); 406 patch_source_stream.Init(patch_file.data(), patch_file.length()); 407 SinkStream new_sink_stream; 408 status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream, 409 &new_sink_stream); 410 if (status != C_OK) 411 return status; 412 413 // Write the patched data to |new_file_name|. 414 base::FilePath new_file_path(new_file_name); 415 int written = 416 file_util::WriteFile( 417 new_file_path, 418 reinterpret_cast<const char*>(new_sink_stream.Buffer()), 419 static_cast<int>(new_sink_stream.Length())); 420 if (written == -1) 421 return C_WRITE_OPEN_ERROR; 422 if (static_cast<size_t>(written) != new_sink_stream.Length()) 423 return C_WRITE_ERROR; 424 425 return C_OK; 426} 427 428} // namespace 429