Merge "More cleanup to imgdiff & imgpatch"
This commit is contained in:
commit
3541934ff5
6 changed files with 134 additions and 198 deletions
|
@ -21,8 +21,7 @@ LOCAL_SRC_FILES := \
|
||||||
applypatch.cpp \
|
applypatch.cpp \
|
||||||
bspatch.cpp \
|
bspatch.cpp \
|
||||||
freecache.cpp \
|
freecache.cpp \
|
||||||
imgpatch.cpp \
|
imgpatch.cpp
|
||||||
utils.cpp
|
|
||||||
LOCAL_MODULE := libapplypatch
|
LOCAL_MODULE := libapplypatch
|
||||||
LOCAL_MODULE_TAGS := eng
|
LOCAL_MODULE_TAGS := eng
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
|
@ -46,8 +45,7 @@ include $(BUILD_STATIC_LIBRARY)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
bspatch.cpp \
|
bspatch.cpp \
|
||||||
imgpatch.cpp \
|
imgpatch.cpp
|
||||||
utils.cpp
|
|
||||||
LOCAL_MODULE := libimgpatch
|
LOCAL_MODULE := libimgpatch
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
$(LOCAL_PATH)/include \
|
$(LOCAL_PATH)/include \
|
||||||
|
@ -56,6 +54,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
libcrypto \
|
libcrypto \
|
||||||
libbspatch \
|
libbspatch \
|
||||||
|
libbase \
|
||||||
libbz \
|
libbz \
|
||||||
libz
|
libz
|
||||||
LOCAL_CFLAGS := \
|
LOCAL_CFLAGS := \
|
||||||
|
@ -68,8 +67,7 @@ include $(BUILD_STATIC_LIBRARY)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
bspatch.cpp \
|
bspatch.cpp \
|
||||||
imgpatch.cpp \
|
imgpatch.cpp
|
||||||
utils.cpp
|
|
||||||
LOCAL_MODULE := libimgpatch
|
LOCAL_MODULE := libimgpatch
|
||||||
LOCAL_MODULE_HOST_OS := linux
|
LOCAL_MODULE_HOST_OS := linux
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
|
@ -79,6 +77,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
libcrypto \
|
libcrypto \
|
||||||
libbspatch \
|
libbspatch \
|
||||||
|
libbase \
|
||||||
libbz \
|
libbz \
|
||||||
libz
|
libz
|
||||||
LOCAL_CFLAGS := \
|
LOCAL_CFLAGS := \
|
||||||
|
@ -123,9 +122,7 @@ LOCAL_SHARED_LIBRARIES := \
|
||||||
LOCAL_CFLAGS := -Werror
|
LOCAL_CFLAGS := -Werror
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
libimgdiff_src_files := \
|
libimgdiff_src_files := imgdiff.cpp
|
||||||
imgdiff.cpp \
|
|
||||||
utils.cpp
|
|
||||||
|
|
||||||
# libbsdiff is compiled with -D_FILE_OFFSET_BITS=64.
|
# libbsdiff is compiled with -D_FILE_OFFSET_BITS=64.
|
||||||
libimgdiff_cflags := \
|
libimgdiff_cflags := \
|
||||||
|
|
|
@ -145,12 +145,22 @@
|
||||||
#include <bsdiff.h>
|
#include <bsdiff.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
using android::base::get_unaligned;
|
using android::base::get_unaligned;
|
||||||
|
|
||||||
static constexpr auto BUFFER_SIZE = 0x8000;
|
static constexpr auto BUFFER_SIZE = 0x8000;
|
||||||
|
|
||||||
|
// If we use this function to write the offset and length (type size_t), their values should not
|
||||||
|
// exceed 2^63; because the signed bit will be casted away.
|
||||||
|
static inline bool Write8(int fd, int64_t value) {
|
||||||
|
return android::base::WriteFully(fd, &value, sizeof(int64_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly, the value should not exceed 2^31 if we are casting from size_t (e.g. target chunk
|
||||||
|
// size).
|
||||||
|
static inline bool Write4(int fd, int32_t value) {
|
||||||
|
return android::base::WriteFully(fd, &value, sizeof(int32_t));
|
||||||
|
}
|
||||||
|
|
||||||
class ImageChunk {
|
class ImageChunk {
|
||||||
public:
|
public:
|
||||||
static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream.
|
static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream.
|
||||||
|
@ -163,11 +173,12 @@ class ImageChunk {
|
||||||
start_(start),
|
start_(start),
|
||||||
input_file_ptr_(file_content),
|
input_file_ptr_(file_content),
|
||||||
raw_data_len_(raw_data_len),
|
raw_data_len_(raw_data_len),
|
||||||
entry_name_(""),
|
|
||||||
compress_level_(6),
|
compress_level_(6),
|
||||||
source_start_(0),
|
source_start_(0),
|
||||||
source_len_(0),
|
source_len_(0),
|
||||||
source_uncompressed_len_(0) {}
|
source_uncompressed_len_(0) {
|
||||||
|
CHECK(file_content != nullptr) << "input file container can't be nullptr";
|
||||||
|
}
|
||||||
|
|
||||||
int GetType() const {
|
int GetType() const {
|
||||||
return type_;
|
return type_;
|
||||||
|
@ -199,7 +210,8 @@ class ImageChunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetHeaderSize(size_t patch_size) const;
|
size_t GetHeaderSize(size_t patch_size) const;
|
||||||
size_t WriteHeaderToFile(FILE* f, const std::vector<uint8_t> patch, size_t offset);
|
// Return the offset of the next patch into the patch data.
|
||||||
|
size_t WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cause a gzip chunk to be treated as a normal chunk (ie, as a blob
|
* Cause a gzip chunk to be treated as a normal chunk (ie, as a blob
|
||||||
|
@ -222,9 +234,9 @@ class ImageChunk {
|
||||||
void MergeAdjacentNormal(const ImageChunk& other);
|
void MergeAdjacentNormal(const ImageChunk& other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
|
int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW
|
||||||
size_t start_; // offset of chunk in the original input file
|
size_t start_; // offset of chunk in the original input file
|
||||||
const std::vector<uint8_t>* input_file_ptr_; // pointer to the full content of 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_;
|
size_t raw_data_len_;
|
||||||
|
|
||||||
// --- for CHUNK_DEFLATE chunks only: ---
|
// --- for CHUNK_DEFLATE chunks only: ---
|
||||||
|
@ -280,11 +292,11 @@ void ImageChunk::SetSourceInfo(const ImageChunk& src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageChunk::SetEntryName(std::string entryname) {
|
void ImageChunk::SetEntryName(std::string entryname) {
|
||||||
entry_name_ = entryname;
|
entry_name_ = std::move(entryname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageChunk::SetUncompressedData(std::vector<uint8_t> data) {
|
void ImageChunk::SetUncompressedData(std::vector<uint8_t> data) {
|
||||||
uncompressed_data_ = data;
|
uncompressed_data_ = std::move(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageChunk::SetBonusData(const std::vector<uint8_t>& bonus_data) {
|
bool ImageChunk::SetBonusData(const std::vector<uint8_t>& bonus_data) {
|
||||||
|
@ -295,7 +307,7 @@ bool ImageChunk::SetBonusData(const std::vector<uint8_t>& bonus_data) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the terget size is
|
// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the target size is
|
||||||
// smaller. Also take the header size into account during size comparison.
|
// smaller. Also take the header size into account during size comparison.
|
||||||
bool ImageChunk::ChangeChunkToRaw(size_t patch_size) {
|
bool ImageChunk::ChangeChunkToRaw(size_t patch_size) {
|
||||||
if (type_ == CHUNK_RAW) {
|
if (type_ == CHUNK_RAW) {
|
||||||
|
@ -310,6 +322,7 @@ bool ImageChunk::ChangeChunkToRaw(size_t patch_size) {
|
||||||
void ImageChunk::ChangeDeflateChunkToNormal() {
|
void ImageChunk::ChangeDeflateChunkToNormal() {
|
||||||
if (type_ != CHUNK_DEFLATE) return;
|
if (type_ != CHUNK_DEFLATE) return;
|
||||||
type_ = CHUNK_NORMAL;
|
type_ = CHUNK_NORMAL;
|
||||||
|
entry_name_.clear();
|
||||||
uncompressed_data_.clear();
|
uncompressed_data_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +330,7 @@ void ImageChunk::ChangeDeflateChunkToNormal() {
|
||||||
// header_type 4 bytes
|
// header_type 4 bytes
|
||||||
// CHUNK_NORMAL 8*3 = 24 bytes
|
// CHUNK_NORMAL 8*3 = 24 bytes
|
||||||
// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes
|
// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes
|
||||||
// CHUNK_RAW 4 bytes
|
// CHUNK_RAW 4 bytes + patch_size
|
||||||
size_t ImageChunk::GetHeaderSize(size_t patch_size) const {
|
size_t ImageChunk::GetHeaderSize(size_t patch_size) const {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case CHUNK_NORMAL:
|
case CHUNK_NORMAL:
|
||||||
|
@ -327,43 +340,43 @@ size_t ImageChunk::GetHeaderSize(size_t patch_size) const {
|
||||||
case CHUNK_RAW:
|
case CHUNK_RAW:
|
||||||
return 4 + 4 + patch_size;
|
return 4 + 4 + patch_size;
|
||||||
default:
|
default:
|
||||||
printf("unexpected chunk type: %d\n", type_); // should not reach here.
|
CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here.
|
||||||
CHECK(false);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ImageChunk::WriteHeaderToFile(FILE* f, const std::vector<uint8_t> patch, size_t offset) {
|
size_t ImageChunk::WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset) {
|
||||||
Write4(type_, f);
|
Write4(fd, type_);
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case CHUNK_NORMAL:
|
case CHUNK_NORMAL:
|
||||||
printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size());
|
printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size());
|
||||||
Write8(source_start_, f);
|
Write8(fd, static_cast<int64_t>(source_start_));
|
||||||
Write8(source_len_, f);
|
Write8(fd, static_cast<int64_t>(source_len_));
|
||||||
Write8(offset, f);
|
Write8(fd, static_cast<int64_t>(offset));
|
||||||
return offset + patch.size();
|
return offset + patch.size();
|
||||||
case CHUNK_DEFLATE:
|
case CHUNK_DEFLATE:
|
||||||
printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(),
|
printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(),
|
||||||
entry_name_.c_str());
|
entry_name_.c_str());
|
||||||
Write8(source_start_, f);
|
Write8(fd, static_cast<int64_t>(source_start_));
|
||||||
Write8(source_len_, f);
|
Write8(fd, static_cast<int64_t>(source_len_));
|
||||||
Write8(offset, f);
|
Write8(fd, static_cast<int64_t>(offset));
|
||||||
Write8(source_uncompressed_len_, f);
|
Write8(fd, static_cast<int64_t>(source_uncompressed_len_));
|
||||||
Write8(uncompressed_data_.size(), f);
|
Write8(fd, static_cast<int64_t>(uncompressed_data_.size()));
|
||||||
Write4(compress_level_, f);
|
Write4(fd, compress_level_);
|
||||||
Write4(METHOD, f);
|
Write4(fd, METHOD);
|
||||||
Write4(WINDOWBITS, f);
|
Write4(fd, WINDOWBITS);
|
||||||
Write4(MEMLEVEL, f);
|
Write4(fd, MEMLEVEL);
|
||||||
Write4(STRATEGY, f);
|
Write4(fd, STRATEGY);
|
||||||
return offset + patch.size();
|
return offset + patch.size();
|
||||||
case CHUNK_RAW:
|
case CHUNK_RAW:
|
||||||
printf("raw (%10zu, %10zu)\n", start_, raw_data_len_);
|
printf("raw (%10zu, %10zu)\n", start_, raw_data_len_);
|
||||||
Write4(patch.size(), f);
|
Write4(fd, static_cast<int32_t>(patch.size()));
|
||||||
fwrite(patch.data(), 1, patch.size(), f);
|
if (!android::base::WriteFully(fd, patch.data(), patch.size())) {
|
||||||
|
CHECK(false) << "failed to write " << patch.size() <<" bytes patch";
|
||||||
|
}
|
||||||
return offset;
|
return offset;
|
||||||
default:
|
default:
|
||||||
printf("unexpected chunk type: %d\n", type_);
|
CHECK(false) << "unexpected chunk type: " << type_;
|
||||||
CHECK(false);
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,20 +493,21 @@ static bool GetZipFileSize(const std::vector<uint8_t>& zip_file, size_t* input_f
|
||||||
|
|
||||||
static bool ReadZip(const char* filename, std::vector<ImageChunk>* chunks,
|
static bool ReadZip(const char* filename, std::vector<ImageChunk>* chunks,
|
||||||
std::vector<uint8_t>* zip_file, bool include_pseudo_chunk) {
|
std::vector<uint8_t>* zip_file, bool include_pseudo_chunk) {
|
||||||
CHECK(zip_file != nullptr);
|
CHECK(chunks != nullptr && zip_file != nullptr);
|
||||||
|
|
||||||
|
android::base::unique_fd fd(open(filename, O_RDONLY));
|
||||||
|
if (fd == -1) {
|
||||||
|
printf("failed to open \"%s\" %s\n", filename, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(filename, &st) != 0) {
|
if (fstat(fd, &st) != 0) {
|
||||||
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
|
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sz = static_cast<size_t>(st.st_size);
|
size_t sz = static_cast<size_t>(st.st_size);
|
||||||
zip_file->resize(sz);
|
zip_file->resize(sz);
|
||||||
android::base::unique_fd fd(open(filename, O_RDONLY));
|
|
||||||
if (fd == -1) {
|
|
||||||
printf("failed to open \"%s\" %s\n", filename, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!android::base::ReadFully(fd, zip_file->data(), sz)) {
|
if (!android::base::ReadFully(fd, zip_file->data(), sz)) {
|
||||||
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
|
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
|
@ -596,20 +610,21 @@ static bool ReadZip(const char* filename, std::vector<ImageChunk>* chunks,
|
||||||
// Read the given file and break it up into chunks, and putting the data in to a vector.
|
// Read the given file and break it up into chunks, and putting the data in to a vector.
|
||||||
static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
|
static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
|
||||||
std::vector<uint8_t>* img) {
|
std::vector<uint8_t>* img) {
|
||||||
CHECK(img != nullptr);
|
CHECK(chunks != nullptr && img != nullptr);
|
||||||
|
|
||||||
|
android::base::unique_fd fd(open(filename, O_RDONLY));
|
||||||
|
if (fd == -1) {
|
||||||
|
printf("failed to open \"%s\" %s\n", filename, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(filename, &st) != 0) {
|
if (fstat(fd, &st) != 0) {
|
||||||
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
|
printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sz = static_cast<size_t>(st.st_size);
|
size_t sz = static_cast<size_t>(st.st_size);
|
||||||
img->resize(sz);
|
img->resize(sz);
|
||||||
android::base::unique_fd fd(open(filename, O_RDONLY));
|
|
||||||
if (fd == -1) {
|
|
||||||
printf("failed to open \"%s\" %s\n", filename, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!android::base::ReadFully(fd, img->data(), sz)) {
|
if (!android::base::ReadFully(fd, img->data(), sz)) {
|
||||||
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
|
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
|
@ -618,9 +633,8 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
|
||||||
while (pos < sz) {
|
while (pos < sz) {
|
||||||
if (sz - pos >= 4 && img->at(pos) == 0x1f && img->at(pos + 1) == 0x8b &&
|
// 0x00 no header flags, 0x08 deflate compression, 0x1f8b gzip magic number
|
||||||
img->at(pos + 2) == 0x08 && // deflate compression
|
if (sz - pos >= 4 && get_unaligned<uint32_t>(img->data() + pos) == 0x00088b1f) {
|
||||||
img->at(pos + 3) == 0x00) { // no header flags
|
|
||||||
// 'pos' is the offset of the start of a gzip chunk.
|
// 'pos' is the offset of the start of a gzip chunk.
|
||||||
size_t chunk_offset = pos;
|
size_t chunk_offset = pos;
|
||||||
|
|
||||||
|
@ -695,7 +709,7 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
|
||||||
// the uncompressed data. Double-check to make sure that it
|
// the uncompressed data. Double-check to make sure that it
|
||||||
// matches the size of the data we got when we actually did
|
// matches the size of the data we got when we actually did
|
||||||
// the decompression.
|
// the decompression.
|
||||||
size_t footer_size = Read4(img->data() + pos - 4);
|
size_t footer_size = get_unaligned<uint32_t>(img->data() + pos - 4);
|
||||||
if (footer_size != body.DataLengthForPatch()) {
|
if (footer_size != body.DataLengthForPatch()) {
|
||||||
printf("Error: footer size %zu != decompressed size %zu\n", footer_size,
|
printf("Error: footer size %zu != decompressed size %zu\n", footer_size,
|
||||||
body.GetRawDataLength());
|
body.GetRawDataLength());
|
||||||
|
@ -708,9 +722,8 @@ static bool ReadImage(const char* filename, std::vector<ImageChunk>* chunks,
|
||||||
// Scan forward until we find a gzip header.
|
// Scan forward until we find a gzip header.
|
||||||
size_t data_len = 0;
|
size_t data_len = 0;
|
||||||
while (data_len + pos < sz) {
|
while (data_len + pos < sz) {
|
||||||
if (data_len + pos + 4 <= sz && img->at(pos + data_len) == 0x1f &&
|
if (data_len + pos + 4 <= sz &&
|
||||||
img->at(pos + data_len + 1) == 0x8b && img->at(pos + data_len + 2) == 0x08 &&
|
get_unaligned<uint32_t>(img->data() + pos + data_len) == 0x00088b1f) {
|
||||||
img->at(pos + data_len + 3) == 0x00) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data_len++;
|
data_len++;
|
||||||
|
@ -759,13 +772,19 @@ static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector<uint8_
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
android::base::unique_fd patch_fd(open(ptemp, O_RDONLY));
|
||||||
|
if (patch_fd == -1) {
|
||||||
|
printf("failed to open %s: %s\n", ptemp, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(ptemp, &st) != 0) {
|
if (fstat(patch_fd, &st) != 0) {
|
||||||
printf("failed to stat patch file %s: %s\n", ptemp, strerror(errno));
|
printf("failed to stat patch file %s: %s\n", ptemp, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sz = static_cast<size_t>(st.st_size);
|
size_t sz = static_cast<size_t>(st.st_size);
|
||||||
|
// Change the chunk type to raw if the patch takes less space that way.
|
||||||
if (tgt->ChangeChunkToRaw(sz)) {
|
if (tgt->ChangeChunkToRaw(sz)) {
|
||||||
unlink(ptemp);
|
unlink(ptemp);
|
||||||
size_t patch_size = tgt->DataLengthForPatch();
|
size_t patch_size = tgt->DataLengthForPatch();
|
||||||
|
@ -773,12 +792,6 @@ static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector<uint8_
|
||||||
std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin());
|
std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
android::base::unique_fd patch_fd(open(ptemp, O_RDONLY));
|
|
||||||
if (patch_fd == -1) {
|
|
||||||
printf("failed to open %s: %s\n", ptemp, strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
patch_data->resize(sz);
|
patch_data->resize(sz);
|
||||||
if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) {
|
if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) {
|
||||||
printf("failed to read \"%s\" %s\n", ptemp, strerror(errno));
|
printf("failed to read \"%s\" %s\n", ptemp, strerror(errno));
|
||||||
|
@ -845,18 +858,19 @@ int imgdiff(int argc, const char** argv) {
|
||||||
|
|
||||||
std::vector<uint8_t> bonus_data;
|
std::vector<uint8_t> bonus_data;
|
||||||
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
|
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
|
||||||
struct stat st;
|
|
||||||
if (stat(argv[2], &st) != 0) {
|
|
||||||
printf("failed to stat bonus file %s: %s\n", argv[2], strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
size_t bonus_size = st.st_size;
|
|
||||||
bonus_data.resize(bonus_size);
|
|
||||||
android::base::unique_fd fd(open(argv[2], O_RDONLY));
|
android::base::unique_fd fd(open(argv[2], O_RDONLY));
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
|
printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) != 0) {
|
||||||
|
printf("failed to stat bonus file %s: %s\n", argv[2], strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bonus_size = st.st_size;
|
||||||
|
bonus_data.resize(bonus_size);
|
||||||
if (!android::base::ReadFully(fd, bonus_data.data(), bonus_size)) {
|
if (!android::base::ReadFully(fd, bonus_data.data(), bonus_size)) {
|
||||||
printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno));
|
printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -999,9 +1013,15 @@ int imgdiff(int argc, const char** argv) {
|
||||||
ImageChunk* src;
|
ImageChunk* src;
|
||||||
if (tgt_chunks[i].GetType() == CHUNK_DEFLATE &&
|
if (tgt_chunks[i].GetType() == CHUNK_DEFLATE &&
|
||||||
(src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks))) {
|
(src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks))) {
|
||||||
MakePatch(src, &tgt_chunks[i], &patch_data[i], nullptr);
|
if (!MakePatch(src, &tgt_chunks[i], &patch_data[i], nullptr)) {
|
||||||
|
printf("Failed to generate patch for target chunk %zu: ", i);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
MakePatch(&src_chunks[0], &tgt_chunks[i], &patch_data[i], &bsdiff_cache);
|
if (!MakePatch(&src_chunks[0], &tgt_chunks[i], &patch_data[i], &bsdiff_cache)) {
|
||||||
|
printf("Failed to generate patch for target chunk %zu: ", i);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i == 1 && !bonus_data.empty()) {
|
if (i == 1 && !bonus_data.empty()) {
|
||||||
|
@ -1009,7 +1029,10 @@ int imgdiff(int argc, const char** argv) {
|
||||||
src_chunks[i].SetBonusData(bonus_data);
|
src_chunks[i].SetBonusData(bonus_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
MakePatch(&src_chunks[i], &tgt_chunks[i], &patch_data[i], nullptr);
|
if (!MakePatch(&src_chunks[i], &tgt_chunks[i], &patch_data[i], nullptr)) {
|
||||||
|
printf("Failed to generate patch for target chunk %zu: ", i);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(),
|
printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(),
|
||||||
src_chunks[i].GetRawDataLength());
|
src_chunks[i].GetRawDataLength());
|
||||||
|
@ -1030,28 +1053,32 @@ int imgdiff(int argc, const char** argv) {
|
||||||
|
|
||||||
size_t offset = total_header_size;
|
size_t offset = total_header_size;
|
||||||
|
|
||||||
FILE* f = fopen(argv[3], "wb");
|
android::base::unique_fd patch_fd(open(argv[3], O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR));
|
||||||
if (f == nullptr) {
|
if (patch_fd == -1) {
|
||||||
printf("failed to open \"%s\": %s\n", argv[3], strerror(errno));
|
printf("failed to open \"%s\": %s\n", argv[3], strerror(errno));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out the headers.
|
// Write out the headers.
|
||||||
|
if (!android::base::WriteStringToFd("IMGDIFF2", patch_fd)) {
|
||||||
fwrite("IMGDIFF2", 1, 8, f);
|
printf("failed to write \"IMGDIFF2\" to \"%s\": %s\n", argv[3], strerror(errno));
|
||||||
Write4(static_cast<int32_t>(tgt_chunks.size()), f);
|
return 1;
|
||||||
|
}
|
||||||
|
Write4(patch_fd, static_cast<int32_t>(tgt_chunks.size()));
|
||||||
for (size_t i = 0; i < tgt_chunks.size(); ++i) {
|
for (size_t i = 0; i < tgt_chunks.size(); ++i) {
|
||||||
printf("chunk %zu: ", i);
|
printf("chunk %zu: ", i);
|
||||||
offset = tgt_chunks[i].WriteHeaderToFile(f, patch_data[i], offset);
|
offset = tgt_chunks[i].WriteHeaderToFd(patch_fd, patch_data[i], offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append each chunk's bsdiff patch, in order.
|
// Append each chunk's bsdiff patch, in order.
|
||||||
for (size_t i = 0; i < tgt_chunks.size(); ++i) {
|
for (size_t i = 0; i < tgt_chunks.size(); ++i) {
|
||||||
if (tgt_chunks[i].GetType() != CHUNK_RAW) {
|
if (tgt_chunks[i].GetType() != CHUNK_RAW) {
|
||||||
fwrite(patch_data[i].data(), 1, patch_data[i].size(), f);
|
if (!android::base::WriteFully(patch_fd, patch_data[i].data(), patch_data[i].size())) {
|
||||||
|
CHECK(false) << "failed to write " << patch_data[i].size() << " bytes patch for chunk "
|
||||||
|
<< i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,17 @@
|
||||||
|
|
||||||
#include <applypatch/applypatch.h>
|
#include <applypatch/applypatch.h>
|
||||||
#include <applypatch/imgdiff.h>
|
#include <applypatch/imgdiff.h>
|
||||||
|
#include <android-base/memory.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "utils.h"
|
static inline int64_t Read8(const void *address) {
|
||||||
|
return android::base::get_unaligned<int64_t>(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t Read4(const void *address) {
|
||||||
|
return android::base::get_unaligned<int32_t>(address);
|
||||||
|
}
|
||||||
|
|
||||||
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
|
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
|
||||||
const unsigned char* patch_data, ssize_t patch_size,
|
const unsigned char* patch_data, ssize_t patch_size,
|
||||||
|
@ -86,9 +93,9 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t src_start = Read8(normal_header);
|
size_t src_start = static_cast<size_t>(Read8(normal_header));
|
||||||
size_t src_len = Read8(normal_header + 8);
|
size_t src_len = static_cast<size_t>(Read8(normal_header + 8));
|
||||||
size_t patch_offset = Read8(normal_header + 16);
|
size_t patch_offset = static_cast<size_t>(Read8(normal_header + 16));
|
||||||
|
|
||||||
if (src_start + src_len > static_cast<size_t>(old_size)) {
|
if (src_start + src_len > static_cast<size_t>(old_size)) {
|
||||||
printf("source data too short\n");
|
printf("source data too short\n");
|
||||||
|
@ -125,11 +132,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t src_start = Read8(deflate_header);
|
size_t src_start = static_cast<size_t>(Read8(deflate_header));
|
||||||
size_t src_len = Read8(deflate_header + 8);
|
size_t src_len = static_cast<size_t>(Read8(deflate_header + 8));
|
||||||
size_t patch_offset = Read8(deflate_header + 16);
|
size_t patch_offset = static_cast<size_t>(Read8(deflate_header + 16));
|
||||||
size_t expanded_len = Read8(deflate_header + 24);
|
size_t expanded_len = static_cast<size_t>(Read8(deflate_header + 24));
|
||||||
size_t target_len = Read8(deflate_header + 32);
|
size_t target_len = static_cast<size_t>(Read8(deflate_header + 32));
|
||||||
int level = Read4(deflate_header + 40);
|
int level = Read4(deflate_header + 40);
|
||||||
int method = Read4(deflate_header + 44);
|
int method = Read4(deflate_header + 44);
|
||||||
int windowBits = Read4(deflate_header + 48);
|
int windowBits = Read4(deflate_header + 48);
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/** Write a 4-byte value to f in little-endian order. */
|
|
||||||
void Write4(int value, FILE* f) {
|
|
||||||
fputc(value & 0xff, f);
|
|
||||||
fputc((value >> 8) & 0xff, f);
|
|
||||||
fputc((value >> 16) & 0xff, f);
|
|
||||||
fputc((value >> 24) & 0xff, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write an 8-byte value to f in little-endian order. */
|
|
||||||
void Write8(int64_t value, FILE* f) {
|
|
||||||
fputc(value & 0xff, f);
|
|
||||||
fputc((value >> 8) & 0xff, f);
|
|
||||||
fputc((value >> 16) & 0xff, f);
|
|
||||||
fputc((value >> 24) & 0xff, f);
|
|
||||||
fputc((value >> 32) & 0xff, f);
|
|
||||||
fputc((value >> 40) & 0xff, f);
|
|
||||||
fputc((value >> 48) & 0xff, f);
|
|
||||||
fputc((value >> 56) & 0xff, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Read2(const void* pv) {
|
|
||||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(pv);
|
|
||||||
return (int)(((unsigned int)p[1] << 8) |
|
|
||||||
(unsigned int)p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Read4(const void* pv) {
|
|
||||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(pv);
|
|
||||||
return (int)(((unsigned int)p[3] << 24) |
|
|
||||||
((unsigned int)p[2] << 16) |
|
|
||||||
((unsigned int)p[1] << 8) |
|
|
||||||
(unsigned int)p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t Read8(const void* pv) {
|
|
||||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(pv);
|
|
||||||
return (int64_t)(((uint64_t)p[7] << 56) |
|
|
||||||
((uint64_t)p[6] << 48) |
|
|
||||||
((uint64_t)p[5] << 40) |
|
|
||||||
((uint64_t)p[4] << 32) |
|
|
||||||
((uint64_t)p[3] << 24) |
|
|
||||||
((uint64_t)p[2] << 16) |
|
|
||||||
((uint64_t)p[1] << 8) |
|
|
||||||
(uint64_t)p[0]);
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 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 _BUILD_TOOLS_APPLYPATCH_UTILS_H
|
|
||||||
#define _BUILD_TOOLS_APPLYPATCH_UTILS_H
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
// Read and write little-endian values of various sizes.
|
|
||||||
|
|
||||||
void Write4(int value, FILE* f);
|
|
||||||
void Write8(int64_t value, FILE* f);
|
|
||||||
int Read2(const void* p);
|
|
||||||
int Read4(const void* p);
|
|
||||||
int64_t Read8(const void* p);
|
|
||||||
|
|
||||||
#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H
|
|
|
@ -18,13 +18,14 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
|
#include <android-base/memory.h>
|
||||||
#include <android-base/test_utils.h>
|
#include <android-base/test_utils.h>
|
||||||
#include <applypatch/imgdiff.h>
|
#include <applypatch/imgdiff.h>
|
||||||
#include <applypatch/imgpatch.h>
|
#include <applypatch/imgpatch.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <ziparchive/zip_writer.h>
|
#include <ziparchive/zip_writer.h>
|
||||||
|
|
||||||
#include "applypatch/utils.h"
|
using android::base::get_unaligned;
|
||||||
|
|
||||||
static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
|
static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
|
||||||
std::string* s = static_cast<std::string*>(token);
|
std::string* s = static_cast<std::string*>(token);
|
||||||
|
@ -41,7 +42,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
|
||||||
ASSERT_GE(size, 12U);
|
ASSERT_GE(size, 12U);
|
||||||
ASSERT_EQ("IMGDIFF2", std::string(data, 8));
|
ASSERT_EQ("IMGDIFF2", std::string(data, 8));
|
||||||
|
|
||||||
const int num_chunks = Read4(data + 8);
|
const int num_chunks = get_unaligned<int32_t>(data + 8);
|
||||||
ASSERT_GE(num_chunks, 0);
|
ASSERT_GE(num_chunks, 0);
|
||||||
|
|
||||||
size_t normal = 0;
|
size_t normal = 0;
|
||||||
|
@ -51,7 +52,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
|
||||||
size_t pos = 12;
|
size_t pos = 12;
|
||||||
for (int i = 0; i < num_chunks; ++i) {
|
for (int i = 0; i < num_chunks; ++i) {
|
||||||
ASSERT_LE(pos + 4, size);
|
ASSERT_LE(pos + 4, size);
|
||||||
int type = Read4(data + pos);
|
int type = get_unaligned<int32_t>(data + pos);
|
||||||
pos += 4;
|
pos += 4;
|
||||||
if (type == CHUNK_NORMAL) {
|
if (type == CHUNK_NORMAL) {
|
||||||
pos += 24;
|
pos += 24;
|
||||||
|
@ -59,7 +60,7 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
|
||||||
normal++;
|
normal++;
|
||||||
} else if (type == CHUNK_RAW) {
|
} else if (type == CHUNK_RAW) {
|
||||||
ASSERT_LE(pos + 4, size);
|
ASSERT_LE(pos + 4, size);
|
||||||
ssize_t data_len = Read4(data + pos);
|
ssize_t data_len = get_unaligned<int32_t>(data + pos);
|
||||||
ASSERT_GT(data_len, 0);
|
ASSERT_GT(data_len, 0);
|
||||||
pos += 4 + data_len;
|
pos += 4 + data_len;
|
||||||
ASSERT_LE(pos, size);
|
ASSERT_LE(pos, size);
|
||||||
|
|
Loading…
Reference in a new issue