Improve storage size code, mount, unmount

Add flag parsing from recovery.fstab
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
+}