Merge AOSP android-9.0.0_r3
Fix conflicts and make it build in 5.1, 6.0, 7.1, 8.1, and 9.0 Change-Id: Ida0a64c29ff27d339b7f42a18d820930964ac6e4
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
// Copyright (C) 2017 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
cc_defaults {
|
||||
name: "applypatch_defaults",
|
||||
|
||||
cflags: [
|
||||
"-D_FILE_OFFSET_BITS=64",
|
||||
"-DZLIB_CONST",
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
],
|
||||
|
||||
local_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libapplypatch",
|
||||
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"applypatch_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"applypatch.cpp",
|
||||
"bspatch.cpp",
|
||||
"freecache.cpp",
|
||||
"imgpatch.cpp",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libbase",
|
||||
"libbspatch",
|
||||
"libbz",
|
||||
"libcrypto",
|
||||
"libedify",
|
||||
"libotafault",
|
||||
"libotautil",
|
||||
"libz",
|
||||
],
|
||||
|
||||
target: {
|
||||
darwin: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libapplypatch_modes",
|
||||
|
||||
defaults: [
|
||||
"applypatch_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"applypatch_modes.cpp",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libapplypatch",
|
||||
"libbase",
|
||||
"libcrypto",
|
||||
"libedify",
|
||||
"libotautil",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "applypatch",
|
||||
|
||||
defaults: [
|
||||
"applypatch_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"applypatch_main.cpp",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libapplypatch_modes",
|
||||
"libapplypatch",
|
||||
"libedify",
|
||||
"libotafault",
|
||||
"libotautil",
|
||||
"libbspatch",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbrotli",
|
||||
"libbz",
|
||||
"libcrypto",
|
||||
"liblog",
|
||||
"libz",
|
||||
"libziparchive",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libimgdiff",
|
||||
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"applypatch_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"imgdiff.cpp",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libbase",
|
||||
"libbsdiff",
|
||||
"libdivsufsort",
|
||||
"libdivsufsort64",
|
||||
"liblog",
|
||||
"libotautil",
|
||||
"libutils",
|
||||
"libz",
|
||||
"libziparchive",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "imgdiff",
|
||||
|
||||
srcs: [
|
||||
"imgdiff_main.cpp",
|
||||
],
|
||||
|
||||
defaults: [
|
||||
"applypatch_defaults",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libimgdiff",
|
||||
"libotautil",
|
||||
"libbsdiff",
|
||||
"libdivsufsort",
|
||||
"libdivsufsort64",
|
||||
"libziparchive",
|
||||
"libbase",
|
||||
"libutils",
|
||||
"liblog",
|
||||
"libbrotli",
|
||||
"libbz",
|
||||
"libz",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libimgpatch",
|
||||
|
||||
// The host module is for recovery_host_test (Linux only).
|
||||
host_supported: true,
|
||||
|
||||
defaults: [
|
||||
"applypatch_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"bspatch.cpp",
|
||||
"imgpatch.cpp",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libbase",
|
||||
"libbspatch",
|
||||
"libbz",
|
||||
"libcrypto",
|
||||
"libedify",
|
||||
"libotautil",
|
||||
"libz",
|
||||
],
|
||||
|
||||
target: {
|
||||
darwin: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
# Copyright (C) 2016 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This file is for building imgdiff in Chrome OS.
|
||||
|
||||
CPPFLAGS += -iquote.. -Iinclude
|
||||
CXXFLAGS += -std=c++11 -O3 -Wall -Werror
|
||||
LDLIBS += -lbz2 -lz
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: imgdiff libimgpatch.a
|
||||
|
||||
clean:
|
||||
rm -f *.o imgdiff libimgpatch.a
|
||||
|
||||
imgdiff: imgdiff.o bsdiff.o utils.o
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDLIBS) -o $@ $^
|
||||
|
||||
libimgpatch.a utils.o: CXXFLAGS += -fPIC
|
||||
libimgpatch.a: imgpatch.o bspatch.o utils.o
|
||||
${AR} rcs $@ $^
|
||||
+19
-33
@@ -42,8 +42,9 @@
|
||||
#include "mtdutils/mtdutils.h"
|
||||
|
||||
#include "edify/expr.h"
|
||||
#include "ota_io.h"
|
||||
#include "print_sha1.h"
|
||||
#include "otafault/ota_io.h"
|
||||
#include "otautil/cache_location.h"
|
||||
#include "otautil/print_sha1.h"
|
||||
|
||||
static int LoadPartitionContents(const std::string& filename, FileContents* file);
|
||||
static size_t FileSink(const unsigned char* data, size_t len, int fd);
|
||||
@@ -64,12 +65,13 @@ int LoadFileContents(const char* filename, FileContents* file) {
|
||||
return LoadPartitionContents(filename, file);
|
||||
}
|
||||
|
||||
if (stat(filename, &file->st) == -1) {
|
||||
struct stat sb;
|
||||
if (stat(filename, &sb) == -1) {
|
||||
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> data(file->st.st_size);
|
||||
std::vector<unsigned char> data(sb.st_size);
|
||||
unique_file f(ota_fopen(filename, "rb"));
|
||||
if (!f) {
|
||||
printf("failed to open \"%s\": %s\n", filename, strerror(errno));
|
||||
@@ -208,10 +210,6 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file
|
||||
|
||||
buffer.resize(buffer_size);
|
||||
file->data = std::move(buffer);
|
||||
// Fake some stat() info.
|
||||
file->st.st_mode = 0644;
|
||||
file->st.st_uid = 0;
|
||||
file->st.st_gid = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -240,15 +238,6 @@ int SaveFileContents(const char* filename, const FileContents* file) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chmod(filename, file->st.st_mode) != 0) {
|
||||
printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) {
|
||||
printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -509,12 +498,10 @@ int applypatch_check(const char* filename, const std::vector<std::string>& patch
|
||||
(!patch_sha1_str.empty() && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) {
|
||||
printf("file \"%s\" doesn't have any of expected sha1 sums; checking cache\n", filename);
|
||||
|
||||
// If the source file is missing or corrupted, it might be because
|
||||
// we were killed in the middle of patching it. A copy of it
|
||||
// should have been made in CACHE_TEMP_SOURCE. If that file
|
||||
// exists and matches the sha1 we're looking for, the check still
|
||||
// passes.
|
||||
if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
|
||||
// If the source file is missing or corrupted, it might be because we were killed in the middle
|
||||
// of patching it. A copy of it should have been made in cache_temp_source. If that file
|
||||
// exists and matches the sha1 we're looking for, the check still passes.
|
||||
if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), &file) != 0) {
|
||||
printf("failed to load cache file\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -560,9 +547,8 @@ int CacheSizeCheck(size_t bytes) {
|
||||
if (MakeFreeSpaceOnCache(bytes) < 0) {
|
||||
printf("unable to make %zu bytes available on /cache\n", bytes);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function applies binary patches to EMMC target files in a way that is safe (the original
|
||||
@@ -587,7 +573,7 @@ int CacheSizeCheck(size_t bytes) {
|
||||
// become obsolete since we have dropped the support for patching non-EMMC targets (EMMC targets
|
||||
// have the size embedded in the filename).
|
||||
int applypatch(const char* source_filename, const char* target_filename,
|
||||
const char* target_sha1_str, size_t target_size __unused,
|
||||
const char* target_sha1_str, size_t /* target_size */,
|
||||
const std::vector<std::string>& patch_sha1_str,
|
||||
const std::vector<std::unique_ptr<Value>>& patch_data, const Value* bonus_data) {
|
||||
printf("patch %s: ", source_filename);
|
||||
@@ -637,7 +623,7 @@ int applypatch(const char* source_filename, const char* target_filename,
|
||||
printf("source file is bad; trying copy\n");
|
||||
|
||||
FileContents copy_file;
|
||||
if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) {
|
||||
if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), ©_file) < 0) {
|
||||
printf("failed to read copy file\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -732,7 +718,7 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
|
||||
printf("not enough free space on /cache\n");
|
||||
return 1;
|
||||
}
|
||||
if (SaveFileContents(CACHE_TEMP_SOURCE, &source_file) < 0) {
|
||||
if (SaveFileContents(CacheLocation::location().cache_temp_source().c_str(), &source_file) < 0) {
|
||||
printf("failed to back up source file\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -749,11 +735,11 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
|
||||
|
||||
int result;
|
||||
if (use_bsdiff) {
|
||||
result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0,
|
||||
sink, &ctx);
|
||||
result =
|
||||
ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), *patch, 0, sink, &ctx);
|
||||
} else {
|
||||
result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink,
|
||||
&ctx, bonus_data);
|
||||
result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), *patch, sink, &ctx,
|
||||
bonus_data);
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
@@ -778,7 +764,7 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
|
||||
}
|
||||
|
||||
// Delete the backup copy of the source.
|
||||
unlink(CACHE_TEMP_SOURCE);
|
||||
unlink(CacheLocation::location().cache_temp_source().c_str());
|
||||
|
||||
// Success!
|
||||
return 0;
|
||||
|
||||
+11
-12
@@ -26,11 +26,12 @@
|
||||
#include <string>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <bspatch.h>
|
||||
#include <bsdiff/bspatch.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "applypatch/applypatch.h"
|
||||
#include "print_sha1.h"
|
||||
#include "edify/expr.h"
|
||||
#include "otautil/print_sha1.h"
|
||||
|
||||
void ShowBSDiffLicense() {
|
||||
puts("The bsdiff library used herein is:\n"
|
||||
@@ -64,7 +65,7 @@ void ShowBSDiffLicense() {
|
||||
);
|
||||
}
|
||||
|
||||
int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch,
|
||||
int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value& patch,
|
||||
size_t patch_offset, SinkFn sink, SHA_CTX* ctx) {
|
||||
auto sha_sink = [&sink, &ctx](const uint8_t* data, size_t len) {
|
||||
len = sink(data, len);
|
||||
@@ -72,23 +73,21 @@ int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value
|
||||
return len;
|
||||
};
|
||||
|
||||
CHECK(patch != nullptr);
|
||||
CHECK_LE(patch_offset, patch->data.size());
|
||||
CHECK_LE(patch_offset, patch.data.size());
|
||||
|
||||
int result = bsdiff::bspatch(old_data, old_size,
|
||||
reinterpret_cast<const uint8_t*>(&patch->data[patch_offset]),
|
||||
patch->data.size() - patch_offset, sha_sink);
|
||||
reinterpret_cast<const uint8_t*>(&patch.data[patch_offset]),
|
||||
patch.data.size() - patch_offset, sha_sink);
|
||||
if (result != 0) {
|
||||
LOG(ERROR) << "bspatch failed, result: " << result;
|
||||
// print SHA1 of the patch in the case of a data error.
|
||||
if (result == 2) {
|
||||
uint8_t digest[SHA_DIGEST_LENGTH];
|
||||
SHA1(reinterpret_cast<const uint8_t*>(patch->data.data() + patch_offset),
|
||||
patch->data.size() - patch_offset, digest);
|
||||
SHA1(reinterpret_cast<const uint8_t*>(patch.data.data() + patch_offset),
|
||||
patch.data.size() - patch_offset, digest);
|
||||
std::string patch_sha1 = print_sha1(digest);
|
||||
LOG(ERROR) << "Patch may be corrupted, offset: " << patch_offset << ", SHA1: "
|
||||
<< patch_sha1;
|
||||
LOG(ERROR) << "Patch may be corrupted, offset: " << patch_offset << ", SHA1: " << patch_sha1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "applypatch/applypatch.h"
|
||||
#include "otautil/cache_location.h"
|
||||
|
||||
static int EliminateOpenFiles(std::set<std::string>* files) {
|
||||
std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
|
||||
@@ -90,10 +91,9 @@ static std::set<std::string> FindExpendableFiles() {
|
||||
while ((de = readdir(d.get())) != 0) {
|
||||
std::string path = std::string(dirs[i]) + "/" + de->d_name;
|
||||
|
||||
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
|
||||
// restarted during installation and could be depending on it to
|
||||
// be there.
|
||||
if (path == CACHE_TEMP_SOURCE) {
|
||||
// We can't delete cache_temp_source; if it's there we might have restarted during
|
||||
// installation and could be depending on it to be there.
|
||||
if (path == CacheLocation::location().cache_temp_source()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,12 @@ static std::set<std::string> FindExpendableFiles() {
|
||||
}
|
||||
|
||||
int MakeFreeSpaceOnCache(size_t bytes_needed) {
|
||||
#ifndef __ANDROID__
|
||||
// TODO (xunchang) implement a heuristic cache size check during host simulation.
|
||||
printf("Skip making (%zu) bytes free space on cache; program is running on host\n", bytes_needed);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
size_t free_now = FreeSpaceForFile("/cache");
|
||||
printf("%zu bytes free on /cache (%zu needed)\n", free_now, bytes_needed);
|
||||
|
||||
|
||||
+1194
-666
File diff suppressed because it is too large
Load Diff
+47
-47
@@ -37,6 +37,8 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "edify/expr.h"
|
||||
|
||||
static inline int64_t Read8(const void *address) {
|
||||
return android::base::get_unaligned<int64_t>(address);
|
||||
}
|
||||
@@ -48,7 +50,7 @@ static inline int32_t Read4(const void *address) {
|
||||
// This function is a wrapper of ApplyBSDiffPatch(). It has a custom sink function to deflate the
|
||||
// patched data and stream the deflated data to output.
|
||||
static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_len,
|
||||
const Value* patch, size_t patch_offset,
|
||||
const Value& patch, size_t patch_offset,
|
||||
const char* deflate_header, SinkFn sink, SHA_CTX* ctx) {
|
||||
size_t expected_target_length = static_cast<size_t>(Read8(deflate_header + 32));
|
||||
int level = Read4(deflate_header + 40);
|
||||
@@ -57,13 +59,13 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
int mem_level = Read4(deflate_header + 52);
|
||||
int strategy = Read4(deflate_header + 56);
|
||||
|
||||
std::unique_ptr<z_stream, decltype(&deflateEnd)> strm(new z_stream(), deflateEnd);
|
||||
strm->zalloc = Z_NULL;
|
||||
strm->zfree = Z_NULL;
|
||||
strm->opaque = Z_NULL;
|
||||
strm->avail_in = 0;
|
||||
strm->next_in = nullptr;
|
||||
int ret = deflateInit2(strm.get(), level, method, window_bits, mem_level, strategy);
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = 0;
|
||||
strm.next_in = nullptr;
|
||||
int ret = deflateInit2(&strm, level, method, window_bits, mem_level, strategy);
|
||||
if (ret != Z_OK) {
|
||||
LOG(ERROR) << "Failed to init uncompressed data deflation: " << ret;
|
||||
return false;
|
||||
@@ -74,18 +76,19 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
size_t actual_target_length = 0;
|
||||
size_t total_written = 0;
|
||||
static constexpr size_t buffer_size = 32768;
|
||||
auto compression_sink = [&](const uint8_t* data, size_t len) -> size_t {
|
||||
auto compression_sink = [&strm, &actual_target_length, &expected_target_length, &total_written,
|
||||
&ret, &ctx, &sink](const uint8_t* data, size_t len) -> size_t {
|
||||
// The input patch length for an update never exceeds INT_MAX.
|
||||
strm->avail_in = len;
|
||||
strm->next_in = data;
|
||||
strm.avail_in = len;
|
||||
strm.next_in = data;
|
||||
do {
|
||||
std::vector<uint8_t> buffer(buffer_size);
|
||||
strm->avail_out = buffer_size;
|
||||
strm->next_out = buffer.data();
|
||||
strm.avail_out = buffer_size;
|
||||
strm.next_out = buffer.data();
|
||||
if (actual_target_length + len < expected_target_length) {
|
||||
ret = deflate(strm.get(), Z_NO_FLUSH);
|
||||
ret = deflate(&strm, Z_NO_FLUSH);
|
||||
} else {
|
||||
ret = deflate(strm.get(), Z_FINISH);
|
||||
ret = deflate(&strm, Z_FINISH);
|
||||
}
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||
LOG(ERROR) << "Failed to deflate stream: " << ret;
|
||||
@@ -93,20 +96,24 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t have = buffer_size - strm->avail_out;
|
||||
size_t have = buffer_size - strm.avail_out;
|
||||
total_written += have;
|
||||
if (sink(buffer.data(), have) != have) {
|
||||
LOG(ERROR) << "Failed to write " << have << " compressed bytes to output.";
|
||||
return 0;
|
||||
}
|
||||
if (ctx) SHA1_Update(ctx, buffer.data(), have);
|
||||
} while ((strm->avail_in != 0 || strm->avail_out == 0) && ret != Z_STREAM_END);
|
||||
} while ((strm.avail_in != 0 || strm.avail_out == 0) && ret != Z_STREAM_END);
|
||||
|
||||
actual_target_length += len;
|
||||
return len;
|
||||
};
|
||||
|
||||
if (ApplyBSDiffPatch(src_data, src_len, patch, patch_offset, compression_sink, nullptr) != 0) {
|
||||
int bspatch_result =
|
||||
ApplyBSDiffPatch(src_data, src_len, patch, patch_offset, compression_sink, nullptr);
|
||||
deflateEnd(&strm);
|
||||
|
||||
if (bspatch_result != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -128,48 +135,39 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
|
||||
int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const unsigned char* patch_data,
|
||||
size_t patch_size, SinkFn sink) {
|
||||
Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size));
|
||||
|
||||
return ApplyImagePatch(old_data, old_size, &patch, sink, nullptr, nullptr);
|
||||
return ApplyImagePatch(old_data, old_size, patch, sink, nullptr, nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply the patch given in 'patch_filename' to the source data given
|
||||
* by (old_data, old_size). Write the patched output to the 'output'
|
||||
* file, and update the SHA context with the output data as well.
|
||||
* Return 0 on success.
|
||||
*/
|
||||
int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink,
|
||||
int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value& patch, SinkFn sink,
|
||||
SHA_CTX* ctx, const Value* bonus_data) {
|
||||
if (patch->data.size() < 12) {
|
||||
if (patch.data.size() < 12) {
|
||||
printf("patch too short to contain header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
|
||||
// (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
|
||||
// CHUNK_GZIP.)
|
||||
size_t pos = 12;
|
||||
const char* header = &patch->data[0];
|
||||
if (memcmp(header, "IMGDIFF2", 8) != 0) {
|
||||
// IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW. (IMGDIFF1, which is no longer
|
||||
// supported, used CHUNK_NORMAL and CHUNK_GZIP.)
|
||||
const char* const patch_header = patch.data.data();
|
||||
if (memcmp(patch_header, "IMGDIFF2", 8) != 0) {
|
||||
printf("corrupt patch file header (magic number)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int num_chunks = Read4(header + 8);
|
||||
|
||||
int num_chunks = Read4(patch_header + 8);
|
||||
size_t pos = 12;
|
||||
for (int i = 0; i < num_chunks; ++i) {
|
||||
// each chunk's header record starts with 4 bytes.
|
||||
if (pos + 4 > patch->data.size()) {
|
||||
if (pos + 4 > patch.data.size()) {
|
||||
printf("failed to read chunk %d record\n", i);
|
||||
return -1;
|
||||
}
|
||||
int type = Read4(&patch->data[pos]);
|
||||
int type = Read4(patch_header + pos);
|
||||
pos += 4;
|
||||
|
||||
if (type == CHUNK_NORMAL) {
|
||||
const char* normal_header = &patch->data[pos];
|
||||
const char* normal_header = patch_header + pos;
|
||||
pos += 24;
|
||||
if (pos > patch->data.size()) {
|
||||
if (pos > patch.data.size()) {
|
||||
printf("failed to read chunk %d normal header data\n", i);
|
||||
return -1;
|
||||
}
|
||||
@@ -187,30 +185,32 @@ int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value*
|
||||
return -1;
|
||||
}
|
||||
} else if (type == CHUNK_RAW) {
|
||||
const char* raw_header = &patch->data[pos];
|
||||
const char* raw_header = patch_header + pos;
|
||||
pos += 4;
|
||||
if (pos > patch->data.size()) {
|
||||
if (pos > patch.data.size()) {
|
||||
printf("failed to read chunk %d raw header data\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t data_len = static_cast<size_t>(Read4(raw_header));
|
||||
|
||||
if (pos + data_len > patch->data.size()) {
|
||||
if (pos + data_len > patch.data.size()) {
|
||||
printf("failed to read chunk %d raw data\n", i);
|
||||
return -1;
|
||||
}
|
||||
if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len);
|
||||
if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len) != data_len) {
|
||||
if (ctx) {
|
||||
SHA1_Update(ctx, patch_header + pos, data_len);
|
||||
}
|
||||
if (sink(reinterpret_cast<const unsigned char*>(patch_header + pos), data_len) != data_len) {
|
||||
printf("failed to write chunk %d raw data\n", i);
|
||||
return -1;
|
||||
}
|
||||
pos += data_len;
|
||||
} else if (type == CHUNK_DEFLATE) {
|
||||
// deflate chunks have an additional 60 bytes in their chunk header.
|
||||
const char* deflate_header = &patch->data[pos];
|
||||
const char* deflate_header = patch_header + pos;
|
||||
pos += 60;
|
||||
if (pos > patch->data.size()) {
|
||||
if (pos > patch.data.size()) {
|
||||
printf("failed to read chunk %d deflate header data\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define _APPLYPATCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -27,24 +26,18 @@
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "edify/expr.h"
|
||||
// Forward declaration to avoid including "edify/expr.h" in the header.
|
||||
struct Value;
|
||||
|
||||
struct FileContents {
|
||||
uint8_t sha1[SHA_DIGEST_LENGTH];
|
||||
std::vector<unsigned char> data;
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
// When there isn't enough room on the target filesystem to hold the
|
||||
// patched version of the file, we copy the original here and delete
|
||||
// it to free up space. If the expected source file doesn't exist, or
|
||||
// is corrupted, we look to see if this file contains the bits we want
|
||||
// and use it as the source instead.
|
||||
#define CACHE_TEMP_SOURCE "/cache/saved.file"
|
||||
|
||||
using SinkFn = std::function<size_t(const unsigned char*, size_t)>;
|
||||
|
||||
// applypatch.cpp
|
||||
|
||||
int ShowLicenses();
|
||||
size_t FreeSpaceForFile(const char* filename);
|
||||
int CacheSizeCheck(size_t bytes);
|
||||
@@ -66,15 +59,25 @@ int LoadFileContents(const char* filename, FileContents* file);
|
||||
int SaveFileContents(const char* filename, const FileContents* file);
|
||||
|
||||
// bspatch.cpp
|
||||
|
||||
void ShowBSDiffLicense();
|
||||
int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch,
|
||||
|
||||
// Applies the bsdiff-patch given in 'patch' (from offset 'patch_offset' to the end) to the source
|
||||
// data given by (old_data, old_size). Writes the patched output through the given 'sink', and
|
||||
// updates the SHA-1 context with the output data. Returns 0 on success.
|
||||
int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value& patch,
|
||||
size_t patch_offset, SinkFn sink, SHA_CTX* ctx);
|
||||
|
||||
// imgpatch.cpp
|
||||
int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink,
|
||||
|
||||
// Applies the imgdiff-patch given in 'patch' to the source data given by (old_data, old_size), with
|
||||
// the optional bonus data. Writes the patched output through the given 'sink', and updates the
|
||||
// SHA-1 context with the output data. Returns 0 on success.
|
||||
int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value& patch, SinkFn sink,
|
||||
SHA_CTX* ctx, const Value* bonus_data);
|
||||
|
||||
// freecache.cpp
|
||||
|
||||
int MakeFreeSpaceOnCache(size_t bytes_needed);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _APPLYPATCH_IMGDIFF_IMAGE_H
|
||||
#define _APPLYPATCH_IMGDIFF_IMAGE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <bsdiff/bsdiff.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "imgdiff.h"
|
||||
#include "otautil/rangeset.h"
|
||||
|
||||
class ImageChunk {
|
||||
public:
|
||||
static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream.
|
||||
static constexpr auto MEMLEVEL = 8; // the default value.
|
||||
static constexpr auto METHOD = Z_DEFLATED;
|
||||
static constexpr auto STRATEGY = Z_DEFAULT_STRATEGY;
|
||||
|
||||
ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content, size_t raw_data_len,
|
||||
std::string entry_name = {});
|
||||
|
||||
int GetType() const {
|
||||
return type_;
|
||||
}
|
||||
size_t GetRawDataLength() const {
|
||||
return raw_data_len_;
|
||||
}
|
||||
const std::string& GetEntryName() const {
|
||||
return entry_name_;
|
||||
}
|
||||
size_t GetStartOffset() const {
|
||||
return start_;
|
||||
}
|
||||
int GetCompressLevel() const {
|
||||
return compress_level_;
|
||||
}
|
||||
|
||||
// CHUNK_DEFLATE will return the uncompressed data for diff, while other types will simply return
|
||||
// the raw data.
|
||||
const uint8_t* DataForPatch() const;
|
||||
size_t DataLengthForPatch() const;
|
||||
|
||||
void Dump(size_t index) const;
|
||||
|
||||
void SetUncompressedData(std::vector<uint8_t> data);
|
||||
bool SetBonusData(const std::vector<uint8_t>& bonus_data);
|
||||
|
||||
bool operator==(const ImageChunk& other) const;
|
||||
bool operator!=(const ImageChunk& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cause a gzip chunk to be treated as a normal chunk (ie, as a blob of uninterpreted data).
|
||||
* The resulting patch will likely be about as big as the target file, but it lets us handle
|
||||
* the case of images where some gzip chunks are reconstructible but others aren't (by treating
|
||||
* the ones that aren't as normal chunks).
|
||||
*/
|
||||
void ChangeDeflateChunkToNormal();
|
||||
|
||||
/*
|
||||
* Verify that we can reproduce exactly the same compressed data that we started with. Sets the
|
||||
* level, method, windowBits, memLevel, and strategy fields in the chunk to the encoding
|
||||
* parameters needed to produce the right output.
|
||||
*/
|
||||
bool ReconstructDeflateChunk();
|
||||
bool IsAdjacentNormal(const ImageChunk& other) const;
|
||||
void MergeAdjacentNormal(const ImageChunk& other);
|
||||
|
||||
/*
|
||||
* Compute a bsdiff patch between |src| and |tgt|; Store the result in the patch_data.
|
||||
* |bsdiff_cache| can be used to cache the suffix array if the same |src| chunk is used
|
||||
* repeatedly, pass nullptr if not needed.
|
||||
*/
|
||||
static bool MakePatch(const ImageChunk& tgt, const ImageChunk& src,
|
||||
std::vector<uint8_t>* patch_data,
|
||||
bsdiff::SuffixArrayIndexInterface** bsdiff_cache);
|
||||
|
||||
private:
|
||||
const uint8_t* GetRawData() const;
|
||||
bool TryReconstruction(int level);
|
||||
|
||||
int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
|
||||
size_t start_; // offset of chunk in the original input file
|
||||
const std::vector<uint8_t>* input_file_ptr_; // ptr to the full content of original input file
|
||||
size_t raw_data_len_;
|
||||
|
||||
// deflate encoder parameters
|
||||
int compress_level_;
|
||||
|
||||
// --- for CHUNK_DEFLATE chunks only: ---
|
||||
std::vector<uint8_t> uncompressed_data_;
|
||||
std::string entry_name_; // used for zip entries
|
||||
};
|
||||
|
||||
// PatchChunk stores the patch data between a source chunk and a target chunk. It also keeps track
|
||||
// of the metadata of src&tgt chunks (e.g. offset, raw data length, uncompressed data length).
|
||||
class PatchChunk {
|
||||
public:
|
||||
PatchChunk(const ImageChunk& tgt, const ImageChunk& src, std::vector<uint8_t> data);
|
||||
|
||||
// Construct a CHUNK_RAW patch from the target data directly.
|
||||
explicit PatchChunk(const ImageChunk& tgt);
|
||||
|
||||
// Return true if raw data size is smaller than the patch size.
|
||||
static bool RawDataIsSmaller(const ImageChunk& tgt, size_t patch_size);
|
||||
|
||||
// Update the source start with the new offset within the source range.
|
||||
void UpdateSourceOffset(const SortedRangeSet& src_range);
|
||||
|
||||
// Return the total size (header + data) of the patch.
|
||||
size_t PatchSize() const;
|
||||
|
||||
static bool WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks, int patch_fd);
|
||||
|
||||
private:
|
||||
size_t GetHeaderSize() const;
|
||||
size_t WriteHeaderToFd(int fd, size_t offset, size_t index) const;
|
||||
|
||||
// The patch chunk type is the same as the target chunk type. The only exception is we change
|
||||
// the |type_| to CHUNK_RAW if target length is smaller than the patch size.
|
||||
int type_;
|
||||
|
||||
size_t source_start_;
|
||||
size_t source_len_;
|
||||
size_t source_uncompressed_len_;
|
||||
|
||||
size_t target_start_; // offset of the target chunk within the target file
|
||||
size_t target_len_;
|
||||
size_t target_uncompressed_len_;
|
||||
size_t target_compress_level_; // the deflate compression level of the target chunk.
|
||||
|
||||
std::vector<uint8_t> data_; // storage for the patch data
|
||||
};
|
||||
|
||||
// Interface for zip_mode and image_mode images. We initialize the image from an input file and
|
||||
// split the file content into a list of image chunks.
|
||||
class Image {
|
||||
public:
|
||||
explicit Image(bool is_source) : is_source_(is_source) {}
|
||||
|
||||
virtual ~Image() {}
|
||||
|
||||
// Create a list of image chunks from input file.
|
||||
virtual bool Initialize(const std::string& filename) = 0;
|
||||
|
||||
// Look for runs of adjacent normal chunks and compress them down into a single chunk. (Such
|
||||
// runs can be produced when deflate chunks are changed to normal chunks.)
|
||||
void MergeAdjacentNormalChunks();
|
||||
|
||||
void DumpChunks() const;
|
||||
|
||||
// Non const iterators to access the stored ImageChunks.
|
||||
std::vector<ImageChunk>::iterator begin() {
|
||||
return chunks_.begin();
|
||||
}
|
||||
|
||||
std::vector<ImageChunk>::iterator end() {
|
||||
return chunks_.end();
|
||||
}
|
||||
|
||||
std::vector<ImageChunk>::const_iterator cbegin() const {
|
||||
return chunks_.cbegin();
|
||||
}
|
||||
|
||||
std::vector<ImageChunk>::const_iterator cend() const {
|
||||
return chunks_.cend();
|
||||
}
|
||||
|
||||
ImageChunk& operator[](size_t i);
|
||||
const ImageChunk& operator[](size_t i) const;
|
||||
|
||||
size_t NumOfChunks() const {
|
||||
return chunks_.size();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool ReadFile(const std::string& filename, std::vector<uint8_t>* file_content);
|
||||
|
||||
bool is_source_; // True if it's for source chunks.
|
||||
std::vector<ImageChunk> chunks_; // Internal storage of ImageChunk.
|
||||
std::vector<uint8_t> file_content_; // Store the whole input file in memory.
|
||||
};
|
||||
|
||||
class ZipModeImage : public Image {
|
||||
public:
|
||||
explicit ZipModeImage(bool is_source, size_t limit = 0) : Image(is_source), limit_(limit) {}
|
||||
|
||||
bool Initialize(const std::string& filename) override;
|
||||
|
||||
// Initialize a dummy ZipModeImage from an existing ImageChunk vector. For src img pieces, we
|
||||
// reconstruct a new file_content based on the source ranges; but it's not needed for the tgt img
|
||||
// pieces; because for each chunk both the data and their offset within the file are unchanged.
|
||||
void Initialize(const std::vector<ImageChunk>& chunks, const std::vector<uint8_t>& file_content) {
|
||||
chunks_ = chunks;
|
||||
file_content_ = file_content;
|
||||
}
|
||||
|
||||
// The pesudo source chunk for bsdiff if there's no match for the given target chunk. It's in
|
||||
// fact the whole source file.
|
||||
ImageChunk PseudoSource() const;
|
||||
|
||||
// Find the matching deflate source chunk by entry name. Search for normal chunks also if
|
||||
// |find_normal| is true.
|
||||
ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false);
|
||||
|
||||
const ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false) const;
|
||||
|
||||
// Verify that we can reconstruct the deflate chunks; also change the type to CHUNK_NORMAL if
|
||||
// src and tgt are identical.
|
||||
static bool CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* src_image);
|
||||
|
||||
// Compute the patch between tgt & src images, and write the data into |patch_name|.
|
||||
static bool GeneratePatches(const ZipModeImage& tgt_image, const ZipModeImage& src_image,
|
||||
const std::string& patch_name);
|
||||
|
||||
// Compute the patch based on the lists of split src and tgt images. Generate patches for each
|
||||
// pair of split pieces and write the data to |patch_name|. If |debug_dir| is specified, write
|
||||
// each split src data and patch data into that directory.
|
||||
static bool GeneratePatches(const std::vector<ZipModeImage>& split_tgt_images,
|
||||
const std::vector<ZipModeImage>& split_src_images,
|
||||
const std::vector<SortedRangeSet>& split_src_ranges,
|
||||
const std::string& patch_name, const std::string& split_info_file,
|
||||
const std::string& debug_dir);
|
||||
|
||||
// Split the tgt chunks and src chunks based on the size limit.
|
||||
static bool SplitZipModeImageWithLimit(const ZipModeImage& tgt_image,
|
||||
const ZipModeImage& src_image,
|
||||
std::vector<ZipModeImage>* split_tgt_images,
|
||||
std::vector<ZipModeImage>* split_src_images,
|
||||
std::vector<SortedRangeSet>* split_src_ranges);
|
||||
|
||||
private:
|
||||
// Initialize image chunks based on the zip entries.
|
||||
bool InitializeChunks(const std::string& filename, ZipArchiveHandle handle);
|
||||
// Add the a zip entry to the list.
|
||||
bool AddZipEntryToChunks(ZipArchiveHandle handle, const std::string& entry_name, ZipEntry* entry);
|
||||
// Return the real size of the zip file. (omit the trailing zeros that used for alignment)
|
||||
bool GetZipFileSize(size_t* input_file_size);
|
||||
|
||||
static void ValidateSplitImages(const std::vector<ZipModeImage>& split_tgt_images,
|
||||
const std::vector<ZipModeImage>& split_src_images,
|
||||
std::vector<SortedRangeSet>& split_src_ranges,
|
||||
size_t total_tgt_size);
|
||||
// Construct the dummy split images based on the chunks info and source ranges; and move them into
|
||||
// the given vectors. Return true if we add a new split image into |split_tgt_images|, and
|
||||
// false otherwise.
|
||||
static bool AddSplitImageFromChunkList(const ZipModeImage& tgt_image,
|
||||
const ZipModeImage& src_image,
|
||||
const SortedRangeSet& split_src_ranges,
|
||||
const std::vector<ImageChunk>& split_tgt_chunks,
|
||||
const std::vector<ImageChunk>& split_src_chunks,
|
||||
std::vector<ZipModeImage>* split_tgt_images,
|
||||
std::vector<ZipModeImage>* split_src_images);
|
||||
|
||||
// Function that actually iterates the tgt_chunks and makes patches.
|
||||
static bool GeneratePatchesInternal(const ZipModeImage& tgt_image, const ZipModeImage& src_image,
|
||||
std::vector<PatchChunk>* patch_chunks);
|
||||
|
||||
// size limit in bytes of each chunk. Also, if the length of one zip_entry exceeds the limit,
|
||||
// we'll split that entry into several smaller chunks in advance.
|
||||
size_t limit_;
|
||||
};
|
||||
|
||||
class ImageModeImage : public Image {
|
||||
public:
|
||||
explicit ImageModeImage(bool is_source) : Image(is_source) {}
|
||||
|
||||
// Initialize the image chunks list by searching the magic numbers in an image file.
|
||||
bool Initialize(const std::string& filename) override;
|
||||
|
||||
bool SetBonusData(const std::vector<uint8_t>& bonus_data);
|
||||
|
||||
// In Image Mode, verify that the source and target images have the same chunk structure (ie, the
|
||||
// same sequence of deflate and normal chunks).
|
||||
static bool CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeImage* src_image);
|
||||
|
||||
// In image mode, generate patches against the given source chunks and bonus_data; write the
|
||||
// result to |patch_name|.
|
||||
static bool GeneratePatches(const ImageModeImage& tgt_image, const ImageModeImage& src_image,
|
||||
const std::string& patch_name);
|
||||
};
|
||||
|
||||
#endif // _APPLYPATCH_IMGDIFF_IMAGE_H
|
||||
@@ -1,6 +0,0 @@
|
||||
# This file is for libimgpatch in Chrome OS.
|
||||
|
||||
Name: libimgpatch
|
||||
Description: Apply imgdiff patch
|
||||
Version: 0.0.1
|
||||
Libs: -limgpatch -lbz2 -lz
|
||||
Reference in New Issue
Block a user