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.
diff --git a/Android.mk b/Android.mk
index 304e607..caa6b09 100644
--- a/Android.mk
+++ b/Android.mk
@@ -66,14 +66,14 @@
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 a226ea5..12bce1c 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 @@
}
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 b050feb..3d6c9eb 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 @@
#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 @@
#include "rapidxml.hpp"
#include "objects.hpp"
+extern RecoveryUI* ui;
+
void curtainClose(void);
GUIAction::GUIAction(xml_node<>* node)
@@ -733,6 +740,7 @@
if (function == "nandroid")
{
operation_start("Nandroid");
+ int ret = 0;
if (simulate) {
DataManager::SetValue("tw_partition", "Simulation");
@@ -741,21 +749,27 @@
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 @@
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 94468d8..decfcad 100755
--- a/gui/devices/800x1280/res/ui.xml
+++ b/gui/devices/800x1280/res/ui.xml
@@ -2541,6 +2541,21 @@
</object>
<object type="button">
+ <placement x="%col1_x%" y="%row4_y%" />
+ <font resource="font" color="%button_text_color%" />
+ <text>ADB Sideload</text>
+ <image resource="main_button" />
+ <actions>
+ <action function="set">tw_action=adbsideload</action>
+ <action function="set">tw_action_text1=ADB Sideload</action>
+ <action function="set">tw_action_text2=Usage: adb sideload filename.zip</action>
+ <action function="set">tw_complete_text1=ADB Sideload Complete</action>
+ <action function="set">tw_slider_text=Swipe to Wipe</action>
+ <action function="page">action_page</action>
+ </actions>
+ </object>
+
+ <object type="button">
<condition var1="tw_show_dumlock" var2="1" />
<placement x="%col2_x%" y="%row4_y%" />
<font resource="font" color="%button_text_color%" />
diff --git a/partition.cpp b/partition.cpp
index f4fa0d8..5217227 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::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 @@
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 @@
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 @@
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 @@
string Command;
Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point;
- __system(Command.c_str());
+ system(Command.c_str());
}
return true;
}
@@ -727,7 +677,38 @@
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 @@
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 @@
Current_File_System = arg;
}
}
- __pclose(fp);
+ fclose(fp);
return;
}
@@ -855,14 +836,14 @@
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 @@
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 @@
}
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 @@
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 @@
}
LOGI("rm -rf command is: '%s'\n", cmd);
- __system(cmd);
+ system(cmd);
return true;
}
@@ -993,8 +974,8 @@
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 @@
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::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 @@
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 @@
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 @@
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 7ff5e8e..a166783 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -117,6 +117,9 @@
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 @@
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 @@
} 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 @@
} 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 @@
} 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 @@
} 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 @@
} 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("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 @@
}
#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 @@
}
#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("Restore: Unable to locate %s partition.\n", SP3_NAME);
}
#endif
+ Update_System_Details();
return true;
}
diff --git a/partitions.hpp b/partitions.hpp
index 5b7dc6d..36138d1 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -51,6 +51,7 @@
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 @@
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 @@
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 @@
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
@@ -173,6 +172,10 @@
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<TWPartition*> Partitions; // Vector list of all partitions
};
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 17e2d4a..650a6a0 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -39,6 +39,7 @@
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 ccf0540..b393f2b 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -7,6 +7,7 @@
#include <vector>
#include <dirent.h>
#include <time.h>
+#include <errno.h>
#include "twrp-functions.hpp"
#include "partitions.hpp"
@@ -162,3 +163,73 @@
__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 19f8eec..b619239 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -10,13 +10,16 @@
{
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
};