Home | History | Annotate | Download | only in setup
      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