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:
Ethan Yonker
2018-08-24 11:17:39 -05:00
208 changed files with 9097 additions and 4512 deletions
+206
View File
@@ -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,
},
},
}
-33
View File
@@ -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
View File
@@ -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, &copy_file) < 0) {
if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), &copy_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
View File
@@ -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;
}
}
+10 -4
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+47 -47
View File
@@ -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;
}
+15 -12
View File
@@ -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
-6
View File
@@ -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