Add resize2fs and ability to run resize2fs via GUI

Note: Only works on ext2/3/4 partitions. Only tested on ext4.

We can use this in some cases to resize the data partition if an
incorrect fstab caused recovery to not reserve the 16KB for a
crypto footer.

Sometimes the BoardConfig for a custom ROM does not have the
correct size for the system partition and if the ROM flashes a
raw system image, that image will not take up the full block
device. Running resize2fs can fix the size and may allow more
room in the system partition for customizations like busybox or
a larger gapps package.

Sometimes flashing a factory image may flash userdata with an
image with a file system that does not take up the full size of
the block device (e.g. factory images for the Nexus 6 will flash
userdata with a ~24GB userdata image, wasting ~30GB of space).
Using resize2fs we can easily fix this issue without having to do
a full format data.

Change-Id: I631f5c6f567bbc6a9241e5dd95f1e435820a1b13
diff --git a/partition.cpp b/partition.cpp
index 2f9f41a..9c5462d 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -534,7 +534,7 @@
 			}
 		} else if (ptr_len > 10 && strncmp(ptr, "blocksize=", 10) == 0) {
 			ptr += 10;
-			Format_Block_Size = atoi(ptr);
+			Format_Block_Size = (unsigned long)(atol(ptr));
 		} else if (ptr_len > 7 && strncmp(ptr, "length=", 7) == 0) {
 			ptr += 7;
 			Length = atoi(ptr);
@@ -1184,6 +1184,8 @@
 }
 
 bool TWPartition::Can_Repair() {
+	if (Mount_Read_Only)
+		return false;
 	if (Current_File_System == "vfat" && TWFunc::Path_Exists("/sbin/dosfsck"))
 		return true;
 	else if ((Current_File_System == "ext2" || Current_File_System == "ext3" || Current_File_System == "ext4") && TWFunc::Path_Exists("/sbin/e2fsck"))
@@ -1226,7 +1228,7 @@
 			return false;
 		gui_print("Repairing %s using e2fsck...\n", Display_Name.c_str());
 		Find_Actual_Block_Device();
-		command = "/sbin/e2fsck -p " + Actual_Block_Device;
+		command = "/sbin/e2fsck -fp " + Actual_Block_Device;
 		LOGINFO("Repair command: %s\n", command.c_str());
 		if (TWFunc::Exec_Cmd(command) == 0) {
 			gui_print("Done.\n");
@@ -1277,6 +1279,77 @@
 	return false;
 }
 
+bool TWPartition::Can_Resize() {
+	if (Mount_Read_Only)
+		return false;
+	if ((Current_File_System == "ext2" || Current_File_System == "ext3" || Current_File_System == "ext4") && TWFunc::Path_Exists("/sbin/resize2fs"))
+		return true;
+	return false;
+}
+
+bool TWPartition::Resize() {
+	string command;
+
+	if (Current_File_System == "ext2" || Current_File_System == "ext3" || Current_File_System == "ext4") {
+		if (!Can_Repair()) {
+			LOGERR("Cannot resize %s because %s cannot be repaired before resizing.\n", Display_Name.c_str(), Display_Name.c_str());
+			return false;
+		}
+		if (!TWFunc::Path_Exists("/sbin/resize2fs")) {
+			gui_print("resize2fs does not exist! Cannot resize!\n");
+			return false;
+		}
+		// Repair will unmount so no need to do it twice
+		gui_print("Repairing %s before resizing.\n", Display_Name.c_str());
+		if (!Repair())
+			return false;
+		gui_print("Resizing %s using resize2fs...\n", Display_Name.c_str());
+		Find_Actual_Block_Device();
+		command = "/sbin/resize2fs " + Actual_Block_Device;
+		if (Length != 0) {
+			unsigned int block_device_size;
+			int fd, ret;
+
+			fd = open(Actual_Block_Device.c_str(), O_RDONLY);
+			if (fd < 0) {
+				LOGERR("Resize: Failed to open '%s'\n", Actual_Block_Device.c_str());
+				return false;
+			}
+			ret = ioctl(fd, BLKGETSIZE, &block_device_size);
+			close(fd);
+			if (ret) {
+				LOGERR("Resize: ioctl error\n");
+				return false;
+			}
+			unsigned long long Actual_Size = (unsigned long long)(block_device_size) * 512LLU;
+			unsigned long long Block_Count;
+			if (Length < 0) {
+				// Reduce overall size by this length
+				Block_Count = (Actual_Size / 1024LLU) - ((unsigned long long)(Length * -1) / 1024LLU);
+			} else {
+				// This is the size, not a size reduction
+				Block_Count = ((unsigned long long)(Length) / 1024LLU);
+			}
+			char temp[256];
+			sprintf(temp, "%llu", Block_Count);
+			command += " ";
+			command += temp;
+			command += "K";
+		}
+		LOGINFO("Resize command: %s\n", command.c_str());
+		if (TWFunc::Exec_Cmd(command) == 0) {
+			Update_Size(true);
+			gui_print("Done.\n");
+			return true;
+		} else {
+			Update_Size(true);
+			LOGERR("Unable to resize '%s'.\n", Mount_Point.c_str());
+			return false;
+		}
+	}
+	return false;
+}
+
 bool TWPartition::Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid) {
 	if (Backup_Method == FILES) {
 		return Backup_Tar(backup_folder, overall_size, other_backups_size, tar_fork_pid);