diff options
Diffstat (limited to 'applypatch')
-rw-r--r-- | applypatch/Android.mk | 4 | ||||
-rw-r--r-- | applypatch/Makefile | 32 | ||||
-rw-r--r-- | applypatch/applypatch.cpp | 109 | ||||
-rw-r--r-- | applypatch/applypatch.h | 13 | ||||
-rw-r--r-- | applypatch/bsdiff.cpp | 1 | ||||
-rw-r--r-- | applypatch/bspatch.cpp | 1 | ||||
-rw-r--r-- | applypatch/imgdiff.cpp | 24 | ||||
-rw-r--r-- | applypatch/imgpatch.cpp | 6 | ||||
-rw-r--r-- | applypatch/libimgpatch.pc | 6 | ||||
-rw-r--r-- | applypatch/main.cpp | 67 |
10 files changed, 125 insertions, 138 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 887a570db..90a86dcb0 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -55,9 +55,7 @@ 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 libotafault libmtdutils libcrypto_static libbz libedify LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) 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.cpp b/applypatch/applypatch.cpp index 9f5e2f200..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); @@ -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<unsigned char, decltype(&free)> data( - static_cast<unsigned char*>(malloc(file->size)), free); - if (data == nullptr) { - printf("failed to allocate memory: %s\n", strerror(errno)); - return -1; - } - + std::vector<unsigned char> 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<size_t>(file->size)) { - printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size); - fclose(f); + 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<unsigned char*>(malloc(size[index[pairs-1]])); - char* p = (char*)file->data; - file->size = 0; // # bytes read so far + std::vector<unsigned char> data(size[index[pairs-1]]); + char* p = reinterpret_cast<char*>(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<ssize_t>(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<std::string> 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; } @@ -936,7 +897,7 @@ static int GenerateTarget(FileContents* source_file, } else { // We write the decoded output to "<tgt-file>.patch". output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, - S_IRUSR | S_IWUSR); + S_IRUSR | S_IWUSR); if (output_fd < 0) { printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno)); @@ -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 14fb490ba..9ee39d293 100644 --- a/applypatch/applypatch.h +++ b/applypatch/applypatch.h @@ -17,6 +17,7 @@ #ifndef _APPLYPATCH_H #define _APPLYPATCH_H +#include <stdint.h> #include <sys/stat.h> #include <vector> @@ -24,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<unsigned char> 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/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..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<unsigned char*>(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; @@ -598,7 +596,6 @@ int ReconstructDeflateChunk(ImageChunk* chunk) { return -1; } - size_t p = 0; unsigned char* out = reinterpret_cast<unsigned char*>(malloc(BUFFER_SIZE)); // We only check two combinations of encoder parameters: level 6 @@ -844,7 +841,6 @@ int main(int argc, char** argv) { } if (argc != 4) { - usage: printf("usage: %s [-z] [-b <bonus-file>] <src-img> <tgt-img> <patch-file>\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. 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 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 "<sha1>" or -// "<sha1>:<filename>" 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 "<sha1>:<filename>" +// into the new parallel arrays *sha1s and *files.Returns true on // success. static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s, - std::vector<std::unique_ptr<Value, decltype(&FreeValue)>>* patches) { + std::vector<FileContents>* 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, decltype(&FreeValue)> value(new Value, FreeValue); - value->type = VAL_BLOB; - value->size = fc.size; - value->data = reinterpret_cast<char*>(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<Value, decltype(&FreeValue)> 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<char*>(fc.data); + bonus->size = bonusFc.data.size(); + bonus->data = reinterpret_cast<char*>(bonusFc.data.data()); argc -= 2; argv += 2; } @@ -118,28 +112,29 @@ static int PatchMode(int argc, char** argv) { // If no <src-sha1>:<patch> 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<char*> sha1s; - std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches; - if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &patches)) { + std::vector<FileContents> files; + if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { printf("failed to parse patch args\n"); return 1; } - - std::vector<Value*> patch_ptrs; - for (const auto& p : patches) { - patch_ptrs.push_back(p.get()); + std::vector<Value> patches(files.size()); + std::vector<Value*> 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<char*>(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 |