From 6f12c082047575ad107bfd005036c0fa6bb29772 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Fri, 22 Feb 2019 22:53:20 -0500 Subject: [PATCH] Use ordered map to store CPIO entries --- native/jni/magiskboot/cpio.cpp | 210 ++++++++++++++---------------- native/jni/magiskboot/cpio.h | 29 +++-- native/jni/magiskboot/ramdisk.cpp | 143 ++++++++++---------- 3 files changed, 185 insertions(+), 197 deletions(-) diff --git a/native/jni/magiskboot/cpio.cpp b/native/jni/magiskboot/cpio.cpp index 095800f04..350a698e3 100644 --- a/native/jni/magiskboot/cpio.cpp +++ b/native/jni/magiskboot/cpio.cpp @@ -11,8 +11,6 @@ using namespace std; -#define parse_align() lseek(fd, do_align(lseek(fd, 0, SEEK_CUR), 4), SEEK_SET) - static uint32_t x8u(char *hex) { uint32_t val, inpos = 8, outpos; char pattern[6]; @@ -30,6 +28,7 @@ static uint32_t x8u(char *hex) { return val; } +#define parse_align() lseek(fd, do_align(lseek(fd, 0, SEEK_CUR), 4), SEEK_SET) cpio_entry::cpio_entry(int fd, cpio_newc_header &header) : mode(x8u(header.mode)), uid(x8u(header.uid)), gid(x8u(header.gid)), filesize(x8u(header.filesize)) { @@ -53,15 +52,17 @@ cpio::cpio(const char *filename) { if (fd < 0) return; fprintf(stderr, "Loading cpio: [%s]\n", filename); cpio_newc_header header; - unique_ptr entry; + cpio_entry *entry = nullptr; while(xxread(fd, &header, sizeof(cpio_newc_header)) != -1) { - entry = std::make_unique(fd, header); + entry = new cpio_entry(fd, header); if (entry->filename == "." || entry->filename == "..") continue; if (entry->filename == "TRAILER!!!") break; - entries.push_back(std::move(entry)); + entries[entry->filename].reset(entry); + entry = nullptr; } + delete entry; close(fd); } @@ -70,29 +71,28 @@ 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 : entries) { 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, + e.second->mode, + e.second->uid, + e.second->gid, 1, // e->nlink 0, // e->mtime - e->filesize, + e.second->filesize, 0, // e->devmajor 0, // e->devminor 0, // e->rdevmajor 0, // e->rdevminor - (uint32_t) e->filename.size() + 1, + (uint32_t) e.first.size() + 1, 0 // e->check ); xwrite(fd, header, 110); - xwrite(fd, e->filename.c_str(), e->filename.size() + 1); + xwrite(fd, e.first.data(), e.first.size() + 1); dump_align(); - if (e->filesize) { - xwrite(fd, e->data, e->filesize); + if (e.second->filesize) { + xwrite(fd, e.second->data, e.second->filesize); dump_align(); } } @@ -105,65 +105,79 @@ void cpio::dump(const char *file) { close(fd); } -int cpio::find(const char *name) { - for (int i = 0; i < entries.size(); ++i) { - if (!entries[i]) - continue; - if (entries[i]->filename == name) - return i; - } - return -1; -} - -void cpio::insert(cpio_entry *e) { - auto ue = unique_ptr(e); - insert(ue); -} - -void cpio::insert(unique_ptr &e) { - int i = find(e->filename.c_str()); - if (i >= 0) { - entries[i] = std::move(e); - } else { - entries.push_back(std::move(e)); - } +void cpio::rm(entry_map::iterator &it) { + fprintf(stderr, "Remove [%s]\n", it->first.data()); + entries.erase(it); } void cpio::rm(const char *name, bool r) { size_t len = strlen(name); - for (auto &e : entries) { - if (!e) - continue; - if (e->filename.compare(0, len, name) == 0 && - ((r && e->filename[len] == '/') || e->filename[len] == '\0')) { - fprintf(stderr, "Remove [%s]\n", e->filename.c_str()); - e.reset(); + for (auto it = entries.begin(); it != entries.end();) { + if (it->first.compare(0, len, name) == 0 && + ((r && it->first[len] == '/') || it->first[len] == '\0')) { + auto tmp = it; + ++it; + rm(tmp); if (!r) return; + } else { + ++it; } } } -void cpio::makedir(mode_t mode, const char *name) { - auto e = make_unique(name); - e->mode = S_IFDIR | mode; - insert(e); - fprintf(stderr, "Create directory [%s] (%04o)\n", name, mode); +static void extract_entry(const entry_map::value_type &e, const char *file) { + fprintf(stderr, "Extract [%s] to [%s]\n", e.first.data(), file); + unlink(file); + rmdir(file); + if (S_ISDIR(e.second->mode)) { + mkdir(file, e.second->mode & 0777); + } else if (S_ISREG(e.second->mode)) { + int fd = creat(file, e.second->mode & 0777); + xwrite(fd, e.second->data, e.second->filesize); + fchown(fd, e.second->uid, e.second->gid); + close(fd); + } else if (S_ISLNK(e.second->mode)) { + auto target = strndup((char *) e.second->data, e.second->filesize); + symlink(target, file); + free(target); + } } -void cpio::ln(const char *target, const char *name) { - auto e = make_unique(name); - e->mode = S_IFLNK; - e->filesize = strlen(target); - e->data = strdup(target); - insert(e); - fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target); +void cpio::extract() { + for (auto &e : entries) + extract_entry(e, e.first.data()); +} + +bool cpio::extract(const char *name, const char *file) { + auto it = entries.find(name); + if (it != entries.end()) { + extract_entry(*it, file); + return true; + } + fprintf(stderr, "Cannot find the file entry [%s]\n", name); + return false; +} + +bool cpio::exists(const char *name) { + return entries.count(name) != 0; +} + +void cpio::insert(cpio_entry *e) { + auto ex = entries.extract(e->filename); + if (!ex) { + entries[e->filename].reset(e); + } else { + ex.key() = e->filename; + ex.mapped().reset(e); + entries.insert(std::move(ex)); + } } void cpio::add(mode_t mode, const char *name, const char *file) { void *buf; size_t sz; mmap_ro(file, &buf, &sz); - auto e = make_unique(name); + auto e = new cpio_entry(name); e->mode = S_IFREG | mode; e->filesize = sz; e->data = xmalloc(sz); @@ -173,66 +187,36 @@ void cpio::add(mode_t mode, const char *name, const char *file) { fprintf(stderr, "Add entry [%s] (%04o)\n", name, mode); } +void cpio::makedir(mode_t mode, const char *name) { + auto e = new cpio_entry(name); + e->mode = S_IFDIR | mode; + 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(name); + e->mode = S_IFLNK; + e->filesize = strlen(target); + e->data = strdup(target); + insert(e); + fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target); +} + +void cpio::mv(entry_map::iterator &it, const char *to) { + fprintf(stderr, "Move [%s] -> [%s]\n", it->first.data(), to); + auto ex = entries.extract(it); + ex.mapped()->filename = to; + ex.key() = ex.mapped()->filename; + entries.insert(std::move(ex)); +} + bool cpio::mv(const char *from, const char *to) { - int f = find(from), t = find(to); - if (f >= 0) { - if (t > 0) - entries[t].reset(); - fprintf(stderr, "Move [%s] -> [%s]\n", from, to); - entries[f]->filename = to; + auto it = entries.find(from); + if (it != entries.end()) { + mv(it, to); return true; } fprintf(stderr, "Cannot find entry %s\n", from); return false; } - -static void extract_entry(cpio_entry *e, const char *file) { - fprintf(stderr, "Extract [%s] to [%s]\n", e->filename.c_str(), file); - unlink(file); - rmdir(file); - if (S_ISDIR(e->mode)) { - mkdir(file, e->mode & 0777); - } else 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)) { - auto target = new char[e->filesize + 1]; - memcpy(target, e->data, e->filesize); - target[e->filesize] = '\0'; - symlink(target, file); - delete[] target; - } -} - -void cpio::extract() { - for (auto &e : entries) { - if (!e) continue; - extract_entry(e.get(), e->filename.c_str()); - } -} - -bool cpio::extract(const char *name, const char *file) { - int i = find(name); - if (i > 0) { - extract_entry(entries[i].get(), file); - return true; - } - fprintf(stderr, "Cannot find the file entry [%s]\n", name); - return false; -} - -void cpio::sort() { - std::sort(entries.begin(), entries.end(), [] - (const unique_ptr &a, const unique_ptr &b) -> bool { - if (a == b || !a) - return false; - if (!b) - return true; - return a->filename < b->filename; - }); - - while (!entries.back()) - entries.pop_back(); -} diff --git a/native/jni/magiskboot/cpio.h b/native/jni/magiskboot/cpio.h index eb09cbc98..ea3d77541 100644 --- a/native/jni/magiskboot/cpio.h +++ b/native/jni/magiskboot/cpio.h @@ -1,10 +1,11 @@ -#ifndef _CPIO_H_ -#define _CPIO_H_ +#pragma once #include #include #include #include +#include +#include struct cpio_newc_header { char magic[6]; @@ -39,24 +40,26 @@ struct cpio_entry { ~cpio_entry(); }; +typedef std::map> entry_map; + class cpio { public: explicit cpio(const char *filename); void dump(const char *file); - int find(const char *name); - void insert(cpio_entry *e); - void insert(std::unique_ptr &e); void rm(const char *name, bool r = false); - 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); - bool mv(const char *from, const char *to); void extract(); bool extract(const char *name, const char *file); - void sort(); + bool exists(const char *name); + + void insert(cpio_entry *e); + void add(mode_t mode, const char *name, const char *file); + void makedir(mode_t mode, const char *name); + void ln(const char *target, const char *name); + bool mv(const char *from, const char *to); protected: - std::vector > entries; -}; + entry_map entries; -#endif + void rm(entry_map::iterator &it); + void mv(entry_map::iterator &it, const char *to); +}; diff --git a/native/jni/magiskboot/ramdisk.cpp b/native/jni/magiskboot/ramdisk.cpp index 9c6e9854e..0f66c152c 100644 --- a/native/jni/magiskboot/ramdisk.cpp +++ b/native/jni/magiskboot/ramdisk.cpp @@ -23,43 +23,43 @@ void magisk_cpio::patch(bool keepverity, bool keepforceencrypt) { fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n", keepverity ? "true" : "false", keepforceencrypt ? "true" : "false"); for (auto &e : entries) { - if (!e) continue; bool fstab = (!keepverity || !keepforceencrypt) && - !str_starts(e->filename, ".backup") && - str_contains(e->filename, "fstab") && S_ISREG(e->mode); + !str_starts(e.first, ".backup") && + str_contains(e.first, "fstab") && S_ISREG(e.second->mode); if (!keepverity) { if (fstab) { - patch_verity(&e->data, &e->filesize, 1); - } else if (e->filename == "verity_key") { + patch_verity(&e.second->data, &e.second->filesize, 1); + } else if (e.first == "verity_key") { fprintf(stderr, "Remove [verity_key]\n"); - e.reset(); + e.second.reset(); continue; } } if (!keepforceencrypt) { if (fstab) { - patch_encryption(&e->data, &e->filesize); + patch_encryption(&e.second->data, &e.second->filesize); } } } } - #define STOCK_BOOT 0x0 #define MAGISK_PATCH 0x1 #define UNSUPPORT_PATCH 0x2 int magisk_cpio::test() { - static const char *UNSUPPORT_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", - "boot/sbin/launch_daemonsu.sh" }; - static const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", - "overlay/init.magisk.rc" }; + static const char *UNSUPPORT_LIST[] = + { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", + "boot/sbin/launch_daemonsu.sh" }; + static const char *MAGISK_LIST[] = + { ".backup/.magisk", "init.magisk.rc", + "overlay/init.magisk.rc" }; for (auto file : UNSUPPORT_LIST) - if (find(file) >= 0) + if (exists(file)) return UNSUPPORT_PATCH; for (auto file : MAGISK_LIST) - if (find(file) >= 0) + if (exists(file)) return MAGISK_PATCH; return STOCK_BOOT; @@ -72,62 +72,66 @@ char *magisk_cpio::sha1() { char sha1[41]; char *line; for (auto &e : entries) { - if (!e) continue; - if (e->filename == "init.magisk.rc" || e->filename == "overlay/init.magisk.rc") { - for_each_line(line, e->data, e->filesize) { + if (e.first == "init.magisk.rc" || e.first == "overlay/init.magisk.rc") { + for_each_line(line, e.second->data, e.second->filesize) { if (strncmp(line, "#STOCKSHA1=", 11) == 0) { strncpy(sha1, line + 12, 40); sha1[40] = '\0'; return strdup(sha1); } } - } else if (e->filename == ".backup/.magisk") { - for_each_line(line, e->data, e->filesize) { + } else if (e.first == ".backup/.magisk") { + for_each_line(line, e.second->data, e.second->filesize) { if (strncmp(line, "SHA1=", 5) == 0) { strncpy(sha1, line + 5, 40); sha1[40] = '\0'; return strdup(sha1); } } - } else if (e->filename == ".backup/.sha1") { - return (char *) e->data; + } else if (e.first == ".backup/.sha1") { + return (char *) e.second->data; } } return nullptr; } +#define for_each_str(str, buf, size) \ +for (str = (char *) buf; str < (char *) buf + size; str = str += strlen(str) + 1) + void magisk_cpio::restore() { - for (auto &e : entries) { - if (!e) continue; - if (str_starts(e->filename, ".backup")) { - 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((char *) e->data + pos, false); - } + char *file; + entry_map::iterator cur; + auto next = entries.begin(); + while (next != entries.end()) { + cur = next; + ++next; + if (str_starts(cur->first, ".backup")) { + if (cur->first.length() == 7 || cur->first.substr(8) == ".magisk") { + rm(cur); + } else if (cur->first.substr(8) == ".rmlist") { + for_each_str(file, cur->second->data, cur->second->filesize) + rm(file, false); + rm(cur); } else { - mv(e->filename.c_str(), &e->filename[8]); + mv(cur, &cur->first[8]); } + } else if (str_starts(cur->first, "overlay") || + str_starts(cur->first, "magisk") || + cur->first == "sbin/magic_mask.sh" || + cur->first == "init.magisk.rc") { + // Some known stuff we can remove + rm(cur); } } - - // Some known stuff we can remove - rm(".backup", true); - rm("overlay", true); - rm("sbin/magic_mask.sh", false); - rm("init.magisk.rc", false); - rm("magisk", true); } -#define lhs o.entries[i] -#define rhs entries[j] void magisk_cpio::backup(const char *orig) { - vector > bkup_entries; + entry_map bkup_entries; string remv; - bkup_entries.emplace_back(new cpio_entry(".backup")); - bkup_entries.back()->mode = S_IFDIR; + auto b = new cpio_entry(".backup"); + b->mode = S_IFDIR; + bkup_entries[b->filename].reset(b); magisk_cpio o(orig); @@ -135,20 +139,17 @@ void magisk_cpio::backup(const char *orig) { o.rm(".backup", true); rm(".backup", true); - // Sort both CPIOs before comparing - o.sort(); - sort(); + auto lhs = o.entries.begin(); + auto rhs = entries.begin(); - // Start comparing - size_t i = 0, j = 0; - while(i != o.entries.size() || j != entries.size()) { + while (lhs != o.entries.end() || rhs != entries.end()) { int res; bool backup = false; - if (i != o.entries.size() && j != entries.size()) { - res = lhs->filename.compare(rhs->filename); - } else if (i == o.entries.size()) { + if (lhs != o.entries.end() && rhs != entries.end()) { + res = lhs->first.compare(rhs->first); + } else if (lhs == o.entries.end()) { res = 1; - } else if (j == entries.size()) { + } else if (rhs == entries.end()) { res = -1; } @@ -157,50 +158,50 @@ void magisk_cpio::backup(const char *orig) { backup = true; fprintf(stderr, "Backup missing entry: "); } else if (res == 0) { - if (memcmp(lhs->data, rhs->data, lhs->filesize) != 0) { + if (lhs->second->filesize != rhs->second->filesize || + memcmp(lhs->second->data, rhs->second->data, lhs->second->filesize) != 0) { // Not the same! backup = true; fprintf(stderr, "Backup mismatch entry: "); } } else { // Something new in ramdisk - remv += rhs->filename; + remv += rhs->first; remv += (char) '\0'; - fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", rhs->filename.c_str()); + fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", rhs->first.data()); } if (backup) { - string back_name = ".backup/" + lhs->filename; - fprintf(stderr, "[%s] -> [%s]\n", lhs->filename.c_str(), back_name.c_str()); - lhs->filename = back_name; - bkup_entries.push_back(std::move(lhs)); + string back_name(".backup/"); + back_name += lhs->first; + fprintf(stderr, "[%s] -> [%s]\n", lhs->first.data(), back_name.data()); + cpio_entry *ex = lhs->second.release(); + ex->filename = back_name; + bkup_entries[ex->filename].reset(ex); } // Increment positions if (res < 0) { - ++i; + ++lhs; } else if (res == 0) { - ++i; ++j; + ++lhs; ++rhs; } else { - ++j; + ++rhs; } } if (!remv.empty()) { - auto rmlist = make_unique(".backup/.rmlist"); + auto rmlist = new cpio_entry(".backup/.rmlist"); rmlist->mode = S_IFREG; rmlist->filesize = remv.length(); rmlist->data = xmalloc(remv.length()); memcpy(rmlist->data, remv.data(), remv.length()); - bkup_entries.push_back(std::move(rmlist)); + bkup_entries[rmlist->filename].reset(rmlist); } - if (bkup_entries.size() > 1) { - entries.insert(entries.end(), - make_move_iterator(bkup_entries.begin()), make_move_iterator(bkup_entries.end())); - } + if (bkup_entries.size() > 1) + entries.merge(bkup_entries); } - int cpio_commands(int argc, char *argv[]) { char *incpio = argv[0]; ++argv; @@ -232,7 +233,7 @@ int cpio_commands(int argc, char *argv[]) { if (sha1) printf("%s\n", sha1); return 0; } else if (cmdc == 2 && strcmp(cmdv[0], "exists") == 0) { - exit(cpio.find(cmdv[1]) < 0); + exit(!cpio.exists(cmdv[1])); } else if (cmdc == 2 && strcmp(cmdv[0], "backup") == 0) { cpio.backup(cmdv[1]); } else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {