From ce8f83c48d200106ff61ad530c863b15c16949d9 Mon Sep 17 00:00:00 2001 From: bigbiff Date: Sat, 12 Dec 2015 18:30:21 -0500 Subject: ADB: Add adb backup for TWRP. Functionality for client side to backup tar and image streams over adbd to the client under backup.ab. Using adb backup on the client side you can backup the partitions TWRP knows about. On the client side you can do the following: adb backup -f --twrp where options are --compress: compress data system: backup system cache: backup cache data: backup data boot: backup boot etc for each partition. You can string multiple options, i.e. adb backup -f --twrp --compress cache system data adb backup in TWRP will take any option corresponding to TWRP fstab partitions, e.g. efs boot as well. If you do not specify the filename with the -f option, adb will backup your data to a filename backup.ab on the client. You can then rename the file and encrypt it with desktop tools. If you don't want to use command line arguments: adb backup --twrp will bring up the gui and allow you to choose partitions from the backup page. To restore the backup use the following convention: adb restore Structures are used to store metadata in binary inside of the file itself. If the metadata structure is modified, update the adb version so that it will invalidate older backups and not cause issues on restore. When restoring, we currently do not support picking specific partitions. It's all or nothing. Change-Id: Idb92c37fc9801dc8d89ed2a4570e9d12e76facf8 --- openrecoveryscript.cpp | 289 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 287 insertions(+), 2 deletions(-) (limited to 'openrecoveryscript.cpp') diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp index 75db902e2..0d2268cd1 100644 --- a/openrecoveryscript.cpp +++ b/openrecoveryscript.cpp @@ -1,5 +1,5 @@ /* - Copyright 2012 bigbiff/Dees_Troy TeamWin + Copyright 2016 TeamWin This file is part of TWRP/TeamWin Recovery Project. TWRP is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ along with TWRP. If not, see . */ +#define __STDC_FORMAT_MACROS 1 #include #include #include @@ -26,21 +27,31 @@ #include #include #include +#include #include #include +#include +#include +#include +#include #include #include +#include #include "twrp-functions.hpp" #include "partitions.hpp" #include "twcommon.h" #include "openrecoveryscript.hpp" +#include "progresstracking.hpp" #include "variables.h" #include "adb_install.h" #include "data.hpp" #include "adb_install.h" #include "fuse_sideload.h" #include "gui/gui.hpp" +#include "gui/pages.hpp" +#include "orscmd/orscmd.h" +#include "adbbu/libtwadbbu.hpp" extern "C" { #include "twinstall.h" #include "gui/gui.h" @@ -139,6 +150,8 @@ int OpenRecoveryScript::run_script_file(void) { // Wipe if (strcmp(value, "cache") == 0 || strcmp(value, "/cache") == 0) { PartitionManager.Wipe_By_Path("/cache"); + } else if (strcmp(value, "system") == 0 || strcmp(value, "/system") == 0) { + PartitionManager.Wipe_By_Path("/system"); } else if (strcmp(value, "dalvik") == 0 || strcmp(value, "dalvick") == 0 || strcmp(value, "dalvikcache") == 0 || strcmp(value, "dalvickcache") == 0) { PartitionManager.Wipe_Dalvik_Cache(); } else if (strcmp(value, "data") == 0 || strcmp(value, "/data") == 0 || strcmp(value, "factory") == 0 || strcmp(value, "factoryreset") == 0) { @@ -280,6 +293,17 @@ int OpenRecoveryScript::run_script_file(void) { ret_val = 1; else gui_msg("done=Done."); + } else if (strncmp(command, "adbbackup", 9) == 0) { + ret_val = Backup_ADB_Command(value); + if (ret_val == 1) { + twadbbu::Write_TWERROR(); + gui_err("adbbackup_error=Error with ADB Backup. Quitting..."); + } + } else if (strcmp(command, "adbrestore") == 0) { + LOGINFO("running adb restore\n"); + ret_val = Restore_ADB_Backup(); + } else if (strcmp(command, "remountrw") == 0) { + ret_val = remountrw(); } else if (strcmp(command, "mount") == 0) { // Mount DataManager::SetValue("tw_action_text2", gui_parse_text("{@mounting}")); @@ -400,6 +424,7 @@ int OpenRecoveryScript::run_script_file(void) { gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(SCRIPT_FILE_TMP)(strerror(errno))); return 1; } + if (install_cmd && DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { gui_msg("injecttwrp=Injecting TWRP into boot image..."); TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot"); @@ -485,6 +510,72 @@ int OpenRecoveryScript::Install_Command(string Zip) { return ret_val; } +int OpenRecoveryScript::Backup_ADB_Command(std::string Options) { + std::vector args; + std::string Backup_List; + bool adbbackup = true, ret = false; + std::string rmopt = "--"; + + std::replace(Options.begin(), Options.end(), ':', ' '); + args = TWFunc::Split_String(Options, " "); + + DataManager::SetValue(TW_USE_COMPRESSION_VAR, 0); + DataManager::SetValue(TW_SKIP_MD5_GENERATE_VAR, 0); + + if (args[1].compare("--twrp") != 0) { + gui_err("twrp_adbbu_option=--twrp option is required to enable twrp adb backup"); + sleep(2); + return 1; + } + + for (unsigned i = 2; i < args.size(); i++) { + int compress; + + std::string::size_type size = args[i].find(rmopt); + if (size != std::string::npos) + args[i].erase(size, rmopt.length()); + + if (args[i].compare("compress") == 0) { + gui_msg("compression_on=Compression is on"); + DataManager::SetValue(TW_USE_COMPRESSION_VAR, 1); + continue; + } + DataManager::GetValue(TW_USE_COMPRESSION_VAR, compress); + gui_print("%s\n", args[i].c_str()); + std::string path; + path = "/" + args[i]; + TWPartition* part = PartitionManager.Find_Partition_By_Path(path); + if (part) { + Backup_List += path; + Backup_List += ";"; + } + else { + gui_msg(Msg(msg::kError, "partition_not_found=path: {1} not found in partition list")(path)); + return 1; + } + } + + if (Backup_List.empty()) { + DataManager::GetValue("tw_backup_list", Backup_List); + if (Backup_List.empty()) { + gui_err("no_partition_selected=No partitions selected for backup."); + return 1; + } + } + else + DataManager::SetValue("tw_backup_list", Backup_List); + + ret = PartitionManager.Run_Backup(adbbackup); + DataManager::SetValue(TW_BACKUP_NAME, gui_lookup("auto_generate", "(Auto Generate)")); + if (!ret) { + gui_err("backup_fail=Backup failed"); + return 1; + } + gui_msg("backup_complete=Backup Complete"); + sleep(2); //give time for user to see messages on console + return 0; +} + string OpenRecoveryScript::Locate_Zip_File(string Zip, string Storage_Root) { string Path = TWFunc::Get_Path(Zip); string File = TWFunc::Get_Filename(Zip); @@ -513,6 +604,7 @@ int OpenRecoveryScript::Backup_Command(string Options) { char value1[SCRIPT_COMMAND_SIZE]; int line_len, i; string Backup_List; + bool adbbackup = false; strcpy(value1, Options.c_str()); @@ -558,7 +650,7 @@ int OpenRecoveryScript::Backup_Command(string Options) { } } DataManager::SetValue("tw_backup_list", Backup_List); - if (!PartitionManager.Run_Backup()) { + if (!PartitionManager.Run_Backup(false)) { gui_err("backup_fail=Backup Failed"); return 1; } @@ -651,3 +743,196 @@ void OpenRecoveryScript::Run_CLI_Command(const char* command) { call_after_cli_command(); LOGINFO("Done reading ORS command from command line\n"); } + +int OpenRecoveryScript::Restore_ADB_Backup(void) { + bool breakloop = false; + int partition_count = 0; + std::string Restore_Name; + std::size_t pos = 0; + struct AdbBackupFileTrailer adbmd5; + struct PartitionSettings part_settings; + int adb_control_twrp_fd, adb_write_fd, systemro; + int adb_control_bu_fd, ret = 0; + char cmd[512]; + int orsfd = open(ORS_OUTPUT_FILE, O_WRONLY); + + part_settings.total_restore_size = 0; + + PartitionManager.Mount_All_Storage(); + DataManager::SetValue(TW_SKIP_MD5_CHECK_VAR, 0); + LOGINFO("opening TW_ADB_BU_CONTROL\n"); + adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK); + LOGINFO("opening TW_ADB_TWRP_CONTROL\n"); + adb_control_twrp_fd = open(TW_ADB_TWRP_CONTROL, O_RDONLY | O_NONBLOCK); + memset(&adbmd5, 0, sizeof(adbmd5)); + + while (!breakloop) { + memset(&cmd, 0, sizeof(cmd)); + if (read(adb_control_twrp_fd, cmd, sizeof(cmd)) > 0) { + struct AdbBackupControlType cmdstruct; + + memset(&cmdstruct, 0, sizeof(cmdstruct)); + memcpy(&cmdstruct, cmd, sizeof(cmdstruct)); + std::string cmdstr(cmdstruct.type); + std::string cmdtype = cmdstr.substr(0, sizeof(cmdstruct.type) - 1); + if (cmdstr.substr(0, sizeof(cmdstruct.type) - 1) == TWSTREAMHDR) { + struct AdbBackupStreamHeader twhdr; + memcpy(&twhdr, cmd, sizeof(cmd)); + LOGINFO("ADB Partition count: %" PRIu64 "\n", twhdr.partition_count); + LOGINFO("ADB version: %" PRIu64 "\n", twhdr.version); + if (twhdr.version != ADB_BACKUP_VERSION) { + LOGERR("Incompatible adb backup version!\n"); + breakloop = false; + break; + } + partition_count = twhdr.partition_count; + } + else if (cmdtype == MD5TRAILER) { + LOGINFO("Restoring MD5TRAILER\n"); + memcpy(&adbmd5, cmd, sizeof(cmd)); + } + else if (cmdtype == TWMD5) { + struct AdbBackupFileTrailer md5check; + LOGINFO("Restoring TWMD5\n"); + + memset(&md5check, 0, sizeof(md5check)); + memcpy(&md5check, cmd, sizeof(cmd)); + if (strcmp(md5check.md5, adbmd5.md5) != 0) { + LOGERR("md5 doesn't match!\n"); + LOGERR("file md5: %s\n", adbmd5.md5); + LOGERR("check md5: %s\n", md5check.md5); + breakloop = true; + ret = 1; + break; + } + else { + LOGINFO("adbrestore md5 matches\n"); + LOGINFO("adbmd5.md5: %s\n", adbmd5.md5); + LOGINFO("md5check.md5: %s\n", md5check.md5); + } + } + else if (cmdtype == TWENDADB) { + LOGINFO("received TWENDADB\n"); + breakloop = true; + break; + } + else { + struct twfilehdr twimghdr; + memcpy(&twimghdr, cmd, sizeof(cmd)); + std::string cmdstr(twimghdr.type); + Restore_Name = twimghdr.name; + part_settings.total_restore_size = twimghdr.size; + if (cmdtype == TWIMG) { + LOGINFO("ADB Type: %s\n", twimghdr.type); + LOGINFO("ADB Restore_Name: %s\n", Restore_Name.c_str()); + LOGINFO("ADB Restore_size: %" PRIu64 "\n", part_settings.total_restore_size); + string compression = (twimghdr.compressed == 1) ? "compressed" : "uncompressed"; + LOGINFO("ADB compression: %s\n", compression.c_str()); + std::string Backup_FileName; + std::size_t pos = Restore_Name.find_last_of("/"); + std::string path = "/" + Restore_Name.substr(pos, Restore_Name.size()); + pos = path.find_first_of("."); + path = path.substr(0, pos); + if (path.substr(0,1).compare("//")) { + path = path.substr(1, path.size()); + } + + pos = Restore_Name.find_last_of("/"); + Backup_FileName = Restore_Name.substr(pos + 1, Restore_Name.size()); + part_settings.Part = PartitionManager.Find_Partition_By_Path(path); + part_settings.Restore_Name = path; + part_settings.partition_count = partition_count; + part_settings.adbbackup = true; + part_settings.adb_compression = twimghdr.compressed; + part_settings.Backup_FileName = Backup_FileName; + part_settings.PM_Method = PM_RESTORE; + ProgressTracking progress(part_settings.total_restore_size); + part_settings.progress = &progress; + if (!PartitionManager.Restore_Partition(&part_settings)) { + LOGERR("ADB Restore failed.\n"); + return 1; + } + } + else if (cmdtype == TWFN) { + LOGINFO("ADB Type: %s\n", twimghdr.type); + LOGINFO("ADB Restore_Name: %s\n", Restore_Name.c_str()); + LOGINFO("ADB Restore_size: %" PRIi64 "\n", part_settings.total_restore_size); + string compression = (twimghdr.compressed == 1) ? "compressed" : "uncompressed"; + LOGINFO("ADB compression: %s\n", compression.c_str()); + std::string Backup_FileName; + std::size_t pos = Restore_Name.find_last_of("/"); + std::string path = "/" + Restore_Name.substr(pos, Restore_Name.size()); + pos = path.find_first_of("."); + path = path.substr(0, pos); + if (path.substr(0,1).compare("//")) { + path = path.substr(1, path.size()); + } + + pos = Restore_Name.find_last_of("/"); + Backup_FileName = Restore_Name.substr(pos + 1, Restore_Name.size()); + pos = Restore_Name.find_last_of("/"); + part_settings.Restore_Name = Restore_Name.substr(0, pos); + part_settings.Part = PartitionManager.Find_Partition_By_Path(path); + + if (path.compare("/system") == 0) { + if (part_settings.Part->Is_Read_Only()) { + struct AdbBackupControlType twerror; + strncpy(twerror.start_of_header, TWRP, sizeof(twerror.start_of_header)); + strncpy(twerror.type, TWERROR, sizeof(twerror.type)); + memset(twerror.space, 0, sizeof(twerror.space)); + twerror.crc = crc32(0L, Z_NULL, 0); + twerror.crc = crc32(twerror.crc, (const unsigned char*) &twerror, sizeof(twerror)); + if (write(adb_control_bu_fd, &twerror, sizeof(twerror)) < 0) { + LOGERR("Cannot write to ADB_CONTROL_BU_FD: %s\n", strerror(errno)); + } + gui_msg(Msg(msg::kError, "restore_read_only=Cannot restore {1} -- mounted read only.")(part_settings.Part->Backup_Display_Name)); + return 1; + + } + } + part_settings.partition_count = partition_count; + part_settings.adbbackup = true; + part_settings.adb_compression = twimghdr.compressed; + part_settings.Backup_FileName = Backup_FileName; + part_settings.total_restore_size += part_settings.Part->Get_Restore_Size(&part_settings); + part_settings.PM_Method = PM_RESTORE; + ProgressTracking progress(part_settings.total_restore_size); + part_settings.progress = &progress; + if (!PartitionManager.Restore_Partition(&part_settings)) { + LOGERR("ADB Restore failed.\n"); + return 1; + } + } + } + } + } + gui_msg("restore_complete=Restore Complete"); + + if (!twadbbu::Write_TWENDADB()) + ret = 1; + sleep(2); //give time for user to see messages on console + return ret; +} + +int OpenRecoveryScript::remountrw(void) +{ + bool remount_system = PartitionManager.Is_Mounted_By_Path("/system"); + int op_status; + TWPartition* Part; + + if (!PartitionManager.UnMount_By_Path("/system", true)) { + op_status = 1; // fail + } else { + Part = PartitionManager.Find_Partition_By_Path("/system"); + if (Part) { + DataManager::SetValue("tw_mount_system_ro", 0); + Part->Change_Mount_Read_Only(false); + } + if (remount_system) { + Part->Mount(true); + } + op_status = 0; // success + } + + return op_status; +} -- cgit v1.2.3