repack: update repacking

This will support updating the ramdisk to a different
compression format and co-exist with magisk.

We are also moving twrp repacking to its own class. We
check the new ramdisk format and if it's different
we have magisk compress using the new ramdisk format.

Change-Id: I770030aae7797e75817178b2f0fccd9f39dc23af
diff --git a/Android.mk b/Android.mk
index a721885..826636f 100755
--- a/Android.mk
+++ b/Android.mk
@@ -75,7 +75,8 @@
     twrpDigestDriver.cpp \
     openrecoveryscript.cpp \
     tarWrite.c \
-    twrpAdbBuFifo.cpp
+    twrpAdbBuFifo.cpp \
+    twrpRepacker.cpp
 
 ifneq ($(TARGET_RECOVERY_REBOOT_SRC),)
   LOCAL_SRC_FILES += $(TARGET_RECOVERY_REBOOT_SRC)
diff --git a/gui/action.cpp b/gui/action.cpp
index c8ee34c..494665c 100755
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -38,6 +38,7 @@
 #include <sstream>
 #include "../partitions.hpp"
 #include "../twrp-functions.hpp"
+#include "../twrpRepacker.hpp"
 #include "../openrecoveryscript.hpp"
 
 #include "../adb_install.h"
@@ -2167,6 +2168,8 @@
 int GUIAction::repackimage(std::string arg __unused)
 {
 	int op_status = 1;
+	twrpRepacker repacker;
+
 	operation_start("Repack Image");
 	if (!simulate)
 	{
@@ -2179,7 +2182,7 @@
 			Repack_Options.Type = REPLACE_KERNEL;
 		else
 			Repack_Options.Type = REPLACE_RAMDISK;
-		if (!PartitionManager.Repack_Images(path, Repack_Options))
+		if (!repacker.Repack_Image_And_Flash(path, Repack_Options))
 			goto exit;
 	} else
 		simulate_progress_bar();
@@ -2192,6 +2195,8 @@
 int GUIAction::fixabrecoverybootloop(std::string arg __unused)
 {
 	int op_status = 1;
+	twrpRepacker repacker;
+
 	operation_start("Repack Image");
 	if (!simulate)
 	{
@@ -2207,7 +2212,7 @@
 			gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot"));
 			goto exit;
 		}
-		if (!PartitionManager.Prepare_Repack(part, REPACK_ORIG_DIR, DataManager::GetIntValue("tw_repack_backup_first") != 0, gui_lookup("repack", "Repack")))
+		if (!repacker.Backup_Image_For_Repack(part, REPACK_ORIG_DIR, DataManager::GetIntValue("tw_repack_backup_first") != 0, gui_lookup("repack", "Repack")))
 			goto exit;
 		DataManager::SetProgress(.25);
 		gui_msg("fixing_recovery_loop_patch=Patching kernel...");
diff --git a/partition.cpp b/partition.cpp
index f108087..d14c72d 100755
--- a/partition.cpp
+++ b/partition.cpp
@@ -1478,7 +1478,7 @@
 		string cmd = "/sbin/exfat-fuse -o big_writes,max_read=131072,max_write=131072 " + Actual_Block_Device + " " + Mount_Point;
 		LOGINFO("cmd: %s\n", cmd.c_str());
 		string result;
-		if (TWFunc::Exec_Cmd(cmd, result) != 0) {
+		if (TWFunc::Exec_Cmd(cmd, result, false) != 0) {
 			LOGINFO("exfat-fuse failed to mount with result '%s', trying vfat\n", result.c_str());
 			Current_File_System = "vfat";
 		} else {
@@ -3482,3 +3482,16 @@
 string TWPartition::Get_Backup_Name() {
 	return Backup_Name;
 }
+
+std::string TWPartition::Get_Backup_FileName() {
+	return Backup_FileName;
+}
+
+std::string TWPartition::Get_Display_Name() {
+	return Display_Name;
+}
+
+bool TWPartition::Is_SlotSelect() {
+	return SlotSelect;
+
+}
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 555723f..6472349 100755
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -52,6 +52,7 @@
 #include "gui/gui.hpp"
 #include "progresstracking.hpp"
 #include "twrpDigestDriver.hpp"
+#include "twrpRepacker.hpp"
 #include "adbbu/libtwadbbu.hpp"
 
 #ifdef TW_HAS_MTP
@@ -2693,6 +2694,7 @@
 }
 
 bool TWPartitionManager::Flash_Image(string& path, string& filename) {
+	twrpRepacker repacker;
 	int partition_count = 0;
 	TWPartition* flash_part = NULL;
 	string Flash_List, flash_path, full_filename;
@@ -2726,7 +2728,7 @@
 		Repack_Options.Disable_Verity = false;
 		Repack_Options.Disable_Force_Encrypt = false;
 		Repack_Options.Backup_First = DataManager::GetIntValue("tw_repack_backup_first") != 0;
-		return Repack_Images(full_filename, Repack_Options);
+		return repacker.Repack_Image_And_Flash(full_filename, Repack_Options);
 	}
 	PartitionSettings part_settings;
 	part_settings.Backup_Folder = path;
@@ -3224,159 +3226,3 @@
 		TWFunc::removeDir(Folder, false);
 	return TWFunc::Recursive_Mkdir(Folder);
 }
-
-bool TWPartitionManager::Prepare_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination, const bool Create_Backup, const std::string& Backup_Name) {
-	if (!Part) {
-		LOGERR("Partition was null!\n");
-		return false;
-	}
-	if (!Prepare_Empty_Folder(Temp_Folder_Destination))
-		return false;
-	std::string target_image = Temp_Folder_Destination + "boot.img";
-	PartitionSettings part_settings;
-	part_settings.Part = Part;
-	if (Create_Backup) {
-		if (Check_Backup_Name(Backup_Name, true, false) != 0)
-			return false;
-		DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder);
-		part_settings.Backup_Folder = part_settings.Backup_Folder + "/" + TWFunc::Get_Current_Date() + " " + Backup_Name + "/";
-		if (!TWFunc::Recursive_Mkdir(part_settings.Backup_Folder))
-			return false;
-	} else
-		part_settings.Backup_Folder = Temp_Folder_Destination;
-	part_settings.adbbackup = false;
-	part_settings.generate_digest = false;
-	part_settings.generate_md5 = false;
-	part_settings.PM_Method = PM_BACKUP;
-	part_settings.progress = NULL;
-	pid_t not_a_pid = 0;
-	if (!Part->Backup(&part_settings, &not_a_pid))
-		return false;
-	std::string backed_up_image = part_settings.Backup_Folder;
-	backed_up_image += Part->Backup_FileName;
-	target_image = Temp_Folder_Destination + "boot.img";
-	if (Create_Backup) {
-		std::string source = part_settings.Backup_Folder + Part->Backup_FileName;
-		if (TWFunc::copy_file(source, target_image, 0644) != 0) {
-			LOGERR("Failed to copy backup file '%s' to temp folder target '%s'\n", source.c_str(), target_image.c_str());
-			return false;
-		}
-	} else {
-		if (rename(backed_up_image.c_str(), target_image.c_str()) != 0) {
-			LOGERR("Failed to rename '%s' to '%s'\n", backed_up_image.c_str(), target_image.c_str());
-			return false;
-		}
-	}
-	return Prepare_Repack(target_image, Temp_Folder_Destination, false, false);
-}
-
-bool TWPartitionManager::Prepare_Repack(const std::string& Source_Path, const std::string& Temp_Folder_Destination, const bool Copy_Source, const bool Create_Destination) {
-	if (Create_Destination) {
-		if (!Prepare_Empty_Folder(Temp_Folder_Destination))
-			return false;
-	}
-	if (Copy_Source) {
-		std::string destination = Temp_Folder_Destination + "/boot.img";
-		if (TWFunc::copy_file(Source_Path, destination, 0644))
-			return false;
-	}
-	std::string command = "cd " + Temp_Folder_Destination + " && /sbin/magiskboot unpack -h '" + Source_Path +"'";
-	if (TWFunc::Exec_Cmd(command) != 0) {
-		LOGINFO("Error unpacking %s!\n", Source_Path.c_str());
-		gui_msg(Msg(msg::kError, "unpack_error=Error unpacking image."));
-		return false;
-	}
-	return true;
-}
-
-bool TWPartitionManager::Repack_Images(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options) {
-	if (!TWFunc::Path_Exists("/sbin/magiskboot")) {
-		LOGERR("Image repacking tool not present in this TWRP build!");
-		return false;
-	}
-	DataManager::SetProgress(0);
-	TWPartition* part = PartitionManager.Find_Partition_By_Path("/boot");
-	if (part)
-		gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Display_Name));
-	else {
-		gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot"));
-		return false;
-	}
-	if (!PartitionManager.Prepare_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
-		return false;
-	DataManager::SetProgress(.25);
-	gui_msg(Msg("unpacking_image=Unpacking {1}...")(Target_Image));
-	if (!PartitionManager.Prepare_Repack(Target_Image, REPACK_NEW_DIR, true))
-		return false;
-	DataManager::SetProgress(.5);
-	gui_msg(Msg("repacking_image=Repacking {1}...")(part->Display_Name));
-	std::string path = REPACK_NEW_DIR;
-	if (Repack_Options.Type == REPLACE_KERNEL) {
-		// When we replace the kernel, what we really do is copy the boot partition ramdisk into the new image's folder
-		if (TWFunc::copy_file(REPACK_ORIG_DIR "ramdisk.cpio", REPACK_NEW_DIR "ramdisk.cpio", 0644)) {
-			LOGERR("Failed to copy ramdisk\n");
-			return false;
-		}
-	} else if (Repack_Options.Type == REPLACE_RAMDISK) {
-		// Repack the ramdisk
-		if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
-			LOGERR("Failed to copy ramdisk\n");
-			return false;
-		}
-		path = REPACK_ORIG_DIR;
-	} else {
-		LOGERR("Invalid repacking options specified\n");
-		return false;
-	}
-	if (Repack_Options.Disable_Verity)
-		LOGERR("Disabling verity is not implemented yet\n");
-	if (Repack_Options.Disable_Force_Encrypt)
-		LOGERR("Disabling force encrypt is not implemented yet\n");
-	std::string command = "cd " + path + " && /sbin/magiskboot repack " + path + "boot.img";
-	if (TWFunc::Exec_Cmd(command) != 0) {
-		gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
-		return false;
-	}
-	DataManager::SetProgress(.75);
-	std::string file = "new-boot.img";
-	DataManager::SetValue("tw_flash_partition", "/boot;");
-	if (!PartitionManager.Flash_Image(path, file)) {
-		LOGINFO("Error flashing new image\n");
-		return false;
-	}
-	DataManager::SetProgress(1);
-	TWFunc::removeDir(REPACK_ORIG_DIR, false);
-	if (part->SlotSelect && Repack_Options.Type == REPLACE_RAMDISK) {
-		LOGINFO("Switching slots to flash ramdisk to both partitions\n");
-		string Current_Slot = Get_Active_Slot_Display();
-		if (Current_Slot == "A")
-			Set_Active_Slot("B");
-		else
-			Set_Active_Slot("A");
-		DataManager::SetProgress(.25);
-		if (!PartitionManager.Prepare_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
-			return false;
-		if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
-			LOGERR("Failed to copy ramdisk\n");
-			return false;
-		}
-		path = REPACK_ORIG_DIR;
-		command = "cd " + path + " && /sbin/magiskboot repack " + path + "boot.img";
-		if (TWFunc::Exec_Cmd(command) != 0) {
-			gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
-			return false;
-		}
-		DataManager::SetProgress(.75);
-		std::string file = "new-boot.img";
-		DataManager::SetValue("tw_flash_partition", "/boot;");
-		if (!PartitionManager.Flash_Image(path, file)) {
-			LOGINFO("Error flashing new image\n");
-			return false;
-		}
-		DataManager::SetProgress(1);
-		TWFunc::removeDir(REPACK_ORIG_DIR, false);
-		Set_Active_Slot(Current_Slot);
-	}
-	TWFunc::removeDir(REPACK_NEW_DIR, false);
-	return true;
-}
diff --git a/partitions.hpp b/partitions.hpp
index 4510281..dba9be8 100755
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -76,19 +76,6 @@
 	char* fstab_line;
 };
 
-enum Repack_Type {
-	REPLACE_NONE = 0,
-	REPLACE_RAMDISK = 1,
-	REPLACE_KERNEL = 2,
-};
-
-struct Repack_Options_struct {
-	Repack_Type Type;
-	bool Backup_First;
-	bool Disable_Verity;
-	bool Disable_Force_Encrypt;
-};
-
 enum PartitionManager_Op {                                                    // PartitionManager Restore Mode for Raw_Read_Write()
 	PM_BACKUP = 0,
 	PM_RESTORE = 1,
@@ -160,9 +147,12 @@
 	int Decrypt_Adopted();
 	void Revert_Adopted();
 	void Partition_Post_Processing(bool Display_Error);                       // Apply partition specific settings after fstab processed
-	void Set_Backup_FileName(string fname);                                   // Set Backup_FileName for partition
+	void Set_Backup_FileName(string fname);                                   // Set backup filename for partition
+	std::string Get_Backup_FileName();                                        // Get the backup filename for the partition
 	string Get_Backup_Name();                                                 // Get Backup_Name for partition
 	bool Decrypt_FBE_DE();                                                    // If FBE is present, backup exclusions are set up and DE decrypt is attempted
+	std::string Get_Display_Name();                                           // Get the display name in the gui for the partition
+	bool Is_SlotSelect();                                                     // Return whether the partition is a slot partition or not
 
 public:
 	string Current_File_System;                                               // Current file system
@@ -390,9 +380,6 @@
 	void read_uevent();                                                       // Reads uevent data into a buffer
 	void close_uevent();                                                      // Closes the uevent netlink socket
 	void Add_Partition(TWPartition* Part);                                    // Adds a new partition to the Partitions vector
-	bool Prepare_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination, const bool Create_Backup, const std::string& Backup_Name); // Prepares an image for repacking by unpacking it to the temp folder destination
-	bool Prepare_Repack(const std::string& Source_Path, const std::string& Temp_Folder_Destination, const bool Copy_Source, const bool Create_Destination = true); // Prepares an image for repacking by unpacking it to the temp folder destination
-	bool Repack_Images(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options); // Repacks the boot image with a new kernel or a new ramdisk
 	std::vector<users_struct>* Get_Users_List();                              // Returns pointer to list of users
 	int Set_FDE_Encrypt_Status();                                             // Sets encryption state for FDE devices (ro.crypto.state and ro.crypto.type)
 
@@ -415,6 +402,8 @@
 	Backup_Method_enum Backup_Method;                                         // Method used for backup
 	void Mark_User_Decrypted(int userID);                                     // Marks given user ID in Users_List as decrypted
 	void Check_Users_Decryption_Status();                                      // Checks to see if all users are decrypted
+	std::string original_ramdisk_format;                                      // Ramdisk format of boot partition
+	std::string repacked_ramdisk_format;                                      // Ramdisk format of boot image to repack from
 
 private:
 	std::vector<TWPartition*> Partitions;                                     // Vector list of all partitions
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index e77d1eb..983d277 100755
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -66,12 +66,15 @@
 struct selabel_handle *selinux_handle;
 
 /* Execute a command */
-int TWFunc::Exec_Cmd(const string& cmd, string &result) {
+int TWFunc::Exec_Cmd(const string& cmd, string &result, bool combine_stderr) {
 	FILE* exec;
 	char buffer[130];
 	int ret = 0;
-	exec = __popen(cmd.c_str(), "r");
-	if (!exec) return -1;
+	std::string popen_cmd = cmd;
+	if (combine_stderr)
+		popen_cmd = cmd + " 2>&1";
+	exec = __popen(popen_cmd.c_str(), "r");
+
 	while (!feof(exec)) {
 		if (fgets(buffer, 128, exec) != NULL) {
 			result += buffer;
@@ -521,7 +524,7 @@
 		if (type == COMPRESSED) {
 			std::string destFileBuffer;
 			std::string getCompressedContents = "pigz -c -d " + Destination;
-			if (Exec_Cmd(getCompressedContents, destFileBuffer) < 0) {
+			if (Exec_Cmd(getCompressedContents, destFileBuffer, false) < 0) {
 				LOGINFO("Unable to get destination logfile contents.\n");
 				return;
 			}
@@ -1222,7 +1225,7 @@
 	std::string dmesgCmd = "/sbin/dmesg";
 
 	std::string result;
-	Exec_Cmd(dmesgCmd, result);
+	Exec_Cmd(dmesgCmd, result, false);
 	write_to_file(dmesgDst, result);
 	gui_msg(Msg("copy_kernel_log=Copied kernel log to {1}")(dmesgDst));
 	tw_set_default_metadata(dmesgDst.c_str());
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 38cdd3b..cd772e5 100755
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -66,8 +66,8 @@
 	static string Get_Path(const string& Path);                                 // Trims everything after the last / in the string
 	static string Get_Filename(const string& Path);                             // Trims the path off of a filename
 
-	static int Exec_Cmd(const string& cmd, string &result);                     //execute a command and return the result as a string by reference
-	static int Exec_Cmd(const string& cmd, bool Show_Errors = true);                   //execute a command, displays an error to the GUI if Show_Errors is true, Show_Errors is true by default
+ 	static int Exec_Cmd(const string& cmd, string &result, bool combine_stderr);     //execute a command and return the result as a string by reference, set combined_stderror to add stderr
+ 	static int Exec_Cmd(const string& cmd, bool Show_Errors = true);            //execute a command, displays an error to the GUI if Show_Errors is true, Show_Errors is true by default
 	static int Wait_For_Child(pid_t pid, int *status, string Child_Name, bool Show_Errors = true); // Waits for pid to exit and checks exit status, displays an error to the GUI if Show_Errors is true which is the default
 	static int Wait_For_Child_Timeout(pid_t pid, int *status, const string& Child_Name, int timeout); // Waits for a pid to exit until the timeout is hit. If timeout is hit, kill the chilld.
 	static bool Path_Exists(string Path);                                       // Returns true if the path exists
diff --git a/twrpRepacker.cpp b/twrpRepacker.cpp
new file mode 100755
index 0000000..2ee5b7d
--- /dev/null
+++ b/twrpRepacker.cpp
@@ -0,0 +1,249 @@
+/*
+	Copyright 2013 to 2020 TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+
+#include "data.hpp"
+#include "partitions.hpp"
+#include "twrp-functions.hpp"
+#include "twrpRepacker.hpp"
+#include "twcommon.h"
+#include "variables.h"
+#include "gui/gui.hpp"
+
+bool twrpRepacker::Prepare_Empty_Folder(const std::string& Folder) {
+	if (TWFunc::Path_Exists(Folder))
+		TWFunc::removeDir(Folder, false);
+	return TWFunc::Recursive_Mkdir(Folder);
+}
+
+bool twrpRepacker::Backup_Image_For_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination,
+										 const bool Create_Backup, const std::string& Backup_Name) {
+	if (!Part) {
+		LOGERR("Partition was null!\n");
+		return false;
+	}
+	if (!Prepare_Empty_Folder(Temp_Folder_Destination))
+		return false;
+	std::string target_image = Temp_Folder_Destination + "boot.img";
+	PartitionSettings part_settings;
+	part_settings.Part = Part;
+	if (Create_Backup) {
+		if (PartitionManager.Check_Backup_Name(Backup_Name, true, false) != 0)
+			return false;
+		DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder);
+		part_settings.Backup_Folder = part_settings.Backup_Folder + "/" + TWFunc::Get_Current_Date() + " " + Backup_Name + "/";
+		if (!TWFunc::Recursive_Mkdir(part_settings.Backup_Folder))
+			return false;
+	} else
+		part_settings.Backup_Folder = Temp_Folder_Destination;
+	part_settings.adbbackup = false;
+	part_settings.generate_digest = false;
+	part_settings.generate_md5 = false;
+	part_settings.PM_Method = PM_BACKUP;
+	part_settings.progress = NULL;
+	pid_t not_a_pid = 0;
+	if (!Part->Backup(&part_settings, &not_a_pid))
+		return false;
+	std::string backed_up_image = part_settings.Backup_Folder;
+	backed_up_image += Part->Get_Backup_FileName();
+	target_image = Temp_Folder_Destination + "boot.img";
+	if (Create_Backup) {
+		std::string source = part_settings.Backup_Folder + Part->Get_Backup_FileName();
+		if (TWFunc::copy_file(source, target_image, 0644) != 0) {
+			LOGERR("Failed to copy backup file '%s' to temp folder target '%s'\n", source.c_str(), target_image.c_str());
+			return false;
+		}
+	} else {
+		if (rename(backed_up_image.c_str(), target_image.c_str()) != 0) {
+			LOGERR("Failed to rename '%s' to '%s'\n", backed_up_image.c_str(), target_image.c_str());
+			return false;
+		}
+	}
+	original_ramdisk_format = Unpack_Image(target_image, Temp_Folder_Destination, false, false);
+	return !original_ramdisk_format.empty();
+}
+
+std::string twrpRepacker::Unpack_Image(const std::string& Source_Path, const std::string& Temp_Folder_Destination,
+										const bool Copy_Source, const bool Create_Destination) {
+	std::string txt_to_find = "RAMDISK_FMT";
+	if (Create_Destination) {
+		if (!Prepare_Empty_Folder(Temp_Folder_Destination))
+			return std::string();
+	}
+	if (Copy_Source) {
+		std::string destination = Temp_Folder_Destination + "/boot.img";
+		if (TWFunc::copy_file(Source_Path, destination, 0644))
+			return std::string();
+	}
+	std::string command = "cd " + Temp_Folder_Destination + " && /sbin/magiskboot unpack -h ";
+	command = command + "'" + Source_Path +"'";
+
+	std::string magisk_unpack_output;
+	int ret;
+	if ((ret = TWFunc::Exec_Cmd(command, magisk_unpack_output, true)) != 0) {
+		LOGINFO("Error unpacking %s, ret: %d!\n", Source_Path.c_str(), ret);
+		gui_msg(Msg(msg::kError, "unpack_error=Error unpacking image."));
+		return std::string();
+	}
+	size_t pos = magisk_unpack_output.find(txt_to_find) + txt_to_find.size();
+	std::string ramdisk_format = magisk_unpack_output.substr(pos, magisk_unpack_output.size() - 1);
+	ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), '['), ramdisk_format.end());
+	ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), ']'), ramdisk_format.end());
+	ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), ' '), ramdisk_format.end());
+	ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), '\n'), ramdisk_format.end());
+	return ramdisk_format;
+}
+
+bool twrpRepacker::Repack_Image_And_Flash(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options) {
+	bool recompress = false;
+
+	if (!TWFunc::Path_Exists("/sbin/magiskboot")) {
+		LOGERR("Image repacking tool not present in this TWRP build!");
+		return false;
+	}
+	DataManager::SetProgress(0);
+	TWPartition* part = PartitionManager.Find_Partition_By_Path("/boot");
+	if (part)
+		gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Get_Display_Name()));
+	else {
+		gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot"));
+		return false;
+	}
+	if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
+		return false;
+	DataManager::SetProgress(.25);
+	gui_msg(Msg("unpacking_image=Unpacking {1}...")(Target_Image));
+	image_ramdisk_format = Unpack_Image(Target_Image, REPACK_NEW_DIR, true);
+	if (image_ramdisk_format.empty())
+		return false;
+	DataManager::SetProgress(.5);
+	gui_msg(Msg("repacking_image=Repacking {1}...")(part->Get_Display_Name()));
+	std::string path = REPACK_NEW_DIR;
+	if (Repack_Options.Type == REPLACE_KERNEL) {
+		// When we replace the kernel, what we really do is copy the boot partition ramdisk into the new image's folder
+		if (TWFunc::copy_file(REPACK_ORIG_DIR "ramdisk.cpio", REPACK_NEW_DIR "ramdisk.cpio", 0644)) {
+			LOGERR("Failed to copy ramdisk\n");
+			return false;
+		}
+	} else if (Repack_Options.Type == REPLACE_RAMDISK) {
+		// Repack the ramdisk
+		if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
+			LOGERR("Failed to copy ramdisk\n");
+			return false;
+		}
+		path = REPACK_ORIG_DIR;
+	} else {
+		LOGERR("Invalid repacking options specified\n");
+		return false;
+	}
+	if (Repack_Options.Disable_Verity)
+		LOGERR("Disabling verity is not implemented yet\n");
+	if (Repack_Options.Disable_Force_Encrypt)
+		LOGERR("Disabling force encrypt is not implemented yet\n");
+	std::string command = "cd " + path + " && /sbin/magiskboot repack ";
+	if (original_ramdisk_format != image_ramdisk_format) {
+		command = command + "-n ";
+		recompress = true;
+	}
+
+	command += path + "boot.img";
+
+	std::string orig_compressed_image(REPACK_ORIG_DIR);
+	orig_compressed_image += "ramdisk.cpio";
+	std::string copy_compressed_image(REPACK_ORIG_DIR);
+	copy_compressed_image += "ramdisk-1.cpio";
+
+	if (recompress) {
+		std::string compress_cmd = "/sbin/magiskboot compress=" + image_ramdisk_format + " " + orig_compressed_image + " " + copy_compressed_image;
+		if (TWFunc::Exec_Cmd(compress_cmd) != 0) {
+			gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
+			return false;
+		}
+		std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
+	}
+
+	if (TWFunc::Exec_Cmd(command) != 0) {
+		gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
+		return false;
+	}
+
+	DataManager::SetProgress(.75);
+	std::string file = "new-boot.img";
+	DataManager::SetValue("tw_flash_partition", "/boot;");
+	if (!PartitionManager.Flash_Image(path, file)) {
+		LOGINFO("Error flashing new image\n");
+		return false;
+	}
+	DataManager::SetProgress(1);
+	TWFunc::removeDir(REPACK_ORIG_DIR, false);
+	if (part->Is_SlotSelect() && Repack_Options.Type == REPLACE_RAMDISK) {
+		LOGINFO("Switching slots to flash ramdisk to both partitions\n");
+		string Current_Slot = PartitionManager.Get_Active_Slot_Display();
+		if (Current_Slot == "A")
+			PartitionManager.Set_Active_Slot("B");
+		else
+			PartitionManager.Set_Active_Slot("A");
+		DataManager::SetProgress(.25);
+		if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
+			return false;
+		if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
+			LOGERR("Failed to copy ramdisk\n");
+			return false;
+		}
+		path = REPACK_ORIG_DIR;
+		std::string command = "cd " + path + " && /sbin/magiskboot repack ";
+
+		if (original_ramdisk_format != image_ramdisk_format) {
+			command = command + "-n ";
+			recompress = true;
+		}
+		command += path + "boot.img";
+
+		if (recompress) {
+			std::string compress_cmd = "/sbin/magiskboot compress=" + image_ramdisk_format + " " + orig_compressed_image + " " + copy_compressed_image;
+			if (TWFunc::Exec_Cmd(compress_cmd) != 0) {
+				gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
+				return false;
+			}
+			std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
+		}
+
+		if (TWFunc::Exec_Cmd(command) != 0) {
+			gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
+			return false;
+		}
+
+		if (TWFunc::Exec_Cmd(command) != 0) {
+			gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
+			return false;
+		}
+		DataManager::SetProgress(.75);
+		std::string file = "new-boot.img";
+		DataManager::SetValue("tw_flash_partition", "/boot;");
+		if (!PartitionManager.Flash_Image(path, file)) {
+			LOGINFO("Error flashing new image\n");
+			return false;
+		}
+		DataManager::SetProgress(1);
+		TWFunc::removeDir(REPACK_ORIG_DIR, false);
+		PartitionManager.Set_Active_Slot(Current_Slot);
+	}
+	TWFunc::removeDir(REPACK_NEW_DIR, false);
+	return true;
+}
diff --git a/twrpRepacker.hpp b/twrpRepacker.hpp
new file mode 100755
index 0000000..346229b
--- /dev/null
+++ b/twrpRepacker.hpp
@@ -0,0 +1,48 @@
+/*

+	Copyright 2014 to 2020 TeamWin

+	This file is part of TWRP/TeamWin Recovery Project.

+

+	TWRP is free software: you can redistribute it and/or modify

+	it under the terms of the GNU General Public License as published by

+	the Free Software Foundation, either version 3 of the License, or

+	(at your option) any later version.

+

+	TWRP is distributed in the hope that it will be useful,

+	but WITHOUT ANY WARRANTY; without even the implied warranty of

+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+	GNU General Public License for more details.

+

+	You should have received a copy of the GNU General Public License

+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.

+*/

+

+#include <string>

+#include "partitions.hpp"

+

+#ifndef TWRP_REPACKER

+#define TWRP_REPACKER

+

+enum Repack_Type {

+	REPLACE_NONE = 0,

+	REPLACE_RAMDISK = 1,

+	REPLACE_KERNEL = 2,

+};

+

+struct Repack_Options_struct {

+	Repack_Type Type;

+	bool Backup_First;

+	bool Disable_Verity;

+	bool Disable_Force_Encrypt;

+};

+

+class twrpRepacker {

+    public:

+        bool Backup_Image_For_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination, const bool Create_Backup, const std::string& Backup_Name); // Prepares an image for repacking by unpacking it to the temp folder destination

+        std::string Unpack_Image(const std::string& Source_Path, const std::string& Temp_Folder_Destination, const bool Copy_Source, const bool Create_Destination = true); // Prepares an image for repacking by unpacking it to the temp folder destination and return the ramdisk format

+        bool Repack_Image_And_Flash(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options); // Repacks the boot image with a new kernel or a new ramdisk

+    private:

+    	bool Prepare_Empty_Folder(const std::string& Folder); // Creates an empty folder at Folder. If the folder already exists, the folder is deleted, then created

+    	std::string original_ramdisk_format;                  // Ramdisk format of boot partition

+	    std::string image_ramdisk_format;                     // Ramdisk format of boot image to repack from

+};

+#endif // TWRP_REPACKER
\ No newline at end of file
diff --git a/twrpTar.cpp b/twrpTar.cpp
index b2d0ea6..94667a5 100644
--- a/twrpTar.cpp
+++ b/twrpTar.cpp
@@ -1471,7 +1471,7 @@
 		Command = "pigz -l '" + filename + "'";
 		/* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
 		we get the uncompressed size at once. */
-		TWFunc::Exec_Cmd(Command, result);
+		TWFunc::Exec_Cmd(Command, result, false);
 		if (!result.empty()) {
 			/* Expected output:
 			compressed original  reduced name
@@ -1496,7 +1496,7 @@
 			Command = "openaes dec --key \"" + password + "\" --in '" + filename + "' | pigz -l";
 			/* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
 			we get the uncompressed size at once. */
-			TWFunc::Exec_Cmd(Command, result);
+			TWFunc::Exec_Cmd(Command, result, false);
 			if (!result.empty()) {
 				LOGINFO("result was: '%s'\n", result.c_str());
 				/* Expected output: