diff options
Diffstat (limited to 'applypatch')
-rw-r--r-- | applypatch/Android.mk | 105 | ||||
-rw-r--r-- | applypatch/applypatch.cpp | 13 | ||||
-rw-r--r-- | applypatch/imgdiff.cpp | 109 | ||||
-rw-r--r-- | applypatch/imgdiff_main.cpp | 21 | ||||
-rw-r--r-- | applypatch/imgpatch.cpp | 405 | ||||
-rw-r--r-- | applypatch/include/applypatch/applypatch.h | 3 | ||||
-rw-r--r-- | applypatch/include/applypatch/imgdiff.h (renamed from applypatch/imgdiff.h) | 21 | ||||
-rw-r--r-- | applypatch/include/applypatch/imgpatch.h | 10 |
8 files changed, 386 insertions, 301 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk index fa0fe8a37..bdaef1b27 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -17,7 +17,6 @@ LOCAL_PATH := $(call my-dir) # libapplypatch (static library) # =============================== include $(CLEAR_VARS) -LOCAL_CLANG := true LOCAL_SRC_FILES := \ applypatch.cpp \ bspatch.cpp \ @@ -26,52 +25,67 @@ LOCAL_SRC_FILES := \ utils.cpp LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng -LOCAL_C_INCLUDES += \ +LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += \ +LOCAL_STATIC_LIBRARIES := \ libotafault \ libbase \ libcrypto \ libbz \ libz -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := \ + -DZLIB_CONST \ + -Werror include $(BUILD_STATIC_LIBRARY) # libimgpatch (static library) # =============================== include $(CLEAR_VARS) -LOCAL_CLANG := true -LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp +LOCAL_SRC_FILES := \ + bspatch.cpp \ + imgpatch.cpp \ + utils.cpp LOCAL_MODULE := libimgpatch -LOCAL_C_INCLUDES += \ +LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += libcrypto libbz libz -LOCAL_CFLAGS := -Werror +LOCAL_STATIC_LIBRARIES := \ + libcrypto \ + libbz \ + libz +LOCAL_CFLAGS := \ + -DZLIB_CONST \ + -Werror include $(BUILD_STATIC_LIBRARY) # libimgpatch (host static library) # =============================== include $(CLEAR_VARS) -LOCAL_CLANG := true -LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp +LOCAL_SRC_FILES := \ + bspatch.cpp \ + imgpatch.cpp \ + utils.cpp LOCAL_MODULE := libimgpatch LOCAL_MODULE_HOST_OS := linux -LOCAL_C_INCLUDES += \ +LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += libcrypto libbz libz -LOCAL_CFLAGS := -Werror +LOCAL_STATIC_LIBRARIES := \ + libcrypto \ + libbz \ + libz +LOCAL_CFLAGS := \ + -DZLIB_CONST \ + -Werror include $(BUILD_HOST_STATIC_LIBRARY) # libapplypatch_modes (static library) # =============================== include $(CLEAR_VARS) -LOCAL_CLANG := true LOCAL_SRC_FILES := \ applypatch_modes.cpp LOCAL_MODULE := libapplypatch_modes @@ -87,7 +101,6 @@ include $(BUILD_STATIC_LIBRARY) # applypatch (target executable) # =============================== include $(CLEAR_VARS) -LOCAL_CLANG := true LOCAL_SRC_FILES := applypatch_main.cpp LOCAL_MODULE := applypatch LOCAL_C_INCLUDES := bootable/recovery @@ -106,18 +119,60 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_CFLAGS := -Werror include $(BUILD_EXECUTABLE) +libimgdiff_src_files := \ + imgdiff.cpp \ + utils.cpp + +# libbsdiff is compiled with -D_FILE_OFFSET_BITS=64. +libimgdiff_cflags := \ + -Werror \ + -D_FILE_OFFSET_BITS=64 + +libimgdiff_static_libraries := \ + libbsdiff \ + libdivsufsort \ + libdivsufsort64 \ + libbase \ + libz + +# libimgdiff (static library) +# =============================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + $(libimgdiff_src_files) +LOCAL_MODULE := libimgdiff +LOCAL_CFLAGS := \ + $(libimgdiff_cflags) +LOCAL_STATIC_LIBRARIES := \ + $(libimgdiff_static_libraries) +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +include $(BUILD_STATIC_LIBRARY) + +# libimgdiff (host static library) +# =============================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + $(libimgdiff_src_files) +LOCAL_MODULE := libimgdiff +LOCAL_CFLAGS := \ + $(libimgdiff_cflags) +LOCAL_STATIC_LIBRARIES := \ + $(libimgdiff_static_libraries) +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +include $(BUILD_HOST_STATIC_LIBRARY) + # imgdiff (host static executable) # =============================== include $(CLEAR_VARS) -LOCAL_CLANG := true -LOCAL_SRC_FILES := imgdiff.cpp utils.cpp +LOCAL_SRC_FILES := imgdiff_main.cpp LOCAL_MODULE := imgdiff -LOCAL_STATIC_LIBRARIES += \ - libbsdiff \ - libbz \ - libdivsufsort64 \ - libdivsufsort \ - libz LOCAL_CFLAGS := -Werror -LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_STATIC_LIBRARIES := \ + libimgdiff \ + $(libimgdiff_static_libraries) \ + libbz include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 95389da6e..500663120 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -332,6 +332,17 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t success = true; break; } + + if (ota_close(fd) != 0) { + printf("failed to close %s: %s\n", partition, strerror(errno)); + return -1; + } + + fd.reset(ota_open(partition, O_RDWR)); + if (fd == -1) { + printf("failed to reopen %s for retry write && verify: %s\n", partition, strerror(errno)); + return -1; + } } if (!success) { @@ -380,7 +391,7 @@ int ParseSha1(const char* str, uint8_t* digest) { // Search an array of sha1 strings for one matching the given sha1. // Return the index of the match on success, or -1 if no match is // found. -int FindMatchingPatch(uint8_t* sha1, const std::vector<std::string>& patch_sha1_str) { +static int FindMatchingPatch(uint8_t* sha1, const std::vector<std::string>& patch_sha1_str) { for (size_t i = 0; i < patch_sha1_str.size(); ++i) { uint8_t patch_sha1[SHA_DIGEST_LENGTH]; if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 && diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 7d6ebab6e..2f0e1651c 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -121,19 +121,23 @@ * information that is stored on the system partition. */ +#include "applypatch/imgdiff.h" + #include <errno.h> -#include <inttypes.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> -#include <unistd.h> #include <sys/types.h> +#include <unistd.h> + +#include <android-base/file.h> +#include <android-base/unique_fd.h> #include <bsdiff.h> +#include <zlib.h> -#include "zlib.h" -#include "imgdiff.h" #include "utils.h" typedef struct { @@ -375,8 +379,7 @@ unsigned char* ReadZip(const char* filename, * return value when done with all the chunks. Returns NULL on * failure. */ -unsigned char* ReadImage(const char* filename, - int* num_chunks, ImageChunk** chunks) { +unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chunks) { struct stat st; if (stat(filename, &st) != 0) { printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); @@ -384,19 +387,12 @@ unsigned char* ReadImage(const char* filename, } size_t sz = static_cast<size_t>(st.st_size); - unsigned char* img = static_cast<unsigned char*>(malloc(sz + 4)); - FILE* f = fopen(filename, "rb"); - if (fread(img, 1, sz, f) != sz) { + unsigned char* img = static_cast<unsigned char*>(malloc(sz)); + android::base::unique_fd fd(open(filename, O_RDONLY)); + if (!android::base::ReadFully(fd, img, sz)) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); - fclose(f); - return NULL; + return nullptr; } - fclose(f); - - // append 4 zero bytes to the data so we can always search for the - // four-byte string 1f8b0800 starting at any point in the actual - // file data, without special-casing the end of the data. - memset(img+sz, 0, 4); size_t pos = 0; @@ -404,7 +400,7 @@ unsigned char* ReadImage(const char* filename, *chunks = NULL; while (pos < sz) { - unsigned char* p = img+pos; + unsigned char* p = img + pos; if (sz - pos >= 4 && p[0] == 0x1f && p[1] == 0x8b && @@ -414,8 +410,7 @@ unsigned char* ReadImage(const char* filename, size_t chunk_offset = pos; *num_chunks += 3; - *chunks = static_cast<ImageChunk*>(realloc(*chunks, - *num_chunks * sizeof(ImageChunk))); + *chunks = static_cast<ImageChunk*>(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); ImageChunk* curr = *chunks + (*num_chunks-3); // create a normal chunk for the header. @@ -503,8 +498,7 @@ unsigned char* ReadImage(const char* filename, // the decompression. size_t footer_size = Read4(p-4); if (footer_size != curr[-2].len) { - printf("Error: footer size %zu != decompressed size %zu\n", - footer_size, curr[-2].len); + printf("Error: footer size %zu != decompressed size %zu\n", footer_size, curr[-2].len); free(img); return NULL; } @@ -522,10 +516,8 @@ unsigned char* ReadImage(const char* filename, curr->data = p; for (curr->len = 0; curr->len < (sz - pos); ++curr->len) { - if (p[curr->len] == 0x1f && - p[curr->len+1] == 0x8b && - p[curr->len+2] == 0x08 && - p[curr->len+3] == 0x00) { + if (sz - pos >= 4 && p[curr->len] == 0x1f && p[curr->len + 1] == 0x8b && + p[curr->len + 2] == 0x08 && p[curr->len + 3] == 0x00) { break; } } @@ -624,12 +616,12 @@ int ReconstructDeflateChunk(ImageChunk* chunk) { } /* - * Given source and target chunks, compute a bsdiff patch between them - * by running bsdiff in a subprocess. Return the patch data, placing - * its length in *size. Return NULL on failure. We expect the bsdiff - * program to be in the path. + * Given source and target chunks, compute a bsdiff patch between them. + * Return the patch data, placing its length in *size. Return NULL on failure. + * |bsdiff_cache| can be used to cache the suffix array if the same |src| chunk + * is used repeatedly, pass nullptr if not needed. */ -unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { +unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size, saidx_t** bsdiff_cache) { if (tgt->type == CHUNK_NORMAL) { if (tgt->len <= 160) { tgt->type = CHUNK_RAW; @@ -638,7 +630,11 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { } } +#if defined(__ANDROID__) + char ptemp[] = "/data/local/tmp/imgdiff-patch-XXXXXX"; +#else char ptemp[] = "/tmp/imgdiff-patch-XXXXXX"; +#endif int fd = mkstemp(ptemp); if (fd == -1) { @@ -649,7 +645,7 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { close(fd); // temporary file is created and we don't need its file // descriptor - int r = bsdiff::bsdiff(src->data, src->len, tgt->data, tgt->len, ptemp); + int r = bsdiff::bsdiff(src->data, src->len, tgt->data, tgt->len, ptemp, bsdiff_cache); if (r != 0) { printf("bsdiff() failed: %d\n", r); return NULL; @@ -794,10 +790,8 @@ void MergeAdjacentNormalChunks(ImageChunk* chunks, int* num_chunks) { *num_chunks = out; } -ImageChunk* FindChunkByName(const char* name, - ImageChunk* chunks, int num_chunks) { - int i; - for (i = 0; i < num_chunks; ++i) { +ImageChunk* FindChunkByName(const char* name, ImageChunk* chunks, int num_chunks) { + for (int i = 0; i < num_chunks; ++i) { if (chunks[i].type == CHUNK_DEFLATE && chunks[i].filename && strcmp(name, chunks[i].filename) == 0) { return chunks+i; @@ -813,11 +807,11 @@ void DumpChunks(ImageChunk* chunks, int num_chunks) { } } -int main(int argc, char** argv) { - int zip_mode = 0; +int imgdiff(int argc, const char** argv) { + bool zip_mode = false; if (argc >= 2 && strcmp(argv[1], "-z") == 0) { - zip_mode = 1; + zip_mode = true; --argc; ++argv; } @@ -881,12 +875,10 @@ int main(int argc, char** argv) { // Verify that the source and target images have the same chunk // structure (ie, the same sequence of deflate and normal chunks). - if (!zip_mode) { - // Merge the gzip header and footer in with any adjacent - // normal chunks. - MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks); - MergeAdjacentNormalChunks(src_chunks, &num_src_chunks); - } + // Merge the gzip header and footer in with any adjacent + // normal chunks. + MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks); + MergeAdjacentNormalChunks(src_chunks, &num_src_chunks); if (num_src_chunks != num_tgt_chunks) { printf("source and target don't have same number of chunks!\n"); @@ -898,8 +890,7 @@ int main(int argc, char** argv) { } for (i = 0; i < num_src_chunks; ++i) { if (src_chunks[i].type != tgt_chunks[i].type) { - printf("source and target don't have same chunk " - "structure! (chunk %d)\n", i); + printf("source and target don't have same chunk structure! (chunk %d)\n", i); printf("source chunks:\n"); DumpChunks(src_chunks, num_src_chunks); printf("target chunks:\n"); @@ -980,30 +971,31 @@ int main(int argc, char** argv) { unsigned char** patch_data = static_cast<unsigned char**>(malloc( num_tgt_chunks * sizeof(unsigned char*))); size_t* patch_size = static_cast<size_t*>(malloc(num_tgt_chunks * sizeof(size_t))); + saidx_t* bsdiff_cache = nullptr; for (i = 0; i < num_tgt_chunks; ++i) { if (zip_mode) { ImageChunk* src; if (tgt_chunks[i].type == CHUNK_DEFLATE && - (src = FindChunkByName(tgt_chunks[i].filename, src_chunks, - num_src_chunks))) { - patch_data[i] = MakePatch(src, tgt_chunks+i, patch_size+i); + (src = FindChunkByName(tgt_chunks[i].filename, src_chunks, num_src_chunks))) { + patch_data[i] = MakePatch(src, tgt_chunks + i, patch_size + i, nullptr); } else { - patch_data[i] = MakePatch(src_chunks, tgt_chunks+i, patch_size+i); + patch_data[i] = MakePatch(src_chunks, tgt_chunks + i, patch_size + i, &bsdiff_cache); } } else { if (i == 1 && bonus_data) { printf(" using %zu bytes of bonus data for chunk %d\n", bonus_size, i); - src_chunks[i].data = static_cast<unsigned char*>(realloc(src_chunks[i].data, - src_chunks[i].len + bonus_size)); - memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size); + src_chunks[i].data = + static_cast<unsigned char*>(realloc(src_chunks[i].data, src_chunks[i].len + bonus_size)); + memcpy(src_chunks[i].data + src_chunks[i].len, bonus_data, bonus_size); src_chunks[i].len += bonus_size; - } + } - patch_data[i] = MakePatch(src_chunks+i, tgt_chunks+i, patch_size+i); + patch_data[i] = MakePatch(src_chunks + i, tgt_chunks + i, patch_size + i, nullptr); } - printf("patch %3d is %zu bytes (of %zu)\n", - i, patch_size[i], tgt_chunks[i].source_len); + printf("patch %3d is %zu bytes (of %zu)\n", i, patch_size[i], tgt_chunks[i].source_len); } + free(bsdiff_cache); + free(src_chunks); // Figure out how big the imgdiff file header is going to be, so // that we can correctly compute the offset of each bsdiff patch @@ -1080,6 +1072,7 @@ int main(int argc, char** argv) { } } + free(tgt_chunks); free(patch_data); free(patch_size); diff --git a/applypatch/imgdiff_main.cpp b/applypatch/imgdiff_main.cpp new file mode 100644 index 000000000..7d5bdf9aa --- /dev/null +++ b/applypatch/imgdiff_main.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#include "applypatch/imgdiff.h" + +int main(int argc, char** argv) { + return imgdiff(argc, const_cast<const char**>(argv)); +} diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 1c4409e36..00ea90efa 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -14,32 +14,34 @@ * limitations under the License. */ -// See imgdiff.c in this directory for a description of the patch file +// See imgdiff.cpp in this directory for a description of the patch file // format. +#include <applypatch/imgpatch.h> + +#include <errno.h> #include <stdio.h> +#include <string.h> #include <sys/cdefs.h> #include <sys/stat.h> -#include <errno.h> #include <unistd.h> -#include <string.h> #include <string> #include <vector> -#include "zlib.h" -#include "openssl/sha.h" -#include "applypatch/applypatch.h" -#include "imgdiff.h" +#include <applypatch/applypatch.h> +#include <applypatch/imgdiff.h> +#include <openssl/sha.h> +#include <zlib.h> + #include "utils.h" int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const unsigned char* patch_data, ssize_t patch_size, SinkFn sink, void* token) { - Value patch(VAL_BLOB, std::string( - reinterpret_cast<const char*>(patch_data), patch_size)); + Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size)); - return ApplyImagePatch(old_data, old_size, &patch, sink, token, nullptr, nullptr); + return ApplyImagePatch(old_data, old_size, &patch, sink, token, nullptr, nullptr); } /* @@ -48,208 +50,201 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, * file, and update the SHA context with the output data as well. * Return 0 on success. */ -int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, - const Value* patch, - SinkFn sink, void* token, SHA_CTX* ctx, - const Value* bonus_data) { - if (patch->data.size() < 12) { - printf("patch too short to contain header\n"); - return -1; +int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, + SinkFn sink, void* token, SHA_CTX* ctx, const Value* bonus_data) { + 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) { + printf("corrupt patch file header (magic number)\n"); + return -1; + } + + int num_chunks = Read4(header + 8); + + for (int i = 0; i < num_chunks; ++i) { + // each chunk's header record starts with 4 bytes. + if (pos + 4 > patch->data.size()) { + printf("failed to read chunk %d record\n", i); + return -1; } + int type = Read4(&patch->data[pos]); + pos += 4; + + if (type == CHUNK_NORMAL) { + const char* normal_header = &patch->data[pos]; + pos += 24; + if (pos > patch->data.size()) { + printf("failed to read chunk %d normal header data\n", i); + 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) { - printf("corrupt patch file header (magic number)\n"); + size_t src_start = Read8(normal_header); + size_t src_len = Read8(normal_header + 8); + size_t patch_offset = Read8(normal_header + 16); + + if (src_start + src_len > static_cast<size_t>(old_size)) { + printf("source data too short\n"); return -1; - } + } + ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, token, ctx); + } else if (type == CHUNK_RAW) { + const char* raw_header = &patch->data[pos]; + pos += 4; + if (pos > patch->data.size()) { + printf("failed to read chunk %d raw header data\n", i); + return -1; + } - int num_chunks = Read4(header+8); + ssize_t data_len = Read4(raw_header); - for (int i = 0; i < num_chunks; ++i) { - // each chunk's header record starts with 4 bytes. - if (pos + 4 > patch->data.size()) { - printf("failed to read chunk %d record\n", i); - return -1; + 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, token) != + 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]; + pos += 60; + if (pos > patch->data.size()) { + printf("failed to read chunk %d deflate header data\n", i); + return -1; + } + + size_t src_start = Read8(deflate_header); + size_t src_len = Read8(deflate_header + 8); + size_t patch_offset = Read8(deflate_header + 16); + size_t expanded_len = Read8(deflate_header + 24); + size_t target_len = Read8(deflate_header + 32); + int level = Read4(deflate_header + 40); + int method = Read4(deflate_header + 44); + int windowBits = Read4(deflate_header + 48); + int memLevel = Read4(deflate_header + 52); + int strategy = Read4(deflate_header + 56); + + if (src_start + src_len > static_cast<size_t>(old_size)) { + printf("source data too short\n"); + return -1; + } + + // Decompress the source data; the chunk header tells us exactly + // how big we expect it to be when decompressed. + + // Note: expanded_len will include the bonus data size if + // the patch was constructed with bonus data. The + // deflation will come up 'bonus_size' bytes short; these + // must be appended from the bonus_data value. + size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->data.size() : 0; + + std::vector<unsigned char> expanded_source(expanded_len); + + // inflate() doesn't like strm.next_out being a nullptr even with + // avail_out being zero (Z_STREAM_ERROR). + if (expanded_len != 0) { + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = src_len; + strm.next_in = old_data + src_start; + strm.avail_out = expanded_len; + strm.next_out = expanded_source.data(); + + int ret = inflateInit2(&strm, -15); + if (ret != Z_OK) { + printf("failed to init source inflation: %d\n", ret); + return -1; } - int type = Read4(&patch->data[pos]); - pos += 4; - - if (type == CHUNK_NORMAL) { - const char* normal_header = &patch->data[pos]; - pos += 24; - if (pos > patch->data.size()) { - printf("failed to read chunk %d normal header data\n", i); - return -1; - } - - size_t src_start = Read8(normal_header); - size_t src_len = Read8(normal_header+8); - size_t patch_offset = Read8(normal_header+16); - - if (src_start + src_len > static_cast<size_t>(old_size)) { - printf("source data too short\n"); - return -1; - } - ApplyBSDiffPatch(old_data + src_start, src_len, - patch, patch_offset, sink, token, ctx); - } else if (type == CHUNK_RAW) { - const char* raw_header = &patch->data[pos]; - pos += 4; - if (pos > patch->data.size()) { - printf("failed to read chunk %d raw header data\n", i); - return -1; - } - - ssize_t data_len = Read4(raw_header); - - 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, token) != 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]; - pos += 60; - if (pos > patch->data.size()) { - printf("failed to read chunk %d deflate header data\n", i); - return -1; - } - - size_t src_start = Read8(deflate_header); - size_t src_len = Read8(deflate_header+8); - size_t patch_offset = Read8(deflate_header+16); - size_t expanded_len = Read8(deflate_header+24); - size_t target_len = Read8(deflate_header+32); - int level = Read4(deflate_header+40); - int method = Read4(deflate_header+44); - int windowBits = Read4(deflate_header+48); - int memLevel = Read4(deflate_header+52); - int strategy = Read4(deflate_header+56); - - if (src_start + src_len > static_cast<size_t>(old_size)) { - printf("source data too short\n"); - return -1; - } - - // Decompress the source data; the chunk header tells us exactly - // how big we expect it to be when decompressed. - - // Note: expanded_len will include the bonus data size if - // the patch was constructed with bonus data. The - // deflation will come up 'bonus_size' bytes short; these - // must be appended from the bonus_data value. - size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->data.size() : 0; - - std::vector<unsigned char> expanded_source(expanded_len); - - // inflate() doesn't like strm.next_out being a nullptr even with - // avail_out being zero (Z_STREAM_ERROR). - if (expanded_len != 0) { - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = src_len; - strm.next_in = (unsigned char*)(old_data + src_start); - strm.avail_out = expanded_len; - strm.next_out = expanded_source.data(); - - int ret; - ret = inflateInit2(&strm, -15); - if (ret != Z_OK) { - printf("failed to init source inflation: %d\n", ret); - return -1; - } - - // Because we've provided enough room to accommodate the output - // data, we expect one call to inflate() to suffice. - ret = inflate(&strm, Z_SYNC_FLUSH); - if (ret != Z_STREAM_END) { - printf("source inflation returned %d\n", ret); - return -1; - } - // We should have filled the output buffer exactly, except - // for the bonus_size. - if (strm.avail_out != bonus_size) { - printf("source inflation short by %zu bytes\n", strm.avail_out-bonus_size); - return -1; - } - inflateEnd(&strm); - - if (bonus_size) { - memcpy(expanded_source.data() + (expanded_len - bonus_size), - &bonus_data->data[0], bonus_size); - } - } - - // Next, apply the bsdiff patch (in memory) to the uncompressed - // data. - std::vector<unsigned char> uncompressed_target_data; - if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len, - patch, patch_offset, - &uncompressed_target_data) != 0) { - return -1; - } - if (uncompressed_target_data.size() != target_len) { - printf("expected target len to be %zu, but it's %zu\n", - target_len, uncompressed_target_data.size()); - return -1; - } - - // Now compress the target data and append it to the output. - - // we're done with the expanded_source data buffer, so we'll - // reuse that memory to receive the output of deflate. - if (expanded_source.size() < 32768U) { - expanded_source.resize(32768U); - } - - { - std::vector<unsigned char>& temp_data = expanded_source; - - // now the deflate stream - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = uncompressed_target_data.size(); - strm.next_in = uncompressed_target_data.data(); - int ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy); - if (ret != Z_OK) { - printf("failed to init uncompressed data deflation: %d\n", ret); - return -1; - } - do { - strm.avail_out = temp_data.size(); - strm.next_out = temp_data.data(); - ret = deflate(&strm, Z_FINISH); - ssize_t have = temp_data.size() - strm.avail_out; - - if (sink(temp_data.data(), have, token) != have) { - printf("failed to write %zd compressed bytes to output\n", - have); - return -1; - } - if (ctx) SHA1_Update(ctx, temp_data.data(), have); - } while (ret != Z_STREAM_END); - deflateEnd(&strm); - } - } else { - printf("patch chunk %d is unknown type %d\n", i, type); - return -1; + + // Because we've provided enough room to accommodate the output + // data, we expect one call to inflate() to suffice. + ret = inflate(&strm, Z_SYNC_FLUSH); + if (ret != Z_STREAM_END) { + printf("source inflation returned %d\n", ret); + return -1; + } + // We should have filled the output buffer exactly, except + // for the bonus_size. + if (strm.avail_out != bonus_size) { + printf("source inflation short by %zu bytes\n", strm.avail_out - bonus_size); + return -1; } + inflateEnd(&strm); + + if (bonus_size) { + memcpy(expanded_source.data() + (expanded_len - bonus_size), &bonus_data->data[0], + bonus_size); + } + } + + // Next, apply the bsdiff patch (in memory) to the uncompressed data. + std::vector<unsigned char> uncompressed_target_data; + if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len, patch, patch_offset, + &uncompressed_target_data) != 0) { + return -1; + } + if (uncompressed_target_data.size() != target_len) { + printf("expected target len to be %zu, but it's %zu\n", target_len, + uncompressed_target_data.size()); + return -1; + } + + // Now compress the target data and append it to the output. + + // we're done with the expanded_source data buffer, so we'll + // reuse that memory to receive the output of deflate. + if (expanded_source.size() < 32768U) { + expanded_source.resize(32768U); + } + + { + std::vector<unsigned char>& temp_data = expanded_source; + + // now the deflate stream + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = uncompressed_target_data.size(); + strm.next_in = uncompressed_target_data.data(); + int ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy); + if (ret != Z_OK) { + printf("failed to init uncompressed data deflation: %d\n", ret); + return -1; + } + do { + strm.avail_out = temp_data.size(); + strm.next_out = temp_data.data(); + ret = deflate(&strm, Z_FINISH); + ssize_t have = temp_data.size() - strm.avail_out; + + if (sink(temp_data.data(), have, token) != have) { + printf("failed to write %zd compressed bytes to output\n", have); + return -1; + } + if (ctx) SHA1_Update(ctx, temp_data.data(), have); + } while (ret != Z_STREAM_END); + deflateEnd(&strm); + } + } else { + printf("patch chunk %d is unknown type %d\n", i, type); + return -1; } + } - return 0; + return 0; } diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h index ca3dafbc9..4489decb6 100644 --- a/applypatch/include/applypatch/applypatch.h +++ b/applypatch/include/applypatch/applypatch.h @@ -63,9 +63,8 @@ int applypatch_flash(const char* source_filename, const char* target_filename, int LoadFileContents(const char* filename, FileContents* file); int SaveFileContents(const char* filename, const FileContents* file); -int FindMatchingPatch(uint8_t* sha1, const std::vector<std::string>& patch_sha1_str); -// bsdiff.cpp +// bspatch.cpp void ShowBSDiffLicense(); int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, ssize_t patch_offset, diff --git a/applypatch/imgdiff.h b/applypatch/include/applypatch/imgdiff.h index f2069b4f3..22cbd4fa0 100644 --- a/applypatch/imgdiff.h +++ b/applypatch/include/applypatch/imgdiff.h @@ -14,17 +14,26 @@ * limitations under the License. */ +#ifndef _APPLYPATCH_IMGDIFF_H +#define _APPLYPATCH_IMGDIFF_H + +#include <stddef.h> + // Image patch chunk types -#define CHUNK_NORMAL 0 -#define CHUNK_GZIP 1 // version 1 only -#define CHUNK_DEFLATE 2 // version 2 only -#define CHUNK_RAW 3 // version 2 only +#define CHUNK_NORMAL 0 +#define CHUNK_GZIP 1 // version 1 only +#define CHUNK_DEFLATE 2 // version 2 only +#define CHUNK_RAW 3 // version 2 only // The gzip header size is actually variable, but we currently don't // support gzipped data with any of the optional fields, so for now it // will always be ten bytes. See RFC 1952 for the definition of the // gzip format. -#define GZIP_HEADER_LEN 10 +static constexpr size_t GZIP_HEADER_LEN = 10; // The gzip footer size really is fixed. -#define GZIP_FOOTER_LEN 8 +static constexpr size_t GZIP_FOOTER_LEN = 8; + +int imgdiff(int argc, const char** argv); + +#endif // _APPLYPATCH_IMGDIFF_H diff --git a/applypatch/include/applypatch/imgpatch.h b/applypatch/include/applypatch/imgpatch.h index 64d9aa9eb..6549f79f0 100644 --- a/applypatch/include/applypatch/imgpatch.h +++ b/applypatch/include/applypatch/imgpatch.h @@ -14,13 +14,15 @@ * limitations under the License. */ -#ifndef _IMGPATCH_H -#define _IMGPATCH_H +#ifndef _APPLYPATCH_IMGPATCH_H +#define _APPLYPATCH_IMGPATCH_H -typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); +#include <sys/types.h> + +using SinkFn = ssize_t (*)(const unsigned char*, ssize_t, void*); int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const unsigned char* patch_data, ssize_t patch_size, SinkFn sink, void* token); -#endif //_IMGPATCH_H +#endif // _APPLYPATCH_IMGPATCH_H |