123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- // Copyright (c) 2011 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // This file contains the code to apply a Courgette patch.
- #include "courgette/ensemble.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include <utility>
- #include "base/check.h"
- #include "base/files/file.h"
- #include "base/files/file_util.h"
- #include "base/files/memory_mapped_file.h"
- #include "courgette/crc.h"
- #include "courgette/patcher_x86_32.h"
- #include "courgette/region.h"
- #include "courgette/simple_delta.h"
- #include "courgette/streams.h"
- namespace courgette {
- // EnsemblePatchApplication is all the logic and data required to apply the
- // multi-stage patch.
- class EnsemblePatchApplication {
- public:
- EnsemblePatchApplication();
- EnsemblePatchApplication(const EnsemblePatchApplication&) = delete;
- EnsemblePatchApplication& operator=(const EnsemblePatchApplication&) = delete;
- ~EnsemblePatchApplication() = default;
- Status ReadHeader(SourceStream* header_stream);
- Status InitBase(const Region& region);
- Status ValidateBase();
- Status ReadInitialParameters(SourceStream* initial_parameters);
- Status PredictTransformParameters(SinkStreamSet* predicted_parameters);
- Status SubpatchTransformParameters(SinkStreamSet* prediction,
- SourceStream* correction,
- SourceStreamSet* corrected_parameters);
- Status TransformUp(SourceStreamSet* parameters,
- SinkStreamSet* transformed_elements);
- Status SubpatchTransformedElements(SinkStreamSet* elements,
- SourceStream* correction,
- SourceStreamSet* corrected_elements);
- Status TransformDown(SourceStreamSet* transformed_elements,
- SinkStream* basic_elements);
- Status SubpatchFinalOutput(SourceStream* original,
- SourceStream* correction,
- SinkStream* corrected_ensemble);
- private:
- Status SubpatchStreamSets(SinkStreamSet* predicted_items,
- SourceStream* correction,
- SourceStreamSet* corrected_items,
- SinkStream* corrected_items_storage);
- Region base_region_; // Location of in-memory copy of 'old' version.
- uint32_t source_checksum_;
- uint32_t target_checksum_;
- uint32_t final_patch_input_size_prediction_;
- std::vector<std::unique_ptr<TransformationPatcher>> patchers_;
- SinkStream corrected_parameters_storage_;
- SinkStream corrected_elements_storage_;
- };
- EnsemblePatchApplication::EnsemblePatchApplication()
- : source_checksum_(0), target_checksum_(0),
- final_patch_input_size_prediction_(0) {
- }
- Status EnsemblePatchApplication::ReadHeader(SourceStream* header_stream) {
- uint32_t magic;
- if (!header_stream->ReadVarint32(&magic))
- return C_BAD_ENSEMBLE_MAGIC;
- if (magic != CourgettePatchFile::kMagic)
- return C_BAD_ENSEMBLE_MAGIC;
- uint32_t version;
- if (!header_stream->ReadVarint32(&version))
- return C_BAD_ENSEMBLE_VERSION;
- if (version != CourgettePatchFile::kVersion)
- return C_BAD_ENSEMBLE_VERSION;
- if (!header_stream->ReadVarint32(&source_checksum_))
- return C_BAD_ENSEMBLE_HEADER;
- if (!header_stream->ReadVarint32(&target_checksum_))
- return C_BAD_ENSEMBLE_HEADER;
- if (!header_stream->ReadVarint32(&final_patch_input_size_prediction_))
- return C_BAD_ENSEMBLE_HEADER;
- return C_OK;
- }
- Status EnsemblePatchApplication::InitBase(const Region& region) {
- base_region_.assign(region);
- return C_OK;
- }
- Status EnsemblePatchApplication::ValidateBase() {
- uint32_t checksum = CalculateCrc(base_region_.start(), base_region_.length());
- if (source_checksum_ != checksum)
- return C_BAD_ENSEMBLE_CRC;
- return C_OK;
- }
- Status EnsemblePatchApplication::ReadInitialParameters(
- SourceStream* transformation_parameters) {
- uint32_t number_of_transformations = 0;
- if (!transformation_parameters->ReadVarint32(&number_of_transformations))
- return C_BAD_ENSEMBLE_HEADER;
- for (size_t i = 0; i < number_of_transformations; ++i) {
- uint32_t kind;
- if (!transformation_parameters->ReadVarint32(&kind))
- return C_BAD_ENSEMBLE_HEADER;
- std::unique_ptr<TransformationPatcher> patcher;
- switch (kind) {
- case EXE_WIN_32_X86: // Fall through.
- case EXE_ELF_32_X86:
- case EXE_WIN_32_X64:
- patcher = std::make_unique<PatcherX86_32>(base_region_);
- break;
- default:
- return C_BAD_ENSEMBLE_HEADER;
- }
- DCHECK(patcher);
- patchers_.push_back(std::move(patcher));
- }
- for (size_t i = 0; i < patchers_.size(); ++i) {
- Status status = patchers_[i]->Init(transformation_parameters);
- if (status != C_OK)
- return status;
- }
- // All transformation_parameters should have been consumed by the above loop.
- if (!transformation_parameters->Empty())
- return C_BAD_ENSEMBLE_HEADER;
- return C_OK;
- }
- Status EnsemblePatchApplication::PredictTransformParameters(
- SinkStreamSet* all_predicted_parameters) {
- for (size_t i = 0; i < patchers_.size(); ++i) {
- SinkStreamSet single_predicted_parameters;
- Status status =
- patchers_[i]->PredictTransformParameters(&single_predicted_parameters);
- if (status != C_OK)
- return status;
- if (!all_predicted_parameters->WriteSet(&single_predicted_parameters))
- return C_STREAM_ERROR;
- }
- return C_OK;
- }
- Status EnsemblePatchApplication::SubpatchTransformParameters(
- SinkStreamSet* predicted_parameters,
- SourceStream* correction,
- SourceStreamSet* corrected_parameters) {
- return SubpatchStreamSets(predicted_parameters,
- correction,
- corrected_parameters,
- &corrected_parameters_storage_);
- }
- Status EnsemblePatchApplication::TransformUp(
- SourceStreamSet* parameters,
- SinkStreamSet* transformed_elements) {
- for (size_t i = 0; i < patchers_.size(); ++i) {
- SourceStreamSet single_parameters;
- if (!parameters->ReadSet(&single_parameters))
- return C_STREAM_ERROR;
- SinkStreamSet single_transformed_element;
- Status status = patchers_[i]->Transform(&single_parameters,
- &single_transformed_element);
- if (status != C_OK)
- return status;
- if (!single_parameters.Empty())
- return C_STREAM_NOT_CONSUMED;
- if (!transformed_elements->WriteSet(&single_transformed_element))
- return C_STREAM_ERROR;
- }
- if (!parameters->Empty())
- return C_STREAM_NOT_CONSUMED;
- return C_OK;
- }
- Status EnsemblePatchApplication::SubpatchTransformedElements(
- SinkStreamSet* predicted_elements,
- SourceStream* correction,
- SourceStreamSet* corrected_elements) {
- return SubpatchStreamSets(predicted_elements,
- correction,
- corrected_elements,
- &corrected_elements_storage_);
- }
- Status EnsemblePatchApplication::TransformDown(
- SourceStreamSet* transformed_elements,
- SinkStream* basic_elements) {
- // Construct blob of original input followed by reformed elements.
- if (!basic_elements->Reserve(final_patch_input_size_prediction_)) {
- return C_STREAM_ERROR;
- }
- // The original input:
- if (!basic_elements->Write(base_region_.start(), base_region_.length()))
- return C_STREAM_ERROR;
- for (size_t i = 0; i < patchers_.size(); ++i) {
- SourceStreamSet single_corrected_element;
- if (!transformed_elements->ReadSet(&single_corrected_element))
- return C_STREAM_ERROR;
- Status status = patchers_[i]->Reform(&single_corrected_element,
- basic_elements);
- if (status != C_OK)
- return status;
- if (!single_corrected_element.Empty())
- return C_STREAM_NOT_CONSUMED;
- }
- if (!transformed_elements->Empty())
- return C_STREAM_NOT_CONSUMED;
- // We have totally consumed transformed_elements, so can free the
- // storage to which it referred.
- corrected_elements_storage_.Retire();
- return C_OK;
- }
- Status EnsemblePatchApplication::SubpatchFinalOutput(
- SourceStream* original,
- SourceStream* correction,
- SinkStream* corrected_ensemble) {
- Status delta_status = ApplySimpleDelta(original, correction,
- corrected_ensemble);
- if (delta_status != C_OK)
- return delta_status;
- if (CalculateCrc(corrected_ensemble->Buffer(),
- corrected_ensemble->Length()) != target_checksum_)
- return C_BAD_ENSEMBLE_CRC;
- return C_OK;
- }
- Status EnsemblePatchApplication::SubpatchStreamSets(
- SinkStreamSet* predicted_items,
- SourceStream* correction,
- SourceStreamSet* corrected_items,
- SinkStream* corrected_items_storage) {
- SinkStream linearized_predicted_items;
- if (!predicted_items->CopyTo(&linearized_predicted_items))
- return C_STREAM_ERROR;
- SourceStream prediction;
- prediction.Init(linearized_predicted_items);
- Status status = ApplySimpleDelta(&prediction,
- correction,
- corrected_items_storage);
- if (status != C_OK)
- return status;
- if (!corrected_items->Init(corrected_items_storage->Buffer(),
- corrected_items_storage->Length()))
- return C_STREAM_ERROR;
- return C_OK;
- }
- Status ApplyEnsemblePatch(SourceStream* base,
- SourceStream* patch,
- SinkStream* output) {
- Status status;
- EnsemblePatchApplication patch_process;
- status = patch_process.ReadHeader(patch);
- if (status != C_OK)
- return status;
- status = patch_process.InitBase(Region(base->Buffer(), base->Remaining()));
- if (status != C_OK)
- return status;
- status = patch_process.ValidateBase();
- if (status != C_OK)
- return status;
- // The rest of the patch stream is a StreamSet.
- SourceStreamSet patch_streams;
- patch_streams.Init(patch);
- SourceStream* transformation_descriptions = patch_streams.stream(0);
- SourceStream* parameter_correction = patch_streams.stream(1);
- SourceStream* transformed_elements_correction = patch_streams.stream(2);
- SourceStream* ensemble_correction = patch_streams.stream(3);
- status = patch_process.ReadInitialParameters(transformation_descriptions);
- if (status != C_OK)
- return status;
- SinkStreamSet predicted_parameters;
- status = patch_process.PredictTransformParameters(&predicted_parameters);
- if (status != C_OK)
- return status;
- SourceStreamSet corrected_parameters;
- status = patch_process.SubpatchTransformParameters(&predicted_parameters,
- parameter_correction,
- &corrected_parameters);
- if (status != C_OK)
- return status;
- SinkStreamSet transformed_elements;
- status = patch_process.TransformUp(&corrected_parameters,
- &transformed_elements);
- if (status != C_OK)
- return status;
- SourceStreamSet corrected_transformed_elements;
- status = patch_process.SubpatchTransformedElements(
- &transformed_elements,
- transformed_elements_correction,
- &corrected_transformed_elements);
- if (status != C_OK)
- return status;
- SinkStream original_ensemble_and_corrected_base_elements;
- status = patch_process.TransformDown(
- &corrected_transformed_elements,
- &original_ensemble_and_corrected_base_elements);
- if (status != C_OK)
- return status;
- SourceStream final_patch_prediction;
- final_patch_prediction.Init(original_ensemble_and_corrected_base_elements);
- status = patch_process.SubpatchFinalOutput(&final_patch_prediction,
- ensemble_correction, output);
- if (status != C_OK)
- return status;
- return C_OK;
- }
- Status ApplyEnsemblePatch(base::File old_file,
- base::File patch_file,
- base::File new_file) {
- base::MemoryMappedFile patch_file_mem;
- if (!patch_file_mem.Initialize(std::move(patch_file)))
- return C_READ_OPEN_ERROR;
- // 'Dry-run' the first step of the patch process to validate format of header.
- SourceStream patch_header_stream;
- patch_header_stream.Init(patch_file_mem.data(), patch_file_mem.length());
- EnsemblePatchApplication patch_process;
- Status status = patch_process.ReadHeader(&patch_header_stream);
- if (status != C_OK)
- return status;
- // Read the old_file.
- base::MemoryMappedFile old_file_mem;
- if (!old_file_mem.Initialize(std::move(old_file)))
- return C_READ_ERROR;
- // Apply patch on streams.
- SourceStream old_source_stream;
- SourceStream patch_source_stream;
- old_source_stream.Init(old_file_mem.data(), old_file_mem.length());
- patch_source_stream.Init(patch_file_mem.data(), patch_file_mem.length());
- SinkStream new_sink_stream;
- status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream,
- &new_sink_stream);
- if (status != C_OK)
- return status;
- // Write the patched data to |new_file_name|.
- int written = new_file.Write(
- 0,
- reinterpret_cast<const char*>(new_sink_stream.Buffer()),
- static_cast<int>(new_sink_stream.Length()));
- if (written == -1)
- return C_WRITE_OPEN_ERROR;
- if (static_cast<size_t>(written) != new_sink_stream.Length())
- return C_WRITE_ERROR;
- return C_OK;
- }
- Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
- const base::FilePath::CharType* patch_file_name,
- const base::FilePath::CharType* new_file_name) {
- Status result = ApplyEnsemblePatch(
- base::File(base::FilePath(old_file_name),
- base::File::FLAG_OPEN | base::File::FLAG_READ |
- base::File::FLAG_WIN_SHARE_DELETE),
- base::File(base::FilePath(patch_file_name),
- base::File::FLAG_OPEN | base::File::FLAG_READ |
- base::File::FLAG_WIN_SHARE_DELETE),
- base::File(base::FilePath(new_file_name),
- base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
- base::File::FLAG_WIN_EXCLUSIVE_WRITE |
- base::File::FLAG_WIN_SHARE_DELETE));
- if (result != C_OK)
- base::DeleteFile(base::FilePath(new_file_name));
- return result;
- }
- } // namespace courgette
|