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
 
 };