Loading applypatch/Android.mk +3 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,9 @@ 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 LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \ libedify \ LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) Loading applypatch/applypatch.cpp +83 −96 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ #include <sys/types.h> #include <unistd.h> #include <memory> #include <string> #include <android-base/strings.h> #include "openssl/sha.h" Loading Loading @@ -68,25 +71,29 @@ int LoadFileContents(const char* filename, FileContents* file) { } file->size = file->st.st_size; file->data = reinterpret_cast<unsigned char*>(malloc(file->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; } FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); free(file->data); file->data = NULL; return -1; } size_t bytes_read = ota_fread(file->data, 1, file->size, f); 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); free(file->data); file->data = NULL; fclose(f); return -1; } ota_fclose(f); file->data = data.release(); SHA1(file->data, file->size, file->sha1); return 0; } Loading Loading @@ -186,7 +193,7 @@ 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 = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]])); file->data = static_cast<unsigned char*>(malloc(size[index[pairs-1]])); char* p = (char*)file->data; file->size = 0; // # bytes read so far bool found = false; Loading Loading @@ -314,7 +321,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { // "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(unsigned char* data, size_t len, const char* target) { int WriteToPartition(const unsigned char* data, size_t len, const char* target) { std::string copy(target); std::vector<std::string> pieces = android::base::Split(copy, ":"); Loading Loading @@ -353,7 +360,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) { return -1; } size_t written = mtd_write_data(ctx, reinterpret_cast<char*>(data), len); size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len); if (written != len) { printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); mtd_write_close(ctx); Loading Loading @@ -579,7 +586,7 @@ int ShowLicenses() { } ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { int fd = *reinterpret_cast<int *>(token); int fd = *static_cast<int*>(token); ssize_t done = 0; ssize_t wrote; while (done < len) { Loading @@ -593,19 +600,9 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { return done; } typedef struct { unsigned char* buffer; ssize_t size; ssize_t pos; } MemorySinkInfo; ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { MemorySinkInfo* msi = reinterpret_cast<MemorySinkInfo*>(token); if (msi->size - msi->pos < len) { return -1; } memcpy(msi->buffer + msi->pos, data, len); msi->pos += len; std::string* s = static_cast<std::string*>(token); s->append(reinterpret_cast<const char*>(data), len); return len; } Loading Loading @@ -816,31 +813,52 @@ static int GenerateTarget(FileContents* source_file, const Value* bonus_data) { int retry = 1; SHA_CTX ctx; int output; MemorySinkInfo msi; std::string memory_sink_str; FileContents* source_to_use; char* outname; int made_copy = 0; bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 || 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(). char target_fs[strlen(target_filename)+1]; char* slash = strchr(target_filename+1, '/'); if (slash != NULL) { int count = slash - target_filename; strncpy(target_fs, target_filename, count); target_fs[count] = '\0'; 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 { strcpy(target_fs, target_filename); source_to_use = copy_file; patch = copy_patch_value; } if (patch->type != VAL_BLOB) { printf("patch is not a blob\n"); return 1; } char* header = patch->data; ssize_t header_bytes_read = patch->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; } do { // Is there enough room in the target filesystem to hold the patched // file? if (strncmp(target_filename, "MTD:", 4) == 0 || strncmp(target_filename, "EMMC:", 5) == 0) { 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 Loading @@ -862,7 +880,7 @@ static int GenerateTarget(FileContents* source_file, } else { int enough_space = 0; if (retry > 0) { size_t free_space = FreeSpaceForFile(target_fs); 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 Loading Loading @@ -902,84 +920,53 @@ static int GenerateTarget(FileContents* source_file, made_copy = 1; unlink(source_filename); size_t free_space = FreeSpaceForFile(target_fs); size_t free_space = FreeSpaceForFile(target_fs.c_str()); printf("(now %zu bytes free for target) ", free_space); } } 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; } SinkFn sink = NULL; void* token = NULL; output = -1; outname = NULL; if (strncmp(target_filename, "MTD:", 4) == 0 || strncmp(target_filename, "EMMC:", 5) == 0) { int output_fd = -1; if (target_is_partition) { // We store the decoded output in memory. msi.buffer = reinterpret_cast<unsigned char*>(malloc(target_size)); if (msi.buffer == NULL) { printf("failed to alloc %zu bytes for output\n", target_size); return 1; } msi.pos = 0; msi.size = target_size; sink = MemorySink; token = &msi; token = &memory_sink_str; } else { // We write the decoded output to "<tgt-file>.patch". outname = reinterpret_cast<char*>(malloc(strlen(target_filename) + 10)); strcpy(outname, target_filename); strcat(outname, ".patch"); output = ota_open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); if (output < 0) { printf("failed to open output file %s: %s\n", outname, strerror(errno)); 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; token = &output_fd; } char* header = patch->data; ssize_t header_bytes_read = patch->size; SHA1_Init(&ctx); int result; if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { if (use_bsdiff) { result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, patch, 0, sink, token, &ctx); } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) { } else { result = ApplyImagePatch(source_to_use->data, source_to_use->size, patch, sink, token, &ctx, bonus_data); } else { printf("Unknown patch file format\n"); return 1; } if (output >= 0) { if (ota_fsync(output) != 0) { printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno)); 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) != 0) { printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno)); if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } } Loading @@ -991,8 +978,8 @@ static int GenerateTarget(FileContents* source_file, } else { printf("applying patch failed; retrying\n"); } if (outname != NULL) { unlink(outname); if (!target_is_partition) { unlink(tmp_target_filename.c_str()); } } else { // succeeded; no need to retry Loading @@ -1009,27 +996,27 @@ static int GenerateTarget(FileContents* source_file, printf("now %s\n", short_sha1(target_sha1).c_str()); } if (output < 0) { if (target_is_partition) { // Copy the temp file to the partition. if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) { if (WriteToPartition(reinterpret_cast<const unsigned char*>(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; } free(msi.buffer); } else { // Give the .patch file the same owner, group, and mode of the // original source file. if (chmod(outname, source_to_use->st.st_mode) != 0) { printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno)); 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(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) { printf("chown of \"%s\" failed: %s\n", outname, strerror(errno)); 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(outname, target_filename) != 0) { 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; } Loading applypatch/applypatch.h +7 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ #define _APPLYPATCH_H #include <sys/stat.h> #include <vector> #include "openssl/sha.h" #include "edify/expr.h" Loading Loading @@ -68,22 +71,22 @@ void FreeFileContents(FileContents* file); int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int num_patches); // bsdiff.c // 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, unsigned char** new_data, ssize_t* new_size); std::vector<unsigned char>* new_data); // imgpatch.c // 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.c // freecache.cpp int MakeFreeSpaceOnCache(size_t bytes_needed); #endif applypatch/bspatch.cpp +14 −23 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <errno.h> #include <malloc.h> #include <unistd.h> #include <string.h> Loading Loading @@ -103,26 +102,22 @@ 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) { unsigned char* new_data; ssize_t new_size; if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data, &new_size) != 0) { std::vector<unsigned char> new_data; if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) { return -1; } if (sink(new_data, new_size, token) < new_size) { if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) { printf("short write of output: %d (%s)\n", errno, strerror(errno)); return 1; } if (ctx) SHA1_Update(ctx, new_data, new_size); free(new_data); 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, unsigned char** new_data, ssize_t* new_size) { std::vector<unsigned char>* new_data) { // Patch data format: // 0 8 "BSDIFF40" // 8 8 X Loading @@ -141,12 +136,12 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, return 1; } ssize_t ctrl_len, data_len; ssize_t ctrl_len, data_len, new_size; ctrl_len = offtin(header+8); data_len = offtin(header+16); *new_size = offtin(header+24); new_size = offtin(header+24); if (ctrl_len < 0 || data_len < 0 || *new_size < 0) { if (ctrl_len < 0 || data_len < 0 || new_size < 0) { printf("corrupt patch file header (data lengths)\n"); return 1; } Loading Loading @@ -183,18 +178,14 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, printf("failed to bzinit extra stream (%d)\n", bzerr); } *new_data = reinterpret_cast<unsigned char*>(malloc(*new_size)); if (*new_data == NULL) { printf("failed to allocate %zd bytes of memory for output file\n", *new_size); return 1; } new_data->resize(new_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) { while (newpos < new_size) { // Read control data if (FillBuffer(buf, 24, &cstream) != 0) { printf("error while reading control stream\n"); Loading @@ -210,13 +201,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, } // Sanity check if (newpos + ctrl[0] > *new_size) { if (newpos + ctrl[0] > new_size) { printf("corrupt patch (new file overrun)\n"); return 1; } // Read diff string if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) { if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) { printf("error while reading diff stream\n"); return 1; } Loading @@ -233,13 +224,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, oldpos += ctrl[0]; // Sanity check if (newpos + ctrl[1] > *new_size) { if (newpos + ctrl[1] > new_size) { printf("corrupt patch (new file overrun)\n"); return 1; } // Read extra string if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) { if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) { printf("error while reading extra stream\n"); return 1; } Loading applypatch/freecache.cpp +49 −92 Original line number Diff line number Diff line Loading @@ -25,119 +25,90 @@ #include <dirent.h> #include <ctype.h> #include <memory> #include <set> #include <string> #include <android-base/parseint.h> #include <android-base/stringprintf.h> #include "applypatch.h" static int EliminateOpenFiles(char** files, int file_count) { DIR* d; struct dirent* de; d = opendir("/proc"); if (d == NULL) { static int EliminateOpenFiles(std::set<std::string>* files) { std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir); if (!d) { printf("error opening /proc: %s\n", strerror(errno)); return -1; } while ((de = readdir(d)) != 0) { int i; for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i); if (de->d_name[i]) continue; // de->d_name[i] is numeric char path[FILENAME_MAX]; strcpy(path, "/proc/"); strcat(path, de->d_name); strcat(path, "/fd/"); struct dirent* de; while ((de = readdir(d.get())) != 0) { unsigned int pid; if (!android::base::ParseUint(de->d_name, &pid)) { continue; } std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name); DIR* fdd; struct dirent* fdde; fdd = opendir(path); if (fdd == NULL) { printf("error opening %s: %s\n", path, strerror(errno)); std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir); if (!fdd) { printf("error opening %s: %s\n", path.c_str(), strerror(errno)); continue; } while ((fdde = readdir(fdd)) != 0) { char fd_path[FILENAME_MAX]; while ((fdde = readdir(fdd.get())) != 0) { std::string fd_path = path + fdde->d_name; char link[FILENAME_MAX]; strcpy(fd_path, path); strcat(fd_path, fdde->d_name); int count; count = readlink(fd_path, link, sizeof(link)-1); int count = readlink(fd_path.c_str(), link, sizeof(link)-1); if (count >= 0) { link[count] = '\0'; // This is inefficient, but it should only matter if there are // lots of files in /cache, and lots of them are open (neither // of which should be true, especially in recovery). if (strncmp(link, "/cache/", 7) == 0) { int j; for (j = 0; j < file_count; ++j) { if (files[j] && strcmp(files[j], link) == 0) { if (files->erase(link) > 0) { printf("%s is open by %s\n", link, de->d_name); free(files[j]); files[j] = NULL; } } } } } closedir(fdd); } closedir(d); return 0; } int FindExpendableFiles(char*** names, int* entries) { DIR* d; struct dirent* de; int size = 32; *entries = 0; *names = reinterpret_cast<char**>(malloc(size * sizeof(char*))); char path[FILENAME_MAX]; static std::set<std::string> FindExpendableFiles() { std::set<std::string> files; // We're allowed to delete unopened regular files in any of these // directories. const char* dirs[2] = {"/cache", "/cache/recovery/otatest"}; for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) { d = opendir(dirs[i]); if (d == NULL) { std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirs[i]), closedir); if (!d) { printf("error opening %s: %s\n", dirs[i], strerror(errno)); continue; } // Look for regular files in the directory (not in any subdirectories). while ((de = readdir(d)) != 0) { strcpy(path, dirs[i]); strcat(path, "/"); strcat(path, de->d_name); struct dirent* de; while ((de = readdir(d.get())) != 0) { std::string path = std::string(dirs[i]) + "/" + de->d_name; // We can't delete CACHE_TEMP_SOURCE; if it's there we might have // restarted during installation and could be depending on it to // be there. if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue; if (path == CACHE_TEMP_SOURCE) { continue; } struct stat st; if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { if (*entries >= size) { size *= 2; *names = reinterpret_cast<char**>(realloc(*names, size * sizeof(char*))); } (*names)[(*entries)++] = strdup(path); if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { files.insert(path); } } closedir(d); } printf("%d regular files in deletable directories\n", *entries); if (EliminateOpenFiles(*names, *entries) < 0) { return -1; printf("%zu regular files in deletable directories\n", files.size()); if (EliminateOpenFiles(&files) < 0) { return std::set<std::string>(); } return 0; return files; } int MakeFreeSpaceOnCache(size_t bytes_needed) { Loading @@ -147,15 +118,8 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) { if (free_now >= bytes_needed) { return 0; } char** names; int entries; if (FindExpendableFiles(&names, &entries) < 0) { return -1; } if (entries == 0) { std::set<std::string> files = FindExpendableFiles(); if (files.empty()) { // nothing we can delete to free up space! printf("no files can be deleted to free space on /cache\n"); return -1; Loading @@ -167,20 +131,13 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) { // // Instead, we'll be dumb. int i; for (i = 0; i < entries && free_now < bytes_needed; ++i) { if (names[i]) { unlink(names[i]); for (const auto& file : files) { unlink(file.c_str()); free_now = FreeSpaceForFile("/cache"); printf("deleted %s; now %zu bytes free\n", names[i], free_now); free(names[i]); printf("deleted %s; now %zu bytes free\n", file.c_str(), free_now); if (free_now < bytes_needed) { break; } } for (; i < entries; ++i) { free(names[i]); } free(names); return (free_now >= bytes_needed) ? 0 : -1; } Loading
applypatch/Android.mk +3 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,9 @@ 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 LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \ libedify \ LOCAL_SHARED_LIBRARIES += libz libcutils libc include $(BUILD_EXECUTABLE) Loading
applypatch/applypatch.cpp +83 −96 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ #include <sys/types.h> #include <unistd.h> #include <memory> #include <string> #include <android-base/strings.h> #include "openssl/sha.h" Loading Loading @@ -68,25 +71,29 @@ int LoadFileContents(const char* filename, FileContents* file) { } file->size = file->st.st_size; file->data = reinterpret_cast<unsigned char*>(malloc(file->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; } FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); free(file->data); file->data = NULL; return -1; } size_t bytes_read = ota_fread(file->data, 1, file->size, f); 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); free(file->data); file->data = NULL; fclose(f); return -1; } ota_fclose(f); file->data = data.release(); SHA1(file->data, file->size, file->sha1); return 0; } Loading Loading @@ -186,7 +193,7 @@ 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 = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]])); file->data = static_cast<unsigned char*>(malloc(size[index[pairs-1]])); char* p = (char*)file->data; file->size = 0; // # bytes read so far bool found = false; Loading Loading @@ -314,7 +321,7 @@ int SaveFileContents(const char* filename, const FileContents* file) { // "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(unsigned char* data, size_t len, const char* target) { int WriteToPartition(const unsigned char* data, size_t len, const char* target) { std::string copy(target); std::vector<std::string> pieces = android::base::Split(copy, ":"); Loading Loading @@ -353,7 +360,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) { return -1; } size_t written = mtd_write_data(ctx, reinterpret_cast<char*>(data), len); size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len); if (written != len) { printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); mtd_write_close(ctx); Loading Loading @@ -579,7 +586,7 @@ int ShowLicenses() { } ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { int fd = *reinterpret_cast<int *>(token); int fd = *static_cast<int*>(token); ssize_t done = 0; ssize_t wrote; while (done < len) { Loading @@ -593,19 +600,9 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { return done; } typedef struct { unsigned char* buffer; ssize_t size; ssize_t pos; } MemorySinkInfo; ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { MemorySinkInfo* msi = reinterpret_cast<MemorySinkInfo*>(token); if (msi->size - msi->pos < len) { return -1; } memcpy(msi->buffer + msi->pos, data, len); msi->pos += len; std::string* s = static_cast<std::string*>(token); s->append(reinterpret_cast<const char*>(data), len); return len; } Loading Loading @@ -816,31 +813,52 @@ static int GenerateTarget(FileContents* source_file, const Value* bonus_data) { int retry = 1; SHA_CTX ctx; int output; MemorySinkInfo msi; std::string memory_sink_str; FileContents* source_to_use; char* outname; int made_copy = 0; bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 || 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(). char target_fs[strlen(target_filename)+1]; char* slash = strchr(target_filename+1, '/'); if (slash != NULL) { int count = slash - target_filename; strncpy(target_fs, target_filename, count); target_fs[count] = '\0'; 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 { strcpy(target_fs, target_filename); source_to_use = copy_file; patch = copy_patch_value; } if (patch->type != VAL_BLOB) { printf("patch is not a blob\n"); return 1; } char* header = patch->data; ssize_t header_bytes_read = patch->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; } do { // Is there enough room in the target filesystem to hold the patched // file? if (strncmp(target_filename, "MTD:", 4) == 0 || strncmp(target_filename, "EMMC:", 5) == 0) { 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 Loading @@ -862,7 +880,7 @@ static int GenerateTarget(FileContents* source_file, } else { int enough_space = 0; if (retry > 0) { size_t free_space = FreeSpaceForFile(target_fs); 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 Loading Loading @@ -902,84 +920,53 @@ static int GenerateTarget(FileContents* source_file, made_copy = 1; unlink(source_filename); size_t free_space = FreeSpaceForFile(target_fs); size_t free_space = FreeSpaceForFile(target_fs.c_str()); printf("(now %zu bytes free for target) ", free_space); } } 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; } SinkFn sink = NULL; void* token = NULL; output = -1; outname = NULL; if (strncmp(target_filename, "MTD:", 4) == 0 || strncmp(target_filename, "EMMC:", 5) == 0) { int output_fd = -1; if (target_is_partition) { // We store the decoded output in memory. msi.buffer = reinterpret_cast<unsigned char*>(malloc(target_size)); if (msi.buffer == NULL) { printf("failed to alloc %zu bytes for output\n", target_size); return 1; } msi.pos = 0; msi.size = target_size; sink = MemorySink; token = &msi; token = &memory_sink_str; } else { // We write the decoded output to "<tgt-file>.patch". outname = reinterpret_cast<char*>(malloc(strlen(target_filename) + 10)); strcpy(outname, target_filename); strcat(outname, ".patch"); output = ota_open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR); if (output < 0) { printf("failed to open output file %s: %s\n", outname, strerror(errno)); 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; token = &output_fd; } char* header = patch->data; ssize_t header_bytes_read = patch->size; SHA1_Init(&ctx); int result; if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) { if (use_bsdiff) { result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size, patch, 0, sink, token, &ctx); } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) { } else { result = ApplyImagePatch(source_to_use->data, source_to_use->size, patch, sink, token, &ctx, bonus_data); } else { printf("Unknown patch file format\n"); return 1; } if (output >= 0) { if (ota_fsync(output) != 0) { printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno)); 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) != 0) { printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno)); if (ota_close(output_fd) != 0) { printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(), strerror(errno)); result = 1; } } Loading @@ -991,8 +978,8 @@ static int GenerateTarget(FileContents* source_file, } else { printf("applying patch failed; retrying\n"); } if (outname != NULL) { unlink(outname); if (!target_is_partition) { unlink(tmp_target_filename.c_str()); } } else { // succeeded; no need to retry Loading @@ -1009,27 +996,27 @@ static int GenerateTarget(FileContents* source_file, printf("now %s\n", short_sha1(target_sha1).c_str()); } if (output < 0) { if (target_is_partition) { // Copy the temp file to the partition. if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) { if (WriteToPartition(reinterpret_cast<const unsigned char*>(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; } free(msi.buffer); } else { // Give the .patch file the same owner, group, and mode of the // original source file. if (chmod(outname, source_to_use->st.st_mode) != 0) { printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno)); 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(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) { printf("chown of \"%s\" failed: %s\n", outname, strerror(errno)); 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(outname, target_filename) != 0) { 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; } Loading
applypatch/applypatch.h +7 −4 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ #define _APPLYPATCH_H #include <sys/stat.h> #include <vector> #include "openssl/sha.h" #include "edify/expr.h" Loading Loading @@ -68,22 +71,22 @@ void FreeFileContents(FileContents* file); int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str, int num_patches); // bsdiff.c // 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, unsigned char** new_data, ssize_t* new_size); std::vector<unsigned char>* new_data); // imgpatch.c // 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.c // freecache.cpp int MakeFreeSpaceOnCache(size_t bytes_needed); #endif
applypatch/bspatch.cpp +14 −23 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ #include <sys/stat.h> #include <sys/types.h> #include <errno.h> #include <malloc.h> #include <unistd.h> #include <string.h> Loading Loading @@ -103,26 +102,22 @@ 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) { unsigned char* new_data; ssize_t new_size; if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data, &new_size) != 0) { std::vector<unsigned char> new_data; if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) { return -1; } if (sink(new_data, new_size, token) < new_size) { if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) { printf("short write of output: %d (%s)\n", errno, strerror(errno)); return 1; } if (ctx) SHA1_Update(ctx, new_data, new_size); free(new_data); 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, unsigned char** new_data, ssize_t* new_size) { std::vector<unsigned char>* new_data) { // Patch data format: // 0 8 "BSDIFF40" // 8 8 X Loading @@ -141,12 +136,12 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, return 1; } ssize_t ctrl_len, data_len; ssize_t ctrl_len, data_len, new_size; ctrl_len = offtin(header+8); data_len = offtin(header+16); *new_size = offtin(header+24); new_size = offtin(header+24); if (ctrl_len < 0 || data_len < 0 || *new_size < 0) { if (ctrl_len < 0 || data_len < 0 || new_size < 0) { printf("corrupt patch file header (data lengths)\n"); return 1; } Loading Loading @@ -183,18 +178,14 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, printf("failed to bzinit extra stream (%d)\n", bzerr); } *new_data = reinterpret_cast<unsigned char*>(malloc(*new_size)); if (*new_data == NULL) { printf("failed to allocate %zd bytes of memory for output file\n", *new_size); return 1; } new_data->resize(new_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) { while (newpos < new_size) { // Read control data if (FillBuffer(buf, 24, &cstream) != 0) { printf("error while reading control stream\n"); Loading @@ -210,13 +201,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, } // Sanity check if (newpos + ctrl[0] > *new_size) { if (newpos + ctrl[0] > new_size) { printf("corrupt patch (new file overrun)\n"); return 1; } // Read diff string if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) { if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) { printf("error while reading diff stream\n"); return 1; } Loading @@ -233,13 +224,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, oldpos += ctrl[0]; // Sanity check if (newpos + ctrl[1] > *new_size) { if (newpos + ctrl[1] > new_size) { printf("corrupt patch (new file overrun)\n"); return 1; } // Read extra string if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) { if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) { printf("error while reading extra stream\n"); return 1; } Loading
applypatch/freecache.cpp +49 −92 Original line number Diff line number Diff line Loading @@ -25,119 +25,90 @@ #include <dirent.h> #include <ctype.h> #include <memory> #include <set> #include <string> #include <android-base/parseint.h> #include <android-base/stringprintf.h> #include "applypatch.h" static int EliminateOpenFiles(char** files, int file_count) { DIR* d; struct dirent* de; d = opendir("/proc"); if (d == NULL) { static int EliminateOpenFiles(std::set<std::string>* files) { std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir); if (!d) { printf("error opening /proc: %s\n", strerror(errno)); return -1; } while ((de = readdir(d)) != 0) { int i; for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i); if (de->d_name[i]) continue; // de->d_name[i] is numeric char path[FILENAME_MAX]; strcpy(path, "/proc/"); strcat(path, de->d_name); strcat(path, "/fd/"); struct dirent* de; while ((de = readdir(d.get())) != 0) { unsigned int pid; if (!android::base::ParseUint(de->d_name, &pid)) { continue; } std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name); DIR* fdd; struct dirent* fdde; fdd = opendir(path); if (fdd == NULL) { printf("error opening %s: %s\n", path, strerror(errno)); std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir); if (!fdd) { printf("error opening %s: %s\n", path.c_str(), strerror(errno)); continue; } while ((fdde = readdir(fdd)) != 0) { char fd_path[FILENAME_MAX]; while ((fdde = readdir(fdd.get())) != 0) { std::string fd_path = path + fdde->d_name; char link[FILENAME_MAX]; strcpy(fd_path, path); strcat(fd_path, fdde->d_name); int count; count = readlink(fd_path, link, sizeof(link)-1); int count = readlink(fd_path.c_str(), link, sizeof(link)-1); if (count >= 0) { link[count] = '\0'; // This is inefficient, but it should only matter if there are // lots of files in /cache, and lots of them are open (neither // of which should be true, especially in recovery). if (strncmp(link, "/cache/", 7) == 0) { int j; for (j = 0; j < file_count; ++j) { if (files[j] && strcmp(files[j], link) == 0) { if (files->erase(link) > 0) { printf("%s is open by %s\n", link, de->d_name); free(files[j]); files[j] = NULL; } } } } } closedir(fdd); } closedir(d); return 0; } int FindExpendableFiles(char*** names, int* entries) { DIR* d; struct dirent* de; int size = 32; *entries = 0; *names = reinterpret_cast<char**>(malloc(size * sizeof(char*))); char path[FILENAME_MAX]; static std::set<std::string> FindExpendableFiles() { std::set<std::string> files; // We're allowed to delete unopened regular files in any of these // directories. const char* dirs[2] = {"/cache", "/cache/recovery/otatest"}; for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) { d = opendir(dirs[i]); if (d == NULL) { std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirs[i]), closedir); if (!d) { printf("error opening %s: %s\n", dirs[i], strerror(errno)); continue; } // Look for regular files in the directory (not in any subdirectories). while ((de = readdir(d)) != 0) { strcpy(path, dirs[i]); strcat(path, "/"); strcat(path, de->d_name); struct dirent* de; while ((de = readdir(d.get())) != 0) { std::string path = std::string(dirs[i]) + "/" + de->d_name; // We can't delete CACHE_TEMP_SOURCE; if it's there we might have // restarted during installation and could be depending on it to // be there. if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue; if (path == CACHE_TEMP_SOURCE) { continue; } struct stat st; if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { if (*entries >= size) { size *= 2; *names = reinterpret_cast<char**>(realloc(*names, size * sizeof(char*))); } (*names)[(*entries)++] = strdup(path); if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { files.insert(path); } } closedir(d); } printf("%d regular files in deletable directories\n", *entries); if (EliminateOpenFiles(*names, *entries) < 0) { return -1; printf("%zu regular files in deletable directories\n", files.size()); if (EliminateOpenFiles(&files) < 0) { return std::set<std::string>(); } return 0; return files; } int MakeFreeSpaceOnCache(size_t bytes_needed) { Loading @@ -147,15 +118,8 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) { if (free_now >= bytes_needed) { return 0; } char** names; int entries; if (FindExpendableFiles(&names, &entries) < 0) { return -1; } if (entries == 0) { std::set<std::string> files = FindExpendableFiles(); if (files.empty()) { // nothing we can delete to free up space! printf("no files can be deleted to free space on /cache\n"); return -1; Loading @@ -167,20 +131,13 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) { // // Instead, we'll be dumb. int i; for (i = 0; i < entries && free_now < bytes_needed; ++i) { if (names[i]) { unlink(names[i]); for (const auto& file : files) { unlink(file.c_str()); free_now = FreeSpaceForFile("/cache"); printf("deleted %s; now %zu bytes free\n", names[i], free_now); free(names[i]); printf("deleted %s; now %zu bytes free\n", file.c_str(), free_now); if (free_now < bytes_needed) { break; } } for (; i < entries; ++i) { free(names[i]); } free(names); return (free_now >= bytes_needed) ? 0 : -1; }