From 391783e26892fb22d545f937a8965e86d72e8c35 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 23 Feb 2019 02:23:24 -0500 Subject: [PATCH] Introduce mmap based CPIO class --- native/jni/magiskboot/cpio.cpp | 97 ++++++++++++++++++++----------- native/jni/magiskboot/cpio.h | 38 ++++++++---- native/jni/magiskboot/ramdisk.cpp | 6 +- 3 files changed, 93 insertions(+), 48 deletions(-) diff --git a/native/jni/magiskboot/cpio.cpp b/native/jni/magiskboot/cpio.cpp index 350a698e3..57e978429 100644 --- a/native/jni/magiskboot/cpio.cpp +++ b/native/jni/magiskboot/cpio.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -11,7 +10,7 @@ using namespace std; -static uint32_t x8u(char *hex) { +static uint32_t x8u(const char *hex) { uint32_t val, inpos = 8, outpos; char pattern[6]; @@ -28,18 +27,19 @@ 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)) { +cpio_entry_base::cpio_entry_base(const cpio_newc_header *h) +: mode(x8u(h->mode)), uid(x8u(h->uid)), gid(x8u(h->gid)), filesize(x8u(h->filesize)) {}; + +#define fd_align() lseek(fd, do_align(lseek(fd, 0, SEEK_CUR), 4), SEEK_SET) +cpio_entry::cpio_entry(int fd, cpio_newc_header &header) : cpio_entry_base(&header) { uint32_t namesize = x8u(header.namesize); filename.resize(namesize - 1); xxread(fd, &filename[0], namesize); - parse_align(); + fd_align(); if (filesize) { data = xmalloc(filesize); xxread(fd, data, filesize); - parse_align(); + fd_align(); } } @@ -47,25 +47,6 @@ cpio_entry::~cpio_entry() { free(data); } -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 = nullptr; - while(xxread(fd, &header, sizeof(cpio_newc_header)) != -1) { - entry = new cpio_entry(fd, header); - if (entry->filename == "." || entry->filename == "..") - continue; - if (entry->filename == "TRAILER!!!") - break; - entries[entry->filename].reset(entry); - entry = nullptr; - } - delete entry; - close(fd); -} - #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); @@ -162,7 +143,23 @@ bool cpio::exists(const char *name) { return entries.count(name) != 0; } -void cpio::insert(cpio_entry *e) { +cpio_rw::cpio_rw(const char *filename) { + int fd = xopen(filename, O_RDONLY); + fprintf(stderr, "Loading cpio: [%s]\n", filename); + cpio_newc_header header; + unique_ptr entry; + while(xxread(fd, &header, sizeof(cpio_newc_header)) != -1) { + entry = make_unique(fd, header); + if (entry->filename == "." || entry->filename == "..") + continue; + if (entry->filename == "TRAILER!!!") + break; + entries[entry->filename] = std::move(entry); + } + close(fd); +} + +void cpio_rw::insert(cpio_entry *e) { auto ex = entries.extract(e->filename); if (!ex) { entries[e->filename].reset(e); @@ -173,7 +170,7 @@ void cpio::insert(cpio_entry *e) { } } -void cpio::add(mode_t mode, const char *name, const char *file) { +void cpio_rw::add(mode_t mode, const char *name, const char *file) { void *buf; size_t sz; mmap_ro(file, &buf, &sz); @@ -187,14 +184,14 @@ 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) { +void cpio_rw::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) { +void cpio_rw::ln(const char *target, const char *name) { auto e = new cpio_entry(name); e->mode = S_IFLNK; e->filesize = strlen(target); @@ -203,15 +200,16 @@ void cpio::ln(const char *target, const char *name) { fprintf(stderr, "Create symlink [%s] -> [%s]\n", name, target); } -void cpio::mv(entry_map::iterator &it, const char *to) { +void cpio_rw::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; + auto &name = static_cast(ex.mapped().get())->filename; + name = to; + ex.key() = name; entries.insert(std::move(ex)); } -bool cpio::mv(const char *from, const char *to) { +bool cpio_rw::mv(const char *from, const char *to) { auto it = entries.find(from); if (it != entries.end()) { mv(it, to); @@ -220,3 +218,32 @@ bool cpio::mv(const char *from, const char *to) { fprintf(stderr, "Cannot find entry %s\n", from); return false; } + +#define pos_align(p) p = do_align(p, 4) +cpio_mmap::cpio_mmap(const char *filename) { + mmap_ro(filename, (void **) &buf, &sz); + fprintf(stderr, "Loading cpio: [%s]\n", filename); + size_t pos = 0; + cpio_newc_header *header; + unique_ptr entry; + while (pos < sz) { + header = (cpio_newc_header *)(buf + pos); + entry = make_unique(header); + pos += sizeof(*header); + string_view name_view(buf + pos); + pos += x8u(header->namesize); + pos_align(pos); + if (name_view == "." || name_view == "..") + continue; + if (name_view == "TRAILER!!!") + break; + entry->data = buf + pos; + pos += entry->filesize; + entries[name_view] = std::move(entry); + pos_align(pos); + } +} + +cpio_mmap::~cpio_mmap() { + munmap(buf, sz); +} diff --git a/native/jni/magiskboot/cpio.h b/native/jni/magiskboot/cpio.h index ea3d77541..d2dbb464f 100644 --- a/native/jni/magiskboot/cpio.h +++ b/native/jni/magiskboot/cpio.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -24,33 +23,46 @@ struct cpio_newc_header { char check[8]; } __attribute__((packed)); -struct cpio_entry { +struct cpio_entry_base { uint32_t mode = 0; uint32_t uid = 0; uint32_t gid = 0; uint32_t filesize = 0; - /* Dynamic data */ - std::string filename; void *data = nullptr; + cpio_entry_base() : mode(0), uid(0), gid(0), filesize(0) {}; + explicit cpio_entry_base(const cpio_newc_header *h); + virtual ~cpio_entry_base() = default; +}; + +struct cpio_entry : public cpio_entry_base { + std::string filename; + cpio_entry() = default; explicit cpio_entry(const char *name) : filename(name) {} cpio_entry(int fd, cpio_newc_header &header); - ~cpio_entry(); + ~cpio_entry() override; }; -typedef std::map> entry_map; +typedef std::map> entry_map; class cpio { public: - explicit cpio(const char *filename); void dump(const char *file); void rm(const char *name, bool r = false); void extract(); bool extract(const char *name, const char *file); bool exists(const char *name); +protected: + entry_map entries; + void rm(entry_map::iterator &it); +}; + +class cpio_rw : public cpio { +public: + explicit cpio_rw(const char *filename); void insert(cpio_entry *e); void add(mode_t mode, const char *name, const char *file); void makedir(mode_t mode, const char *name); @@ -58,8 +70,14 @@ public: bool mv(const char *from, const char *to); protected: - entry_map entries; - - void rm(entry_map::iterator &it); void mv(entry_map::iterator &it, const char *to); }; + +class cpio_mmap : public cpio { +public: + explicit cpio_mmap(const char *filename); + ~cpio_mmap(); +private: + char *buf; + size_t sz; +}; diff --git a/native/jni/magiskboot/ramdisk.cpp b/native/jni/magiskboot/ramdisk.cpp index 0f66c152c..679713d59 100644 --- a/native/jni/magiskboot/ramdisk.cpp +++ b/native/jni/magiskboot/ramdisk.cpp @@ -9,9 +9,9 @@ using namespace std; -class magisk_cpio : public cpio { +class magisk_cpio : public cpio_rw { public: - explicit magisk_cpio(const char *filename) : cpio(filename) {} + explicit magisk_cpio(const char *filename) : cpio_rw(filename) {} void patch(bool keepverity, bool keepforceencrypt); int test(); char * sha1(); @@ -174,7 +174,7 @@ void magisk_cpio::backup(const char *orig) { 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(); + auto ex = static_cast(lhs->second.release()); ex->filename = back_name; bkup_entries[ex->filename].reset(ex); }