Improve storage size code, mount, unmount

Add flag parsing from recovery.fstab
diff --git a/data.cpp b/data.cpp
index 92e2e41..2968435 100644
--- a/data.cpp
+++ b/data.cpp
@@ -296,14 +296,8 @@
 		if (GetIntValue(TW_HAS_DUAL_STORAGE) == 1) {
 			if (value == 0) {
 				str = GetStrValue(TW_INTERNAL_PATH);
-				if (GetIntValue(TW_HAS_DATA_MEDIA) == 1) {
-					LOGE("TODO: Fix storage size code!\n"); //SetValue(TW_STORAGE_FREE_SIZE, (int)((dat.sze - dat.used) / 1048576LLU));
-				} else {
-					LOGE("TODO: Fix storage size code!\n"); //SetValue(TW_STORAGE_FREE_SIZE, (int)((sdcint.sze - sdcint.used) / 1048576LLU));
-				}
 			} else {
 				str = GetStrValue(TW_EXTERNAL_PATH);
-				LOGE("TODO: Fix storage size code!\n"); //SetValue(TW_STORAGE_FREE_SIZE, (int)((sdcext.sze - sdcext.used) / 1048576LLU));
 			}
 		} else if (GetIntValue(TW_HAS_INTERNAL) == 1)
 			str = GetStrValue(TW_INTERNAL_PATH);
diff --git a/etc/init.rc b/etc/init.rc
index a6f2f90..e26027a 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -10,7 +10,6 @@
 
     symlink /system/etc /etc
 
-    mkdir /emmc
     mkdir /system
     mkdir /data
     mkdir /cache
diff --git a/gui/action.cpp b/gui/action.cpp
index db4c9c4..aee5684 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -416,14 +416,11 @@
         {
             string cmd;
 			if (arg == "EXTERNAL")
-				cmd = "mount " + DataManager::GetStrValue(TW_EXTERNAL_MOUNT);
+				PartitionManager.Mount_By_Path(DataManager::GetStrValue(TW_EXTERNAL_MOUNT), true);
 			else if (arg == "INTERNAL")
-				cmd = "mount " + DataManager::GetStrValue(TW_INTERNAL_MOUNT);
+				PartitionManager.Mount_By_Path(DataManager::GetStrValue(TW_INTERNAL_MOUNT), true);
 			else
-				cmd = "mount " + arg;
-            __system(cmd.c_str());
-			if (arg == "/data" && DataManager::GetIntValue(TW_HAS_DATADATA) == 1)
-				__system("mount /datadata");
+				PartitionManager.Mount_By_Path(arg, true);
         } else
 			ui_print("Simulating actions...\n");
         return 0;
@@ -443,16 +440,11 @@
         {
             string cmd;
 			if (arg == "EXTERNAL")
-				cmd = "umount " + DataManager::GetStrValue(TW_EXTERNAL_MOUNT);
+				PartitionManager.UnMount_By_Path(DataManager::GetStrValue(TW_EXTERNAL_MOUNT), true);
 			else if (arg == "INTERNAL")
-				cmd = "umount " + DataManager::GetStrValue(TW_INTERNAL_MOUNT);
-			else if (DataManager::GetIntValue(TW_DONT_UNMOUNT_SYSTEM) == 1 && (arg == "system" || arg == "/system"))
-				return 0;
+				PartitionManager.UnMount_By_Path(DataManager::GetStrValue(TW_INTERNAL_MOUNT), true);
 			else
-				cmd = "umount " + arg;
-            __system(cmd.c_str());
-			if (arg == "/data" && DataManager::GetIntValue(TW_HAS_DATADATA) == 1)
-				__system("umount /datadata");
+				PartitionManager.UnMount_By_Path(arg, true);
         } else
 			ui_print("Simulating actions...\n");
         return 0;
@@ -549,7 +541,7 @@
 		} else if (arg == "external") {
 			DataManager::SetValue(TW_USE_EXTERNAL_STORAGE, 1);
 		}
-		if (PartitionManager.Mount_Settings_Storage(true)) {
+		if (PartitionManager.Mount_Current_Storage(true)) {
 			if (arg == "internal") {
 				// Save the current zip location to the external variable
 				DataManager::SetValue(TW_ZIP_EXTERNAL_VAR, DataManager::GetStrValue(TW_ZIP_LOCATION_VAR));
diff --git a/partition.cpp b/partition.cpp
index 29a20dc..017af88 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -27,6 +27,7 @@
 #include <sys/vfs.h>
 #include <sys/mount.h>
 #include <unistd.h>
+#include <dirent.h>
 
 #include "variables.h"
 #include "common.h"
@@ -35,8 +36,6 @@
 extern "C" {
 	#include "extra-functions.h"
 	int __system(const char *command);
-	FILE * __popen(const char *program, const char *type);
-	int __pclose(FILE *iop);
 }
 
 TWPartition::TWPartition(void) {
@@ -81,13 +80,13 @@
 	char full_line[MAX_FSTAB_LINE_LENGTH], item[MAX_FSTAB_LINE_LENGTH];
 	int line_len = Line.size(), index = 0, item_index = 0;
 	char* ptr;
+	string Flags;
 
 	strncpy(full_line, Line.c_str(), line_len);
 
-	while (index < line_len) {
+	for (index = 0; index < line_len; index++) {
 		if (full_line[index] <= 32)
 			full_line[index] = '\0';
-		index++;
 	}
 	string mount_pt(full_line);
 	Mount_Point = mount_pt;
@@ -124,6 +123,10 @@
 				// Partition length
 				ptr += 7;
 				Length = atoi(ptr);
+			} else if (strlen(ptr) > 6 && strncmp(ptr, "flags=", 6) == 0) {
+				// Custom flags, save for later so that new values aren't overwritten by defaults
+				ptr += 6;
+				Flags = ptr;
 			} else {
 				// Unhandled data
 				LOGI("Unhandled fstab information: '%s', %i\n", ptr, index);
@@ -144,14 +147,16 @@
 		if (Mount_Point == "/system") {
 			Display_Name = "System";
 			Wipe_Available_in_GUI = true;
-			Update_Size(Display_Error);
-			int backup_display_size = (int)(Backup_Size / 1048576LLU);
-			DataManager::SetValue(TW_BACKUP_SYSTEM_SIZE, backup_display_size);
 		} else if (Mount_Point == "/data") {
 			Display_Name = "Data";
 			Wipe_Available_in_GUI = true;
+			Wipe_During_Factory_Reset = true;
 #ifdef RECOVERY_SDCARD_ON_DATA
 			Has_Data_Media = true;
+			Is_Storage = true;
+			Storage_Path = "/data/media";
+			Make_Dir("/sdcard", Display_Error);
+			Make_Dir("/emmc", Display_Error);
 #endif
 #ifdef TW_INCLUDE_CRYPTO
 			Can_Be_Encrypted = true;
@@ -161,36 +166,23 @@
 				DataManager::SetValue(TW_IS_ENCRYPTED, 1);
 				DataManager::SetValue(TW_CRYPTO_PASSWORD, "");
 				DataManager::SetValue("tw_crypto_display", "");
-			} else
-				Update_Size(Display_Error);
-#else
-			Update_Size(Display_Error);
+			}
 #endif
-			int backup_display_size = (int)(Backup_Size / 1048576LLU);
-			DataManager::SetValue(TW_BACKUP_DATA_SIZE, backup_display_size);
 		} else if (Mount_Point == "/cache") {
 			Display_Name = "Cache";
 			Wipe_Available_in_GUI = true;
+			Wipe_During_Factory_Reset = true;
 			Update_Size(Display_Error);
-			int backup_display_size = (int)(Backup_Size / 1048576LLU);
-			DataManager::SetValue(TW_BACKUP_CACHE_SIZE, backup_display_size);
 		} else if (Mount_Point == "/datadata") {
+			Wipe_During_Factory_Reset = true;
 			Display_Name = "DataData";
 			Is_SubPartition = true;
 			SubPartition_Of = "/data";
-			Update_Size(Display_Error);
 			DataManager::SetValue(TW_HAS_DATADATA, 1);
 		} else if (Mount_Point == "/sd-ext") {
+			Wipe_During_Factory_Reset = true;
 			Display_Name = "SD-Ext";
 			Wipe_Available_in_GUI = true;
-			Update_Size(Display_Error);
-			int backup_display_size = (int)(Backup_Size / 1048576LLU);
-			DataManager::SetValue(TW_BACKUP_SDEXT_SIZE, backup_display_size);
-			if (Backup_Size == 0) {
-				DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 0);
-				DataManager::SetValue(TW_BACKUP_SDEXT_VAR, 0);
-			} else
-				DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 1);
 		} else
 			Update_Size(Display_Error);
 	} else if (Is_Image(Fstab_File_System)) {
@@ -214,7 +206,62 @@
 		}
 	}
 
-	return 1;
+	// Process any custom flags
+	if (Flags.size() > 0)
+		Process_Flags(Flags, Display_Error);
+
+	return true;
+}
+
+bool TWPartition::Process_Flags(string Flags, bool Display_Error) {
+	char flags[MAX_FSTAB_LINE_LENGTH];
+	int flags_len, index = 0;
+	char* ptr;
+
+	strcpy(flags, Flags.c_str());
+	flags_len = Flags.size();
+	for (index = 0; index < flags_len; index++) {
+		if (flags[index] == ';')
+			flags[index] = '\0';
+	}
+
+	index = 0;
+	while (index < flags_len) {
+		while (index < flags_len && flags[index] == '\0')
+			index++;
+		if (index >= flags_len)
+			continue;
+		ptr = flags + index;
+		if (strcmp(ptr, "removable") == 0) {
+			Removable = true;
+		} else if (strcmp(ptr, "storage") == 0) {
+			Is_Storage = true;
+		} else if (strlen(ptr) > 15 && strncmp(ptr, "subpartitionof=", 15) == 0) {
+			ptr += 13;
+			Is_SubPartition = true;
+			SubPartition_Of = ptr;
+		} else if (strlen(ptr) > 8 && strncmp(ptr, "symlink=", 8) == 0) {
+			ptr += 8;
+			Symlink_Path = ptr;
+		} else if (strlen(ptr) > 8 && strncmp(ptr, "display=", 8) == 0) {
+			ptr += 8;
+			Display_Name = ptr;
+		} else if (strlen(ptr) > 10 && strncmp(ptr, "blocksize=", 10) == 0) {
+			ptr += 10;
+			Format_Block_Size = atoi(ptr);
+		} else if (strlen(ptr) > 7 && strncmp(ptr, "length=", 7) == 0) {
+			ptr += 7;
+			Length = atoi(ptr);
+		} else {
+			if (Display_Error)
+				LOGE("Unhandled flag: '%s'\n", ptr);
+			else
+				LOGI("Unhandled flag: '%s'\n", ptr);
+		}
+		while (index < flags_len && flags[index] != '\0')
+			index++;
+	}
+	return true;
 }
 
 bool TWPartition::Is_File_System(string File_System) {
@@ -238,6 +285,22 @@
 		return false;
 }
 
+bool TWPartition::Make_Dir(string Path, bool Display_Error) {
+	if (!Path_Exists(Path)) {
+		if (mkdir(Path.c_str(), 0777) == -1) {
+			if (Display_Error)
+				LOGE("Can not create '%s' folder.\n", Path.c_str());
+			else
+				LOGI("Can not create '%s' folder.\n", Path.c_str());
+			return false;
+		} else {
+			LOGI("Created '%s' folder.\n", Path.c_str());
+			return true;
+		}
+	}
+	return true;
+}
+
 void TWPartition::Setup_File_System(bool Display_Error) {
 	struct statfs st;
 
@@ -252,15 +315,7 @@
 		Is_Present = true;
 	}
 	// Make the mount point folder if it doesn't exist
-	if (!Path_Exists(Mount_Point.c_str())) {
-		if (mkdir(Mount_Point.c_str(), 0777) == -1) {
-			if (Display_Error)
-				LOGE("Can not create '%s' folder.\n", Mount_Point.c_str());
-			else
-				LOGI("Can not create '%s' folder.\n", Mount_Point.c_str());
-		} else
-			LOGI("Created '%s' folder.\n", Mount_Point.c_str());
-	}
+	Make_Dir(Mount_Point, Display_Error);
 	Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
 	Backup_Name = Display_Name;
 	Backup_Method = FILES;
@@ -315,7 +370,30 @@
 	}
 }
 
-bool TWPartition::Get_Size_Via_df(string Path, bool Display_Error) {
+bool TWPartition::Get_Size_Via_statfs(bool Display_Error) {
+	struct statfs st;
+	string Local_Path = Mount_Point + "/.";
+
+	if (!Mount(Display_Error))
+		return false;
+
+	if (statfs(Local_Path.c_str(), &st) != 0) {
+		if (!Removable) {
+			if (Display_Error)
+				LOGE("Unable to statfs '%s'\n", Local_Path.c_str());
+			else
+				LOGI("Unable to statfs '%s'\n", Local_Path.c_str());
+		}
+		return false;
+	}
+	Size = (st.f_blocks * st.f_bsize);
+	Used = ((st.f_blocks - st.f_bfree) * st.f_bsize);
+	Free = (st.f_bfree * st.f_bsize);
+	Backup_Size = Used;
+	return true;
+}
+
+bool TWPartition::Get_Size_Via_df(bool Display_Error) {
 	FILE* fp;
 	char command[255], line[512];
 	int include_block = 1;
@@ -325,10 +403,13 @@
 		return false;
 
 	min_len = Block_Device.size() + 2;
-	sprintf(command, "df %s", Path.c_str());
-	fp = __popen(command, "r");
-	if (fp == NULL)
+	sprintf(command, "df %s > /tmp/dfoutput.txt", Mount_Point.c_str());
+	__system(command);
+	fp = fopen("/tmp/dfoutput.txt", "rt");
+	if (fp == NULL) {
+		LOGI("Unable to open /tmp/dfoutput.txt.\n");
 		return false;
+	}
 
 	while (fgets(line, sizeof(line), fp) != NULL)
 	{
@@ -362,19 +443,42 @@
 	return true;
 }
 
-unsigned long long TWPartition::Get_Size_Via_du(string Path, bool Display_Error) {
-	char cmd[512];
-    sprintf(cmd, "du -sk %s | awk '{ print $1 }'", Path.c_str());
+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;
 
-    FILE *fp;
-    fp = __popen(cmd, "r");
-    
-    char str[512];
-    fgets(str, sizeof(str), fp);
-    __pclose(fp);
+	// Make a copy of path in case the data in the pointer gets overwritten later
+	strcpy(path2, Path.c_str());
 
-    unsigned long long dusize = atol(str);
-    dusize *= 1024ULL;
+	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;
 }
@@ -456,6 +560,8 @@
 	} else if (!Can_Be_Mounted) {
 		return false;
 	}
+	if (Removable)
+		Check_FS_Type();
 	if (Is_Decrypted) {
 		if (mount(Decrypted_Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) {
 			Check_FS_Type();
@@ -465,10 +571,16 @@
 				else
 					LOGI("Unable to mount decrypted block device '%s' to '%s'\n", Decrypted_Block_Device.c_str(), Mount_Point.c_str());
 				return false;
-			} else
+			} else {
+				if (Removable)
+					Update_Size(Display_Error);
 				return true;
-		} else
+			}
+		} else {
+			if (Removable)
+				Update_Size(Display_Error);
 			return true;
+		}
 	}
 	if (mount(Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) {
 		Check_FS_Type();
@@ -482,13 +594,21 @@
 					else
 						LOGI("Unable to mount '%s'\n", Mount_Point.c_str());
 					return false;
-				} else
+				} else {
+					if (Removable)
+						Update_Size(Display_Error);
 					return true;
+				}
 			} else
 				return false;
-		} else
+		} else {
+			if (Removable)
+				Update_Size(Display_Error);
 			return true;
+		}
 	}
+	if (Removable)
+		Update_Size(Display_Error);
 	return true;
 }
 
@@ -555,10 +675,12 @@
 		return; // Running blkid on some mtd devices causes a massive crash
 
 	if (Is_Decrypted)
-		blkCommand = "blkid " + Decrypted_Block_Device;
+		blkCommand = "blkid " + Decrypted_Block_Device + " > /tmp/blkidoutput.txt";
 	else
-		blkCommand = "blkid " + Block_Device;
-	fp = __popen(blkCommand.c_str(), "r");
+		blkCommand = "blkid " + Block_Device + " > /tmp/blkidoutput.txt";
+
+	__system(blkCommand.c_str());
+	fp = fopen("/tmp/blkidoutput.txt", "rt");
 	while (fgets(blkOutput, sizeof(blkOutput), fp) != NULL)
 	{
 		blk = blkOutput;
@@ -672,20 +794,33 @@
 }
 
 bool TWPartition::Update_Size(bool Display_Error) {
+	bool ret = false;
+
 	if (!Can_Be_Mounted)
 		return false;
 
-	if (!Get_Size_Via_df(Mount_Point, Display_Error))
+	if (!Mount(Display_Error))
 		return false;
+
+	ret = Get_Size_Via_statfs(Display_Error);
+	if (!ret || Size == 0)
+		if (!Get_Size_Via_df(Display_Error))
+			return false;
+
 	if (Has_Data_Media) {
 		if (Mount(Display_Error)) {
-			unsigned long long data_used, data_media_used, actual_data;
-			data_used = Get_Size_Via_du("/data/", Display_Error);
-			data_media_used = Get_Size_Via_du("/data/media/", Display_Error);
-			actual_data = data_used - data_media_used;
+			unsigned long long data_media_used, actual_data;
+			data_media_used = Get_Folder_Size("/data/media", Display_Error);
+			actual_data = Used - data_media_used;
 			Backup_Size = actual_data;
+			int bak = (int)(Backup_Size / 1048576LLU);
+			int total = (int)(Size / 1048576LLU);
+			int us = (int)(Used / 1048576LLU);
+			int fre = (int)(Free / 1048576LLU);
+			int datmed = (int)(data_media_used / 1048576LLU);
+			LOGI("Data backup size is %iMB, size: %iMB, used: %iMB, free: %iMB, in data/media: %iMB.\n", bak, total, us, fre, datmed);
 		} else
 			return false;
 	}
 	return true;
-}
\ No newline at end of file
+}
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 2e50641..b30e3b7 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -71,6 +71,7 @@
 		else
 			LOGI("Error creating fstab\n");
 	}
+	Update_System_Details();
 	return true;
 }
 
@@ -85,12 +86,20 @@
 		return false;
 	}
     for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
-		if ((*iter)->Can_Be_Mounted && (*iter)->Is_Present) {
+		if ((*iter)->Can_Be_Mounted) {
 			if ((*iter)->Is_Decrypted)
 				Line = (*iter)->Decrypted_Block_Device + " " + (*iter)->Mount_Point + " " + (*iter)->Current_File_System + " rw\n";
 			else
 				Line = (*iter)->Block_Device + " " + (*iter)->Mount_Point + " " + (*iter)->Current_File_System + " rw\n";
 			fputs(Line.c_str(), fp);
+			// Handle subpartition tracking
+			if ((*iter)->Is_SubPartition) {
+				TWPartition* ParentPartition = Find_Partition_By_Path((*iter)->SubPartition_Of);
+				if (ParentPartition)
+					ParentPartition->Has_SubPartition = true;
+				else
+					LOGE("Unable to locate parent partition '%s' of '%s'\n", (*iter)->SubPartition_Of.c_str(), (*iter)->Mount_Point.c_str());
+			}
 		}
 	}
 	fclose(fp);
@@ -101,99 +110,180 @@
 	std::vector<TWPartition*>::iterator iter;
 	int ret = false;
 	bool found = false;
-	string Local_Path = Path;
-
-	// Make sure that we have a leading slash
-	if (Local_Path.substr(0, 1) != "/")
-		Local_Path = "/" + Local_Path;
-
-	// Trim the path to get the root path only
-	size_t position = Local_Path.find("/", 2);
-	if (position != string::npos) {
-		Local_Path.resize(position);
-	}
+	string Local_Path = Get_Root_Path(Path);
 
 	// Iterate through all partitions
 	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
 		if ((*iter)->Mount_Point == Local_Path) {
 			ret = (*iter)->Mount(Display_Error);
 			found = true;
-		} else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path)
+		} else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) {
 			(*iter)->Mount(Display_Error);
+		}
 	}
 	if (found) {
 		return ret;
 	} else if (Display_Error) {
-		LOGE("Unable to find partition for path '%s'\n", Local_Path.c_str());
+		LOGE("Mount: Unable to find partition for path '%s'\n", Local_Path.c_str());
 	} else {
-		LOGI("Unable to find partition for path '%s'\n", Local_Path.c_str());
+		LOGI("Mount: Unable to find partition for path '%s'\n", Local_Path.c_str());
 	}
 	return false;
 }
 
 int TWPartitionManager::Mount_By_Block(string Block, bool Display_Error) {
-	std::vector<TWPartition*>::iterator iter;
+	TWPartition* Part = Find_Partition_By_Block(Block);
 
-	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
-		if ((*iter)->Block_Device == Block)
-			return (*iter)->Mount(Display_Error);
-		else if ((*iter)->Alternate_Block_Device == Block)
-			return (*iter)->Mount(Display_Error);
+	if (Part) {
+		if (Part->Has_SubPartition) {
+			std::vector<TWPartition*>::iterator subpart;
+
+			for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
+				if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
+					(*subpart)->Mount(Display_Error);
+			}
+			return Part->Mount(Display_Error);
+		} else
+			return Part->Mount(Display_Error);
 	}
 	if (Display_Error)
-		LOGE("Unable to find partition for block '%s'\n", Block.c_str());
+		LOGE("Mount: Unable to find partition for block '%s'\n", Block.c_str());
 	else
-		LOGI("Unable to find partition for block '%s'\n", Block.c_str());
+		LOGI("Mount: Unable to find partition for block '%s'\n", Block.c_str());
 	return false;
 }
 
 int TWPartitionManager::Mount_By_Name(string Name, bool Display_Error) {
-	std::vector<TWPartition*>::iterator iter;
+	TWPartition* Part = Find_Partition_By_Name(Name);
 
-	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
-		if ((*iter)->Display_Name == Name)
-			return (*iter)->Mount(Display_Error);
+	if (Part) {
+		if (Part->Has_SubPartition) {
+			std::vector<TWPartition*>::iterator subpart;
+
+			for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
+				if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
+					(*subpart)->Mount(Display_Error);
+			}
+			return Part->Mount(Display_Error);
+		} else
+			return Part->Mount(Display_Error);
 	}
 	if (Display_Error)
-		LOGE("Unable to find partition for name '%s'\n", Name.c_str());
+		LOGE("Mount: Unable to find partition for name '%s'\n", Name.c_str());
 	else
-		LOGI("Unable to find partition for name '%s'\n", Name.c_str());
+		LOGI("Mount: Unable to find partition for name '%s'\n", Name.c_str());
 	return false;
-	return 1;
 }
 
 int TWPartitionManager::UnMount_By_Path(string Path, bool Display_Error) {
-	LOGI("STUB TWPartitionManager::UnMount_By_Path, Path: '%s', Display_Error: %i\n", Path.c_str(), Display_Error);
-	return 1;
+	std::vector<TWPartition*>::iterator iter;
+	int ret = false;
+	bool found = false;
+	string Local_Path = Get_Root_Path(Path);
+
+	// Iterate through all partitions
+	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+		if ((*iter)->Mount_Point == Local_Path) {
+			ret = (*iter)->UnMount(Display_Error);
+			found = true;
+		} else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) {
+			(*iter)->UnMount(Display_Error);
+		}
+	}
+	if (found) {
+		return ret;
+	} else if (Display_Error) {
+		LOGE("UnMount: Unable to find partition for path '%s'\n", Local_Path.c_str());
+	} else {
+		LOGI("UnMount: Unable to find partition for path '%s'\n", Local_Path.c_str());
+	}
+	return false;
 }
 
 int TWPartitionManager::UnMount_By_Block(string Block, bool Display_Error) {
-	LOGI("STUB TWPartitionManager::UnMount_By_Block, Block: '%s', Display_Error: %i\n", Block.c_str(), Display_Error);
-	return 1;
+	TWPartition* Part = Find_Partition_By_Block(Block);
+
+	if (Part) {
+		if (Part->Has_SubPartition) {
+			std::vector<TWPartition*>::iterator subpart;
+
+			for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
+				if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
+					(*subpart)->UnMount(Display_Error);
+			}
+			return Part->UnMount(Display_Error);
+		} else
+			return Part->UnMount(Display_Error);
+	}
+	if (Display_Error)
+		LOGE("UnMount: Unable to find partition for block '%s'\n", Block.c_str());
+	else
+		LOGI("UnMount: Unable to find partition for block '%s'\n", Block.c_str());
+	return false;
 }
 
 int TWPartitionManager::UnMount_By_Name(string Name, bool Display_Error) {
-	LOGI("STUB TWPartitionManager::UnMount_By_Name, Name: '%s', Display_Error: %i\n", Name.c_str(), Display_Error);
-	return 1;
+	TWPartition* Part = Find_Partition_By_Name(Name);
+
+	if (Part) {
+		if (Part->Has_SubPartition) {
+			std::vector<TWPartition*>::iterator subpart;
+
+			for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
+				if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
+					(*subpart)->UnMount(Display_Error);
+			}
+			return Part->UnMount(Display_Error);
+		} else
+			return Part->UnMount(Display_Error);
+	}
+	if (Display_Error)
+		LOGE("UnMount: Unable to find partition for name '%s'\n", Name.c_str());
+	else
+		LOGI("UnMount: Unable to find partition for name '%s'\n", Name.c_str());
+	return false;
 }
 
 int TWPartitionManager::Is_Mounted_By_Path(string Path) {
-	LOGI("STUB TWPartitionManager::Is_Mounted_By_Path, Path: '%s'\n", Path.c_str());
-	return 1;
+	TWPartition* Part = Find_Partition_By_Path(Path);
+
+	if (Part)
+		return Part->Is_Mounted();
+	else
+		LOGI("Is_Mounted: Unable to find partition for path '%s'\n", Path.c_str());
+	return false;
 }
 
 int TWPartitionManager::Is_Mounted_By_Block(string Block) {
-	LOGI("STUB TWPartitionManager::Is_Mounted_By_Block, Block: '%s'\n", Block.c_str());
-	return 1;
+	TWPartition* Part = Find_Partition_By_Block(Block);
+
+	if (Part)
+		return Part->Is_Mounted();
+	else
+		LOGI("Is_Mounted: Unable to find partition for block '%s'\n", Block.c_str());
+	return false;
 }
 
 int TWPartitionManager::Is_Mounted_By_Name(string Name) {
-	LOGI("STUB TWPartitionManager::Is_Mounted_By_Name, Name: '%s'\n", Name.c_str());
-	return 1;
+	TWPartition* Part = Find_Partition_By_Name(Name);
+
+	if (Part)
+		return Part->Is_Mounted();
+	else
+		LOGI("Is_Mounted: Unable to find partition for name '%s'\n", Name.c_str());
+	return false;
 }
 
 int TWPartitionManager::Mount_Current_Storage(bool Display_Error) {
-	return Mount_By_Path(DataManager::GetCurrentStoragePath(), Display_Error);
+	string current_storage_path = DataManager::GetCurrentStoragePath();
+
+	if (Mount_By_Path(current_storage_path, Display_Error)) {
+		TWPartition* FreeStorage = Find_Partition_By_Path(current_storage_path);
+		if (FreeStorage)
+			DataManager::SetValue(TW_STORAGE_FREE_SIZE, (int)(FreeStorage->Free / 1048576LLU));
+		return true;
+	}
+	return false;
 }
 
 int TWPartitionManager::Mount_Settings_Storage(bool Display_Error) {
@@ -202,21 +292,32 @@
 
 TWPartition* TWPartitionManager::Find_Partition_By_Path(string Path) {
 	std::vector<TWPartition*>::iterator iter;
+	string Local_Path = Get_Root_Path(Path);
 
 	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
-		if ((*iter)->Mount_Point == Path)
+		if ((*iter)->Mount_Point == Local_Path)
 			return (*iter);
 	}
 	return NULL;
 }
 
 TWPartition* TWPartitionManager::Find_Partition_By_Block(string Block) {
-	LOGI("STUB TWPartitionManager::Find_Partition_By_Block, Block: '%s'\n", Block.c_str());
+	std::vector<TWPartition*>::iterator iter;
+
+	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+		if ((*iter)->Block_Device == Block || (*iter)->Alternate_Block_Device == Block || ((*iter)->Is_Decrypted && (*iter)->Decrypted_Block_Device == Block))
+			return (*iter);
+	}
 	return NULL;
 }
 
 TWPartition* TWPartitionManager::Find_Partition_By_Name(string Name) {
-	LOGI("STUB TWPartitionManager::Find_Partition_By_Name, Name: '%s'\n", Name.c_str());
+	std::vector<TWPartition*>::iterator iter;
+
+	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+		if ((*iter)->Display_Name == Name)
+			return (*iter);
+	}
 	return NULL;
 }
 
@@ -256,18 +357,44 @@
 }
 
 void TWPartitionManager::Refresh_Sizes(void) {
-	LOGI("STUB TWPartitionManager::Refresh_Sizes\n");
+	Update_System_Details();
 	return;
 }
 
 void TWPartitionManager::Update_System_Details(void) {
 	std::vector<TWPartition*>::iterator iter;
+	int data_size = 0;
 
 	LOGI("Updating system details...\n");
 	for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
-		(*iter)->Check_FS_Type();
-		(*iter)->Update_Size(false);
+		if ((*iter)->Can_Be_Mounted) {
+			(*iter)->Update_Size(true);
+			if ((*iter)->Mount_Point == "/system") {
+				int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
+				DataManager::SetValue(TW_BACKUP_SYSTEM_SIZE, backup_display_size);
+			} else if ((*iter)->Mount_Point == "/data" || (*iter)->Mount_Point == "/datadata") {
+				data_size += (int)((*iter)->Backup_Size / 1048576LLU);
+			} else if ((*iter)->Mount_Point == "/cache") {
+				int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
+				DataManager::SetValue(TW_BACKUP_CACHE_SIZE, backup_display_size);
+			} else if ((*iter)->Mount_Point == "/sd-ext") {
+				int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
+				DataManager::SetValue(TW_BACKUP_SDEXT_SIZE, backup_display_size);
+				if ((*iter)->Backup_Size == 0) {
+					DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 0);
+					DataManager::SetValue(TW_BACKUP_SDEXT_VAR, 0);
+				} else
+					DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 1);
+			}
+		}
 	}
+	DataManager::SetValue(TW_BACKUP_DATA_SIZE, data_size);
+	string current_storage_path = DataManager::GetCurrentStoragePath();
+	TWPartition* FreeStorage = Find_Partition_By_Path(current_storage_path);
+	if (FreeStorage)
+		DataManager::SetValue(TW_STORAGE_FREE_SIZE, (int)(FreeStorage->Free / 1048576LLU));
+	else
+		LOGI("Unable to find storage partition '%s'.\n", current_storage_path.c_str());
 	if (!Write_Fstab())
 		LOGE("Error creating fstab\n");
 	return;
@@ -318,4 +445,19 @@
 	return -1;
 #endif
 	return 1;
-}
\ No newline at end of file
+}
+
+string TWPartitionManager::Get_Root_Path(string Path) {
+	string Local_Path = Path;
+
+	// Make sure that we have a leading slash
+	if (Local_Path.substr(0, 1) != "/")
+		Local_Path = "/" + Local_Path;
+
+	// Trim the path to get the root path only
+	size_t position = Local_Path.find("/", 2);
+	if (position != string::npos) {
+		Local_Path.resize(position);
+	}
+	return Local_Path;
+}
diff --git a/partitions.hpp b/partitions.hpp
index 13ce028..5ed723c 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -52,7 +52,7 @@
 	virtual bool Wipe();                                                      // Wipes the partition
 	virtual bool Backup(string backup_folder);                                // Backs up the partition to the folder specified
 	virtual bool Restore(string restore_folder);                              // Restores the partition using the backup folder provided
-	static string Backup_Method_By_Name();                                    // Returns a string of the backup method for human readable output
+	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
 	virtual bool Wipe_Encryption();                                           // Ignores wipe commands for /data/media devices and formats the original block device
 	virtual void Check_FS_Type();                                             // Checks the fs type using blkid, does not do anything on MTD / yaffs2 because this crashes on some devices
@@ -67,6 +67,7 @@
 	bool Wipe_During_Factory_Reset;                                           // Indicates that this partition is wiped during a factory reset
 	bool Wipe_Available_in_GUI;                                               // Inidcates that the wipe can be user initiated in the GUI system
 	bool Is_SubPartition;                                                     // Indicates that this partition is a sub-partition of another partition (e.g. datadata is a sub-partition of data)
+	bool Has_SubPartition;                                                    // Indicates that this partition has a sub-partition
 	string SubPartition_Of;                                                   // Indicates which partition is the parent partition of this partition (e.g. /data is the parent partition of /datadata)
 	string Symlink_Path;                                                      // Symlink path (e.g. /data/media)
 	string Symlink_Mount_Point;                                               // /sdcard could be the symlink mount point for /data/media
@@ -95,6 +96,7 @@
 	int Format_Block_Size;                                                    // Block size for formatting
 
 private:
+	bool Process_Flags(string Flags, bool Display_Error);                     // Process custom fstab flags
 	bool Is_File_System(string File_System);                                  // Checks to see if the file system given is considered a file system
 	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
@@ -102,7 +104,6 @@
 	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
-	bool Get_Size_Via_df(string Path, bool Display_Error);                    // Uses df to get sizes
 	unsigned long long Get_Size_Via_du(string Path, bool Display_Error);      // Uses du to get sizes
 	void Flip_Block_Device();                                                 // Flips the Block_Device and Alternate_Block_Device
 	bool Wipe_EXT23();                                                        // Formats as ext3 or ext2
@@ -117,6 +118,10 @@
 	bool Restore_Tar(string restore_folder);                                  // Restore using tar for file systems
 	bool Restore_DD(string restore_folder);                                   // Restore using dd for emmc memory types
 	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
 
 friend class TWPartitionManager;
 };
@@ -154,9 +159,10 @@
 	virtual void Refresh_Sizes();                                             // Refreshes size data of partitions
 	virtual void Update_System_Details();                                     // Updates fstab, file systems, sizes, etc.
 	virtual int Decrypt_Device(string Password);                              // Attempt to decrypt any encrypted partitions
+	virtual string Get_Root_Path(string Path);                                // Trims any trailing folders or filenames from the path, also adds a leading / if not present
 
 private:
-	std::vector<TWPartition*> Partitions;
+	std::vector<TWPartition*> Partitions;                                     // Vector list of all partitions
 };
 
 extern TWPartitionManager PartitionManager;
diff --git a/recovery.cpp b/recovery.cpp
index 319cdc7..450f363 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -51,6 +51,7 @@
 #include "gui/gui.h"
 }
 #include "partitions.hpp"
+#include "variables.h"
 
 TWPartitionManager PartitionManager;
 char device_id[64];
@@ -787,7 +788,7 @@
         return 0;
     }
 
-    printf("Starting TWRP %s on %s", EXPAND(TW_VERSION_STR), ctime(&start));
+    printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));
 	// Recovery needs to install world-readable files, so clear umask
     // set by init
     umask(0);
@@ -802,7 +803,7 @@
 	// Load default values to set DataManager constants and handle ifdefs
 	DataManager_LoadDefaults();
 	printf("Starting the UI...");
-	printf(" result was: %i\n", gui_init());
+	gui_init();
 	printf("=> Installing busybox into /sbin\n");
 	__system("/sbin/bbinstall.sh"); // Let's install busybox
 	printf("=> Linking mtab\n");
diff --git a/roots.cpp b/roots.cpp
index 3bd6801..e747473 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -40,7 +40,8 @@
     while ((option = strtok(options, ","))) {
         options = NULL;
 
-        if (strncmp(option, "length=", 7) == 0) {
+        if (strncmp(option, "flags=", 6) == 0)   continue;
+		if (strncmp(option, "length=", 7) == 0) {
             volume->length = strtoll(option+7, NULL, 10);
         } else {
             LOGE("bad option \"%s\"\n", option);