// Copyright 2013 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 "chrome/installer/setup/archive_patch_helper.h" #include "base/files/file_util.h" #include "base/logging.h" #include "chrome/installer/util/lzma_util.h" #include "courgette/courgette.h" #include "third_party/bspatch/mbspatch.h" namespace installer { ArchivePatchHelper::ArchivePatchHelper(const base::FilePath& working_directory, const base::FilePath& compressed_archive, const base::FilePath& patch_source, const base::FilePath& target) : working_directory_(working_directory), compressed_archive_(compressed_archive), patch_source_(patch_source), target_(target) {} ArchivePatchHelper::~ArchivePatchHelper() {} // static bool ArchivePatchHelper::UncompressAndPatch( const base::FilePath& working_directory, const base::FilePath& compressed_archive, const base::FilePath& patch_source, const base::FilePath& target) { ArchivePatchHelper instance(working_directory, compressed_archive, patch_source, target); return (instance.Uncompress(NULL) && (instance.EnsemblePatch() || instance.BinaryPatch())); } bool ArchivePatchHelper::Uncompress(base::FilePath* last_uncompressed_file) { // The target shouldn't already exist. DCHECK(!base::PathExists(target_)); // UnPackArchive takes care of logging. base::string16 output_file; int32 lzma_result = LzmaUtil::UnPackArchive(compressed_archive_.value(), working_directory_.value(), &output_file); if (lzma_result != NO_ERROR) return false; last_uncompressed_file_ = base::FilePath(output_file); if (last_uncompressed_file) *last_uncompressed_file = last_uncompressed_file_; return true; } bool ArchivePatchHelper::EnsemblePatch() { if (last_uncompressed_file_.empty()) { LOG(ERROR) << "No patch file found in compressed archive."; return false; } courgette::Status result = courgette::ApplyEnsemblePatch(patch_source_.value().c_str(), last_uncompressed_file_.value().c_str(), target_.value().c_str()); if (result == courgette::C_OK) return true; LOG(ERROR) << "Failed to apply patch " << last_uncompressed_file_.value() << " to file " << patch_source_.value() << " and generating file " << target_.value() << " using courgette. err=" << result; // Ensure a partial output is not left behind. base::DeleteFile(target_, false); return false; } bool ArchivePatchHelper::BinaryPatch() { if (last_uncompressed_file_.empty()) { LOG(ERROR) << "No patch file found in compressed archive."; return false; } int result = ApplyBinaryPatch(patch_source_.value().c_str(), last_uncompressed_file_.value().c_str(), target_.value().c_str()); if (result == OK) return true; LOG(ERROR) << "Failed to apply patch " << last_uncompressed_file_.value() << " to file " << patch_source_.value() << " and generating file " << target_.value() << " using bsdiff. err=" << result; // Ensure a partial output is not left behind. base::DeleteFile(target_, false); return false; } } // namespace installer