ADB: Add adb backup for TWRP.

Functionality for client side to backup
tar and image streams over adbd to the client under backup.ab.

Using adb backup on the client side you can backup the partitions
TWRP knows about.

On the client side you can do the following:
adb backup -f <filename> --twrp <options> where options are
--compress: compress data
system: backup system
cache: backup cache
data: backup data
boot: backup boot
etc for each partition.

You can string multiple options,
i.e. adb backup -f <filename> --twrp --compress cache system data

adb backup in TWRP will take any option corresponding
to TWRP fstab partitions, e.g. efs boot as well.

If you do not specify the filename with the -f option,
adb will backup your data to a filename backup.ab on the client.
You can then rename the file and encrypt it with desktop tools.

If you don't want to use command line arguments:
adb backup --twrp

will bring up the gui and allow you to choose partitions
from the backup page.

To restore the backup use the following convention:
adb restore <filename>

Structures are used to store metadata in binary inside
of the file itself. If the metadata structure is modified,
update the adb version so that it will invalidate older
backups and not cause issues on restore. When restoring,
we currently do not support picking specific partitions.
It's all or nothing.

Change-Id: Idb92c37fc9801dc8d89ed2a4570e9d12e76facf8
diff --git a/partition.cpp b/partition.cpp
index 1261a2a..bf87de3 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <dirent.h>
 #include <libgen.h>
+#include <zlib.h>
 #include <iostream>
 #include <sstream>
 #include <sys/param.h>
@@ -46,6 +47,7 @@
 #include "infomanager.hpp"
 #include "set_metadata.h"
 #include "gui/gui.hpp"
+#include "adbbu/libtwadbbu.hpp"
 extern "C" {
 	#include "mtdutils/mtdutils.h"
 	#include "mtdutils/mounts.h"
@@ -208,7 +210,7 @@
 	Backup_Name = "";
 	Backup_FileName = "";
 	MTD_Name = "";
-	Backup_Method = NONE;
+	Backup_Method = BM_NONE;
 	Can_Encrypt_Backup = false;
 	Use_Userdata_Encryption = false;
 	Has_Data_Media = false;
@@ -801,16 +803,16 @@
 	Make_Dir(Mount_Point, Display_Error);
 	Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
 	Backup_Name = Display_Name;
-	Backup_Method = FILES;
+	Backup_Method = BM_FILES;
 }
 
 void TWPartition::Setup_Image(bool Display_Error) {
 	Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
 	Backup_Name = Display_Name;
 	if (Current_File_System == "emmc")
-		Backup_Method = DD;
+		Backup_Method = BM_DD;
 	else if (Current_File_System == "mtd" || Current_File_System == "bml")
-		Backup_Method = FLASH_UTILS;
+		Backup_Method = BM_FLASH_UTILS;
 	else
 		LOGINFO("Unhandled file system '%s' on image '%s'\n", Current_File_System.c_str(), Display_Name.c_str());
 	if (Find_Partition_Size()) {
@@ -1598,14 +1600,13 @@
 	return false;
 }
 
-bool TWPartition::Backup(const string& backup_folder, pid_t &tar_fork_pid, ProgressTracking *progress) {
-	if (Backup_Method == FILES) {
-		return Backup_Tar(backup_folder, progress, tar_fork_pid);
-	}
-	else if (Backup_Method == DD)
-		return Backup_Image(backup_folder, progress);
-	else if (Backup_Method == FLASH_UTILS)
-		return Backup_Dump_Image(backup_folder, progress);
+bool TWPartition::Backup(PartitionSettings *part_settings, pid_t *tar_fork_pid) {
+	if (Backup_Method == BM_FILES)
+		return Backup_Tar(part_settings, tar_fork_pid);
+	else if (Backup_Method == BM_DD)
+		return Backup_Image(part_settings);
+	else if (Backup_Method == BM_FLASH_UTILS)
+		return Backup_Dump_Image(part_settings);
 	LOGERR("Unknown backup method for '%s'\n", Mount_Point.c_str());
 	return false;
 }
@@ -1658,53 +1659,49 @@
 	return false;
 }
 
-bool TWPartition::Restore(const string& restore_folder, ProgressTracking *progress) {
-	string Restore_File_System;
-
+bool TWPartition::Restore(PartitionSettings *part_settings) {
 	TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, gui_parse_text("{@restoring_hdr}"));
-	LOGINFO("Restore filename is: %s\n", Backup_FileName.c_str());
+	LOGINFO("Restore filename is: %s/%s\n", part_settings->Restore_Name.c_str(), part_settings->Backup_FileName.c_str());
 
-	Restore_File_System = Get_Restore_File_System(restore_folder);
+	string Restore_File_System = Get_Restore_File_System(part_settings);
 
 	if (Is_File_System(Restore_File_System))
-		return Restore_Tar(restore_folder, Restore_File_System, progress);
-	else if (Is_Image(Restore_File_System)) {
-		return Restore_Image(restore_folder, Restore_File_System, progress);
-	}
+		return Restore_Tar(part_settings);
+	else if (Is_Image(Restore_File_System))
+		return Restore_Image(part_settings);
 
 	LOGERR("Unknown restore method for '%s'\n", Mount_Point.c_str());
 	return false;
 }
 
-string TWPartition::Get_Restore_File_System(const string& restore_folder) {
+string TWPartition::Get_Restore_File_System(PartitionSettings *part_settings) {
 	size_t first_period, second_period;
 	string Restore_File_System;
 
 	// Parse backup filename to extract the file system before wiping
-	first_period = Backup_FileName.find(".");
+	first_period = part_settings->Backup_FileName.find(".");
 	if (first_period == string::npos) {
 		LOGERR("Unable to find file system (first period).\n");
 		return string();
 	}
-	Restore_File_System = Backup_FileName.substr(first_period + 1, Backup_FileName.size() - first_period - 1);
+	Restore_File_System = part_settings->Backup_FileName.substr(first_period + 1, part_settings->Backup_FileName.size() - first_period - 1);
 	second_period = Restore_File_System.find(".");
 	if (second_period == string::npos) {
 		LOGERR("Unable to find file system (second period).\n");
 		return string();
 	}
 	Restore_File_System.resize(second_period);
-	LOGINFO("Restore file system is: '%s'.\n", Restore_File_System.c_str());
 	return Restore_File_System;
 }
 
 string TWPartition::Backup_Method_By_Name() {
-	if (Backup_Method == NONE)
+	if (Backup_Method == BM_NONE)
 		return "none";
-	else if (Backup_Method == FILES)
+	else if (Backup_Method == BM_FILES)
 		return "files";
-	else if (Backup_Method == DD)
+	else if (Backup_Method == BM_DD)
 		return "dd";
-	else if (Backup_Method == FLASH_UTILS)
+	else if (Backup_Method == BM_FLASH_UTILS)
 		return "flash_utils";
 	else
 		return "undefined";
@@ -2141,7 +2138,7 @@
 	return false;
 }
 
-bool TWPartition::Backup_Tar(const string& backup_folder, ProgressTracking *progress, pid_t &tar_fork_pid) {
+bool TWPartition::Backup_Tar(PartitionSettings *part_settings, pid_t *tar_fork_pid) {
 	string Full_FileName;
 	twrpTar tar;
 
@@ -2169,72 +2166,114 @@
 #endif
 
 	Backup_FileName = Backup_Name + "." + Current_File_System + ".win";
-	Full_FileName = backup_folder + "/" + Backup_FileName;
+	Full_FileName = part_settings->Full_Backup_Path + Backup_FileName;
 	tar.has_data_media = Has_Data_Media;
-	Full_FileName = backup_folder + "/" + Backup_FileName;
+	tar.part_settings = part_settings;
 	tar.setdir(Backup_Path);
 	tar.setfn(Full_FileName);
 	tar.setsize(Backup_Size);
 	tar.partition_name = Backup_Name;
-	tar.backup_folder = backup_folder;
-	if (tar.createTarFork(progress, tar_fork_pid) != 0)
+	tar.backup_folder = part_settings->Full_Backup_Path;
+	if (tar.createTarFork(tar_fork_pid) != 0)
 		return false;
 	return true;
 }
 
-bool TWPartition::Backup_Image(const string& backup_folder, ProgressTracking *progress) {
-	string Full_FileName;
+bool TWPartition::Backup_Image(PartitionSettings *part_settings) {
+	string Full_FileName, adb_file_name;
+	int adb_control_bu_fd, compressed;
 
 	TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, gui_parse_text("{@backing}"));
 	gui_msg(Msg("backing_up=Backing up {1}...")(Backup_Display_Name));
 
 	Backup_FileName = Backup_Name + "." + Current_File_System + ".win";
-	Full_FileName = backup_folder + "/" + Backup_FileName;
 
-	if (!Raw_Read_Write(Actual_Block_Device, Full_FileName, Backup_Size, progress))
+	if (part_settings->adbbackup) {
+		Full_FileName = TW_ADB_BACKUP;
+		adb_file_name  = part_settings->Full_Backup_Path + "/" + Backup_FileName;
+	}
+	else
+		Full_FileName = part_settings->Full_Backup_Path + "/" + Backup_FileName;
+
+	part_settings->total_restore_size = Backup_Size;
+
+	if (part_settings->adbbackup) {
+		if (!twadbbu::Write_TWIMG(adb_file_name, Backup_Size))
+			return false;
+	}
+
+	if (!Raw_Read_Write(part_settings))
 		return false;
 
-	tw_set_default_metadata(Full_FileName.c_str());
-	if (TWFunc::Get_File_Size(Full_FileName) == 0) {
-		gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(Full_FileName));
-		return false;
+	if (part_settings->adbbackup) {
+		if (!twadbbu::Write_TWEOF())
+			return false;
 	}
 	return true;
 }
 
-bool TWPartition::Raw_Read_Write(const string& input_file, const string& output_file, const unsigned long long input_size, ProgressTracking *progress) {
-	unsigned long long RW_Block_Size, Remain;
-	int src_fd = -1, dest_fd = -1, bs;
+bool TWPartition::Raw_Read_Write(PartitionSettings *part_settings) {
+	unsigned long long RW_Block_Size, Remain = Backup_Size;
+	int src_fd = -1, dest_fd = -1;
+	ssize_t bs;
 	bool ret = false;
 	void* buffer = NULL;
 	unsigned long long backedup_size = 0;
+	string srcfn, destfn;
 
-	RW_Block_Size = 1048576LLU; // 1MB
-	Remain = input_size;
+	if (part_settings->PM_Method == PM_BACKUP) {
+		srcfn = Actual_Block_Device;
+		if (part_settings->adbbackup)
+			destfn = TW_ADB_BACKUP;
+		else
+			destfn = part_settings->Full_Backup_Path + part_settings->Backup_FileName;
+	}
+	else {
+		destfn = Actual_Block_Device;
+		if (part_settings->adbbackup) {
+			srcfn = TW_ADB_RESTORE;
+		} else {
+			srcfn = part_settings->Restore_Name + "/" + part_settings->Backup_FileName;
+			Remain = TWFunc::Get_File_Size(srcfn);
+		}
+	}
 
-	src_fd = open(input_file.c_str(), O_RDONLY | O_LARGEFILE);
+	src_fd = open(srcfn.c_str(), O_RDONLY | O_LARGEFILE);
 	if (src_fd < 0) {
-		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(input_file)(strerror(errno)));
+		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(srcfn.c_str())(strerror(errno)));
 		return false;
 	}
-	dest_fd = open(output_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR);
+
+	dest_fd = open(destfn.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR);
 	if (dest_fd < 0) {
-		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(output_file)(strerror(errno)));
+		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(destfn.c_str())(strerror(errno)));
 		goto exit;
 	}
-	bs = (int)(RW_Block_Size);
+	
+	LOGINFO("Reading '%s', writing '%s'\n", srcfn.c_str(), destfn.c_str());
+
+	if (part_settings->adbbackup) {
+		RW_Block_Size = MAX_ADB_READ;
+		bs = MAX_ADB_READ;
+	}
+	else {
+		RW_Block_Size = 1048576LLU; // 1MB
+		bs = (ssize_t)(RW_Block_Size);
+	}
+
 	buffer = malloc((size_t)bs);
 	if (!buffer) {
 		LOGINFO("Raw_Read_Write failed to malloc\n");
 		goto exit;
 	}
-	LOGINFO("Reading '%s', writing '%s'\n", input_file.c_str(), output_file.c_str());
-	if (progress)
-		progress->SetPartitionSize(input_size);
+
+	if (part_settings->progress)
+		part_settings->progress->SetPartitionSize(part_settings->total_restore_size);
+
 	while (Remain > 0) {
 		if (Remain < RW_Block_Size)
-			bs = (int)(Remain);
-		if (read(src_fd, buffer, bs) != bs) {
+			bs = (ssize_t)(Remain);
+		if (read(src_fd,  buffer, bs) != bs) {
 			LOGINFO("Error reading source fd (%s)\n", strerror(errno));
 			goto exit;
 		}
@@ -2243,14 +2282,14 @@
 			goto exit;
 		}
 		backedup_size += (unsigned long long)(bs);
-		Remain -= (unsigned long long)(bs);
-		if (progress)
-			progress->UpdateSize(backedup_size);
+		Remain = Remain - (unsigned long long)(bs);
+		if (part_settings->progress)
+			part_settings->progress->UpdateSize(backedup_size);
 		if (PartitionManager.Check_Backup_Cancel() != 0)
 			goto exit;
 	}
-	if (progress)
-		progress->UpdateDisplayDetails(true);
+	if (part_settings->progress)
+		part_settings->progress->UpdateDisplayDetails(true);
 	fsync(dest_fd);
 	ret = true;
 exit:
@@ -2263,19 +2302,22 @@
 	return ret;
 }
 
-bool TWPartition::Backup_Dump_Image(const string& backup_folder, ProgressTracking *progress) {
+bool TWPartition::Backup_Dump_Image(PartitionSettings *part_settings) {
 	string Full_FileName, Command;
+	int use_compression, adb_control_bu_fd;
+	unsigned long long compressed;
 
 	TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, gui_parse_text("{@backing}"));
 	gui_msg(Msg("backing_up=Backing up {1}...")(Backup_Display_Name));
 
-	if (progress)
-		progress->SetPartitionSize(Backup_Size);
+	if (part_settings->progress)
+		part_settings->progress->SetPartitionSize(Backup_Size);
 
 	Backup_FileName = Backup_Name + "." + Current_File_System + ".win";
-	Full_FileName = backup_folder + "/" + Backup_FileName;
+	Full_FileName = part_settings->Full_Backup_Path + "/" + Backup_FileName;
 
 	Command = "dump_image " + MTD_Name + " '" + Full_FileName + "'";
+
 	LOGINFO("Backup command: '%s'\n", Command.c_str());
 	TWFunc::Exec_Cmd(Command);
 	tw_set_default_metadata(Full_FileName.c_str());
@@ -2284,23 +2326,26 @@
 		gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(Full_FileName));
 		return false;
 	}
-	if (progress)
-		progress->UpdateSize(Backup_Size);
+	if (part_settings->progress)
+		part_settings->progress->UpdateSize(Backup_Size);
+
 	return true;
 }
 
-unsigned long long TWPartition::Get_Restore_Size(const string& restore_folder) {
-	InfoManager restore_info(restore_folder + "/" + Backup_Name + ".info");
-	if (restore_info.LoadValues() == 0) {
-		if (restore_info.GetValue("backup_size", Restore_Size) == 0) {
-			LOGINFO("Read info file, restore size is %llu\n", Restore_Size);
-			return Restore_Size;
+unsigned long long TWPartition::Get_Restore_Size(PartitionSettings *part_settings) {
+	if (!part_settings->adbbackup) {
+		InfoManager restore_info(part_settings->Restore_Name + "/" + Backup_Name + ".info");
+		if (restore_info.LoadValues() == 0) {
+			if (restore_info.GetValue("backup_size", Restore_Size) == 0) {
+				LOGINFO("Read info file, restore size is %llu\n", Restore_Size);
+				return Restore_Size;
+			}
 		}
 	}
-	string Full_FileName, Restore_File_System = Get_Restore_File_System(restore_folder);
 
-	Full_FileName = restore_folder + "/" + Backup_FileName;
+	string Full_FileName, Restore_File_System = Get_Restore_File_System(part_settings);
 
+	Full_FileName = part_settings->Restore_Name + "/" + Backup_FileName;
 	if (Is_Image(Restore_File_System)) {
 		Restore_Size = TWFunc::Get_File_Size(Full_FileName);
 		return Restore_Size;
@@ -2309,7 +2354,7 @@
 	twrpTar tar;
 	tar.setdir(Backup_Path);
 	tar.setfn(Full_FileName);
-	tar.backup_name = Backup_Name;
+	tar.backup_name = Full_FileName;
 #ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
 	string Password;
 	DataManager::GetValue("tw_restore_password", Password);
@@ -2317,14 +2362,16 @@
 		tar.setpassword(Password);
 #endif
 	tar.partition_name = Backup_Name;
-	tar.backup_folder = restore_folder;
+	tar.backup_folder = part_settings->Restore_Name;
+	tar.part_settings = part_settings;
 	Restore_Size = tar.get_size();
 	return Restore_Size;
 }
 
-bool TWPartition::Restore_Tar(const string& restore_folder, const string& Restore_File_System, ProgressTracking *progress) {
+bool TWPartition::Restore_Tar(PartitionSettings *part_settings) {
 	string Full_FileName;
 	bool ret = false;
+	string Restore_File_System = Get_Restore_File_System(part_settings);
 
 	if (Has_Android_Secure) {
 		if (!Wipe_AndSec())
@@ -2347,8 +2394,9 @@
 	if (!ReMount_RW(true))
 		return false;
 
-	Full_FileName = restore_folder + "/" + Backup_FileName;
+	Full_FileName = part_settings->Restore_Name + "/" + part_settings->Backup_FileName;
 	twrpTar tar;
+	tar.part_settings = part_settings;
 	tar.setdir(Backup_Path);
 	tar.setfn(Full_FileName);
 	tar.backup_name = Backup_Name;
@@ -2358,8 +2406,8 @@
 	if (!Password.empty())
 		tar.setpassword(Password);
 #endif
-	progress->SetPartitionSize(Get_Restore_Size(restore_folder));
-	if (tar.extractTarFork(progress) != 0)
+	part_settings->progress->SetPartitionSize(Get_Restore_Size(part_settings));
+	if (tar.extractTarFork() != 0)
 		ret = false;
 	else
 		ret = true;
@@ -2389,19 +2437,30 @@
 	return ret;
 }
 
-bool TWPartition::Restore_Image(const string& restore_folder, const string& Restore_File_System, ProgressTracking *progress) {
+bool TWPartition::Restore_Image(PartitionSettings *part_settings) {
 	string Full_FileName;
+	string Restore_File_System = Get_Restore_File_System(part_settings);
 
 	TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Backup_Display_Name, gui_parse_text("{@restoring_hdr}"));
 	gui_msg(Msg("restoring=Restoring {1}...")(Backup_Display_Name));
-	Full_FileName = restore_folder + "/" + Backup_FileName;
+
+	if (part_settings->adbbackup)
+		Full_FileName = TW_ADB_RESTORE;
+	else
+		Full_FileName = part_settings->Full_Backup_Path + part_settings->Backup_FileName;
 
 	if (Restore_File_System == "emmc") {
-		unsigned long long file_size = (unsigned long long)(TWFunc::Get_File_Size(Full_FileName));
-		if (!Raw_Read_Write(Full_FileName, Actual_Block_Device, file_size, progress))
+		if (!part_settings->adbbackup)
+			part_settings->total_restore_size = (uint64_t)(TWFunc::Get_File_Size(Full_FileName));
+		if (!Raw_Read_Write(part_settings))
 			return false;
 	} else if (Restore_File_System == "mtd" || Restore_File_System == "bml") {
-		if (!Flash_Image_FI(Full_FileName, progress))
+		if (!Flash_Image_FI(Full_FileName, part_settings->progress))
+			return false;
+	}
+
+	if (part_settings->adbbackup) {
+		if (!twadbbu::Write_TWEOF())
 			return false;
 	}
 	return true;
@@ -2544,12 +2603,14 @@
 	return maxFileSize - 1;
 }
 
-bool TWPartition::Flash_Image(const string& Filename) {
-	string Restore_File_System;
+bool TWPartition::Flash_Image(PartitionSettings *part_settings) {
+	string Restore_File_System, full_filename;
 
-	LOGINFO("Image filename is: %s\n", Filename.c_str());
+	full_filename = part_settings->Restore_Name + "/" + part_settings->Backup_FileName;
 
-	if (Backup_Method == FILES) {
+	LOGINFO("Image filename is: %s\n", part_settings->Backup_FileName.c_str());
+
+	if (Backup_Method == BM_FILES) {
 		LOGERR("Cannot flash images to file systems\n");
 		return false;
 	} else if (!Can_Flash_Img) {
@@ -2560,22 +2621,23 @@
 			LOGERR("Unable to find partition size for '%s'\n", Mount_Point.c_str());
 			return false;
 		}
-		unsigned long long image_size = TWFunc::Get_File_Size(Filename);
+		unsigned long long image_size = TWFunc::Get_File_Size(full_filename);
 		if (image_size > Size) {
 			LOGINFO("Size (%llu bytes) of image '%s' is larger than target device '%s' (%llu bytes)\n",
-				image_size, Filename.c_str(), Actual_Block_Device.c_str(), Size);
+				image_size, part_settings->Backup_FileName.c_str(), Actual_Block_Device.c_str(), Size);
 			gui_err("img_size_err=Size of image is larger than target device");
 			return false;
 		}
-		if (Backup_Method == DD) {
-			if (Is_Sparse_Image(Filename)) {
-				return Flash_Sparse_Image(Filename);
+		if (Backup_Method == BM_DD) {
+			if (!part_settings->adbbackup) {
+				if (Is_Sparse_Image(full_filename)) {
+					return Flash_Sparse_Image(full_filename);
+				}
 			}
-			unsigned long long file_size = (unsigned long long)(TWFunc::Get_File_Size(Filename));
-			ProgressTracking pt(file_size);
-			return Raw_Read_Write(Filename, Actual_Block_Device, file_size, &pt);
-		} else if (Backup_Method == FLASH_UTILS) {
-			return Flash_Image_FI(Filename, NULL);
+			unsigned long long file_size = (unsigned long long)(TWFunc::Get_File_Size(full_filename));
+			return Raw_Read_Write(part_settings);
+		} else if (Backup_Method == BM_FLASH_UTILS) {
+			return Flash_Image_FI(full_filename, NULL);
 		}
 	}
 
@@ -2590,6 +2652,7 @@
 		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(Filename)(strerror(errno)));
 		return false;
 	}
+
 	if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) {
 		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(Filename)(strerror(errno)));
 		close(fd);
@@ -2637,6 +2700,10 @@
 	Mount_Read_Only = new_value;
 }
 
+bool TWPartition::Is_Read_Only() {
+	return Mount_Read_Only;
+}
+
 int TWPartition::Check_Lifetime_Writes() {
 	bool original_read_only = Mount_Read_Only;
 	int ret = 1;