From a2719156c236c8be02403ef028490f001d393d8e Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Thu, 28 May 2015 09:44:41 -0500 Subject: 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 --- gui/action.cpp | 27 ++++++++++++ gui/devices/landscape/res/landscape.xml | 19 ++++++++ gui/devices/portrait/res/portrait.xml | 19 ++++++++ gui/devices/watch/res/watch.xml | 19 ++++++++ gui/objects.hpp | 1 + partition.cpp | 77 ++++++++++++++++++++++++++++++++- partitionmanager.cpp | 28 ++++++++++++ partitions.hpp | 5 ++- prebuilt/Android.mk | 1 + 9 files changed, 193 insertions(+), 3 deletions(-) diff --git a/gui/action.cpp b/gui/action.cpp index 7ecd0b46a..fc3973738 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -223,6 +223,7 @@ GUIAction::GUIAction(xml_node<>* node) ADD_ACTION(installsu); ADD_ACTION(decrypt_backup); ADD_ACTION(repair); + ADD_ACTION(resize); ADD_ACTION(changefilesystem); ADD_ACTION(flashimage); } @@ -872,6 +873,10 @@ int GUIAction::getpartitiondetails(std::string arg) DataManager::SetValue("tw_partition_can_repair", 1); else DataManager::SetValue("tw_partition_can_repair", 0); + if (Part->Can_Resize()) + DataManager::SetValue("tw_partition_can_resize", 1); + else + DataManager::SetValue("tw_partition_can_resize", 0); if (TWFunc::Path_Exists("/sbin/mkdosfs")) DataManager::SetValue("tw_partition_vfat", 1); else @@ -1651,6 +1656,28 @@ int GUIAction::repair(std::string arg) return 0; } +int GUIAction::resize(std::string arg) +{ + int op_status = 0; + + operation_start("Resize Partition"); + if (simulate) { + simulate_progress_bar(); + } else { + string part_path; + DataManager::GetValue("tw_partition_mount_point", part_path); + if (PartitionManager.Resize_By_Path(part_path, true)) { + op_status = 0; // success + } else { + LOGERR("Error resizing file system.\n"); + op_status = 1; // fail + } + } + + operation_end(op_status); + return 0; +} + int GUIAction::changefilesystem(std::string arg) { int op_status = 0; diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml index 12c66290b..529aef79c 100644 --- a/gui/devices/landscape/res/landscape.xml +++ b/gui/devices/landscape/res/landscape.xml @@ -1380,6 +1380,25 @@ Backup Size: %tw_partition_backup_size%MB + + + + Resize + + tw_back=partitionoptions + tw_action=resize + tw_action_param=%tw_partition_mount_point% + tw_has_action2=1 + tw_action2=getpartitiondetails + tw_text1=Resize %tw_partition_name%? + tw_text2= + tw_action_text1=Resizing... + tw_complete_text1=Resize Complete + tw_slider_text=Swipe to Resize + confirm_action + + + diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml index 997da9d23..9ffd6e44e 100644 --- a/gui/devices/portrait/res/portrait.xml +++ b/gui/devices/portrait/res/portrait.xml @@ -1117,6 +1117,25 @@ Backup Size: %tw_partition_backup_size%MB + + + + Resize + + tw_back=partitionoptions + tw_action=resize + tw_action_param=%tw_partition_mount_point% + tw_has_action2=1 + tw_action2=getpartitiondetails + tw_text1=Resize %tw_partition_name%? + tw_text2= + tw_action_text1=Resizing... + tw_complete_text1=Resize Complete + tw_slider_text=Swipe to Resize + confirm_action + + + diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml index f0f383dcb..a8535c659 100644 --- a/gui/devices/watch/res/watch.xml +++ b/gui/devices/watch/res/watch.xml @@ -1095,6 +1095,25 @@ Backup Size: %tw_partition_backup_size%MB + + + + Resize + + tw_back=partitionoptions + tw_action=resize + tw_action_param=%tw_partition_mount_point% + tw_has_action2=1 + tw_action2=getpartitiondetails + tw_text1=Resize %tw_partition_name%? + tw_text2= + tw_action_text1=Resizing... + tw_complete_text1=Resize Complete + tw_slider_text=Swipe to Resize + confirm_action + + + diff --git a/gui/objects.hpp b/gui/objects.hpp index ee0f08b8f..1991877ee 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -354,6 +354,7 @@ protected: int fixsu(std::string arg); int decrypt_backup(std::string arg); int repair(std::string arg); + int resize(std::string arg); int changefilesystem(std::string arg); int startmtp(std::string arg); int stopmtp(std::string arg); diff --git a/partition.cpp b/partition.cpp index 2f9f41a69..9c5462d3e 100644 --- a/partition.cpp +++ b/partition.cpp @@ -534,7 +534,7 @@ bool TWPartition::Process_Flags(string Flags, bool Display_Error) { } } 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::Wipe_AndSec(void) { } 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 @@ bool TWPartition::Repair() { 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 @@ bool TWPartition::Repair() { 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); diff --git a/partitionmanager.cpp b/partitionmanager.cpp index 055f73697..572cd7c93 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -1259,6 +1259,34 @@ int TWPartitionManager::Repair_By_Path(string Path, bool Display_Error) { return false; } +int TWPartitionManager::Resize_By_Path(string Path, bool Display_Error) { + std::vector::iterator iter; + int ret = false; + bool found = false; + string Local_Path = TWFunc::Get_Root_Path(Path); + + if (Local_Path == "/tmp" || Local_Path == "/") + 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)) { + ret = (*iter)->Resize(); + found = true; + } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) { + (*iter)->Resize(); + } + } + if (found) { + return ret; + } else if (Display_Error) { + LOGERR("Resize: Unable to find partition for path '%s'\n", Local_Path.c_str()); + } else { + LOGINFO("Resize: Unable to find partition for path '%s'\n", Local_Path.c_str()); + } + return false; +} + void TWPartitionManager::Update_System_Details(void) { std::vector::iterator iter; int data_size = 0; diff --git a/partitions.hpp b/partitions.hpp index 1489a8ec2..63c01af8d 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -59,6 +59,8 @@ public: bool Can_Repair(); // Checks to see if we have everything needed to be able to repair the current file system uint64_t Get_Max_FileSize(); //get partition maxFileSie bool Repair(); // Repairs the current file system + bool Can_Resize(); // Checks to see if we have everything needed to be able to resize the current file system + bool Resize(); // Resizes the current file system bool Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid); // Backs up the partition to the folder specified bool Check_MD5(string restore_folder); // Checks MD5 of a backup bool Restore(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restores the partition using the backup folder provided @@ -165,7 +167,7 @@ private: string Fstab_File_System; // File system from the recovery.fstab int Mount_Flags; // File system flags from recovery.fstab string Mount_Options; // File system options from recovery.fstab - int Format_Block_Size; // Block size for formatting + unsigned long Format_Block_Size; // Block size for formatting bool Ignore_Blkid; // Ignore blkid results due to superblocks lying to us on certain devices / partitions bool Retain_Layout_Version; // Retains the .layout_version file during a wipe (needed on devices like Sony Xperia T where /data and /data/media are separate partitions) bool Can_Flash_Img; // Indicates if this partition can have images flashed to it via the GUI @@ -207,6 +209,7 @@ public: int Format_Data(); // Really formats data on /data/media devices -- also removes encryption int Wipe_Media_From_Data(); // Removes and recreates the media folder on /data/media devices int Repair_By_Path(string Path, bool Display_Error); // Repairs a partition based on path + int Resize_By_Path(string Path, bool Display_Error); // Resizes a partition based on path void Update_System_Details(); // Updates fstab, file systems, sizes, etc. int Decrypt_Device(string Password); // Attempt to decrypt any encrypted partitions int usb_storage_enable(void); // Enable USB storage mode diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk index 1449dc8af..3ecf02fbf 100644 --- a/prebuilt/Android.mk +++ b/prebuilt/Android.mk @@ -26,6 +26,7 @@ RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/mkdosfs RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/e2fsck RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/mke2fs RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/tune2fs +RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/resize2fs ifneq ($(TARGET_ARCH), x86_64) RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/linker endif -- cgit v1.2.3