diff options
author | Dees_Troy <dees_troy@teamw.in> | 2012-09-11 02:32:10 +0200 |
---|---|---|
committer | Dees_Troy <dees_troy@teamw.in> | 2012-09-11 02:32:20 +0200 |
commit | 657c30948694632e937da9a4e61219c5e4bf95a0 (patch) | |
tree | 169514d80d22ba9bb4ac4378de140a9a9e56620b | |
parent | More Partition Manager functionality (diff) | |
download | android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.tar android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.tar.gz android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.tar.bz2 android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.tar.lz android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.tar.xz android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.tar.zst android_bootable_recovery-657c30948694632e937da9a4e61219c5e4bf95a0.zip |
-rw-r--r-- | extra-functions.c | 559 | ||||
-rw-r--r-- | extra-functions.h | 11 | ||||
-rw-r--r-- | gui/action.cpp | 23 | ||||
-rw-r--r-- | gui/objects.hpp | 2 | ||||
-rw-r--r-- | partition.cpp | 32 | ||||
-rw-r--r-- | partitionmanager.cpp | 8 |
6 files changed, 441 insertions, 194 deletions
diff --git a/extra-functions.c b/extra-functions.c index ccdbba576..4b03bc963 100644 --- a/extra-functions.c +++ b/extra-functions.c @@ -43,8 +43,6 @@ #include "bootloader.h" #include "common.h" #include "extra-functions.h" -#include "cutils/properties.h" -#include "install.h" #include "minuitwrp/minui.h" #include "minzip/DirUtil.h" #include "minzip/Zip.h" @@ -52,13 +50,22 @@ #include "roots.h" #include "data.h" #include "variables.h" -#include "install.h" +#include "mincrypt/rsa.h" +#include "verifier.h" +#include "mincrypt/sha.h" + +#ifndef PUBLIC_KEYS_FILE +#define PUBLIC_KEYS_FILE "/res/keys" +#endif +#ifndef ASSUMED_UPDATE_BINARY_NAME +#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" +#endif +enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT }; //kang system() from bionic/libc/unistd and rename it __system() so we can be even more hackish :) #undef _PATH_BSHELL #define _PATH_BSHELL "/sbin/sh" -static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; extern char **environ; int __system(const char *command) { @@ -414,204 +421,412 @@ int check_md5(char* path) { return o; } -static int really_install_package(const char *path, int* wipe_cache) -{ - //ui->SetBackground(RecoveryUI::INSTALLING); - LOGI("Finding update package...\n"); - //ui->SetProgressType(RecoveryUI::INDETERMINATE); - LOGI("Update location: %s\n", path); +static void set_sdcard_update_bootloader_message() { + struct bootloader_message boot; + memset(&boot, 0, sizeof(boot)); + strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); + strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); + set_bootloader_message(&boot); +} - if (ensure_path_mounted(path) != 0) { - LOGE("Can't mount %s\n", path); +int TWtry_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) { + const ZipEntry* binary_entry = + mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); + if (binary_entry == NULL) { + mzCloseZipArchive(zip); return INSTALL_CORRUPT; } + const char* binary = "/tmp/update_binary"; + unlink(binary); + int fd = creat(binary, 0755); + if (fd < 0) { + mzCloseZipArchive(zip); + LOGE("Can't make %s\n", binary); + return INSTALL_ERROR; + } + bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); + close(fd); + mzCloseZipArchive(zip); - LOGI("Opening update package...\n"); - - int numKeys; - /*RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); - if (loadedKeys == NULL) { - LOGE("Failed to load keys\n"); - return INSTALL_CORRUPT; + if (!ok) { + LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME); + return INSTALL_ERROR; } - LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);*/ - - // Give verification half the progress bar... - LOGI("Verifying update package...\n"); - //ui->SetProgressType(RecoveryUI::DETERMINATE); - //ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); - - int err; - /*err = verify_file(path, loadedKeys, numKeys); - free(loadedKeys); - LOGI("verify_file returned %d\n", err); - if (err != VERIFY_SUCCESS) { - LOGE("signature verification failed\n"); - return INSTALL_CORRUPT; - }*/ - /* Try to open the package. - */ - ZipArchive zip; - err = mzOpenZipArchive(path, &zip); - if (err != 0) { - LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad"); - return INSTALL_CORRUPT; + int pipefd[2]; + pipe(pipefd); + + // When executing the update binary contained in the package, the + // arguments passed are: + // + // - the version number for this interface + // + // - an fd to which the program can write in order to update the + // progress bar. The program can write single-line commands: + // + // progress <frac> <secs> + // fill up the next <frac> part of of the progress bar + // over <secs> seconds. If <secs> is zero, use + // set_progress commands to manually control the + // progress of this segment of the bar + // + // set_progress <frac> + // <frac> should be between 0.0 and 1.0; sets the + // progress bar within the segment defined by the most + // recent progress command. + // + // firmware <"hboot"|"radio"> <filename> + // arrange to install the contents of <filename> in the + // given partition on reboot. + // + // (API v2: <filename> may start with "PACKAGE:" to + // indicate taking a file from the OTA package.) + // + // (API v3: this command no longer exists.) + // + // ui_print <string> + // display <string> on the screen. + // + // - the name of the package zip file. + // + + const char** args = (const char**)malloc(sizeof(char*) * 5); + args[0] = binary; + args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk + char* temp = (char*)malloc(10); + sprintf(temp, "%d", pipefd[1]); + args[2] = temp; + args[3] = (char*)path; + args[4] = NULL; + + pid_t pid = fork(); + if (pid == 0) { + close(pipefd[0]); + execv(binary, (char* const*)args); + fprintf(stdout, "E:Can't run %s (error)\n", binary); + _exit(-1); } + close(pipefd[1]); + *wipe_cache = 0; + + char buffer[1024]; + FILE* from_child = fdopen(pipefd[0], "r"); + LOGI("8\n"); + while (fgets(buffer, sizeof(buffer), from_child) != NULL) { + char* command = strtok(buffer, " \n"); + if (command == NULL) { + continue; + } else if (strcmp(command, "progress") == 0) { + char* fraction_s = strtok(NULL, " \n"); + char* seconds_s = strtok(NULL, " \n"); + + float fraction = strtof(fraction_s, NULL); + int seconds = strtol(seconds_s, NULL, 10); + + //ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds); + } else if (strcmp(command, "set_progress") == 0) { + char* fraction_s = strtok(NULL, " \n"); + float fraction = strtof(fraction_s, NULL); + //ui->SetProgress(fraction); + } else if (strcmp(command, "ui_print") == 0) { + char* str = strtok(NULL, "\n"); + if (str) { + //ui->Print("%s", str); + } else { + //ui->Print("\n"); + } + } else if (strcmp(command, "wipe_cache") == 0) { + *wipe_cache = 1; + } else if (strcmp(command, "clear_display") == 0) { + //ui->SetBackground(RecoveryUI::NONE); + } else { + LOGE("unknown command [%s]\n", command); + } + } + fclose(from_child); - /* Verify and install the contents of the package. - */ - LOGI("Installing update...\n"); - return try_update_binary(path, &zip, wipe_cache); + int status; + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status)); + return INSTALL_ERROR; + } + return INSTALL_SUCCESS; } -static void set_sdcard_update_bootloader_message() { - struct bootloader_message boot; - memset(&boot, 0, sizeof(boot)); - strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); - strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); - set_bootloader_message(&boot); -} +// Look for an RSA signature embedded in the .ZIP file comment given +// the path to the zip. Verify it matches one of the given public +// keys. +// +// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered +// or no key matches the signature). -static char* copy_sideloaded_package(const char* original_path) { - if (ensure_path_mounted(original_path) != 0) { - LOGE("Can't mount %s\n", original_path); - return NULL; - } +int TWverify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) { + //ui->SetProgress(0.0); - if (ensure_path_mounted(SIDELOAD_TEMP_DIR) != 0) { - LOGE("Can't mount %s\n", SIDELOAD_TEMP_DIR); - return NULL; - } + FILE* f = fopen(path, "rb"); + if (f == NULL) { + LOGE("failed to open %s (%s)\n", path, strerror(errno)); + return VERIFY_FAILURE; + } - if (mkdir(SIDELOAD_TEMP_DIR, 0700) != 0) { - if (errno != EEXIST) { - LOGE("Can't mkdir %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno)); - return NULL; + // An archive with a whole-file signature will end in six bytes: + // + // (2-byte signature start) $ff $ff (2-byte comment size) + // + // (As far as the ZIP format is concerned, these are part of the + // archive comment.) We start by reading this footer, this tells + // us how far back from the end we have to start reading to find + // the whole comment. + +#define FOOTER_SIZE 6 + + if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) { + LOGE("failed to seek in %s (%s)\n", path, strerror(errno)); + fclose(f); + return VERIFY_FAILURE; } - } - // verify that SIDELOAD_TEMP_DIR is exactly what we expect: a - // directory, owned by root, readable and writable only by root. - struct stat st; - if (stat(SIDELOAD_TEMP_DIR, &st) != 0) { - LOGE("failed to stat %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno)); - return NULL; - } - if (!S_ISDIR(st.st_mode)) { - LOGE("%s isn't a directory\n", SIDELOAD_TEMP_DIR); - return NULL; - } - if ((st.st_mode & 0777) != 0700) { - LOGE("%s has perms %o\n", SIDELOAD_TEMP_DIR, st.st_mode); - return NULL; - } - if (st.st_uid != 0) { - LOGE("%s owned by %lu; not root\n", SIDELOAD_TEMP_DIR, st.st_uid); - return NULL; - } + unsigned char footer[FOOTER_SIZE]; + if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) { + LOGE("failed to read footer from %s (%s)\n", path, strerror(errno)); + fclose(f); + return VERIFY_FAILURE; + } - char copy_path[PATH_MAX]; - strcpy(copy_path, SIDELOAD_TEMP_DIR); - strcat(copy_path, "/package.zip"); + if (footer[2] != 0xff || footer[3] != 0xff) { + fclose(f); + return VERIFY_FAILURE; + } - char* buffer = malloc(BUFSIZ); - if (buffer == NULL) { - LOGE("Failed to allocate buffer\n"); - return NULL; - } + size_t comment_size = footer[4] + (footer[5] << 8); + size_t signature_start = footer[0] + (footer[1] << 8); + LOGI("comment is %d bytes; signature %d bytes from end\n", + comment_size, signature_start); - size_t read; - FILE* fin = fopen(original_path, "rb"); - if (fin == NULL) { - LOGE("Failed to open %s (%s)\n", original_path, strerror(errno)); - return NULL; - } - FILE* fout = fopen(copy_path, "wb"); - if (fout == NULL) { - LOGE("Failed to open %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } + if (signature_start - FOOTER_SIZE < RSANUMBYTES) { + // "signature" block isn't big enough to contain an RSA block. + LOGE("signature is too short\n"); + fclose(f); + return VERIFY_FAILURE; + } + +#define EOCD_HEADER_SIZE 22 - while ((read = fread(buffer, 1, BUFSIZ, fin)) > 0) { - if (fwrite(buffer, 1, read, fout) != read) { - LOGE("Short write of %s (%s)\n", copy_path, strerror(errno)); - return NULL; + // The end-of-central-directory record is 22 bytes plus any + // comment length. + size_t eocd_size = comment_size + EOCD_HEADER_SIZE; + + if (fseek(f, -eocd_size, SEEK_END) != 0) { + LOGE("failed to seek in %s (%s)\n", path, strerror(errno)); + fclose(f); + return VERIFY_FAILURE; } - } - free(buffer); + // Determine how much of the file is covered by the signature. + // This is everything except the signature data and length, which + // includes all of the EOCD except for the comment length field (2 + // bytes) and the comment data. + size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2; + + unsigned char* eocd = (unsigned char*)malloc(eocd_size); + if (eocd == NULL) { + LOGE("malloc for EOCD record failed\n"); + fclose(f); + return VERIFY_FAILURE; + } + if (fread(eocd, 1, eocd_size, f) != eocd_size) { + LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno)); + fclose(f); + return VERIFY_FAILURE; + } - if (fclose(fout) != 0) { - LOGE("Failed to close %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } + // If this is really is the EOCD record, it will begin with the + // magic number $50 $4b $05 $06. + if (eocd[0] != 0x50 || eocd[1] != 0x4b || + eocd[2] != 0x05 || eocd[3] != 0x06) { + LOGE("signature length doesn't match EOCD marker\n"); + fclose(f); + return VERIFY_FAILURE; + } - if (fclose(fin) != 0) { - LOGE("Failed to close %s (%s)\n", original_path, strerror(errno)); - return NULL; - } + size_t i; + for (i = 4; i < eocd_size-3; ++i) { + if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b && + eocd[i+2] == 0x05 && eocd[i+3] == 0x06) { + // if the sequence $50 $4b $05 $06 appears anywhere after + // the real one, minzip will find the later (wrong) one, + // which could be exploitable. Fail verification if + // this sequence occurs anywhere after the real one. + LOGE("EOCD marker occurs after start of EOCD\n"); + fclose(f); + return VERIFY_FAILURE; + } + } - // "adb push" is happy to overwrite read-only files when it's - // running as root, but we'll try anyway. - if (chmod(copy_path, 0400) != 0) { - LOGE("Failed to chmod %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } +#define BUFFER_SIZE 4096 + + SHA_CTX ctx; + SHA_init(&ctx); + unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); + if (buffer == NULL) { + LOGE("failed to alloc memory for sha1 buffer\n"); + fclose(f); + return VERIFY_FAILURE; + } - return strdup(copy_path); + double frac = -1.0; + size_t so_far = 0; + fseek(f, 0, SEEK_SET); + while (so_far < signed_len) { + size_t size = BUFFER_SIZE; + if (signed_len - so_far < size) size = signed_len - so_far; + if (fread(buffer, 1, size, f) != size) { + LOGE("failed to read data from %s (%s)\n", path, strerror(errno)); + fclose(f); + return VERIFY_FAILURE; + } + SHA_update(&ctx, buffer, size); + so_far += size; + double f = so_far / (double)signed_len; + if (f > frac + 0.02 || size == so_far) { + //ui->SetProgress(f); + frac = f; + } + } + fclose(f); + free(buffer); + + const uint8_t* sha1 = SHA_final(&ctx); + for (i = 0; i < numKeys; ++i) { + // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that + // the signing tool appends after the signature itself. + if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES, + RSANUMBYTES, sha1)) { + LOGI("whole-file signature verified against key %d\n", i); + free(eocd); + return VERIFY_SUCCESS; + } + } + free(eocd); + LOGE("failed to verify whole-file signature\n"); + return VERIFY_FAILURE; } -int install_zip_package(const char* zip_path_filename) { - int result = 0; - - //mount_current_storage(); - int md5_req = DataManager_GetIntValue(TW_FORCE_MD5_CHECK_VAR); - if (md5_req == 1) { - ui_print("\n-- Verify md5 for %s", zip_path_filename); - int md5chk = check_md5((char*) zip_path_filename); - if (md5chk == 1) { - ui_print("\n-- Md5 verified, continue"); - result = 0; - } - else if (md5chk == -1) { - if (md5_req == 1) { - ui_print("\n-- No md5 file found!"); - ui_print("\n-- Aborting install"); - result = INSTALL_ERROR; - } - else { - ui_print("\n-- No md5 file found, ignoring"); - } - } - else if (md5chk == -2) { - ui_print("\n-- md5 file doesn't match!"); - ui_print("\n-- Aborting install"); - result = INSTALL_ERROR; - } - printf("%d\n", result); - } - if (result != INSTALL_ERROR) { - ui_print("\n-- Install %s ...\n", zip_path_filename); - set_sdcard_update_bootloader_message(); - char* copy; - if (DataManager_GetIntValue(TW_FLASH_ZIP_IN_PLACE) == 1 && strlen(zip_path_filename) > 6 && strncmp(zip_path_filename, "/cache", 6) != 0) { - copy = strdup(zip_path_filename); - } else { - copy = copy_sideloaded_package(zip_path_filename); - //unmount_current_storage(); +// Reads a file containing one or more public keys as produced by +// DumpPublicKey: this is an RSAPublicKey struct as it would appear +// as a C source literal, eg: +// +// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}" +// +// (Note that the braces and commas in this example are actual +// characters the parser expects to find in the file; the ellipses +// indicate more numbers omitted from this example.) +// +// The file may contain multiple keys in this format, separated by +// commas. The last key must not be followed by a comma. +// +// Returns NULL if the file failed to parse, or if it contain zero keys. +static RSAPublicKey* +TWload_keys(const char* filename, int* numKeys) { + RSAPublicKey* out = NULL; + *numKeys = 0; + + FILE* f = fopen(filename, "r"); + if (f == NULL) { + LOGE("opening %s: ERROR\n", filename); + goto exit; + } + + { + int i; + bool done = false; + while (!done) { + ++*numKeys; + out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey)); + RSAPublicKey* key = out + (*numKeys - 1); + if (fscanf(f, " { %i , 0x%x , { %u", + &(key->len), &(key->n0inv), &(key->n[0])) != 3) { + goto exit; + } + if (key->len != RSANUMWORDS) { + LOGE("key length (%d) does not match expected size\n", key->len); + goto exit; + } + for (i = 1; i < key->len; ++i) { + if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit; + } + if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit; + for (i = 1; i < key->len; ++i) { + if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit; + } + fscanf(f, " } } "); + + // if the line ends in a comma, this file has more keys. + switch (fgetc(f)) { + case ',': + // more keys to come. + break; + + case EOF: + done = true; + break; + + default: + LOGE("unexpected character between keys\n"); + goto exit; + } + } + } + + fclose(f); + return out; + +exit: + if (f) fclose(f); + free(out); + *numKeys = 0; + return NULL; +} + +int TWinstall_zip(const char* path, int* wipe_cache) { + int err; + + if (DataManager_GetIntValue(TW_SIGNED_ZIP_VERIFY_VAR)) { + int numKeys; + RSAPublicKey* loadedKeys = TWload_keys(PUBLIC_KEYS_FILE, &numKeys); + if (loadedKeys == NULL) { + LOGE("Failed to load keys\n"); + return -1; } - if (copy) { - result = really_install_package(copy, 0); - free(copy); - //update_system_details(); - } else { - result = INSTALL_ERROR; + LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE); + + // Give verification half the progress bar... + //ui->Print("Verifying update package...\n"); + //ui->SetProgressType(RecoveryUI::DETERMINATE); + //ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); + + err = TWverify_file(path, loadedKeys, numKeys); + free(loadedKeys); + LOGI("verify_file returned %d\n", err); + if (err != VERIFY_SUCCESS) { + LOGE("signature verification failed\n"); + return -1; } } - //mount_current_storage(); - //finish_recovery(NULL); - return result; + /* Try to open the package. + */ + ZipArchive zip; + err = mzOpenZipArchive(path, &zip); + if (err != 0) { + LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad"); + return INSTALL_CORRUPT; + } + + /* Verify and install the contents of the package. + */ + //ui->Print("Installing update...\n"); + return TWtry_update_binary(path, &zip, wipe_cache); } //partial kangbang from system/vold diff --git a/extra-functions.h b/extra-functions.h index 6d2a085fc..0c702b7da 100644 --- a/extra-functions.h +++ b/extra-functions.h @@ -1,15 +1,22 @@ #ifndef _EXTRAFUNCTIONS_HEADER #define _EXTRAFUNCTIONS_HEADER +#include "mincrypt/rsa.h" +#include "minzip/Zip.h" + int __system(const char *command); FILE * __popen(const char *program, const char *type); int __pclose(FILE *iop); +// Install Zip functions +int TWtry_update_binary(const char *path, ZipArchive *zip, int* wipe_cache); +static RSAPublicKey* TWload_keys(const char* filename, int* numKeys); +int TWverify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys); +int TWinstall_zip(const char* path, int* wipe_cache); + // Device ID variable / function extern char device_id[64]; void get_device_id(); -static char* copy_sideloaded_package(const char* original_path); -int install_zip_package(const char* zip_path_filename); void wipe_dalvik_cache(); void wipe_battery_stats(); diff --git a/gui/action.cpp b/gui/action.cpp index aee56849f..3e19a6132 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -14,6 +14,7 @@ #include <time.h> #include <unistd.h> #include <stdlib.h> +#include <sys/wait.h> #include <string> #include <sstream> @@ -28,7 +29,6 @@ extern "C" { #include "../extra-functions.h" #include "../variables.h" -int install_zip_package(const char* zip_path_filename); void fix_perms(); void wipe_dalvik_cache(void); int check_backup_name(int show_error); @@ -53,7 +53,6 @@ int gui_start(); #include "rapidxml.hpp" #include "objects.hpp" - void curtainClose(void); GUIAction::GUIAction(xml_node<>* node) @@ -159,7 +158,7 @@ void GUIAction::simulate_progress_bar(void) } } -int GUIAction::flash_zip(std::string filename, std::string pageName, const int simulate) +int GUIAction::flash_zip(std::string filename, std::string pageName, const int simulate, int* wipe_cache) { int ret_val = 0; @@ -177,7 +176,10 @@ int GUIAction::flash_zip(std::string filename, std::string pageName, const int s int fd = -1; ZipArchive zip; - if (mzOpenZipArchive(filename.c_str(), &zip)) + if (!PartitionManager.Mount_By_Path(filename, true)) + return -1; + + if (mzOpenZipArchive(filename.c_str(), &zip)) { LOGE("Unable to open zip file.\n"); return -1; @@ -195,14 +197,14 @@ int GUIAction::flash_zip(std::string filename, std::string pageName, const int s !PageManager::LoadPackage("install", "/tmp/twrp.zip", "main")) { mzCloseZipArchive(&zip); - PageManager::SelectPackage("install"); + PageManager::SelectPackage("install"); gui_changePage("main"); } else { // In this case, we just use the default page mzCloseZipArchive(&zip); - gui_changePage(pageName); + gui_changePage(pageName); } if (fd >= 0) close(fd); @@ -210,7 +212,7 @@ int GUIAction::flash_zip(std::string filename, std::string pageName, const int s if (simulate) { simulate_progress_bar(); } else { - ret_val = install_zip_package(filename.c_str()); + ret_val = TWinstall_zip(filename.c_str(), wipe_cache); // Now, check if we need to ensure TWRP remains installed... struct stat st; @@ -624,14 +626,14 @@ int GUIAction::doAction(Action action, int isThreaded /* = 0 */) if (function == "flash") { - int i, ret_val = 0; + int i, ret_val = 0, wipe_cache = 0; for (i=0; i<zip_queue_index; i++) { operation_start("Flashing"); DataManager::SetValue("tw_filename", zip_queue[i]); DataManager::SetValue(TW_ZIP_INDEX, (i + 1)); - ret_val = flash_zip(zip_queue[i], arg, simulate); + ret_val = flash_zip(zip_queue[i], arg, simulate, &wipe_cache); if (ret_val != 0) { ui_print("Error flashing zip '%s'\n", zip_queue[i].c_str()); i = 10; // Error flashing zip - exit queue @@ -641,6 +643,9 @@ int GUIAction::doAction(Action action, int isThreaded /* = 0 */) zip_queue_index = 0; DataManager::SetValue(TW_ZIP_QUEUE_COUNT, zip_queue_index); + if (wipe_cache) + PartitionManager.Wipe_By_Path("/cache"); + if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { operation_start("ReinjectTWRP"); ui_print("Injecting TWRP into boot image...\n"); diff --git a/gui/objects.hpp b/gui/objects.hpp index 6b247facc..1f3f11a90 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -251,7 +251,7 @@ protected: virtual int doAction(Action action, int isThreaded = 0); static void* thread_start(void *cookie); void simulate_progress_bar(void); - int flash_zip(std::string filename, std::string pageName, const int simulate); + int flash_zip(std::string filename, std::string pageName, const int simulate, int* wipe_cache); void operation_start(const string operation_name); void operation_end(const int operation_status, const int simulate); static void* command_thread(void *cookie); diff --git a/partition.cpp b/partition.cpp index 081487e79..f3c79f7c2 100644 --- a/partition.cpp +++ b/partition.cpp @@ -29,6 +29,10 @@ #include <unistd.h> #include <dirent.h> +#ifdef TW_INCLUDE_CRYPTO + #include "cutils/properties.h" +#endif + #include "variables.h" #include "common.h" #include "partitions.hpp" @@ -156,12 +160,28 @@ bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) { Has_Data_Media = true; Is_Storage = true; Storage_Path = "/data/media"; - Make_Dir("/sdcard", Display_Error); - Make_Dir("/emmc", Display_Error); + if (strcmp(EXPAND(TW_EXTERNAL_STORAGE_PATH), "/sdcard") == 0) { + Make_Dir("/emmc", Display_Error); + Symlink_Path = "/data/media"; + Symlink_Mount_Point = "/emmc"; + } else { + Make_Dir("/sdcard", Display_Error); + Symlink_Path = "/data/media"; + Symlink_Mount_Point = "/sdcard"; + } #endif #ifdef TW_INCLUDE_CRYPTO Can_Be_Encrypted = true; - if (!Mount(false)) { + char crypto_blkdev[255]; + property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, "error"); + if (strcmp(crypto_blkdev, "error") != 0) { + DataManager::SetValue(TW_DATA_BLK_DEVICE, Block_Device); + DataManager::SetValue(TW_IS_DECRYPTED, 1); + Is_Encrypted = true; + Is_Decrypted = true; + Decrypted_Block_Device = crypto_blkdev; + LOGI("Data already decrypted, new block device: '%s'\n", crypto_blkdev); + } else if (!Mount(false)) { Is_Encrypted = true; Is_Decrypted = false; DataManager::SetValue(TW_IS_ENCRYPTED, 1); @@ -320,7 +340,7 @@ void TWPartition::Setup_File_System(bool Display_Error) { // Check to see if the block device exists if (Path_Exists(Block_Device)) { Is_Present = true; - } else if (Alternate_Block_Device != "" && Path_Exists(Alternate_Block_Device)) { + } else if (!Alternate_Block_Device.empty() && Path_Exists(Alternate_Block_Device)) { Flip_Block_Device(); Is_Present = true; } @@ -334,7 +354,7 @@ void TWPartition::Setup_File_System(bool Display_Error) { void TWPartition::Setup_Image(bool Display_Error) { if (Path_Exists(Block_Device)) { Is_Present = true; - } else if (Alternate_Block_Device != "" && Path_Exists(Alternate_Block_Device)) { + } else if (!Alternate_Block_Device.empty() && Path_Exists(Alternate_Block_Device)) { Flip_Block_Device(); Is_Present = true; } @@ -595,7 +615,7 @@ bool TWPartition::Mount(bool Display_Error) { if (mount(Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { Check_FS_Type(); if (mount(Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { - if (Alternate_Block_Device != "" && Path_Exists(Alternate_Block_Device)) { + if (!Alternate_Block_Device.empty() && Path_Exists(Alternate_Block_Device)) { Flip_Block_Device(); Check_FS_Type(); if (mount(Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) { diff --git a/partitionmanager.cpp b/partitionmanager.cpp index 3509c4c3e..47cc84746 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -116,7 +116,7 @@ int TWPartitionManager::Mount_By_Path(string Path, bool Display_Error) { // Iterate through all partitions for (iter = Partitions.begin(); iter != Partitions.end(); iter++) { - if ((*iter)->Mount_Point == Local_Path) { + if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) { ret = (*iter)->Mount(Display_Error); found = true; } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) { @@ -185,7 +185,7 @@ int TWPartitionManager::UnMount_By_Path(string Path, bool Display_Error) { // Iterate through all partitions for (iter = Partitions.begin(); iter != Partitions.end(); iter++) { - if ((*iter)->Mount_Point == Local_Path) { + if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) { ret = (*iter)->UnMount(Display_Error); found = true; } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) { @@ -297,7 +297,7 @@ TWPartition* TWPartitionManager::Find_Partition_By_Path(string Path) { string Local_Path = Get_Root_Path(Path); for (iter = Partitions.begin(); iter != Partitions.end(); iter++) { - if ((*iter)->Mount_Point == Local_Path) + if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) return (*iter); } return NULL; @@ -555,7 +555,7 @@ int TWPartitionManager::Wipe_By_Path(string Path) { // Iterate through all partitions for (iter = Partitions.begin(); iter != Partitions.end(); iter++) { - if ((*iter)->Mount_Point == Local_Path) { + if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) { ret = (*iter)->Wipe(); found = true; } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) { |