From 43d8b0077072ff4ef5ffa07be5dcbf7a73fe499f Mon Sep 17 00:00:00 2001 From: Dees_Troy Date: Mon, 17 Sep 2012 16:00:01 -0400 Subject: Update backup and restore code, adb sideload Fixed a problem with using make_ext4fs by making its lib a dynamic lib. Added ADB sideload zip install feature - no way to cancel it yet. Improve backup and restore code. --- Android.mk | 6 +- adb_install.cpp | 4 +- gui/action.cpp | 43 +++- gui/devices/800x1280/res/ui.xml | 15 ++ partition.cpp | 266 +++++++++++++++-------- partitionmanager.cpp | 471 ++++++++++++++++++++++++++++++++++++++-- partitions.hpp | 9 +- prebuilt/Android.mk | 1 + twrp-functions.cpp | 71 ++++++ twrp-functions.hpp | 15 +- 10 files changed, 773 insertions(+), 128 deletions(-) diff --git a/Android.mk b/Android.mk index 304e60727..caa6b09ed 100644 --- a/Android.mk +++ b/Android.mk @@ -66,14 +66,14 @@ LOCAL_STATIC_LIBRARIES := LOCAL_SHARED_LIBRARIES := LOCAL_STATIC_LIBRARIES += libmtdutils -LOCAL_STATIC_LIBRARIES += libext4_utils libminadbd libminzip libunz +LOCAL_STATIC_LIBRARIES += libminadbd libminzip libunz LOCAL_STATIC_LIBRARIES += libminuitwrp libpixelflinger_static libpng libjpegtwrp libgui -LOCAL_SHARED_LIBRARIES += libz libc libstlport libcutils libstdc++ libmincrypt +LOCAL_SHARED_LIBRARIES += libz libc libstlport libcutils libstdc++ libmincrypt libext4_utils ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) LOCAL_CFLAGS += -DUSE_EXT4 LOCAL_C_INCLUDES += system/extras/ext4_utils - LOCAL_STATIC_LIBRARIES += libext4_utils + #LOCAL_STATIC_LIBRARIES += libext4_utils endif ifeq ($(HAVE_SELINUX), true) diff --git a/adb_install.cpp b/adb_install.cpp index a226ea571..12bce1cca 100644 --- a/adb_install.cpp +++ b/adb_install.cpp @@ -32,6 +32,8 @@ #include "adb_install.h" extern "C" { #include "minadbd/adb.h" +#include "twinstall.h" +int TWinstall_zip(const char* path, int* wipe_cache); } static RecoveryUI* ui = NULL; @@ -106,5 +108,5 @@ apply_from_adb(RecoveryUI* ui_, int* wipe_cache, const char* install_file) { } return INSTALL_ERROR; } - return install_package(ADB_SIDELOAD_FILENAME, wipe_cache, install_file); + return TWinstall_zip(ADB_SIDELOAD_FILENAME, wipe_cache); } diff --git a/gui/action.cpp b/gui/action.cpp index b050febd0..3d6c9ebaa 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -21,6 +21,9 @@ #include "../partitions.hpp" #include "../twrp-functions.hpp" +#include "../ui.h" +#include "../adb_install.h" + extern "C" { #include "../common.h" #include "../roots.h" @@ -31,6 +34,8 @@ extern "C" { #include "../variables.h" #include "../twinstall.h" +#include "../minadbd/adb.h" + int TWinstall_zip(const char* path, int* wipe_cache); void wipe_dalvik_cache(void); int check_backup_name(int show_error); @@ -55,6 +60,8 @@ int gui_start(); #include "rapidxml.hpp" #include "objects.hpp" +extern RecoveryUI* ui; + void curtainClose(void); GUIAction::GUIAction(xml_node<>* node) @@ -733,6 +740,7 @@ int GUIAction::doAction(Action action, int isThreaded /* = 0 */) if (function == "nandroid") { operation_start("Nandroid"); + int ret = 0; if (simulate) { DataManager::SetValue("tw_partition", "Simulation"); @@ -741,21 +749,27 @@ int GUIAction::doAction(Action action, int isThreaded /* = 0 */) if (arg == "backup") { string Backup_Name; DataManager::GetValue(TW_BACKUP_NAME, Backup_Name); - if (Backup_Name == "(Current Date)" || Backup_Name == "0" || Backup_Name == "(" || check_backup_name(1)) - PartitionManager.Run_Backup(Backup_Name); - else + if (Backup_Name == "(Current Date)" || Backup_Name == "0" || Backup_Name == "(" || check_backup_name(1) == 0) + ret = PartitionManager.Run_Backup(); + else { + operation_end(1, simulate); return -1; + } DataManager::SetValue(TW_BACKUP_NAME, "(Current Date)"); } else if (arg == "restore") { string Restore_Name; DataManager::GetValue("tw_restore", Restore_Name); - PartitionManager.Run_Restore(Restore_Name); + ret = PartitionManager.Run_Restore(Restore_Name); } else { operation_end(1, simulate); return -1; } } - operation_end(0, simulate); + if (ret == false) + ret = 1; // 1 for failure + else + ret = 0; // 0 for success + operation_end(ret, simulate); return 0; } if (function == "fixpermissions") @@ -1048,6 +1062,25 @@ LOGE("TODO: Implement ORS support\n"); operation_end(op_status, simulate); return 0; } + if (function == "adbsideload") + { + int ret = 0; + + operation_start("Sideload"); + if (simulate) { + simulate_progress_bar(); + } else { + int wipe_cache = 0; + ui_print("Starting ADB sideload feature...\n"); + __system("touch /tmp/update.zip"); + ret = apply_from_adb(ui, &wipe_cache, "/tmp/last_install"); + LOGI("Result was: %i\n", ret); + if (ret != 0) + ret = 1; + } + operation_end(ret, simulate); + return 0; + } } else { diff --git a/gui/devices/800x1280/res/ui.xml b/gui/devices/800x1280/res/ui.xml index 94468d8c0..decfcad55 100755 --- a/gui/devices/800x1280/res/ui.xml +++ b/gui/devices/800x1280/res/ui.xml @@ -2540,6 +2540,21 @@ terminalfolder + + + + ADB Sideload + + + tw_action=adbsideload + tw_action_text1=ADB Sideload + tw_action_text2=Usage: adb sideload filename.zip + tw_complete_text1=ADB Sideload Complete + tw_slider_text=Swipe to Wipe + action_page + + + diff --git a/partition.cpp b/partition.cpp index f4fa0d86e..521722774 100644 --- a/partition.cpp +++ b/partition.cpp @@ -37,11 +37,11 @@ #include "common.h" #include "partitions.hpp" #include "data.hpp" +#include "twrp-functions.hpp" extern "C" { #include "mtdutils/mtdutils.h" #include "mtdutils/mounts.h" - #include "extra-functions.h" - int __system(const char *command); + #include "makelist.h" } TWPartition::TWPartition(void) { @@ -333,7 +333,7 @@ bool TWPartition::Is_Image(string File_System) { } bool TWPartition::Make_Dir(string Path, bool Display_Error) { - if (!Path_Exists(Path)) { + if (!TWFunc::Path_Exists(Path)) { if (mkdir(Path.c_str(), 0777) == -1) { if (Display_Error) LOGE("Can not create '%s' folder.\n", Path.c_str()); @@ -479,7 +479,7 @@ bool TWPartition::Get_Size_Via_df(bool Display_Error) { min_len = Actual_Block_Device.size() + 2; sprintf(command, "df %s > /tmp/dfoutput.txt", Mount_Point.c_str()); - __system(command); + system(command); fp = fopen("/tmp/dfoutput.txt", "rt"); if (fp == NULL) { LOGI("Unable to open /tmp/dfoutput.txt.\n"); @@ -518,46 +518,6 @@ bool TWPartition::Get_Size_Via_df(bool Display_Error) { return true; } -unsigned long long TWPartition::Get_Folder_Size(string Path, bool Display_Error) { - DIR* d; - struct dirent* de; - struct stat st; - char path2[1024], filename[1024]; - unsigned long long dusize = 0; - - // Make a copy of path in case the data in the pointer gets overwritten later - strcpy(path2, Path.c_str()); - - d = opendir(path2); - if (d == NULL) - { - LOGE("error opening '%s'\n", path2); - return 0; - } - - while ((de = readdir(d)) != NULL) - { - if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) - { - strcpy(filename, path2); - strcat(filename, "/"); - strcat(filename, de->d_name); - dusize += Get_Folder_Size(filename, Display_Error); - } - else if (de->d_type == DT_REG) - { - strcpy(filename, path2); - strcat(filename, "/"); - strcat(filename, de->d_name); - stat(filename, &st); - dusize += (unsigned long long)(st.st_size); - } - } - closedir(d); - - return dusize; -} - bool TWPartition::Find_Partition_Size(void) { FILE* fp; char line[512]; @@ -590,16 +550,6 @@ bool TWPartition::Find_Partition_Size(void) { return false; } -bool TWPartition::Path_Exists(string Path) { - // Check to see if the Path exists - struct statfs st; - - if (statfs(Path.c_str(), &st) != 0) - return false; - else - return true; -} - void TWPartition::Flip_Block_Device(void) { string temp; @@ -655,7 +605,7 @@ bool TWPartition::Mount(bool Display_Error) { string Command; Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point; - __system(Command.c_str()); + system(Command.c_str()); } return true; } @@ -727,7 +677,38 @@ bool TWPartition::Backup(string backup_folder) { return false; } +bool TWPartition::Check_MD5(string restore_folder) { + string Full_Filename; + char split_filename[512]; + int index = 0; + + Full_Filename = restore_folder + "/" + Backup_FileName; + LOGI("Full_Filename: '%s'\n", Full_Filename.c_str()); + if (!TWFunc::Path_Exists(Full_Filename)) { + // This is a split archive, we presume + sprintf(split_filename, "%s%03i", Full_Filename.c_str(), index); + while (index < 1000 && TWFunc::Path_Exists(split_filename)) { + if (TWFunc::Check_MD5(split_filename) == 0) { + LOGE("MD5 failed to match on '%s'.\n", split_filename); + return false; + } + index++; + sprintf(split_filename, "%s%03i", Full_Filename.c_str(), index); + LOGI("Full_Filename: '%s'\n", Full_Filename.c_str()); + } + } else { + // Single file archive + if (TWFunc::Check_MD5(Full_Filename) == 0) { + LOGE("MD5 failed to match on '%s'.\n", split_filename); + return false; + } else + return true; + } + return false; +} + bool TWPartition::Restore(string restore_folder) { + ui_print("Restoring %s...\n", Display_Name.c_str()); if (Backup_Method == FILES) return Restore_Tar(restore_folder); else if (Backup_Method == DD) @@ -797,7 +778,7 @@ void TWPartition::Check_FS_Type() { Find_Actual_Block_Device(); blkCommand = "blkid " + Actual_Block_Device + " > /tmp/blkidoutput.txt"; - __system(blkCommand.c_str()); + system(blkCommand.c_str()); fp = fopen("/tmp/blkidoutput.txt", "rt"); while (fgets(blkOutput, sizeof(blkOutput), fp) != NULL) { @@ -847,7 +828,7 @@ void TWPartition::Check_FS_Type() { Current_File_System = arg; } } - __pclose(fp); + fclose(fp); return; } @@ -855,14 +836,14 @@ bool TWPartition::Wipe_EXT23() { if (!UnMount(true)) return false; - if (Path_Exists("/sbin/mke2fs")) { + if (TWFunc::Path_Exists("/sbin/mke2fs")) { char command[512]; ui_print("Formatting %s using mke2fs...\n", Display_Name.c_str()); Find_Actual_Block_Device(); sprintf(command, "mke2fs -t %s -m 0 %s", Current_File_System.c_str(), Actual_Block_Device.c_str()); LOGI("mke2fs command: %s\n", command); - if (__system(command) == 0) { + if (system(command) == 0) { ui_print("Done.\n"); return true; } else { @@ -879,7 +860,7 @@ bool TWPartition::Wipe_EXT4() { if (!UnMount(true)) return false; - if (Path_Exists("/sbin/make_ext4fs")) { + if (TWFunc::Path_Exists("/sbin/make_ext4fs")) { string Command; ui_print("Formatting %s using make_ext4fs...\n", Display_Name.c_str()); @@ -894,7 +875,7 @@ bool TWPartition::Wipe_EXT4() { } Command += " " + Actual_Block_Device; LOGI("make_ext4fs command: %s\n", Command.c_str()); - if (__system(Command.c_str()) == 0) { + if (system(Command.c_str()) == 0) { ui_print("Done.\n"); return true; } else { @@ -913,14 +894,14 @@ bool TWPartition::Wipe_FAT() { if (Backup_Name == "and-sec") // Don't format if it's android secure return Wipe_RMRF(); - if (Path_Exists("/sbin/mkdosfs")) { + if (TWFunc::Path_Exists("/sbin/mkdosfs")) { if (!UnMount(true)) return false; ui_print("Formatting %s using mkdosfs...\n", Display_Name.c_str()); Find_Actual_Block_Device(); sprintf(command,"mkdosfs %s", Actual_Block_Device.c_str()); // use mkdosfs to format it - if (__system(command) == 0) { + if (system(command) == 0) { ui_print("Done.\n"); return true; } else { @@ -981,7 +962,7 @@ bool TWPartition::Wipe_RMRF() { } LOGI("rm -rf command is: '%s'\n", cmd); - __system(cmd); + system(cmd); return true; } @@ -993,8 +974,8 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() { return false; ui_print("Wiping data without wiping /data/media ...\n"); - __system("rm -f /data/*"); - __system("rm -f /data/.*"); + system("rm -f /data/*"); + system("rm -f /data/.*"); DIR* d; d = opendir("/data"); @@ -1005,7 +986,7 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() { if (strcmp(de->d_name, "media") == 0) continue; sprintf(cmd, "rm -fr /data/%s", de->d_name); - __system(cmd); + system(cmd); } closedir(d); } @@ -1014,34 +995,142 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() { } bool TWPartition::Backup_Tar(string backup_folder) { - LOGI("STUB TWPartition::Backup_Tar, backup_folder: '%s'\n", backup_folder.c_str()); - return 1; + char back_name[255]; + string Full_FileName, Tar_Args, Command; + int use_compression; + + if (!Mount(true)) + return false; + + ui_print("Backing up %s...\n", Display_Name.c_str()); + + DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression); + if (use_compression) + Tar_Args = "-cz"; + else + Tar_Args = "-c"; + + sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str()); + Backup_FileName = back_name; + + Full_FileName = backup_folder + "/" + Backup_FileName; + if (Backup_Size > MAX_ARCHIVE_SIZE) { + // This backup needs to be split into multiple archives + LOGE("Multiple archive splitting is not implemented yet!\n"); + return false; + } else { + if (Has_Data_Media) + Command = "cd " + Mount_Point + " && tar " + Tar_Args + " ./ --exclude='media*' -f '" + Full_FileName + "'"; + else + Command = "cd " + Mount_Point + " && tar " + Tar_Args + " -f '" + Full_FileName + "' ./*"; + LOGI("Backup command: '%s'\n", Command.c_str()); + system(Command.c_str()); + } + return true; } bool TWPartition::Backup_DD(string backup_folder) { - LOGI("STUB TWPartition::Backup_DD, backup_folder: '%s'\n", backup_folder.c_str()); - return 1; + char back_name[255]; + string Full_FileName, Command; + int use_compression; + + ui_print("Backing up %s...\n", Display_Name.c_str()); + + sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str()); + Backup_FileName = back_name; + + Full_FileName = backup_folder + "/" + Backup_FileName; + + Command = "dd if=" + Actual_Block_Device + " of='" + Full_FileName + "'"; + LOGI("Backup command: '%s'\n", Command.c_str()); + system(Command.c_str()); + return true; } bool TWPartition::Backup_Dump_Image(string backup_folder) { - LOGI("STUB TWPartition::Backup_Dump_Image, backup_folder: '%s'\n", backup_folder.c_str()); - return 1; + char back_name[255]; + string Full_FileName, Command; + int use_compression; + + ui_print("Backing up %s...\n", Display_Name.c_str()); + + sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str()); + Backup_FileName = back_name; + + Full_FileName = backup_folder + "/" + Backup_FileName; + + Command = "dump_image " + MTD_Name + " '" + Full_FileName + "'"; + LOGI("Backup command: '%s'\n", Command.c_str()); + system(Command.c_str()); + return true; } bool TWPartition::Restore_Tar(string restore_folder) { - LOGI("STUB TWPartition::Restore_Tar, backup_folder: '%s'\n", restore_folder.c_str()); - return 1; + size_t first_period, second_period; + string Restore_File_System, Full_FileName, Command; + + LOGI("Restore filename is: %s\n", Backup_FileName.c_str()); + + // Parse backup filename to extract the file system before wiping + first_period = Backup_FileName.find("."); + if (first_period == string::npos) { + LOGE("Unable to find file system (first period).\n"); + return false; + } + Restore_File_System = Backup_FileName.substr(first_period + 1, Backup_FileName.size() - first_period - 1); + second_period = Restore_File_System.find("."); + if (second_period == string::npos) { + LOGE("Unable to find file system (second period).\n"); + return false; + } + Restore_File_System.resize(second_period); + LOGI("Restore file system is: '%s'.\n", Restore_File_System.c_str()); + Current_File_System = Restore_File_System; + ui_print("Wiping %s...\n", Display_Name.c_str()); + if (!Wipe()) + return false; + + if (!Mount(true)) + return false; + + Full_FileName = restore_folder + "/" + Backup_FileName; + ui_print("Restoring %s...\n", Display_Name.c_str()); + if (!TWFunc::Path_Exists(Full_FileName)) { + // This backup is multiple archives + LOGE("Multiple archive not implemented yet.\n"); + return false; + } else { + Command = "cd " + Mount_Point + " && tar -xf '" + Full_FileName + "'"; + LOGI("Restore command: '%s'\n", Command.c_str()); + system(Command.c_str()); + } + return true; } bool TWPartition::Restore_DD(string restore_folder) { - LOGI("STUB TWPartition::Restore_DD, backup_folder: '%s'\n", restore_folder.c_str()); - return 1; + string Full_FileName, Command; + + ui_print("Restoring %s...\n", Display_Name.c_str()); + Full_FileName = restore_folder + "/" + Backup_FileName; + Command = "dd bs=4096 if='" + Full_FileName + "' of=" + Actual_Block_Device; + LOGI("Restore command: '%s'\n", Command.c_str()); + system(Command.c_str()); + return true; } bool TWPartition::Restore_Flash_Image(string restore_folder) { - LOGI("STUB TWPartition::Restore_Flash_Image, backup_folder: '%s'\n", restore_folder.c_str()); - // might erase image first just to ensure that it flashes - return 1; + string Full_FileName, Command; + + ui_print("Restoring %s...\n", Display_Name.c_str()); + Full_FileName = restore_folder + "/" + Backup_FileName; + // Sometimes flash image doesn't like to flash due to the first 2KB matching, so we erase first to ensure that it flashes + Command = "erase_image " + MTD_Name; + LOGI("Erase command: '%s'\n", Command.c_str()); + system(Command.c_str()); + Command = "flash_image " + MTD_Name + " '" + Full_FileName + "'"; + LOGI("Restore command: '%s'\n", Command.c_str()); + system(Command.c_str()); + return true; } bool TWPartition::Update_Size(bool Display_Error) { @@ -1064,7 +1153,8 @@ bool TWPartition::Update_Size(bool Display_Error) { if (Has_Data_Media) { if (Mount(Display_Error)) { unsigned long long data_media_used, actual_data; - data_media_used = Get_Folder_Size("/data/media", Display_Error); + Used = TWFunc::Get_Folder_Size("/data", Display_Error); + data_media_used = TWFunc::Get_Folder_Size("/data/media", Display_Error); actual_data = Used - data_media_used; Backup_Size = actual_data; int bak = (int)(Backup_Size / 1048576LLU); @@ -1082,12 +1172,12 @@ bool TWPartition::Update_Size(bool Display_Error) { void TWPartition::Find_Actual_Block_Device(void) { if (Is_Decrypted) { Actual_Block_Device = Decrypted_Block_Device; - if (Path_Exists(Primary_Block_Device)) + if (TWFunc::Path_Exists(Primary_Block_Device)) Is_Present = true; - } else if (Path_Exists(Primary_Block_Device)) { + } else if (TWFunc::Path_Exists(Primary_Block_Device)) { Is_Present = true; Actual_Block_Device = Primary_Block_Device; - } else if (!Alternate_Block_Device.empty() && Path_Exists(Alternate_Block_Device)) { + } else if (!Alternate_Block_Device.empty() && TWFunc::Path_Exists(Alternate_Block_Device)) { Flip_Block_Device(); Actual_Block_Device = Primary_Block_Device; Is_Present = true; @@ -1102,10 +1192,10 @@ void TWPartition::Recreate_Media_Folder(void) { LOGE("Unable to recreate /data/media folder.\n"); } else { LOGI("Recreating /data/media folder.\n"); - __system("cd /data && mkdir media && chmod 755 media"); + system("cd /data && mkdir media && chmod 755 media"); Command = "umount " + Symlink_Mount_Point; - __system(Command.c_str()); + system(Command.c_str()); Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point; - __system(Command.c_str()); + system(Command.c_str()); } -} \ No newline at end of file +} diff --git a/partitionmanager.cpp b/partitionmanager.cpp index 7ff5e8e05..a16678307 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -117,6 +117,9 @@ int TWPartitionManager::Mount_By_Path(string Path, bool Display_Error) { bool found = false; string Local_Path = TWFunc::Get_Root_Path(Path); + if (Local_Path == "/tmp") + return true; + // Iterate through all partitions for (iter = Partitions.begin(); iter != Partitions.end(); iter++) { if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) { @@ -326,17 +329,443 @@ TWPartition* TWPartitionManager::Find_Partition_By_Name(string Name) { return NULL; } -int TWPartitionManager::Run_Backup(string Backup_Name) { - LOGI("STUB TWPartitionManager::Run_Backup, Backup_Name: '%s'\n", Backup_Name.c_str()); - return 1; +bool TWPartitionManager::Make_MD5(bool generate_md5, string Backup_Folder, string Backup_Filename) +{ + char command[512]; + string Full_File = Backup_Folder + Backup_Filename; + + if (!generate_md5) { + LOGI("MD5 disabled\n"); + return true; + } + + ui_print(" * Generating md5...\n"); + + if (TWFunc::Path_Exists(Full_File)) { + sprintf(command, "cd '%s' && md5sum %s > %s.md5",Backup_Folder.c_str(), Backup_Filename.c_str(), Backup_Filename.c_str()); + LOGI("MD5 command is: '%s'\n", command); + if (system(command) == 0) { + ui_print("....MD5 Created.\n"); + return true; + } else { + ui_print("....MD5 Error.\n"); + return false; + } + } else { + char filename[512]; + int index = 0; + + sprintf(filename, "%s%03i", Full_File.c_str(), index); + while (TWFunc::Path_Exists(filename)) { + sprintf(command, "cd '%s' && md5sum %s%03i > %s%03i.md5",Backup_Folder.c_str(), Backup_Filename.c_str(), index, Backup_Filename.c_str(), index); + LOGI("MD5 command is: '%s'\n", command); + if (system(command) == 0) { + ui_print("....MD5 Created.\n"); + } else { + ui_print("....MD5 Error.\n"); + return false; + } + index++; + } + if (index == 0) { + LOGE("Backup file: '%s' not found!\n", filename); + return false; + } + } + return true; +} + +bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folder, bool generate_md5, unsigned long long* img_bytes_remaining, unsigned long long* file_bytes_remaining, unsigned long *img_time, unsigned long *file_time) { + time_t start, stop; + + if (Part == NULL) + return true; + + time(&start); + + if (Part->Backup(Backup_Folder)) { + time(&stop); + if (Part->Backup_Method == 1) { + *file_bytes_remaining -= Part->Backup_Size; + *file_time += (int) difftime(stop, start); + } else { + *img_bytes_remaining -= Part->Backup_Size; + *img_time += (int) difftime(stop, start); + } + return Make_MD5(generate_md5, Backup_Folder, Part->Backup_FileName); + } else { + return false; + } +} + +int TWPartitionManager::Run_Backup(void) { + int check, do_md5, partition_count = 0; + string Backup_Folder, Backup_Name, Full_Backup_Path; + unsigned long long total_bytes = 0, file_bytes = 0, img_bytes = 0, free_space = 0, img_bytes_remaining, file_bytes_remaining; + unsigned long img_time = 0, file_time = 0; + TWPartition* backup_sys = NULL; + TWPartition* backup_data = NULL; + TWPartition* backup_cache = NULL; + TWPartition* backup_recovery = NULL; + TWPartition* backup_boot = NULL; + TWPartition* backup_andsec = NULL; + TWPartition* backup_sdext = NULL; + TWPartition* backup_sp1 = NULL; + TWPartition* backup_sp2 = NULL; + TWPartition* backup_sp3 = NULL; + TWPartition* storage = NULL; + struct tm *t; + time_t start, stop, seconds, total_start, total_stop; + seconds = time(0); + t = localtime(&seconds); + + time(&total_start); + + Update_System_Details(); + + if (!Mount_Current_Storage(true)) + return false; + + DataManager::GetValue(TW_SKIP_MD5_GENERATE_VAR, do_md5); + if (do_md5 != 0) { + LOGI("MD5 creation enabled.\n"); + do_md5 = true; + } + DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Folder); + DataManager::GetValue(TW_BACKUP_NAME, Backup_Name); + if (Backup_Name == "(Current Date)" || Backup_Name == "0") { + char timestamp[255]; + sprintf(timestamp,"%04d-%02d-%02d--%02d-%02d-%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); + Backup_Name = timestamp; + } + LOGI("Backup Name is: '%s'\n", Backup_Name.c_str()); + Full_Backup_Path = Backup_Folder + "/" + Backup_Name + "/"; + LOGI("Full_Backup_Path is: '%s'\n", Full_Backup_Path.c_str()); + + ui_print("\n[BACKUP STARTED]\n"); + ui_print(" * Backup Folder: %s\n", Full_Backup_Path.c_str()); + if (!TWFunc::Recursive_Mkdir(Full_Backup_Path)) { + LOGE("Failed to make backup folder.\n"); + return false; + } + + LOGI("Calculating backup details...\n"); + DataManager::GetValue(TW_BACKUP_SYSTEM_VAR, check); + if (check) { + backup_sys = Find_Partition_By_Path("/system"); + if (backup_sys != NULL) { + partition_count++; + if (backup_sys->Backup_Method == 1) + file_bytes += backup_sys->Backup_Size; + else + img_bytes += backup_sys->Backup_Size; + } else { + LOGE("Unable to locate system partition.\n"); + return false; + } + } + DataManager::GetValue(TW_BACKUP_DATA_VAR, check); + if (check) { + backup_data = Find_Partition_By_Path("/data"); + if (backup_data != NULL) { + partition_count++; + if (backup_data->Backup_Method == 1) + file_bytes += backup_data->Backup_Size; + else + img_bytes += backup_data->Backup_Size; + } else { + LOGE("Unable to locate data partition.\n"); + return false; + } + } + DataManager::GetValue(TW_BACKUP_CACHE_VAR, check); + if (check) { + backup_cache = Find_Partition_By_Path("/cache"); + if (backup_cache != NULL) { + partition_count++; + if (backup_cache->Backup_Method == 1) + file_bytes += backup_cache->Backup_Size; + else + img_bytes += backup_cache->Backup_Size; + } else { + LOGE("Unable to locate cache partition.\n"); + return false; + } + } + DataManager::GetValue(TW_BACKUP_RECOVERY_VAR, check); + if (check) { + backup_recovery = Find_Partition_By_Path("/recovery"); + if (backup_recovery != NULL) { + partition_count++; + if (backup_recovery->Backup_Method == 1) + file_bytes += backup_recovery->Backup_Size; + else + img_bytes += backup_recovery->Backup_Size; + } else { + LOGE("Unable to locate recovery partition.\n"); + return false; + } + } + DataManager::GetValue(TW_BACKUP_BOOT_VAR, check); + if (check) { + backup_boot = Find_Partition_By_Path("/boot"); + if (backup_boot != NULL) { + partition_count++; + if (backup_boot->Backup_Method == 1) + file_bytes += backup_boot->Backup_Size; + else + img_bytes += backup_boot->Backup_Size; + } else { + LOGE("Unable to locate boot partition.\n"); + return false; + } + } + DataManager::GetValue(TW_BACKUP_ANDSEC_VAR, check); + if (check) { + backup_andsec = Find_Partition_By_Path("/and-sec"); + if (backup_andsec != NULL) { + partition_count++; + if (backup_andsec->Backup_Method == 1) + file_bytes += backup_andsec->Backup_Size; + else + img_bytes += backup_andsec->Backup_Size; + } else { + LOGE("Unable to locate android secure partition.\n"); + return false; + } + } + DataManager::GetValue(TW_BACKUP_SDEXT_VAR, check); + if (check) { + backup_sdext = Find_Partition_By_Path("/sd-ext"); + if (backup_sdext != NULL) { + partition_count++; + if (backup_sdext->Backup_Method == 1) + file_bytes += backup_sdext->Backup_Size; + else + img_bytes += backup_sdext->Backup_Size; + } else { + LOGE("Unable to locate sd-ext partition.\n"); + return false; + } + } +#ifdef SP1_NAME + DataManager::GetValue(TW_BACKUP_SP1_VAR, check); + if (check) { + backup_sp1 = Find_Partition_By_Path(SP1_NAME); + if (backup_sp1 != NULL) { + partition_count++; + if (backup_sp1->Backup_Method == 1) + file_bytes += backup_sp1->Backup_Size; + else + img_bytes += backup_sp1->Backup_Size; + } else { + LOGE("Unable to locate %s partition.\n", SP1_NAME); + return false; + } + } +#endif +#ifdef SP2_NAME + DataManager::GetValue(TW_BACKUP_SP2_VAR, check); + if (check) { + backup_sp2 = Find_Partition_By_Path(SP2_NAME); + if (backup_sp2 != NULL) { + partition_count++; + if (backup_sp2->Backup_Method == 1) + file_bytes += backup_sp2->Backup_Size; + else + img_bytes += backup_sp2->Backup_Size; + } else { + LOGE("Unable to locate %s partition.\n", SP2_NAME); + return false; + } + } +#endif +#ifdef SP3_NAME + DataManager::GetValue(TW_BACKUP_SP3_VAR, check); + if (check) { + backup_sp3 = Find_Partition_By_Path(SP3_NAME); + if (backup_sp3 != NULL) { + partition_count++; + if (backup_sp3->Backup_Method == 1) + file_bytes += backup_sp3->Backup_Size; + else + img_bytes += backup_sp3->Backup_Size; + } else { + LOGE("Unable to locate %s partition.\n", SP3_NAME); + return false; + } + } +#endif + + if (partition_count == 0) { + ui_print("No partitions selected for backup.\n"); + return false; + } + total_bytes = file_bytes + img_bytes; + ui_print(" * Total number of partitions to back up: %d\n", partition_count); + ui_print(" * Total size of all data: %lluMB\n", total_bytes / 1024 / 1024); + storage = Find_Partition_By_Path(DataManager::GetCurrentStoragePath()); + if (storage != NULL) { + free_space = storage->Free; + ui_print(" * Available space: %lluMB\n", free_space / 1024 / 1024); + } else { + LOGE("Unable to locate storage device.\n"); + return false; + } + if (free_space + (32 * 1024 * 1024) < total_bytes) { + // We require an extra 32MB just in case + LOGE("Not enough free space on storage.\n"); + return false; + } + img_bytes_remaining = img_bytes; + file_bytes_remaining = file_bytes; + + if (!Backup_Partition(backup_sys, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_data, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_cache, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_recovery, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_boot, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_andsec, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_sdext, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_sp1, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_sp2, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + if (!Backup_Partition(backup_sp3, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time)) + return false; + + // Average BPS + if (img_time == 0) + img_time = 1; + if (file_time == 0) + file_time = 1; + unsigned long int img_bps = img_bytes / img_time; + unsigned long int file_bps = file_bytes / file_time; + + ui_print("Average backup rate for file systems: %lu MB/sec\n", (file_bps / (1024 * 1024))); + ui_print("Average backup rate for imaged drives: %lu MB/sec\n", (img_bps / (1024 * 1024))); + + time(&total_stop); + int total_time = (int) difftime(total_stop, total_start); + unsigned long long actual_backup_size = TWFunc::Get_Folder_Size(Full_Backup_Path, true); + actual_backup_size /= (1024LLU * 1024LLU); + + ui_print("[%llu MB TOTAL BACKED UP]\n", actual_backup_size); + Update_System_Details(); + ui_print("[BACKUP COMPLETED IN %d SECONDS]\n\n", total_time); // the end + return true; } int TWPartitionManager::Run_Restore(string Restore_Name) { - int check; + int check, restore_sys, restore_data, restore_cache, restore_boot, restore_andsec, restore_sdext, restore_sp1, restore_sp2, restore_sp3; TWPartition* Part; -LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); - DataManager::GetValue(TW_RESTORE_SYSTEM_VAR, check); + + DataManager::GetValue(TW_SKIP_MD5_CHECK_VAR, check); + DataManager::GetValue(TW_RESTORE_SYSTEM_VAR, restore_sys); + DataManager::GetValue(TW_RESTORE_DATA_VAR, restore_data); + DataManager::GetValue(TW_RESTORE_CACHE_VAR, restore_cache); + DataManager::GetValue(TW_RESTORE_BOOT_VAR, restore_boot); + DataManager::GetValue(TW_RESTORE_ANDSEC_VAR, restore_andsec); + DataManager::GetValue(TW_RESTORE_SDEXT_VAR, restore_sdext); + DataManager::GetValue(TW_RESTORE_SP1_VAR, restore_sp1); + DataManager::GetValue(TW_RESTORE_SP2_VAR, restore_sp2); + DataManager::GetValue(TW_RESTORE_SP3_VAR, restore_sp3); + if (check > 0) { + // Check MD5 files first before restoring to ensure that all of them match before starting a restore + if (restore_sys > 0) { + Part = Find_Partition_By_Path("/system"); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate system partition.\n"); + } + + if (restore_data > 0) { + Part = Find_Partition_By_Path("/data"); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate data partition.\n"); + } + + if (restore_cache > 0) { + Part = Find_Partition_By_Path("/cache"); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate cache partition.\n"); + } + + if (restore_boot > 0) { + Part = Find_Partition_By_Path("/boot"); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate boot partition.\n"); + } + + if (restore_andsec > 0) { + Part = Find_Partition_By_Path("/.android_secure"); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate android_secure partition.\n"); + } + + if (restore_sdext > 0) { + Part = Find_Partition_By_Path("/sd-ext"); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate sd-ext partition.\n"); + } +#ifdef SP1_NAME + if (restore_sp1 > 0) { + Part = Find_Partition_By_Path(TWFunc::Get_Root_Path(SP1_NAME)); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate %s partition.\n", SP1_NAME); + } +#endif +#ifdef SP2_NAME + if (restore_sp2 > 0) { + Part = Find_Partition_By_Path(TWFunc::Get_Root_Path(SP2_NAME)); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate %s partition.\n", SP2_NAME); + } +#endif +#ifdef SP3_NAME + if (restore_sp3 > 0) { + Part = Find_Partition_By_Path(TWFunc::Get_Root_Path(SP3_NAME)); + if (Part) { + if (!Part->Check_MD5(Restore_Name)) + return false; + } else + LOGE("Restore: Unable to locate %s partition.\n", SP3_NAME); + } +#endif + } + + if (restore_sys > 0) { Part = Find_Partition_By_Path("/system"); if (Part) { if (!Part->Restore(Restore_Name)) @@ -344,8 +773,8 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } else LOGE("Restore: Unable to locate system partition.\n"); } - DataManager::GetValue(TW_RESTORE_DATA_VAR, check); - if (check > 0) { + + if (restore_data > 0) { Part = Find_Partition_By_Path("/data"); if (Part) { if (!Part->Restore(Restore_Name)) @@ -353,8 +782,8 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } else LOGE("Restore: Unable to locate data partition.\n"); } - DataManager::GetValue(TW_RESTORE_CACHE_VAR, check); - if (check > 0) { + + if (restore_cache > 0) { Part = Find_Partition_By_Path("/cache"); if (Part) { if (!Part->Restore(Restore_Name)) @@ -362,8 +791,8 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } else LOGE("Restore: Unable to locate cache partition.\n"); } - DataManager::GetValue(TW_RESTORE_BOOT_VAR, check); - if (check > 0) { + + if (restore_boot > 0) { Part = Find_Partition_By_Path("/boot"); if (Part) { if (!Part->Restore(Restore_Name)) @@ -371,8 +800,8 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } else LOGE("Restore: Unable to locate boot partition.\n"); } - DataManager::GetValue(TW_RESTORE_ANDSEC_VAR, check); - if (check > 0) { + + if (restore_andsec > 0) { Part = Find_Partition_By_Path("/.android_secure"); if (Part) { if (!Part->Restore(Restore_Name)) @@ -380,8 +809,8 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } else LOGE("Restore: Unable to locate android_secure partition.\n"); } - DataManager::GetValue(TW_RESTORE_SDEXT_VAR, check); - if (check > 0) { + + if (restore_sdext > 0) { Part = Find_Partition_By_Path("/sd-ext"); if (Part) { if (!Part->Restore(Restore_Name)) @@ -390,8 +819,7 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); LOGE("Restore: Unable to locate sd-ext partition.\n"); } #ifdef SP1_NAME - DataManager::GetValue(TW_RESTORE_SP1_VAR, check); - if (check > 0) { + if (restore_sp1 > 0) { Part = Find_Partition_By_Path(TWFunc::Get_Root_Path(SP1_NAME)); if (Part) { if (!Part->Restore(Restore_Name)) @@ -401,8 +829,7 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } #endif #ifdef SP2_NAME - DataManager::GetValue(TW_RESTORE_SP2_VAR, check); - if (check > 0) { + if (restore_sp2 > 0) { Part = Find_Partition_By_Path(TWFunc::Get_Root_Path(SP2_NAME)); if (Part) { if (!Part->Restore(Restore_Name)) @@ -412,8 +839,7 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); } #endif #ifdef SP3_NAME - DataManager::GetValue(TW_RESTORE_SP3_VAR, check); - if (check > 0) { + if (restore_sp3 > 0) { Part = Find_Partition_By_Path(TWFunc::Get_Root_Path(SP3_NAME)); if (Part) { if (!Part->Restore(Restore_Name)) @@ -422,6 +848,7 @@ LOGE("TO DO: Check MD5 of all partitions before restoring ANY partitions.\n"); LOGE("Restore: Unable to locate %s partition.\n", SP3_NAME); } #endif + Update_System_Details(); return true; } diff --git a/partitions.hpp b/partitions.hpp index 5b7dc6df9..36138d102 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -51,6 +51,7 @@ public: virtual bool UnMount(bool Display_Error); // Unmounts the partition if it is mounted virtual bool Wipe(); // Wipes the partition virtual bool Backup(string backup_folder); // Backs up the partition to the folder specified + virtual bool Check_MD5(string restore_folder); // Checks MD5 of a backup virtual bool Restore(string restore_folder); // Restores the partition using the backup folder provided virtual string Backup_Method_By_Name(); // Returns a string of the backup method for human readable output virtual bool Decrypt(string Password); // Decrypts the partition, return 0 for failure and -1 for success @@ -106,7 +107,6 @@ private: bool Is_Image(string File_System); // Checks to see if the file system given is considered an image void Setup_File_System(bool Display_Error); // Sets defaults for a file system partition void Setup_Image(bool Display_Error); // Sets defaults for an image partition - bool Path_Exists(string Path); // Checks to see if the Path exists in the file system void Find_Real_Block_Device(string& Block_Device, bool Display_Error); // Checks the block device given and follows symlinks until it gets to the real block device bool Find_Partition_Size(); // Finds the partition size from /proc/partitions unsigned long long Get_Size_Via_du(string Path, bool Display_Error); // Uses du to get sizes @@ -125,7 +125,6 @@ private: bool Restore_Flash_Image(string restore_folder); // Restore using flash_image for MTD memory types bool Get_Size_Via_statfs(bool Display_Error); // Get Partition size, used, and free space using statfs bool Get_Size_Via_df(bool Display_Error); // Get Partition size, used, and free space using df command - unsigned long long Get_Folder_Size(string Path, bool Display_Error); // Gets the size of the files in a folder and all of its subfolders bool Make_Dir(string Path, bool Display_Error); // Creates a directory if it doesn't already exist bool Find_MTD_Block_Device(string MTD_Name); // Finds the mtd block device based on the name from the fstab @@ -155,7 +154,7 @@ public: TWPartition* Find_Partition_By_Path(string Path); // Returns a pointer to a partition based on path TWPartition* Find_Partition_By_Block(string Block); // Returns a pointer to a partition based on block device TWPartition* Find_Partition_By_Name(string Block); // Returns a pointer to a partition based on name - virtual int Run_Backup(string Backup_Name); // Initiates a backup in the current storage + virtual int Run_Backup(); // Initiates a backup in the current storage virtual int Run_Restore(string Restore_Name); // Restores a backup virtual void Set_Restore_Files(string Restore_Name); // Used to gather a list of available backup partitions for the user to select for a restore virtual int Wipe_By_Path(string Path); // Wipes a partition based on path @@ -172,6 +171,10 @@ public: virtual int Decrypt_Device(string Password); // Attempt to decrypt any encrypted partitions virtual int Fix_Permissions(); // Fixes permissions in /system and /data +private: + bool Make_MD5(bool generate_md5, string Backup_Folder, string Backup_Filename); // Generates an MD5 after a backup is made + bool Backup_Partition(TWPartition* Part, string Backup_Folder, bool generate_md5, unsigned long long* img_bytes_remaining, unsigned long long* file_bytes_remaining, unsigned long *img_time, unsigned long *file_time); + private: std::vector Partitions; // Vector list of all partitions }; diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk index 17e2d4aca..650a6a057 100644 --- a/prebuilt/Android.mk +++ b/prebuilt/Android.mk @@ -39,6 +39,7 @@ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbmlutils.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libflashutils.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libstlport.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmincrypt.so +RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext4_utils.so ifeq ($(TW_INCLUDE_BLOBPACK), true) RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/blobpack endif diff --git a/twrp-functions.cpp b/twrp-functions.cpp index ccf0540a1..b393f2b03 100644 --- a/twrp-functions.cpp +++ b/twrp-functions.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "twrp-functions.hpp" #include "partitions.hpp" @@ -162,3 +163,73 @@ void TWFunc::htc_dumlock_reflash_recovery_to_boot(void) { __system("htcdumlock recovery noreboot"); ui_print("Recovery is flashed to boot.\n"); } + +int TWFunc::Recursive_Mkdir(string Path) { + string pathCpy = Path; + string wholePath; + size_t pos = pathCpy.find("/", 2); + + while (pos != string::npos) + { + wholePath = pathCpy.substr(0, pos); + if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST) { + LOGE("Unable to create folder: %s (errno=%d)\n", wholePath.c_str(), errno); + return false; + } + + pos = pathCpy.find("/", pos + 1); + } + if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST) + return false; + return true; +} + +unsigned long long TWFunc::Get_Folder_Size(string Path, bool Display_Error) { + DIR* d; + struct dirent* de; + struct stat st; + char path2[1024], filename[1024]; + unsigned long long dusize = 0; + + // Make a copy of path in case the data in the pointer gets overwritten later + strcpy(path2, Path.c_str()); + + d = opendir(path2); + if (d == NULL) + { + LOGE("error opening '%s'\n", path2); + return 0; + } + + while ((de = readdir(d)) != NULL) + { + if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) + { + strcpy(filename, path2); + strcat(filename, "/"); + strcat(filename, de->d_name); + dusize += Get_Folder_Size(filename, Display_Error); + } + else if (de->d_type == DT_REG) + { + strcpy(filename, path2); + strcat(filename, "/"); + strcat(filename, de->d_name); + stat(filename, &st); + dusize += (unsigned long long)(st.st_size); + } + } + closedir(d); + + return dusize; +} + +bool TWFunc::Path_Exists(string Path) { + // Check to see if the Path exists + struct statfs st; + + if (statfs(Path.c_str(), &st) != 0) + return false; + else + return true; +} \ No newline at end of file diff --git a/twrp-functions.hpp b/twrp-functions.hpp index 19f8eec66..b619239b8 100644 --- a/twrp-functions.hpp +++ b/twrp-functions.hpp @@ -10,13 +10,16 @@ class TWFunc { public: static int Check_MD5(string File); - static string Get_Root_Path(string Path); // Trims any trailing folders or filenames from the path, also adds a leading / if not present - static string Get_Path(string Path); // Trims everything after the last / in the string - static string Get_Filename(string Path); // Trims the path off of a filename + static string Get_Root_Path(string Path); // Trims any trailing folders or filenames from the path, also adds a leading / if not present + static string Get_Path(string Path); // Trims everything after the last / in the string + static string Get_Filename(string Path); // Trims the path off of a filename - static void install_htc_dumlock(void); // Installs HTC Dumlock - static void htc_dumlock_restore_original_boot(void); // Restores the backup of boot from HTC Dumlock - static void htc_dumlock_reflash_recovery_to_boot(void); // Reflashes the current recovery to boot + static void install_htc_dumlock(void); // Installs HTC Dumlock + static void htc_dumlock_restore_original_boot(void); // Restores the backup of boot from HTC Dumlock + static void htc_dumlock_reflash_recovery_to_boot(void); // Reflashes the current recovery to boot + static int Recursive_Mkdir(string Path); // Recursively makes the entire path + static unsigned long long Get_Folder_Size(string Path, bool Display_Error); // Gets the size of a folder and all of its subfolders using dirent and stat + static bool Path_Exists(string Path); // Returns true if the path exists }; -- cgit v1.2.3