Chromium 142 broke delta updates on Windows. This commit fixes them by reverting upstream commits 13ca199c and a4d120da with a few patches, vendored code and chromium_src overrides. The changes should affect the browser Windows installer only, and not the Omaha update client. Co-authored-by: Max Karolinskiy <max@brave.com>
126 lines
4.1 KiB
C++
126 lines
4.1 KiB
C++
/* Copyright (c) 2025 The Brave Authors. All rights reserved.
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
// This file contains code that used to be upstream and had to be restored in
|
|
// Brave to support delta updates on Windows until we are on Omaha 4. See:
|
|
// github.com/brave/brave-core/pull/31937
|
|
|
|
#include "brave/installer/setup/archive_patch_helper.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <optional>
|
|
|
|
#include "base/files/file_util.h"
|
|
#include "base/logging.h"
|
|
#include "brave/third_party/bspatch/mbspatch.h"
|
|
#include "chrome/installer/util/lzma_util.h"
|
|
#include "components/zucchini/zucchini.h"
|
|
#include "components/zucchini/zucchini_integration.h"
|
|
|
|
namespace installer {
|
|
|
|
ArchivePatchHelper::ArchivePatchHelper(const base::FilePath& working_directory,
|
|
const base::FilePath& compressed_archive,
|
|
const base::FilePath& patch_source,
|
|
const base::FilePath& target,
|
|
UnPackConsumer consumer)
|
|
: working_directory_(working_directory),
|
|
compressed_archive_(compressed_archive),
|
|
patch_source_(patch_source),
|
|
target_(target),
|
|
consumer_(consumer) {}
|
|
|
|
ArchivePatchHelper::~ArchivePatchHelper() = default;
|
|
|
|
// static
|
|
bool ArchivePatchHelper::UncompressAndPatch(
|
|
const base::FilePath& working_directory,
|
|
const base::FilePath& compressed_archive,
|
|
const base::FilePath& patch_source,
|
|
const base::FilePath& target,
|
|
UnPackConsumer consumer) {
|
|
ArchivePatchHelper instance(working_directory, compressed_archive,
|
|
patch_source, target, consumer);
|
|
return (instance.Uncompress(nullptr) && instance.ApplyAndDeletePatch());
|
|
}
|
|
|
|
bool ArchivePatchHelper::Uncompress(base::FilePath* last_uncompressed_file) {
|
|
// The target shouldn't already exist.
|
|
DCHECK(!base::PathExists(target_));
|
|
|
|
// UnPackArchive takes care of logging.
|
|
base::FilePath output_file;
|
|
UnPackStatus unpack_status =
|
|
UnPackArchive(compressed_archive_, working_directory_, &output_file);
|
|
RecordUnPackMetrics(unpack_status, consumer_);
|
|
if (unpack_status != UNPACK_NO_ERROR) {
|
|
return false;
|
|
}
|
|
|
|
last_uncompressed_file_ = output_file;
|
|
if (last_uncompressed_file) {
|
|
*last_uncompressed_file = last_uncompressed_file_;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ArchivePatchHelper::ApplyAndDeletePatch() {
|
|
const bool succeeded = ZucchiniEnsemblePatch() || BinaryPatch();
|
|
if (!last_uncompressed_file_.empty()) {
|
|
base::DeleteFile(last_uncompressed_file_);
|
|
}
|
|
return succeeded;
|
|
}
|
|
|
|
bool ArchivePatchHelper::ZucchiniEnsemblePatch() {
|
|
if (last_uncompressed_file_.empty()) {
|
|
LOG(ERROR) << "No patch file found in compressed archive.";
|
|
return false;
|
|
}
|
|
|
|
zucchini::status::Code result =
|
|
zucchini::Apply(patch_source_, last_uncompressed_file_, target_);
|
|
|
|
if (result == zucchini::status::kStatusSuccess) {
|
|
return true;
|
|
}
|
|
|
|
LOG(ERROR) << "Failed to apply patch " << last_uncompressed_file_.value()
|
|
<< " to file " << patch_source_.value() << " and generating file "
|
|
<< target_.value()
|
|
<< " using Zucchini. err=" << static_cast<uint32_t>(result);
|
|
|
|
// Ensure a partial output is not left behind.
|
|
base::DeleteFile(target_);
|
|
|
|
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_);
|
|
|
|
return false;
|
|
}
|
|
|
|
} // namespace installer
|