From 696692a3c9fe4bd8879f98f3e85341303f85afd5 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 2 Feb 2016 16:01:23 +0800 Subject: applypatch: Add a Makefile to build imgdiff in Chrome OS. Also fixed some warnings and added check for target_len. Test: mma; emerge-peppy imgdiff; emerge-nyan imgdiff; sudo emerge imgdiff Bug: 26866274 Change-Id: Ifbcd3afd6701c769ccf626e33ed94461706f7ee6 --- applypatch/Makefile | 32 ++++++++++++++++++++++++++++++++ applypatch/applypatch.h | 1 + applypatch/bsdiff.cpp | 1 - applypatch/bspatch.cpp | 1 - applypatch/imgdiff.cpp | 2 -- applypatch/imgpatch.cpp | 6 ++++++ 6 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 applypatch/Makefile (limited to 'applypatch') diff --git a/applypatch/Makefile b/applypatch/Makefile new file mode 100644 index 000000000..fa6298d46 --- /dev/null +++ b/applypatch/Makefile @@ -0,0 +1,32 @@ +# 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.. +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: imgpatch.o bspatch.o utils.o + ${AR} rcs $@ $^ diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index 14fb490ba..096596f03 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -17,6 +17,7 @@ #ifndef _APPLYPATCH_H #define _APPLYPATCH_H +#include #include #include diff --git a/applypatch/bsdiff.cpp b/applypatch/bsdiff.cpp index 55dbe5cf1..cca1b32fb 100644 --- a/applypatch/bsdiff.cpp +++ b/applypatch/bsdiff.cpp @@ -224,7 +224,6 @@ static void offtout(off_t x,u_char *buf) int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize, const char* patch_filename) { - int fd; off_t *I; off_t scan,pos,len; off_t lastscan,lastpos,lastoffset; diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index ebb55f1d1..1fc1455a6 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -182,7 +182,6 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, off_t oldpos = 0, newpos = 0; off_t ctrl[3]; - off_t len_read; int i; unsigned char buf[24]; while (newpos < new_size) { diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index f22502e38..a3c10b40a 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -598,7 +598,6 @@ int ReconstructDeflateChunk(ImageChunk* chunk) { return -1; } - size_t p = 0; unsigned char* out = reinterpret_cast(malloc(BUFFER_SIZE)); // We only check two combinations of encoder parameters: level 6 @@ -844,7 +843,6 @@ int main(int argc, char** argv) { } if (argc != 4) { - usage: printf("usage: %s [-z] [-b ] \n", argv[0]); return 2; diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 8824038ea..0ab995b30 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -130,6 +130,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, 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); @@ -195,6 +196,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, &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. -- cgit v1.2.3 From a7b9a4660c18a88413280c84c03917ae953d62b0 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: IO fault injection for OTA packages Bug: 25951086 Change-Id: I31c74c735eb7a975b7f41fe2b2eff042e5699c0c (cherry-picked from commit f1fc48c6e62cfee42d25ad12f443e22d50c15d0b) --- applypatch/Android.mk | 4 ++-- applypatch/applypatch.cpp | 53 ++++++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 28 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 23d0f7bb1..90a86dcb0 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -21,7 +21,7 @@ LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.c LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libbase libmtdutils libcrypto_static libbz libz +LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz include $(BUILD_STATIC_LIBRARY) @@ -55,7 +55,7 @@ LOCAL_CLANG := true LOCAL_SRC_FILES := main.cpp LOCAL_MODULE := applypatch LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libmtdutils libcrypto_static libbz libedify +LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz libedify LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 75d77372e..4eec33256 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -35,6 +35,7 @@ #include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "print_sha1.h" +#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); @@ -79,19 +80,19 @@ int LoadFileContents(const char* filename, FileContents* file) { return -1; } - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; } - size_t bytes_read = fread(data.get(), 1, file->size, f); + size_t bytes_read = ota_fread(data.get(), 1, file->size, f); if (bytes_read != static_cast(file->size)) { printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); - fclose(f); + ota_fclose(f); return -1; } - fclose(f); + ota_fclose(f); file->data = data.release(); SHA1(file->data, file->size, file->sha1); return 0; @@ -180,7 +181,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } case EMMC: - dev = fopen(partition, "rb"); + dev = ota_fopen(partition, "rb"); if (dev == NULL) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; @@ -209,7 +210,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { break; case EMMC: - read = fread(p, 1, next, dev); + read = ota_fread(p, 1, next, dev); break; } if (next != read) { @@ -255,7 +256,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { break; case EMMC: - fclose(dev); + ota_fclose(dev); break; } @@ -282,7 +283,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { - int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); + int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); if (fd < 0) { printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); return -1; @@ -292,14 +293,14 @@ int SaveFileContents(const char* filename, const FileContents* file) { if (bytes_written != file->size) { printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n", filename, bytes_written, file->size, strerror(errno)); - close(fd); + ota_close(fd); return -1; } - if (fsync(fd) != 0) { + if (ota_fsync(fd) != 0) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -382,7 +383,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) case EMMC: { size_t start = 0; bool success = false; - int fd = open(partition, O_RDWR | O_SYNC); + int fd = ota_open(partition, O_RDWR | O_SYNC); if (fd < 0) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; @@ -397,22 +398,22 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) size_t to_write = len - start; if (to_write > 1<<20) to_write = 1<<20; - ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write)); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); if (written == -1) { printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; } start += written; } - if (fsync(fd) != 0) { + if (ota_fsync(fd) != 0) { printf("failed to sync to %s (%s)\n", partition, strerror(errno)); return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("failed to close %s (%s)\n", partition, strerror(errno)); return -1; } - fd = open(partition, O_RDONLY); + fd = ota_open(partition, O_RDONLY); if (fd < 0) { printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); return -1; @@ -421,13 +422,13 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) // Drop caches so our subsequent verification read // won't just be reading the cache. sync(); - int dc = open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) { + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); } else { printf(" caches dropped\n"); } - close(dc); + ota_close(dc); sleep(1); // verify @@ -447,7 +448,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) size_t so_far = 0; while (so_far < to_read) { ssize_t read_count = - TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far)); + TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); if (read_count == -1) { printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); @@ -479,7 +480,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - if (close(fd) != 0) { + if (ota_close(fd) != 0) { printf("error closing %s (%s)\n", partition, strerror(errno)); return -1; } @@ -589,7 +590,7 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { ssize_t done = 0; ssize_t wrote; while (done < len) { - wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done)); + wrote = TEMP_FAILURE_RETRY(ota_write(fd, data+done, len-done)); if (wrote == -1) { printf("error writing %zd bytes: %s\n", (len-done), strerror(errno)); return done; @@ -934,8 +935,8 @@ static int GenerateTarget(FileContents* source_file, token = &memory_sink_str; } else { // We write the decoded output to ".patch". - output_fd = open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR); + output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + S_IRUSR | S_IWUSR); if (output_fd < 0) { printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); @@ -958,12 +959,12 @@ static int GenerateTarget(FileContents* source_file, } if (!target_is_partition) { - if (fsync(output_fd) != 0) { + if (ota_fsync(output_fd) != 0) { printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (close(output_fd) != 0) { + if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; -- cgit v1.2.3 From d6c93afcc28cc65217ba65eeb646009c4f15a2ad Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 10 Feb 2016 16:41:10 -0800 Subject: applypatch: use vector to store data in FileContents. Bug: 26906416 Change-Id: Ib53b445cd415a1ed5e95733fbc4073f9ef4dbc43 --- applypatch/applypatch.cpp | 103 ++++++++++++++-------------------------------- applypatch/applypatch.h | 12 ++---- applypatch/main.cpp | 67 ++++++++++++++---------------- 3 files changed, 66 insertions(+), 116 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 4eec33256..f66dbe3bf 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -56,8 +56,6 @@ static bool mtd_partitions_scanned = false; // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - file->data = NULL; - // A special 'filename' beginning with "MTD:" or "EMMC:" means to // load the contents of a partition. if (strncmp(filename, "MTD:", 4) == 0 || @@ -70,31 +68,22 @@ int LoadFileContents(const char* filename, FileContents* file) { return -1; } - file->size = file->st.st_size; - file->data = nullptr; - - std::unique_ptr data( - static_cast(malloc(file->size)), free); - if (data == nullptr) { - printf("failed to allocate memory: %s\n", strerror(errno)); - return -1; - } - + std::vector data(file->st.st_size); FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; } - size_t bytes_read = ota_fread(data.get(), 1, file->size, f); - if (bytes_read != static_cast(file->size)) { - printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); + size_t bytes_read = ota_fread(data.data(), 1, data.size(), f); + if (bytes_read != data.size()) { + printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); ota_fclose(f); return -1; } ota_fclose(f); - file->data = data.release(); - SHA1(file->data, file->size, file->sha1); + file->data = std::move(data); + SHA1(file->data.data(), file->data.size(), file->sha1); return 0; } @@ -193,17 +182,17 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { uint8_t parsed_sha[SHA_DIGEST_LENGTH]; // Allocate enough memory to hold the largest size. - file->data = static_cast(malloc(size[index[pairs-1]])); - char* p = (char*)file->data; - file->size = 0; // # bytes read so far + std::vector data(size[index[pairs-1]]); + char* p = reinterpret_cast(data.data()); + size_t data_size = 0; // # bytes read so far bool found = false; for (size_t i = 0; i < pairs; ++i) { // Read enough additional bytes to get us up to the next size. (Again, // we're trying the possibilities in order of increasing size). - size_t next = size[index[i]] - file->size; - size_t read = 0; + size_t next = size[index[i]] - data_size; if (next > 0) { + size_t read = 0; switch (type) { case MTD: read = mtd_read_data(ctx, p, next); @@ -216,12 +205,11 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (next != read) { printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); - free(file->data); - file->data = NULL; return -1; } SHA1_Update(&sha_ctx, p, read); - file->size += read; + data_size += read; + p += read; } // Duplicate the SHA context and finalize the duplicate so we can @@ -233,8 +221,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) { printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename); - free(file->data); - file->data = NULL; return -1; } @@ -246,8 +232,6 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { found = true; break; } - - p += read; } switch (type) { @@ -264,13 +248,13 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { if (!found) { // Ran off the end of the list of (size,sha1) pairs without finding a match. printf("contents of partition \"%s\" didn't match %s\n", partition, filename); - free(file->data); - file->data = NULL; return -1; } SHA1_Final(file->sha1, &sha_ctx); + data.resize(data_size); + file->data = std::move(data); // Fake some stat() info. file->st.st_mode = 0644; file->st.st_uid = 0; @@ -289,10 +273,10 @@ int SaveFileContents(const char* filename, const FileContents* file) { return -1; } - ssize_t bytes_written = FileSink(file->data, file->size, &fd); - if (bytes_written != file->size) { - printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n", - filename, bytes_written, file->size, strerror(errno)); + ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); + if (bytes_written != static_cast(file->data.size())) { + printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n", + filename, bytes_written, file->data.size(), strerror(errno)); ota_close(fd); return -1; } @@ -543,7 +527,6 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int applypatch_check(const char* filename, int num_patches, char** const patch_sha1_str) { FileContents file; - file.data = NULL; // It's okay to specify no sha1s; the check will pass if the // LoadFileContents is successful. (Useful for reading @@ -555,9 +538,6 @@ int applypatch_check(const char* filename, int num_patches, printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); - free(file.data); - file.data = NULL; - // 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 @@ -571,12 +551,9 @@ int applypatch_check(const char* filename, int num_patches, if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) { printf("cache bits don't match any sha1 for \"%s\"\n", filename); - free(file.data); return 1; } } - - free(file.data); return 0; } @@ -674,8 +651,6 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; - copy_file.data = NULL; - source_file.data = NULL; const Value* source_patch_value = NULL; const Value* copy_patch_value = NULL; @@ -685,22 +660,20 @@ int applypatch(const char* source_filename, // The early-exit case: the patch was already applied, this file // has the desired hash, nothing for us to do. printf("already %s\n", short_sha1(target_sha1).c_str()); - free(source_file.data); return 0; } } - if (source_file.data == NULL || + if (source_file.data.empty() || (target_filename != source_filename && strcmp(target_filename, source_filename) != 0)) { // Need to load the source file: either we failed to load the // target file, or we did but it's different from the source file. - free(source_file.data); - source_file.data = NULL; + source_file.data.clear(); LoadFileContents(source_filename, &source_file); } - if (source_file.data != NULL) { + if (!source_file.data.empty()) { int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches); if (to_use >= 0) { source_patch_value = patch_data[to_use]; @@ -708,8 +681,7 @@ int applypatch(const char* source_filename, } if (source_patch_value == NULL) { - free(source_file.data); - source_file.data = NULL; + source_file.data.clear(); printf("source file is bad; trying copy\n"); if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { @@ -726,19 +698,14 @@ int applypatch(const char* source_filename, if (copy_patch_value == NULL) { // fail. printf("copy file doesn't match source SHA-1s either\n"); - free(copy_file.data); return 1; } } - int result = GenerateTarget(&source_file, source_patch_value, - ©_file, copy_patch_value, - source_filename, target_filename, - target_sha1, target_size, bonus_data); - free(source_file.data); - free(copy_file.data); - - return result; + return GenerateTarget(&source_file, source_patch_value, + ©_file, copy_patch_value, + source_filename, target_filename, + target_sha1, target_size, bonus_data); } /* @@ -759,7 +726,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, } FileContents source_file; - source_file.data = NULL; std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); @@ -777,7 +743,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, // The early-exit case: the image was already applied, this partition // has the desired hash, nothing for us to do. printf("already %s\n", short_sha1(target_sha1).c_str()); - free(source_file.data); return 0; } @@ -787,18 +752,14 @@ int applypatch_flash(const char* source_filename, const char* target_filename, printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), short_sha1(source_file.sha1).c_str()); - free(source_file.data); return 1; } } - if (WriteToPartition(source_file.data, target_size, target_filename) != 0) { + if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { printf("write of copied data to %s failed\n", target_filename); - free(source_file.data); return 1; } - - free(source_file.data); return 0; } @@ -867,7 +828,7 @@ static int GenerateTarget(FileContents* source_file, // We still write the original source to cache, in case // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->size) < 0) { + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -908,7 +869,7 @@ static int GenerateTarget(FileContents* source_file, return 1; } - if (MakeFreeSpaceOnCache(source_file->size) < 0) { + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { printf("not enough free space on /cache\n"); return 1; } @@ -951,10 +912,10 @@ static int GenerateTarget(FileContents* source_file, int result; if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, + result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, sink, token, &ctx); } else { - result = ApplyImagePatch(source_to_use->data, source_to_use->size, + result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, token, &ctx, bonus_data); } diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h index 096596f03..9ee39d293 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -25,17 +25,11 @@ #include "openssl/sha.h" #include "edify/expr.h" -typedef struct _Patch { +struct FileContents { uint8_t sha1[SHA_DIGEST_LENGTH]; - const char* patch_filename; -} Patch; - -typedef struct _FileContents { - uint8_t sha1[SHA_DIGEST_LENGTH]; - unsigned char* data; - ssize_t size; + std::vector data; struct stat st; -} FileContents; +}; // 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 diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 7606d5d3c..9013760c4 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -46,40 +46,32 @@ static int SpaceMode(int argc, char** argv) { return CacheSizeCheck(bytes); } -// Parse arguments (which should be of the form "" or -// ":" into the new parallel arrays *sha1s and -// *patches (loading file contents into the patches). Returns true on +// Parse arguments (which should be of the form ":" +// into the new parallel arrays *sha1s and *files.Returns true on // success. static bool ParsePatchArgs(int argc, char** argv, std::vector* sha1s, - std::vector>* patches) { + std::vector* files) { uint8_t digest[SHA_DIGEST_LENGTH]; for (int i = 0; i < argc; ++i) { char* colon = strchr(argv[i], ':'); - if (colon != NULL) { - *colon = '\0'; - ++colon; + if (colon == nullptr) { + printf("no ':' in patch argument \"%s\"\n", argv[i]); + return false; } - + *colon = '\0'; + ++colon; if (ParseSha1(argv[i], digest) != 0) { printf("failed to parse sha1 \"%s\"\n", argv[i]); return false; } sha1s->push_back(argv[i]); - if (colon == NULL) { - patches->emplace_back(nullptr, FreeValue); - } else { - FileContents fc; - if (LoadFileContents(colon, &fc) != 0) { - return false; - } - std::unique_ptr value(new Value, FreeValue); - value->type = VAL_BLOB; - value->size = fc.size; - value->data = reinterpret_cast(fc.data); - patches->push_back(std::move(value)); + FileContents fc; + if (LoadFileContents(colon, &fc) != 0) { + return false; } + files->push_back(std::move(fc)); } return true; } @@ -90,17 +82,19 @@ static int FlashMode(const char* src_filename, const char* tgt_filename, } static int PatchMode(int argc, char** argv) { - std::unique_ptr bonus(nullptr, FreeValue); + FileContents bonusFc; + Value bonusValue; + Value* bonus = nullptr; + if (argc >= 3 && strcmp(argv[1], "-b") == 0) { - FileContents fc; - if (LoadFileContents(argv[2], &fc) != 0) { + if (LoadFileContents(argv[2], &bonusFc) != 0) { printf("failed to load bonus file %s\n", argv[2]); return 1; } - bonus.reset(new Value); + bonus = &bonusValue; bonus->type = VAL_BLOB; - bonus->size = fc.size; - bonus->data = reinterpret_cast(fc.data); + bonus->size = bonusFc.data.size(); + bonus->data = reinterpret_cast(bonusFc.data.data()); argc -= 2; argv += 2; } @@ -118,28 +112,29 @@ static int PatchMode(int argc, char** argv) { // If no : is provided, it is in flash mode. if (argc == 5) { - if (bonus != NULL) { + if (bonus != nullptr) { printf("bonus file not supported in flash mode\n"); return 1; } return FlashMode(argv[1], argv[2], argv[3], target_size); } - - std::vector sha1s; - std::vector> patches; - if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches)) { + std::vector files; + if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { printf("failed to parse patch args\n"); return 1; } - - std::vector patch_ptrs; - for (const auto& p : patches) { - patch_ptrs.push_back(p.get()); + std::vector patches(files.size()); + std::vector patch_ptrs(files.size()); + for (size_t i = 0; i < files.size(); ++i) { + patches[i].type = VAL_BLOB; + patches[i].size = files[i].data.size(); + patches[i].data = reinterpret_cast(files[i].data.data()); + patch_ptrs[i] = &patches[i]; } return applypatch(argv[1], argv[2], argv[3], target_size, patch_ptrs.size(), sha1s.data(), - patch_ptrs.data(), bonus.get()); + patch_ptrs.data(), bonus); } // This program applies binary patches to files in a way that is safe -- cgit v1.2.3 From fa4f1b75b6686f73a253536d6ce6deb3ed065148 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Thu, 11 Feb 2016 16:14:23 -0800 Subject: imgdiff: don't fail if gzip is corrupted. Treat it as a normal chunk if inflate() fails. Test: run imgdiff on corrupted gzip and apply the patch Bug: 27153028 Change-Id: Idcbb3c1360ec0774e6c7861b21d99af8ee10604a --- applypatch/imgdiff.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index a3c10b40a..2aa4a6862 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -407,7 +407,6 @@ unsigned char* ReadImage(const char* filename, while (pos < sz) { unsigned char* p = img+pos; - bool processed_deflate = false; if (sz - pos >= 4 && p[0] == 0x1f && p[1] == 0x8b && p[2] == 0x08 && // deflate compression @@ -461,28 +460,27 @@ unsigned char* ReadImage(const char* filename, strm.next_out = curr->data + curr->len; ret = inflate(&strm, Z_NO_FLUSH); if (ret < 0) { - if (!processed_deflate) { - // This is the first chunk, assume that it's just a spurious - // gzip header instead of a real one. - break; - } - printf("Error: inflate failed [%s] at file offset [%zu]\n" - "imgdiff only supports gzip kernel compression," - " did you try CONFIG_KERNEL_LZO?\n", + printf("Warning: inflate failed [%s] at offset [%zu]," + " treating as a normal chunk\n", strm.msg, chunk_offset); - free(img); - return NULL; + break; } curr->len = allocated - strm.avail_out; if (strm.avail_out == 0) { allocated *= 2; curr->data = reinterpret_cast(realloc(curr->data, allocated)); } - processed_deflate = true; } while (ret != Z_STREAM_END); curr->deflate_len = sz - strm.avail_in - pos; inflateEnd(&strm); + + if (ret < 0) { + free(curr->data); + *num_chunks -= 2; + continue; + } + pos += curr->deflate_len; p += curr->deflate_len; ++curr; -- cgit v1.2.3 From f3e05f504d9ef387228e5bcd28723f6617991e8c Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 16 Feb 2016 11:23:09 -0800 Subject: applypatch: Add libimgpatch.pc Test: pkg-config --libs libimgpatch Bug: 26866274 Change-Id: I79a103099d951943a88768c577224fccacbb79e3 --- applypatch/libimgpatch.pc | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 applypatch/libimgpatch.pc (limited to 'applypatch') diff --git a/applypatch/libimgpatch.pc b/applypatch/libimgpatch.pc new file mode 100644 index 000000000..e5002934f --- /dev/null +++ b/applypatch/libimgpatch.pc @@ -0,0 +1,6 @@ +# This file is for libimgpatch in Chrome OS. + +Name: libimgpatch +Description: Apply imgdiff patch +Version: 0.0.1 +Libs: -limgpatch -lbz2 -lz -- cgit v1.2.3 From 39c1b5e8722dbf0bbb3ee45e201373099f075345 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: Control fault injection with config files instead of build flags Bug: 26570379 Change-Id: I76109d09276d6e3ed3a32b6fedafb2582f545c0c (cherry picked from commit d940887dde23597dc358b16d96ca48dd7480fee6) --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index f66dbe3bf..644515997 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -34,8 +34,8 @@ #include "applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" +#include "ota_io.h" #include "print_sha1.h" -#include "otafault/ota_io.h" static int LoadPartitionContents(const char* filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); -- cgit v1.2.3 From d80a99883d5ae2b117c54f076fe1df7eae86d2f8 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Mar 2016 11:43:47 -0800 Subject: Fix the improper use of LOCAL_WHOLE_STATIC_LIBRARIES. If two libraries both use LOCAL_WHOLE_STATIC_LIBRARIES and include a same library, there would be linking errors when generating a shared library (or executable) that depends on the two libraries both. Also clean up Android.mk files. Remove the "LOCAL_MODULE_TAGS := eng" line for the updater module. The module will then default to "optional" which won't be built until needed. Change-Id: I3ec227109b8aa744b7568e7f82f575aae3fe0e6f --- applypatch/Android.mk | 64 +++++++++++++++------- applypatch/applypatch.cpp | 2 +- applypatch/applypatch.h | 87 ------------------------------ applypatch/bspatch.cpp | 2 +- applypatch/freecache.cpp | 2 +- applypatch/imgpatch.cpp | 2 +- applypatch/include/applypatch/applypatch.h | 87 ++++++++++++++++++++++++++++++ applypatch/main.cpp | 2 +- 8 files changed, 136 insertions(+), 112 deletions(-) delete mode 100644 applypatch/applypatch.h create mode 100644 applypatch/include/applypatch/applypatch.h (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 90a86dcb0..9e64718c1 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -14,59 +14,83 @@ LOCAL_PATH := $(call my-dir) +# libapplypatch (static library) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true -LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.cpp +LOCAL_SRC_FILES := \ + applypatch.cpp \ + bspatch.cpp \ + freecache.cpp \ + imgpatch.cpp \ + utils.cpp LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng -LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz - +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + bootable/recovery +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_STATIC_LIBRARIES += \ + libotafault \ + libmtdutils \ + libbase \ + libcrypto_static \ + libbz \ + libz include $(BUILD_STATIC_LIBRARY) +# libimgpatch (static library) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp LOCAL_MODULE := libimgpatch -LOCAL_C_INCLUDES += bootable/recovery +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz - include $(BUILD_STATIC_LIBRARY) -ifeq ($(HOST_OS),linux) +# libimgpatch (host static library) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp LOCAL_MODULE := libimgpatch -LOCAL_C_INCLUDES += bootable/recovery +LOCAL_MODULE_HOST_OS := linux +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz - include $(BUILD_HOST_STATIC_LIBRARY) -endif # HOST_OS == linux +# applypatch (executable) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := main.cpp LOCAL_MODULE := applypatch LOCAL_C_INCLUDES += bootable/recovery -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz libedify +LOCAL_STATIC_LIBRARIES += \ + libapplypatch \ + libbase \ + libedify \ + libotafault \ + libminzip \ + libmtdutils \ + libcrypto_static \ + libbz LOCAL_SHARED_LIBRARIES += libz libcutils libc - include $(BUILD_EXECUTABLE) +# imgdiff (host static executable) +# =============================== include $(CLEAR_VARS) - LOCAL_CLANG := true LOCAL_SRC_FILES := imgdiff.cpp utils.cpp bsdiff.cpp LOCAL_MODULE := imgdiff -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_C_INCLUDES += external/zlib external/bzip2 LOCAL_STATIC_LIBRARIES += libz libbz - +LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 644515997..c8594c283 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -31,7 +31,7 @@ #include #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "ota_io.h" diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h deleted file mode 100644 index 9ee39d293..000000000 --- a/applypatch/applypatch.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2008 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_H -#define _APPLYPATCH_H - -#include -#include - -#include - -#include "openssl/sha.h" -#include "edify/expr.h" - -struct FileContents { - uint8_t sha1[SHA_DIGEST_LENGTH]; - std::vector 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" - -typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); - -// applypatch.c -int ShowLicenses(); -size_t FreeSpaceForFile(const char* filename); -int CacheSizeCheck(size_t bytes); -int ParseSha1(const char* str, uint8_t* digest); - -int applypatch_flash(const char* source_filename, const char* target_filename, - const char* target_sha1_str, size_t target_size); -int applypatch(const char* source_filename, - const char* target_filename, - const char* target_sha1_str, - size_t target_size, - int num_patches, - char** const patch_sha1_str, - Value** patch_data, - Value* bonus_data); -int applypatch_check(const char* filename, - int num_patches, - char** const patch_sha1_str); - -int LoadFileContents(const char* filename, FileContents* file); -int SaveFileContents(const char* filename, const FileContents* file); -void FreeFileContents(FileContents* file); -int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, - int num_patches); - -// bsdiff.cpp -void ShowBSDiffLicense(); -int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, - const Value* patch, ssize_t patch_offset, - SinkFn sink, void* token, SHA_CTX* ctx); -int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, - const Value* patch, ssize_t patch_offset, - std::vector* new_data); - -// imgpatch.cpp -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); - -// freecache.cpp -int MakeFreeSpaceOnCache(size_t bytes_needed); - -#endif diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index 1fc1455a6..a4945da28 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -30,7 +30,7 @@ #include #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" void ShowBSDiffLicense() { puts("The bsdiff library used herein is:\n" diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp index c84f42797..331cae265 100644 --- a/applypatch/freecache.cpp +++ b/applypatch/freecache.cpp @@ -32,7 +32,7 @@ #include #include -#include "applypatch.h" +#include "applypatch/applypatch.h" static int EliminateOpenFiles(std::set* files) { std::unique_ptr d(opendir("/proc"), closedir); diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 0ab995b30..4251c0120 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -28,7 +28,7 @@ #include "zlib.h" #include "openssl/sha.h" -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "imgdiff.h" #include "utils.h" diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h new file mode 100644 index 000000000..9ee39d293 --- /dev/null +++ b/applypatch/include/applypatch/applypatch.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 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_H +#define _APPLYPATCH_H + +#include +#include + +#include + +#include "openssl/sha.h" +#include "edify/expr.h" + +struct FileContents { + uint8_t sha1[SHA_DIGEST_LENGTH]; + std::vector 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" + +typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); + +// applypatch.c +int ShowLicenses(); +size_t FreeSpaceForFile(const char* filename); +int CacheSizeCheck(size_t bytes); +int ParseSha1(const char* str, uint8_t* digest); + +int applypatch_flash(const char* source_filename, const char* target_filename, + const char* target_sha1_str, size_t target_size); +int applypatch(const char* source_filename, + const char* target_filename, + const char* target_sha1_str, + size_t target_size, + int num_patches, + char** const patch_sha1_str, + Value** patch_data, + Value* bonus_data); +int applypatch_check(const char* filename, + int num_patches, + char** const patch_sha1_str); + +int LoadFileContents(const char* filename, FileContents* file); +int SaveFileContents(const char* filename, const FileContents* file); +void FreeFileContents(FileContents* file); +int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, + int num_patches); + +// bsdiff.cpp +void ShowBSDiffLicense(); +int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, + const Value* patch, ssize_t patch_offset, + SinkFn sink, void* token, SHA_CTX* ctx); +int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, + const Value* patch, ssize_t patch_offset, + std::vector* new_data); + +// imgpatch.cpp +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); + +// freecache.cpp +int MakeFreeSpaceOnCache(size_t bytes_needed); + +#endif diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 9013760c4..0ff8cbf9a 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -22,7 +22,7 @@ #include #include -#include "applypatch.h" +#include "applypatch/applypatch.h" #include "edify/expr.h" #include "openssl/sha.h" -- cgit v1.2.3 From ef2016f711eaef6c22d177a12d335055556ea3a0 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 8 Mar 2016 14:27:14 -0800 Subject: applypatch: add -fPIC for libimgpatch in Chrome OS. To make the static library position independent. Bug: 26866274 Test: emerge-peppy imgdiff; sudo emerge imgdiff; emerge nyan imgdiff Change-Id: I319e721ccfb6a51f63d31afa49f54aa7f607f4bf --- applypatch/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'applypatch') diff --git a/applypatch/Makefile b/applypatch/Makefile index fa6298d46..de6d4268f 100644 --- a/applypatch/Makefile +++ b/applypatch/Makefile @@ -28,5 +28,6 @@ clean: 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 $@ $^ -- cgit v1.2.3 From 82f8c820463f73ac1149ffbe65e4a6f24f826ab4 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Mon, 14 Mar 2016 14:25:33 -0700 Subject: Add include/ to the Makefile include path. The applypatch heaaders were recently moved to the include/ directory. This patch reflects that change in the Makefile. Bug: None TEST=sudo emerge imgdiff Change-Id: I0bf3f991b5e0c98054033c5939ed69b3e3c827a9 --- applypatch/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch') diff --git a/applypatch/Makefile b/applypatch/Makefile index de6d4268f..fb4984303 100644 --- a/applypatch/Makefile +++ b/applypatch/Makefile @@ -14,7 +14,7 @@ # This file is for building imgdiff in Chrome OS. -CPPFLAGS += -iquote.. +CPPFLAGS += -iquote.. -Iinclude CXXFLAGS += -std=c++11 -O3 -Wall -Werror LDLIBS += -lbz2 -lz -- cgit v1.2.3 From 54a2747ef305c10d07d8db393125dbcbb461c428 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Mon, 18 Apr 2016 11:30:55 -0700 Subject: Fix google-runtime-int warnings. Bug: 28220065 Change-Id: Ida199c66692a1638be6990d583d2ed42583fb592 --- applypatch/applypatch.cpp | 2 +- applypatch/imgpatch.cpp | 4 ++-- applypatch/utils.cpp | 20 ++++++++++---------- applypatch/utils.h | 5 +++-- 4 files changed, 16 insertions(+), 15 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index c8594c283..270fde5c4 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -596,7 +596,7 @@ size_t FreeSpaceForFile(const char* filename) { int CacheSizeCheck(size_t bytes) { if (MakeFreeSpaceOnCache(bytes) < 0) { - printf("unable to make %ld bytes available on /cache\n", (long)bytes); + printf("unable to make %zu bytes available on /cache\n", bytes); return 1; } else { return 0; diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 4251c0120..f5aed763d 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -229,8 +229,8 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, ssize_t have = temp_data.size() - strm.avail_out; if (sink(temp_data.data(), have, token) != have) { - printf("failed to write %ld compressed bytes to output\n", - (long)have); + printf("failed to write %zd compressed bytes to output\n", + have); return -1; } if (ctx) SHA1_Update(ctx, temp_data.data(), have); diff --git a/applypatch/utils.cpp b/applypatch/utils.cpp index 4a80be75f..fef250f01 100644 --- a/applypatch/utils.cpp +++ b/applypatch/utils.cpp @@ -27,7 +27,7 @@ void Write4(int value, FILE* f) { } /** Write an 8-byte value to f in little-endian order. */ -void Write8(long long value, FILE* f) { +void Write8(int64_t value, FILE* f) { fputc(value & 0xff, f); fputc((value >> 8) & 0xff, f); fputc((value >> 16) & 0xff, f); @@ -52,14 +52,14 @@ int Read4(void* pv) { (unsigned int)p[0]); } -long long Read8(void* pv) { +int64_t Read8(void* pv) { unsigned char* p = reinterpret_cast(pv); - return (long long)(((unsigned long long)p[7] << 56) | - ((unsigned long long)p[6] << 48) | - ((unsigned long long)p[5] << 40) | - ((unsigned long long)p[4] << 32) | - ((unsigned long long)p[3] << 24) | - ((unsigned long long)p[2] << 16) | - ((unsigned long long)p[1] << 8) | - (unsigned long long)p[0]); + 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]); } diff --git a/applypatch/utils.h b/applypatch/utils.h index bc97f1720..1c34edd97 100644 --- a/applypatch/utils.h +++ b/applypatch/utils.h @@ -17,14 +17,15 @@ #ifndef _BUILD_TOOLS_APPLYPATCH_UTILS_H #define _BUILD_TOOLS_APPLYPATCH_UTILS_H +#include #include // Read and write little-endian values of various sizes. void Write4(int value, FILE* f); -void Write8(long long value, FILE* f); +void Write8(int64_t value, FILE* f); int Read2(void* p); int Read4(void* p); -long long Read8(void* p); +int64_t Read8(void* p); #endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H -- cgit v1.2.3 From 2fffcb174b403959d87b400634bca343ce85d480 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 3 May 2016 15:49:10 -0700 Subject: applypatch: Use bsdiff from external/bsdiff. external/bsdiff uses divsufsort which is much faster, and also include some bug fixes. Bug: 26982501 Test: ./imgdiff_test.sh Change-Id: I089a301c291ee55d79938c7a3ca6d509895440d1 --- applypatch/Android.mk | 9 +- applypatch/bsdiff.cpp | 409 ------------------------------------------------- applypatch/imgdiff.cpp | 17 +- 3 files changed, 10 insertions(+), 425 deletions(-) delete mode 100644 applypatch/bsdiff.cpp (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 9e64718c1..a15ac0280 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -89,8 +89,13 @@ include $(BUILD_EXECUTABLE) # =============================== include $(CLEAR_VARS) LOCAL_CLANG := true -LOCAL_SRC_FILES := imgdiff.cpp utils.cpp bsdiff.cpp +LOCAL_SRC_FILES := imgdiff.cpp utils.cpp LOCAL_MODULE := imgdiff -LOCAL_STATIC_LIBRARIES += libz libbz +LOCAL_STATIC_LIBRARIES += \ + libbsdiff \ + libbz \ + libdivsufsort64 \ + libdivsufsort \ + libz LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/bsdiff.cpp b/applypatch/bsdiff.cpp deleted file mode 100644 index cca1b32fb..000000000 --- a/applypatch/bsdiff.cpp +++ /dev/null @@ -1,409 +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. - */ - -/* - * Most of this code comes from bsdiff.c from the bsdiff-4.3 - * distribution, which is: - */ - -/*- - * Copyright 2003-2005 Colin Percival - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define MIN(x,y) (((x)<(y)) ? (x) : (y)) - -static void split(off_t *I,off_t *V,off_t start,off_t len,off_t h) -{ - off_t i,j,k,x,tmp,jj,kk; - - if(len<16) { - for(k=start;kstart) split(I,V,start,jj-start,h); - - for(i=0;ikk) split(I,V,kk,start+len-kk,h); -} - -static void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize) -{ - off_t buckets[256]; - off_t i,h,len; - - for(i=0;i<256;i++) buckets[i]=0; - for(i=0;i0;i--) buckets[i]=buckets[i-1]; - buckets[0]=0; - - for(i=0;iy) { - *pos=I[st]; - return x; - } else { - *pos=I[en]; - return y; - } - }; - - x=st+(en-st)/2; - if(memcmp(old+I[x],newdata,MIN(oldsize-I[x],newsize))<0) { - return search(I,old,oldsize,newdata,newsize,x,en,pos); - } else { - return search(I,old,oldsize,newdata,newsize,st,x,pos); - }; -} - -static void offtout(off_t x,u_char *buf) -{ - off_t y; - - if(x<0) y=-x; else y=x; - - buf[0]=y%256;y-=buf[0]; - y=y/256;buf[1]=y%256;y-=buf[1]; - y=y/256;buf[2]=y%256;y-=buf[2]; - y=y/256;buf[3]=y%256;y-=buf[3]; - y=y/256;buf[4]=y%256;y-=buf[4]; - y=y/256;buf[5]=y%256;y-=buf[5]; - y=y/256;buf[6]=y%256;y-=buf[6]; - y=y/256;buf[7]=y%256; - - if(x<0) buf[7]|=0x80; -} - -// This is main() from bsdiff.c, with the following changes: -// -// - old, oldsize, newdata, newsize are arguments; we don't load this -// data from files. old and newdata are owned by the caller; we -// don't free them at the end. -// -// - the "I" block of memory is owned by the caller, who passes a -// pointer to *I, which can be NULL. This way if we call -// bsdiff() multiple times with the same 'old' data, we only do -// the qsufsort() step the first time. -// -int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize, - const char* patch_filename) -{ - off_t *I; - off_t scan,pos,len; - off_t lastscan,lastpos,lastoffset; - off_t oldscore,scsc; - off_t s,Sf,lenf,Sb,lenb; - off_t overlap,Ss,lens; - off_t i; - off_t dblen,eblen; - u_char *db,*eb; - u_char buf[8]; - u_char header[32]; - FILE * pf; - BZFILE * pfbz2; - int bz2err; - - if (*IP == NULL) { - off_t* V; - *IP = reinterpret_cast(malloc((oldsize+1) * sizeof(off_t))); - V = reinterpret_cast(malloc((oldsize+1) * sizeof(off_t))); - qsufsort(*IP, V, old, oldsize); - free(V); - } - I = *IP; - - if(((db=reinterpret_cast(malloc(newsize+1)))==NULL) || - ((eb=reinterpret_cast(malloc(newsize+1)))==NULL)) err(1,NULL); - dblen=0; - eblen=0; - - /* Create the patch file */ - if ((pf = fopen(patch_filename, "w")) == NULL) - err(1, "%s", patch_filename); - - /* Header is - 0 8 "BSDIFF40" - 8 8 length of bzip2ed ctrl block - 16 8 length of bzip2ed diff block - 24 8 length of new file */ - /* File is - 0 32 Header - 32 ?? Bzip2ed ctrl block - ?? ?? Bzip2ed diff block - ?? ?? Bzip2ed extra block */ - memcpy(header,"BSDIFF40",8); - offtout(0, header + 8); - offtout(0, header + 16); - offtout(newsize, header + 24); - if (fwrite(header, 32, 1, pf) != 1) - err(1, "fwrite(%s)", patch_filename); - - /* Compute the differences, writing ctrl as we go */ - if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) - errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err); - scan=0;len=0; - lastscan=0;lastpos=0;lastoffset=0; - while(scanoldscore+8)) break; - - if((scan+lastoffsetSf*2-lenf) { Sf=s; lenf=i; }; - }; - - lenb=0; - if(scan=lastscan+i)&&(pos>=i);i++) { - if(old[pos-i]==newdata[scan-i]) s++; - if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; - }; - }; - - if(lastscan+lenf>scan-lenb) { - overlap=(lastscan+lenf)-(scan-lenb); - s=0;Ss=0;lens=0; - for(i=0;iSs) { Ss=s; lens=i+1; }; - }; - - lenf+=lens-overlap; - lenb-=lens; - }; - - for(i=0;i #include +#include + #include "zlib.h" #include "imgdiff.h" #include "utils.h" @@ -144,8 +146,6 @@ typedef struct { size_t source_start; size_t source_len; - off_t* I; // used by bsdiff - // --- for CHUNK_DEFLATE chunks only: --- // original (compressed) deflate data @@ -179,10 +179,6 @@ static int fileentry_compare(const void* a, const void* b) { } } -// from bsdiff.c -int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize, - const char* patch_filename); - unsigned char* ReadZip(const char* filename, int* num_chunks, ImageChunk** chunks, int include_pseudo_chunk) { @@ -296,7 +292,6 @@ unsigned char* ReadZip(const char* filename, curr->len = st.st_size; curr->data = img; curr->filename = NULL; - curr->I = NULL; ++curr; ++*num_chunks; } @@ -311,7 +306,6 @@ unsigned char* ReadZip(const char* filename, curr->deflate_len = temp_entries[nextentry].deflate_len; curr->deflate_data = img + pos; curr->filename = temp_entries[nextentry].filename; - curr->I = NULL; curr->len = temp_entries[nextentry].uncomp_len; curr->data = reinterpret_cast(malloc(curr->len)); @@ -356,7 +350,6 @@ unsigned char* ReadZip(const char* filename, } curr->data = img + pos; curr->filename = NULL; - curr->I = NULL; pos += curr->len; ++*num_chunks; @@ -424,7 +417,6 @@ unsigned char* ReadImage(const char* filename, curr->type = CHUNK_NORMAL; curr->len = GZIP_HEADER_LEN; curr->data = p; - curr->I = NULL; pos += curr->len; p += curr->len; @@ -432,7 +424,6 @@ unsigned char* ReadImage(const char* filename, curr->type = CHUNK_DEFLATE; curr->filename = NULL; - curr->I = NULL; // We must decompress this chunk in order to discover where it // ends, and so we can put the uncompressed data and its length @@ -491,7 +482,6 @@ unsigned char* ReadImage(const char* filename, curr->start = pos; curr->len = GZIP_FOOTER_LEN; curr->data = img+pos; - curr->I = NULL; pos += curr->len; p += curr->len; @@ -515,7 +505,6 @@ unsigned char* ReadImage(const char* filename, *chunks = reinterpret_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); ImageChunk* curr = *chunks + (*num_chunks-1); curr->start = pos; - curr->I = NULL; // 'pos' is not the offset of the start of a gzip chunk, so scan // forward until we find a gzip header. @@ -642,7 +631,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(src->data, src->len, &(src->I), tgt->data, tgt->len, ptemp); + int r = bsdiff::bsdiff(src->data, src->len, tgt->data, tgt->len, ptemp); if (r != 0) { printf("bsdiff() failed: %d\n", r); return NULL; -- cgit v1.2.3 From b4422bd76952be4321cfbce3220bcb4fd41b5154 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 30 May 2016 21:53:11 -0700 Subject: imgdiff: Generate statically linked imgdiff. Bug: 28941046 Change-Id: If3019d8cff91fd4f6fa4516bef5a0f51c2ddebc7 --- applypatch/Android.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index a15ac0280..7b46c5937 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -97,5 +97,6 @@ LOCAL_STATIC_LIBRARIES += \ libdivsufsort64 \ libdivsufsort \ libz -LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_NO_FPIE := true +LOCAL_LDFLAGS := -static include $(BUILD_HOST_EXECUTABLE) -- cgit v1.2.3 From 16e3861c84619b649ef77b4d2ec03150556a0948 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 1 Jun 2016 00:08:40 +0000 Subject: Revert "imgdiff: Generate statically linked imgdiff." This reverts commit b4422bd76952be4321cfbce3220bcb4fd41b5154. Bug: 28941046 Change-Id: Ic3c7439c64b8e55832252850514f721a944993d6 --- applypatch/Android.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 7b46c5937..a15ac0280 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -97,6 +97,5 @@ LOCAL_STATIC_LIBRARIES += \ libdivsufsort64 \ libdivsufsort \ libz -LOCAL_NO_FPIE := true -LOCAL_LDFLAGS := -static +LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE) -- cgit v1.2.3 From 50a6f8c8335be920833d06e5dabd37de279c98a9 Mon Sep 17 00:00:00 2001 From: Adam Buchbinder Date: Fri, 20 May 2016 16:45:37 -0700 Subject: Fix memory/resource handling in imgdiff.cpp, using unique_ptr and vector. This fixes the following cppcheck reports: [imgdiff.cpp:197]: (error) Memory leak: img [imgdiff.cpp:386]: (error) Memory leak: img [imgdiff.cpp:656]: (error) Memory leak: data [imgdiff.cpp:664]: (error) Memory leak: data [imgdiff.cpp:668]: (error) Memory leak: data [imgdiff.cpp:668]: (error) Resource leak: f [imgdiff.cpp:820]: (error) Memory leak: bonus_data [imgdiff.cpp:824]: (error) Memory leak: bonus_data [imgdiff.cpp:824]: (error) Resource leak: f [imgdiff.cpp:847]: (error) Memory leak: bonus_data [imgdiff.cpp:851]: (error) Memory leak: bonus_data [imgdiff.cpp:856]: (error) Memory leak: bonus_data [imgdiff.cpp:860]: (error) Memory leak: bonus_data [imgdiff.cpp:227]: (error) Memory leak: temp_entries Change-Id: I06f878d0b677a25328e0deb84f65f3b7212e24b1 (cherry picked from commit 51dc9444bcf8d8900a521795e873d07f6cd445ef) --- applypatch/imgdiff.cpp | 78 ++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 40 deletions(-) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 7c5bb866d..c59edeb6b 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -130,6 +130,10 @@ #include #include +#include +#include +#include + #include #include "zlib.h" @@ -167,16 +171,8 @@ typedef struct { char* filename; } ZipFileEntry; -static int fileentry_compare(const void* a, const void* b) { - int ao = ((ZipFileEntry*)a)->data_offset; - int bo = ((ZipFileEntry*)b)->data_offset; - if (ao < bo) { - return -1; - } else if (ao > bo) { - return 1; - } else { - return 0; - } +static bool fileentry_compare(const ZipFileEntry& a, const ZipFileEntry& b) { + return a.data_offset < b.data_offset; } unsigned char* ReadZip(const char* filename, @@ -189,9 +185,9 @@ unsigned char* ReadZip(const char* filename, } size_t sz = static_cast(st.st_size); - unsigned char* img = reinterpret_cast(malloc(sz)); + std::unique_ptr img(new unsigned char[sz]); FILE* f = fopen(filename, "rb"); - if (fread(img, 1, sz, f) != sz) { + if (fread(img.get(), 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); fclose(f); return NULL; @@ -213,14 +209,13 @@ unsigned char* ReadZip(const char* filename, return NULL; } - int cdcount = Read2(img+i+8); - int cdoffset = Read4(img+i+16); + int cdcount = Read2(&img[i+8]); + int cdoffset = Read4(&img[i+16]); - ZipFileEntry* temp_entries = reinterpret_cast(malloc( - cdcount * sizeof(ZipFileEntry))); + std::vector temp_entries(cdcount); int entrycount = 0; - unsigned char* cd = img+cdoffset; + unsigned char* cd = &img[cdoffset]; for (i = 0; i < cdcount; ++i) { if (!(cd[0] == 0x50 && cd[1] == 0x4b && cd[2] == 0x01 && cd[3] == 0x02)) { printf("bad central directory entry %d\n", i); @@ -247,7 +242,7 @@ unsigned char* ReadZip(const char* filename, continue; } - unsigned char* lh = img + hoffset; + unsigned char* lh = &img[hoffset]; if (!(lh[0] == 0x50 && lh[1] == 0x4b && lh[2] == 0x03 && lh[3] == 0x04)) { printf("bad local file header entry %d\n", i); @@ -268,7 +263,7 @@ unsigned char* ReadZip(const char* filename, ++entrycount; } - qsort(temp_entries, entrycount, sizeof(ZipFileEntry), fileentry_compare); + std::sort(temp_entries.begin(), temp_entries.end(), fileentry_compare); #if 0 printf("found %d deflated entries\n", entrycount); @@ -290,7 +285,7 @@ unsigned char* ReadZip(const char* filename, curr->type = CHUNK_NORMAL; curr->start = 0; curr->len = st.st_size; - curr->data = img; + curr->data = img.get(); curr->filename = NULL; ++curr; ++*num_chunks; @@ -304,7 +299,7 @@ unsigned char* ReadZip(const char* filename, curr->type = CHUNK_DEFLATE; curr->start = pos; curr->deflate_len = temp_entries[nextentry].deflate_len; - curr->deflate_data = img + pos; + curr->deflate_data = &img[pos]; curr->filename = temp_entries[nextentry].filename; curr->len = temp_entries[nextentry].uncomp_len; @@ -348,7 +343,7 @@ unsigned char* ReadZip(const char* filename, } else { curr->len = st.st_size - pos; } - curr->data = img + pos; + curr->data = &img[pos]; curr->filename = NULL; pos += curr->len; @@ -356,8 +351,7 @@ unsigned char* ReadZip(const char* filename, ++curr; } - free(temp_entries); - return img; + return img.release(); } /* @@ -378,9 +372,9 @@ unsigned char* ReadImage(const char* filename, } size_t sz = static_cast(st.st_size); - unsigned char* img = reinterpret_cast(malloc(sz + 4)); + std::unique_ptr img(new unsigned char[sz+4]); FILE* f = fopen(filename, "rb"); - if (fread(img, 1, sz, f) != sz) { + if (fread(img.get(), 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); fclose(f); return NULL; @@ -390,7 +384,7 @@ unsigned char* ReadImage(const char* filename, // 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); + memset(&img[sz], 0, 4); size_t pos = 0; @@ -398,7 +392,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 && @@ -481,7 +475,7 @@ unsigned char* ReadImage(const char* filename, curr->type = CHUNK_NORMAL; curr->start = pos; curr->len = GZIP_FOOTER_LEN; - curr->data = img+pos; + curr->data = &img[pos]; pos += curr->len; p += curr->len; @@ -495,7 +489,6 @@ unsigned char* ReadImage(const char* filename, if (footer_size != curr[-2].len) { printf("Error: footer size %zu != decompressed size %zu\n", footer_size, curr[-2].len); - free(img); return NULL; } } else { @@ -523,7 +516,7 @@ unsigned char* ReadImage(const char* filename, } } - return img; + return img.release(); } #define BUFFER_SIZE 32768 @@ -645,8 +638,7 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { } size_t sz = static_cast(st.st_size); - // TODO: Memory leak on error return. - unsigned char* data = reinterpret_cast(malloc(sz)); + std::unique_ptr data(new unsigned char[sz]); if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) { unlink(ptemp); @@ -663,8 +655,9 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { printf("failed to open patch %s: %s\n", ptemp, strerror(errno)); return NULL; } - if (fread(data, 1, sz, f) != sz) { + if (fread(data.get(), 1, sz, f) != sz) { printf("failed to read patch %s: %s\n", ptemp, strerror(errno)); + fclose(f); return NULL; } fclose(f); @@ -682,7 +675,7 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { break; } - return data; + return data.release(); } /* @@ -805,7 +798,7 @@ int main(int argc, char** argv) { } size_t bonus_size = 0; - unsigned char* bonus_data = NULL; + std::vector bonus_data; if (argc >= 3 && strcmp(argv[1], "-b") == 0) { struct stat st; if (stat(argv[2], &st) != 0) { @@ -813,14 +806,15 @@ int main(int argc, char** argv) { return 1; } bonus_size = st.st_size; - bonus_data = reinterpret_cast(malloc(bonus_size)); + bonus_data.resize(bonus_size); FILE* f = fopen(argv[2], "rb"); if (f == NULL) { printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno)); return 1; } - if (fread(bonus_data, 1, bonus_size, f) != bonus_size) { + if (fread(bonus_data.data(), 1, bonus_size, f) != bonus_size) { printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno)); + fclose(f); return 1; } fclose(f); @@ -973,11 +967,11 @@ int main(int argc, char** argv) { patch_data[i] = MakePatch(src_chunks, tgt_chunks+i, patch_size+i); } } else { - if (i == 1 && bonus_data) { + if (i == 1 && !bonus_data.empty()) { printf(" using %zu bytes of bonus data for chunk %d\n", bonus_size, i); src_chunks[i].data = reinterpret_cast(realloc(src_chunks[i].data, src_chunks[i].len + bonus_size)); - memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size); + memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data.data(), bonus_size); src_chunks[i].len += bonus_size; } @@ -1063,6 +1057,10 @@ int main(int argc, char** argv) { } fclose(f); + for (i = 0; i < num_tgt_chunks; ++i) { + free(patch_data[i]); + } + free(patch_data); return 0; } -- cgit v1.2.3 From a0c40110281584fcfa22dc16e73622fa0e5b7a57 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 1 Jun 2016 13:15:44 -0700 Subject: Revert "Fix memory/resource handling in imgdiff.cpp, using unique_ptr and vector." This reverts commit 50a6f8c8335be920833d06e5dabd37de279c98a9. A mix of new and free leads to memory corruptions. --- applypatch/imgdiff.cpp | 78 ++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 38 deletions(-) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index c59edeb6b..7c5bb866d 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -130,10 +130,6 @@ #include #include -#include -#include -#include - #include #include "zlib.h" @@ -171,8 +167,16 @@ typedef struct { char* filename; } ZipFileEntry; -static bool fileentry_compare(const ZipFileEntry& a, const ZipFileEntry& b) { - return a.data_offset < b.data_offset; +static int fileentry_compare(const void* a, const void* b) { + int ao = ((ZipFileEntry*)a)->data_offset; + int bo = ((ZipFileEntry*)b)->data_offset; + if (ao < bo) { + return -1; + } else if (ao > bo) { + return 1; + } else { + return 0; + } } unsigned char* ReadZip(const char* filename, @@ -185,9 +189,9 @@ unsigned char* ReadZip(const char* filename, } size_t sz = static_cast(st.st_size); - std::unique_ptr img(new unsigned char[sz]); + unsigned char* img = reinterpret_cast(malloc(sz)); FILE* f = fopen(filename, "rb"); - if (fread(img.get(), 1, sz, f) != sz) { + if (fread(img, 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); fclose(f); return NULL; @@ -209,13 +213,14 @@ unsigned char* ReadZip(const char* filename, return NULL; } - int cdcount = Read2(&img[i+8]); - int cdoffset = Read4(&img[i+16]); + int cdcount = Read2(img+i+8); + int cdoffset = Read4(img+i+16); - std::vector temp_entries(cdcount); + ZipFileEntry* temp_entries = reinterpret_cast(malloc( + cdcount * sizeof(ZipFileEntry))); int entrycount = 0; - unsigned char* cd = &img[cdoffset]; + unsigned char* cd = img+cdoffset; for (i = 0; i < cdcount; ++i) { if (!(cd[0] == 0x50 && cd[1] == 0x4b && cd[2] == 0x01 && cd[3] == 0x02)) { printf("bad central directory entry %d\n", i); @@ -242,7 +247,7 @@ unsigned char* ReadZip(const char* filename, continue; } - unsigned char* lh = &img[hoffset]; + unsigned char* lh = img + hoffset; if (!(lh[0] == 0x50 && lh[1] == 0x4b && lh[2] == 0x03 && lh[3] == 0x04)) { printf("bad local file header entry %d\n", i); @@ -263,7 +268,7 @@ unsigned char* ReadZip(const char* filename, ++entrycount; } - std::sort(temp_entries.begin(), temp_entries.end(), fileentry_compare); + qsort(temp_entries, entrycount, sizeof(ZipFileEntry), fileentry_compare); #if 0 printf("found %d deflated entries\n", entrycount); @@ -285,7 +290,7 @@ unsigned char* ReadZip(const char* filename, curr->type = CHUNK_NORMAL; curr->start = 0; curr->len = st.st_size; - curr->data = img.get(); + curr->data = img; curr->filename = NULL; ++curr; ++*num_chunks; @@ -299,7 +304,7 @@ unsigned char* ReadZip(const char* filename, curr->type = CHUNK_DEFLATE; curr->start = pos; curr->deflate_len = temp_entries[nextentry].deflate_len; - curr->deflate_data = &img[pos]; + curr->deflate_data = img + pos; curr->filename = temp_entries[nextentry].filename; curr->len = temp_entries[nextentry].uncomp_len; @@ -343,7 +348,7 @@ unsigned char* ReadZip(const char* filename, } else { curr->len = st.st_size - pos; } - curr->data = &img[pos]; + curr->data = img + pos; curr->filename = NULL; pos += curr->len; @@ -351,7 +356,8 @@ unsigned char* ReadZip(const char* filename, ++curr; } - return img.release(); + free(temp_entries); + return img; } /* @@ -372,9 +378,9 @@ unsigned char* ReadImage(const char* filename, } size_t sz = static_cast(st.st_size); - std::unique_ptr img(new unsigned char[sz+4]); + unsigned char* img = reinterpret_cast(malloc(sz + 4)); FILE* f = fopen(filename, "rb"); - if (fread(img.get(), 1, sz, f) != sz) { + if (fread(img, 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); fclose(f); return NULL; @@ -384,7 +390,7 @@ unsigned char* ReadImage(const char* filename, // 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); + memset(img+sz, 0, 4); size_t pos = 0; @@ -392,7 +398,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 && @@ -475,7 +481,7 @@ unsigned char* ReadImage(const char* filename, curr->type = CHUNK_NORMAL; curr->start = pos; curr->len = GZIP_FOOTER_LEN; - curr->data = &img[pos]; + curr->data = img+pos; pos += curr->len; p += curr->len; @@ -489,6 +495,7 @@ unsigned char* ReadImage(const char* filename, if (footer_size != curr[-2].len) { printf("Error: footer size %zu != decompressed size %zu\n", footer_size, curr[-2].len); + free(img); return NULL; } } else { @@ -516,7 +523,7 @@ unsigned char* ReadImage(const char* filename, } } - return img.release(); + return img; } #define BUFFER_SIZE 32768 @@ -638,7 +645,8 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { } size_t sz = static_cast(st.st_size); - std::unique_ptr data(new unsigned char[sz]); + // TODO: Memory leak on error return. + unsigned char* data = reinterpret_cast(malloc(sz)); if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) { unlink(ptemp); @@ -655,9 +663,8 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { printf("failed to open patch %s: %s\n", ptemp, strerror(errno)); return NULL; } - if (fread(data.get(), 1, sz, f) != sz) { + if (fread(data, 1, sz, f) != sz) { printf("failed to read patch %s: %s\n", ptemp, strerror(errno)); - fclose(f); return NULL; } fclose(f); @@ -675,7 +682,7 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { break; } - return data.release(); + return data; } /* @@ -798,7 +805,7 @@ int main(int argc, char** argv) { } size_t bonus_size = 0; - std::vector bonus_data; + unsigned char* bonus_data = NULL; if (argc >= 3 && strcmp(argv[1], "-b") == 0) { struct stat st; if (stat(argv[2], &st) != 0) { @@ -806,15 +813,14 @@ int main(int argc, char** argv) { return 1; } bonus_size = st.st_size; - bonus_data.resize(bonus_size); + bonus_data = reinterpret_cast(malloc(bonus_size)); FILE* f = fopen(argv[2], "rb"); if (f == NULL) { printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno)); return 1; } - if (fread(bonus_data.data(), 1, bonus_size, f) != bonus_size) { + if (fread(bonus_data, 1, bonus_size, f) != bonus_size) { printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno)); - fclose(f); return 1; } fclose(f); @@ -967,11 +973,11 @@ int main(int argc, char** argv) { patch_data[i] = MakePatch(src_chunks, tgt_chunks+i, patch_size+i); } } else { - if (i == 1 && !bonus_data.empty()) { + if (i == 1 && bonus_data) { printf(" using %zu bytes of bonus data for chunk %d\n", bonus_size, i); src_chunks[i].data = reinterpret_cast(realloc(src_chunks[i].data, src_chunks[i].len + bonus_size)); - memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data.data(), bonus_size); + memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size); src_chunks[i].len += bonus_size; } @@ -1057,10 +1063,6 @@ int main(int argc, char** argv) { } fclose(f); - for (i = 0; i < num_tgt_chunks; ++i) { - free(patch_data[i]); - } - free(patch_data); return 0; } -- cgit v1.2.3 From 63a319201fc0f5c34c1c62b446527e06f57f8d40 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 9 Jun 2016 17:41:22 -0700 Subject: Remove obsolete MTD support. Bug: http://b/29250988 Change-Id: Ia97ba9082a165c37f74d6e1c3f71a367adc59945 --- applypatch/Android.mk | 2 - applypatch/applypatch.cpp | 308 +++++++++++++++------------------------------- applypatch/main.cpp | 8 +- 3 files changed, 105 insertions(+), 213 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index a15ac0280..48efe340e 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -32,7 +32,6 @@ LOCAL_C_INCLUDES += \ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += \ libotafault \ - libmtdutils \ libbase \ libcrypto_static \ libbz \ @@ -79,7 +78,6 @@ LOCAL_STATIC_LIBRARIES += \ libedify \ libotafault \ libminzip \ - libmtdutils \ libcrypto_static \ libbz LOCAL_SHARED_LIBRARIES += libz libcutils libc diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 270fde5c4..02a3c6e41 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -32,7 +32,6 @@ #include "openssl/sha.h" #include "applypatch/applypatch.h" -#include "mtdutils/mtdutils.h" #include "edify/expr.h" #include "ota_io.h" #include "print_sha1.h" @@ -49,17 +48,14 @@ static int GenerateTarget(FileContents* source_file, size_t target_size, const Value* bonus_data); -static bool mtd_partitions_scanned = false; - // Read a file into memory; store the file contents and associated // metadata in *file. // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - // A special 'filename' beginning with "MTD:" or "EMMC:" means to + // A special 'filename' beginning with "EMMC:" means to // load the contents of a partition. - if (strncmp(filename, "MTD:", 4) == 0 || - strncmp(filename, "EMMC:", 5) == 0) { + if (strncmp(filename, "EMMC:", 5) == 0) { return LoadPartitionContents(filename, file); } @@ -87,10 +83,9 @@ int LoadFileContents(const char* filename, FileContents* file) { return 0; } -// Load the contents of an MTD or EMMC partition into the provided +// Load the contents of an EMMC partition into the provided // FileContents. filename should be a string of the form -// "MTD::::::..." (or -// "EMMC::..."). The smallest size_n bytes for +// "EMMC::...". The smallest size_n bytes for // which that prefix of the partition contents has the corresponding // sha1 hash will be loaded. It is acceptable for a size value to be // repeated with different sha1s. Will return 0 on success. @@ -102,8 +97,6 @@ int LoadFileContents(const char* filename, FileContents* file) { // "end-of-file" marker), so the caller must specify the possible // lengths and the hash of the data, and we'll do the load expecting // to find one of those hashes. -enum PartitionType { MTD, EMMC }; - static int LoadPartitionContents(const char* filename, FileContents* file) { std::string copy(filename); std::vector pieces = android::base::Split(copy, ":"); @@ -112,12 +105,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { return -1; } - enum PartitionType type; - if (pieces[0] == "MTD") { - type = MTD; - } else if (pieces[0] == "EMMC") { - type = EMMC; - } else { + if (pieces[0] != "EMMC") { printf("LoadPartitionContents called with bad filename (%s)\n", filename); return -1; } @@ -145,36 +133,10 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } ); - MtdReadContext* ctx = NULL; - FILE* dev = NULL; - - switch (type) { - case MTD: { - if (!mtd_partitions_scanned) { - mtd_scan_partitions(); - mtd_partitions_scanned = true; - } - - const MtdPartition* mtd = mtd_find_partition_by_name(partition); - if (mtd == NULL) { - printf("mtd partition \"%s\" not found (loading %s)\n", partition, filename); - return -1; - } - - ctx = mtd_read_partition(mtd); - if (ctx == NULL) { - printf("failed to initialize read of mtd partition \"%s\"\n", partition); - return -1; - } - break; - } - - case EMMC: - dev = ota_fopen(partition, "rb"); - if (dev == NULL) { - printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); - return -1; - } + FILE* dev = ota_fopen(partition, "rb"); + if (dev == NULL) { + printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); + return -1; } SHA_CTX sha_ctx; @@ -192,16 +154,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { // we're trying the possibilities in order of increasing size). size_t next = size[index[i]] - data_size; if (next > 0) { - size_t read = 0; - switch (type) { - case MTD: - read = mtd_read_data(ctx, p, next); - break; - - case EMMC: - read = ota_fread(p, 1, next, dev); - break; - } + size_t read = ota_fread(p, 1, next, dev); if (next != read) { printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); @@ -234,16 +187,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) { } } - switch (type) { - case MTD: - mtd_read_close(ctx); - break; - - case EMMC: - ota_fclose(dev); - break; - } - + ota_fclose(dev); if (!found) { // Ran off the end of the list of (size,sha1) pairs without finding a match. @@ -302,7 +246,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { } // Write a memory buffer to 'target' partition, a string of the form -// "MTD:[:...]" or "EMMC:[:...]". The target name +// "EMMC:[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(const unsigned char* data, size_t len, const char* target) { @@ -314,165 +258,117 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - enum PartitionType type; - if (pieces[0] == "MTD") { - type = MTD; - } else if (pieces[0] == "EMMC") { - type = EMMC; - } else { + if (pieces[0] != "EMMC") { printf("WriteToPartition called with bad target (%s)\n", target); return -1; } const char* partition = pieces[1].c_str(); - switch (type) { - case MTD: { - if (!mtd_partitions_scanned) { - mtd_scan_partitions(); - mtd_partitions_scanned = true; - } - - const MtdPartition* mtd = mtd_find_partition_by_name(partition); - if (mtd == NULL) { - printf("mtd partition \"%s\" not found for writing\n", partition); - return -1; - } - - MtdWriteContext* ctx = mtd_write_partition(mtd); - if (ctx == NULL) { - printf("failed to init mtd partition \"%s\" for writing\n", partition); - return -1; - } + size_t start = 0; + bool success = false; + int fd = ota_open(partition, O_RDWR | O_SYNC); + if (fd < 0) { + printf("failed to open %s: %s\n", partition, strerror(errno)); + return -1; + } - size_t written = mtd_write_data(ctx, reinterpret_cast(data), len); - if (written != len) { - printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); - mtd_write_close(ctx); - return -1; - } + for (size_t attempt = 0; attempt < 2; ++attempt) { + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { + printf("failed seek on %s: %s\n", partition, strerror(errno)); + return -1; + } + while (start < len) { + size_t to_write = len - start; + if (to_write > 1<<20) to_write = 1<<20; - if (mtd_erase_blocks(ctx, -1) < 0) { - printf("error finishing mtd write of %s\n", partition); - mtd_write_close(ctx); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); + if (written == -1) { + printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; } + start += written; + } + if (ota_fsync(fd) != 0) { + printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + return -1; + } + if (ota_close(fd) != 0) { + printf("failed to close %s (%s)\n", partition, strerror(errno)); + return -1; + } + fd = ota_open(partition, O_RDONLY); + if (fd < 0) { + printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + return -1; + } - if (mtd_write_close(ctx)) { - printf("error closing mtd write of %s\n", partition); - return -1; - } - break; + // Drop caches so our subsequent verification read + // won't just be reading the cache. + sync(); + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { + printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + } else { + printf(" caches dropped\n"); } + ota_close(dc); + sleep(1); - case EMMC: { - size_t start = 0; - bool success = false; - int fd = ota_open(partition, O_RDWR | O_SYNC); - if (fd < 0) { - printf("failed to open %s: %s\n", partition, strerror(errno)); - return -1; + // verify + if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { + printf("failed to seek back to beginning of %s: %s\n", + partition, strerror(errno)); + return -1; + } + unsigned char buffer[4096]; + start = len; + for (size_t p = 0; p < len; p += sizeof(buffer)) { + size_t to_read = len - p; + if (to_read > sizeof(buffer)) { + to_read = sizeof(buffer); } - for (size_t attempt = 0; attempt < 2; ++attempt) { - if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { - printf("failed seek on %s: %s\n", partition, strerror(errno)); + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = + TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); + if (read_count == -1) { + printf("verify read error %s at %zu: %s\n", + partition, p, strerror(errno)); return -1; } - while (start < len) { - size_t to_write = len - start; - if (to_write > 1<<20) to_write = 1<<20; - - ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); - if (written == -1) { - printf("failed write writing to %s: %s\n", partition, strerror(errno)); - return -1; - } - start += written; - } - if (ota_fsync(fd) != 0) { - printf("failed to sync to %s (%s)\n", partition, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("failed to close %s (%s)\n", partition, strerror(errno)); - return -1; - } - fd = ota_open(partition, O_RDONLY); - if (fd < 0) { - printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); - return -1; - } - - // Drop caches so our subsequent verification read - // won't just be reading the cache. - sync(); - int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { - printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); - } else { - printf(" caches dropped\n"); - } - ota_close(dc); - sleep(1); - - // verify - if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { - printf("failed to seek back to beginning of %s: %s\n", - partition, strerror(errno)); - return -1; - } - unsigned char buffer[4096]; - start = len; - for (size_t p = 0; p < len; p += sizeof(buffer)) { - size_t to_read = len - p; - if (to_read > sizeof(buffer)) { - to_read = sizeof(buffer); - } - - size_t so_far = 0; - while (so_far < to_read) { - ssize_t read_count = - TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); - if (read_count == -1) { - printf("verify read error %s at %zu: %s\n", - partition, p, strerror(errno)); - return -1; - } - if (static_cast(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu %s\n", - partition, p, read_count, to_read, strerror(errno)); - } - so_far += read_count; - } - - if (memcmp(buffer, data+p, to_read) != 0) { - printf("verification failed starting at %zu\n", p); - start = p; - break; - } - } - - if (start == len) { - printf("verification read succeeded (attempt %zu)\n", attempt+1); - success = true; - break; + if (static_cast(read_count) < to_read) { + printf("short verify read %s at %zu: %zd %zu %s\n", + partition, p, read_count, to_read, strerror(errno)); } + so_far += read_count; } - if (!success) { - printf("failed to verify after all attempts\n"); - return -1; + if (memcmp(buffer, data+p, to_read) != 0) { + printf("verification failed starting at %zu\n", p); + start = p; + break; } + } - if (ota_close(fd) != 0) { - printf("error closing %s (%s)\n", partition, strerror(errno)); - return -1; - } - sync(); + if (start == len) { + printf("verification read succeeded (attempt %zu)\n", attempt+1); + success = true; break; } } + if (!success) { + printf("failed to verify after all attempts\n"); + return -1; + } + + if (ota_close(fd) != 0) { + printf("error closing %s (%s)\n", partition, strerror(errno)); + return -1; + } + sync(); + return 0; } @@ -729,7 +625,7 @@ int applypatch_flash(const char* source_filename, const char* target_filename, std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); - if (pieces.size() != 2 || (pieces[0] != "MTD" && pieces[0] != "EMMC")) { + if (pieces.size() != 2 || pieces[0] != "EMMC") { printf("invalid target name \"%s\"", target_filename); return 1; } @@ -778,8 +674,7 @@ static int GenerateTarget(FileContents* source_file, FileContents* source_to_use; int made_copy = 0; - bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 || - strncmp(target_filename, "EMMC:", 5) == 0); + bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); const std::string tmp_target_filename = std::string(target_filename) + ".patch"; // assume that target_filename (eg "/system/app/Foo.apk") is located @@ -860,8 +755,7 @@ static int GenerateTarget(FileContents* source_file, // copy the source file to cache, then delete it from the original // location. - if (strncmp(source_filename, "MTD:", 4) == 0 || - strncmp(source_filename, "EMMC:", 5) == 0) { + if (strncmp(source_filename, "EMMC:", 5) == 0) { // It's impossible to free space on the target filesystem by // deleting the source if the source is a partition. If // we're ever in a state where we need to do this, fail. diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 0ff8cbf9a..1968ae48f 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -160,9 +160,9 @@ static int PatchMode(int argc, char** argv) { // - otherwise, or if any error is encountered, exits with non-zero // status. // -// (or in check mode) may refer to an MTD partition +// (or in check mode) may refer to an EMMC partition // to read the source data. See the comments for the -// LoadMTDContents() function above for the format of such a filename. +// LoadPartitionContents() function for the format of such a filename. int main(int argc, char** argv) { if (argc < 2) { @@ -175,8 +175,8 @@ int main(int argc, char** argv) { " or %s -l\n" "\n" "Filenames may be of the form\n" - " MTD::::::...\n" - "to specify reading from or writing to an MTD partition.\n\n", + " EMMC::::::...\n" + "to specify reading from or writing to an EMMC partition.\n\n", argv[0], argv[0], argv[0], argv[0]); return 2; } -- cgit v1.2.3 From 073164f24b212685c181c8620f0397d13e9d79c0 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 5 Aug 2016 15:59:05 -0700 Subject: Fix references to libcrypto_utils_static. Bug: http://b/30708454 Change-Id: I7a5048beff1d8b783a9683dcb4a79606a77f20ee --- applypatch/Android.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 48efe340e..604787e78 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -33,7 +33,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += \ libotafault \ libbase \ - libcrypto_static \ + libcrypto \ libbz \ libz include $(BUILD_STATIC_LIBRARY) @@ -48,7 +48,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz +LOCAL_STATIC_LIBRARIES += libcrypto libbz libz include $(BUILD_STATIC_LIBRARY) # libimgpatch (host static library) @@ -62,7 +62,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include -LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz +LOCAL_STATIC_LIBRARIES += libcrypto libbz libz include $(BUILD_HOST_STATIC_LIBRARY) # applypatch (executable) @@ -78,7 +78,7 @@ LOCAL_STATIC_LIBRARIES += \ libedify \ libotafault \ libminzip \ - libcrypto_static \ + libcrypto \ libbz LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) -- cgit v1.2.3 From 71e182bc3879a53f04a50de9d25c333163cb7c76 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 31 Aug 2016 18:06:33 -0700 Subject: Check an edge case when read(2) returns 0 We might end up in an infinite loop if read(2) reached EOF unexpectedly. The problematic code in uncrypt mentioned in the bug has been fixed by switching to libbase ReadFully(). So I grepped through the recovery code and fixed some other occurences of the issue. Bug: 31073201 Change-Id: Ib867029158ba23363b8f85d61c25058a635c5a6b --- applypatch/applypatch.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 02a3c6e41..e52ef99dc 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -336,6 +336,9 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); return -1; + } else if (read_count == 0) { + printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); + return -1; } if (static_cast(read_count) < to_read) { printf("short verify read %s at %zu: %zd %zu %s\n", -- cgit v1.2.3 From 7b0ad9c638176dc364dabb65b363536055a0ea9c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 5 Aug 2016 18:00:04 -0700 Subject: Switch recovery to libbase logging Clean up the recovery image and switch to libbase logging. Bug: 28191554 Change-Id: Icd999c3cc832f0639f204b5c36cea8afe303ad35 Merged-In: Icd999c3cc832f0639f204b5c36cea8afe303ad35 --- applypatch/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 604787e78..0fc6e3682 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -80,7 +80,7 @@ LOCAL_STATIC_LIBRARIES += \ libminzip \ libcrypto \ libbz -LOCAL_SHARED_LIBRARIES += libz libcutils libc +LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc include $(BUILD_EXECUTABLE) # imgdiff (host static executable) -- cgit v1.2.3 From 7aa88748f6ec4e53333d1a15747bc44826ccc410 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 28 Sep 2016 11:42:17 -0700 Subject: Turn on -Werror for recovery Also remove the 0xff comparison when validating the bootloader message fields. As the fields won't be erased to 0xff after we remove the MTD support. Bug: 28202046 Test: The recovery folder compiles for aosp_x86-eng Change-Id: Ibb30ea1b2b28676fb08c7e92a1e5f7b6ef3247ab --- applypatch/Android.mk | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 0fc6e3682..77e499ec6 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -36,6 +36,7 @@ LOCAL_STATIC_LIBRARIES += \ libcrypto \ libbz \ libz +LOCAL_CFLAGS := -Werror include $(BUILD_STATIC_LIBRARY) # libimgpatch (static library) @@ -49,6 +50,7 @@ LOCAL_C_INCLUDES += \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += libcrypto libbz libz +LOCAL_CFLAGS := -Werror include $(BUILD_STATIC_LIBRARY) # libimgpatch (host static library) @@ -63,6 +65,7 @@ LOCAL_C_INCLUDES += \ bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES += libcrypto libbz libz +LOCAL_CFLAGS := -Werror include $(BUILD_HOST_STATIC_LIBRARY) # applypatch (executable) @@ -81,6 +84,7 @@ LOCAL_STATIC_LIBRARIES += \ libcrypto \ libbz LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc +LOCAL_CFLAGS := -Werror include $(BUILD_EXECUTABLE) # imgdiff (host static executable) @@ -95,5 +99,6 @@ LOCAL_STATIC_LIBRARIES += \ libdivsufsort64 \ libdivsufsort \ libz +LOCAL_CFLAGS := -Werror LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE) -- cgit v1.2.3 From aced5d9e4e438ba478ce54f9217166b8ab7cc24f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 12 Oct 2016 10:55:04 -0700 Subject: Change StringValue to use std::string Changing the field of 'Value' in edify to std::string from char*. Meanwhile cleaning up the users of 'Value' and switching them to cpp style. Test: compontent tests passed. Bug: 31713288 Change-Id: Iec5a7d601b1e4ca40935bf1c70d325dafecec235 --- applypatch/applypatch.cpp | 28 ++++++++----------- applypatch/bspatch.cpp | 12 ++++---- applypatch/imgpatch.cpp | 44 +++++++++++++++--------------- applypatch/include/applypatch/applypatch.h | 10 +++---- applypatch/main.cpp | 42 ++++++++++++++-------------- applypatch/utils.cpp | 12 ++++---- applypatch/utils.h | 6 ++-- 7 files changed, 75 insertions(+), 79 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index e52ef99dc..cf155607b 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -408,11 +408,10 @@ 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, char* const * const patch_sha1_str, - int num_patches) { - uint8_t patch_sha1[SHA_DIGEST_LENGTH]; - for (int i = 0; i < num_patches; ++i) { - if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 && +int FindMatchingPatch(uint8_t* sha1, const std::vector& 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 && memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { return i; } @@ -423,8 +422,7 @@ int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, // Returns 0 if the contents of the file (argv[2]) or the cached file // match any of the sha1's on the command line (argv[3:]). Returns // nonzero otherwise. -int applypatch_check(const char* filename, int num_patches, - char** const patch_sha1_str) { +int applypatch_check(const char* filename, const std::vector& patch_sha1_str) { FileContents file; // It's okay to specify no sha1s; the check will pass if the @@ -432,8 +430,7 @@ int applypatch_check(const char* filename, int num_patches, // partitions, where the filename encodes the sha1s; no need to // check them twice.) if (LoadFileContents(filename, &file) != 0 || - (num_patches > 0 && - FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) { + FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); @@ -448,7 +445,7 @@ int applypatch_check(const char* filename, int num_patches, return 1; } - if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) { + if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { printf("cache bits don't match any sha1 for \"%s\"\n", filename); return 1; } @@ -532,8 +529,7 @@ int applypatch(const char* source_filename, const char* target_filename, const char* target_sha1_str, size_t target_size, - int num_patches, - char** const patch_sha1_str, + const std::vector& patch_sha1_str, Value** patch_data, Value* bonus_data) { printf("patch %s: ", source_filename); @@ -573,7 +569,7 @@ int applypatch(const char* source_filename, } if (!source_file.data.empty()) { - int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches); + int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); if (to_use >= 0) { source_patch_value = patch_data[to_use]; } @@ -589,7 +585,7 @@ int applypatch(const char* source_filename, return 1; } - int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str, num_patches); + int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); if (to_use >= 0) { copy_patch_value = patch_data[to_use]; } @@ -701,8 +697,8 @@ static int GenerateTarget(FileContents* source_file, printf("patch is not a blob\n"); return 1; } - char* header = patch->data; - ssize_t header_bytes_read = patch->size; + const char* header = &patch->data[0]; + size_t header_bytes_read = patch->data.size(); bool use_bsdiff = false; if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { use_bsdiff = true; diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index a4945da28..eb45e9ce9 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -64,7 +64,7 @@ void ShowBSDiffLicense() { ); } -static off_t offtin(u_char *buf) +static off_t offtin(const u_char *buf) { off_t y; @@ -130,7 +130,7 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, // from oldfile to x bytes from the diff block; copy y bytes from the // extra block; seek forwards in oldfile by z bytes". - unsigned char* header = (unsigned char*) patch->data + patch_offset; + const unsigned char* header = reinterpret_cast(&patch->data[patch_offset]); if (memcmp(header, "BSDIFF40", 8) != 0) { printf("corrupt bsdiff patch file header (magic number)\n"); return 1; @@ -149,7 +149,7 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, int bzerr; bz_stream cstream; - cstream.next_in = patch->data + patch_offset + 32; + cstream.next_in = const_cast(&patch->data[patch_offset + 32]); cstream.avail_in = ctrl_len; cstream.bzalloc = NULL; cstream.bzfree = NULL; @@ -159,7 +159,7 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, } bz_stream dstream; - dstream.next_in = patch->data + patch_offset + 32 + ctrl_len; + dstream.next_in = const_cast(&patch->data[patch_offset + 32 + ctrl_len]); dstream.avail_in = data_len; dstream.bzalloc = NULL; dstream.bzfree = NULL; @@ -169,8 +169,8 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, } bz_stream estream; - estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len; - estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len); + estream.next_in = const_cast(&patch->data[patch_offset + 32 + ctrl_len + data_len]); + estream.avail_in = patch->data.size() - (patch_offset + 32 + ctrl_len + data_len); estream.bzalloc = NULL; estream.bzfree = NULL; estream.opaque = NULL; diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 0c06d6b1e..1c4409e36 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "zlib.h" @@ -35,10 +36,10 @@ 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, patch_size, - reinterpret_cast(const_cast(patch_data))}; - return ApplyImagePatch( - old_data, old_size, &patch, sink, token, nullptr, nullptr); + Value patch(VAL_BLOB, std::string( + reinterpret_cast(patch_data), patch_size)); + + return ApplyImagePatch(old_data, old_size, &patch, sink, token, nullptr, nullptr); } /* @@ -51,9 +52,7 @@ 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) { - ssize_t pos = 12; - char* header = patch->data; - if (patch->size < 12) { + if (patch->data.size() < 12) { printf("patch too short to contain header\n"); return -1; } @@ -61,6 +60,8 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, // 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; @@ -68,20 +69,19 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, int num_chunks = Read4(header+8); - int i; - for (i = 0; i < num_chunks; ++i) { + for (int i = 0; i < num_chunks; ++i) { // each chunk's header record starts with 4 bytes. - if (pos + 4 > patch->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->data[pos]); pos += 4; if (type == CHUNK_NORMAL) { - char* normal_header = patch->data + pos; + const char* normal_header = &patch->data[pos]; pos += 24; - if (pos > patch->size) { + if (pos > patch->data.size()) { printf("failed to read chunk %d normal header data\n", i); return -1; } @@ -97,21 +97,21 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, token, ctx); } else if (type == CHUNK_RAW) { - char* raw_header = patch->data + pos; + const char* raw_header = &patch->data[pos]; pos += 4; - if (pos > patch->size) { + 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->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((unsigned char*)patch->data + pos, + if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len); + if (sink(reinterpret_cast(&patch->data[pos]), data_len, token) != data_len) { printf("failed to write chunk %d raw data\n", i); return -1; @@ -119,9 +119,9 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, pos += data_len; } else if (type == CHUNK_DEFLATE) { // deflate chunks have an additional 60 bytes in their chunk header. - char* deflate_header = patch->data + pos; + const char* deflate_header = &patch->data[pos]; pos += 60; - if (pos > patch->size) { + if (pos > patch->data.size()) { printf("failed to read chunk %d deflate header data\n", i); return -1; } @@ -149,7 +149,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, // 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->size : 0; + size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->data.size() : 0; std::vector expanded_source(expanded_len); @@ -189,7 +189,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, if (bonus_size) { memcpy(expanded_source.data() + (expanded_len - bonus_size), - bonus_data->data, bonus_size); + &bonus_data->data[0], bonus_size); } } diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h index 9ee39d293..80d681638 100644 --- a/applypatch/include/applypatch/applypatch.h +++ b/applypatch/include/applypatch/applypatch.h @@ -20,6 +20,7 @@ #include #include +#include #include #include "openssl/sha.h" @@ -52,19 +53,16 @@ int applypatch(const char* source_filename, const char* target_filename, const char* target_sha1_str, size_t target_size, - int num_patches, - char** const patch_sha1_str, + const std::vector& patch_sha1_str, Value** patch_data, Value* bonus_data); int applypatch_check(const char* filename, - int num_patches, - char** const patch_sha1_str); + const std::vector& patch_sha1_str); int LoadFileContents(const char* filename, FileContents* file); int SaveFileContents(const char* filename, const FileContents* file); void FreeFileContents(FileContents* file); -int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, - int num_patches); +int FindMatchingPatch(uint8_t* sha1, const std::vector& patch_sha1_str); // bsdiff.cpp void ShowBSDiffLicense(); diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 1968ae48f..a3a45d06f 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "applypatch/applypatch.h" @@ -30,7 +31,12 @@ static int CheckMode(int argc, char** argv) { if (argc < 3) { return 2; } - return applypatch_check(argv[2], argc-3, argv+3); + std::vector sha1; + for (int i = 3; i < argc; i++) { + sha1.push_back(argv[i]); + } + + return applypatch_check(argv[2], sha1); } static int SpaceMode(int argc, char** argv) { @@ -49,11 +55,13 @@ static int SpaceMode(int argc, char** argv) { // Parse arguments (which should be of the form ":" // into the new parallel arrays *sha1s and *files.Returns true on // success. -static bool ParsePatchArgs(int argc, char** argv, std::vector* sha1s, +static bool ParsePatchArgs(int argc, char** argv, std::vector* sha1s, std::vector* files) { - uint8_t digest[SHA_DIGEST_LENGTH]; - + if (sha1s == nullptr) { + return false; + } for (int i = 0; i < argc; ++i) { + uint8_t digest[SHA_DIGEST_LENGTH]; char* colon = strchr(argv[i], ':'); if (colon == nullptr) { printf("no ':' in patch argument \"%s\"\n", argv[i]); @@ -83,18 +91,15 @@ static int FlashMode(const char* src_filename, const char* tgt_filename, static int PatchMode(int argc, char** argv) { FileContents bonusFc; - Value bonusValue; - Value* bonus = nullptr; + Value bonus(VAL_INVALID, ""); if (argc >= 3 && strcmp(argv[1], "-b") == 0) { if (LoadFileContents(argv[2], &bonusFc) != 0) { printf("failed to load bonus file %s\n", argv[2]); return 1; } - bonus = &bonusValue; - bonus->type = VAL_BLOB; - bonus->size = bonusFc.data.size(); - bonus->data = reinterpret_cast(bonusFc.data.data()); + bonus.type = VAL_BLOB; + bonus.data = reinterpret_cast(bonusFc.data.data()); argc -= 2; argv += 2; } @@ -112,29 +117,26 @@ static int PatchMode(int argc, char** argv) { // If no : is provided, it is in flash mode. if (argc == 5) { - if (bonus != nullptr) { + if (bonus.type != VAL_INVALID) { printf("bonus file not supported in flash mode\n"); return 1; } return FlashMode(argv[1], argv[2], argv[3], target_size); } - std::vector sha1s; + std::vector sha1s; std::vector files; if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { printf("failed to parse patch args\n"); return 1; } - std::vector patches(files.size()); - std::vector patch_ptrs(files.size()); + std::vector patches; + std::vector patch_ptrs; for (size_t i = 0; i < files.size(); ++i) { - patches[i].type = VAL_BLOB; - patches[i].size = files[i].data.size(); - patches[i].data = reinterpret_cast(files[i].data.data()); - patch_ptrs[i] = &patches[i]; + patches.push_back(Value(VAL_BLOB, reinterpret_cast(files[i].data.data()))); + patch_ptrs.push_back(&patches[i]); } return applypatch(argv[1], argv[2], argv[3], target_size, - patch_ptrs.size(), sha1s.data(), - patch_ptrs.data(), bonus); + sha1s, patch_ptrs.data(), &bonus); } // This program applies binary patches to files in a way that is safe diff --git a/applypatch/utils.cpp b/applypatch/utils.cpp index fef250f01..450dc8d76 100644 --- a/applypatch/utils.cpp +++ b/applypatch/utils.cpp @@ -38,22 +38,22 @@ void Write8(int64_t value, FILE* f) { fputc((value >> 56) & 0xff, f); } -int Read2(void* pv) { - unsigned char* p = reinterpret_cast(pv); +int Read2(const void* pv) { + const unsigned char* p = reinterpret_cast(pv); return (int)(((unsigned int)p[1] << 8) | (unsigned int)p[0]); } -int Read4(void* pv) { - unsigned char* p = reinterpret_cast(pv); +int Read4(const void* pv) { + const unsigned char* p = reinterpret_cast(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(void* pv) { - unsigned char* p = reinterpret_cast(pv); +int64_t Read8(const void* pv) { + const unsigned char* p = reinterpret_cast(pv); return (int64_t)(((uint64_t)p[7] << 56) | ((uint64_t)p[6] << 48) | ((uint64_t)p[5] << 40) | diff --git a/applypatch/utils.h b/applypatch/utils.h index 1c34edd97..c7c8e90e2 100644 --- a/applypatch/utils.h +++ b/applypatch/utils.h @@ -24,8 +24,8 @@ void Write4(int value, FILE* f); void Write8(int64_t value, FILE* f); -int Read2(void* p); -int Read4(void* p); -int64_t Read8(void* p); +int Read2(const void* p); +int Read4(const void* p); +int64_t Read8(const void* p); #endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H -- cgit v1.2.3 From 8cf5c8f60f51049278b08ae4cbc31df397b651fd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 8 Sep 2016 20:10:11 -0700 Subject: Replace minzip with libziparchive Clean up the duplicated codes that handle the zip files in bootable/recovery; and rename the library of the remaining utility functions to libotautil. Test: Update package installed successfully on angler. Bug: 19472796 Change-Id: Iea8962fcf3004473cb0322b6bb3a9ea3ca7f679e --- applypatch/Android.mk | 1 - 1 file changed, 1 deletion(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 77e499ec6..9bbac4410 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -80,7 +80,6 @@ LOCAL_STATIC_LIBRARIES += \ libbase \ libedify \ libotafault \ - libminzip \ libcrypto \ libbz LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc -- cgit v1.2.3 From 984d7d058e65ddc1b8a1ffc79a5f178ad88dd596 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 18 Oct 2016 13:37:18 -0700 Subject: Fix applypatch_check failure when applying update on angler Applypatch_check should be skipped if no sha is specified. As the comments said: "It's okay to specify no sha1s; the check will pass if the LoadFileContents is successful. Useful for reading partitions, where the filename encodes the sha1s." Test: The update package applied on angler successfully. Bug: 32243751 Change-Id: Ib8f3dadf19f745c2dbd350d60da46ab12d75bc87 --- applypatch/applypatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index cf155607b..48e4c8386 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -430,7 +430,7 @@ int applypatch_check(const char* filename, const std::vector& patch // partitions, where the filename encodes the sha1s; no need to // check them twice.) if (LoadFileContents(filename, &file) != 0 || - FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { + (patch_sha1_str.size() > 0 && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) { printf("file \"%s\" doesn't have any of expected " "sha1 sums; checking cache\n", filename); -- cgit v1.2.3 From edf1b15fefca1fa43d628a9c79d351dd960a002f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 24 Oct 2016 16:08:28 -0700 Subject: applypatch: Fix the bug when constructing VAL_BLOB. When constructing std::string from C-string, the string may be truncated at null char. Use range constructor instead. Bug: 32380016 Test: Use applypatch to install a previously failed recovery image. Change-Id: Id3e2afb4a810594243cd21db526933d1fea5044b --- applypatch/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'applypatch') diff --git a/applypatch/main.cpp b/applypatch/main.cpp index a3a45d06f..294f7ee21 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -99,7 +99,7 @@ static int PatchMode(int argc, char** argv) { return 1; } bonus.type = VAL_BLOB; - bonus.data = reinterpret_cast(bonusFc.data.data()); + bonus.data = std::string(bonusFc.data.cbegin(), bonusFc.data.cend()); argc -= 2; argv += 2; } @@ -132,7 +132,8 @@ static int PatchMode(int argc, char** argv) { std::vector patches; std::vector patch_ptrs; for (size_t i = 0; i < files.size(); ++i) { - patches.push_back(Value(VAL_BLOB, reinterpret_cast(files[i].data.data()))); + patches.push_back(Value(VAL_BLOB, + std::string(files[i].data.cbegin(), files[i].data.cend()))); patch_ptrs.push_back(&patches[i]); } return applypatch(argv[1], argv[2], argv[3], target_size, -- cgit v1.2.3 From fada91ccf2b31d69d72899388b1833186d763d1a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 27 Oct 2016 18:16:06 -0700 Subject: applypatch: Switch the parameter of Value** to std::vector. Test: Unit tests and install-recovery.sh pass on angler and dragon. Change-Id: I328e6554edca667cf850f5584ebf1ac211e3d4d1 --- applypatch/applypatch.cpp | 16 ++++++++-------- applypatch/include/applypatch/applypatch.h | 15 ++++++++------- applypatch/main.cpp | 15 +++++++-------- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 48e4c8386..9d505f9f6 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -530,8 +530,8 @@ int applypatch(const char* source_filename, const char* target_sha1_str, size_t target_size, const std::vector& patch_sha1_str, - Value** patch_data, - Value* bonus_data) { + const std::vector>& patch_data, + const Value* bonus_data) { printf("patch %s: ", source_filename); if (target_filename[0] == '-' && target_filename[1] == '\0') { @@ -546,8 +546,8 @@ int applypatch(const char* source_filename, FileContents copy_file; FileContents source_file; - const Value* source_patch_value = NULL; - const Value* copy_patch_value = NULL; + const Value* source_patch_value = nullptr; + const Value* copy_patch_value = nullptr; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file) == 0) { @@ -571,11 +571,11 @@ int applypatch(const char* source_filename, if (!source_file.data.empty()) { int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); if (to_use >= 0) { - source_patch_value = patch_data[to_use]; + source_patch_value = patch_data[to_use].get(); } } - if (source_patch_value == NULL) { + if (source_patch_value == nullptr) { source_file.data.clear(); printf("source file is bad; trying copy\n"); @@ -587,10 +587,10 @@ int applypatch(const char* source_filename, int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); if (to_use >= 0) { - copy_patch_value = patch_data[to_use]; + copy_patch_value = patch_data[to_use].get(); } - if (copy_patch_value == NULL) { + if (copy_patch_value == nullptr) { // fail. printf("copy file doesn't match source SHA-1s either\n"); return 1; diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h index 80d681638..ca3dafbc9 100644 --- a/applypatch/include/applypatch/applypatch.h +++ b/applypatch/include/applypatch/applypatch.h @@ -20,10 +20,12 @@ #include #include +#include #include #include -#include "openssl/sha.h" +#include + #include "edify/expr.h" struct FileContents { @@ -41,27 +43,26 @@ struct FileContents { typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); -// applypatch.c +// applypatch.cpp int ShowLicenses(); size_t FreeSpaceForFile(const char* filename); int CacheSizeCheck(size_t bytes); int ParseSha1(const char* str, uint8_t* digest); -int applypatch_flash(const char* source_filename, const char* target_filename, - const char* target_sha1_str, size_t target_size); int applypatch(const char* source_filename, const char* target_filename, const char* target_sha1_str, size_t target_size, const std::vector& patch_sha1_str, - Value** patch_data, - Value* bonus_data); + const std::vector>& patch_data, + const Value* bonus_data); int applypatch_check(const char* filename, const std::vector& patch_sha1_str); +int applypatch_flash(const char* source_filename, const char* target_filename, + const char* target_sha1_str, size_t target_size); int LoadFileContents(const char* filename, FileContents* file); int SaveFileContents(const char* filename, const FileContents* file); -void FreeFileContents(FileContents* file); int FindMatchingPatch(uint8_t* sha1, const std::vector& patch_sha1_str); // bsdiff.cpp diff --git a/applypatch/main.cpp b/applypatch/main.cpp index 294f7ee21..988b6f9b1 100644 --- a/applypatch/main.cpp +++ b/applypatch/main.cpp @@ -23,9 +23,10 @@ #include #include +#include + #include "applypatch/applypatch.h" #include "edify/expr.h" -#include "openssl/sha.h" static int CheckMode(int argc, char** argv) { if (argc < 3) { @@ -129,15 +130,13 @@ static int PatchMode(int argc, char** argv) { printf("failed to parse patch args\n"); return 1; } - std::vector patches; - std::vector patch_ptrs; + + std::vector> patches; for (size_t i = 0; i < files.size(); ++i) { - patches.push_back(Value(VAL_BLOB, - std::string(files[i].data.cbegin(), files[i].data.cend()))); - patch_ptrs.push_back(&patches[i]); + patches.push_back(std::make_unique( + VAL_BLOB, std::string(files[i].data.cbegin(), files[i].data.cend()))); } - return applypatch(argv[1], argv[2], argv[3], target_size, - sha1s, patch_ptrs.data(), &bonus); + return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus); } // This program applies binary patches to files in a way that is safe -- cgit v1.2.3 From 36c35119526023c9e28ec22915b26b1bf7da6bc3 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 25 Oct 2016 14:17:26 -0700 Subject: applypatch: Add testcases for applypatch executable. Refactor applypatch/main.cpp into libapplypatch_modes so that we can add testcases. Some changes to applypatch/main.cpp: - Replace char** argv with const char**; - Use android::base::Split() to split ":"; - Use android::base::ParseUInt(). Bug: 32383590 Test: Unit tests pass, install-recovery.sh works. Change-Id: I44e7bfa5ab717d439ea1d0ee9ddb7b2c40bb95a4 --- applypatch/Android.mk | 30 +++++- applypatch/applypatch_main.cpp | 28 ++++++ applypatch/applypatch_modes.cpp | 204 ++++++++++++++++++++++++++++++++++++++++ applypatch/applypatch_modes.h | 22 +++++ applypatch/main.cpp | 202 --------------------------------------- 5 files changed, 279 insertions(+), 207 deletions(-) create mode 100644 applypatch/applypatch_main.cpp create mode 100644 applypatch/applypatch_modes.cpp create mode 100644 applypatch/applypatch_modes.h delete mode 100644 applypatch/main.cpp (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 9bbac4410..fa0fe8a37 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -68,21 +68,41 @@ LOCAL_STATIC_LIBRARIES += libcrypto libbz libz LOCAL_CFLAGS := -Werror include $(BUILD_HOST_STATIC_LIBRARY) -# applypatch (executable) +# libapplypatch_modes (static library) # =============================== include $(CLEAR_VARS) LOCAL_CLANG := true -LOCAL_SRC_FILES := main.cpp +LOCAL_SRC_FILES := \ + applypatch_modes.cpp +LOCAL_MODULE := libapplypatch_modes +LOCAL_C_INCLUDES := bootable/recovery +LOCAL_STATIC_LIBRARIES := \ + libapplypatch \ + libbase \ + libedify \ + libcrypto +LOCAL_CFLAGS := -Werror +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 -LOCAL_STATIC_LIBRARIES += \ +LOCAL_C_INCLUDES := bootable/recovery +LOCAL_STATIC_LIBRARIES := \ + libapplypatch_modes \ libapplypatch \ libbase \ libedify \ libotafault \ libcrypto \ libbz -LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libz \ + libcutils LOCAL_CFLAGS := -Werror include $(BUILD_EXECUTABLE) diff --git a/applypatch/applypatch_main.cpp b/applypatch/applypatch_main.cpp new file mode 100644 index 000000000..197077c93 --- /dev/null +++ b/applypatch/applypatch_main.cpp @@ -0,0 +1,28 @@ +/* + * 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_modes.h" + +// This program (applypatch) applies binary patches to files in a way that +// is safe (the original file is not touched until we have the desired +// replacement for it) and idempotent (it's okay to run this program +// multiple times). +// +// See the comments to applypatch_modes() function. + +int main(int argc, char** argv) { + return applypatch_modes(argc, const_cast(argv)); +} diff --git a/applypatch/applypatch_modes.cpp b/applypatch/applypatch_modes.cpp new file mode 100644 index 000000000..7b191a801 --- /dev/null +++ b/applypatch/applypatch_modes.cpp @@ -0,0 +1,204 @@ +/* + * 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 "applypatch_modes.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "applypatch/applypatch.h" +#include "edify/expr.h" + +static int CheckMode(int argc, const char** argv) { + if (argc < 3) { + return 2; + } + std::vector sha1; + for (int i = 3; i < argc; i++) { + sha1.push_back(argv[i]); + } + + return applypatch_check(argv[2], sha1); +} + +static int SpaceMode(int argc, const char** argv) { + if (argc != 3) { + return 2; + } + + size_t bytes; + if (!android::base::ParseUint(argv[2], &bytes) || bytes == 0) { + printf("can't parse \"%s\" as byte count\n\n", argv[2]); + return 1; + } + return CacheSizeCheck(bytes); +} + +// Parse arguments (which should be of the form ":" into the +// new parallel arrays *sha1s and *files. Returns true on success. +static bool ParsePatchArgs(int argc, const char** argv, std::vector* sha1s, + std::vector* files) { + if (sha1s == nullptr) { + return false; + } + for (int i = 0; i < argc; ++i) { + std::vector pieces = android::base::Split(argv[i], ":"); + if (pieces.size() != 2) { + printf("failed to parse patch argument \"%s\"\n", argv[i]); + return false; + } + + uint8_t digest[SHA_DIGEST_LENGTH]; + if (ParseSha1(pieces[0].c_str(), digest) != 0) { + printf("failed to parse sha1 \"%s\"\n", argv[i]); + return false; + } + + sha1s->push_back(pieces[0]); + FileContents fc; + if (LoadFileContents(pieces[1].c_str(), &fc) != 0) { + return false; + } + files->push_back(std::move(fc)); + } + return true; +} + +static int FlashMode(const char* src_filename, const char* tgt_filename, + const char* tgt_sha1, size_t tgt_size) { + return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size); +} + +static int PatchMode(int argc, const char** argv) { + FileContents bonusFc; + Value bonus(VAL_INVALID, ""); + + if (argc >= 3 && strcmp(argv[1], "-b") == 0) { + if (LoadFileContents(argv[2], &bonusFc) != 0) { + printf("failed to load bonus file %s\n", argv[2]); + return 1; + } + bonus.type = VAL_BLOB; + bonus.data = std::string(bonusFc.data.cbegin(), bonusFc.data.cend()); + argc -= 2; + argv += 2; + } + + if (argc < 4) { + return 2; + } + + size_t target_size; + if (!android::base::ParseUint(argv[4], &target_size) || target_size == 0) { + printf("can't parse \"%s\" as byte count\n\n", argv[4]); + return 1; + } + + // If no : is provided, it is in flash mode. + if (argc == 5) { + if (bonus.type != VAL_INVALID) { + printf("bonus file not supported in flash mode\n"); + return 1; + } + return FlashMode(argv[1], argv[2], argv[3], target_size); + } + + std::vector sha1s; + std::vector files; + if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { + printf("failed to parse patch args\n"); + return 1; + } + + std::vector> patches; + for (size_t i = 0; i < files.size(); ++i) { + patches.push_back(std::make_unique( + VAL_BLOB, std::string(files[i].data.cbegin(), files[i].data.cend()))); + } + return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus); +} + +// This program (applypatch) applies binary patches to files in a way that +// is safe (the original file is not touched until we have the desired +// replacement for it) and idempotent (it's okay to run this program +// multiple times). +// +// - if the sha1 hash of is , does nothing and exits +// successfully. +// +// - otherwise, if no : is provided, flashes with +// . must be a partition name, while must +// be a regular image file. will not be deleted on success. +// +// - otherwise, if the sha1 hash of is , applies the +// bsdiff to to produce a new file (the type of patch +// is automatically detected from the file header). If that new +// file has sha1 hash , moves it to replace , and +// exits successfully. Note that if and are +// not the same, is NOT deleted on success. +// may be the string "-" to mean "the same as src-file". +// +// - otherwise, or if any error is encountered, exits with non-zero +// status. +// +// (or in check mode) may refer to an EMMC partition +// to read the source data. See the comments for the +// LoadPartitionContents() function for the format of such a filename. + +int applypatch_modes(int argc, const char** argv) { + if (argc < 2) { + usage: + printf( + "usage: %s [-b ] " + "[: ...]\n" + " or %s -c [ ...]\n" + " or %s -s \n" + " or %s -l\n" + "\n" + "Filenames may be of the form\n" + " EMMC::::::...\n" + "to specify reading from or writing to an EMMC partition.\n\n", + argv[0], argv[0], argv[0], argv[0]); + return 2; + } + + int result; + + if (strncmp(argv[1], "-l", 3) == 0) { + result = ShowLicenses(); + } else if (strncmp(argv[1], "-c", 3) == 0) { + result = CheckMode(argc, argv); + } else if (strncmp(argv[1], "-s", 3) == 0) { + result = SpaceMode(argc, argv); + } else { + result = PatchMode(argc, argv); + } + + if (result == 2) { + goto usage; + } + return result; +} diff --git a/applypatch/applypatch_modes.h b/applypatch/applypatch_modes.h new file mode 100644 index 000000000..3d9d08df5 --- /dev/null +++ b/applypatch/applypatch_modes.h @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#ifndef _APPLYPATCH_MODES_H +#define _APPLYPATCH_MODES_H + +int applypatch_modes(int argc, const char** argv); + +#endif // _APPLYPATCH_MODES_H diff --git a/applypatch/main.cpp b/applypatch/main.cpp deleted file mode 100644 index 988b6f9b1..000000000 --- a/applypatch/main.cpp +++ /dev/null @@ -1,202 +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 -#include -#include -#include - -#include -#include -#include - -#include - -#include "applypatch/applypatch.h" -#include "edify/expr.h" - -static int CheckMode(int argc, char** argv) { - if (argc < 3) { - return 2; - } - std::vector sha1; - for (int i = 3; i < argc; i++) { - sha1.push_back(argv[i]); - } - - return applypatch_check(argv[2], sha1); -} - -static int SpaceMode(int argc, char** argv) { - if (argc != 3) { - return 2; - } - char* endptr; - size_t bytes = strtol(argv[2], &endptr, 10); - if (bytes == 0 && endptr == argv[2]) { - printf("can't parse \"%s\" as byte count\n\n", argv[2]); - return 1; - } - return CacheSizeCheck(bytes); -} - -// Parse arguments (which should be of the form ":" -// into the new parallel arrays *sha1s and *files.Returns true on -// success. -static bool ParsePatchArgs(int argc, char** argv, std::vector* sha1s, - std::vector* files) { - if (sha1s == nullptr) { - return false; - } - for (int i = 0; i < argc; ++i) { - uint8_t digest[SHA_DIGEST_LENGTH]; - char* colon = strchr(argv[i], ':'); - if (colon == nullptr) { - printf("no ':' in patch argument \"%s\"\n", argv[i]); - return false; - } - *colon = '\0'; - ++colon; - if (ParseSha1(argv[i], digest) != 0) { - printf("failed to parse sha1 \"%s\"\n", argv[i]); - return false; - } - - sha1s->push_back(argv[i]); - FileContents fc; - if (LoadFileContents(colon, &fc) != 0) { - return false; - } - files->push_back(std::move(fc)); - } - return true; -} - -static int FlashMode(const char* src_filename, const char* tgt_filename, - const char* tgt_sha1, size_t tgt_size) { - return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size); -} - -static int PatchMode(int argc, char** argv) { - FileContents bonusFc; - Value bonus(VAL_INVALID, ""); - - if (argc >= 3 && strcmp(argv[1], "-b") == 0) { - if (LoadFileContents(argv[2], &bonusFc) != 0) { - printf("failed to load bonus file %s\n", argv[2]); - return 1; - } - bonus.type = VAL_BLOB; - bonus.data = std::string(bonusFc.data.cbegin(), bonusFc.data.cend()); - argc -= 2; - argv += 2; - } - - if (argc < 4) { - return 2; - } - - char* endptr; - size_t target_size = strtol(argv[4], &endptr, 10); - if (target_size == 0 && endptr == argv[4]) { - printf("can't parse \"%s\" as byte count\n\n", argv[4]); - return 1; - } - - // If no : is provided, it is in flash mode. - if (argc == 5) { - if (bonus.type != VAL_INVALID) { - printf("bonus file not supported in flash mode\n"); - return 1; - } - return FlashMode(argv[1], argv[2], argv[3], target_size); - } - std::vector sha1s; - std::vector files; - if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { - printf("failed to parse patch args\n"); - return 1; - } - - std::vector> patches; - for (size_t i = 0; i < files.size(); ++i) { - patches.push_back(std::make_unique( - VAL_BLOB, std::string(files[i].data.cbegin(), files[i].data.cend()))); - } - return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus); -} - -// This program applies binary patches to files in a way that is safe -// (the original file is not touched until we have the desired -// replacement for it) and idempotent (it's okay to run this program -// multiple times). -// -// - if the sha1 hash of is , does nothing and exits -// successfully. -// -// - otherwise, if no : is provided, flashes with -// . must be a partition name, while must -// be a regular image file. will not be deleted on success. -// -// - otherwise, if the sha1 hash of is , applies the -// bsdiff to to produce a new file (the type of patch -// is automatically detected from the file header). If that new -// file has sha1 hash , moves it to replace , and -// exits successfully. Note that if and are -// not the same, is NOT deleted on success. -// may be the string "-" to mean "the same as src-file". -// -// - otherwise, or if any error is encountered, exits with non-zero -// status. -// -// (or in check mode) may refer to an EMMC partition -// to read the source data. See the comments for the -// LoadPartitionContents() function for the format of such a filename. - -int main(int argc, char** argv) { - if (argc < 2) { - usage: - printf( - "usage: %s [-b ] " - "[: ...]\n" - " or %s -c [ ...]\n" - " or %s -s \n" - " or %s -l\n" - "\n" - "Filenames may be of the form\n" - " EMMC::::::...\n" - "to specify reading from or writing to an EMMC partition.\n\n", - argv[0], argv[0], argv[0], argv[0]); - return 2; - } - - int result; - - if (strncmp(argv[1], "-l", 3) == 0) { - result = ShowLicenses(); - } else if (strncmp(argv[1], "-c", 3) == 0) { - result = CheckMode(argc, argv); - } else if (strncmp(argv[1], "-s", 3) == 0) { - result = SpaceMode(argc, argv); - } else { - result = PatchMode(argc, argv); - } - - if (result == 2) { - goto usage; - } - return result; -} -- cgit v1.2.3 From 3a5177b16d574c902183d1322367fe7db08fffc1 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Tue, 15 Nov 2016 16:18:46 -0800 Subject: bootable/recovery: cleanup compiler warnings (potential leak of memory) bootable/recovery/applypatch/imgdiff.cpp:1065:3: warning: Potential leak of memory pointed to by 'patch_data' bootable/recovery/applypatch/imgdiff.cpp:1065:3: warning: Potential leak of memory pointed to by 'patch_size' bootable/recovery/applypatch/imgdiff.cpp:226:7: warning: Potential leak of memory pointed to by 'temp_entries' Bug: 26936282 Test: WITH_TIDY=1 WITH_STATIC_ANALYZER=1 mm Change-Id: I3cac945d7677d367934d5619ef7419daf6f48d6f --- applypatch/imgdiff.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 7c5bb866d..e78a60477 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -224,6 +224,7 @@ unsigned char* ReadZip(const char* filename, for (i = 0; i < cdcount; ++i) { if (!(cd[0] == 0x50 && cd[1] == 0x4b && cd[2] == 0x01 && cd[3] == 0x02)) { printf("bad central directory entry %d\n", i); + free(temp_entries); return NULL; } @@ -1062,6 +1063,9 @@ int main(int argc, char** argv) { } } + free(patch_data); + free(patch_size); + fclose(f); return 0; -- cgit v1.2.3 From b29f23f7e7c791e7d8786de93d630a12e4250c71 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Wed, 9 Nov 2016 13:17:01 -0800 Subject: Use static_cast to cast pointers returned by malloc/calloc/realloc/mmap. static_cast is preferable to reinterpret_cast when casting from void* pointers returned by malloc/calloc/realloc/mmap calls. Discovered while looking at compiler warnings (b/26936282). Test: WITH_TIDY=1 WITH_STATIC_ANALYZER=1 mma Change-Id: Iaffd537784aa857108f6981fdfd82d0496eb5592 Merged-In: I151642d5a60c94f312d0611576ad0143c249ba3d --- applypatch/imgdiff.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 7c5bb866d..f6087de01 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -189,7 +189,7 @@ unsigned char* ReadZip(const char* filename, } size_t sz = static_cast(st.st_size); - unsigned char* img = reinterpret_cast(malloc(sz)); + unsigned char* img = static_cast(malloc(sz)); FILE* f = fopen(filename, "rb"); if (fread(img, 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); @@ -216,7 +216,7 @@ unsigned char* ReadZip(const char* filename, int cdcount = Read2(img+i+8); int cdoffset = Read4(img+i+16); - ZipFileEntry* temp_entries = reinterpret_cast(malloc( + ZipFileEntry* temp_entries = static_cast(malloc( cdcount * sizeof(ZipFileEntry))); int entrycount = 0; @@ -234,7 +234,7 @@ unsigned char* ReadZip(const char* filename, int mlen = Read2(cd+32); // file comment len int hoffset = Read4(cd+42); // local header offset - char* filename = reinterpret_cast(malloc(nlen+1)); + char* filename = static_cast(malloc(nlen+1)); memcpy(filename, cd+46, nlen); filename[nlen] = '\0'; @@ -283,7 +283,7 @@ unsigned char* ReadZip(const char* filename, #endif *num_chunks = 0; - *chunks = reinterpret_cast(malloc((entrycount*2+2) * sizeof(ImageChunk))); + *chunks = static_cast(malloc((entrycount*2+2) * sizeof(ImageChunk))); ImageChunk* curr = *chunks; if (include_pseudo_chunk) { @@ -308,7 +308,7 @@ unsigned char* ReadZip(const char* filename, curr->filename = temp_entries[nextentry].filename; curr->len = temp_entries[nextentry].uncomp_len; - curr->data = reinterpret_cast(malloc(curr->len)); + curr->data = static_cast(malloc(curr->len)); z_stream strm; strm.zalloc = Z_NULL; @@ -378,7 +378,7 @@ unsigned char* ReadImage(const char* filename, } size_t sz = static_cast(st.st_size); - unsigned char* img = reinterpret_cast(malloc(sz + 4)); + unsigned char* img = static_cast(malloc(sz + 4)); FILE* f = fopen(filename, "rb"); if (fread(img, 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); @@ -408,7 +408,7 @@ unsigned char* ReadImage(const char* filename, size_t chunk_offset = pos; *num_chunks += 3; - *chunks = reinterpret_cast(realloc(*chunks, + *chunks = static_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); ImageChunk* curr = *chunks + (*num_chunks-3); @@ -431,7 +431,7 @@ unsigned char* ReadImage(const char* filename, size_t allocated = 32768; curr->len = 0; - curr->data = reinterpret_cast(malloc(allocated)); + curr->data = static_cast(malloc(allocated)); curr->start = pos; curr->deflate_data = p; @@ -459,7 +459,7 @@ unsigned char* ReadImage(const char* filename, curr->len = allocated - strm.avail_out; if (strm.avail_out == 0) { allocated *= 2; - curr->data = reinterpret_cast(realloc(curr->data, allocated)); + curr->data = static_cast(realloc(curr->data, allocated)); } } while (ret != Z_STREAM_END); @@ -502,7 +502,7 @@ unsigned char* ReadImage(const char* filename, // Reallocate the list for every chunk; we expect the number of // chunks to be small (5 for typical boot and recovery images). ++*num_chunks; - *chunks = reinterpret_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); + *chunks = static_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); ImageChunk* curr = *chunks + (*num_chunks-1); curr->start = pos; @@ -585,7 +585,7 @@ int ReconstructDeflateChunk(ImageChunk* chunk) { return -1; } - unsigned char* out = reinterpret_cast(malloc(BUFFER_SIZE)); + unsigned char* out = static_cast(malloc(BUFFER_SIZE)); // We only check two combinations of encoder parameters: level 6 // (the default) and level 9 (the maximum). @@ -646,7 +646,7 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) { size_t sz = static_cast(st.st_size); // TODO: Memory leak on error return. - unsigned char* data = reinterpret_cast(malloc(sz)); + unsigned char* data = static_cast(malloc(sz)); if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) { unlink(ptemp); @@ -813,7 +813,7 @@ int main(int argc, char** argv) { return 1; } bonus_size = st.st_size; - bonus_data = reinterpret_cast(malloc(bonus_size)); + bonus_data = static_cast(malloc(bonus_size)); FILE* f = fopen(argv[2], "rb"); if (f == NULL) { printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno)); @@ -959,9 +959,9 @@ int main(int argc, char** argv) { DumpChunks(src_chunks, num_src_chunks); printf("Construct patches for %d chunks...\n", num_tgt_chunks); - unsigned char** patch_data = reinterpret_cast(malloc( + unsigned char** patch_data = static_cast(malloc( num_tgt_chunks * sizeof(unsigned char*))); - size_t* patch_size = reinterpret_cast(malloc(num_tgt_chunks * sizeof(size_t))); + size_t* patch_size = static_cast(malloc(num_tgt_chunks * sizeof(size_t))); for (i = 0; i < num_tgt_chunks; ++i) { if (zip_mode) { ImageChunk* src; @@ -975,7 +975,7 @@ int main(int argc, char** argv) { } else { if (i == 1 && bonus_data) { printf(" using %zu bytes of bonus data for chunk %d\n", bonus_size, i); - src_chunks[i].data = reinterpret_cast(realloc(src_chunks[i].data, + src_chunks[i].data = static_cast(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; -- cgit v1.2.3 From 8fce75a0697d07deed7dc81b0b9384920d8a46a4 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 10 Nov 2016 12:33:41 -0800 Subject: applypatch: Clean up LoadPartitionContents(). We don't need three vectors to sort the (size, SHA-1) pairs. Test: recovery_component_test passes. Test: Apply a package that calls apply_patch_check() to patch EMMC partitions. Change-Id: I4a6620630a6711f490822cf30f1e7fe5cea6ce49 --- applypatch/applypatch.cpp | 540 ++++++++++++++++++++++------------------------ 1 file changed, 257 insertions(+), 283 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 9d505f9f6..5483a68da 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "applypatch/applypatch.h" + #include #include #include @@ -27,16 +29,18 @@ #include #include +#include +#include +#include #include +#include -#include "openssl/sha.h" -#include "applypatch/applypatch.h" #include "edify/expr.h" #include "ota_io.h" #include "print_sha1.h" -static int LoadPartitionContents(const char* filename, FileContents* file); +static int LoadPartitionContents(const std::string& filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); static int GenerateTarget(FileContents* source_file, const Value* source_patch_value, @@ -48,39 +52,34 @@ static int GenerateTarget(FileContents* source_file, size_t target_size, const Value* bonus_data); -// Read a file into memory; store the file contents and associated -// metadata in *file. -// +// Read a file into memory; store the file contents and associated metadata in *file. // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - // A special 'filename' beginning with "EMMC:" means to - // load the contents of a partition. - if (strncmp(filename, "EMMC:", 5) == 0) { - return LoadPartitionContents(filename, file); - } + // A special 'filename' beginning with "EMMC:" means to load the contents of a partition. + if (strncmp(filename, "EMMC:", 5) == 0) { + return LoadPartitionContents(filename, file); + } - if (stat(filename, &file->st) != 0) { - printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); - return -1; - } + if (stat(filename, &file->st) == -1) { + printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); + return -1; + } - std::vector data(file->st.st_size); - FILE* f = ota_fopen(filename, "rb"); - if (f == NULL) { - printf("failed to open \"%s\": %s\n", filename, strerror(errno)); - return -1; - } + std::vector data(file->st.st_size); + std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); + if (!f) { + printf("failed to open \"%s\": %s\n", filename, strerror(errno)); + return -1; + } - size_t bytes_read = ota_fread(data.data(), 1, data.size(), f); - if (bytes_read != data.size()) { - printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); - ota_fclose(f); - return -1; - } - ota_fclose(f); - file->data = std::move(data); - SHA1(file->data.data(), file->data.size(), file->sha1); - return 0; + size_t bytes_read = ota_fread(data.data(), 1, data.size(), f.get()); + if (bytes_read != data.size()) { + printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size()); + return -1; + } + file->data = std::move(data); + SHA1(file->data.data(), file->data.size(), file->sha1); + return 0; } // Load the contents of an EMMC partition into the provided @@ -97,114 +96,98 @@ int LoadFileContents(const char* filename, FileContents* file) { // "end-of-file" marker), so the caller must specify the possible // lengths and the hash of the data, and we'll do the load expecting // to find one of those hashes. -static int LoadPartitionContents(const char* filename, FileContents* file) { - std::string copy(filename); - std::vector pieces = android::base::Split(copy, ":"); - if (pieces.size() < 4 || pieces.size() % 2 != 0) { - printf("LoadPartitionContents called with bad filename (%s)\n", filename); - return -1; - } - - if (pieces[0] != "EMMC") { - printf("LoadPartitionContents called with bad filename (%s)\n", filename); +static int LoadPartitionContents(const std::string& filename, FileContents* file) { + std::vector pieces = android::base::Split(filename, ":"); + if (pieces.size() < 4 || pieces.size() % 2 != 0 || pieces[0] != "EMMC") { + printf("LoadPartitionContents called with bad filename \"%s\"\n", filename.c_str()); + return -1; + } + + size_t pair_count = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename + std::vector> pairs; + for (size_t i = 0; i < pair_count; ++i) { + size_t size; + if (!android::base::ParseUint(pieces[i * 2 + 2], &size) || size == 0) { + printf("LoadPartitionContents called with bad size \"%s\"\n", pieces[i * 2 + 2].c_str()); + return -1; + } + pairs.push_back({ size, pieces[i * 2 + 3] }); + } + + // Sort the pairs array so that they are in order of increasing size. + std::sort(pairs.begin(), pairs.end()); + + const char* partition = pieces[1].c_str(); + std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); + if (!dev) { + printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); + return -1; + } + + SHA_CTX sha_ctx; + SHA1_Init(&sha_ctx); + + // Allocate enough memory to hold the largest size. + std::vector buffer(pairs[pair_count - 1].first); + unsigned char* buffer_ptr = buffer.data(); + size_t buffer_size = 0; // # bytes read so far + bool found = false; + + for (const auto& pair : pairs) { + size_t current_size = pair.first; + const std::string& current_sha1 = pair.second; + + // Read enough additional bytes to get us up to the next size. (Again, + // we're trying the possibilities in order of increasing size). + size_t next = current_size - buffer_size; + if (next > 0) { + size_t read = ota_fread(buffer_ptr, 1, next, dev.get()); + if (next != read) { + printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition); return -1; - } - const char* partition = pieces[1].c_str(); - - size_t pairs = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename - std::vector index(pairs); - std::vector size(pairs); - std::vector sha1sum(pairs); - - for (size_t i = 0; i < pairs; ++i) { - size[i] = strtol(pieces[i*2+2].c_str(), NULL, 10); - if (size[i] == 0) { - printf("LoadPartitionContents called with bad size (%s)\n", filename); - return -1; - } - sha1sum[i] = pieces[i*2+3].c_str(); - index[i] = i; + } + SHA1_Update(&sha_ctx, buffer_ptr, read); + buffer_size += read; + buffer_ptr += read; } - // Sort the index[] array so it indexes the pairs in order of increasing size. - sort(index.begin(), index.end(), - [&](const size_t& i, const size_t& j) { - return (size[i] < size[j]); - } - ); + // Duplicate the SHA context and finalize the duplicate so we can + // check it against this pair's expected hash. + SHA_CTX temp_ctx; + memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); + uint8_t sha_so_far[SHA_DIGEST_LENGTH]; + SHA1_Final(sha_so_far, &temp_ctx); - FILE* dev = ota_fopen(partition, "rb"); - if (dev == NULL) { - printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); - return -1; - } - - SHA_CTX sha_ctx; - SHA1_Init(&sha_ctx); uint8_t parsed_sha[SHA_DIGEST_LENGTH]; - - // Allocate enough memory to hold the largest size. - std::vector data(size[index[pairs-1]]); - char* p = reinterpret_cast(data.data()); - size_t data_size = 0; // # bytes read so far - bool found = false; - - for (size_t i = 0; i < pairs; ++i) { - // Read enough additional bytes to get us up to the next size. (Again, - // we're trying the possibilities in order of increasing size). - size_t next = size[index[i]] - data_size; - if (next > 0) { - size_t read = ota_fread(p, 1, next, dev); - if (next != read) { - printf("short read (%zu bytes of %zu) for partition \"%s\"\n", - read, next, partition); - return -1; - } - SHA1_Update(&sha_ctx, p, read); - data_size += read; - p += read; - } - - // Duplicate the SHA context and finalize the duplicate so we can - // check it against this pair's expected hash. - SHA_CTX temp_ctx; - memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); - uint8_t sha_so_far[SHA_DIGEST_LENGTH]; - SHA1_Final(sha_so_far, &temp_ctx); - - if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) { - printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename); - return -1; - } - - if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) { - // we have a match. stop reading the partition; we'll return - // the data we've read so far. - printf("partition read matched size %zu sha %s\n", - size[index[i]], sha1sum[index[i]].c_str()); - found = true; - break; - } + if (ParseSha1(current_sha1.c_str(), parsed_sha) != 0) { + printf("failed to parse SHA-1 %s in %s\n", current_sha1.c_str(), filename.c_str()); + return -1; } - ota_fclose(dev); - - if (!found) { - // Ran off the end of the list of (size,sha1) pairs without finding a match. - printf("contents of partition \"%s\" didn't match %s\n", partition, filename); - return -1; + if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) { + // We have a match. Stop reading the partition; we'll return the data we've read so far. + printf("partition read matched size %zu SHA-1 %s\n", current_size, current_sha1.c_str()); + found = true; + break; } + } - SHA1_Final(file->sha1, &sha_ctx); + if (!found) { + // Ran off the end of the list of (size, sha1) pairs without finding a match. + printf("contents of partition \"%s\" didn't match %s\n", partition, filename.c_str()); + return -1; + } - data.resize(data_size); - file->data = std::move(data); - // Fake some stat() info. - file->st.st_mode = 0644; - file->st.st_uid = 0; - file->st.st_gid = 0; + SHA1_Final(file->sha1, &sha_ctx); - return 0; + 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; } @@ -250,131 +233,124 @@ int SaveFileContents(const char* filename, const FileContents* file) { // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(const unsigned char* data, size_t len, const char* target) { - std::string copy(target); - std::vector pieces = android::base::Split(copy, ":"); - - if (pieces.size() < 2) { - printf("WriteToPartition called with bad target (%s)\n", target); - return -1; - } - - if (pieces[0] != "EMMC") { - printf("WriteToPartition called with bad target (%s)\n", target); - return -1; - } - const char* partition = pieces[1].c_str(); - - size_t start = 0; - bool success = false; - int fd = ota_open(partition, O_RDWR | O_SYNC); - if (fd < 0) { - printf("failed to open %s: %s\n", partition, strerror(errno)); - return -1; - } - - for (size_t attempt = 0; attempt < 2; ++attempt) { - if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { - printf("failed seek on %s: %s\n", partition, strerror(errno)); - return -1; - } - while (start < len) { - size_t to_write = len - start; - if (to_write > 1<<20) to_write = 1<<20; - - ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); - if (written == -1) { - printf("failed write writing to %s: %s\n", partition, strerror(errno)); - return -1; - } - start += written; - } - if (ota_fsync(fd) != 0) { - printf("failed to sync to %s (%s)\n", partition, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("failed to close %s (%s)\n", partition, strerror(errno)); - return -1; - } - fd = ota_open(partition, O_RDONLY); - if (fd < 0) { - printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); - return -1; - } + std::vector pieces = android::base::Split(std::string(target), ":"); - // Drop caches so our subsequent verification read - // won't just be reading the cache. - sync(); - int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); - if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { - printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); - } else { - printf(" caches dropped\n"); - } - ota_close(dc); - sleep(1); - - // verify - if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { - printf("failed to seek back to beginning of %s: %s\n", - partition, strerror(errno)); - return -1; - } - unsigned char buffer[4096]; - start = len; - for (size_t p = 0; p < len; p += sizeof(buffer)) { - size_t to_read = len - p; - if (to_read > sizeof(buffer)) { - to_read = sizeof(buffer); - } + if (pieces.size() < 2 || pieces[0] != "EMMC") { + printf("WriteToPartition called with bad target (%s)\n", target); + return -1; + } - size_t so_far = 0; - while (so_far < to_read) { - ssize_t read_count = - TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); - if (read_count == -1) { - printf("verify read error %s at %zu: %s\n", - partition, p, strerror(errno)); - return -1; - } else if (read_count == 0) { - printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); - return -1; - } - if (static_cast(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu %s\n", - partition, p, read_count, to_read, strerror(errno)); - } - so_far += read_count; - } + const char* partition = pieces[1].c_str(); - if (memcmp(buffer, data+p, to_read) != 0) { - printf("verification failed starting at %zu\n", p); - start = p; - break; - } - } + size_t start = 0; + bool success = false; + int fd = ota_open(partition, O_RDWR | O_SYNC); + if (fd < 0) { + printf("failed to open %s: %s\n", partition, strerror(errno)); + return -1; + } - if (start == len) { - printf("verification read succeeded (attempt %zu)\n", attempt+1); - success = true; - break; - } + for (size_t attempt = 0; attempt < 2; ++attempt) { + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { + printf("failed seek on %s: %s\n", partition, strerror(errno)); + return -1; } + while (start < len) { + size_t to_write = len - start; + if (to_write > 1 << 20) to_write = 1 << 20; - if (!success) { - printf("failed to verify after all attempts\n"); + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data + start, to_write)); + if (written == -1) { + printf("failed write writing to %s: %s\n", partition, strerror(errno)); return -1; + } + start += written; } + if (ota_fsync(fd) != 0) { + printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + return -1; + } if (ota_close(fd) != 0) { - printf("error closing %s (%s)\n", partition, strerror(errno)); - return -1; + printf("failed to close %s (%s)\n", partition, strerror(errno)); + return -1; } + + fd = ota_open(partition, O_RDONLY); + if (fd < 0) { + printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + return -1; + } + + // Drop caches so our subsequent verification read won't just be reading the cache. sync(); + int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { + printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + } else { + printf(" caches dropped\n"); + } + ota_close(dc); + sleep(1); + + // verify + if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { + printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno)); + return -1; + } + + unsigned char buffer[4096]; + start = len; + for (size_t p = 0; p < len; p += sizeof(buffer)) { + size_t to_read = len - p; + if (to_read > sizeof(buffer)) { + to_read = sizeof(buffer); + } + + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = TEMP_FAILURE_RETRY(ota_read(fd, buffer + so_far, to_read - so_far)); + if (read_count == -1) { + printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); + return -1; + } else if (read_count == 0) { + printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); + return -1; + } + if (static_cast(read_count) < to_read) { + printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read, + strerror(errno)); + } + so_far += read_count; + } + + if (memcmp(buffer, data + p, to_read) != 0) { + printf("verification failed starting at %zu\n", p); + start = p; + break; + } + } + + if (start == len) { + printf("verification read succeeded (attempt %zu)\n", attempt + 1); + success = true; + break; + } + } + + if (!success) { + printf("failed to verify after all attempts\n"); + return -1; + } - return 0; -} + if (ota_close(fd) != 0) { + printf("error closing %s (%s)\n", partition, strerror(errno)); + return -1; + } + sync(); + return 0; +} // Take a string 'str' of 40 hex digits and parse it into the 20 // byte array 'digest'. 'str' may contain only the digest or be of @@ -409,48 +385,46 @@ int ParseSha1(const char* str, uint8_t* digest) { // Return the index of the match on success, or -1 if no match is // found. int FindMatchingPatch(uint8_t* sha1, const std::vector& 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 && - memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { - return i; - } - } - return -1; + 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 && + memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) { + return i; + } + } + return -1; } // Returns 0 if the contents of the file (argv[2]) or the cached file // match any of the sha1's on the command line (argv[3:]). Returns // nonzero otherwise. int applypatch_check(const char* filename, const std::vector& patch_sha1_str) { - FileContents file; - - // It's okay to specify no sha1s; the check will pass if the - // LoadFileContents is successful. (Useful for reading - // partitions, where the filename encodes the sha1s; no need to - // check them twice.) - if (LoadFileContents(filename, &file) != 0 || - (patch_sha1_str.size() > 0 && 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) { - printf("failed to load cache file\n"); - return 1; - } - - if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { - printf("cache bits don't match any sha1 for \"%s\"\n", filename); - return 1; - } - } - return 0; + FileContents file; + + // It's okay to specify no sha1s; the check will pass if the + // LoadFileContents is successful. (Useful for reading + // partitions, where the filename encodes the sha1s; no need to + // check them twice.) + if (LoadFileContents(filename, &file) != 0 || + (!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) { + printf("failed to load cache file\n"); + return 1; + } + + if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) { + printf("cache bits don't match any sha1 for \"%s\"\n", filename); + return 1; + } + } + return 0; } int ShowLicenses() { @@ -544,10 +518,8 @@ int applypatch(const char* source_filename, return 1; } - FileContents copy_file; FileContents source_file; const Value* source_patch_value = nullptr; - const Value* copy_patch_value = nullptr; // We try to load the target file into the source_file object. if (LoadFileContents(target_filename, &source_file) == 0) { @@ -575,6 +547,8 @@ int applypatch(const char* source_filename, } } + FileContents copy_file; + const Value* copy_patch_value = nullptr; if (source_patch_value == nullptr) { source_file.data.clear(); printf("source file is bad; trying copy\n"); @@ -620,7 +594,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename, return 1; } - FileContents source_file; std::string target_str(target_filename); std::vector pieces = android::base::Split(target_str, ":"); @@ -633,12 +606,13 @@ int applypatch_flash(const char* source_filename, const char* target_filename, pieces.push_back(std::to_string(target_size)); pieces.push_back(target_sha1_str); std::string fullname = android::base::Join(pieces, ':'); - if (LoadPartitionContents(fullname.c_str(), &source_file) == 0 && + FileContents source_file; + if (LoadPartitionContents(fullname, &source_file) == 0 && memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { - // The early-exit case: the image was already applied, this partition - // has the desired hash, nothing for us to do. - printf("already %s\n", short_sha1(target_sha1).c_str()); - return 0; + // The early-exit case: the image was already applied, this partition + // has the desired hash, nothing for us to do. + printf("already %s\n", short_sha1(target_sha1).c_str()); + return 0; } if (LoadFileContents(source_filename, &source_file) == 0) { -- cgit v1.2.3 From 6e02ea92ec8af1da74f55e616b7cda82740dccc0 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 17 Nov 2016 11:24:07 -0800 Subject: applypatch: Use unique_fd to avoid leaking FDs. Add unique_fd that calls ota_close() instead of the default closer. Test: recovery_component_test passes. Test: Apply a package that calls apply_patch(). Change-Id: I0c19921731757934f76cf7d5215916673a8f2777 --- applypatch/applypatch.cpp | 552 +++++++++++++++++++++++----------------------- 1 file changed, 270 insertions(+), 282 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 5483a68da..9b84fa104 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -194,62 +194,59 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { - int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); - return -1; - } + unique_fd fd(ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR)); + if (fd == -1) { + printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno)); + return -1; + } - ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); - if (bytes_written != static_cast(file->data.size())) { - printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n", - filename, bytes_written, file->data.size(), strerror(errno)); - ota_close(fd); - return -1; - } - if (ota_fsync(fd) != 0) { - printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); - return -1; - } + ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); + if (bytes_written != static_cast(file->data.size())) { + printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written, + file->data.size(), strerror(errno)); + return -1; + } + if (ota_fsync(fd) != 0) { + printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); + return -1; + } + if (ota_close(fd) != 0) { + printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); + 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; - } + 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; + return 0; } // Write a memory buffer to 'target' partition, a string of the form // "EMMC:[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. -int WriteToPartition(const unsigned char* data, size_t len, const char* target) { - std::vector pieces = android::base::Split(std::string(target), ":"); - +int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) { + std::vector pieces = android::base::Split(target, ":"); if (pieces.size() < 2 || pieces[0] != "EMMC") { - printf("WriteToPartition called with bad target (%s)\n", target); + printf("WriteToPartition called with bad target (%s)\n", target.c_str()); return -1; } const char* partition = pieces[1].c_str(); - - size_t start = 0; - bool success = false; - int fd = ota_open(partition, O_RDWR | O_SYNC); - if (fd < 0) { + unique_fd fd(ota_open(partition, O_RDWR)); + if (fd == -1) { printf("failed to open %s: %s\n", partition, strerror(errno)); return -1; } + size_t start = 0; + bool success = false; for (size_t attempt = 0; attempt < 2; ++attempt) { if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { printf("failed seek on %s: %s\n", partition, strerror(errno)); @@ -268,23 +265,23 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) } if (ota_fsync(fd) != 0) { - printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + printf("failed to sync to %s: %s\n", partition, strerror(errno)); return -1; } if (ota_close(fd) != 0) { - printf("failed to close %s (%s)\n", partition, strerror(errno)); + printf("failed to close %s: %s\n", partition, strerror(errno)); return -1; } - fd = ota_open(partition, O_RDONLY); - if (fd < 0) { - printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + fd.reset(ota_open(partition, O_RDONLY)); + if (fd == -1) { + printf("failed to reopen %s for verify: %s\n", partition, strerror(errno)); return -1; } // Drop caches so our subsequent verification read won't just be reading the cache. sync(); - int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY); + unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY)); if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); } else { @@ -293,7 +290,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) ota_close(dc); sleep(1); - // verify + // Verify. if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno)); return -1; @@ -318,8 +315,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } if (static_cast(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read, - strerror(errno)); + printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read); } so_far += read_count; } @@ -343,8 +339,8 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target) return -1; } - if (ota_close(fd) != 0) { - printf("error closing %s (%s)\n", partition, strerror(errno)); + if (ota_close(fd) == -1) { + printf("error closing %s: %s\n", partition, strerror(errno)); return -1; } sync(); @@ -586,50 +582,49 @@ int applypatch(const char* source_filename, */ int applypatch_flash(const char* source_filename, const char* target_filename, const char* target_sha1_str, size_t target_size) { - printf("flash %s: ", target_filename); + printf("flash %s: ", target_filename); - uint8_t target_sha1[SHA_DIGEST_LENGTH]; - if (ParseSha1(target_sha1_str, target_sha1) != 0) { - printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); - return 1; - } + uint8_t target_sha1[SHA_DIGEST_LENGTH]; + if (ParseSha1(target_sha1_str, target_sha1) != 0) { + printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); + return 1; + } - std::string target_str(target_filename); + std::string target_str(target_filename); + std::vector pieces = android::base::Split(target_str, ":"); + if (pieces.size() != 2 || pieces[0] != "EMMC") { + printf("invalid target name \"%s\"", target_filename); + return 1; + } - std::vector pieces = android::base::Split(target_str, ":"); - if (pieces.size() != 2 || pieces[0] != "EMMC") { - printf("invalid target name \"%s\"", target_filename); - return 1; - } + // Load the target into the source_file object to see if already applied. + pieces.push_back(std::to_string(target_size)); + pieces.push_back(target_sha1_str); + std::string fullname = android::base::Join(pieces, ':'); + FileContents source_file; + if (LoadPartitionContents(fullname, &source_file) == 0 && + memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { + // The early-exit case: the image was already applied, this partition + // has the desired hash, nothing for us to do. + printf("already %s\n", short_sha1(target_sha1).c_str()); + return 0; + } - // Load the target into the source_file object to see if already applied. - pieces.push_back(std::to_string(target_size)); - pieces.push_back(target_sha1_str); - std::string fullname = android::base::Join(pieces, ':'); - FileContents source_file; - if (LoadPartitionContents(fullname, &source_file) == 0 && - memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { - // The early-exit case: the image was already applied, this partition - // has the desired hash, nothing for us to do. - printf("already %s\n", short_sha1(target_sha1).c_str()); - return 0; - } - - if (LoadFileContents(source_filename, &source_file) == 0) { - if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { - // The source doesn't have desired checksum. - printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); - printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), - short_sha1(source_file.sha1).c_str()); - return 1; - } + if (LoadFileContents(source_filename, &source_file) == 0) { + if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { + // The source doesn't have desired checksum. + printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename); + printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(), + short_sha1(source_file.sha1).c_str()); + return 1; } + } - if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { - printf("write of copied data to %s failed\n", target_filename); - return 1; - } - return 0; + if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) { + printf("write of copied data to %s failed\n", target_filename); + return 1; + } + return 0; } static int GenerateTarget(FileContents* source_file, @@ -641,221 +636,214 @@ static int GenerateTarget(FileContents* source_file, const uint8_t target_sha1[SHA_DIGEST_LENGTH], size_t target_size, const Value* bonus_data) { - int retry = 1; - SHA_CTX ctx; - std::string memory_sink_str; - FileContents* source_to_use; - int made_copy = 0; - - bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); - const std::string tmp_target_filename = std::string(target_filename) + ".patch"; - - // assume that target_filename (eg "/system/app/Foo.apk") is located - // on the same filesystem as its top-level directory ("/system"). - // We need something that exists for calling statfs(). - std::string target_fs = target_filename; - auto slash_pos = target_fs.find('/', 1); - if (slash_pos != std::string::npos) { - target_fs.resize(slash_pos); - } - - const Value* patch; - if (source_patch_value != NULL) { - source_to_use = source_file; - patch = source_patch_value; - } else { - source_to_use = copy_file; - patch = copy_patch_value; - } - if (patch->type != VAL_BLOB) { - printf("patch is not a blob\n"); - return 1; - } - const char* header = &patch->data[0]; - size_t header_bytes_read = patch->data.size(); - bool use_bsdiff = false; - if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { - use_bsdiff = true; - } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) { - use_bsdiff = false; - } else { - printf("Unknown patch file format\n"); - return 1; - } + // assume that target_filename (eg "/system/app/Foo.apk") is located + // on the same filesystem as its top-level directory ("/system"). + // We need something that exists for calling statfs(). + std::string target_fs = target_filename; + auto slash_pos = target_fs.find('/', 1); + if (slash_pos != std::string::npos) { + target_fs.resize(slash_pos); + } - do { - // Is there enough room in the target filesystem to hold the patched - // file? - - if (target_is_partition) { - // If the target is a partition, we're actually going to - // write the output to /tmp and then copy it to the - // partition. statfs() always returns 0 blocks free for - // /tmp, so instead we'll just assume that /tmp has enough - // space to hold the file. - - // We still write the original source to cache, in case - // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = 1; - retry = 0; - } else { - int enough_space = 0; - if (retry > 0) { - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - enough_space = - (free_space > (256 << 10)) && // 256k (two-block) minimum - (free_space > (target_size * 3 / 2)); // 50% margin of error - if (!enough_space) { - printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", - target_size, free_space, retry, enough_space); - } - } - - if (!enough_space) { - retry = 0; - } - - if (!enough_space && source_patch_value != NULL) { - // Using the original source, but not enough free space. First - // copy the source file to cache, then delete it from the original - // location. - - if (strncmp(source_filename, "EMMC:", 5) == 0) { - // It's impossible to free space on the target filesystem by - // deleting the source if the source is a partition. If - // we're ever in a state where we need to do this, fail. - printf("not enough free space for target but source is partition\n"); - return 1; - } - - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = 1; - unlink(source_filename); - - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - printf("(now %zu bytes free for target) ", free_space); - } - } + FileContents* source_to_use; + const Value* patch; + if (source_patch_value != nullptr) { + source_to_use = source_file; + patch = source_patch_value; + } else { + source_to_use = copy_file; + patch = copy_patch_value; + } + if (patch->type != VAL_BLOB) { + printf("patch is not a blob\n"); + return 1; + } - SinkFn sink = NULL; - void* token = NULL; - int output_fd = -1; - if (target_is_partition) { - // We store the decoded output in memory. - sink = MemorySink; - token = &memory_sink_str; - } else { - // We write the decoded output to ".patch". - output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR); - if (output_fd < 0) { - printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), - strerror(errno)); - return 1; - } - sink = FileSink; - token = &output_fd; - } + const char* header = &patch->data[0]; + size_t header_bytes_read = patch->data.size(); + bool use_bsdiff = false; + if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { + use_bsdiff = true; + } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) { + use_bsdiff = false; + } else { + printf("Unknown patch file format\n"); + return 1; + } + bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); + const std::string tmp_target_filename = std::string(target_filename) + ".patch"; - SHA1_Init(&ctx); + int retry = 1; + bool made_copy = false; + SHA_CTX ctx; + std::string memory_sink_str; // Don't need to reserve space. + do { + // Is there enough room in the target filesystem to hold the patched file? - int result; - if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), - patch, 0, sink, token, &ctx); - } else { - result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), - patch, sink, token, &ctx, bonus_data); + if (target_is_partition) { + // If the target is a partition, we're actually going to + // write the output to /tmp and then copy it to the + // partition. statfs() always returns 0 blocks free for + // /tmp, so instead we'll just assume that /tmp has enough + // space to hold the file. + + // We still write the original source to cache, in case + // the partition write is interrupted. + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { + printf("not enough free space on /cache\n"); + return 1; + } + if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { + printf("failed to back up source file\n"); + return 1; + } + made_copy = true; + retry = 0; + } else { + bool enough_space = false; + if (retry > 0) { + size_t free_space = FreeSpaceForFile(target_fs.c_str()); + enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum + (free_space > (target_size * 3 / 2)); // 50% margin of error + if (!enough_space) { + printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size, + free_space, retry, enough_space); } + } + + if (!enough_space) { + retry = 0; + } - if (!target_is_partition) { - if (ota_fsync(output_fd) != 0) { - printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(), - strerror(errno)); - result = 1; - } - if (ota_close(output_fd) != 0) { - printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), - strerror(errno)); - result = 1; - } + if (!enough_space && source_patch_value != nullptr) { + // Using the original source, but not enough free space. First + // copy the source file to cache, then delete it from the original + // location. + + if (strncmp(source_filename, "EMMC:", 5) == 0) { + // It's impossible to free space on the target filesystem by + // deleting the source if the source is a partition. If + // we're ever in a state where we need to do this, fail. + printf("not enough free space for target but source is partition\n"); + return 1; } - if (result != 0) { - if (retry == 0) { - printf("applying patch failed\n"); - return result != 0; - } else { - printf("applying patch failed; retrying\n"); - } - if (!target_is_partition) { - unlink(tmp_target_filename.c_str()); - } - } else { - // succeeded; no need to retry - break; + if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { + printf("not enough free space on /cache\n"); + return 1; } - } while (retry-- > 0); - uint8_t current_target_sha1[SHA_DIGEST_LENGTH]; - SHA1_Final(current_target_sha1, &ctx); - if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { - printf("patch did not produce expected sha1\n"); + if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { + printf("failed to back up source file\n"); + return 1; + } + made_copy = true; + unlink(source_filename); + + size_t free_space = FreeSpaceForFile(target_fs.c_str()); + printf("(now %zu bytes free for target) ", free_space); + } + } + + SinkFn sink = nullptr; + void* token = nullptr; + unique_fd output_fd; + if (target_is_partition) { + // We store the decoded output in memory. + sink = MemorySink; + token = &memory_sink_str; + } else { + // We write the decoded output to ".patch". + output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + S_IRUSR | S_IWUSR)); + if (output_fd == -1) { + printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); return 1; + } + sink = FileSink; + token = &output_fd; + } + + SHA1_Init(&ctx); + + int result; + if (use_bsdiff) { + result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, + sink, token, &ctx); } else { - printf("now %s\n", short_sha1(target_sha1).c_str()); + result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, + token, &ctx, bonus_data); } - if (target_is_partition) { - // Copy the temp file to the partition. - if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), - memory_sink_str.size(), target_filename) != 0) { - printf("write of patched data to %s failed\n", target_filename); - return 1; - } + if (!target_is_partition) { + if (ota_fsync(output_fd) != 0) { + printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); + result = 1; + } + if (ota_close(output_fd) != 0) { + printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); + result = 1; + } + } + + if (result != 0) { + if (retry == 0) { + printf("applying patch failed\n"); + return 1; + } else { + printf("applying patch failed; retrying\n"); + } + if (!target_is_partition) { + unlink(tmp_target_filename.c_str()); + } } else { - // Give the .patch file the same owner, group, and mode of the - // original source file. - if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } + // succeeded; no need to retry + break; + } + } while (retry-- > 0); - // Finally, rename the .patch file to replace the target file. - if (rename(tmp_target_filename.c_str(), target_filename) != 0) { - printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno)); - return 1; - } + uint8_t current_target_sha1[SHA_DIGEST_LENGTH]; + SHA1_Final(current_target_sha1, &ctx); + if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) { + printf("patch did not produce expected sha1\n"); + return 1; + } else { + printf("now %s\n", short_sha1(target_sha1).c_str()); + } + + if (target_is_partition) { + // Copy the temp file to the partition. + if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), + memory_sink_str.size(), target_filename) != 0) { + printf("write of patched data to %s failed\n", target_filename); + return 1; + } + } else { + // Give the .patch file the same owner, group, and mode of the original source file. + if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) { + printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); + return 1; + } + if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, + source_to_use->st.st_gid) != 0) { + printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); + return 1; } - // If this run of applypatch created the copy, and we're here, we - // can delete it. - if (made_copy) { - unlink(CACHE_TEMP_SOURCE); + // Finally, rename the .patch file to replace the target file. + if (rename(tmp_target_filename.c_str(), target_filename) != 0) { + printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno)); + return 1; } + } - // Success! - return 0; + // If this run of applypatch created the copy, and we're here, we can delete it. + if (made_copy) { + unlink(CACHE_TEMP_SOURCE); + } + + // Success! + return 0; } -- cgit v1.2.3 From 48cf770471ef53fbf0a1837196220862a0bdb18d Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 21 Nov 2016 09:42:33 -0800 Subject: applypatch: Release FD when explicitly calling close. We use android::base::unique_fd() to avoid leaking FD. We also want to call close (or ota_close) to explicitly check the close result. When combining the two together, we need to release the unique_fd to avoid closing the same FD twice. Bug: 33034669 Test: Trigger applypatch with install-recovery.sh. Change-Id: I1a4f5d5fba7a23ef98d8bd7b7b07e87ae6f705c5 --- applypatch/applypatch.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 9b84fa104..41a8d582b 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -210,7 +210,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (ota_close(fd) != 0) { + if (ota_close(fd.release()) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -268,7 +268,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t printf("failed to sync to %s: %s\n", partition, strerror(errno)); return -1; } - if (ota_close(fd) != 0) { + if (ota_close(fd.release()) != 0) { printf("failed to close %s: %s\n", partition, strerror(errno)); return -1; } @@ -287,7 +287,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t } else { printf(" caches dropped\n"); } - ota_close(dc); + ota_close(dc.release()); sleep(1); // Verify. @@ -339,7 +339,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t return -1; } - if (ota_close(fd) == -1) { + if (ota_close(fd.release()) == -1) { printf("error closing %s: %s\n", partition, strerror(errno)); return -1; } @@ -782,7 +782,7 @@ static int GenerateTarget(FileContents* source_file, printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (ota_close(output_fd) != 0) { + if (ota_close(output_fd.release()) != 0) { printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } -- cgit v1.2.3 From 3dc14cb429061e49ef76948cf55a0e3edf8b170a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 22 Nov 2016 11:37:13 -0800 Subject: Add ota_close(unique_fd&) and ota_fclose(std::unique_ptr&). We were using the below sequence prior to the CL in [1]. unique_fd fd(ota_open(...)); ota_close(fd); fd.reset(ota_open(...)); fd.reset() may unintentionally close the newly opened FD if it has the same value as the early ota_open. The CL in [1] changed to "ota_close(fd.release())" to avoid the issue. This CL adds a new overloaded function ota_close(unique_fd&) to handle the release automatically. Similarly add ota_fclose(std::unique_ptr&). [1] commit 48cf770471ef53fbf0a1837196220862a0bdb18d. Bug: 33034669 Test: recovery_component_test passes. Change-Id: Ief91edc590e95a7426e33364b28754173efb1056 --- applypatch/applypatch.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 41a8d582b..0250407a5 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -66,7 +66,7 @@ int LoadFileContents(const char* filename, FileContents* file) { } std::vector data(file->st.st_size); - std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); + std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); if (!f) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; @@ -118,7 +118,7 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file std::sort(pairs.begin(), pairs.end()); const char* partition = pieces[1].c_str(); - std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); + std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); if (!dev) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; @@ -210,7 +210,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } - if (ota_close(fd.release()) != 0) { + if (ota_close(fd) != 0) { printf("close of \"%s\" failed: %s\n", filename, strerror(errno)); return -1; } @@ -268,7 +268,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t printf("failed to sync to %s: %s\n", partition, strerror(errno)); return -1; } - if (ota_close(fd.release()) != 0) { + if (ota_close(fd) != 0) { printf("failed to close %s: %s\n", partition, strerror(errno)); return -1; } @@ -287,7 +287,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t } else { printf(" caches dropped\n"); } - ota_close(dc.release()); + ota_close(dc); sleep(1); // Verify. @@ -339,7 +339,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const std::string& t return -1; } - if (ota_close(fd.release()) == -1) { + if (ota_close(fd) == -1) { printf("error closing %s: %s\n", partition, strerror(errno)); return -1; } @@ -782,7 +782,7 @@ static int GenerateTarget(FileContents* source_file, printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } - if (ota_close(output_fd.release()) != 0) { + if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } -- cgit v1.2.3 From 358c2ec1dca24d48a503b441d38545ace021ea8e Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 28 Nov 2016 11:48:43 -0800 Subject: Remove ota_close(int) and ota_fclose(FILE*). We should always use unique_fd or unique_file to hold the FD or FILE* pointer when opening via ota_(f)open functions. This CL avoids accidentally closing raw FDs or FILE* pointers that are managed by unique_fd/unique_file. Test: recovery_component_test passes. Change-Id: If58eb8b5c5da507563f85efd5d56276472a1c957 --- applypatch/applypatch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 0250407a5..95389da6e 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -66,7 +66,7 @@ int LoadFileContents(const char* filename, FileContents* file) { } std::vector data(file->st.st_size); - std::unique_ptr f(ota_fopen(filename, "rb"), ota_fclose); + unique_file f(ota_fopen(filename, "rb")); if (!f) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); return -1; @@ -118,7 +118,7 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file std::sort(pairs.begin(), pairs.end()); const char* partition = pieces[1].c_str(); - std::unique_ptr dev(ota_fopen(partition, "rb"), ota_fclose); + unique_file dev(ota_fopen(partition, "rb")); if (!dev) { printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno)); return -1; -- cgit v1.2.3 From a793c58208bc54fe83c5aa0e456a66ee2609e408 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Tue, 29 Nov 2016 17:10:14 -0800 Subject: bootable/recovery: cleanup compiler warnings (unused value) bootable/recovery/applypatch/imgdiff.cpp:322:11: warning: Value stored to 'ret' during its initialization is never read [clang-analyzer-deadcode.DeadStores] bootable/recovery/applypatch/imgdiff.cpp:447:11: warning: Value stored to 'ret' during its initialization is never read [clang-analyzer-deadcode.DeadStores] bootable/recovery/applypatch/imgdiff.cpp:553:3: warning: Value stored to 'ret' is never read [clang-analyzer-deadcode.DeadStores] Bug: 26936282 Test: WITH_TIDY=1 WITH_STATIC_ANALYZER=1 mm Change-Id: I3f865e3e9b9d19e5ea5e8dfd2fe2c644254ffbb5 --- applypatch/imgdiff.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index f6087de01..77c19ad97 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -320,6 +320,10 @@ unsigned char* ReadZip(const char* filename, // -15 means we are decoding a 'raw' deflate stream; zlib will // not expect zlib headers. int ret = inflateInit2(&strm, -15); + if (ret < 0) { + printf("failed to initialize inflate: %d\n", ret); + return NULL; + } strm.avail_out = curr->len; strm.next_out = curr->data; @@ -445,6 +449,10 @@ unsigned char* ReadImage(const char* filename, // -15 means we are decoding a 'raw' deflate stream; zlib will // not expect zlib headers. int ret = inflateInit2(&strm, -15); + if (ret < 0) { + printf("failed to initialize inflate: %d\n", ret); + return NULL; + } do { strm.avail_out = allocated - curr->len; @@ -552,10 +560,18 @@ int TryReconstruction(ImageChunk* chunk, unsigned char* out) { int ret; ret = deflateInit2(&strm, chunk->level, chunk->method, chunk->windowBits, chunk->memLevel, chunk->strategy); + if (ret < 0) { + printf("failed to initialize deflate: %d\n", ret); + return -1; + } do { strm.avail_out = BUFFER_SIZE; strm.next_out = out; ret = deflate(&strm, Z_FINISH); + if (ret < 0) { + printf("failed to deflate: %d\n", ret); + return -1; + } size_t have = BUFFER_SIZE - strm.avail_out; if (memcmp(out, chunk->deflate_data+p, have) != 0) { -- cgit v1.2.3 From 8b640ffabc3f7c81c94dcbba6fec3436f85383fb Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Tue, 6 Dec 2016 15:10:41 -0800 Subject: bootable/recovery: cleanup compiler warnings (potential leak of memory) bootable/recovery/applypatch/imgdiff.cpp:195:5: warning: Potential leak of memory pointed to by 'img' [clang-analyzer-unix.Malloc] Bug: 26936282 Test: WITH_TIDY=1 WITH_STATIC_ANALYZER=1 mm Change-Id: Ie79c780233ddfebf85686a24df3bf2561f831580 --- applypatch/imgdiff.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'applypatch') diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 528daf113..7d6ebab6e 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -194,6 +194,7 @@ unsigned char* ReadZip(const char* filename, if (fread(img, 1, sz, f) != sz) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); fclose(f); + free(img); return NULL; } fclose(f); -- cgit v1.2.3 From 9a6f5204190cda6bb6aecb59dff0293cc90ab0b7 Mon Sep 17 00:00:00 2001 From: katao Date: Mon, 19 Dec 2016 11:22:30 +0800 Subject: Bugfix:updater always retry apply patch failed,when memcpy failed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://code.google.com/p/android/issues/detail?id=230602 On the second attempt, open the file with O_RDONLY, which causing a write failure。 Change-Id: If89165b8c7619fe25722073a46b3cc7c61530a71 Signed-off-by: katao --- applypatch/applypatch.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 95389da6e..8682e128b 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) { -- cgit v1.2.3 From 97555da4a67d45ada0020c0ee58d1b280cb4b57d Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 15 Dec 2016 10:15:06 -0800 Subject: Add tests for imgdiff. Factor out libimgdiff static library for testing purpose. This CL adds the imgdiff tests on host and on target both (similar to libimgpatch). In practice, we only need imgdiff binary on host, and libimgpatch on target. But they should build and pass tests on both platforms. Test: recovery_host_test passes; recovery_component_test passes. Change-Id: I0eafb7faf727cdf70066310e845af6ee245d4f60 --- applypatch/Android.mk | 90 +++++-- applypatch/imgdiff.cpp | 54 ++--- applypatch/imgdiff.h | 30 --- applypatch/imgdiff_main.cpp | 21 ++ applypatch/imgpatch.cpp | 405 +++++++++++++++---------------- applypatch/include/applypatch/imgdiff.h | 39 +++ applypatch/include/applypatch/imgpatch.h | 10 +- 7 files changed, 359 insertions(+), 290 deletions(-) delete mode 100644 applypatch/imgdiff.h create mode 100644 applypatch/imgdiff_main.cpp create mode 100644 applypatch/include/applypatch/imgdiff.h (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index fa0fe8a37..61e110617 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,11 +25,11 @@ 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 \ @@ -42,36 +41,45 @@ 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_STATIC_LIBRARIES := \ + libcrypto \ + libbz \ + libz LOCAL_CFLAGS := -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_STATIC_LIBRARIES := \ + libcrypto \ + libbz \ + libz LOCAL_CFLAGS := -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 +95,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 +113,59 @@ 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 \ + 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 \ +LOCAL_CFLAGS := -Werror +LOCAL_STATIC_LIBRARIES := \ + libimgdiff \ + $(libimgdiff_static_libraries) \ libbz \ - libdivsufsort64 \ libdivsufsort \ - libz -LOCAL_CFLAGS := -Werror -LOCAL_FORCE_STATIC_EXECUTABLE := true + libdivsufsort64 include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 528daf113..18a15a164 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -121,19 +121,19 @@ * information that is stored on the system partition. */ +#include "applypatch/imgdiff.h" + #include -#include #include #include #include #include -#include #include +#include #include +#include -#include "zlib.h" -#include "imgdiff.h" #include "utils.h" typedef struct { @@ -374,8 +374,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)); @@ -403,7 +402,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 && @@ -413,8 +412,7 @@ unsigned char* ReadImage(const char* filename, size_t chunk_offset = pos; *num_chunks += 3; - *chunks = static_cast(realloc(*chunks, - *num_chunks * sizeof(ImageChunk))); + *chunks = static_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); ImageChunk* curr = *chunks + (*num_chunks-3); // create a normal chunk for the header. @@ -502,8 +500,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; } @@ -637,7 +634,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) { @@ -793,10 +794,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; @@ -812,11 +811,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; } @@ -880,12 +879,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"); @@ -897,8 +894,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"); @@ -983,8 +979,7 @@ int main(int argc, char** argv) { if (zip_mode) { ImageChunk* src; if (tgt_chunks[i].type == CHUNK_DEFLATE && - (src = FindChunkByName(tgt_chunks[i].filename, src_chunks, - num_src_chunks))) { + (src = FindChunkByName(tgt_chunks[i].filename, src_chunks, num_src_chunks))) { patch_data[i] = MakePatch(src, tgt_chunks+i, patch_size+i); } else { patch_data[i] = MakePatch(src_chunks, tgt_chunks+i, patch_size+i); @@ -1000,8 +995,7 @@ int main(int argc, char** argv) { patch_data[i] = MakePatch(src_chunks+i, tgt_chunks+i, patch_size+i); } - 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); } // Figure out how big the imgdiff file header is going to be, so diff --git a/applypatch/imgdiff.h b/applypatch/imgdiff.h deleted file mode 100644 index f2069b4f3..000000000 --- a/applypatch/imgdiff.h +++ /dev/null @@ -1,30 +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. - */ - -// 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 - -// 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 - -// The gzip footer size really is fixed. -#define GZIP_FOOTER_LEN 8 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(argv)); +} diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 1c4409e36..ae6071f0e 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 + +#include #include +#include #include #include -#include #include -#include #include #include -#include "zlib.h" -#include "openssl/sha.h" -#include "applypatch/applypatch.h" -#include "imgdiff.h" +#include +#include +#include +#include + #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(patch_data), patch_size)); + Value patch(VAL_BLOB, std::string(reinterpret_cast(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(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(&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(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 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 = const_cast(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(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(&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(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 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 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& 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 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& 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/imgdiff.h b/applypatch/include/applypatch/imgdiff.h new file mode 100644 index 000000000..22cbd4fa0 --- /dev/null +++ b/applypatch/include/applypatch/imgdiff.h @@ -0,0 +1,39 @@ +/* + * 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 _APPLYPATCH_IMGDIFF_H +#define _APPLYPATCH_IMGDIFF_H + +#include + +// 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 + +// 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. +static constexpr size_t GZIP_HEADER_LEN = 10; + +// The gzip footer size really is fixed. +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 + +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 -- cgit v1.2.3 From c8e79340e45d4ff423e11db23cdb6aeb3a178585 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 28 Dec 2016 10:11:22 -0800 Subject: applypatch: Don't expose FindMatchingPatch(). Test: make Change-Id: Ic77c4669574b6129e06aa6051804f419bcc8196c --- applypatch/applypatch.cpp | 2 +- applypatch/include/applypatch/applypatch.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 8682e128b..500663120 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -391,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& patch_sha1_str) { +static int FindMatchingPatch(uint8_t* sha1, const std::vector& 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/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& 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, -- cgit v1.2.3 From d37ce8f0821758edc33ad9c42b0bf78ff29b365f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 17 Dec 2016 17:10:04 -0800 Subject: imgdiff: Fix an edge case that leads to infinite loop. When the input image ends with the magic value sequence of 0x1f, 0x8b, 0x0b (optionally with 0x00), the image parsing code will be stuck in an infinite loop. Test: recovery_component_test passes. Change-Id: Ie3629dfdc41360387b19cc3e0359c95ae4fb998e --- applypatch/Android.mk | 1 + applypatch/imgdiff.cpp | 25 ++++++++++--------------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 61e110617..ec3c6ee38 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -124,6 +124,7 @@ libimgdiff_cflags := \ libimgdiff_static_libraries := \ libbsdiff \ + libbase \ libz # libimgdiff (static library) diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 18a15a164..62de726a4 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -124,6 +124,7 @@ #include "applypatch/imgdiff.h" #include +#include #include #include #include @@ -131,6 +132,9 @@ #include #include +#include +#include + #include #include @@ -382,19 +386,12 @@ unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chu } size_t sz = static_cast(st.st_size); - unsigned char* img = static_cast(malloc(sz + 4)); - FILE* f = fopen(filename, "rb"); - if (fread(img, 1, sz, f) != sz) { + unsigned char* img = static_cast(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; @@ -518,10 +515,8 @@ unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chu 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; } } -- cgit v1.2.3 From 930edb666122d04ffb6a1ff1648181d5b08dda84 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Wed, 18 Jan 2017 17:26:42 -0800 Subject: imgdiff: cache bsdiff suffix array in zip mode. In zip mode, if a chunk is not deflate or its filename can't be found in source chunks, the entire source file is used as old data for bsdiff, To avoid repeatedly construct the suffix array used by bsdiff, we cache the suffix array of the entire source file. Bug: 34281147 Test: =time -v imgdiff -z Chrome-ORF74B.apk Chrome-ORF76B.apk Chrome.imgdiff Change-Id: Ifd957ccecf7226fcb44dbf28c58969a06ef74f4b --- applypatch/Android.mk | 6 +++--- applypatch/imgdiff.cpp | 30 +++++++++++++++++------------- 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index ec3c6ee38..85b5c9fcd 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -124,6 +124,8 @@ libimgdiff_cflags := \ libimgdiff_static_libraries := \ libbsdiff \ + libdivsufsort \ + libdivsufsort64 \ libbase \ libz @@ -166,7 +168,5 @@ LOCAL_CFLAGS := -Werror LOCAL_STATIC_LIBRARIES := \ libimgdiff \ $(libimgdiff_static_libraries) \ - libbz \ - libdivsufsort \ - libdivsufsort64 + libbz include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 62de726a4..395150614 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -615,12 +615,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; @@ -644,7 +644,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; @@ -970,28 +970,31 @@ int imgdiff(int argc, const char** argv) { unsigned char** patch_data = static_cast(malloc( num_tgt_chunks * sizeof(unsigned char*))); size_t* patch_size = static_cast(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); + 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(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(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); } + 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 @@ -1068,6 +1071,7 @@ int imgdiff(int argc, const char** argv) { } } + free(tgt_chunks); free(patch_data); free(patch_size); -- cgit v1.2.3 From 087bc0c7d380fafc41bcc76610bff17f433cecd2 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 19 Jan 2017 10:46:39 -0800 Subject: imgpatch: Compile with ZLIB_CONST defined. So z_stream.next_in takes pointer to const data. Test: mmma bootable/recovery/applypatch Change-Id: If269b766a7c84fa2f67424ee61ba5afab0159261 --- applypatch/Android.mk | 12 +++++++++--- applypatch/imgpatch.cpp | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index ec3c6ee38..3c88d1f58 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -35,7 +35,9 @@ LOCAL_STATIC_LIBRARIES := \ libcrypto \ libbz \ libz -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := \ + -DZLIB_CONST \ + -Werror include $(BUILD_STATIC_LIBRARY) # libimgpatch (static library) @@ -54,7 +56,9 @@ LOCAL_STATIC_LIBRARIES := \ libcrypto \ libbz \ libz -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := \ + -DZLIB_CONST \ + -Werror include $(BUILD_STATIC_LIBRARY) # libimgpatch (host static library) @@ -74,7 +78,9 @@ LOCAL_STATIC_LIBRARIES := \ libcrypto \ libbz \ libz -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := \ + -DZLIB_CONST \ + -Werror include $(BUILD_HOST_STATIC_LIBRARY) # libapplypatch_modes (static library) diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index ae6071f0e..00ea90efa 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -160,7 +160,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = src_len; - strm.next_in = const_cast(old_data + src_start); + strm.next_in = old_data + src_start; strm.avail_out = expanded_len; strm.next_out = expanded_source.data(); -- cgit v1.2.3 From 25c56979dd85a33a6467949ab76f99a987a0a006 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 10 May 2016 15:23:25 -0700 Subject: Use bspatch from external/bsdiff. Now ApplyBSDiffPatch() will stream the output to sink as we go instead of sinking everything at the end. Test: recovery_host_test Bug: 26982501 Change-Id: I05b6ed40d45e4b1b19ae72784cf705b731b976e3 --- applypatch/Android.mk | 4 + applypatch/bspatch.cpp | 204 +++++------------------------------------------- applypatch/imgpatch.cpp | 3 + 3 files changed, 28 insertions(+), 183 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index bdaef1b27..47ddad6c8 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -33,6 +33,7 @@ LOCAL_STATIC_LIBRARIES := \ libotafault \ libbase \ libcrypto \ + libbspatch \ libbz \ libz LOCAL_CFLAGS := \ @@ -54,6 +55,7 @@ LOCAL_C_INCLUDES := \ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ libcrypto \ + libbspatch \ libbz \ libz LOCAL_CFLAGS := \ @@ -76,6 +78,7 @@ LOCAL_C_INCLUDES := \ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ libcrypto \ + libbspatch \ libbz \ libz LOCAL_CFLAGS := \ @@ -111,6 +114,7 @@ LOCAL_STATIC_LIBRARIES := \ libedify \ libotafault \ libcrypto \ + libbspatch \ libbz LOCAL_SHARED_LIBRARIES := \ libbase \ diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index eb45e9ce9..9920c2be1 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp @@ -21,16 +21,12 @@ // notice. #include -#include #include -#include -#include -#include -#include +#include -#include "openssl/sha.h" #include "applypatch/applypatch.h" +#include "openssl/sha.h" void ShowBSDiffLicense() { puts("The bsdiff library used herein is:\n" @@ -64,183 +60,25 @@ void ShowBSDiffLicense() { ); } -static off_t offtin(const u_char *buf) -{ - off_t y; - - y=buf[7]&0x7F; - y=y*256;y+=buf[6]; - y=y*256;y+=buf[5]; - y=y*256;y+=buf[4]; - y=y*256;y+=buf[3]; - y=y*256;y+=buf[2]; - y=y*256;y+=buf[1]; - y=y*256;y+=buf[0]; - - if(buf[7]&0x80) y=-y; - - return y; -} - -int FillBuffer(unsigned char* buffer, int size, bz_stream* stream) { - stream->next_out = (char*)buffer; - stream->avail_out = size; - while (stream->avail_out > 0) { - int bzerr = BZ2_bzDecompress(stream); - if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) { - printf("bz error %d decompressing\n", bzerr); - return -1; - } - if (stream->avail_out > 0) { - printf("need %d more bytes\n", stream->avail_out); - } - } - return 0; +int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, + ssize_t patch_offset, SinkFn sink, void* token, SHA_CTX* ctx) { + auto sha_sink = [&](const uint8_t* data, size_t len) { + len = sink(data, len, token); + if (ctx) SHA1_Update(ctx, data, len); + return len; + }; + return bsdiff::bspatch(old_data, old_size, + reinterpret_cast(&patch->data[patch_offset]), + patch->data.size(), sha_sink); } -int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, - const Value* patch, ssize_t patch_offset, - SinkFn sink, void* token, SHA_CTX* ctx) { - - std::vector new_data; - if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) { - return -1; - } - - if (sink(new_data.data(), new_data.size(), token) < static_cast(new_data.size())) { - printf("short write of output: %d (%s)\n", errno, strerror(errno)); - return 1; - } - if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size()); - return 0; -} - -int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, - const Value* patch, ssize_t patch_offset, - std::vector* new_data) { - // Patch data format: - // 0 8 "BSDIFF40" - // 8 8 X - // 16 8 Y - // 24 8 sizeof(newfile) - // 32 X bzip2(control block) - // 32+X Y bzip2(diff block) - // 32+X+Y ??? bzip2(extra block) - // with control block a set of triples (x,y,z) meaning "add x bytes - // from oldfile to x bytes from the diff block; copy y bytes from the - // extra block; seek forwards in oldfile by z bytes". - - const unsigned char* header = reinterpret_cast(&patch->data[patch_offset]); - if (memcmp(header, "BSDIFF40", 8) != 0) { - printf("corrupt bsdiff patch file header (magic number)\n"); - return 1; - } - - ssize_t ctrl_len, data_len, new_size; - ctrl_len = offtin(header+8); - data_len = offtin(header+16); - new_size = offtin(header+24); - - if (ctrl_len < 0 || data_len < 0 || new_size < 0) { - printf("corrupt patch file header (data lengths)\n"); - return 1; - } - - int bzerr; - - bz_stream cstream; - cstream.next_in = const_cast(&patch->data[patch_offset + 32]); - cstream.avail_in = ctrl_len; - cstream.bzalloc = NULL; - cstream.bzfree = NULL; - cstream.opaque = NULL; - if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) { - printf("failed to bzinit control stream (%d)\n", bzerr); - } - - bz_stream dstream; - dstream.next_in = const_cast(&patch->data[patch_offset + 32 + ctrl_len]); - dstream.avail_in = data_len; - dstream.bzalloc = NULL; - dstream.bzfree = NULL; - dstream.opaque = NULL; - if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) { - printf("failed to bzinit diff stream (%d)\n", bzerr); - } - - bz_stream estream; - estream.next_in = const_cast(&patch->data[patch_offset + 32 + ctrl_len + data_len]); - estream.avail_in = patch->data.size() - (patch_offset + 32 + ctrl_len + data_len); - estream.bzalloc = NULL; - estream.bzfree = NULL; - estream.opaque = NULL; - if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) { - printf("failed to bzinit extra stream (%d)\n", bzerr); - } - - new_data->resize(new_size); - - off_t oldpos = 0, newpos = 0; - off_t ctrl[3]; - int i; - unsigned char buf[24]; - while (newpos < new_size) { - // Read control data - if (FillBuffer(buf, 24, &cstream) != 0) { - printf("error while reading control stream\n"); - return 1; - } - ctrl[0] = offtin(buf); - ctrl[1] = offtin(buf+8); - ctrl[2] = offtin(buf+16); - - if (ctrl[0] < 0 || ctrl[1] < 0) { - printf("corrupt patch (negative byte counts)\n"); - return 1; - } - - // Sanity check - if (newpos + ctrl[0] > new_size) { - printf("corrupt patch (new file overrun)\n"); - return 1; - } - - // Read diff string - if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) { - printf("error while reading diff stream\n"); - return 1; - } - - // Add old data to diff string - for (i = 0; i < ctrl[0]; ++i) { - if ((oldpos+i >= 0) && (oldpos+i < old_size)) { - (*new_data)[newpos+i] += old_data[oldpos+i]; - } - } - - // Adjust pointers - newpos += ctrl[0]; - oldpos += ctrl[0]; - - // Sanity check - if (newpos + ctrl[1] > new_size) { - printf("corrupt patch (new file overrun)\n"); - return 1; - } - - // Read extra string - if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) { - printf("error while reading extra stream\n"); - return 1; - } - - // Adjust pointers - newpos += ctrl[1]; - oldpos += ctrl[2]; - } - - BZ2_bzDecompressEnd(&cstream); - BZ2_bzDecompressEnd(&dstream); - BZ2_bzDecompressEnd(&estream); - return 0; +int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, const Value* patch, + ssize_t patch_offset, std::vector* new_data) { + auto vector_sink = [new_data](const uint8_t* data, size_t len) { + new_data->insert(new_data->end(), data, data + len); + return len; + }; + return bsdiff::bspatch(old_data, old_size, + reinterpret_cast(&patch->data[patch_offset]), + patch->data.size(), vector_sink); } diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 00ea90efa..8f4a2a42b 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -193,6 +193,9 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value // Next, apply the bsdiff patch (in memory) to the uncompressed data. std::vector uncompressed_target_data; + // TODO(senj): Remove the only usage of ApplyBSDiffPatchMem here, + // replace it with ApplyBSDiffPatch with a custom sink function that + // wraps the given sink function to stream output to save memory. if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len, patch, patch_offset, &uncompressed_target_data) != 0) { return -1; -- cgit v1.2.3 From 1ea84d6da97f4c4269ac16c4d332bbff3466b1b8 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 22 Feb 2017 18:23:58 -0800 Subject: Refractor the code for imgdiff Put ImageChunk and some helper functions into a class. Also switch to using std::vector instead of malloc. Bug: 18606652 Test: imgdiff_test passed on host. Also generate a complete incremental OTA package. The file content is the same and time consumption is similar. Change-Id: Id603ada4e130ef521218400761a119001a86ca79 --- applypatch/Android.mk | 3 + applypatch/imgdiff.cpp | 1211 ++++++++++++++++++++++++------------------------ 2 files changed, 596 insertions(+), 618 deletions(-) (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 47ddad6c8..8be5c36be 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -136,6 +136,9 @@ libimgdiff_static_libraries := \ libbsdiff \ libdivsufsort \ libdivsufsort64 \ + libziparchive \ + libutils \ + liblog \ libbase \ libz diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 2f0e1651c..fba74e836 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -132,502 +132,611 @@ #include #include +#include +#include +#include + #include +#include +#include #include +#include #include #include #include "utils.h" -typedef struct { - int type; // CHUNK_NORMAL, CHUNK_DEFLATE - size_t start; // offset of chunk in original image file +using android::base::get_unaligned; + +static constexpr auto BUFFER_SIZE = 0x8000; + +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* file_content, size_t raw_data_len) + : type_(type), + start_(start), + input_file_ptr_(file_content), + raw_data_len_(raw_data_len), + entry_name_(""), + compress_level_(6), + source_start_(0), + source_len_(0), + source_uncompressed_len_(0) {} + + int GetType() const { + return type_; + } + size_t GetRawDataLength() const { + return raw_data_len_; + } + const std::string& GetEntryName() const { + return entry_name_; + } - size_t len; - unsigned char* data; // data to be patched (uncompressed, for deflate chunks) + // 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; - size_t source_start; - size_t source_len; + void Dump() const { + printf("type %d start %zu len %zu\n", type_, start_, DataLengthForPatch()); + } - // --- for CHUNK_DEFLATE chunks only: --- + void SetSourceInfo(const ImageChunk& other); + void SetEntryName(std::string entryname); + void SetUncompressedData(std::vector data); + bool SetBonusData(const std::vector& bonus_data); + + bool operator==(const ImageChunk& other) const; + bool operator!=(const ImageChunk& other) const { + return !(*this == other); + } - // original (compressed) deflate data - size_t deflate_len; - unsigned char* deflate_data; + size_t GetHeaderSize(size_t patch_size) const; + size_t WriteHeaderToFile(FILE* f, const std::vector patch, size_t offset); + + /* + * 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(); + bool ChangeChunkToRaw(size_t patch_size); + + /* + * 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); + + private: + int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW + size_t start_; // offset of chunk in the original input file + const std::vector* input_file_ptr_; // pointer to the full content of original input file + size_t raw_data_len_; - char* filename; // used for zip entries + // --- for CHUNK_DEFLATE chunks only: --- + std::vector uncompressed_data_; + std::string entry_name_; // used for zip entries // deflate encoder parameters - int level, method, windowBits, memLevel, strategy; - - size_t source_uncompressed_len; -} ImageChunk; - -typedef struct { - int data_offset; - int deflate_len; - int uncomp_len; - char* filename; -} ZipFileEntry; - -static int fileentry_compare(const void* a, const void* b) { - int ao = ((ZipFileEntry*)a)->data_offset; - int bo = ((ZipFileEntry*)b)->data_offset; - if (ao < bo) { - return -1; - } else if (ao > bo) { - return 1; - } else { - return 0; - } + int compress_level_; + + size_t source_start_; + size_t source_len_; + size_t source_uncompressed_len_; + + const uint8_t* GetRawData() const; + bool TryReconstruction(int level); +}; + +const uint8_t* ImageChunk::GetRawData() const { + CHECK_LE(start_ + raw_data_len_, input_file_ptr_->size()); + return input_file_ptr_->data() + start_; } -unsigned char* ReadZip(const char* filename, - int* num_chunks, ImageChunk** chunks, - int include_pseudo_chunk) { - struct stat st; - if (stat(filename, &st) != 0) { - printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); - return NULL; +const uint8_t * ImageChunk::DataForPatch() const { + if (type_ == CHUNK_DEFLATE) { + return uncompressed_data_.data(); } + return GetRawData(); +} - size_t sz = static_cast(st.st_size); - unsigned char* img = static_cast(malloc(sz)); - FILE* f = fopen(filename, "rb"); - if (fread(img, 1, sz, f) != sz) { - printf("failed to read \"%s\" %s\n", filename, strerror(errno)); - fclose(f); - free(img); - return NULL; +size_t ImageChunk::DataLengthForPatch() const { + if (type_ == CHUNK_DEFLATE) { + return uncompressed_data_.size(); } - fclose(f); + return raw_data_len_; +} - // look for the end-of-central-directory record. +bool ImageChunk::operator==(const ImageChunk& other) const { + if (type_ != other.type_) { + return false; + } + return (raw_data_len_ == other.raw_data_len_ && + memcmp(GetRawData(), other.GetRawData(), raw_data_len_) == 0); +} - int i; - for (i = st.st_size-20; i >= 0 && i > st.st_size - 65600; --i) { - if (img[i] == 0x50 && img[i+1] == 0x4b && - img[i+2] == 0x05 && img[i+3] == 0x06) { - break; - } +void ImageChunk::SetSourceInfo(const ImageChunk& src) { + source_start_ = src.start_; + if (type_ == CHUNK_NORMAL) { + source_len_ = src.raw_data_len_; + } else if (type_ == CHUNK_DEFLATE) { + source_len_ = src.raw_data_len_; + source_uncompressed_len_ = src.uncompressed_data_.size(); } - // double-check: this archive consists of a single "disk" - if (!(img[i+4] == 0 && img[i+5] == 0 && img[i+6] == 0 && img[i+7] == 0)) { - printf("can't process multi-disk archive\n"); - return NULL; +} + +void ImageChunk::SetEntryName(std::string entryname) { + entry_name_ = entryname; +} + +void ImageChunk::SetUncompressedData(std::vector data) { + uncompressed_data_ = data; +} + +bool ImageChunk::SetBonusData(const std::vector& bonus_data) { + if (type_ != CHUNK_DEFLATE) { + return false; } + uncompressed_data_.insert(uncompressed_data_.end(), bonus_data.begin(), bonus_data.end()); + return true; +} - int cdcount = Read2(img+i+8); - int cdoffset = Read4(img+i+16); +// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the terget size is +// smaller. Also take the header size into account during size comparison. +bool ImageChunk::ChangeChunkToRaw(size_t patch_size) { + if (type_ == CHUNK_RAW) { + return true; + } else if (type_ == CHUNK_NORMAL && (raw_data_len_ <= 160 || raw_data_len_ < patch_size)) { + type_ = CHUNK_RAW; + return true; + } + return false; +} - ZipFileEntry* temp_entries = static_cast(malloc( - cdcount * sizeof(ZipFileEntry))); - int entrycount = 0; +void ImageChunk::ChangeDeflateChunkToNormal() { + if (type_ != CHUNK_DEFLATE) return; + type_ = CHUNK_NORMAL; + uncompressed_data_.clear(); +} - unsigned char* cd = img+cdoffset; - for (i = 0; i < cdcount; ++i) { - if (!(cd[0] == 0x50 && cd[1] == 0x4b && cd[2] == 0x01 && cd[3] == 0x02)) { - printf("bad central directory entry %d\n", i); - free(temp_entries); - return NULL; - } +// Header size: +// header_type 4 bytes +// CHUNK_NORMAL 8*3 = 24 bytes +// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes +// CHUNK_RAW 4 bytes +size_t ImageChunk::GetHeaderSize(size_t patch_size) const { + switch (type_) { + case CHUNK_NORMAL: + return 4 + 8 * 3; + case CHUNK_DEFLATE: + return 4 + 8 * 5 + 4 * 5; + case CHUNK_RAW: + return 4 + 4 + patch_size; + default: + printf("unexpected chunk type: %d\n", type_); // should not reach here. + CHECK(false); + return 0; + } +} - int clen = Read4(cd+20); // compressed len - int ulen = Read4(cd+24); // uncompressed len - int nlen = Read2(cd+28); // filename len - int xlen = Read2(cd+30); // extra field len - int mlen = Read2(cd+32); // file comment len - int hoffset = Read4(cd+42); // local header offset +size_t ImageChunk::WriteHeaderToFile(FILE* f, const std::vector patch, size_t offset) { + Write4(type_, f); + switch (type_) { + case CHUNK_NORMAL: + printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size()); + Write8(source_start_, f); + Write8(source_len_, f); + Write8(offset, f); + return offset + patch.size(); + case CHUNK_DEFLATE: + printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(), + entry_name_.c_str()); + Write8(source_start_, f); + Write8(source_len_, f); + Write8(offset, f); + Write8(source_uncompressed_len_, f); + Write8(uncompressed_data_.size(), f); + Write4(compress_level_, f); + Write4(METHOD, f); + Write4(WINDOWBITS, f); + Write4(MEMLEVEL, f); + Write4(STRATEGY, f); + return offset + patch.size(); + case CHUNK_RAW: + printf("raw (%10zu, %10zu)\n", start_, raw_data_len_); + Write4(patch.size(), f); + fwrite(patch.data(), 1, patch.size(), f); + return offset; + default: + printf("unexpected chunk type: %d\n", type_); + CHECK(false); + return offset; + } +} - char* filename = static_cast(malloc(nlen+1)); - memcpy(filename, cd+46, nlen); - filename[nlen] = '\0'; +bool ImageChunk::IsAdjacentNormal(const ImageChunk& other) const { + if (type_ != CHUNK_NORMAL || other.type_ != CHUNK_NORMAL) { + return false; + } + return (other.start_ == start_ + raw_data_len_); +} - int method = Read2(cd+10); +void ImageChunk::MergeAdjacentNormal(const ImageChunk& other) { + CHECK(IsAdjacentNormal(other)); + raw_data_len_ = raw_data_len_ + other.raw_data_len_; +} - cd += 46 + nlen + xlen + mlen; +bool ImageChunk::ReconstructDeflateChunk() { + if (type_ != CHUNK_DEFLATE) { + printf("attempt to reconstruct non-deflate chunk\n"); + return false; + } - if (method != 8) { // 8 == deflate - free(filename); - continue; + // We only check two combinations of encoder parameters: level 6 + // (the default) and level 9 (the maximum). + for (int level = 6; level <= 9; level += 3) { + if (TryReconstruction(level)) { + compress_level_ = level; + return true; } + } + + return false; +} - unsigned char* lh = img + hoffset; +/* + * Takes the uncompressed data stored in the chunk, compresses it + * using the zlib parameters stored in the chunk, and checks that it + * matches exactly the compressed data we started with (also stored in + * the chunk). + */ +bool ImageChunk::TryReconstruction(int level) { + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = uncompressed_data_.size(); + strm.next_in = uncompressed_data_.data(); + int ret = deflateInit2(&strm, level, METHOD, WINDOWBITS, MEMLEVEL, STRATEGY); + if (ret < 0) { + printf("failed to initialize deflate: %d\n", ret); + return false; + } - if (!(lh[0] == 0x50 && lh[1] == 0x4b && lh[2] == 0x03 && lh[3] == 0x04)) { - printf("bad local file header entry %d\n", i); - return NULL; + std::vector buffer(BUFFER_SIZE); + size_t offset = 0; + do { + strm.avail_out = buffer.size(); + strm.next_out = buffer.data(); + ret = deflate(&strm, Z_FINISH); + if (ret < 0) { + printf("failed to deflate: %d\n", ret); + return false; } - if (Read2(lh+26) != nlen || memcmp(lh+30, filename, nlen) != 0) { - printf("central dir filename doesn't match local header\n"); - return NULL; + size_t compressed_size = buffer.size() - strm.avail_out; + if (memcmp(buffer.data(), input_file_ptr_->data() + start_ + offset, compressed_size) != 0) { + // mismatch; data isn't the same. + deflateEnd(&strm); + return false; } + offset += compressed_size; + } while (ret != Z_STREAM_END); + deflateEnd(&strm); - xlen = Read2(lh+28); // extra field len; might be different from CD entry? + if (offset != raw_data_len_) { + // mismatch; ran out of data before we should have. + return false; + } + return true; +} - temp_entries[entrycount].data_offset = hoffset+30+nlen+xlen; - temp_entries[entrycount].deflate_len = clen; - temp_entries[entrycount].uncomp_len = ulen; - temp_entries[entrycount].filename = filename; - ++entrycount; +// EOCD record +// offset 0: signature 0x06054b50, 4 bytes +// offset 4: number of this disk, 2 bytes +// ... +// offset 20: comment length, 2 bytes +// offset 22: comment, n bytes +static bool GetZipFileSize(const std::vector& zip_file, size_t* input_file_size) { + if (zip_file.size() < 22) { + printf("file is too small to be a zip file\n"); + return false; } - qsort(temp_entries, entrycount, sizeof(ZipFileEntry), fileentry_compare); - -#if 0 - printf("found %d deflated entries\n", entrycount); - for (i = 0; i < entrycount; ++i) { - printf("off %10d len %10d unlen %10d %p %s\n", - temp_entries[i].data_offset, - temp_entries[i].deflate_len, - temp_entries[i].uncomp_len, - temp_entries[i].filename, - temp_entries[i].filename); + // Look for End of central directory record of the zip file, and calculate the actual + // zip_file size. + for (int i = zip_file.size() - 22; i >= 0; i--) { + if (zip_file[i] == 0x50) { + if (get_unaligned(&zip_file[i]) == 0x06054b50) { + // double-check: this archive consists of a single "disk". + CHECK_EQ(get_unaligned(&zip_file[i + 4]), 0); + + uint16_t comment_length = get_unaligned(&zip_file[i + 20]); + size_t file_size = i + 22 + comment_length; + CHECK_LE(file_size, zip_file.size()); + *input_file_size = file_size; + return true; + } + } } -#endif - *num_chunks = 0; - *chunks = static_cast(malloc((entrycount*2+2) * sizeof(ImageChunk))); - ImageChunk* curr = *chunks; + // EOCD not found, this file is likely not a valid zip file. + return false; +} - if (include_pseudo_chunk) { - curr->type = CHUNK_NORMAL; - curr->start = 0; - curr->len = st.st_size; - curr->data = img; - curr->filename = NULL; - ++curr; - ++*num_chunks; +static bool ReadZip(const char* filename, std::vector* chunks, + std::vector* zip_file, bool include_pseudo_chunk) { + CHECK(zip_file != nullptr); + struct stat st; + if (stat(filename, &st) != 0) { + printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); + return false; } - int pos = 0; - int nextentry = 0; + size_t sz = static_cast(st.st_size); + 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)) { + printf("failed to read \"%s\" %s\n", filename, strerror(errno)); + return false; + } + fd.reset(); - while (pos < st.st_size) { - if (nextentry < entrycount && pos == temp_entries[nextentry].data_offset) { - curr->type = CHUNK_DEFLATE; - curr->start = pos; - curr->deflate_len = temp_entries[nextentry].deflate_len; - curr->deflate_data = img + pos; - curr->filename = temp_entries[nextentry].filename; + // Trim the trailing zeros before we pass the file to ziparchive handler. + size_t zipfile_size; + if (!GetZipFileSize(*zip_file, &zipfile_size)) { + printf("failed to parse the actual size of %s\n", filename); + return false; + } + ZipArchiveHandle handle; + int err = OpenArchiveFromMemory(zip_file->data(), zipfile_size, filename, &handle); + if (err != 0) { + printf("failed to open zip file %s: %s\n", filename, ErrorCodeString(err)); + CloseArchive(handle); + return false; + } - curr->len = temp_entries[nextentry].uncomp_len; - curr->data = static_cast(malloc(curr->len)); + // Create a list of deflated zip entries, sorted by offset. + std::vector> temp_entries; + void* cookie; + int ret = StartIteration(handle, &cookie, nullptr, nullptr); + if (ret != 0) { + printf("failed to iterate over entries in %s: %s\n", filename, ErrorCodeString(ret)); + CloseArchive(handle); + return false; + } - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = curr->deflate_len; - strm.next_in = curr->deflate_data; + ZipString name; + ZipEntry entry; + while ((ret = Next(cookie, &entry, &name)) == 0) { + if (entry.method == kCompressDeflated) { + std::string entryname(name.name, name.name + name.name_length); + temp_entries.push_back(std::make_pair(entryname, entry)); + } + } - // -15 means we are decoding a 'raw' deflate stream; zlib will - // not expect zlib headers. - int ret = inflateInit2(&strm, -15); - if (ret < 0) { - printf("failed to initialize inflate: %d\n", ret); - return NULL; - } + if (ret != -1) { + printf("Error while iterating over zip entries: %s\n", ErrorCodeString(ret)); + CloseArchive(handle); + return false; + } + std::sort(temp_entries.begin(), temp_entries.end(), + [](auto& entry1, auto& entry2) { + return entry1.second.offset < entry2.second.offset; + }); + + EndIteration(cookie); + + if (include_pseudo_chunk) { + chunks->emplace_back(CHUNK_NORMAL, 0, zip_file, zip_file->size()); + } - strm.avail_out = curr->len; - strm.next_out = curr->data; - ret = inflate(&strm, Z_NO_FLUSH); - if (ret != Z_STREAM_END) { - printf("failed to inflate \"%s\"; %d\n", curr->filename, ret); - return NULL; + size_t pos = 0; + size_t nextentry = 0; + while (pos < zip_file->size()) { + if (nextentry < temp_entries.size() && + static_cast(pos) == temp_entries[nextentry].second.offset) { + // compose the next deflate chunk. + std::string entryname = temp_entries[nextentry].first; + size_t uncompressed_len = temp_entries[nextentry].second.uncompressed_length; + std::vector uncompressed_data(uncompressed_len); + if ((ret = ExtractToMemory(handle, &temp_entries[nextentry].second, uncompressed_data.data(), + uncompressed_len)) != 0) { + printf("failed to extract %s with size %zu: %s\n", entryname.c_str(), uncompressed_len, + ErrorCodeString(ret)); + CloseArchive(handle); + return false; } - inflateEnd(&strm); + size_t compressed_len = temp_entries[nextentry].second.compressed_length; + ImageChunk curr(CHUNK_DEFLATE, pos, zip_file, compressed_len); + curr.SetEntryName(std::move(entryname)); + curr.SetUncompressedData(std::move(uncompressed_data)); + chunks->push_back(curr); - pos += curr->deflate_len; + pos += compressed_len; ++nextentry; - ++*num_chunks; - ++curr; continue; } - // use a normal chunk to take all the data up to the start of the - // next deflate section. - - curr->type = CHUNK_NORMAL; - curr->start = pos; - if (nextentry < entrycount) { - curr->len = temp_entries[nextentry].data_offset - pos; + // Use a normal chunk to take all the data up to the start of the next deflate section. + size_t raw_data_len; + if (nextentry < temp_entries.size()) { + raw_data_len = temp_entries[nextentry].second.offset - pos; } else { - curr->len = st.st_size - pos; + raw_data_len = zip_file->size() - pos; } - curr->data = img + pos; - curr->filename = NULL; - pos += curr->len; + chunks->emplace_back(CHUNK_NORMAL, pos, zip_file, raw_data_len); - ++*num_chunks; - ++curr; + pos += raw_data_len; } - free(temp_entries); - return img; + CloseArchive(handle); + return true; } -/* - * Read the given file and break it up into chunks, putting the number - * of chunks and their info in *num_chunks and **chunks, - * respectively. Returns a malloc'd block of memory containing the - * contents of the file; various pointers in the output chunk array - * will point into this block of memory. The caller should free the - * return value when done with all the chunks. Returns NULL on - * failure. - */ -unsigned char* ReadImage(const char* filename, int* num_chunks, ImageChunk** chunks) { +// 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* chunks, + std::vector* img) { + CHECK(img != nullptr); struct stat st; if (stat(filename, &st) != 0) { printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); - return NULL; + return false; } size_t sz = static_cast(st.st_size); - unsigned char* img = static_cast(malloc(sz)); + img->resize(sz); android::base::unique_fd fd(open(filename, O_RDONLY)); - if (!android::base::ReadFully(fd, img, sz)) { + if (fd == -1) { + printf("failed to open \"%s\" %s\n", filename, strerror(errno)); + return false; + } + if (!android::base::ReadFully(fd, img->data(), sz)) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); - return nullptr; + return false; } size_t pos = 0; - *num_chunks = 0; - *chunks = NULL; - while (pos < sz) { - unsigned char* p = img + pos; - - if (sz - pos >= 4 && - p[0] == 0x1f && p[1] == 0x8b && - p[2] == 0x08 && // deflate compression - p[3] == 0x00) { // no header flags + if (sz - pos >= 4 && img->at(pos) == 0x1f && img->at(pos + 1) == 0x8b && + img->at(pos + 2) == 0x08 && // deflate compression + img->at(pos + 3) == 0x00) { // no header flags // 'pos' is the offset of the start of a gzip chunk. size_t chunk_offset = pos; - *num_chunks += 3; - *chunks = static_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); - ImageChunk* curr = *chunks + (*num_chunks-3); - - // create a normal chunk for the header. - curr->start = pos; - curr->type = CHUNK_NORMAL; - curr->len = GZIP_HEADER_LEN; - curr->data = p; - - pos += curr->len; - p += curr->len; - ++curr; - - curr->type = CHUNK_DEFLATE; - curr->filename = NULL; + // The remaining data is too small to be a gzip chunk; treat them as a normal chunk. + if (sz - pos < GZIP_HEADER_LEN + GZIP_FOOTER_LEN) { + chunks->emplace_back(CHUNK_NORMAL, pos, img, sz - pos); + break; + } - // We must decompress this chunk in order to discover where it - // ends, and so we can put the uncompressed data and its length - // into curr->data and curr->len. + // We need three chunks for the deflated image in total, one normal chunk for the header, + // one deflated chunk for the body, and another normal chunk for the footer. + chunks->emplace_back(CHUNK_NORMAL, pos, img, GZIP_HEADER_LEN); + pos += GZIP_HEADER_LEN; - size_t allocated = 32768; - curr->len = 0; - curr->data = static_cast(malloc(allocated)); - curr->start = pos; - curr->deflate_data = p; + // We must decompress this chunk in order to discover where it ends, and so we can update + // the uncompressed_data of the image body and its length. z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = sz - pos; - strm.next_in = p; + strm.next_in = img->data() + pos; // -15 means we are decoding a 'raw' deflate stream; zlib will // not expect zlib headers. int ret = inflateInit2(&strm, -15); if (ret < 0) { printf("failed to initialize inflate: %d\n", ret); - return NULL; + return false; } + size_t allocated = BUFFER_SIZE; + std::vector uncompressed_data(allocated); + size_t uncompressed_len = 0, raw_data_len = 0; do { - strm.avail_out = allocated - curr->len; - strm.next_out = curr->data + curr->len; + strm.avail_out = allocated - uncompressed_len; + strm.next_out = uncompressed_data.data() + uncompressed_len; ret = inflate(&strm, Z_NO_FLUSH); if (ret < 0) { - printf("Warning: inflate failed [%s] at offset [%zu]," - " treating as a normal chunk\n", + printf("Warning: inflate failed [%s] at offset [%zu], treating as a normal chunk\n", strm.msg, chunk_offset); break; } - curr->len = allocated - strm.avail_out; + uncompressed_len = allocated - strm.avail_out; if (strm.avail_out == 0) { allocated *= 2; - curr->data = static_cast(realloc(curr->data, allocated)); + uncompressed_data.resize(allocated); } } while (ret != Z_STREAM_END); - curr->deflate_len = sz - strm.avail_in - pos; + raw_data_len = sz - strm.avail_in - pos; inflateEnd(&strm); if (ret < 0) { - free(curr->data); - *num_chunks -= 2; continue; } - pos += curr->deflate_len; - p += curr->deflate_len; - ++curr; + ImageChunk body(CHUNK_DEFLATE, pos, img, raw_data_len); + uncompressed_data.resize(uncompressed_len); + body.SetUncompressedData(std::move(uncompressed_data)); + chunks->push_back(body); - // create a normal chunk for the footer + pos += raw_data_len; - curr->type = CHUNK_NORMAL; - curr->start = pos; - curr->len = GZIP_FOOTER_LEN; - curr->data = img+pos; + // create a normal chunk for the footer + chunks->emplace_back(CHUNK_NORMAL, pos, img, GZIP_FOOTER_LEN); - pos += curr->len; - p += curr->len; - ++curr; + pos += GZIP_FOOTER_LEN; // The footer (that we just skipped over) contains the size of // the uncompressed data. Double-check to make sure that it // matches the size of the data we got when we actually did // 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); - free(img); - return NULL; + size_t footer_size = Read4(img->data() + pos - 4); + if (footer_size != body.DataLengthForPatch()) { + printf("Error: footer size %zu != decompressed size %zu\n", footer_size, + body.GetRawDataLength()); + return false; } } else { - // Reallocate the list for every chunk; we expect the number of - // chunks to be small (5 for typical boot and recovery images). - ++*num_chunks; - *chunks = static_cast(realloc(*chunks, *num_chunks * sizeof(ImageChunk))); - ImageChunk* curr = *chunks + (*num_chunks-1); - curr->start = pos; - - // 'pos' is not the offset of the start of a gzip chunk, so scan - // forward until we find a gzip header. - curr->type = CHUNK_NORMAL; - curr->data = p; - - for (curr->len = 0; curr->len < (sz - pos); ++curr->len) { - if (sz - pos >= 4 && p[curr->len] == 0x1f && p[curr->len + 1] == 0x8b && - p[curr->len + 2] == 0x08 && p[curr->len + 3] == 0x00) { + // Use a normal chunk to take all the contents until the next gzip chunk (or EOF); we expect + // the number of chunks to be small (5 for typical boot and recovery images). + + // Scan forward until we find a gzip header. + size_t data_len = 0; + while (data_len + pos < sz) { + if (data_len + pos + 4 <= sz && img->at(pos + data_len) == 0x1f && + img->at(pos + data_len + 1) == 0x8b && img->at(pos + data_len + 2) == 0x08 && + img->at(pos + data_len + 3) == 0x00) { break; } + data_len++; } - pos += curr->len; - } - } - - return img; -} - -#define BUFFER_SIZE 32768 - -/* - * Takes the uncompressed data stored in the chunk, compresses it - * using the zlib parameters stored in the chunk, and checks that it - * matches exactly the compressed data we started with (also stored in - * the chunk). Return 0 on success. - */ -int TryReconstruction(ImageChunk* chunk, unsigned char* out) { - size_t p = 0; - -#if 0 - printf("trying %d %d %d %d %d\n", - chunk->level, chunk->method, chunk->windowBits, - chunk->memLevel, chunk->strategy); -#endif - - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = chunk->len; - strm.next_in = chunk->data; - int ret; - ret = deflateInit2(&strm, chunk->level, chunk->method, chunk->windowBits, - chunk->memLevel, chunk->strategy); - if (ret < 0) { - printf("failed to initialize deflate: %d\n", ret); - return -1; - } - do { - strm.avail_out = BUFFER_SIZE; - strm.next_out = out; - ret = deflate(&strm, Z_FINISH); - if (ret < 0) { - printf("failed to deflate: %d\n", ret); - return -1; - } - size_t have = BUFFER_SIZE - strm.avail_out; - - if (memcmp(out, chunk->deflate_data+p, have) != 0) { - // mismatch; data isn't the same. - deflateEnd(&strm); - return -1; - } - p += have; - } while (ret != Z_STREAM_END); - deflateEnd(&strm); - if (p != chunk->deflate_len) { - // mismatch; ran out of data before we should have. - return -1; - } - return 0; -} - -/* - * 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. Returns 0 on success. - */ -int ReconstructDeflateChunk(ImageChunk* chunk) { - if (chunk->type != CHUNK_DEFLATE) { - printf("attempt to reconstruct non-deflate chunk\n"); - return -1; - } + chunks->emplace_back(CHUNK_NORMAL, pos, img, data_len); - unsigned char* out = static_cast(malloc(BUFFER_SIZE)); - - // We only check two combinations of encoder parameters: level 6 - // (the default) and level 9 (the maximum). - for (chunk->level = 6; chunk->level <= 9; chunk->level += 3) { - chunk->windowBits = -15; // 32kb window; negative to indicate a raw stream. - chunk->memLevel = 8; // the default value. - chunk->method = Z_DEFLATED; - chunk->strategy = Z_DEFAULT_STRATEGY; - - if (TryReconstruction(chunk, out) == 0) { - free(out); - return 0; + pos += data_len; } } - free(out); - return -1; + return true; } /* * Given source and target chunks, compute a bsdiff patch between them. - * Return the patch data, placing its length in *size. Return NULL on failure. + * 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. */ -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; - *size = tgt->len; - return tgt->data; - } +static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector* patch_data, + saidx_t** bsdiff_cache) { + if (tgt->ChangeChunkToRaw(0)) { + size_t patch_size = tgt->DataLengthForPatch(); + patch_data->resize(patch_size); + std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin()); + return true; } #if defined(__ANDROID__) @@ -635,104 +744,51 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size, saidx_t #else char ptemp[] = "/tmp/imgdiff-patch-XXXXXX"; #endif - int fd = mkstemp(ptemp); + int fd = mkstemp(ptemp); if (fd == -1) { - printf("MakePatch failed to create a temporary file: %s\n", - strerror(errno)); - return NULL; + printf("MakePatch failed to create a temporary file: %s\n", strerror(errno)); + return false; } - close(fd); // temporary file is created and we don't need its file - // descriptor + close(fd); - int r = bsdiff::bsdiff(src->data, src->len, tgt->data, tgt->len, ptemp, bsdiff_cache); + int r = bsdiff::bsdiff(src->DataForPatch(), src->DataLengthForPatch(), tgt->DataForPatch(), + tgt->DataLengthForPatch(), ptemp, bsdiff_cache); if (r != 0) { printf("bsdiff() failed: %d\n", r); - return NULL; + return false; } struct stat st; if (stat(ptemp, &st) != 0) { - printf("failed to stat patch file %s: %s\n", - ptemp, strerror(errno)); - return NULL; + printf("failed to stat patch file %s: %s\n", ptemp, strerror(errno)); + return false; } size_t sz = static_cast(st.st_size); - // TODO: Memory leak on error return. - unsigned char* data = static_cast(malloc(sz)); - - if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) { + if (tgt->ChangeChunkToRaw(sz)) { unlink(ptemp); - - tgt->type = CHUNK_RAW; - *size = tgt->len; - return tgt->data; + size_t patch_size = tgt->DataLengthForPatch(); + patch_data->resize(patch_size); + std::copy(tgt->DataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin()); + return true; } - *size = sz; - - FILE* f = fopen(ptemp, "rb"); - if (f == NULL) { - printf("failed to open patch %s: %s\n", ptemp, strerror(errno)); - return NULL; + 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; } - if (fread(data, 1, sz, f) != sz) { - printf("failed to read patch %s: %s\n", ptemp, strerror(errno)); - return NULL; + patch_data->resize(sz); + if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) { + printf("failed to read \"%s\" %s\n", ptemp, strerror(errno)); + return false; } - fclose(f); unlink(ptemp); + tgt->SetSourceInfo(*src); - tgt->source_start = src->start; - switch (tgt->type) { - case CHUNK_NORMAL: - tgt->source_len = src->len; - break; - case CHUNK_DEFLATE: - tgt->source_len = src->deflate_len; - tgt->source_uncompressed_len = src->len; - break; - } - - return data; -} - -/* - * 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(ImageChunk* ch) { - if (ch->type != CHUNK_DEFLATE) return; - ch->type = CHUNK_NORMAL; - free(ch->data); - ch->data = ch->deflate_data; - ch->len = ch->deflate_len; -} - -/* - * Return true if the data in the chunk is identical (including the - * compressed representation, for gzip chunks). - */ -int AreChunksEqual(ImageChunk* a, ImageChunk* b) { - if (a->type != b->type) return 0; - - switch (a->type) { - case CHUNK_NORMAL: - return a->len == b->len && memcmp(a->data, b->data, a->len) == 0; - - case CHUNK_DEFLATE: - return a->deflate_len == b->deflate_len && - memcmp(a->deflate_data, b->deflate_data, a->deflate_len) == 0; - - default: - printf("unknown chunk type %d\n", a->type); - return 0; - } + return true; } /* @@ -740,71 +796,42 @@ int AreChunksEqual(ImageChunk* a, ImageChunk* b) { * a single chunk. (Such runs can be produced when deflate chunks are * changed to normal chunks.) */ -void MergeAdjacentNormalChunks(ImageChunk* chunks, int* num_chunks) { - int out = 0; - int in_start = 0, in_end; - while (in_start < *num_chunks) { - if (chunks[in_start].type != CHUNK_NORMAL) { - in_end = in_start+1; - } else { - // in_start is a normal chunk. Look for a run of normal chunks - // that constitute a solid block of data (ie, each chunk begins - // where the previous one ended). - for (in_end = in_start+1; - in_end < *num_chunks && chunks[in_end].type == CHUNK_NORMAL && - (chunks[in_end].start == - chunks[in_end-1].start + chunks[in_end-1].len && - chunks[in_end].data == - chunks[in_end-1].data + chunks[in_end-1].len); - ++in_end); +static void MergeAdjacentNormalChunks(std::vector* chunks) { + size_t merged_last = 0, cur = 0; + while (cur < chunks->size()) { + // Look for normal chunks adjacent to the current one. If such chunk exists, extend the + // length of the current normal chunk. + size_t to_check = cur + 1; + while (to_check < chunks->size() && chunks->at(cur).IsAdjacentNormal(chunks->at(to_check))) { + chunks->at(cur).MergeAdjacentNormal(chunks->at(to_check)); + to_check++; } - if (in_end == in_start+1) { -#if 0 - printf("chunk %d is now %d\n", in_start, out); -#endif - if (out != in_start) { - memcpy(chunks+out, chunks+in_start, sizeof(ImageChunk)); - } - } else { -#if 0 - printf("collapse normal chunks %d-%d into %d\n", in_start, in_end-1, out); -#endif - - // Merge chunks [in_start, in_end-1] into one chunk. Since the - // data member of each chunk is just a pointer into an in-memory - // copy of the file, this can be done without recopying (the - // output chunk has the first chunk's start location and data - // pointer, and length equal to the sum of the input chunk - // lengths). - chunks[out].type = CHUNK_NORMAL; - chunks[out].start = chunks[in_start].start; - chunks[out].data = chunks[in_start].data; - chunks[out].len = chunks[in_end-1].len + - (chunks[in_end-1].start - chunks[in_start].start); + if (merged_last != cur) { + chunks->at(merged_last) = std::move(chunks->at(cur)); } - - ++out; - in_start = in_end; + merged_last++; + cur = to_check; + } + if (merged_last < chunks->size()) { + chunks->erase(chunks->begin() + merged_last, chunks->end()); } - *num_chunks = out; } -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; +static ImageChunk* FindChunkByName(const std::string& name, std::vector& chunks) { + for (size_t i = 0; i < chunks.size(); ++i) { + if (chunks[i].GetType() == CHUNK_DEFLATE && chunks[i].GetEntryName() == name) { + return &chunks[i]; } } - return NULL; + return nullptr; } -void DumpChunks(ImageChunk* chunks, int num_chunks) { - for (int i = 0; i < num_chunks; ++i) { - printf("chunk %d: type %d start %zu len %zu\n", - i, chunks[i].type, chunks[i].start, chunks[i].len); - } +static void DumpChunks(const std::vector& chunks) { + for (size_t i = 0; i < chunks.size(); ++i) { + printf("chunk %zu: ", i); + chunks[i].Dump(); + } } int imgdiff(int argc, const char** argv) { @@ -816,26 +843,24 @@ int imgdiff(int argc, const char** argv) { ++argv; } - size_t bonus_size = 0; - unsigned char* bonus_data = NULL; + std::vector bonus_data; 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; } - bonus_size = st.st_size; - bonus_data = static_cast(malloc(bonus_size)); - FILE* f = fopen(argv[2], "rb"); - if (f == NULL) { + size_t bonus_size = st.st_size; + bonus_data.resize(bonus_size); + android::base::unique_fd fd(open(argv[2], O_RDONLY)); + if (fd == -1) { printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno)); return 1; } - if (fread(bonus_data, 1, bonus_size, f) != 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)); return 1; } - fclose(f); argc -= 2; argv += 2; @@ -847,27 +872,26 @@ int imgdiff(int argc, const char** argv) { return 2; } - int num_src_chunks; - ImageChunk* src_chunks; - int num_tgt_chunks; - ImageChunk* tgt_chunks; - int i; + std::vector src_chunks; + std::vector tgt_chunks; + std::vector src_file; + std::vector tgt_file; if (zip_mode) { - if (ReadZip(argv[1], &num_src_chunks, &src_chunks, 1) == NULL) { + if (!ReadZip(argv[1], &src_chunks, &src_file, true)) { printf("failed to break apart source zip file\n"); return 1; } - if (ReadZip(argv[2], &num_tgt_chunks, &tgt_chunks, 0) == NULL) { + if (!ReadZip(argv[2], &tgt_chunks, &tgt_file, false)) { printf("failed to break apart target zip file\n"); return 1; } } else { - if (ReadImage(argv[1], &num_src_chunks, &src_chunks) == NULL) { + if (!ReadImage(argv[1], &src_chunks, &src_file)) { printf("failed to break apart source image\n"); return 1; } - if (ReadImage(argv[2], &num_tgt_chunks, &tgt_chunks) == NULL) { + if (!ReadImage(argv[2], &tgt_chunks, &tgt_file)) { printf("failed to break apart target image\n"); return 1; } @@ -875,48 +899,47 @@ int imgdiff(int argc, const char** argv) { // Verify that the source and target images have the same chunk // structure (ie, the same sequence of deflate and normal 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); + // Merge the gzip header and footer in with any adjacent normal chunks. + MergeAdjacentNormalChunks(&tgt_chunks); + MergeAdjacentNormalChunks(&src_chunks); - if (num_src_chunks != num_tgt_chunks) { + if (src_chunks.size() != tgt_chunks.size()) { printf("source and target don't have same number of chunks!\n"); printf("source chunks:\n"); - DumpChunks(src_chunks, num_src_chunks); + DumpChunks(src_chunks); printf("target chunks:\n"); - DumpChunks(tgt_chunks, num_tgt_chunks); + DumpChunks(tgt_chunks); return 1; } - 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); + for (size_t i = 0; i < src_chunks.size(); ++i) { + if (src_chunks[i].GetType() != tgt_chunks[i].GetType()) { + printf("source and target don't have same chunk structure! (chunk %zu)\n", i); printf("source chunks:\n"); - DumpChunks(src_chunks, num_src_chunks); + DumpChunks(src_chunks); printf("target chunks:\n"); - DumpChunks(tgt_chunks, num_tgt_chunks); + DumpChunks(tgt_chunks); return 1; } } } - for (i = 0; i < num_tgt_chunks; ++i) { - if (tgt_chunks[i].type == CHUNK_DEFLATE) { + for (size_t i = 0; i < tgt_chunks.size(); ++i) { + if (tgt_chunks[i].GetType() == CHUNK_DEFLATE) { // Confirm that given the uncompressed chunk data in the target, we // can recompress it and get exactly the same bits as are in the // input target image. If this fails, treat the chunk as a normal // non-deflated chunk. - if (ReconstructDeflateChunk(tgt_chunks+i) < 0) { - printf("failed to reconstruct target deflate chunk %d [%s]; " - "treating as normal\n", i, tgt_chunks[i].filename); - ChangeDeflateChunkToNormal(tgt_chunks+i); + if (!tgt_chunks[i].ReconstructDeflateChunk()) { + printf("failed to reconstruct target deflate chunk %zu [%s]; treating as normal\n", i, + tgt_chunks[i].GetEntryName().c_str()); + tgt_chunks[i].ChangeDeflateChunkToNormal(); if (zip_mode) { - ImageChunk* src = FindChunkByName(tgt_chunks[i].filename, src_chunks, num_src_chunks); - if (src) { - ChangeDeflateChunkToNormal(src); + ImageChunk* src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks); + if (src != nullptr) { + src->ChangeDeflateChunkToNormal(); } } else { - ChangeDeflateChunkToNormal(src_chunks+i); + src_chunks[i].ChangeDeflateChunkToNormal(); } continue; } @@ -929,16 +952,16 @@ int imgdiff(int argc, const char** argv) { // data. ImageChunk* src; if (zip_mode) { - src = FindChunkByName(tgt_chunks[i].filename, src_chunks, num_src_chunks); + src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks); } else { - src = src_chunks+i; + src = &src_chunks[i]; } - if (src == NULL || AreChunksEqual(tgt_chunks+i, src)) { - ChangeDeflateChunkToNormal(tgt_chunks+i); - if (src) { - ChangeDeflateChunkToNormal(src); - } + if (src == nullptr) { + tgt_chunks[i].ChangeDeflateChunkToNormal(); + } else if (tgt_chunks[i] == *src) { + tgt_chunks[i].ChangeDeflateChunkToNormal(); + src->ChangeDeflateChunkToNormal(); } } } @@ -948,14 +971,15 @@ int imgdiff(int argc, const char** argv) { // For zips, we only need to do this to the target: deflated // chunks are matched via filename, and normal chunks are patched // using the entire source file as the source. - MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks); + MergeAdjacentNormalChunks(&tgt_chunks); + } else { // For images, we need to maintain the parallel structure of the // chunk lists, so do the merging in both the source and target // lists. - MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks); - MergeAdjacentNormalChunks(src_chunks, &num_src_chunks); - if (num_src_chunks != num_tgt_chunks) { + MergeAdjacentNormalChunks(&tgt_chunks); + MergeAdjacentNormalChunks(&src_chunks); + if (src_chunks.size() != tgt_chunks.size()) { // This shouldn't happen. printf("merging normal chunks went awry\n"); return 1; @@ -965,117 +989,68 @@ int imgdiff(int argc, const char** argv) { // Compute bsdiff patches for each chunk's data (the uncompressed // data, in the case of deflate chunks). - DumpChunks(src_chunks, num_src_chunks); + DumpChunks(src_chunks); - printf("Construct patches for %d chunks...\n", num_tgt_chunks); - unsigned char** patch_data = static_cast(malloc( - num_tgt_chunks * sizeof(unsigned char*))); - size_t* patch_size = static_cast(malloc(num_tgt_chunks * sizeof(size_t))); + printf("Construct patches for %zu chunks...\n", tgt_chunks.size()); + std::vector> patch_data(tgt_chunks.size()); saidx_t* bsdiff_cache = nullptr; - for (i = 0; i < num_tgt_chunks; ++i) { + for (size_t i = 0; i < tgt_chunks.size(); ++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, nullptr); + if (tgt_chunks[i].GetType() == CHUNK_DEFLATE && + (src = FindChunkByName(tgt_chunks[i].GetEntryName(), src_chunks))) { + MakePatch(src, &tgt_chunks[i], &patch_data[i], nullptr); } else { - patch_data[i] = MakePatch(src_chunks, tgt_chunks + i, patch_size + i, &bsdiff_cache); + MakePatch(&src_chunks[0], &tgt_chunks[i], &patch_data[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(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; + if (i == 1 && !bonus_data.empty()) { + printf(" using %zu bytes of bonus data for chunk %zu\n", bonus_data.size(), i); + src_chunks[i].SetBonusData(bonus_data); } - patch_data[i] = MakePatch(src_chunks + i, tgt_chunks + i, patch_size + i, nullptr); + MakePatch(&src_chunks[i], &tgt_chunks[i], &patch_data[i], nullptr); } - printf("patch %3d is %zu bytes (of %zu)\n", i, patch_size[i], tgt_chunks[i].source_len); + printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(), + src_chunks[i].GetRawDataLength()); + } + + if (bsdiff_cache != nullptr) { + free(bsdiff_cache); } - 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 // within the file. size_t total_header_size = 12; - for (i = 0; i < num_tgt_chunks; ++i) { - total_header_size += 4; - switch (tgt_chunks[i].type) { - case CHUNK_NORMAL: - total_header_size += 8*3; - break; - case CHUNK_DEFLATE: - total_header_size += 8*5 + 4*5; - break; - case CHUNK_RAW: - total_header_size += 4 + patch_size[i]; - break; - } + for (size_t i = 0; i < tgt_chunks.size(); ++i) { + total_header_size += tgt_chunks[i].GetHeaderSize(patch_data[i].size()); } size_t offset = total_header_size; FILE* f = fopen(argv[3], "wb"); + if (f == nullptr) { + printf("failed to open \"%s\": %s\n", argv[3], strerror(errno)); + } // Write out the headers. fwrite("IMGDIFF2", 1, 8, f); - Write4(num_tgt_chunks, f); - for (i = 0; i < num_tgt_chunks; ++i) { - Write4(tgt_chunks[i].type, f); - - switch (tgt_chunks[i].type) { - case CHUNK_NORMAL: - printf("chunk %3d: normal (%10zu, %10zu) %10zu\n", i, - tgt_chunks[i].start, tgt_chunks[i].len, patch_size[i]); - Write8(tgt_chunks[i].source_start, f); - Write8(tgt_chunks[i].source_len, f); - Write8(offset, f); - offset += patch_size[i]; - break; - - case CHUNK_DEFLATE: - printf("chunk %3d: deflate (%10zu, %10zu) %10zu %s\n", i, - tgt_chunks[i].start, tgt_chunks[i].deflate_len, patch_size[i], - tgt_chunks[i].filename); - Write8(tgt_chunks[i].source_start, f); - Write8(tgt_chunks[i].source_len, f); - Write8(offset, f); - Write8(tgt_chunks[i].source_uncompressed_len, f); - Write8(tgt_chunks[i].len, f); - Write4(tgt_chunks[i].level, f); - Write4(tgt_chunks[i].method, f); - Write4(tgt_chunks[i].windowBits, f); - Write4(tgt_chunks[i].memLevel, f); - Write4(tgt_chunks[i].strategy, f); - offset += patch_size[i]; - break; - - case CHUNK_RAW: - printf("chunk %3d: raw (%10zu, %10zu)\n", i, - tgt_chunks[i].start, tgt_chunks[i].len); - Write4(patch_size[i], f); - fwrite(patch_data[i], 1, patch_size[i], f); - break; - } + Write4(static_cast(tgt_chunks.size()), f); + for (size_t i = 0; i < tgt_chunks.size(); ++i) { + printf("chunk %zu: ", i); + offset = tgt_chunks[i].WriteHeaderToFile(f, patch_data[i], offset); } // Append each chunk's bsdiff patch, in order. - - for (i = 0; i < num_tgt_chunks; ++i) { - if (tgt_chunks[i].type != CHUNK_RAW) { - fwrite(patch_data[i], 1, patch_size[i], f); + for (size_t i = 0; i < tgt_chunks.size(); ++i) { + if (tgt_chunks[i].GetType() != CHUNK_RAW) { + fwrite(patch_data[i].data(), 1, patch_data[i].size(), f); } } - free(tgt_chunks); - free(patch_data); - free(patch_size); - fclose(f); return 0; -- cgit v1.2.3 From 40e144dae877654f75e65242535036058ea48f58 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 15 Mar 2017 01:10:58 -0700 Subject: applypatch: Drop the support for patching non-EMMC targets. Patching regular files is used in file-based OTA only, which has become obsolete. Bug: 35853185 Test: Apply an incremental that patches the boot.img. Test: /system/bin/install-recovery.sh works. Test: recovery_component_test passes. Change-Id: Id44e42c4bc63f2162ecc8a6df1cb528b7ae6b0a9 --- applypatch/applypatch.cpp | 386 +++++++++++++--------------------------------- 1 file changed, 109 insertions(+), 277 deletions(-) (limited to 'applypatch') diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 500663120..7be3fdbde 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -42,15 +43,9 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file); static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); -static int GenerateTarget(FileContents* source_file, - const Value* source_patch_value, - FileContents* copy_file, - const Value* copy_patch_value, - const char* source_filename, - const char* target_filename, - const uint8_t target_sha1[SHA_DIGEST_LENGTH], - size_t target_size, - const Value* bonus_data); +static int GenerateTarget(const FileContents& source_file, const std::unique_ptr& patch, + const std::string& target_filename, + const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data); // Read a file into memory; store the file contents and associated metadata in *file. // Return 0 on success. @@ -190,7 +185,6 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file return 0; } - // Save the contents of the given FileContents object under the given // filename. Return 0 on success. int SaveFileContents(const char* filename, const FileContents* file) { @@ -480,108 +474,90 @@ int CacheSizeCheck(size_t bytes) { } } -// This function applies binary patches to files in a way that is safe -// (the original file is not touched until we have the desired -// replacement for it) and idempotent (it's okay to run this program -// multiple times). +// This function applies binary patches to EMMC target files in a way that is safe (the original +// file is not touched until we have the desired replacement for it) and idempotent (it's okay to +// run this program multiple times). // -// - if the sha1 hash of is , -// does nothing and exits successfully. +// - If the SHA-1 hash of is , does nothing and exits +// successfully. // -// - otherwise, if the sha1 hash of is one of the -// entries in , the corresponding patch from -// (which must be a VAL_BLOB) is applied to produce a -// new file (the type of patch is automatically detected from the -// blob data). If that new file has sha1 hash , -// moves it to replace , and exits successfully. -// Note that if and are not the -// same, is NOT deleted on success. -// may be the string "-" to mean "the same as -// source_filename". +// - Otherwise, if the SHA-1 hash of is one of the entries in , +// the corresponding patch from (which must be a VAL_BLOB) is applied to produce a +// new file (the type of patch is automatically detected from the blob data). If that new file +// has SHA-1 hash , moves it to replace , and exits +// successfully. Note that if and are not the same, +// is NOT deleted on success. may be the string "-" to mean +// "the same as ". // -// - otherwise, or if any error is encountered, exits with non-zero -// status. +// - Otherwise, or if any error is encountered, exits with non-zero status. // -// may refer to a partition to read the source data. -// See the comments for the LoadPartitionContents() function above -// for the format of such a filename. - -int applypatch(const char* source_filename, - const char* target_filename, - const char* target_sha1_str, - size_t target_size, +// must refer to an EMMC partition to read the source data. See the comments for +// the LoadPartitionContents() function above for the format of such a filename. has +// 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 std::vector& patch_sha1_str, - const std::vector>& patch_data, - const Value* bonus_data) { - printf("patch %s: ", source_filename); + const std::vector>& patch_data, const Value* bonus_data) { + printf("patch %s: ", source_filename); - if (target_filename[0] == '-' && target_filename[1] == '\0') { - target_filename = source_filename; - } + if (target_filename[0] == '-' && target_filename[1] == '\0') { + target_filename = source_filename; + } - uint8_t target_sha1[SHA_DIGEST_LENGTH]; - if (ParseSha1(target_sha1_str, target_sha1) != 0) { - printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); - return 1; - } + if (strncmp(target_filename, "EMMC:", 5) != 0) { + printf("Supporting patching EMMC targets only.\n"); + return 1; + } - FileContents source_file; - const Value* source_patch_value = nullptr; + uint8_t target_sha1[SHA_DIGEST_LENGTH]; + if (ParseSha1(target_sha1_str, target_sha1) != 0) { + printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str); + return 1; + } - // We try to load the target file into the source_file object. - if (LoadFileContents(target_filename, &source_file) == 0) { - if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { - // The early-exit case: the patch was already applied, this file - // has the desired hash, nothing for us to do. - printf("already %s\n", short_sha1(target_sha1).c_str()); - return 0; - } + // We try to load the target file into the source_file object. + FileContents source_file; + if (LoadFileContents(target_filename, &source_file) == 0) { + if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) { + // The early-exit case: the patch was already applied, this file has the desired hash, nothing + // for us to do. + printf("already %s\n", short_sha1(target_sha1).c_str()); + return 0; } + } - if (source_file.data.empty() || - (target_filename != source_filename && - strcmp(target_filename, source_filename) != 0)) { - // Need to load the source file: either we failed to load the - // target file, or we did but it's different from the source file. - source_file.data.clear(); - LoadFileContents(source_filename, &source_file); - } + if (source_file.data.empty() || + (target_filename != source_filename && strcmp(target_filename, source_filename) != 0)) { + // Need to load the source file: either we failed to load the target file, or we did but it's + // different from the expected. + source_file.data.clear(); + LoadFileContents(source_filename, &source_file); + } - if (!source_file.data.empty()) { - int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); - if (to_use >= 0) { - source_patch_value = patch_data[to_use].get(); - } + if (!source_file.data.empty()) { + int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str); + if (to_use != -1) { + return GenerateTarget(source_file, patch_data[to_use], target_filename, target_sha1, + bonus_data); } + } - FileContents copy_file; - const Value* copy_patch_value = nullptr; - if (source_patch_value == nullptr) { - source_file.data.clear(); - printf("source file is bad; trying copy\n"); - - if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { - // fail. - printf("failed to read copy file\n"); - return 1; - } + printf("source file is bad; trying copy\n"); - int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); - if (to_use >= 0) { - copy_patch_value = patch_data[to_use].get(); - } + FileContents copy_file; + if (LoadFileContents(CACHE_TEMP_SOURCE, ©_file) < 0) { + printf("failed to read copy file\n"); + return 1; + } - if (copy_patch_value == nullptr) { - // fail. - printf("copy file doesn't match source SHA-1s either\n"); - return 1; - } - } + int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str); + if (to_use == -1) { + printf("copy file doesn't match source SHA-1s either\n"); + return 1; + } - return GenerateTarget(&source_file, source_patch_value, - ©_file, copy_patch_value, - source_filename, target_filename, - target_sha1, target_size, bonus_data); + return GenerateTarget(copy_file, patch_data[to_use], target_filename, target_sha1, bonus_data); } /* @@ -638,34 +614,9 @@ int applypatch_flash(const char* source_filename, const char* target_filename, return 0; } -static int GenerateTarget(FileContents* source_file, - const Value* source_patch_value, - FileContents* copy_file, - const Value* copy_patch_value, - const char* source_filename, - const char* target_filename, - const uint8_t target_sha1[SHA_DIGEST_LENGTH], - size_t target_size, - const Value* bonus_data) { - // assume that target_filename (eg "/system/app/Foo.apk") is located - // on the same filesystem as its top-level directory ("/system"). - // We need something that exists for calling statfs(). - std::string target_fs = target_filename; - auto slash_pos = target_fs.find('/', 1); - if (slash_pos != std::string::npos) { - target_fs.resize(slash_pos); - } - - FileContents* source_to_use; - const Value* patch; - if (source_patch_value != nullptr) { - source_to_use = source_file; - patch = source_patch_value; - } else { - source_to_use = copy_file; - patch = copy_patch_value; - } - +static int GenerateTarget(const FileContents& source_file, const std::unique_ptr& patch, + const std::string& target_filename, + const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data) { if (patch->type != VAL_BLOB) { printf("patch is not a blob\n"); return 1; @@ -683,137 +634,39 @@ static int GenerateTarget(FileContents* source_file, return 1; } - bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0); - const std::string tmp_target_filename = std::string(target_filename) + ".patch"; - - int retry = 1; - bool made_copy = false; - SHA_CTX ctx; - std::string memory_sink_str; // Don't need to reserve space. - do { - // Is there enough room in the target filesystem to hold the patched file? - - if (target_is_partition) { - // If the target is a partition, we're actually going to - // write the output to /tmp and then copy it to the - // partition. statfs() always returns 0 blocks free for - // /tmp, so instead we'll just assume that /tmp has enough - // space to hold the file. - - // We still write the original source to cache, in case - // the partition write is interrupted. - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = true; - retry = 0; - } else { - bool enough_space = false; - if (retry > 0) { - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum - (free_space > (target_size * 3 / 2)); // 50% margin of error - if (!enough_space) { - printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size, - free_space, retry, enough_space); - } - } - - if (!enough_space) { - retry = 0; - } - - if (!enough_space && source_patch_value != nullptr) { - // Using the original source, but not enough free space. First - // copy the source file to cache, then delete it from the original - // location. - - if (strncmp(source_filename, "EMMC:", 5) == 0) { - // It's impossible to free space on the target filesystem by - // deleting the source if the source is a partition. If - // we're ever in a state where we need to do this, fail. - printf("not enough free space for target but source is partition\n"); - return 1; - } + CHECK(android::base::StartsWith(target_filename, "EMMC:")); - if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) { - printf("not enough free space on /cache\n"); - return 1; - } - - if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { - printf("failed to back up source file\n"); - return 1; - } - made_copy = true; - unlink(source_filename); - - size_t free_space = FreeSpaceForFile(target_fs.c_str()); - printf("(now %zu bytes free for target) ", free_space); - } - } - - SinkFn sink = nullptr; - void* token = nullptr; - unique_fd output_fd; - if (target_is_partition) { - // We store the decoded output in memory. - sink = MemorySink; - token = &memory_sink_str; - } else { - // We write the decoded output to ".patch". - output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR)); - if (output_fd == -1) { - printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - sink = FileSink; - token = &output_fd; - } + // We still write the original source to cache, in case the partition write is interrupted. + if (MakeFreeSpaceOnCache(source_file.data.size()) < 0) { + printf("not enough free space on /cache\n"); + return 1; + } + if (SaveFileContents(CACHE_TEMP_SOURCE, &source_file) < 0) { + printf("failed to back up source file\n"); + return 1; + } - SHA1_Init(&ctx); + // We store the decoded output in memory. + SinkFn sink = MemorySink; + std::string memory_sink_str; // Don't need to reserve space. + void* token = &memory_sink_str; - int result; - if (use_bsdiff) { - result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0, - sink, token, &ctx); - } else { - result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink, - token, &ctx, bonus_data); - } + SHA_CTX ctx; + SHA1_Init(&ctx); - if (!target_is_partition) { - if (ota_fsync(output_fd) != 0) { - printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); - result = 1; - } - if (ota_close(output_fd) != 0) { - printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno)); - result = 1; - } - } + int result; + if (use_bsdiff) { + result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0, + sink, token, &ctx); + } else { + result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink, + token, &ctx, bonus_data); + } - if (result != 0) { - if (retry == 0) { - printf("applying patch failed\n"); - return 1; - } else { - printf("applying patch failed; retrying\n"); - } - if (!target_is_partition) { - unlink(tmp_target_filename.c_str()); - } - } else { - // succeeded; no need to retry - break; - } - } while (retry-- > 0); + if (result != 0) { + printf("applying patch failed\n"); + return 1; + } uint8_t current_target_sha1[SHA_DIGEST_LENGTH]; SHA1_Final(current_target_sha1, &ctx); @@ -824,36 +677,15 @@ static int GenerateTarget(FileContents* source_file, printf("now %s\n", short_sha1(target_sha1).c_str()); } - if (target_is_partition) { - // Copy the temp file to the partition. - if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), - memory_sink_str.size(), target_filename) != 0) { - printf("write of patched data to %s failed\n", target_filename); - return 1; - } - } else { - // Give the .patch file the same owner, group, and mode of the original source file. - if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) { - printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, - source_to_use->st.st_gid) != 0) { - printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno)); - return 1; - } - - // Finally, rename the .patch file to replace the target file. - if (rename(tmp_target_filename.c_str(), target_filename) != 0) { - printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno)); - return 1; - } + // Write back the temp file to the partition. + if (WriteToPartition(reinterpret_cast(memory_sink_str.c_str()), + memory_sink_str.size(), target_filename) != 0) { + printf("write of patched data to %s failed\n", target_filename.c_str()); + return 1; } - // If this run of applypatch created the copy, and we're here, we can delete it. - if (made_copy) { - unlink(CACHE_TEMP_SOURCE); - } + // Delete the backup copy of the source. + unlink(CACHE_TEMP_SOURCE); // Success! return 0; -- cgit v1.2.3 From 12b90553d784b9d4ddd1b48300af6345bdf1085f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 7 Mar 2017 14:44:14 -0800 Subject: More cleanup to imgdiff & imgpatch Also remove the utils in applypatch and replace them with the corresponding libbase functions. Test: recovery tests pass. Change-Id: I77254c141bd3e7d3d6894c23b60e866009516f81 --- applypatch/Android.mk | 15 ++-- applypatch/imgdiff.cpp | 185 +++++++++++++++++++++++++++--------------------- applypatch/imgpatch.cpp | 25 ++++--- applypatch/utils.cpp | 65 ----------------- applypatch/utils.h | 31 -------- 5 files changed, 128 insertions(+), 193 deletions(-) delete mode 100644 applypatch/utils.cpp delete mode 100644 applypatch/utils.h (limited to 'applypatch') diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 8be5c36be..a7412d238 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -21,8 +21,7 @@ LOCAL_SRC_FILES := \ applypatch.cpp \ bspatch.cpp \ freecache.cpp \ - imgpatch.cpp \ - utils.cpp + imgpatch.cpp LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES := \ @@ -46,8 +45,7 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ bspatch.cpp \ - imgpatch.cpp \ - utils.cpp + imgpatch.cpp LOCAL_MODULE := libimgpatch LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ @@ -56,6 +54,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ libcrypto \ libbspatch \ + libbase \ libbz \ libz LOCAL_CFLAGS := \ @@ -68,8 +67,7 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ bspatch.cpp \ - imgpatch.cpp \ - utils.cpp + imgpatch.cpp LOCAL_MODULE := libimgpatch LOCAL_MODULE_HOST_OS := linux LOCAL_C_INCLUDES := \ @@ -79,6 +77,7 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ libcrypto \ libbspatch \ + libbase \ libbz \ libz LOCAL_CFLAGS := \ @@ -123,9 +122,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_CFLAGS := -Werror include $(BUILD_EXECUTABLE) -libimgdiff_src_files := \ - imgdiff.cpp \ - utils.cpp +libimgdiff_src_files := imgdiff.cpp # libbsdiff is compiled with -D_FILE_OFFSET_BITS=64. libimgdiff_cflags := \ diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index fba74e836..41d73ab98 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -145,12 +145,22 @@ #include #include -#include "utils.h" - using android::base::get_unaligned; 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 { public: static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream. @@ -163,11 +173,12 @@ class ImageChunk { start_(start), input_file_ptr_(file_content), raw_data_len_(raw_data_len), - entry_name_(""), compress_level_(6), source_start_(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 { return type_; @@ -199,7 +210,8 @@ class ImageChunk { } size_t GetHeaderSize(size_t patch_size) const; - size_t WriteHeaderToFile(FILE* f, const std::vector patch, size_t offset); + // Return the offset of the next patch into the patch data. + size_t WriteHeaderToFd(int fd, const std::vector& patch, size_t offset); /* * 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); private: - int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW - size_t start_; // offset of chunk in the original input file - const std::vector* input_file_ptr_; // pointer to the full content of original input file + int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW + size_t start_; // offset of chunk in the original input file + const std::vector* input_file_ptr_; // ptr to the full content of original input file size_t raw_data_len_; // --- for CHUNK_DEFLATE chunks only: --- @@ -280,11 +292,11 @@ void ImageChunk::SetSourceInfo(const ImageChunk& src) { } void ImageChunk::SetEntryName(std::string entryname) { - entry_name_ = entryname; + entry_name_ = std::move(entryname); } void ImageChunk::SetUncompressedData(std::vector data) { - uncompressed_data_ = data; + uncompressed_data_ = std::move(data); } bool ImageChunk::SetBonusData(const std::vector& bonus_data) { @@ -295,7 +307,7 @@ bool ImageChunk::SetBonusData(const std::vector& bonus_data) { 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. bool ImageChunk::ChangeChunkToRaw(size_t patch_size) { if (type_ == CHUNK_RAW) { @@ -310,6 +322,7 @@ bool ImageChunk::ChangeChunkToRaw(size_t patch_size) { void ImageChunk::ChangeDeflateChunkToNormal() { if (type_ != CHUNK_DEFLATE) return; type_ = CHUNK_NORMAL; + entry_name_.clear(); uncompressed_data_.clear(); } @@ -317,7 +330,7 @@ void ImageChunk::ChangeDeflateChunkToNormal() { // header_type 4 bytes // CHUNK_NORMAL 8*3 = 24 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 { switch (type_) { case CHUNK_NORMAL: @@ -327,43 +340,43 @@ size_t ImageChunk::GetHeaderSize(size_t patch_size) const { case CHUNK_RAW: return 4 + 4 + patch_size; default: - printf("unexpected chunk type: %d\n", type_); // should not reach here. - CHECK(false); + CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here. return 0; } } -size_t ImageChunk::WriteHeaderToFile(FILE* f, const std::vector patch, size_t offset) { - Write4(type_, f); +size_t ImageChunk::WriteHeaderToFd(int fd, const std::vector& patch, size_t offset) { + Write4(fd, type_); switch (type_) { case CHUNK_NORMAL: printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size()); - Write8(source_start_, f); - Write8(source_len_, f); - Write8(offset, f); + Write8(fd, static_cast(source_start_)); + Write8(fd, static_cast(source_len_)); + Write8(fd, static_cast(offset)); return offset + patch.size(); case CHUNK_DEFLATE: printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(), entry_name_.c_str()); - Write8(source_start_, f); - Write8(source_len_, f); - Write8(offset, f); - Write8(source_uncompressed_len_, f); - Write8(uncompressed_data_.size(), f); - Write4(compress_level_, f); - Write4(METHOD, f); - Write4(WINDOWBITS, f); - Write4(MEMLEVEL, f); - Write4(STRATEGY, f); + Write8(fd, static_cast(source_start_)); + Write8(fd, static_cast(source_len_)); + Write8(fd, static_cast(offset)); + Write8(fd, static_cast(source_uncompressed_len_)); + Write8(fd, static_cast(uncompressed_data_.size())); + Write4(fd, compress_level_); + Write4(fd, METHOD); + Write4(fd, WINDOWBITS); + Write4(fd, MEMLEVEL); + Write4(fd, STRATEGY); return offset + patch.size(); case CHUNK_RAW: printf("raw (%10zu, %10zu)\n", start_, raw_data_len_); - Write4(patch.size(), f); - fwrite(patch.data(), 1, patch.size(), f); + Write4(fd, static_cast(patch.size())); + if (!android::base::WriteFully(fd, patch.data(), patch.size())) { + CHECK(false) << "failed to write " << patch.size() <<" bytes patch"; + } return offset; default: - printf("unexpected chunk type: %d\n", type_); - CHECK(false); + CHECK(false) << "unexpected chunk type: " << type_; return offset; } } @@ -480,20 +493,21 @@ static bool GetZipFileSize(const std::vector& zip_file, size_t* input_f static bool ReadZip(const char* filename, std::vector* chunks, std::vector* 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; - if (stat(filename, &st) != 0) { + if (fstat(fd, &st) != 0) { printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); return false; } size_t sz = static_cast(st.st_size); 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)) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); return false; @@ -596,20 +610,21 @@ static bool ReadZip(const char* filename, std::vector* chunks, // 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* chunks, std::vector* 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; - if (stat(filename, &st) != 0) { + if (fstat(fd, &st) != 0) { printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); return false; } size_t sz = static_cast(st.st_size); 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)) { printf("failed to read \"%s\" %s\n", filename, strerror(errno)); return false; @@ -618,9 +633,8 @@ static bool ReadImage(const char* filename, std::vector* chunks, size_t pos = 0; while (pos < sz) { - if (sz - pos >= 4 && img->at(pos) == 0x1f && img->at(pos + 1) == 0x8b && - img->at(pos + 2) == 0x08 && // deflate compression - img->at(pos + 3) == 0x00) { // no header flags + // 0x00 no header flags, 0x08 deflate compression, 0x1f8b gzip magic number + if (sz - pos >= 4 && get_unaligned(img->data() + pos) == 0x00088b1f) { // 'pos' is the offset of the start of a gzip chunk. size_t chunk_offset = pos; @@ -695,7 +709,7 @@ static bool ReadImage(const char* filename, std::vector* chunks, // the uncompressed data. Double-check to make sure that it // matches the size of the data we got when we actually did // the decompression. - size_t footer_size = Read4(img->data() + pos - 4); + size_t footer_size = get_unaligned(img->data() + pos - 4); if (footer_size != body.DataLengthForPatch()) { printf("Error: footer size %zu != decompressed size %zu\n", footer_size, body.GetRawDataLength()); @@ -708,9 +722,8 @@ static bool ReadImage(const char* filename, std::vector* chunks, // Scan forward until we find a gzip header. size_t data_len = 0; while (data_len + pos < sz) { - if (data_len + pos + 4 <= sz && img->at(pos + data_len) == 0x1f && - img->at(pos + data_len + 1) == 0x8b && img->at(pos + data_len + 2) == 0x08 && - img->at(pos + data_len + 3) == 0x00) { + if (data_len + pos + 4 <= sz && + get_unaligned(img->data() + pos + data_len) == 0x00088b1f) { break; } data_len++; @@ -759,13 +772,19 @@ static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vector(st.st_size); + // Change the chunk type to raw if the patch takes less space that way. if (tgt->ChangeChunkToRaw(sz)) { unlink(ptemp); size_t patch_size = tgt->DataLengthForPatch(); @@ -773,12 +792,6 @@ static bool MakePatch(const ImageChunk* src, ImageChunk* tgt, std::vectorDataForPatch(), tgt->DataForPatch() + patch_size, patch_data->begin()); 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); if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) { printf("failed to read \"%s\" %s\n", ptemp, strerror(errno)); @@ -845,18 +858,19 @@ int imgdiff(int argc, const char** argv) { std::vector bonus_data; if (argc >= 3 && strcmp(argv[1], "-b") == 0) { + android::base::unique_fd fd(open(argv[2], O_RDONLY)); + if (fd == -1) { + printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno)); + return 1; + } struct stat st; - if (stat(argv[2], &st) != 0) { + 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); - android::base::unique_fd fd(open(argv[2], O_RDONLY)); - if (fd == -1) { - printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno)); - return 1; - } if (!android::base::ReadFully(fd, bonus_data.data(), bonus_size)) { printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno)); return 1; @@ -999,9 +1013,15 @@ int imgdiff(int argc, const char** argv) { ImageChunk* src; if (tgt_chunks[i].GetType() == CHUNK_DEFLATE && (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 { - 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 { if (i == 1 && !bonus_data.empty()) { @@ -1009,7 +1029,10 @@ int imgdiff(int argc, const char** argv) { 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(), src_chunks[i].GetRawDataLength()); @@ -1030,28 +1053,32 @@ int imgdiff(int argc, const char** argv) { size_t offset = total_header_size; - FILE* f = fopen(argv[3], "wb"); - if (f == nullptr) { + android::base::unique_fd patch_fd(open(argv[3], O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)); + if (patch_fd == -1) { printf("failed to open \"%s\": %s\n", argv[3], strerror(errno)); + return 1; } // Write out the headers. - - fwrite("IMGDIFF2", 1, 8, f); - Write4(static_cast(tgt_chunks.size()), f); + if (!android::base::WriteStringToFd("IMGDIFF2", patch_fd)) { + printf("failed to write \"IMGDIFF2\" to \"%s\": %s\n", argv[3], strerror(errno)); + return 1; + } + Write4(patch_fd, static_cast(tgt_chunks.size())); for (size_t i = 0; i < tgt_chunks.size(); ++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. for (size_t i = 0; i < tgt_chunks.size(); ++i) { 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; } diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index 8f4a2a42b..adcc61fd6 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp @@ -31,10 +31,17 @@ #include #include +#include #include #include -#include "utils.h" +static inline int64_t Read8(const void *address) { + return android::base::get_unaligned(address); +} + +static inline int32_t Read4(const void *address) { + return android::base::get_unaligned(address); +} int ApplyImagePatch(const unsigned char* old_data, ssize_t old_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; } - size_t src_start = Read8(normal_header); - size_t src_len = Read8(normal_header + 8); - size_t patch_offset = Read8(normal_header + 16); + size_t src_start = static_cast(Read8(normal_header)); + size_t src_len = static_cast(Read8(normal_header + 8)); + size_t patch_offset = static_cast(Read8(normal_header + 16)); if (src_start + src_len > static_cast(old_size)) { 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; } - 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); + size_t src_start = static_cast(Read8(deflate_header)); + size_t src_len = static_cast(Read8(deflate_header + 8)); + size_t patch_offset = static_cast(Read8(deflate_header + 16)); + size_t expanded_len = static_cast(Read8(deflate_header + 24)); + size_t target_len = static_cast(Read8(deflate_header + 32)); int level = Read4(deflate_header + 40); int method = Read4(deflate_header + 44); int windowBits = Read4(deflate_header + 48); diff --git a/applypatch/utils.cpp b/applypatch/utils.cpp deleted file mode 100644 index 450dc8d76..000000000 --- a/applypatch/utils.cpp +++ /dev/null @@ -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 - -#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(pv); - return (int)(((unsigned int)p[1] << 8) | - (unsigned int)p[0]); -} - -int Read4(const void* pv) { - const unsigned char* p = reinterpret_cast(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(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]); -} diff --git a/applypatch/utils.h b/applypatch/utils.h deleted file mode 100644 index c7c8e90e2..000000000 --- a/applypatch/utils.h +++ /dev/null @@ -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 -#include - -// 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 -- cgit v1.2.3