From 06f1ae9aaca969ee95ef840f22b6b461c304542d Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Tue, 13 Mar 2018 18:19:34 +0000 Subject: [Zucchini] Move Zucchini from /chrome/installer/ to /components/. (Use "git log --follow" to see older revisions of files). /components/ is the most logical place to put Zucchini, which only depends on /base and /testing/gtest. This move also enables Zucchini to be used by the Component Updater. Details: - Move all files; run the following to change deps and guards: sed 's/chrome\/installer/components/' *.cc *.h -i sed 's/CHROME_INSTALLER/COMPONENTS/' *.cc *.h -i - Sorting works out pretty well! - Change all 'chrome/installer/zucchini' to 'components/zucchini' throughout other parts of the repo; sort if necessary. - Fix 6 'git cl lint' errors. - Change 1 Bind() usage to BindRepeated(). - Update OWNER. Bug: 729154 Change-Id: I50c5a7d411ea85f707b5994ab319dfb2a1acccf7 Reviewed-on: https://chromium-review.googlesource.com/954923 Reviewed-by: Greg Thompson Reviewed-by: Jochen Eisinger Reviewed-by: Samuel Huang Commit-Queue: Samuel Huang Cr-Commit-Position: refs/heads/master@{#542857} NOKEYCHECK=True GitOrigin-RevId: 577ef6c435e8d43be6e3e60ccbcbd1881780f4ec --- zucchini_apply.cc | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 zucchini_apply.cc (limited to 'zucchini_apply.cc') diff --git a/zucchini_apply.cc b/zucchini_apply.cc new file mode 100644 index 0000000..1532874 --- /dev/null +++ b/zucchini_apply.cc @@ -0,0 +1,202 @@ +// Copyright 2017 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. + +#include "components/zucchini/zucchini_apply.h" + +#include +#include +#include +#include + +#include "base/logging.h" +#include "components/zucchini/disassembler.h" +#include "components/zucchini/element_detection.h" +#include "components/zucchini/equivalence_map.h" +#include "components/zucchini/image_index.h" + +namespace zucchini { + +bool ApplyEquivalenceAndExtraData(ConstBufferView old_image, + const PatchElementReader& patch_reader, + MutableBufferView new_image) { + EquivalenceSource equiv_source = patch_reader.GetEquivalenceSource(); + ExtraDataSource extra_data_source = patch_reader.GetExtraDataSource(); + MutableBufferView::iterator dst_it = new_image.begin(); + + for (auto equivalence = equiv_source.GetNext(); equivalence.has_value(); + equivalence = equiv_source.GetNext()) { + // TODO(etiennep): Guard against out of range errors and return false + // instead. + MutableBufferView::iterator next_dst_it = + new_image.begin() + equivalence->dst_offset; + CHECK(next_dst_it >= dst_it); + offset_t gap = static_cast(next_dst_it - dst_it); + base::Optional extra_data = extra_data_source.GetNext(gap); + if (!extra_data) { + LOG(ERROR) << "Error reading extra_data"; + return false; + } + dst_it = std::copy(extra_data->begin(), extra_data->end(), dst_it); + CHECK_EQ(dst_it, next_dst_it); + dst_it = std::copy_n(old_image.begin() + equivalence->src_offset, + equivalence->length, dst_it); + CHECK_EQ(dst_it, next_dst_it + equivalence->length); + } + offset_t gap = static_cast(new_image.end() - dst_it); + base::Optional extra_data = extra_data_source.GetNext(gap); + if (!extra_data) { + LOG(ERROR) << "Error reading extra_data"; + return false; + } + std::copy(extra_data->begin(), extra_data->end(), dst_it); + if (!equiv_source.Done() || !extra_data_source.Done()) { + LOG(ERROR) << "Found trailing equivalence and extra_data"; + return false; + } + return true; +} + +bool ApplyRawDelta(const PatchElementReader& patch_reader, + MutableBufferView new_image) { + EquivalenceSource equiv_source = patch_reader.GetEquivalenceSource(); + RawDeltaSource raw_delta_source = patch_reader.GetRawDeltaSource(); + // Traverse |equiv_source| and |raw_delta_source| in lockstep. + auto equivalence = equiv_source.GetNext(); + offset_t base_copy_offset = 0; + for (auto delta = raw_delta_source.GetNext(); delta.has_value(); + delta = raw_delta_source.GetNext()) { + while (equivalence.has_value() && + base_copy_offset + equivalence->length <= delta->copy_offset) { + base_copy_offset += equivalence->length; + equivalence = equiv_source.GetNext(); + } + if (!equivalence.has_value()) { + LOG(ERROR) << "Error reading equivalences"; + return false; + } + CHECK_GE(delta->copy_offset, base_copy_offset); + CHECK_LT(delta->copy_offset, base_copy_offset + equivalence->length); + + // Invert byte diff. + new_image[equivalence->dst_offset - base_copy_offset + + delta->copy_offset] += delta->diff; + } + if (!raw_delta_source.Done()) { + LOG(ERROR) << "Found trailing raw_delta"; + return false; + } + return true; +} + +bool ApplyReferencesCorrection(ExecutableType exe_type, + ConstBufferView old_image, + const PatchElementReader& patch, + MutableBufferView new_image) { + auto old_disasm = MakeDisassemblerOfType(old_image, exe_type); + auto new_disasm = + MakeDisassemblerOfType(ConstBufferView(new_image), exe_type); + if (!old_disasm || !new_disasm) { + LOG(ERROR) << "Failed to create Disassembler"; + return false; + } + + ReferenceDeltaSource ref_delta_source = patch.GetReferenceDeltaSource(); + std::map> pool_groups; + for (const auto& ref_group : old_disasm->MakeReferenceGroups()) + pool_groups[ref_group.pool_tag()].push_back(ref_group); + + OffsetMapper offset_mapper(patch.GetEquivalenceSource()); + + std::vector new_groups = new_disasm->MakeReferenceGroups(); + for (const auto& pool_and_sub_groups : pool_groups) { + PoolTag pool_tag = pool_and_sub_groups.first; + const std::vector& sub_groups = pool_and_sub_groups.second; + + TargetPool targets; + // Load "old" targets, then filter and map them to "new" targets. + for (ReferenceGroup group : sub_groups) + targets.InsertTargets(std::move(*group.GetReader(old_disasm.get()))); + targets.FilterAndProject(offset_mapper); + + // Load extra targets from patch. + TargetSource target_source = patch.GetExtraTargetSource(pool_tag); + targets.InsertTargets(&target_source); + if (!target_source.Done()) { + LOG(ERROR) << "Found trailing extra_targets"; + return false; + } + + // Correct all new references, and write results to |new_disasm|. + for (ReferenceGroup group : sub_groups) { + std::unique_ptr ref_writer = + new_groups[group.type_tag().value()].GetWriter(new_image, + new_disasm.get()); + + EquivalenceSource equiv_source = patch.GetEquivalenceSource(); + for (auto equivalence = equiv_source.GetNext(); equivalence.has_value(); + equivalence = equiv_source.GetNext()) { + std::unique_ptr ref_gen = group.GetReader( + equivalence->src_offset, equivalence->src_end(), old_disasm.get()); + for (auto ref = ref_gen->GetNext(); ref.has_value(); + ref = ref_gen->GetNext()) { + DCHECK_GE(ref->location, equivalence->src_offset); + DCHECK_LT(ref->location, equivalence->src_end()); + + offset_t projected_target = offset_mapper.ForwardProject(ref->target); + offset_t expected_key = targets.KeyForNearestOffset(projected_target); + auto delta = ref_delta_source.GetNext(); + if (!delta.has_value()) { + LOG(ERROR) << "Error reading reference_delta"; + return false; + } + ref->target = targets.OffsetForKey(expected_key + delta.value()); + ref->location = + ref->location - equivalence->src_offset + equivalence->dst_offset; + ref_writer->PutNext(*ref); + } + } + } + } + if (!ref_delta_source.Done()) { + LOG(ERROR) << "Found trailing ref_delta_source"; + return false; + } + return true; +} + +bool ApplyElement(ExecutableType exe_type, + ConstBufferView old_image, + const PatchElementReader& patch_reader, + MutableBufferView new_image) { + return ApplyEquivalenceAndExtraData(old_image, patch_reader, new_image) && + ApplyRawDelta(patch_reader, new_image) && + ApplyReferencesCorrection(exe_type, old_image, patch_reader, + new_image); +} + +/******** Exported Functions ********/ + +status::Code Apply(ConstBufferView old_image, + const EnsemblePatchReader& patch_reader, + MutableBufferView new_image) { + if (!patch_reader.CheckOldFile(old_image)) { + LOG(ERROR) << "Invalid old_image."; + return status::kStatusInvalidOldImage; + } + + for (const auto& element_patch : patch_reader.elements()) { + ElementMatch match = element_patch.element_match(); + if (!ApplyElement(match.exe_type(), old_image[match.old_element.region()], + element_patch, new_image[match.new_element.region()])) + return status::kStatusFatal; + } + + if (!patch_reader.CheckNewFile(ConstBufferView(new_image))) { + LOG(ERROR) << "Invalid new_image."; + return status::kStatusInvalidNewImage; + } + return status::kStatusSuccess; +} + +} // namespace zucchini -- cgit v1.2.3