1 // Copyright 2013 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 "chrome/installer/setup/archive_patch_helper.h" 6 7 #include "base/file_util.h" 8 #include "base/logging.h" 9 #include "chrome/installer/util/lzma_util.h" 10 #include "courgette/courgette.h" 11 #include "third_party/bspatch/mbspatch.h" 12 13 namespace installer { 14 15 ArchivePatchHelper::ArchivePatchHelper(const base::FilePath& working_directory, 16 const base::FilePath& compressed_archive, 17 const base::FilePath& patch_source, 18 const base::FilePath& target) 19 : working_directory_(working_directory), 20 compressed_archive_(compressed_archive), 21 patch_source_(patch_source), 22 target_(target) {} 23 24 ArchivePatchHelper::~ArchivePatchHelper() {} 25 26 // static 27 bool ArchivePatchHelper::UncompressAndPatch( 28 const base::FilePath& working_directory, 29 const base::FilePath& compressed_archive, 30 const base::FilePath& patch_source, 31 const base::FilePath& target) { 32 ArchivePatchHelper instance(working_directory, compressed_archive, 33 patch_source, target); 34 return (instance.Uncompress(NULL) && 35 (instance.EnsemblePatch() || instance.BinaryPatch())); 36 } 37 38 bool ArchivePatchHelper::Uncompress(base::FilePath* last_uncompressed_file) { 39 // The target shouldn't already exist. 40 DCHECK(!base::PathExists(target_)); 41 42 // UnPackArchive takes care of logging. 43 string16 output_file; 44 int32 lzma_result = LzmaUtil::UnPackArchive(compressed_archive_.value(), 45 working_directory_.value(), 46 &output_file); 47 if (lzma_result != NO_ERROR) 48 return false; 49 50 last_uncompressed_file_ = base::FilePath(output_file); 51 if (last_uncompressed_file) 52 *last_uncompressed_file = last_uncompressed_file_; 53 return true; 54 } 55 56 bool ArchivePatchHelper::EnsemblePatch() { 57 if (last_uncompressed_file_.empty()) { 58 LOG(ERROR) << "No patch file found in compressed archive."; 59 return false; 60 } 61 62 courgette::Status result = 63 courgette::ApplyEnsemblePatch(patch_source_.value().c_str(), 64 last_uncompressed_file_.value().c_str(), 65 target_.value().c_str()); 66 if (result == courgette::C_OK) 67 return true; 68 69 LOG(ERROR) 70 << "Failed to apply patch " << last_uncompressed_file_.value() 71 << " to file " << patch_source_.value() 72 << " and generating file " << target_.value() 73 << " using courgette. err=" << result; 74 75 // Ensure a partial output is not left behind. 76 base::DeleteFile(target_, false); 77 78 return false; 79 } 80 81 bool ArchivePatchHelper::BinaryPatch() { 82 if (last_uncompressed_file_.empty()) { 83 LOG(ERROR) << "No patch file found in compressed archive."; 84 return false; 85 } 86 87 int result = ApplyBinaryPatch(patch_source_.value().c_str(), 88 last_uncompressed_file_.value().c_str(), 89 target_.value().c_str()); 90 if (result == OK) 91 return true; 92 93 LOG(ERROR) 94 << "Failed to apply patch " << last_uncompressed_file_.value() 95 << " to file " << patch_source_.value() 96 << " and generating file " << target_.value() 97 << " using bsdiff. err=" << result; 98 99 // Ensure a partial output is not left behind. 100 base::DeleteFile(target_, false); 101 102 return false; 103 } 104 105 } // namespace installer 106