Support encrypted backup files

Also includes features merged from:

Update twrpTar by kokotas

Revised function entryExists().
Added function to get archive's uncompressed size.
Added option to exclude item(s) from the archive.
Revised forks()

http://review.teamw.in/#/c/590/

Change-Id: I01fa2c81643161984eff2625247af75990684bd9
diff --git a/partition.cpp b/partition.cpp
index 4405536..7b687e7 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -87,6 +87,8 @@
 	Backup_FileName = "";
 	MTD_Name = "";
 	Backup_Method = NONE;
+	Can_Encrypt_Backup = false;
+	Use_Userdata_Encryption = false;
 	Has_Data_Media = false;
 	Has_Android_Secure = false;
 	Is_Storage = false;
@@ -210,6 +212,8 @@
 			Wipe_Available_in_GUI = true;
 			Wipe_During_Factory_Reset = true;
 			Can_Be_Backed_Up = true;
+			Can_Encrypt_Backup = true;
+			Use_Userdata_Encryption = true;
 #ifdef RECOVERY_SDCARD_ON_DATA
 			Storage_Name = "Internal Storage";
 			Has_Data_Media = true;
@@ -287,6 +291,8 @@
 			SubPartition_Of = "/data";
 			DataManager::SetValue(TW_HAS_DATADATA, 1);
 			Can_Be_Backed_Up = true;
+			Can_Encrypt_Backup = true;
+			Use_Userdata_Encryption = false; // This whole partition should be encrypted
 		} else if (Mount_Point == "/sd-ext") {
 			Wipe_During_Factory_Reset = true;
 			Display_Name = "SD-Ext";
@@ -295,6 +301,8 @@
 			Wipe_Available_in_GUI = true;
 			Removable = true;
 			Can_Be_Backed_Up = true;
+			Can_Encrypt_Backup = true;
+			Use_Userdata_Encryption = true;
 		} else if (Mount_Point == "/boot") {
 			Display_Name = "Boot";
 			Backup_Display_Name = Display_Name;
@@ -445,6 +453,20 @@
 		} else if (ptr_len > 7 && strncmp(ptr, "length=", 7) == 0) {
 			ptr += 7;
 			Length = atoi(ptr);
+		} else if (ptr_len > 17 && strncmp(ptr, "canencryptbackup=", 17) == 0) {
+			ptr += 17;
+			if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y')
+				Can_Encrypt_Backup = true;
+			else
+				Can_Encrypt_Backup = false;
+		} else if (ptr_len > 21 && strncmp(ptr, "userdataencryptbackup=", 21) == 0) {
+			ptr += 21;
+			if (*ptr == '1' || *ptr == 'y' || *ptr == 'Y') {
+				Can_Encrypt_Backup = true;
+				Use_Userdata_Encryption = true;
+			} else {
+				Use_Userdata_Encryption = false;
+			}
 		} else {
 			if (Display_Error)
 				LOGERR("Unhandled flag: '%s'\n", ptr);
@@ -1046,8 +1068,8 @@
 			return false;
 		}
 		md5sum.setfn(split_filename);
-		while (index < 1000 && TWFunc::Path_Exists(split_filename)) {
-			if (md5sum.verify_md5digest() != 0) {
+		while (index < 1000) {
+			if (TWFunc::Path_Exists(split_filename) && md5sum.verify_md5digest() != 0) {
 				LOGERR("MD5 failed to match on '%s'.\n", split_filename);
 				return false;
 			}
@@ -1370,7 +1392,7 @@
 bool TWPartition::Backup_Tar(string backup_folder) {
 	char back_name[255], split_index[5];
 	string Full_FileName, Split_FileName, Tar_Args, Command;
-	int use_compression, index, backup_count;
+	int use_compression, use_encryption = 0, index, backup_count;
 	struct stat st;
 	unsigned long long total_bsize = 0, file_size;
 	twrpTar tar;
@@ -1383,11 +1405,23 @@
 	gui_print("Backing up %s...\n", Backup_Display_Name.c_str());
 
 	DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
+	tar.use_compression = use_compression;
+#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
+	DataManager::GetValue("tw_encrypt_backup", use_encryption);
+	if (use_encryption && Can_Encrypt_Backup) {
+		tar.use_encryption = use_encryption;
+		if (Use_Userdata_Encryption)
+			tar.userdata_encryption = use_encryption;
+	} else {
+		use_encryption = false;
+	}
+#endif
 
 	sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
 	Backup_FileName = back_name;
 	Full_FileName = backup_folder + "/" + Backup_FileName;
-	 if (Backup_Size > MAX_ARCHIVE_SIZE) {
+	tar.has_data_media = Has_Data_Media;
+	if (!use_encryption && Backup_Size > MAX_ARCHIVE_SIZE) {
 		// This backup needs to be split into multiple archives
 		gui_print("Breaking backup file into multiple archives...\n");
 		sprintf(back_name, "%s", Backup_Path.c_str());
@@ -1401,20 +1435,16 @@
 		return true;
 	} else {
 		Full_FileName = backup_folder + "/" + Backup_FileName;
-		if (use_compression) {
-			tar.setdir(Backup_Path);
-			tar.setfn(Full_FileName);
-			if (tar.createTarGZFork() != 0)
-				return -1;
+		tar.setdir(Backup_Path);
+		tar.setfn(Full_FileName);
+		if (tar.createTarFork() != 0)
+			return false;
+		if (use_compression && !use_encryption) {
 			string gzname = Full_FileName + ".gz";
 			rename(gzname.c_str(), Full_FileName.c_str());
 		}
-		else {
-			tar.setdir(Backup_Path);
-			tar.setfn(Full_FileName);
-			if (tar.createTarFork() != 0)
-				return -1;
-		}
+		if (use_encryption)
+			Full_FileName += "000";
 		if (TWFunc::Get_File_Size(Full_FileName) == 0) {
 			LOGERR("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str());
 			return false;
@@ -1493,7 +1523,7 @@
 		return false;
 
 	Full_FileName = restore_folder + "/" + Backup_FileName;
-	if (!TWFunc::Path_Exists(Full_FileName)) {
+	/*if (!TWFunc::Path_Exists(Full_FileName)) {
 		if (!TWFunc::Path_Exists(Full_FileName)) {
 			// Backup is multiple archives
 			LOGINFO("Backup is multiple archives.\n");
@@ -1516,13 +1546,14 @@
 				return false;
 			}
 		}
-	} else {
+	} else {*/
 		twrpTar tar;
 		tar.setdir(Backup_Path);
 		tar.setfn(Full_FileName);
+		tar.backup_name = Backup_Name;
 		if (tar.extractTarFork() != 0)
 			return false;
-	}
+	//}
 	return true;
 }