From fc8a3c5fb41a45476ef620c4728d59f581b72bca Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 24 Oct 2018 21:08:06 -0400 Subject: [PATCH] Migrate MagiskBoot to C++ --- native/jni/Android.mk | 16 +- native/jni/magiskboot/bootimg.cpp | 10 +- .../magiskboot/{compress.c => compress.cpp} | 105 +++---- native/jni/magiskboot/cpio.c | 260 ----------------- native/jni/magiskboot/cpio.cpp | 272 ++++++++++++++++++ native/jni/magiskboot/cpio.h | 78 ++--- native/jni/magiskboot/{dtb.c => dtb.cpp} | 16 +- .../jni/magiskboot/{format.c => format.cpp} | 2 +- native/jni/magiskboot/format.h | 4 +- .../magiskboot/{hexpatch.c => hexpatch.cpp} | 16 +- native/jni/magiskboot/magiskboot.h | 13 +- native/jni/magiskboot/{main.c => main.cpp} | 11 +- .../jni/magiskboot/{pattern.c => pattern.cpp} | 6 +- .../jni/magiskboot/{ramdisk.c => ramdisk.cpp} | 235 ++++++++------- native/jni/utils/include/array.h | 138 +++++++++ native/jni/utils/include/logging.h | 7 + native/jni/utils/include/utils.h | 8 + 17 files changed, 683 insertions(+), 514 deletions(-) rename native/jni/magiskboot/{compress.c => compress.cpp} (79%) delete mode 100644 native/jni/magiskboot/cpio.c create mode 100644 native/jni/magiskboot/cpio.cpp rename native/jni/magiskboot/{dtb.c => dtb.cpp} (91%) rename native/jni/magiskboot/{format.c => format.cpp} (98%) rename native/jni/magiskboot/{hexpatch.c => hexpatch.cpp} (69%) rename native/jni/magiskboot/{main.c => main.cpp} (96%) rename native/jni/magiskboot/{pattern.c => pattern.cpp} (91%) rename native/jni/magiskboot/{ramdisk.c => ramdisk.cpp} (52%) create mode 100644 native/jni/utils/include/array.h diff --git a/native/jni/Android.mk b/native/jni/Android.mk index c8d237253..e008ab1fe 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -100,15 +100,15 @@ LOCAL_C_INCLUDES := \ $(LIBUTILS) LOCAL_SRC_FILES := \ - magiskboot/cpio.c \ - magiskboot/main.c \ + magiskboot/main.cpp \ + magiskboot/cpio.cpp \ magiskboot/bootimg.cpp \ - magiskboot/hexpatch.c \ - magiskboot/compress.c \ - magiskboot/format.c \ - magiskboot/dtb.c \ - magiskboot/ramdisk.c \ - magiskboot/pattern.c + magiskboot/hexpatch.cpp \ + magiskboot/compress.cpp \ + magiskboot/format.cpp \ + magiskboot/dtb.cpp \ + magiskboot/ramdisk.cpp \ + magiskboot/pattern.cpp LOCAL_LDLIBS := -lz include $(BUILD_EXECUTABLE) diff --git a/native/jni/magiskboot/bootimg.cpp b/native/jni/magiskboot/bootimg.cpp index e23e15432..6eb4097ee 100644 --- a/native/jni/magiskboot/bootimg.cpp +++ b/native/jni/magiskboot/bootimg.cpp @@ -7,12 +7,10 @@ #include #include -extern "C" { #include "bootimg.h" #include "magiskboot.h" #include "utils.h" #include "logging.h" -} static void dump(void *buf, size_t size, const char *filename) { if (size == 0) @@ -259,7 +257,7 @@ int unpack(const char *image) { // Dump kernel if (COMPRESSED(boot.k_fmt)) { fd = creat(KERNEL_FILE, 0644); - decomp(boot.k_fmt, fd, boot.kernel, boot.hdr->kernel_size); + decompress(boot.k_fmt, fd, boot.kernel, boot.hdr->kernel_size); close(fd); } else { dump(boot.kernel, boot.hdr->kernel_size, KERNEL_FILE); @@ -271,7 +269,7 @@ int unpack(const char *image) { // Dump ramdisk if (COMPRESSED(boot.r_fmt)) { fd = creat(RAMDISK_FILE, 0644); - decomp(boot.r_fmt, fd, boot.ramdisk, boot.hdr->ramdisk_size); + decompress(boot.r_fmt, fd, boot.ramdisk, boot.hdr->ramdisk_size); close(fd); } else { dump(boot.ramdisk, boot.hdr->ramdisk_size, RAMDISK_FILE); @@ -335,7 +333,7 @@ void repack(const char* orig_image, const char* out_image) { size_t raw_size; void *kernel_raw; mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size); - boot.hdr->kernel_size = comp(boot.k_fmt, fd, kernel_raw, raw_size); + boot.hdr->kernel_size = compress(boot.k_fmt, fd, kernel_raw, raw_size); munmap(kernel_raw, raw_size); } else { boot.hdr->kernel_size = restore(KERNEL_FILE, fd); @@ -358,7 +356,7 @@ void repack(const char* orig_image, const char* out_image) { size_t cpio_size; void *cpio; mmap_ro(RAMDISK_FILE, &cpio, &cpio_size); - boot.hdr->ramdisk_size = comp(boot.r_fmt, fd, cpio, cpio_size); + boot.hdr->ramdisk_size = compress(boot.r_fmt, fd, cpio, cpio_size); munmap(cpio, cpio_size); } else { boot.hdr->ramdisk_size = restore(RAMDISK_FILE, fd); diff --git a/native/jni/magiskboot/compress.c b/native/jni/magiskboot/compress.cpp similarity index 79% rename from native/jni/magiskboot/compress.c rename to native/jni/magiskboot/compress.cpp index 74c1f4e6e..af8c8b310 100644 --- a/native/jni/magiskboot/compress.c +++ b/native/jni/magiskboot/compress.cpp @@ -39,7 +39,7 @@ size_t gzip(int mode, int fd, const void *buf, size_t size) { if (ret != Z_OK) LOGE("Unable to init zlib stream\n"); - strm.next_in = (void *) buf; + strm.next_in = (Bytef *) buf; strm.avail_in = size; do { @@ -73,7 +73,7 @@ size_t gzip(int mode, int fd, const void *buf, size_t size) { // Mode: 0 = decode xz/lzma; 1 = encode xz; 2 = encode lzma size_t lzma(int mode, int fd, const void *buf, size_t size) { size_t have, total = 0; - lzma_ret ret = 0; + lzma_ret ret = LZMA_OK; lzma_stream strm = LZMA_STREAM_INIT; lzma_options_lzma opt; unsigned char out[CHUNK]; @@ -82,7 +82,7 @@ size_t lzma(int mode, int fd, const void *buf, size_t size) { lzma_lzma_preset(&opt, 9); lzma_filter filters[] = { { .id = LZMA_FILTER_LZMA2, .options = &opt }, - { .id = LZMA_VLI_UNKNOWN, .options = NULL }, + { .id = LZMA_VLI_UNKNOWN, .options = nullptr }, }; switch(mode) { @@ -101,7 +101,7 @@ size_t lzma(int mode, int fd, const void *buf, size_t size) { if (ret != LZMA_OK) LOGE("Unable to init lzma stream\n"); - strm.next_in = buf; + strm.next_in = static_cast(buf); strm.avail_in = size; do { @@ -119,14 +119,14 @@ size_t lzma(int mode, int fd, const void *buf, size_t size) { } // Mode: 0 = decode; 1 = encode -size_t lz4(int mode, int fd, const void *buf, size_t size) { +size_t lz4(int mode, int fd, const uint8_t *buf, size_t size) { LZ4F_decompressionContext_t dctx; LZ4F_compressionContext_t cctx; LZ4F_frameInfo_t info; size_t blockSize, outCapacity, avail_in, ret = 0, pos = 0, total = 0; size_t have, read; - void *out = NULL; + uint8_t *out = nullptr; // Initialize context switch(mode) { @@ -162,21 +162,21 @@ size_t lz4(int mode, int fd, const void *buf, size_t size) { pos += read; break; case 1: - outCapacity = LZ4F_compressFrameBound(blockSize, NULL); + outCapacity = LZ4F_compressFrameBound(blockSize, nullptr); break; } - out = xmalloc(outCapacity); + out = new uint8_t[outCapacity]; // Write header if (mode == 1) { - LZ4F_preferences_t prefs; - memset(&prefs, 0, sizeof(prefs)); + LZ4F_preferences_t prefs = LZ4F_preferences_t(); prefs.autoFlush = 1; prefs.compressionLevel = 9; - prefs.frameInfo.blockMode = 1; - prefs.frameInfo.blockSizeID = 7; - prefs.frameInfo.contentChecksumFlag = 1; + prefs.frameInfo.blockMode = LZ4F_blockIndependent; + prefs.frameInfo.blockSizeID = LZ4F_max4MB; + prefs.frameInfo.blockChecksumFlag = LZ4F_noBlockChecksum; + prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; have = ret = LZ4F_compressBegin(cctx, out, size, &prefs); if (LZ4F_isError(ret)) LOGE("Failed to start compression: error %s\n", LZ4F_getErrorName(ret)); @@ -195,11 +195,11 @@ size_t lz4(int mode, int fd, const void *buf, size_t size) { case 0: have = outCapacity; read = avail_in; - ret = LZ4F_decompress(dctx, out, &have, buf + pos, &read, NULL); + ret = LZ4F_decompress(dctx, out, &have, buf + pos, &read, nullptr); break; case 1: read = avail_in; - have = ret = LZ4F_compressUpdate(cctx, out, outCapacity, buf + pos, avail_in, NULL); + have = ret = LZ4F_compressUpdate(cctx, out, outCapacity, buf + pos, avail_in, nullptr); break; } if (LZ4F_isError(ret)) @@ -218,7 +218,7 @@ size_t lz4(int mode, int fd, const void *buf, size_t size) { LZ4F_freeDecompressionContext(dctx); break; case 1: - have = ret = LZ4F_compressEnd(cctx, out, outCapacity, NULL); + have = ret = LZ4F_compressEnd(cctx, out, outCapacity, nullptr); if (LZ4F_isError(ret)) LOGE("Failed to end compression: error %s\n", LZ4F_getErrorName(ret)); @@ -228,7 +228,7 @@ size_t lz4(int mode, int fd, const void *buf, size_t size) { break; } - free(out); + delete[] out; return total; } @@ -238,9 +238,9 @@ size_t bzip2(int mode, int fd, const void* buf, size_t size) { bz_stream strm; char out[CHUNK]; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; + strm.bzalloc = nullptr; + strm.bzfree = nullptr; + strm.opaque = nullptr; switch(mode) { case 0: @@ -254,7 +254,7 @@ size_t bzip2(int mode, int fd, const void* buf, size_t size) { if (ret != BZ_OK) LOGE("Unable to init bzlib stream\n"); - strm.next_in = (void *) buf; + strm.next_in = (char *) buf; strm.avail_in = size; do { @@ -286,7 +286,7 @@ size_t bzip2(int mode, int fd, const void* buf, size_t size) { #define LZ4_LEGACY_BLOCKSIZE 0x800000 // Mode: 0 = decode; 1 = encode -size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { +size_t lz4_legacy(int mode, int fd, const uint8_t *buf, size_t size) { size_t pos = 0; int have; char *out; @@ -294,12 +294,12 @@ size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { switch(mode) { case 0: - out = xmalloc(LZ4_LEGACY_BLOCKSIZE); + out = new char[LZ4_LEGACY_BLOCKSIZE]; // Skip magic pos += 4; break; case 1: - out = xmalloc(LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE)); + out = new char[LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE)]; // Write magic total += xwrite(fd, "\x02\x21\x4c\x18", 4); break; @@ -313,7 +313,7 @@ size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { pos += 4; if (block_size > LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE)) goto done; - have = LZ4_decompress_safe(buf + pos, out, block_size, LZ4_LEGACY_BLOCKSIZE); + have = LZ4_decompress_safe((const char *) buf + pos, out, block_size, LZ4_LEGACY_BLOCKSIZE); if (have < 0) LOGE("Cannot decode lz4_legacy block\n"); pos += block_size; @@ -323,7 +323,7 @@ size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) { insize = size - pos; else insize = LZ4_LEGACY_BLOCKSIZE; - have = LZ4_compress_HC(buf + pos, out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE), 9); + have = LZ4_compress_HC((const char *) buf + pos, out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE), 9); if (have == 0) LOGE("lz4_legacy compression error\n"); pos += insize; @@ -341,44 +341,46 @@ done: unsigned uncomp = size; xwrite(fd, &uncomp, sizeof(uncomp)); } - free(out); + delete[] out; return total; } -long long decomp(format_t type, int to, const void *from, size_t size) { +long long decompress(format_t type, int fd, const void *from, size_t size) { + const uint8_t *buf = (uint8_t *) from; switch (type) { case GZIP: - return gzip(0, to, from, size); + return gzip(0, fd, buf, size); case XZ: - return lzma(0, to, from, size); + return lzma(0, fd, buf, size); case LZMA: - return lzma(0, to, from, size); + return lzma(0, fd, buf, size); case BZIP2: - return bzip2(0, to, from, size); + return bzip2(0, fd, buf, size); case LZ4: - return lz4(0, to, from, size); + return lz4(0, fd, buf, size); case LZ4_LEGACY: - return lz4_legacy(0, to, from, size); + return lz4_legacy(0, fd, buf, size); default: // Unsupported return -1; } } -long long comp(format_t type, int to, const void *from, size_t size) { +long long compress(format_t type, int fd, const void *from, size_t size) { + const uint8_t *buf = (uint8_t *) from; switch (type) { case GZIP: - return gzip(1, to, from, size); + return gzip(1, fd, buf, size); case XZ: - return lzma(1, to, from, size); + return lzma(1, fd, buf, size); case LZMA: - return lzma(2, to, from, size); + return lzma(2, fd, buf, size); case BZIP2: - return bzip2(1, to, from, size); + return bzip2(1, fd, buf, size); case LZ4: - return lz4(1, to, from, size); + return lz4(1, fd, buf, size); case LZ4_LEGACY: - return lz4_legacy(1, to, from, size); + return lz4_legacy(1, fd, buf, size); default: // Unsupported return -1; @@ -389,7 +391,7 @@ long long comp(format_t type, int to, const void *from, size_t size) { * Below are utility functions for commandline */ -void decomp_file(char *from, const char *to) { +void decompress(char *from, const char *to) { int strip = 1; void *file; size_t size = 0; @@ -400,9 +402,9 @@ void decomp_file(char *from, const char *to) { format_t type = check_fmt(file, size); char *ext; ext = strrchr(from, '.'); - if (to == NULL) + if (to == nullptr) to = from; - if (ext != NULL) { + if (ext != nullptr) { // Strip out a matched file extension switch (type) { case GZIP: @@ -442,9 +444,9 @@ void decomp_file(char *from, const char *to) { fprintf(stderr, "Decompressing to [%s]\n", to); } - decomp(type, fd, file, size); + decompress(type, fd, file, size); close(fd); - if (to == from && ext != NULL) { + if (to == from && ext != nullptr) { *ext = '.'; unlink(from); } @@ -454,9 +456,10 @@ void decomp_file(char *from, const char *to) { munmap(file, size); } -void comp_file(const char *method, const char *from, const char *to) { +void compress(const char *method, const char *from, const char *to) { format_t type; - char *ext, dest[PATH_MAX]; + const char *ext; + char dest[PATH_MAX]; if (strcmp(method, "gzip") == 0) { type = GZIP; ext = "gz"; @@ -488,7 +491,7 @@ void comp_file(const char *method, const char *from, const char *to) { stream_full_read(STDIN_FILENO, &file, &size); else mmap_ro(from, &file, &size); - if (to == NULL) { + if (to == nullptr) { if (strcmp(from, "-") == 0) strcpy(dest, "-"); else @@ -502,13 +505,13 @@ void comp_file(const char *method, const char *from, const char *to) { fd = creat(dest, 0644); fprintf(stderr, "Compressing to [%s]\n", dest); } - comp(type, fd, file, size); + compress(type, fd, file, size); close(fd); if (strcmp(from, "-") == 0) free(file); else munmap(file, size); - if (to == NULL) + if (to == nullptr) unlink(from); } diff --git a/native/jni/magiskboot/cpio.c b/native/jni/magiskboot/cpio.c deleted file mode 100644 index bfd04f5e6..000000000 --- a/native/jni/magiskboot/cpio.c +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include -#include -#include -#include - -#include "cpio.h" -#include "logging.h" -#include "utils.h" - -static uint32_t x8u(char *hex) { - uint32_t val, inpos = 8, outpos; - char pattern[6]; - - while (*hex == '0') { - hex++; - if (!--inpos) return 0; - } - // Because scanf gratuitously treats %*X differently than printf does. - sprintf(pattern, "%%%dx%%n", inpos); - sscanf(hex, pattern, &val, &outpos); - if (inpos != outpos) LOGE("bad cpio header\n"); - - return val; -} - -void cpio_free(cpio_entry *e) { - if (e) { - free(e->filename); - free(e->data); - free(e); - } -} - -int cpio_find(struct vector *v, const char *entry) { - cpio_entry *e; - vec_for_each(v, e) { - if (!e) continue; - if (strcmp(e->filename, entry) == 0) - return _; - } - return -1; -} - -int cpio_cmp(const void *a, const void *b) { - return strcmp(((cpio_entry *) a)->filename, ((cpio_entry *) b)->filename); -} - -void cpio_vec_insert(struct vector *v, cpio_entry *n) { - int i = cpio_find(v, n->filename); - if (i >= 0) { - // Replace, then all is done - cpio_free(vec_entry(v)[i]); - vec_entry(v)[i] = n; - return; - } - vec_push_back(v, n); -} - -// Parse cpio file to a vector of cpio_entry -#define parse_align() lseek(fd, align(lseek(fd, 0, SEEK_CUR), 4), SEEK_SET) -void parse_cpio(struct vector *v, const char *filename) { - int fd = open(filename, O_RDONLY); - if (fd < 0) return; - fprintf(stderr, "Loading cpio: [%s]\n", filename); - cpio_newc_header header; - cpio_entry *f; - while(xxread(fd, &header, 110) != -1) { - f = xcalloc(sizeof(*f), 1); - // f->ino = x8u(header.ino); - f->mode = x8u(header.mode); - f->uid = x8u(header.uid); - f->gid = x8u(header.gid); - // f->nlink = x8u(header.nlink); - // f->mtime = x8u(header.mtime); - f->filesize = x8u(header.filesize); - // f->devmajor = x8u(header.devmajor); - // f->devminor = x8u(header.devminor); - // f->rdevmajor = x8u(header.rdevmajor); - // f->rdevminor = x8u(header.rdevminor); - uint32_t namesize = x8u(header.namesize); - // f->check = x8u(header.check); - f->filename = xmalloc(namesize); - xxread(fd, f->filename, namesize); - parse_align(); - if (strcmp(f->filename, ".") == 0 || strcmp(f->filename, "..") == 0) { - cpio_free(f); - continue; - } - if (strcmp(f->filename, "TRAILER!!!") == 0) { - cpio_free(f); - break; - } - if (f->filesize) { - f->data = xmalloc(f->filesize); - xxread(fd, f->data, f->filesize); - parse_align(); - } - vec_push_back(v, f); - } - close(fd); -} - -#define dump_align() write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), 4)) -void dump_cpio(struct vector *v, const char *filename) { - fprintf(stderr, "Dump cpio: [%s]\n", filename); - unsigned inode = 300000; - char header[111]; - // Sort by name - vec_sort(v, cpio_cmp); - cpio_entry *e; - int fd = creat(filename, 0644); - vec_for_each(v, e) { - sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", - inode++, // e->ino - e->mode, - e->uid, - e->gid, - 1, // e->nlink - 0, // e->mtime - e->filesize, - 0, // e->devmajor - 0, // e->devminor - 0, // e->rdevmajor - 0, // e->rdevminor - (uint32_t) strlen(e->filename) + 1, - 0 // e->check - ); - xwrite(fd, header, 110); - xwrite(fd, e->filename, strlen(e->filename) + 1); - dump_align(); - if (e->filesize) { - xwrite(fd, e->data, e->filesize); - dump_align(); - } - } - // Write trailer - sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", inode++, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0); - xwrite(fd, header, 110); - xwrite(fd, "TRAILER!!!\0", 11); - dump_align(); - close(fd); -} - -void cpio_vec_destroy(struct vector *v) { - // Free each cpio_entry - cpio_entry *e; - vec_for_each(v, e) - cpio_free(e); - vec_destroy(v); -} - -void cpio_rm(struct vector *v, int recursive, const char *entry) { - cpio_entry *e; - size_t len = strlen(entry); - vec_for_each(v, e) { - if (!e) continue; - if (strncmp(e->filename, entry, len) == 0) { - if ((recursive && e->filename[len] == '/') || e->filename[len] == '\0') { - fprintf(stderr, "Remove [%s]\n", e->filename); - cpio_free(e); - vec_cur(v) = NULL; - if (!recursive) return; - } - } - } -} - -void cpio_mkdir(struct vector *v, mode_t mode, const char *entry) { - cpio_entry *e = xcalloc(sizeof(*e), 1); - e->mode = S_IFDIR | mode; - e->filename = strdup(entry); - cpio_vec_insert(v, e); - fprintf(stderr, "Create directory [%s] (%04o)\n",entry, mode); -} - -void cpio_ln(struct vector *v, const char *target, const char *entry) { - cpio_entry *e = xcalloc(sizeof(*e), 1); - e->mode = S_IFLNK; - e->filename = strdup(entry); - e->filesize = strlen(target); - e->data = strdup(target); - cpio_vec_insert(v, e); - fprintf(stderr, "Create symlink [%s] -> [%s]\n", entry, target); -} - -void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename) { - int fd = xopen(filename, O_RDONLY); - cpio_entry *e = xcalloc(sizeof(*e), 1); - e->mode = S_IFREG | mode; - e->filename = strdup(entry); - e->filesize = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - e->data = xmalloc(e->filesize); - xxread(fd, e->data, e->filesize); - close(fd); - cpio_vec_insert(v, e); - fprintf(stderr, "Add entry [%s] (%04o)\n", entry, mode); -} - -int cpio_mv(struct vector *v, const char *from, const char *to) { - struct cpio_entry *e; - int f = cpio_find(v, from), t = cpio_find(v, to); - if (f > 0) { - if (t > 0) { - cpio_free(vec_entry(v)[t]); - vec_entry(v)[t] = NULL; - } - e = vec_entry(v)[f]; - free(e->filename); - e->filename = strdup(to); - return 0; - } - fprintf(stderr, "Cannot find entry %s\n", from); - return 1; -} - -int cpio_extract(struct vector *v, const char *entry, const char *filename) { - int i = cpio_find(v, entry); - if (i > 0) { - cpio_entry *e = vec_entry(v)[i]; - fprintf(stderr, "Extracting [%s] to [%s]\n", entry, filename); - if (S_ISREG(e->mode)) { - int fd = creat(filename, e->mode & 0777); - xwrite(fd, e->data, e->filesize); - fchown(fd, e->uid, e->gid); - close(fd); - } else if (S_ISLNK(e->mode)) { - char *target = xcalloc(e->filesize + 1, 1); - memcpy(target, e->data, e->filesize); - unlink(filename); - symlink(target, filename); - } - return 0; - } - fprintf(stderr, "Cannot find the file entry [%s]\n", entry); - return 1; -} - -void cpio_extract_all(struct vector *v) { - cpio_entry *e; - vec_for_each(v, e) { - if (!e) continue; - fprintf(stderr, "Extracting [%s]\n", e->filename); - unlink(e->filename); - rmdir(e->filename); - if (S_ISDIR(e->mode)) { - mkdir(e->filename, e->mode & 0777); - } else if (S_ISREG(e->mode)) { - int fd = creat(e->filename, e->mode & 0777); - xwrite(fd, e->data, e->filesize); - fchown(fd, e->uid, e->gid); - close(fd); - } else if (S_ISLNK(e->mode)) { - char *target = xcalloc(e->filesize + 1, 1); - memcpy(target, e->data, e->filesize); - symlink(target, e->filename); - } - } -} diff --git a/native/jni/magiskboot/cpio.cpp b/native/jni/magiskboot/cpio.cpp new file mode 100644 index 000000000..264e364f0 --- /dev/null +++ b/native/jni/magiskboot/cpio.cpp @@ -0,0 +1,272 @@ +#include +#include +#include +#include + +#include "cpio.h" +#include "utils.h" +#include "logging.h" + +#define parse_align() lseek(fd, align(lseek(fd, 0, SEEK_CUR), 4), SEEK_SET) + +static uint32_t x8u(char *hex) { + uint32_t val, inpos = 8, outpos; + char pattern[6]; + + while (*hex == '0') { + hex++; + if (!--inpos) return 0; + } + // Because scanf gratuitously treats %*X differently than printf does. + sprintf(pattern, "%%%dx%%n", inpos); + sscanf(hex, pattern, &val, &outpos); + if (inpos != outpos) + LOGE("bad cpio header\n"); + + return val; +} + +cpio_entry::cpio_entry(int fd, cpio_newc_header &header) { + // ino = x8u(header.ino); + mode = x8u(header.mode); + uid = x8u(header.uid); + gid = x8u(header.gid); + // nlink = x8u(header.nlink); + // mtime = x8u(header.mtime); + filesize = x8u(header.filesize); + // devmajor = x8u(header.devmajor); + // devminor = x8u(header.devminor); + // rdevmajor = x8u(header.rdevmajor); + // rdevminor = x8u(header.rdevminor); + uint32_t namesize = x8u(header.namesize); + // check = x8u(header.check); + filename = (char *) xmalloc(namesize); + xxread(fd, filename, namesize); + parse_align(); + if (filesize) { + data = xmalloc(filesize); + xxread(fd, data, filesize); + parse_align(); + } +} + +cpio_entry::~cpio_entry() { + free(filename); + free(data); +} + +// Define the way to sort cpio_entry +template<> +int(*Array::_cmp)(cpio_entry*&, cpio_entry*&) = [](auto a, auto b) -> int { + if (a == b) return 0; + if (a == nullptr) return 1; + if (b == nullptr) return -1; + return strcmp(a->filename, b->filename); +}; + + +cpio::cpio(const char *filename) { + int fd = open(filename, O_RDONLY); + if (fd < 0) return; + fprintf(stderr, "Loading cpio: [%s]\n", filename); + cpio_newc_header header; + cpio_entry *entry; + while(xxread(fd, &header, sizeof(cpio_newc_header)) != -1) { + entry = new cpio_entry(fd, header); + if (strcmp(entry->filename, ".") == 0 || strcmp(entry->filename, "..") == 0 || + strcmp(entry->filename, "TRAILER!!!") == 0) { + delete entry; + if (entry->filename[0] == 'T') + break; + continue; + } + arr.push_back(entry); + } + close(fd); +} + +cpio::~cpio() { + for (auto &e : arr) + if (e) delete e; +} + +#define dump_align() write_zero(fd, align_off(lseek(fd, 0, SEEK_CUR), 4)) +void cpio::dump(const char *file) { + fprintf(stderr, "Dump cpio: [%s]\n", file); + unsigned inode = 300000; + char header[111]; + sort(); + int fd = creat(file, 0644); + for (auto &e : arr) { + sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", + inode++, // e->ino + e->mode, + e->uid, + e->gid, + 1, // e->nlink + 0, // e->mtime + e->filesize, + 0, // e->devmajor + 0, // e->devminor + 0, // e->rdevmajor + 0, // e->rdevminor + (uint32_t) strlen(e->filename) + 1, + 0 // e->check + ); + xwrite(fd, header, 110); + xwrite(fd, e->filename, strlen(e->filename) + 1); + dump_align(); + if (e->filesize) { + xwrite(fd, e->data, e->filesize); + dump_align(); + } + } + // Write trailer + sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", + inode++, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0); + xwrite(fd, header, 110); + xwrite(fd, "TRAILER!!!\0", 11); + dump_align(); + close(fd); +} + +int cpio::find(const char *name) { + for (int i = 0; i < arr.size(); ++i) { + if (!arr[i]) + continue; + if (strcmp(arr[i]->filename, name) == 0) + return i; + } + return -1; +} + +void cpio::insert(cpio_entry *e) { + int i = find(e->filename); + if (i >= 0) { + // Replace, then all is done + delete arr[i]; + arr[i] = e; + return; + } + arr.push_back(e); +} + +void cpio::insert(Array &arr) { + for (auto &e : arr) + insert(e); +} + +void cpio::rm(int recur, const char *name) { + size_t len = strlen(name); + for (auto &e : arr) { + if (!e) + continue; + if (strncmp(e->filename, name, len) == 0 && + ((recur && e->filename[len] == '/') || e->filename[len] == '\0')) { + fprintf(stderr, "Remove [%s]\n", e->filename); + delete e; + e = nullptr; + if (!recur) + return; + } + } +} + +void cpio::makedir(mode_t mode, const char *name) { + auto e = new cpio_entry(); + e->mode = S_IFDIR | mode; + e->filename = strdup(name); + insert(e); + fprintf(stderr, "Create directory [%s] (%04o)\n", name, mode); +} + +void cpio::ln(const char *target, const char *name) { + auto e = new cpio_entry(); + e->mode = S_IFLNK; + e->filename = strdup(name); + e->filesize = strlen(target); + e->data = strdup(target); + insert(e); + fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target); +} + +void cpio::add(mode_t mode, const char *name, const char *file) { + int fd = xopen(file, O_RDONLY); + auto e = new cpio_entry(); + e->mode = S_IFREG | mode; + e->filename = strdup(name); + e->filesize = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + e->data = xmalloc(e->filesize); + xxread(fd, e->data, e->filesize); + close(fd); + insert(e); + fprintf(stderr, "Add entry [%s] (%04o)\n", name, mode); +} + +bool cpio::mv(const char *from, const char *to) { + int f = find(from), t = find(to); + if (f >= 0) { + if (t > 0) { + delete arr[t]; + arr[t] = nullptr; + } + free(arr[f]->filename); + arr[f]->filename = strdup(to); + fprintf(stderr, "Move [%s] -> [%s]\n", from, to); + return true; + } + fprintf(stderr, "Cannot find entry %s\n", from); + return false; +} + +void cpio::extract() { + for (auto &e : arr) { + if (!e) + continue; + fprintf(stderr, "Extract [%s]\n", e->filename); + unlink(e->filename); + rmdir(e->filename); + if (S_ISDIR(e->mode)) { + mkdir(e->filename, e->mode & 0777); + } else if (S_ISREG(e->mode)) { + int fd = creat(e->filename, e->mode & 0777); + xwrite(fd, e->data, e->filesize); + fchown(fd, e->uid, e->gid); + close(fd); + } else if (S_ISLNK(e->mode)) { + char *target = new char[e->filesize + 1]; + memcpy(target, e->data, e->filesize); + symlink(target, e->filename); + delete[] target; + } + } +} + +bool cpio::extract(const char *name, const char *file) { + int i = find(name); + if (i > 0) { + auto e = arr[i]; + fprintf(stderr, "Extract [%s] to [%s]\n", name, file); + if (S_ISREG(e->mode)) { + int fd = creat(file, e->mode & 0777); + xwrite(fd, e->data, e->filesize); + fchown(fd, e->uid, e->gid); + close(fd); + } else if (S_ISLNK(e->mode)) { + char *target = new char[e->filesize + 1]; + memcpy(target, e->data, e->filesize); + symlink(target, e->filename); + delete[] target; + } + return true; + } + fprintf(stderr, "Cannot find the file entry [%s]\n", name); + return false; +} + +void cpio::sort() { + arr.sort(); + while (arr.back() == nullptr) + arr.pop_back(); +} diff --git a/native/jni/magiskboot/cpio.h b/native/jni/magiskboot/cpio.h index 0c7a3f85c..96c662b03 100644 --- a/native/jni/magiskboot/cpio.h +++ b/native/jni/magiskboot/cpio.h @@ -3,9 +3,26 @@ #include -#include "vector.h" +#include "array.h" -typedef struct cpio_entry { +struct cpio_newc_header { + char magic[6]; + char ino[8]; + char mode[8]; + char uid[8]; + char gid[8]; + char nlink[8]; + char mtime[8]; + char filesize[8]; + char devmajor[8]; + char devminor[8]; + char rdevmajor[8]; + char rdevminor[8]; + char namesize[8]; + char check[8]; +} __attribute__((packed)); + +struct cpio_entry { // uint32_t ino; uint32_t mode; uint32_t uid; @@ -21,40 +38,31 @@ typedef struct cpio_entry { // uint32_t check; char *filename; void *data; - int remove; -} cpio_entry; -typedef struct cpio_newc_header { - char magic[6]; - char ino[8]; - char mode[8]; - char uid[8]; - char gid[8]; - char nlink[8]; - char mtime[8]; - char filesize[8]; - char devmajor[8]; - char devminor[8]; - char rdevmajor[8]; - char rdevminor[8]; - char namesize[8]; - char check[8]; -} cpio_newc_header; + cpio_entry() {} + cpio_entry(int fd, cpio_newc_header &header); + ~cpio_entry(); +}; -// Basic cpio functions -void cpio_free(cpio_entry *e); -int cpio_find(struct vector *v, const char *entry); -int cpio_cmp(const void *a, const void *b); -void parse_cpio(struct vector *v, const char *filename); -void dump_cpio(struct vector *v, const char *filename); -void cpio_vec_insert(struct vector *v, cpio_entry *n); -void cpio_vec_destroy(struct vector *v); -void cpio_rm(struct vector *v, int recursive, const char *entry); -void cpio_mkdir(struct vector *v, mode_t mode, const char *entry); -void cpio_ln(struct vector *v, const char *target, const char *entry); -void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename); -int cpio_mv(struct vector *v, const char *from, const char *to); -int cpio_extract(struct vector *v, const char *entry, const char *filename); -void cpio_extract_all(struct vector *v); +class cpio { +public: + cpio(const char *filename); + ~cpio(); + void dump(const char *file); + int find(const char *name); + void insert(cpio_entry *e); + void rm(int recur, const char *name); + void makedir(mode_t mode, const char *name); + void ln(const char *target, const char *name); + void add(mode_t mode, const char *name, const char *file); + void insert(Array &arr); + bool mv(const char *from, const char *to); + void extract(); + bool extract(const char *name, const char *file); + void sort(); + +protected: + Array arr; +}; #endif diff --git a/native/jni/magiskboot/dtb.c b/native/jni/magiskboot/dtb.cpp similarity index 91% rename from native/jni/magiskboot/dtb.c rename to native/jni/magiskboot/dtb.cpp index 19cbbd1ae..d7245895d 100644 --- a/native/jni/magiskboot/dtb.c +++ b/native/jni/magiskboot/dtb.cpp @@ -1,6 +1,8 @@ -#include #include #include +extern "C" { +#include +} #include "magiskboot.h" #include "utils.h" @@ -12,7 +14,7 @@ static void print_props(const void *fdt, int node, int depth) { printf(" "); int size; const char *name; - const char *value = fdt_getprop_by_offset(fdt, prop, &name, &size); + const char *value = (char *) fdt_getprop_by_offset(fdt, prop, &name, &size); printf("[%s]: [%s]\n", name, value); } } @@ -41,9 +43,9 @@ static int find_fstab(const void *fdt, int parent) { static void dtb_dump(const char *file) { size_t size ; - void *dtb, *fdt; + uint8_t *dtb, *fdt; fprintf(stderr, "Loading dtbs from [%s]\n", file); - mmap_ro(file, &dtb, &size); + mmap_ro(file, (void **) &dtb, &size); // Loop through all the dtbs int dtb_num = 0; for (int i = 0; i < size; ++i) { @@ -60,12 +62,12 @@ static void dtb_dump(const char *file) { static void dtb_patch(const char *file, int patch) { size_t size ; - void *dtb, *fdt; + uint8_t *dtb, *fdt; fprintf(stderr, "Loading dtbs from [%s]\n", file); if (patch) - mmap_rw(file, &dtb, &size); + mmap_rw(file, (void **) &dtb, &size); else - mmap_ro(file, &dtb, &size); + mmap_ro(file, (void **) &dtb, &size); // Loop through all the dtbs int dtb_num = 0, found = 0; for (int i = 0; i < size; ++i) { diff --git a/native/jni/magiskboot/format.c b/native/jni/magiskboot/format.cpp similarity index 98% rename from native/jni/magiskboot/format.c rename to native/jni/magiskboot/format.cpp index 7dd4add92..5a4815ff0 100644 --- a/native/jni/magiskboot/format.c +++ b/native/jni/magiskboot/format.cpp @@ -42,7 +42,7 @@ format_t check_fmt(const void *buf, size_t len) { } void get_fmt_name(format_t fmt, char *name) { - char *s; + const char *s; switch (fmt) { case CHROMEOS: s = "chromeos"; diff --git a/native/jni/magiskboot/format.h b/native/jni/magiskboot/format.h index 1189595fd..abf4b4a30 100644 --- a/native/jni/magiskboot/format.h +++ b/native/jni/magiskboot/format.h @@ -44,8 +44,8 @@ typedef enum { #define ACCLAIM_MAGIC "BauwksBoot" #define ACCLAIM_PRE_HEADER_SZ 262144 -#define SUP_LIST ((char *[]) { "gzip", "xz", "lzma", "bzip2", "lz4", "lz4_legacy", NULL }) -#define SUP_EXT_LIST ((char *[]) { "gz", "xz", "lzma", "bz2", "lz4", "lz4", NULL }) +#define SUP_LIST ((const char *[]) { "gzip", "xz", "lzma", "bzip2", "lz4", "lz4_legacy", NULL }) +#define SUP_EXT_LIST ((const char *[]) { "gz", "xz", "lzma", "bz2", "lz4", "lz4", NULL }) format_t check_fmt(const void *buf, size_t len); void get_fmt_name(format_t fmt, char *name); diff --git a/native/jni/magiskboot/hexpatch.c b/native/jni/magiskboot/hexpatch.cpp similarity index 69% rename from native/jni/magiskboot/hexpatch.c rename to native/jni/magiskboot/hexpatch.cpp index 2442fc084..f4f5a6a88 100644 --- a/native/jni/magiskboot/hexpatch.c +++ b/native/jni/magiskboot/hexpatch.cpp @@ -6,9 +6,9 @@ #include "magiskboot.h" #include "utils.h" -static void hex2byte(const char *hex, unsigned char *str) { +static void hex2byte(uint8_t *hex, uint8_t *str) { char high, low; - for (int i = 0, length = strlen(hex); i < length; i += 2) { + for (int i = 0, length = strlen((char *) hex); i < length; i += 2) { high = toupper(hex[i]) - '0'; low = toupper(hex[i + 1]) - '0'; str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low); @@ -18,12 +18,12 @@ static void hex2byte(const char *hex, unsigned char *str) { void hexpatch(const char *image, const char *from, const char *to) { int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2; size_t filesize; - void *file, *pattern, *patch; - mmap_rw(image, &file, &filesize); - pattern = xmalloc(patternsize); - patch = xmalloc(patchsize); - hex2byte(from, pattern); - hex2byte(to, patch); + uint8_t *file, *pattern, *patch; + mmap_rw(image, (void **) &file, &filesize); + pattern = (uint8_t *) xmalloc(patternsize); + patch = (uint8_t *) xmalloc(patchsize); + hex2byte((uint8_t *) from, pattern); + hex2byte((uint8_t *) to, patch); for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) { if (memcmp(file + i, pattern, patternsize) == 0) { fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to); diff --git a/native/jni/magiskboot/magiskboot.h b/native/jni/magiskboot/magiskboot.h index 57a29f9e6..e909db02c 100644 --- a/native/jni/magiskboot/magiskboot.h +++ b/native/jni/magiskboot/magiskboot.h @@ -3,7 +3,6 @@ #include -#include "logging.h" #include "format.h" #define KERNEL_FILE "kernel" @@ -19,18 +18,18 @@ int unpack(const char *image); void repack(const char* orig_image, const char* out_image); void hexpatch(const char *image, const char *from, const char *to); int cpio_commands(int argc, char *argv[]); -void comp_file(const char *method, const char *from, const char *to); -void decomp_file(char *from, const char *to); +void compress(const char *method, const char *from, const char *to); +void decompress(char *from, const char *to); int dtb_commands(const char *cmd, int argc, char *argv[]); // Compressions size_t gzip(int mode, int fd, const void *buf, size_t size); size_t lzma(int mode, int fd, const void *buf, size_t size); -size_t lz4(int mode, int fd, const void *buf, size_t size); +size_t lz4(int mode, int fd, const uint8_t *buf, size_t size); size_t bzip2(int mode, int fd, const void *buf, size_t size); -size_t lz4_legacy(int mode, int fd, const void *buf, size_t size); -long long comp(format_t type, int to, const void *from, size_t size); -long long decomp(format_t type, int to, const void *from, size_t size); +size_t lz4_legacy(int mode, int fd, const uint8_t *buf, size_t size); +long long compress(format_t type, int fd, const void *from, size_t size); +long long decompress(format_t type, int fd, const void *from, size_t size); // Pattern int patch_verity(void **buf, uint32_t *size, int patch); diff --git a/native/jni/magiskboot/main.c b/native/jni/magiskboot/main.cpp similarity index 96% rename from native/jni/magiskboot/main.c rename to native/jni/magiskboot/main.cpp index 2bad4b843..776975de8 100644 --- a/native/jni/magiskboot/main.c +++ b/native/jni/magiskboot/main.cpp @@ -4,9 +4,11 @@ #include #include +#include + #include "magiskboot.h" +#include "logging.h" #include "utils.h" -#include "mincrypt/sha.h" /******************** Patch Boot Image @@ -107,6 +109,7 @@ static void usage(char *arg0) { } int main(int argc, char *argv[]) { + cmdline_logging(); fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n"); umask(0); @@ -138,13 +141,13 @@ int main(int argc, char *argv[]) { } else if (argc > 2 && strcmp(argv[1], "--repack") == 0) { repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT); } else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) { - decomp_file(argv[2], argc > 3 ? argv[3] : NULL); + decompress(argv[2], argc > 3 ? argv[3] : NULL); } else if (argc > 2 && strncmp(argv[1], "--compress", 10) == 0) { - char *method; + const char *method; method = strchr(argv[1], '='); if (method == NULL) method = "gzip"; else method++; - comp_file(method, argv[2], argc > 3 ? argv[3] : NULL); + compress(method, argv[2], argc > 3 ? argv[3] : NULL); } else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) { hexpatch(argv[2], argv[3], argv[4]); } else if (argc > 2 && strcmp(argv[1], "--cpio") == 0) { diff --git a/native/jni/magiskboot/pattern.c b/native/jni/magiskboot/pattern.cpp similarity index 91% rename from native/jni/magiskboot/pattern.c rename to native/jni/magiskboot/pattern.cpp index 76a0c693f..743d916cb 100644 --- a/native/jni/magiskboot/pattern.c +++ b/native/jni/magiskboot/pattern.cpp @@ -1,8 +1,8 @@ #include #include -#include "utils.h" #include "magiskboot.h" +#include "utils.h" static int check_verity_pattern(const char *s) { int skip = 0; @@ -32,7 +32,7 @@ static int check_encryption_pattern(const char *s) { int patch_verity(void **buf, uint32_t *size, int patch) { int skip, src_size = *size, found = 0; - char *src = *buf, *patched = patch ? xcalloc(src_size, 1) : NULL; + char *src = (char *) *buf, *patched = patch ? (char *) xcalloc(src_size, 1) : nullptr; for (int read = 0, write = 0; read < src_size; ++read, ++write) { if ((skip = check_verity_pattern(src + read)) > 0) { if (patch) { @@ -56,7 +56,7 @@ int patch_verity(void **buf, uint32_t *size, int patch) { void patch_encryption(void **buf, uint32_t *size) { int skip, src_size = *size; - char *src = *buf, *patched = xcalloc(src_size, 1); + char *src = (char *) *buf, *patched = (char *) xcalloc(src_size, 1); for (int read = 0, write = 0; read < src_size; ++read, ++write) { if ((skip = check_encryption_pattern(src + read)) > 0) { fprintf(stderr, "Replace pattern [%.*s] with [encryptable]\n", skip, src + read); diff --git a/native/jni/magiskboot/ramdisk.c b/native/jni/magiskboot/ramdisk.cpp similarity index 52% rename from native/jni/magiskboot/ramdisk.c rename to native/jni/magiskboot/ramdisk.cpp index a9e74984e..7c08a47ff 100644 --- a/native/jni/magiskboot/ramdisk.c +++ b/native/jni/magiskboot/ramdisk.cpp @@ -1,28 +1,35 @@ -#include -#include #include #include #include -#include -#include #include "magiskboot.h" +#include "array.h" #include "cpio.h" #include "utils.h" -static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) { +class magisk_cpio : public cpio { +public: + magisk_cpio(const char *filename) : cpio(filename) {} + void patch(bool keepverity, bool keepforceencrypt); + int test(); + char * sha1(); + void restore(); + void backup(Array &bak, const char *orig, const char *sha1); +}; + +void magisk_cpio::patch(bool keepverity, bool keepforceencrypt) { fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n", keepverity ? "true" : "false", keepforceencrypt ? "true" : "false"); - cpio_entry *e; - vec_for_each(v, e) { - if (!e) continue; + for (auto &e : arr) { + if (!e) + continue; if (!keepverity) { if (strncmp(e->filename, ".backup", 7) && strstr(e->filename, "fstab") && S_ISREG(e->mode)) { patch_verity(&e->data, &e->filesize, 1); } else if (strcmp(e->filename, "verity_key") == 0) { fprintf(stderr, "Remove [verity_key]\n"); - cpio_free(e); - vec_cur(v) = NULL; + delete e; + e = nullptr; continue; } } @@ -34,33 +41,35 @@ static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) { } } + #define STOCK_BOOT 0x0 #define MAGISK_PATCH 0x1 #define UNSUPPORT_PATCH 0x2 - -static int cpio_test(struct vector *v) { - const char *UNSUPPORT_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL }; - const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL }; +int magisk_cpio::test() { + static const char *UNSUPPORT_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", + "boot/sbin/launch_daemonsu.sh", nullptr }; + static const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", + "overlay/init.magisk.rc", nullptr }; for (int i = 0; UNSUPPORT_LIST[i]; ++i) - if (cpio_find(v, UNSUPPORT_LIST[i]) >= 0) + if (find(UNSUPPORT_LIST[i]) >= 0) return UNSUPPORT_PATCH; for (int i = 0; MAGISK_LIST[i]; ++i) - if (cpio_find(v, MAGISK_LIST[i]) >= 0) + if (find(MAGISK_LIST[i]) >= 0) return MAGISK_PATCH; return STOCK_BOOT; } -static char *cpio_sha1(struct vector *v) { - cpio_entry *e; +char * magisk_cpio::sha1() { char sha1[41]; - vec_for_each(v, e) { + for (auto &e : arr) { if (!e) continue; if (strcmp(e->filename, "init.magisk.rc") == 0 || strcmp(e->filename, "overlay/init.magisk.rc") == 0) { - for (void *pos = e->data; pos < e->data + e->filesize; pos = strchr(pos + 1, '\n') + 1) { + for (char *pos = (char *) e->data; pos < (char *) e->data + e->filesize; + pos = strchr(pos + 1, '\n') + 1) { if (memcmp(pos, "# STOCKSHA1=", 12) == 0) { pos += 12; memcpy(sha1, pos, 40); @@ -69,80 +78,104 @@ static char *cpio_sha1(struct vector *v) { } } } else if (strcmp(e->filename, ".backup/.sha1") == 0) { - return e->data; + return (char *) e->data; } } - return NULL; + return nullptr; } -static void cpio_backup(struct vector *v, struct vector *bak, const char *orig, const char *sha1) { - struct vector o_body, *o = &o_body; +void magisk_cpio::restore() { + for (auto &e : arr) { + if (!e) continue; + if (strncmp(e->filename, ".backup", 7) == 0) { + if (e->filename[7] == '\0') continue; + if (e->filename[8] == '.') { + if (strcmp(e->filename + 8, ".rmlist") == 0) { + for (int pos = 0; pos < e->filesize; pos += strlen((char *) e->data + pos) + 1) + rm(false, (char *) e->data + pos); + } + } else { + mv(e->filename, e->filename + 8); + } + } + } + + // Some known stuff we can remove + rm(true, ".backup"); + rm(true, "overlay"); + rm(false, "sbin/magic_mask.sh"); + rm(false, "init.magisk.rc"); + rm(true, "magisk"); +} + +void magisk_cpio::backup(Array &bak, const char *orig, const char *sha1) { cpio_entry *m, *n, *rem, *cksm; char buf[PATH_MAX]; - int res, backup; + int res; + bool backup; - m = xcalloc(sizeof(*m), 1); + m = new cpio_entry(); m->filename = strdup(".backup"); m->mode = S_IFDIR; - vec_push_back(bak, m); + bak.push_back(m); - rem = xcalloc(sizeof(*rem), 1); + rem = new cpio_entry(); rem->filename = strdup(".backup/.rmlist"); rem->mode = S_IFREG; if (sha1) { fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1); - cksm = xcalloc(sizeof(*cksm), 1); - vec_push_back(bak, cksm); + cksm = new cpio_entry(); + bak.push_back(cksm); cksm->filename = strdup(".backup/.sha1"); cksm->mode = S_IFREG; cksm->data = strdup(sha1); cksm->filesize = strlen(sha1) + 1; } - vec_init(o); - parse_cpio(o, orig); - // Remove possible backups in original ramdisk - cpio_rm(o, 1, ".backup"); - cpio_rm(v, 1, ".backup"); + magisk_cpio o = magisk_cpio(orig); - // Sort both vectors before comparing - vec_sort(o, cpio_cmp); - vec_sort(v, cpio_cmp); + // Remove possible backups in original ramdisk + o.rm(true, ".backup"); + rm(true, ".backup"); + + // Sort both CPIOs before comparing + o.sort(); + sort(); // Start comparing size_t i = 0, j = 0; - while(i != vec_size(o) || j != vec_size(v)) { - backup = 0; - if (i != vec_size(o) && j != vec_size(v)) { - m = vec_entry(o)[i]; - n = vec_entry(v)[j]; + while(i != o.arr.size() || j != arr.size()) { + backup = false; + if (i != o.arr.size() && j != arr.size()) { + m = o.arr[i]; + n = arr[j]; res = strcmp(m->filename, n->filename); - } else if (i == vec_size(o)) { - n = vec_entry(v)[j]; + } else if (i == o.arr.size()) { + n = arr[j]; res = 1; - } else if (j == vec_size(v)) { - m = vec_entry(o)[i]; + } else if (j == arr.size()) { + m = o.arr[i]; res = -1; } if (res < 0) { // Something is missing in new ramdisk, backup! ++i; - backup = 1; + backup = true; fprintf(stderr, "Backup missing entry: "); } else if (res == 0) { ++i; ++j; if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0) continue; // Not the same! - backup = 1; + backup = true; fprintf(stderr, "Backup mismatch entry: "); } else { // Something new in ramdisk, record in rem ++j; rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1); - memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1); + memcpy((char *) rem->data + rem->filesize, n->filename, strlen(n->filename) + 1); rem->filesize += strlen(n->filename) + 1; fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename); } @@ -151,59 +184,25 @@ static void cpio_backup(struct vector *v, struct vector *bak, const char *orig, fprintf(stderr, "[%s] -> [%s]\n", m->filename, buf); free(m->filename); m->filename = strdup(buf); - vec_push_back(bak, m); + bak.push_back(m); // NULL the original entry, so it won't be freed - vec_entry(o)[i - 1] = NULL; + o.arr[i - 1] = nullptr; } } if (rem->filesize) - vec_push_back(bak, rem); + bak.push_back(rem); else - cpio_free(rem); - - // Cleanup - cpio_vec_destroy(o); + delete rem; } -static void cpio_restore(struct vector *v) { - cpio_entry *e; - vec_for_each(v, e) { - if (!e) continue; - if (strncmp(e->filename, ".backup", 7) == 0) { - if (e->filename[7] == '\0') continue; - if (e->filename[8] == '.') { - if (strcmp(e->filename, ".backup/.rmlist") == 0) { - for (int pos = 0; pos < e->filesize; pos += strlen(e->data + pos) + 1) - cpio_rm(v, 0, e->data + pos); - } - continue; - } else { - fprintf(stderr, "Restore [%s] -> [%s]\n", e->filename, e->filename + 8); - vec_cur(v) = NULL; - char *new_name = strdup(e->filename + 8); - free(e->filename); - e->filename = new_name; - cpio_vec_insert(v, e); - } - } - } - // Some known stuff we can remove - cpio_rm(v, 1, ".backup"); - cpio_rm(v, 1, "overlay"); - cpio_rm(v, 0, "sbin/magic_mask.sh"); - cpio_rm(v, 0, "init.magisk.rc"); - cpio_rm(v, 0, "magisk"); -} int cpio_commands(int argc, char *argv[]) { char *incpio = argv[0]; ++argv; --argc; - struct vector v; - vec_init(&v); - parse_cpio(&v, incpio); + magisk_cpio cpio = magisk_cpio(incpio); int cmdc; char *cmdv[6]; @@ -214,61 +213,54 @@ int cpio_commands(int argc, char *argv[]) { cmdv[cmdc++] = tok; if (strcmp(cmdv[0], "test") == 0) { - exit(cpio_test(&v)); + exit(cpio.test()); } else if (strcmp(cmdv[0], "restore") == 0) { - cpio_restore(&v); + cpio.restore(); } else if (strcmp(cmdv[0], "sha1") == 0) { - char *sha1 = cpio_sha1(&v); + char *sha1 = cpio.sha1(); if (sha1) printf("%s\n", sha1); + free(sha1); return 0; } else if (cmdc >= 2 && strcmp(cmdv[0], "backup") == 0) { - struct vector back; - vec_init(&back); - cpio_backup(&v, &back, cmdv[1], cmdc > 2 ? cmdv[2] : NULL); - cpio_entry *e; - vec_for_each(&back, e) - if (e) vec_push_back(&v, e); - vec_destroy(&back); + auto bak = Array(); + cpio.backup(bak, cmdv[1], cmdc > 2 ? cmdv[2] : nullptr); + cpio.insert(bak); } else if (cmdc >= 4 && strcmp(cmdv[0], "magisk") == 0) { - cpio_patch(&v, strcmp(cmdv[2], "true") == 0, strcmp(cmdv[3], "true") == 0); + cpio.patch(strcmp(cmdv[2], "true") == 0, strcmp(cmdv[3], "true") == 0); - struct vector back; - vec_init(&back); - cpio_backup(&v, &back, cmdv[1], cmdc > 4 ? cmdv[4] : NULL); + auto bak = Array(); + cpio.backup(bak, cmdv[1], cmdc > 4 ? cmdv[4] : nullptr); - cpio_entry *e; - e = xcalloc(sizeof(*e), 1); + auto e = new cpio_entry(); e->filename = strdup(".backup/.magisk"); e->mode = S_IFREG; e->data = xmalloc(50); - snprintf(e->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", cmdv[2], cmdv[3]); - e->filesize = strlen(e->data) + 1; - vec_push_back(&back, e); + snprintf((char *) e->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", cmdv[2], cmdv[3]); + e->filesize = strlen((char *) e->data) + 1; - vec_for_each(&back, e) - if (e) vec_push_back(&v, e); - vec_destroy(&back); + cpio.insert(bak); + cpio.insert(e); } else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) { int recur = cmdc > 2 && strcmp(cmdv[1], "-r") == 0; - cpio_rm(&v, recur, cmdv[1 + recur]); + cpio.rm(recur, cmdv[1 + recur]); } else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) { - cpio_mv(&v, cmdv[1], cmdv[2]); + cpio.mv(cmdv[1], cmdv[2]); } else if (cmdc == 3 && strcmp(cmdv[0], "patch") == 0) { - cpio_patch(&v, strcmp(cmdv[1], "true") == 0, strcmp(cmdv[2], "true") == 0); + cpio.patch(strcmp(cmdv[1], "true") == 0, strcmp(cmdv[2], "true") == 0); } else if (strcmp(cmdv[0], "extract") == 0) { if (cmdc == 3) { - return cpio_extract(&v, cmdv[1], cmdv[2]); + return cpio.extract(cmdv[1], cmdv[2]); } else { - cpio_extract_all(&v); + cpio.extract(); return 0; } } else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) { - cpio_mkdir(&v, strtoul(cmdv[1], NULL, 8), cmdv[2]); + cpio.makedir(strtoul(cmdv[1], NULL, 8), cmdv[2]); } else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) { - cpio_ln(&v, cmdv[1], cmdv[2]); + cpio.ln(cmdv[1], cmdv[2]); } else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) { - cpio_add(&v, strtoul(cmdv[1], NULL, 8), cmdv[2], cmdv[3]); + cpio.add(strtoul(cmdv[1], NULL, 8), cmdv[2], cmdv[3]); } else { return 1; } @@ -277,7 +269,6 @@ int cpio_commands(int argc, char *argv[]) { ++argv; } - dump_cpio(&v, incpio); - cpio_vec_destroy(&v); + cpio.dump(incpio); return 0; -} +} \ No newline at end of file diff --git a/native/jni/utils/include/array.h b/native/jni/utils/include/array.h new file mode 100644 index 000000000..38c3d245a --- /dev/null +++ b/native/jni/utils/include/array.h @@ -0,0 +1,138 @@ +#pragma once + +#include + +template +class Array { +public: + Array() : _data(0), _size(0), _capacity(0) {} + ~Array() { delete []_data; } + + class iterator { + friend class Array; + + public: + iterator(T* n= 0): _node(n) {} + iterator(const iterator& i): _node(i._node) {} + ~iterator() {} // Should NOT delete _node + + const T& operator * () const { return (*_node); } + T& operator * () { return (*_node); } + iterator& operator ++ () { + ++_node; + return (*this); + } + iterator operator ++ (int) { + iterator temp = *this; + ++_node; + return temp; + } + iterator& operator -- () { + --_node; + return (*this); + } + iterator operator -- (int) { + iterator temp = *this; + --_node; + return temp; + } + + iterator operator + (int i) const { + iterator temp = *this; + temp += i; + return temp; + } + iterator& operator += (int i) { + _node += i; + return (*this); + } + + iterator& operator = (const iterator& i) { + _node = i._node; + return (*this); + } + + bool operator != (const iterator& i) const { + return _node != i._node; + } + bool operator == (const iterator& i) const { return !(*this != i); } + + private: + T* _node; + }; + + iterator begin() const { return iterator(_data); } + iterator end() const { return iterator(_data + _size); } + bool empty() const { return !_size; } + size_t size() const { return _size; } + + T& operator [] (size_t i) { return _data[i]; } + const T& operator [] (size_t i) const { return _data[i]; } + + const T& back() const { return _data[_size - 1]; } + + void push_back(const T& x) { + if(_size == _capacity) + expand(); + _data[_size] = x; + ++_size; + } + + void pop_front() { erase(begin()); } + + void pop_back() { if(_size) --_size; } + + bool erase(iterator pos) { + T* d = pos._node; + if (_size == 0 || d < _data || d >= _data + _size) + return false; + for (; d < _data + _size - 1; ++d) + *d = *(d + 1); + --_size; + return true; + + } + + bool erase(const T& x) { + for (T* i = _data; i < _data + _size; ++i) { + if(*i == x) { + erase(iterator(i)); + return true; + } + } + return false; + } + + void clear() { _size = 0; } + + void sort() const { + qsort(_data, _size, sizeof(T), compare); + } + + // void reserve(size_t n) { ... } + // void resize(size_t n) { ... } + +private: + T* _data; + size_t _size; // number of valid elements + size_t _capacity; // max number of elements + static int(*_cmp)(T&, T&); + + static int compare(const void *a, const void *b) { + return _cmp ? _cmp(*((T*) a), *((T*) b)) : 0; + } + + void expand() { + if (_capacity == 0) + _capacity = 1; + else + _capacity *= 2; + T* temp = _data; + _data = new T[_capacity]; + for(int i = 0; i < _size; ++i) _data[i] = temp[i]; + delete [] temp; + } +}; + +template +int(* Array::_cmp)(T&, T&) = nullptr; diff --git a/native/jni/utils/include/logging.h b/native/jni/utils/include/logging.h index e4232ed36..b7f9f4b58 100644 --- a/native/jni/utils/include/logging.h +++ b/native/jni/utils/include/logging.h @@ -7,6 +7,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define str(a) #a #define xstr(a) str(a) @@ -42,3 +46,6 @@ void cmdline_logging(); int log_handler(log_type t, const char *fmt, ...); +#ifdef __cplusplus +} +#endif diff --git a/native/jni/utils/include/utils.h b/native/jni/utils/include/utils.h index 504040242..1b7070eff 100644 --- a/native/jni/utils/include/utils.h +++ b/native/jni/utils/include/utils.h @@ -11,6 +11,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #include "vector.h" #define UID_SHELL (get_shell_uid()) @@ -140,4 +144,8 @@ void full_read_at(int dirfd, const char *filename, void **buf, size_t *size); void stream_full_read(int fd, void **buf, size_t *size); void write_zero(int fd, size_t size); +#ifdef __cplusplus +} +#endif + #endif