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/Android.mk b/Android.mk
index 6ee7889..67e504f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -100,7 +100,8 @@
     system/vold \
     system/extras/ext4_utils \
     system/core/adb \
-    system/core/libsparse
+    system/core/libsparse \
+    external/zlib
 
 LOCAL_C_INCLUDES += bionic external/openssl/include $(LOCAL_PATH)/libmincrypt/includes
 ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
@@ -111,7 +112,7 @@
 LOCAL_SHARED_LIBRARIES :=
 
 LOCAL_STATIC_LIBRARIES += libguitwrp
-LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery
+LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery libtwadbbu
 LOCAL_SHARED_LIBRARIES += libcrecovery
 
 ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
@@ -588,6 +589,7 @@
     $(commands_recovery_local_path)/etc/Android.mk \
     $(commands_recovery_local_path)/toybox/Android.mk \
     $(commands_recovery_local_path)/simg2img/Android.mk \
+    $(commands_recovery_local_path)/adbbu/Android.mk \
     $(commands_recovery_local_path)/libpixelflinger/Android.mk
 
 ifeq ($(TW_INCLUDE_CRYPTO), true)
diff --git a/adbbu/Android.mk b/adbbu/Android.mk
new file mode 100644
index 0000000..65568ef
--- /dev/null
+++ b/adbbu/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	twrpback.cpp \
+	../twrpDigest.cpp \
+	../digest/md5.c
+LOCAL_SHARED_LIBRARIES += libstdc++ libz
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
+    LOCAL_C_INCLUDES += external/stlport/stlport
+    LOCAL_SHARED_LIBRARIES += libstlport
+else
+    LOCAL_SHARED_LIBRARIES += libc++
+endif
+
+LOCAL_C_INCLUDES += bionic external/zlib
+LOCAL_CFLAGS:= -c -W
+LOCAL_MODULE:= twrpbu
+LOCAL_MODULE_STEM := bu
+LOCAL_MODULE_TAGS:= eng
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libtwadbbu
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DMTP_DEVICE -DMTP_HOST -fno-strict-aliasing
+LOCAL_C_INCLUDES += $(LOCAL_PATH) bionic frameworks/base/include system/core/include bionic/libc/private/
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
+    LOCAL_C_INCLUDES += external/stlport/stlport
+endif
+
+LOCAL_SRC_FILES = \
+    libtwadbbu.cpp
+
+LOCAL_SHARED_LIBRARIES += libz libc libstdc++
+
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
+    LOCAL_SHARED_LIBRARIES += libstlport
+else
+    LOCAL_SHARED_LIBRARIES += libc++
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/adbbu/libtwadbbu.cpp b/adbbu/libtwadbbu.cpp
new file mode 100644
index 0000000..cdc2170
--- /dev/null
+++ b/adbbu/libtwadbbu.cpp
@@ -0,0 +1,196 @@
+/*
+		Copyright 2013 to 2016 TeamWin
+		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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <zlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#include "twadbstream.h"
+#include "libtwadbbu.hpp"
+
+bool twadbbu::Write_ADB_Stream_Header(uint64_t partition_count) {
+	struct AdbBackupStreamHeader twhdr;
+	int adb_control_bu_fd;
+
+	memset(&twhdr, 0, sizeof(twhdr));
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+	if (adb_control_bu_fd < 0) {
+		printf("Cannot write to TW_ADB_BU_CONTROL.\n");
+		return false;
+	}
+
+	strncpy(twhdr.start_of_header, TWRP, sizeof(twhdr.start_of_header));
+	strncpy(twhdr.type, TWSTREAMHDR, sizeof(twhdr.type));
+	twhdr.partition_count = partition_count;
+	twhdr.version = ADB_BACKUP_VERSION;
+	memset(twhdr.space, 0, sizeof(twhdr.space));
+	twhdr.crc = crc32(0L, Z_NULL, 0);
+	twhdr.crc = crc32(twhdr.crc, (const unsigned char*) &twhdr, sizeof(twhdr));
+	if (write(adb_control_bu_fd, &twhdr, sizeof(twhdr)) < 0) {
+		printf("Cannot write to adb control channel\n");
+		close(adb_control_bu_fd);
+		return false;
+	}
+	return true;
+}
+
+bool twadbbu::Write_ADB_Stream_Trailer() {
+	int adb_control_bu_fd;
+	struct AdbBackupControlType endadb;
+
+	memset(&endadb, 0, sizeof(endadb));
+
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY);
+	if (adb_control_bu_fd < 0) {
+		printf("Error opening adb_control_bu_fd\n");
+		return false;
+	}
+	strncpy(endadb.start_of_header, TWRP, sizeof(endadb.start_of_header));
+	strncpy(endadb.type, TWENDADB, sizeof(endadb.type));
+	endadb.crc = crc32(0L, Z_NULL, 0);
+	endadb.crc = crc32(endadb.crc, (const unsigned char*) &endadb, sizeof(endadb));
+	if (write(adb_control_bu_fd, &endadb, sizeof(endadb)) < 0) {
+		printf("Cannot write to ADB control.\n");
+		close(adb_control_bu_fd);
+		return false;
+	}
+	close(adb_control_bu_fd);
+	return true;
+}
+
+bool twadbbu::Write_TWFN(std::string Backup_FileName, uint64_t file_size, bool use_compression) {
+	int adb_control_bu_fd;
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+	struct twfilehdr twfilehdr;
+	strncpy(twfilehdr.start_of_header, TWRP, sizeof(twfilehdr.start_of_header));
+	strncpy(twfilehdr.type, TWFN, sizeof(twfilehdr.type));
+	strncpy(twfilehdr.name, Backup_FileName.c_str(), sizeof(twfilehdr.name));
+	twfilehdr.size = (file_size == 0 ? 1024 : file_size);
+	twfilehdr.compressed = use_compression;
+	twfilehdr.crc = crc32(0L, Z_NULL, 0);
+	twfilehdr.crc = crc32(twfilehdr.crc, (const unsigned char*) &twfilehdr, sizeof(twfilehdr));
+
+	printf("Sending TWFN to adb\n");
+	if (write(adb_control_bu_fd, &twfilehdr, sizeof(twfilehdr)) < 1) {
+		printf("Cannot that write to adb_control_bu_fd\n");
+		close(adb_control_bu_fd);
+		return false;
+	}
+	close(adb_control_bu_fd);
+	return true;
+}
+
+bool twadbbu::Write_TWIMG(std::string Backup_FileName, uint64_t file_size) {
+	int adb_control_bu_fd;
+	struct twfilehdr twimghdr;
+
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+	strncpy(twimghdr.start_of_header, TWRP, sizeof(twimghdr.start_of_header));
+	strncpy(twimghdr.type, TWIMG, sizeof(twimghdr.type));
+	twimghdr.size = file_size;
+	strncpy(twimghdr.name, Backup_FileName.c_str(), sizeof(twimghdr.name));
+	twimghdr.crc = crc32(0L, Z_NULL, 0);
+	twimghdr.crc = crc32(twimghdr.crc, (const unsigned char*) &twimghdr, sizeof(twimghdr));
+	printf("Sending TWIMG to adb\n");
+	if (write(adb_control_bu_fd, &twimghdr, sizeof(twimghdr)) < 1) {
+		printf("Cannot write to adb control channel\n");
+		return false;
+	}
+
+	return true;
+}
+
+bool twadbbu::Write_TWEOF() {
+	struct AdbBackupControlType tweof;
+	int adb_control_bu_fd;
+	int errctr = 0;
+
+	printf("opening TW_ADB_BU_CONTROL\n");
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+	while (adb_control_bu_fd < 0) {
+		printf("failed to open TW_ADB_BU_CONTROL. Retrying: %s\n", strerror(errno));
+		adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+		usleep(10000);
+		errctr++;
+		if (errctr > ADB_BU_MAX_ERROR) {
+			printf("Cannot write to adb_control_bu_fd: %s.\n", strerror(errno));
+			close(adb_control_bu_fd);
+			return false;
+		}
+	}
+	memset(&tweof, 0, sizeof(tweof));
+	strncpy(tweof.start_of_header, TWRP, sizeof(tweof.start_of_header));
+	strncpy(tweof.type, TWEOF, sizeof(tweof.type));
+	tweof.crc = crc32(0L, Z_NULL, 0);
+	tweof.crc = crc32(tweof.crc, (const unsigned char*) &tweof, sizeof(tweof));
+	printf("Sending TWEOF to adb backup\n");
+	if (write(adb_control_bu_fd, &tweof, sizeof(tweof)) < 0) {
+		printf("Cannot write to adb_control_bu_fd: %s.\n", strerror(errno));
+		close(adb_control_bu_fd);
+		return false;
+	}
+	close(adb_control_bu_fd);
+	return true;
+}
+
+bool twadbbu::Write_TWERROR() {
+	struct AdbBackupControlType twerror;
+	int adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+
+	strncpy(twerror.start_of_header, TWRP, sizeof(twerror.start_of_header));
+	strncpy(twerror.type, TWERROR, sizeof(twerror.type));
+	memset(twerror.space, 0, sizeof(twerror.space));
+	twerror.crc = crc32(0L, Z_NULL, 0);
+	twerror.crc = crc32(twerror.crc, (const unsigned char*) &twerror, sizeof(twerror));
+	if (write(adb_control_bu_fd, &twerror, sizeof(twerror)) < 0) {
+		printf("Cannot write to adb control channel");
+		return false;
+	}
+	close(adb_control_bu_fd);
+	return true;
+}
+
+bool twadbbu::Write_TWENDADB() {
+	struct AdbBackupControlType endadb;
+	int adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+
+	memset(&endadb, 0, sizeof(endadb));
+	strncpy(endadb.start_of_header, TWRP, sizeof(endadb.start_of_header));
+	strncpy(endadb.type, TWENDADB, sizeof(endadb.type));
+	endadb.crc = crc32(0L, Z_NULL, 0);
+	endadb.crc = crc32(endadb.crc, (const unsigned char*) &endadb, sizeof(endadb));
+
+	printf("Sending TWENDADB to ADB Backup\n");
+	if (write(adb_control_bu_fd, &endadb, sizeof(endadb)) < 1) {
+		printf("Cannot write to ADB_CONTROL_BU_FD: %s\n", strerror(errno));
+		return false;
+	}
+
+	close(adb_control_bu_fd);
+	return true;
+}
diff --git a/adbbu/libtwadbbu.hpp b/adbbu/libtwadbbu.hpp
new file mode 100644
index 0000000..bcd8b6a
--- /dev/null
+++ b/adbbu/libtwadbbu.hpp
@@ -0,0 +1,44 @@
+/*
+		Copyright 2013 to 2016 TeamWin
+		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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#include "twadbstream.h"
+#include "twrpback.hpp"
+
+class twadbbu {
+public:
+	static bool Write_ADB_Stream_Header(uint64_t partition_count);                                 //Write ADB Stream Header to stream
+	static bool Write_ADB_Stream_Trailer();                                                        //Write ADB Stream Trailer to stream
+	static bool Write_TWFN(std::string Backup_FileName, uint64_t file_size, bool use_compression); //Write a tar image to stream
+	static bool Write_TWIMG(std::string Backup_FileName, uint64_t file_size);                      //Write a partition image to stream
+	static bool Write_TWEOF();                                                                     //Write ADB End-Of-File marker to stream
+	static bool Write_TWERROR();                                                                   //Write error message occurred to stream
+	static bool Write_TWENDADB();                                                                  //Write ADB End-Of-Stream command to stream
+};
diff --git a/adbbu/twadbstream.h b/adbbu/twadbstream.h
new file mode 100644
index 0000000..4e76be1
--- /dev/null
+++ b/adbbu/twadbstream.h
@@ -0,0 +1,101 @@
+/*
+		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/>.
+*/
+
+#ifndef __TWADBSTREAM_H
+#define __TWADBSTREAM_H
+
+#define TW_ADB_BACKUP "/tmp/twadbbackup"		//FIFO for adb backup
+#define TW_ADB_RESTORE "/tmp/twadbrestore"		//FIFO for adb restore
+#define TW_ADB_BU_CONTROL "/tmp/twadbbucontrol"		//FIFO for sending control from TWRP to ADB Backup
+#define TW_ADB_TWRP_CONTROL "/tmp/twadbtwrpcontrol"	//FIFO for sending control from ADB Backup to TWRP
+#define TWRP "TWRP"					//Magic Value
+#define ADB_BU_MAX_ERROR 10				//Max amount of errors for while loops
+
+//ADB Backup Control Commands
+#define TWSTREAMHDR "twstreamheader"			//TWRP Parititon Count Control
+#define TWFN "twfilename"				//TWRP Filename Control
+#define TWIMG "twimage"					//TWRP Image name Control
+#define TWEOF "tweof"					//End of File for Image/File
+#define MD5TRAILER "md5trailer"				//Image/File MD5 Trailer
+#define TWDATA "twdatablock"				// twrp adb backup data block header
+#define TWMD5 "twverifymd5"				//This command is compared to the md5trailer by ORS to verify transfer
+#define TWENDADB "twendadb"				//End Protocol
+#define TWERROR "twerror"				//Send error
+#define ADB_BACKUP_VERSION 1				//Backup Version
+#define DATA_MAX_CHUNK_SIZE 1048576			//Maximum size between each data header
+#define MAX_ADB_READ 512				//align with default tar size for amount to read fom adb stream
+
+/*
+structs for adb backup need to align to 512 bytes for reading 512
+bytes at a time
+Each struct contains a crc field so that when we are checking for commands
+and the crc doesn't match we still assume it's data matching the command
+struct but not really a command
+*/
+
+/*  stream format:
+  | TW ADB Backup Header   |
+  | TW File Stream Header  |
+  | File Data              |
+  | File/Image MD5 Trailer |
+  | TW File Stream Header  |
+  | File Data              |
+  | File/Image MD5 Trailer |
+  | etc...                 |
+*/
+
+//determine whether struct is 512 bytes, if not fail compilation
+#define ADBSTRUCT_STATIC_ASSERT(structure) typedef char adb_assertion[( !!(structure) )*2-1 ]
+
+//generic cmd structure to align fields for sending commands to and from adb backup
+struct AdbBackupControlType {
+	char start_of_header[8];			//stores the magic value #define TWRP
+	char type[16];					//stores the type of command, TWENDADB, TWCNT, TWEOF, TWMD5, TWDATA and TWERROR
+	uint32_t crc;					//stores the zlib 32 bit crc of the AdbBackupControlType struct to allow for making sure we are processing metadata
+	char space[484];				//stores space to align the struct to 512 bytes
+};
+
+//general info for file metadata stored in adb backup header
+struct twfilehdr {
+	char start_of_header[8];			//stores the magic value #define TWRP
+	char type[16];					//stores the type of file header, TWFN or TWIMG
+	uint64_t size;					//stores the size of the file contained after this header in the backup file
+	uint64_t compressed;				//stores whether the file is compressed or not. 1 == compressed and 0 == uncompressed
+	uint32_t crc;					//stores the zlib 32 bit crc of the twfilehdr struct to allow for making sure we are processing metadata
+	char name[468];					//stores the filename of the file
+};
+
+//md5 for files stored as a trailer to files in the adb backup file to check
+//that they are restored correctly
+struct AdbBackupFileTrailer {
+	char start_of_trailer[8];			//stores the magic value #define TWRP
+	char type[16];					//stores the AdbBackupFileTrailer type MD5TRAILER
+	uint32_t crc;					//stores the zlib 32 bit crc of the AdbBackupFileTrailer struct to allow for making sure we are processing metadata
+	uint32_t ident;					//stores crc to determine if header is encapsulated in stream as data
+	char md5[40];					//stores the md5 computation of the file
+	char space[440];				//stores space to align the struct to 512 bytes
+};
+
+//info for version and number of partitions backed up
+struct AdbBackupStreamHeader {
+	char start_of_header[8];			//stores the magic value #define TWRP
+	char type[16];					//stores the AdbBackupStreamHeader value TWCNT
+	uint64_t partition_count;			//stores the number of partitions to restore in the stream
+	uint64_t version;				//stores the version of adb backup. increment ADB_BACKUP_VERSION each time the metadata is updated
+	uint32_t crc;					//stores the zlib 32 bit crc of the AdbBackupStreamHeader struct to allow for making sure we are processing metadata
+	char space[468];				//stores space to align the struct to 512 bytes
+};
+
+#endif //__TWADBSTREAM_H
diff --git a/adbbu/twrpback.cpp b/adbbu/twrpback.cpp
new file mode 100644
index 0000000..e22574b
--- /dev/null
+++ b/adbbu/twrpback.cpp
@@ -0,0 +1,823 @@
+/*
+		Copyright 2013 to 2016 TeamWin
+		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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <zlib.h>
+#include <ctype.h>
+#include <semaphore.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <algorithm>
+
+#include "twadbstream.h"
+#include "twrpback.hpp"
+#include "../variables.h"
+#include "../twcommon.h"
+#include "../twrpDigest.hpp"
+
+twrpback::twrpback(void) {
+	read_fd = 0;
+	write_fd = 0;
+	adb_control_twrp_fd = 0;
+	adb_control_bu_fd = 0;
+	adb_read_fd = 0;
+	adb_write_fd = 0;
+	adb_write_fd = 0;
+	ors_fd = 0;
+	firstPart = true;
+	adbloginit();
+}
+
+twrpback::~twrpback(void) {
+	adblogfile.close();
+}
+
+void twrpback::adbloginit(void) {
+	adblogfile.open("/tmp/adb.log", std::fstream::app);
+}
+
+void twrpback::adblogwrite(std::string writemsg) {
+	adblogfile << writemsg << std::flush;
+}
+
+void twrpback::close_backup_fds() {
+	if (ors_fd > 0)
+		close(ors_fd);
+	if (write_fd > 0)
+		close(write_fd);
+	if (adb_read_fd > 0)
+		close(adb_read_fd);
+	if (adb_control_bu_fd > 0)
+		close(adb_control_bu_fd);
+	if (adbd_fp != NULL)
+		fclose(adbd_fp);
+	if (access(TW_ADB_BACKUP, F_OK) == 0)
+		unlink(TW_ADB_BACKUP);
+}
+
+void twrpback::close_restore_fds() {
+	if (ors_fd > 0)
+		close(ors_fd);
+	if (write_fd > 0)
+		close(write_fd);
+	if (adb_control_bu_fd > 0)
+		close(adb_control_bu_fd);
+	if (adb_control_twrp_fd > 0)
+		close(adb_control_twrp_fd);
+	if (adbd_fp != NULL)
+		fclose(adbd_fp);
+	if (access(TW_ADB_RESTORE, F_OK) == 0)
+		unlink(TW_ADB_RESTORE);
+}
+
+int twrpback::backup(std::string command) {
+	twrpDigest adb_md5;
+	bool breakloop = false;
+	int bytes = 0, errctr = 0;
+	char result[MAX_ADB_READ];
+	uint64_t totalbytes = 0, dataChunkBytes = 0;
+	int64_t count = -1;			// Count of how many blocks set
+	uint64_t md5fnsize = 0;
+	struct AdbBackupControlType endadb;
+
+	ADBSTRUCT_STATIC_ASSERT(sizeof(endadb) == MAX_ADB_READ);
+
+	bool writedata = true;
+	bool compressed = false;
+	bool firstDataPacket = true;
+
+	adbd_fp = fdopen(adbd_fd, "w");
+	if (adbd_fp == NULL) {
+		adblogwrite("Unable to open adb_fp\n");
+		return -1;
+	}
+
+	if (mkfifo(TW_ADB_BACKUP, 0666) < 0) {
+		adblogwrite("Unable to create TW_ADB_BACKUP fifo\n");
+		return -1;
+	}
+
+	adblogwrite("opening ORS_INPUT_FILE\n");
+	write_fd = open(ORS_INPUT_FILE, O_WRONLY);
+	while (write_fd < 0) {
+		write_fd = open(ORS_INPUT_FILE, O_WRONLY);
+		usleep(10000);
+		errctr++;
+		if (errctr > ADB_BU_MAX_ERROR) {
+			adblogwrite("Unable to open ORS_INPUT_FILE\n");
+			close_backup_fds();
+			return -1;
+		}
+	}
+
+	sprintf(operation, "adbbackup %s", command.c_str());
+	if (write(write_fd, operation, sizeof(operation)) != sizeof(operation)) {
+		adblogwrite("Unable to write to ORS_INPUT_FILE\n");
+		close_backup_fds();
+		return -1;
+	}
+
+	adblogwrite("opening ORS_OUTPUT_FILE\n");
+	ors_fd = open(ORS_OUTPUT_FILE, O_RDONLY);
+	if (ors_fd < 0) {
+		adblogwrite("Unable to open ORS_OUTPUT_FILE\n");
+		close_backup_fds();
+		return -1;
+	}
+
+	memset(&result, 0, sizeof(result));
+	memset(&cmd, 0, sizeof(cmd));
+
+	adblogwrite("opening TW_ADB_BU_CONTROL\n");
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_RDONLY | O_NONBLOCK);
+	if (adb_control_bu_fd < 0) {
+		adblogwrite("Unable to open TW_ADB_BU_CONTROL for reading.\n");
+		close_backup_fds();
+		return -1;
+	}
+
+	adblogwrite("opening TW_ADB_BACKUP\n");
+	adb_read_fd = open(TW_ADB_BACKUP, O_RDONLY | O_NONBLOCK);
+	if (adb_read_fd < 0) {
+		adblogwrite("Unable to open TW_ADB_BACKUP for reading.\n");
+		close_backup_fds();
+		return -1;
+	}
+
+	//loop until TWENDADB sent
+	while (!breakloop) {
+		if (read(adb_control_bu_fd, &cmd, sizeof(cmd)) > 0) {
+			struct AdbBackupControlType structcmd;
+
+			memcpy(&structcmd, cmd, sizeof(cmd));
+			std::string cmdstr(structcmd.type);
+			std::string cmdtype = cmdstr.substr(0, sizeof(structcmd.type) - 1);
+
+			//we received an error, exit and unlink
+			if (cmdtype == TWERROR) {
+				writedata = false;
+				adblogwrite("Error received. Quitting...\n");
+				close_backup_fds();
+				return -1;
+			}
+			//we received the end of adb backup stream so we should break the loop
+			else if (cmdtype == TWENDADB) {
+				writedata = false;
+				adblogwrite("Recieved TWENDADB\n");
+				memcpy(&endadb, cmd, sizeof(cmd));
+				stringstream str;
+				str << totalbytes;
+				adblogwrite(str.str() + " total bytes written\n");
+				breakloop = true;
+			}
+			//we recieved the TWSTREAMHDR structure metadata to write to adb
+			else if (cmdtype == TWSTREAMHDR) {
+				writedata = false;
+				adblogwrite("Writing TWSTREAMHDR\n");
+				if (fwrite(cmd, 1, sizeof(cmd), adbd_fp) != sizeof(cmd)) {
+					stringstream str;
+					str << strerror(errno);
+					adblogwrite("Error writing TWSTREAMHDR to adbd" + str.str() + "\n");
+					close_backup_fds();
+					return -1;
+				}
+				fflush(adbd_fp);
+			}
+			//we will be writing an image from TWRP
+			else if (cmdtype == TWIMG) {
+				struct twfilehdr twimghdr;
+
+				adblogwrite("Writing TWIMG\n");
+				adb_md5.initMD5();
+
+				memset(&twimghdr, 0, sizeof(twimghdr));
+				memcpy(&twimghdr, cmd, sizeof(cmd));
+				md5fnsize = twimghdr.size;
+
+				if (fwrite(cmd, 1, sizeof(cmd), adbd_fp)  != sizeof(cmd)) {
+					adblogwrite("Error writing TWIMG to adbd\n");
+					close_backup_fds();
+					return -1;
+				}
+				fflush(adbd_fp);
+				writedata = true;
+			}
+			//we will be writing a tar from TWRP
+			else if (cmdtype == TWFN) {
+				struct twfilehdr twfilehdr;
+
+				adblogwrite("Writing TWFN\n");
+				adb_md5.initMD5();
+
+				ADBSTRUCT_STATIC_ASSERT(sizeof(twfilehdr) == MAX_ADB_READ);
+
+				memset(&twfilehdr, 0, sizeof(twfilehdr));
+				memcpy(&twfilehdr, cmd, sizeof(cmd));
+				md5fnsize = twfilehdr.size;
+
+				compressed = twfilehdr.compressed == 1 ? true: false;
+
+				if (fwrite(cmd, 1, sizeof(cmd), adbd_fp) != sizeof(cmd)) {
+					adblogwrite("Error writing TWFN to adbd\n");
+					close_backup_fds();
+					return -1;
+				}
+				fflush(adbd_fp);
+				writedata = true;
+			}
+			/*
+			We received the command that we are done with the file stream.
+			We will flush the remaining data stream.
+			Update md5 and write final results to adb stream.
+			If we need padding because the total bytes are not a multiple
+			of 512, we pad the end with 0s to we reach 512.
+			We also write the final md5 to the adb stream.
+			*/
+			else if (cmdtype == TWEOF) {
+				adblogwrite("received TWEOF\n");
+				count = totalbytes / MAX_ADB_READ + 1;
+				count = count * MAX_ADB_READ;
+
+				while ((bytes = read(adb_read_fd, &result, sizeof(result))) == MAX_ADB_READ) {
+					totalbytes += bytes;
+					char *writeresult = new char [bytes];
+					memcpy(writeresult, result, bytes);
+					if (adb_md5.updateMD5stream((unsigned char *) writeresult, bytes) == -1)
+						adblogwrite("failed to update md5 stream\n");
+					if (fwrite(writeresult, 1, bytes, adbd_fp) != bytes) {
+						adblogwrite("Error writing backup data to adbd\n");
+						close_backup_fds();
+						return -1;
+					}
+					fflush(adbd_fp);
+					delete [] writeresult;
+					memset(&result, 0, sizeof(result));
+				}
+
+				if ((totalbytes % MAX_ADB_READ) != 0) {
+					adblogwrite("writing padding to stream\n");
+					char padding[count - totalbytes];
+					memset(padding, 0, sizeof(padding));
+					if (fwrite(padding, 1, sizeof(padding), adbd_fp) != sizeof(padding)) {
+						adblogwrite("Error writing padding to adbd\n");
+						close_backup_fds();
+						return -1;
+					}
+					if (adb_md5.updateMD5stream((unsigned char *) padding, sizeof(padding)) == -1)
+						adblogwrite("failed to update md5 stream\n");
+					fflush(adbd_fp);
+					totalbytes = 0;
+				}
+
+				AdbBackupFileTrailer md5trailer;
+
+				memset(&md5trailer, 0, sizeof(md5trailer));
+				adb_md5.finalizeMD5stream();
+
+				std::string md5string = adb_md5.createMD5string();
+
+				strncpy(md5trailer.start_of_trailer, TWRP, sizeof(md5trailer.start_of_trailer));
+				strncpy(md5trailer.type, MD5TRAILER, sizeof(md5trailer.type));
+				strncpy(md5trailer.md5, md5string.c_str(), sizeof(md5trailer.md5));
+
+				md5trailer.crc = crc32(0L, Z_NULL, 0);
+				md5trailer.crc = crc32(md5trailer.crc, (const unsigned char*) &md5trailer, sizeof(md5trailer));
+
+				md5trailer.ident = crc32(0L, Z_NULL, 0);
+				md5trailer.ident = crc32(md5trailer.ident, (const unsigned char*) &md5trailer, sizeof(md5trailer));
+				md5trailer.ident = crc32(md5trailer.ident, (const unsigned char*) &md5fnsize, sizeof(md5fnsize));
+
+				if (fwrite(&md5trailer, 1, sizeof(md5trailer), adbd_fp) != sizeof(md5trailer))  {
+					adblogwrite("Error writing md5trailer to adbd\n");
+					close_backup_fds();
+					return -1;
+				}
+				fflush(adbd_fp);
+				writedata = false;
+				firstDataPacket = true;
+			}
+			memset(&cmd, 0, sizeof(cmd));
+		}
+		//If we are to write data because of a new file stream, lets write all the data.
+		//This will allow us to not write data after a command structure has been written
+		//to the adb stream.
+		//If the stream is compressed, we need to always write the data.
+		if (writedata || compressed) {
+			while ((bytes = read(adb_read_fd, &result, sizeof(result))) == MAX_ADB_READ) {
+				if (firstDataPacket) {
+					struct AdbBackupControlType data_block;
+
+					memset(&data_block, 0, sizeof(data_block));
+					strncpy(data_block.start_of_header, TWRP, sizeof(data_block.start_of_header));
+					strncpy(data_block.type, TWDATA, sizeof(data_block.type));
+					data_block.crc = crc32(0L, Z_NULL, 0);
+					data_block.crc = crc32(data_block.crc, (const unsigned char*) &data_block, sizeof(data_block));
+					if (fwrite(&data_block, 1, sizeof(data_block), adbd_fp) != sizeof(data_block))  {
+						adblogwrite("Error writing data_block to adbd\n");
+						close_backup_fds();
+						return -1;
+					}
+					fflush(adbd_fp);
+					firstDataPacket = false;
+				}
+				char *writeresult = new char [bytes];
+				memcpy(writeresult, result, bytes);
+
+				if (adb_md5.updateMD5stream((unsigned char *) writeresult, bytes) == -1)
+					adblogwrite("failed to update md5 stream\n");
+
+				totalbytes += bytes;
+				dataChunkBytes += bytes;
+
+				if (fwrite(writeresult, 1, bytes, adbd_fp) != bytes) {
+					adblogwrite("Error writing backup data to adbd\n");
+					close_backup_fds();
+					return -1;
+				}
+				fflush(adbd_fp);
+
+				delete [] writeresult;
+				memset(&result, 0, sizeof(result));
+				if (dataChunkBytes == DATA_MAX_CHUNK_SIZE - sizeof(result)) {
+					struct AdbBackupControlType data_block;
+
+					memset(&data_block, 0, sizeof(data_block));
+					strncpy(data_block.start_of_header, TWRP, sizeof(data_block.start_of_header));
+					strncpy(data_block.type, TWDATA, sizeof(data_block.type));
+					data_block.crc = crc32(0L, Z_NULL, 0);
+					data_block.crc = crc32(data_block.crc, (const unsigned char*) &data_block, sizeof(data_block));
+					if (fwrite(&data_block, 1, sizeof(data_block), adbd_fp) != sizeof(data_block))  {
+						adblogwrite("Error writing data_block to adbd\n");
+						close_backup_fds();
+						return -1;
+					}
+					fflush(adbd_fp);
+					dataChunkBytes = 0;
+				}
+
+			}
+			compressed = false;
+		}
+	}
+
+	//Write the final end adb structure to the adb stream
+	if (fwrite(&endadb, 1, sizeof(endadb), adbd_fp) != sizeof(endadb)) {
+		adblogwrite("Error writing endadb to adbd\n");
+		close_backup_fds();
+		return -1;
+	}
+	fflush(adbd_fp);
+	close_backup_fds();
+	return 0;
+}
+
+int twrpback::restore(void) {
+	twrpDigest adb_md5;
+	char cmd[MAX_ADB_READ];
+	char result[MAX_ADB_READ];
+	struct AdbBackupControlType structcmd;
+	int adb_control_twrp_fd, errctr = 0;
+	uint64_t totalbytes = 0, dataChunkBytes = 0;
+	uint64_t md5fnsize = 0;
+	bool writedata, read_from_adb;
+	bool breakloop, eofsent, md5trsent;
+
+	breakloop = false;
+	read_from_adb = true;
+
+	signal(SIGPIPE, SIG_IGN);
+
+	adbd_fp = fdopen(adbd_fd, "r");
+	if (adbd_fp == NULL) {
+		adblogwrite("Unable to open adb_fp\n");
+		close_restore_fds();
+		return -1;
+	}
+
+	if(mkfifo(TW_ADB_RESTORE, 0666)) {
+		adblogwrite("Unable to create TW_ADB_RESTORE fifo\n");
+		close_restore_fds();
+		return -1;
+	}
+
+	adblogwrite("opening ORS_INPUT_FILE\n");
+	write_fd = open(ORS_INPUT_FILE, O_WRONLY);
+
+	while (write_fd < 0) {
+		write_fd = open(ORS_INPUT_FILE, O_WRONLY);
+		errctr++;
+		if (errctr > ADB_BU_MAX_ERROR) {
+			adblogwrite("Unable to open ORS_INPUT_FILE\n");
+			close_restore_fds();
+			return -1;
+		}
+	}
+
+	sprintf(operation, "adbrestore");
+	if (write(write_fd, operation, sizeof(operation)) != sizeof(operation)) {
+		adblogwrite("Unable to write to ORS_INPUT_FILE\n");
+		close_restore_fds();
+		return -1;
+	}
+
+	ors_fd = open(ORS_OUTPUT_FILE, O_RDONLY);
+	if (ors_fd < 0) {
+		stringstream str;
+		str << strerror(errno);
+		adblogwrite("Unable to write to ORS_OUTPUT_FILE: " + str.str() + "\n");
+		close_restore_fds();
+		return -1;
+	}
+
+	memset(&result, 0, sizeof(result));
+	memset(&cmd, 0, sizeof(cmd));
+
+	adblogwrite("opening TW_ADB_BU_CONTROL\n");
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_RDONLY | O_NONBLOCK);
+	if (adb_control_bu_fd < 0) {
+		stringstream str;
+		str << strerror(errno);
+		adblogwrite("Unable to open TW_ADB_BU_CONTROL for writing. " + str.str() + "\n");
+		close_restore_fds();
+		return -1;
+	}
+
+	adblogwrite("opening TW_ADB_TWRP_CONTROL\n");
+	adb_control_twrp_fd = open(TW_ADB_TWRP_CONTROL, O_WRONLY | O_NONBLOCK);
+	if (adb_control_twrp_fd < 0) {
+		stringstream str;
+		str << strerror(errno);
+		adblogwrite("Unable to open TW_ADB_TWRP_CONTROL for writing. " + str.str() + ". Retrying...\n");
+		while (adb_control_twrp_fd < 0) {
+			adb_control_twrp_fd = open(TW_ADB_TWRP_CONTROL, O_WRONLY | O_NONBLOCK);
+			usleep(10000);
+			errctr++;
+			if (errctr > ADB_BU_MAX_ERROR) {
+				adblogwrite("Unable to open TW_ADB_TWRP_CONTROL\n");
+				close_backup_fds();
+				return -1;
+			}
+		}
+	}
+
+	//Loop until we receive TWENDADB from TWRP
+	while (!breakloop) {
+		memset(&cmd, 0, sizeof(cmd));
+		if (read(adb_control_bu_fd, &cmd, sizeof(cmd)) > 0) {
+			struct AdbBackupControlType structcmd;
+			memcpy(&structcmd, cmd, sizeof(cmd));
+			std::string cmdstr(structcmd.type);
+			std::string cmdtype = cmdstr.substr(0, sizeof(structcmd.type) - 1);
+
+			//If we receive TWEOF from TWRP close adb data fifo
+			if (cmdtype == TWEOF) {
+				adblogwrite("Received TWEOF\n");
+				struct AdbBackupControlType tweof;
+
+				memset(&tweof, 0, sizeof(tweof));
+				memcpy(&tweof, result, sizeof(result));
+				read_from_adb = true;
+			}
+			//Break when TWRP sends TWENDADB
+			else if (cmdtype == TWENDADB) {
+				adblogwrite("Received TWENDADB\n");
+				breakloop = true;
+				close_restore_fds();
+			}
+			//we received an error, exit and unlink
+			else if (cmdtype == TWERROR) {
+				adblogwrite("Error received. Quitting...\n");
+				close_restore_fds();
+				return -1;
+			}
+		}
+
+		//If we should read from the adb stream, write commands and data to TWRP
+		if (read_from_adb) {
+			std::string cmdstr;
+			int readbytes;
+			if ((readbytes = fread(result, 1, sizeof(result), adbd_fp)) == sizeof(result)) {
+				totalbytes += readbytes;
+				memcpy(&structcmd, result, sizeof(result));
+				cmdstr = structcmd.type;
+				std::string cmdtype = cmdstr.substr(0, sizeof(structcmd.type) - 1);
+
+				//Tell TWRP we have read the entire adb stream
+				if (cmdtype == TWENDADB) {
+					struct AdbBackupControlType endadb;
+					uint32_t crc, endadbcrc;
+
+					totalbytes -= sizeof(result);
+					memset(&endadb, 0, sizeof(endadb));
+					memcpy(&endadb, result, sizeof(result));
+					endadbcrc = endadb.crc;
+					memset(&endadb.crc, 0, sizeof(endadb.crc));
+					crc = crc32(0L, Z_NULL, 0);
+					crc = crc32(crc, (const unsigned char*) &endadb, sizeof(endadb));
+
+					if (crc == endadbcrc) {
+						adblogwrite("Sending TWENDADB\n");
+						if (write(adb_control_twrp_fd, &endadb, sizeof(endadb)) < 1) {
+							stringstream str;
+							str << strerror(errno);
+							adblogwrite("Cannot write to ADB_CONTROL_READ_FD: " + str.str() + "\n");
+							close_restore_fds();
+							return -1;
+						}
+					}
+					else {
+						adblogwrite("ADB TWENDADB crc header doesn't match\n");
+						close_restore_fds();
+						return -1;
+					}
+				}
+				//Send TWRP partition metadata
+				else if (cmdtype == TWSTREAMHDR) {
+					struct AdbBackupStreamHeader cnthdr;
+					uint32_t crc, cnthdrcrc;
+
+					ADBSTRUCT_STATIC_ASSERT(sizeof(cnthdr) == MAX_ADB_READ);
+					totalbytes -= sizeof(result);
+
+					memset(&cnthdr, 0, sizeof(cnthdr));
+					memcpy(&cnthdr, result, sizeof(result));
+					cnthdrcrc = cnthdr.crc;
+					memset(&cnthdr.crc, 0, sizeof(cnthdr.crc));
+					crc = crc32(0L, Z_NULL, 0);
+					crc = crc32(crc, (const unsigned char*) &cnthdr, sizeof(cnthdr));
+
+					if (crc == cnthdrcrc) {
+						adblogwrite("Restoring TWSTREAMHDR\n");
+						if (write(adb_control_twrp_fd, result, sizeof(result)) < 0) {
+							stringstream str;
+							str << strerror(errno);
+							adblogwrite("Cannot write to adb_control_twrp_fd: " + str.str() + "\n");
+							close_restore_fds();
+							return -1;
+						}
+					}
+					else {
+						adblogwrite("ADB TWSTREAMHDR crc header doesn't match\n");
+						close_restore_fds();
+						return -1;
+					}
+				}
+				//Tell TWRP we are sending a partition image
+				else if (cmdtype == TWIMG) {
+					struct twfilehdr twimghdr;
+					uint32_t crc, twimghdrcrc;
+
+					totalbytes -= sizeof(result);
+					adb_md5.initMD5();
+					adblogwrite("Restoring TWIMG\n");
+					memset(&twimghdr, 0, sizeof(twimghdr));
+					memcpy(&twimghdr, result, sizeof(result));
+					md5fnsize = twimghdr.size;
+					twimghdrcrc = twimghdr.crc;
+					memset(&twimghdr.crc, 0, sizeof(twimghdr.crc));
+
+					crc = crc32(0L, Z_NULL, 0);
+					crc = crc32(crc, (const unsigned char*) &twimghdr, sizeof(twimghdr));
+					if (crc == twimghdrcrc) {
+						if (write(adb_control_twrp_fd, result, sizeof(result)) < 1) {
+							stringstream str;
+							str << strerror(errno);
+							adblogwrite("Cannot write to adb_control_twrp_fd: " + str.str() + "\n");
+							close_restore_fds();
+							return -1;
+						}
+					}
+					else {
+						adblogwrite("ADB TWIMG crc header doesn't match\n");
+						close_restore_fds();
+						return -1;
+					}
+					adblogwrite("opening TW_ADB_RESTORE\n");
+					adb_write_fd = open(TW_ADB_RESTORE, O_WRONLY);
+				}
+				//Tell TWRP we are sending a tar stream
+				else if (cmdtype == TWFN) {
+					struct twfilehdr twfilehdr;
+					uint32_t crc, twfilehdrcrc;
+
+					totalbytes -= sizeof(result);
+					adb_md5.initMD5();
+					adblogwrite("Restoring TWFN\n");
+					memset(&twfilehdr, 0, sizeof(twfilehdr));
+					memcpy(&twfilehdr, result, sizeof(result));
+					md5fnsize = twfilehdr.size;
+					twfilehdrcrc = twfilehdr.crc;
+					memset(&twfilehdr.crc, 0, sizeof(twfilehdr.crc));
+
+					crc = crc32(0L, Z_NULL, 0);
+					crc = crc32(crc, (const unsigned char*) &twfilehdr, sizeof(twfilehdr));
+
+					if (crc == twfilehdrcrc) {
+						if (write(adb_control_twrp_fd, result, sizeof(result)) < 1) {
+							stringstream str;
+							str << strerror(errno);
+							adblogwrite("Cannot write to adb_control_twrp_fd: " + str.str() + "\n");
+							close_restore_fds();
+							return -1;
+						}
+					}
+					else {
+						adblogwrite("ADB TWFN crc header doesn't match\n");
+						close_restore_fds();
+						return -1;
+					}
+
+					adblogwrite("opening TW_ADB_RESTORE\n");
+					adb_write_fd = open(TW_ADB_RESTORE, O_WRONLY);
+				}
+				//Send the tar or partition image md5 to TWRP
+				else if (cmdtype == TWDATA) {
+					totalbytes -= sizeof(result);
+					while (1) {
+						if ((readbytes = fread(result, 1, sizeof(result), adbd_fp)) != sizeof(result)) {
+							close_restore_fds();
+							return -1;
+						}
+						totalbytes += readbytes;
+						memcpy(&structcmd, result, sizeof(result));
+						cmdstr = structcmd.type;
+
+						if (cmdstr.substr(0, sizeof(MD5TRAILER) - 1) == MD5TRAILER) {
+							struct AdbBackupFileTrailer md5tr;
+							uint32_t crc, md5trcrc, md5ident, md5identmatch;
+
+							ADBSTRUCT_STATIC_ASSERT(sizeof(md5tr) == MAX_ADB_READ);
+							memset(&md5tr, 0, sizeof(md5tr));
+							memcpy(&md5tr, result, sizeof(result));
+							md5ident = md5tr.ident;
+
+							memset(&md5tr.ident, 0, sizeof(md5tr.ident));
+
+							md5identmatch = crc32(0L, Z_NULL, 0);
+							md5identmatch = crc32(md5identmatch, (const unsigned char*) &md5tr, sizeof(md5tr));
+							md5identmatch = crc32(md5identmatch, (const unsigned char*) &md5fnsize, sizeof(md5fnsize));
+
+							if (md5identmatch == md5ident) {
+								totalbytes -= sizeof(result);
+								close(adb_write_fd);
+								adblogwrite("Restoring MD5TRAILER\n");
+								md5trcrc = md5tr.crc;
+								memset(&md5tr.crc, 0, sizeof(md5tr.crc));
+								crc = crc32(0L, Z_NULL, 0);
+								crc = crc32(crc, (const unsigned char*) &md5tr, sizeof(md5tr));
+								if (crc == md5trcrc) {
+									if (write(adb_control_twrp_fd, result, sizeof(result)) < 1) {
+										stringstream str;
+										str << strerror(errno);
+										adblogwrite("Cannot write to adb_control_twrp_fd: " + str.str() + "\n");
+										close_restore_fds();
+										return -1;
+									}
+								}
+								else {
+									adblogwrite("ADB MD5TRAILER crc header doesn't match\n");
+									close_restore_fds();
+									return -1;
+								}
+								adblogwrite("md5 finalize stream\n");
+								adb_md5.finalizeMD5stream();
+
+								AdbBackupFileTrailer md5;
+
+								memset(&md5, 0, sizeof(md5));
+								strncpy(md5.start_of_trailer, TWRP, sizeof(md5.start_of_trailer));
+								strncpy(md5.type, TWMD5, sizeof(md5.type));
+								std::string md5string = adb_md5.createMD5string();
+								strncpy(md5.md5, md5string.c_str(), sizeof(md5.md5));
+
+								adblogwrite("Sending MD5Check\n");
+								if (write(adb_control_twrp_fd, &md5, sizeof(md5)) < 1) {
+									stringstream str;
+									str << strerror(errno);
+									adblogwrite("Cannot write to adb_control_twrp_fd: " + str.str() + "\n");
+									close_restore_fds();
+									return -1;
+								}
+								read_from_adb = false; //don't read from adb until TWRP sends TWEOF
+								break;
+							}
+						}
+						if (adb_md5.updateMD5stream((unsigned char*)result, sizeof(result)) == -1)
+							adblogwrite("failed to update md5 stream\n");
+						dataChunkBytes += readbytes;
+
+						if (write(adb_write_fd, result, sizeof(result)) < 0) {
+							stringstream str;
+							str << strerror(errno);
+							adblogwrite("Cannot write to adb_write_fd\n" + str.str() + ". Retrying.\n");
+							while(write(adb_write_fd, result, sizeof(result)) < 0) {
+								adblogwrite("Cannot write to adb_write_fd\n" + str.str() + ". Retrying.\n");
+								continue;
+							}
+						}
+						if (dataChunkBytes == ((DATA_MAX_CHUNK_SIZE) - sizeof(result))) {
+							dataChunkBytes = 0;
+							break;
+						}
+						memset(&result, 0, sizeof(result));
+					}
+				}
+			}
+		}
+	}
+
+	stringstream str;
+	str << totalbytes;
+	adblogwrite(str.str() + " bytes restored from adbbackup\n");
+	return 0;
+}
+
+int main(int argc, char **argv) {
+	int index;
+	int ret = 0, pos = 0;
+	std::string command;
+	twrpback tw;
+
+	tw.adblogwrite("Starting adb backup and restore\n");
+	if (mkfifo(TW_ADB_BU_CONTROL, 0666) < 0) {
+		stringstream str;
+		str << strerror(errno);
+		tw.adblogwrite("Unable to create TW_ADB_BU_CONTROL fifo: " + str.str() + "\n");
+		unlink(TW_ADB_BU_CONTROL);
+		return -1;
+	}
+	if (mkfifo(TW_ADB_TWRP_CONTROL, 0666) < 0) {
+		stringstream str;
+		str << strerror(errno);
+		tw.adblogwrite("Unable to create TW_ADB_TWRP_CONTROL fifo: " + str.str() + "\n");
+		unlink(TW_ADB_TWRP_CONTROL);
+		unlink(TW_ADB_BU_CONTROL);
+		return -1;
+	}
+
+	command = argv[1];
+	for (index = 2; index < argc; index++) {
+		command = command + " " + argv[index];
+	}
+
+	pos = command.find("backup");
+	if (pos < 0) {
+		pos = command.find("restore");
+	}
+	command.erase(0, pos);
+	command.erase(std::remove(command.begin(), command.end(), '\''), command.end());
+	tw.adblogwrite("command: " + command + "\n");
+
+	if (command.substr(0, sizeof("backup") - 1) == "backup") {
+		tw.adblogwrite("Starting adb backup\n");
+		if (isdigit(*argv[1]))
+			tw.adbd_fd = atoi(argv[1]);
+		else
+			tw.adbd_fd = 1;
+		ret = tw.backup(command);
+	}
+	else if (command.substr(0, sizeof("restore") - 1) == "restore") {
+		tw.adblogwrite("Starting adb restore\n");
+		if (isdigit(*argv[1]))
+			tw.adbd_fd = atoi(argv[1]);
+		else
+			tw.adbd_fd = 0;
+		ret = tw.restore();
+	}
+	if (ret == 0)
+		tw.adblogwrite("Adb backup/restore completed\n");
+	else
+		tw.adblogwrite("Adb backup/restore failed\n");
+
+	if (unlink(TW_ADB_BU_CONTROL) < 0) {
+		stringstream str;
+		str << strerror(errno);
+		tw.adblogwrite("Unable to remove TW_ADB_BU_CONTROL: " + str.str());
+	}
+	unlink(TW_ADB_TWRP_CONTROL);
+	return ret;
+}
diff --git a/adbbu/twrpback.hpp b/adbbu/twrpback.hpp
new file mode 100644
index 0000000..752d35e
--- /dev/null
+++ b/adbbu/twrpback.hpp
@@ -0,0 +1,49 @@
+/*
+		Copyright 2013 to 2016 TeamWin
+		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 <fstream>
+
+#include "../orscmd/orscmd.h"
+#include "../variables.h"
+#include "../twcommon.h"
+
+class twrpback {
+public:
+	int adbd_fd;                                                             // adbd data stream
+
+	twrpback(void);
+	virtual ~twrpback(void);
+	int backup(std::string command);                                         // adb backup stream
+	int restore(void);                                                       // adb restore stream
+	void adblogwrite(std::string writemsg);                                  // adb debugging log function
+	void close_backup_fds();                                                 // close backup resources
+	void close_restore_fds();                                                // close restore resources
+
+private:
+	int read_fd;                                                             // ors input fd
+	int write_fd;                                                            // ors operation fd
+	int ors_fd;                                                              // ors output fd
+	int adb_control_twrp_fd;                                                 // fd for bu to twrp communication
+	int adb_control_bu_fd;                                                   // fd for twrp to bu communication
+	int adb_read_fd;                                                         // adb read data stream
+	int adb_write_fd;                                                        // adb write data stream
+	bool firstPart;                                                          // first partition in the stream
+	FILE *adbd_fp;                                                           // file pointer for adb stream
+	char cmd[512];                                                           // store result of commands
+	char operation[512];                                                     // operation to send to ors
+	std::ofstream adblogfile;                                                // adb stream log file
+	void adbloginit(void);                                                   // setup adb log stream file
+};
diff --git a/gui/Android.mk b/gui/Android.mk
index 045824d..98d5629 100644
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -110,6 +110,7 @@
             TW_THEME := landscape_hdpi
         endif
     endif
+
 ifeq ($(TWRP_NEW_THEME),true)
     TWRP_THEME_LOC := $(commands_recovery_local_path)/gui/theme/$(TW_THEME)
     TWRP_RES := $(commands_recovery_local_path)/gui/theme/common/fonts
diff --git a/gui/action.cpp b/gui/action.cpp
index aac2c31..d98a814 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -1180,9 +1180,8 @@
 			DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
 			string auto_gen = gui_lookup("auto_generate", "(Auto Generate)");
 			if (Backup_Name == auto_gen || Backup_Name == gui_lookup("curr_date", "(Current Date)") || Backup_Name == "0" || Backup_Name == "(" || PartitionManager.Check_Backup_Name(true) == 0) {
-				ret = PartitionManager.Run_Backup();
-			}
-			else {
+				ret = PartitionManager.Run_Backup(false);
+			} else {
 				operation_end(1);
 				return -1;
 			}
@@ -1728,12 +1727,16 @@
 {
 	int op_status = 0;
 
+	PartitionSettings part_settings;
 	operation_start("Flash Image");
-	string path, filename, full_filename;
-	DataManager::GetValue("tw_zip_location", path);
-	DataManager::GetValue("tw_file", filename);
-	full_filename = path + "/" + filename;
-	if (PartitionManager.Flash_Image(full_filename))
+	DataManager::GetValue("tw_zip_location", part_settings.Restore_Name);
+	DataManager::GetValue("tw_file", part_settings.Backup_FileName);
+	unsigned long long total_bytes = TWFunc::Get_File_Size(part_settings.Restore_Name + "/" + part_settings.Backup_FileName);
+	ProgressTracking progress(total_bytes);
+	part_settings.progress = &progress;
+	part_settings.adbbackup = false;
+	part_settings.PM_Method = PM_RESTORE;
+	if (PartitionManager.Flash_Image(&part_settings))
 		op_status = 0; // success
 	else
 		op_status = 1; // fail
diff --git a/gui/devices/common/res/languages/en.xml b/gui/devices/common/res/languages/en.xml
index 8ce4762..e47ee70 100644
--- a/gui/devices/common/res/languages/en.xml
+++ b/gui/devices/common/res/languages/en.xml
@@ -227,5 +227,9 @@
 		<string name="change_fs_err">Error changing file system.</string>
 		<string name="theme_ver_err">Custom theme version does not match TWRP version. Using stock theme.</string>
 		<string name="install_reboot">Rebooting in 5 seconds</string>
+		<string name="adbbackup_error">Error with ADB Backup. Quitting..."</string>
+		<string name="adbbackup_control_error">Cannot write to adb control channel</string>
+		<string name="twrp_adbbu_option">--twrp option is required to enable twrp adb backup</string>
+		<string name="partition_not_found">path: {1} not found in partititon list</string>
 	</resources>
 </language>
diff --git a/gui/gui.cpp b/gui/gui.cpp
index 4cf80a4..df41939 100644
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -460,6 +460,14 @@
 				gui_set_FILE(orsout);
 				PageManager::GetResources()->DumpStrings();
 				ors_command_done();
+			//check to see if we should show backup page for parsing adbbackup partitions
+			} else if (strlen(command) == 23 && strncmp(command, "adbbackup", 9) == 0) {
+				gui_set_FILE(orsout);
+				DataManager::SetValue("tw_action", "twcmd");
+				DataManager::SetValue("tw_action_param", command);
+				DataManager::SetValue("tw_enable_adb_backup", 1);
+				gui_changePage("backup");
+				ors_command_done();
 			} else {
 				// mirror output messages
 				gui_set_FILE(orsout);
@@ -480,8 +488,6 @@
 				// put all things that need to be done after the command is finished into ors_command_done, not here
 			}
 		}
-	} else {
-		LOGINFO("ORS command line read returned an error: %i, %i, %s\n", read_ret, errno, strerror(errno));
 	}
 }
 
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index 525a2c1..a7a59d8 100644
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -1557,6 +1557,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%col1_x_right%" y="%row3_y%"/>
 				<text>{@enc_disabled=disabled - set a password to enable}</text>
@@ -1566,6 +1567,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%col1_x_right%" y="%row3_y%"/>
 				<text>{@enc_enabled=enabled}</text>
@@ -1608,6 +1610,7 @@
 			</checkbox>
 
 			<button style="main_button_half_width">
+				<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				<placement x="%col1_x_left%" y="%row15a_y%"/>
 				<text>{@select_storage_btn=Select Storage}</text>
 				<actions>
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 4c26d30..2b80b25 100644
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -668,5 +668,9 @@
 		<string name="theme_ver_err">Custom theme version does not match TWRP version. Using stock theme.</string>
 		<string name="up_a_level">(Up A Level)</string>
 		<string name="install_reboot">Rebooting in 5 seconds</string>
+		<string name="adbbackup_error">Error with ADB Backup. Quitting..."</string>
+		<string name="adbbackup_control_error">Cannot write to adb control channel</string>
+		<string name="twrp_adbbu_option">--twrp option is required to enable twrp adb backup</string>
+		<string name="partition_not_found">path: {1} not found in partititon list</string>
 	</resources>
 </language>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index 03e3982..6b74538 100644
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -1485,6 +1485,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1499,6 +1500,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1524,6 +1526,7 @@
 			</fill>
 
 			<button>
+				<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				<placement x="indent" y="%row3a_y%" w="%content_width%" h="%navbar_height%"/>
 				<fill color="%transparent%"/>
 				<actions>
@@ -1540,6 +1543,7 @@
 			</partitionlist>
 
 			<button style="main_button_half_height">
+				<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				<placement x="%indent%" y="%row18a_y%"/>
 				<text>{@select_storage_btn=Select Storage}</text>
 				<actions>
@@ -1596,6 +1600,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1610,6 +1615,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1683,6 +1689,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1697,6 +1704,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1793,6 +1801,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1807,6 +1816,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1899,6 +1909,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
@@ -1913,6 +1924,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%tab3_col3_x%" y="%row1_y%" w="%tab3_width%" h="%tab_height%"/>
 				<text>{@encryption_tab=ENCRYPTION}</text>
diff --git a/gui/theme/common/watch.xml b/gui/theme/common/watch.xml
index 4516ce2..38a2a23 100644
--- a/gui/theme/common/watch.xml
+++ b/gui/theme/common/watch.xml
@@ -213,7 +213,7 @@
 				<text>{@backup_btn=Backup}</text>
 				<actions>
 					<action function="set">tw_back=main</action>
-					<action function="page">backup_selectstorage</action>
+					<action function="page">backup</action>
 				</actions>
 			</button>
 
@@ -1786,7 +1786,7 @@
 			</action>
 		</page>
 
-		<page name="backup_selectstorage">
+		<page name="backup">
 			<template name="page"/>
 
 			<template name="statusbar"/>
@@ -1807,7 +1807,7 @@
 				<image resource="q_btn_refresh"/>
 				<actions>
 					<action function="refreshsizes"/>
-					<action function="page">backup_selectstorage</action>
+					<action function="page">backup</action>
 				</actions>
 			</button>
 
@@ -1824,7 +1824,7 @@
 				<highlight color="%highlight_color%"/>
 				<image resource="q_btn_arrow_right"/>
 				<actions>
-					<action function="set">tw_back=backup_selectstorage</action>
+					<action function="set">tw_back=backup</action>
 					<action function="page">backup_selectpartitions</action>
 				</actions>
 			</button>
@@ -1869,7 +1869,7 @@
 				<placement x="%col1_x_left%" y="%row11_y%"/>
 				<highlight color="%highlight_color%"/>
 				<image resource="q_btn_arrow_left"/>
-				<action function="page">backup_selectstorage</action>
+				<action function="page">backup</action>
 			</button>
 
 			<button>
@@ -1946,6 +1946,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%btn4_col2_x%" y="%row11_y%"/>
 				<highlight color="%highlight_color%"/>
@@ -1961,6 +1962,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%btn4_col2_x%" y="%row11_y%"/>
 				<highlight color="%highlight_color%"/>
@@ -2071,7 +2073,7 @@
 				<placement x="%center_x%" y="%row2_header_y%" w="%screen_half_width%" h="48"/>
 				<actions>
 					<action function="set">tw_back=backup_confirm</action>
-					<action function="page">backup_selectstorage</action>
+					<action function="page">backup</action>
 				</actions>
 			</button>
 
@@ -2084,6 +2086,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="0"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%col1_x_right%" y="%row4a_y%"/>
 				<text>{@disabled=Disabled}</text>
@@ -2093,6 +2096,7 @@
 				<conditions>
 					<condition var1="tw_include_encrypted_backup" var2="1"/>
 					<condition var1="tw_encrypt_backup" var2="1"/>
+					<condition var1="tw_enable_adb_backup" op="!=" var2="1"/>
 				</conditions>
 				<placement x="%col1_x_right%" y="%row4a_y%"/>
 				<text>{@enabled=Enabled}</text>
@@ -2146,7 +2150,7 @@
 
 			<action>
 				<touch key="back"/>
-				<action function="page">backup_selectstorage</action>
+				<action function="page">backup</action>
 			</action>
 		</page>
 
diff --git a/openrecoveryscript.cpp b/openrecoveryscript.cpp
index 75db902..0d2268c 100644
--- a/openrecoveryscript.cpp
+++ b/openrecoveryscript.cpp
@@ -1,5 +1,5 @@
 /*
-	Copyright 2012 bigbiff/Dees_Troy TeamWin
+	Copyright 2016 TeamWin
 	This file is part of TWRP/TeamWin Recovery Project.
 
 	TWRP is free software: you can redistribute it and/or modify
@@ -16,6 +16,7 @@
 	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#define __STDC_FORMAT_MACROS 1
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,21 +27,31 @@
 #include <dirent.h>
 #include <time.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <iostream>
 #include <fstream>
+#include <sstream>
+#include <string>
+#include <iterator>
+#include <algorithm>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <zlib.h>
 
 #include "twrp-functions.hpp"
 #include "partitions.hpp"
 #include "twcommon.h"
 #include "openrecoveryscript.hpp"
+#include "progresstracking.hpp"
 #include "variables.h"
 #include "adb_install.h"
 #include "data.hpp"
 #include "adb_install.h"
 #include "fuse_sideload.h"
 #include "gui/gui.hpp"
+#include "gui/pages.hpp"
+#include "orscmd/orscmd.h"
+#include "adbbu/libtwadbbu.hpp"
 extern "C" {
 	#include "twinstall.h"
 	#include "gui/gui.h"
@@ -139,6 +150,8 @@
 				// Wipe
 				if (strcmp(value, "cache") == 0 || strcmp(value, "/cache") == 0) {
 					PartitionManager.Wipe_By_Path("/cache");
+				} else if (strcmp(value, "system") == 0 || strcmp(value, "/system") == 0) {
+					PartitionManager.Wipe_By_Path("/system");
 				} else if (strcmp(value, "dalvik") == 0 || strcmp(value, "dalvick") == 0 || strcmp(value, "dalvikcache") == 0 || strcmp(value, "dalvickcache") == 0) {
 					PartitionManager.Wipe_Dalvik_Cache();
 				} else if (strcmp(value, "data") == 0 || strcmp(value, "/data") == 0 || strcmp(value, "factory") == 0 || strcmp(value, "factoryreset") == 0) {
@@ -280,6 +293,17 @@
 					ret_val = 1;
 				else
 					gui_msg("done=Done.");
+			} else if (strncmp(command, "adbbackup", 9) == 0) {
+				ret_val = Backup_ADB_Command(value);
+				if (ret_val == 1) {
+					twadbbu::Write_TWERROR();
+					gui_err("adbbackup_error=Error with ADB Backup. Quitting...");
+				}
+			} else if (strcmp(command, "adbrestore") == 0) {
+				LOGINFO("running adb restore\n");
+				ret_val = Restore_ADB_Backup();
+			} else if (strcmp(command, "remountrw") == 0) {
+				ret_val = remountrw();
 			} else if (strcmp(command, "mount") == 0) {
 				// Mount
 				DataManager::SetValue("tw_action_text2", gui_parse_text("{@mounting}"));
@@ -400,6 +424,7 @@
 		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(SCRIPT_FILE_TMP)(strerror(errno)));
 		return 1;
 	}
+
 	if (install_cmd && DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) {
 		gui_msg("injecttwrp=Injecting TWRP into boot image...");
 		TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot");
@@ -485,6 +510,72 @@
 	return ret_val;
 }
 
+int OpenRecoveryScript::Backup_ADB_Command(std::string Options) {
+	std::vector<std::string> args;
+	std::string Backup_List;
+	bool adbbackup = true, ret = false;
+	std::string rmopt = "--";
+
+	std::replace(Options.begin(), Options.end(), ':', ' ');
+	args = TWFunc::Split_String(Options, " ");
+
+	DataManager::SetValue(TW_USE_COMPRESSION_VAR, 0);
+	DataManager::SetValue(TW_SKIP_MD5_GENERATE_VAR, 0);
+
+	if (args[1].compare("--twrp") != 0) {
+		gui_err("twrp_adbbu_option=--twrp option is required to enable twrp adb backup");
+		sleep(2);
+		return 1;
+	}
+
+	for (unsigned i = 2; i < args.size(); i++) {
+		int compress;
+
+		std::string::size_type size = args[i].find(rmopt);
+		if (size != std::string::npos)
+			args[i].erase(size, rmopt.length());
+
+		if (args[i].compare("compress") == 0) {
+			gui_msg("compression_on=Compression is on");
+			DataManager::SetValue(TW_USE_COMPRESSION_VAR, 1);
+			continue;
+		}
+		DataManager::GetValue(TW_USE_COMPRESSION_VAR, compress);
+		gui_print("%s\n", args[i].c_str());
+		std::string path;
+		path = "/" + args[i];
+		TWPartition* part = PartitionManager.Find_Partition_By_Path(path);
+		if (part) {
+			Backup_List += path;
+			Backup_List += ";";
+		}
+		else {
+			gui_msg(Msg(msg::kError, "partition_not_found=path: {1} not found in partition list")(path));
+			return 1;
+		}
+	}
+
+	if (Backup_List.empty()) {
+		DataManager::GetValue("tw_backup_list", Backup_List);
+		if (Backup_List.empty()) {
+			gui_err("no_partition_selected=No partitions selected for backup.");
+			return 1;
+		}
+	}
+	else
+		DataManager::SetValue("tw_backup_list", Backup_List);
+
+	ret = PartitionManager.Run_Backup(adbbackup);
+	DataManager::SetValue(TW_BACKUP_NAME, gui_lookup("auto_generate", "(Auto Generate)"));
+	if (!ret) {
+		gui_err("backup_fail=Backup failed");
+		return 1;
+	}
+	gui_msg("backup_complete=Backup Complete");
+	sleep(2); //give time for user to see messages on console
+	return 0;
+}
+
 string OpenRecoveryScript::Locate_Zip_File(string Zip, string Storage_Root) {
 	string Path = TWFunc::Get_Path(Zip);
 	string File = TWFunc::Get_Filename(Zip);
@@ -513,6 +604,7 @@
 	char value1[SCRIPT_COMMAND_SIZE];
 	int line_len, i;
 	string Backup_List;
+	bool adbbackup = false;
 
 	strcpy(value1, Options.c_str());
 
@@ -558,7 +650,7 @@
 		}
 	}
 	DataManager::SetValue("tw_backup_list", Backup_List);
-	if (!PartitionManager.Run_Backup()) {
+	if (!PartitionManager.Run_Backup(false)) {
 		gui_err("backup_fail=Backup Failed");
 		return 1;
 	}
@@ -651,3 +743,196 @@
 	call_after_cli_command();
 	LOGINFO("Done reading ORS command from command line\n");
 }
+
+int OpenRecoveryScript::Restore_ADB_Backup(void) {
+	bool breakloop = false;
+	int partition_count = 0;
+	std::string Restore_Name;
+	std::size_t pos = 0;
+	struct AdbBackupFileTrailer adbmd5;
+	struct PartitionSettings part_settings;
+	int adb_control_twrp_fd, adb_write_fd, systemro;
+	int adb_control_bu_fd, ret = 0;
+	char cmd[512];
+	int orsfd = open(ORS_OUTPUT_FILE, O_WRONLY);
+
+	part_settings.total_restore_size = 0;
+
+	PartitionManager.Mount_All_Storage();
+	DataManager::SetValue(TW_SKIP_MD5_CHECK_VAR, 0);
+	LOGINFO("opening TW_ADB_BU_CONTROL\n");
+	adb_control_bu_fd = open(TW_ADB_BU_CONTROL, O_WRONLY | O_NONBLOCK);
+	LOGINFO("opening TW_ADB_TWRP_CONTROL\n");
+	adb_control_twrp_fd = open(TW_ADB_TWRP_CONTROL, O_RDONLY | O_NONBLOCK);
+	memset(&adbmd5, 0, sizeof(adbmd5));
+
+	while (!breakloop) {
+		memset(&cmd, 0, sizeof(cmd));
+		if (read(adb_control_twrp_fd, cmd, sizeof(cmd)) > 0) {
+			struct AdbBackupControlType cmdstruct;
+
+			memset(&cmdstruct, 0, sizeof(cmdstruct));
+			memcpy(&cmdstruct, cmd, sizeof(cmdstruct));
+			std::string cmdstr(cmdstruct.type);
+			std::string cmdtype = cmdstr.substr(0, sizeof(cmdstruct.type) - 1);
+			if (cmdstr.substr(0, sizeof(cmdstruct.type) - 1) == TWSTREAMHDR) {
+				struct AdbBackupStreamHeader twhdr;
+				memcpy(&twhdr, cmd, sizeof(cmd));
+				LOGINFO("ADB Partition count: %" PRIu64 "\n", twhdr.partition_count);
+				LOGINFO("ADB version: %" PRIu64 "\n", twhdr.version);
+				if (twhdr.version != ADB_BACKUP_VERSION) {
+					LOGERR("Incompatible adb backup version!\n");
+					breakloop = false;
+					break;
+				}
+				partition_count = twhdr.partition_count;
+			}
+			else if (cmdtype == MD5TRAILER) {
+				LOGINFO("Restoring MD5TRAILER\n");
+				memcpy(&adbmd5, cmd, sizeof(cmd));
+			}
+			else if (cmdtype == TWMD5) {
+				struct AdbBackupFileTrailer md5check;
+				LOGINFO("Restoring TWMD5\n");
+
+				memset(&md5check, 0, sizeof(md5check));
+				memcpy(&md5check, cmd, sizeof(cmd));
+				if (strcmp(md5check.md5, adbmd5.md5) != 0) {
+					LOGERR("md5 doesn't match!\n");
+					LOGERR("file md5: %s\n", adbmd5.md5);
+					LOGERR("check md5: %s\n", md5check.md5);
+					breakloop = true;
+					ret = 1;
+					break;
+				}
+				else {
+					LOGINFO("adbrestore md5 matches\n");
+					LOGINFO("adbmd5.md5: %s\n", adbmd5.md5);
+					LOGINFO("md5check.md5: %s\n", md5check.md5);
+				}
+			}
+			else if (cmdtype == TWENDADB) {
+				LOGINFO("received TWENDADB\n");
+				breakloop = true;
+				break;
+			}
+			else {
+				struct twfilehdr twimghdr;
+				memcpy(&twimghdr, cmd, sizeof(cmd));
+				std::string cmdstr(twimghdr.type);
+				Restore_Name = twimghdr.name;
+				part_settings.total_restore_size = twimghdr.size;
+				if (cmdtype == TWIMG) {
+					LOGINFO("ADB Type: %s\n", twimghdr.type);
+					LOGINFO("ADB Restore_Name: %s\n", Restore_Name.c_str());
+					LOGINFO("ADB Restore_size: %" PRIu64 "\n", part_settings.total_restore_size);
+					string compression = (twimghdr.compressed == 1) ? "compressed" : "uncompressed";
+					LOGINFO("ADB compression: %s\n", compression.c_str());
+					std::string Backup_FileName;
+					std::size_t pos = Restore_Name.find_last_of("/");
+					std::string path = "/" + Restore_Name.substr(pos, Restore_Name.size());
+					pos = path.find_first_of(".");
+					path = path.substr(0, pos);
+					if (path.substr(0,1).compare("//")) {
+						path = path.substr(1, path.size());
+					}
+
+					pos = Restore_Name.find_last_of("/");
+					Backup_FileName = Restore_Name.substr(pos + 1, Restore_Name.size());
+					part_settings.Part = PartitionManager.Find_Partition_By_Path(path);
+					part_settings.Restore_Name = path;
+					part_settings.partition_count = partition_count;
+					part_settings.adbbackup = true;
+					part_settings.adb_compression = twimghdr.compressed;
+					part_settings.Backup_FileName = Backup_FileName;
+					part_settings.PM_Method = PM_RESTORE;
+					ProgressTracking progress(part_settings.total_restore_size);
+					part_settings.progress = &progress;
+					if (!PartitionManager.Restore_Partition(&part_settings)) {
+						LOGERR("ADB Restore failed.\n");
+						return 1;
+					}
+				}
+				else if (cmdtype == TWFN) {
+					LOGINFO("ADB Type: %s\n", twimghdr.type);
+					LOGINFO("ADB Restore_Name: %s\n", Restore_Name.c_str());
+					LOGINFO("ADB Restore_size: %" PRIi64 "\n", part_settings.total_restore_size);
+					string compression = (twimghdr.compressed == 1) ? "compressed" : "uncompressed";
+					LOGINFO("ADB compression: %s\n", compression.c_str());
+					std::string Backup_FileName;
+					std::size_t pos = Restore_Name.find_last_of("/");
+					std::string path = "/" + Restore_Name.substr(pos, Restore_Name.size());
+					pos = path.find_first_of(".");
+					path = path.substr(0, pos);
+					if (path.substr(0,1).compare("//")) {
+						path = path.substr(1, path.size());
+					}
+
+					pos = Restore_Name.find_last_of("/");
+					Backup_FileName = Restore_Name.substr(pos + 1, Restore_Name.size());
+					pos = Restore_Name.find_last_of("/");
+					part_settings.Restore_Name = Restore_Name.substr(0, pos);
+					part_settings.Part = PartitionManager.Find_Partition_By_Path(path);
+
+					if (path.compare("/system") == 0) {
+						if (part_settings.Part->Is_Read_Only()) {
+							struct AdbBackupControlType twerror;
+							strncpy(twerror.start_of_header, TWRP, sizeof(twerror.start_of_header));
+							strncpy(twerror.type, TWERROR, sizeof(twerror.type));
+							memset(twerror.space, 0, sizeof(twerror.space));
+							twerror.crc = crc32(0L, Z_NULL, 0);
+							twerror.crc = crc32(twerror.crc, (const unsigned char*) &twerror, sizeof(twerror));
+							if (write(adb_control_bu_fd, &twerror, sizeof(twerror)) < 0) {
+								LOGERR("Cannot write to ADB_CONTROL_BU_FD: %s\n", strerror(errno));
+							}
+							gui_msg(Msg(msg::kError, "restore_read_only=Cannot restore {1} -- mounted read only.")(part_settings.Part->Backup_Display_Name));
+							return 1;
+
+						}
+					}
+					part_settings.partition_count = partition_count;
+					part_settings.adbbackup = true;
+					part_settings.adb_compression = twimghdr.compressed;
+					part_settings.Backup_FileName = Backup_FileName;
+					part_settings.total_restore_size += part_settings.Part->Get_Restore_Size(&part_settings);
+					part_settings.PM_Method = PM_RESTORE;
+					ProgressTracking progress(part_settings.total_restore_size);
+					part_settings.progress = &progress;
+					if (!PartitionManager.Restore_Partition(&part_settings)) {
+						LOGERR("ADB Restore failed.\n");
+						return 1;
+					}
+				}
+			}
+		}
+	}
+	gui_msg("restore_complete=Restore Complete");
+
+	if (!twadbbu::Write_TWENDADB())
+		ret = 1;
+	sleep(2); //give time for user to see messages on console
+	return ret;
+}
+
+int OpenRecoveryScript::remountrw(void)
+{
+	bool remount_system = PartitionManager.Is_Mounted_By_Path("/system");
+	int op_status;
+	TWPartition* Part;
+
+	if (!PartitionManager.UnMount_By_Path("/system", true)) {
+		op_status = 1; // fail
+	} else {
+		Part = PartitionManager.Find_Partition_By_Path("/system");
+		if (Part) {
+			DataManager::SetValue("tw_mount_system_ro", 0);
+			Part->Change_Mount_Read_Only(false);
+		}
+		if (remount_system) {
+			Part->Mount(true);
+		}
+		op_status = 0; // success
+	}
+
+	return op_status;
+}
diff --git a/openrecoveryscript.hpp b/openrecoveryscript.hpp
index 3831195..f442746 100644
--- a/openrecoveryscript.hpp
+++ b/openrecoveryscript.hpp
@@ -40,6 +40,9 @@
 	static int Run_OpenRecoveryScript_Action();                                    // Actually runs the ORS scripts for the GUI action
 	static void Call_After_CLI_Command(VoidFunction fn) { call_after_cli_command = fn; }
 	static void Run_CLI_Command(const char* command);                              // Runs a command for orscmd (twrp binary)
+	static int Backup_ADB_Command(string Options);                                 // Runs adbbackup
+	static int Restore_ADB_Backup();                                               // Restore adb backup through ors
+	static int remountrw();                                                        // Remount system and vendor rw
 };
 
 #endif // _OPENRECOVERYSCRIPT_HPP
diff --git a/orscmd/Android.mk b/orscmd/Android.mk
index 8ddf93f..9f18c16 100644
--- a/orscmd/Android.mk
+++ b/orscmd/Android.mk
@@ -3,7 +3,7 @@
 
 LOCAL_SRC_FILES:= \
 	orscmd.cpp
-LOCAL_CFLAGS:= -g -c -W
+LOCAL_CFLAGS:= -c -W
 LOCAL_MODULE:=orscmd
 LOCAL_MODULE_STEM := twrp
 LOCAL_MODULE_TAGS:= eng
diff --git a/orscmd/orscmd.cpp b/orscmd/orscmd.cpp
index 0240ff9..53c5bc0 100644
--- a/orscmd/orscmd.cpp
+++ b/orscmd/orscmd.cpp
@@ -40,6 +40,7 @@
 	printf("  set variable value\n");
 	printf("  get variable\n");
 	printf("  decrypt password\n");
+	printf("  remountrw\n");
 	printf("\nSee more documentation at http://teamw.in/openrecoveryscript\n");
 }
 
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;
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 320944c..96e3002 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -27,6 +27,7 @@
 #include <time.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <zlib.h>
 #include <iostream>
 #include <iomanip>
 #include <sys/wait.h>
@@ -44,6 +45,7 @@
 #include "tw_atomic.hpp"
 #include "gui/gui.hpp"
 #include "progresstracking.hpp"
+#include "adbbu/libtwadbbu.hpp"
 
 #ifdef TW_HAS_MTP
 #include "mtp/mtp_MtpServer.hpp"
@@ -68,7 +70,6 @@
 	mtp_was_enabled = false;
 	mtp_write_fd = -1;
 	stop_backup.set_value(0);
-	tar_fork_pid = 0;
 }
 
 int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
@@ -472,6 +473,7 @@
 	if (TWFunc::Path_Exists(tw_image_dir)) {
 		if (Display_Error)
 			gui_err("backup_name_exists=A backup with that name already exists!");
+
 		return -4;
 	}
 	// No problems found, return 0
@@ -481,7 +483,7 @@
 bool TWPartitionManager::Make_MD5(bool generate_md5, string Backup_Folder, string Backup_Filename)
 {
 	string command;
-	string Full_File = Backup_Folder + Backup_Filename;
+	string Full_File = Backup_Folder + "/" + Backup_Filename;
 	string result;
 	twrpDigest md5sum;
 
@@ -490,9 +492,8 @@
 
 	TWFunc::GUI_Operation_Text(TW_GENERATE_MD5_TEXT, gui_parse_text("{@generating_md51}"));
 	gui_msg("generating_md52= * Generating md5...");
-
 	if (TWFunc::Path_Exists(Full_File)) {
-		md5sum.setfn(Backup_Folder + Backup_Filename);
+		md5sum.setfn(Full_File);
 		if (md5sum.computeMD5() == 0)
 			if (md5sum.write_md5digest() == 0)
 				gui_msg("md5_created= * MD5 Created.");
@@ -533,13 +534,13 @@
 	return true;
 }
 
-bool TWPartitionManager::Backup_Partition(TWPartition* Part, const string& Backup_Folder, bool generate_md5, unsigned long *img_time, unsigned long *file_time, ProgressTracking *progress) {
+
+bool TWPartitionManager::Backup_Partition(PartitionSettings *part_settings) {
 	time_t start, stop;
-	int use_compression;
+	int use_compression, adb_control_bu_fd;
+	string backup_log = part_settings->Backup_Folder + "/recovery.log";
 
-	string backup_log = Backup_Folder + "recovery.log";
-
-	if (Part == NULL)
+	if (part_settings->Part == NULL)
 		return true;
 
 	DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
@@ -547,25 +548,28 @@
 	TWFunc::SetPerformanceMode(true);
 	time(&start);
 
-	if (Part->Backup(Backup_Folder, tar_fork_pid, progress)) {
+	part_settings->Backup_FileName = part_settings->Part->Backup_Name + "." +  part_settings->Part->Current_File_System + ".win";
+	if (part_settings->Part->Backup(part_settings, &tar_fork_pid)) {
 		bool md5Success = false;
-		if (Part->Has_SubPartition) {
+		if (part_settings->Part->Has_SubPartition) {
 			std::vector<TWPartition*>::iterator subpart;
 
 			for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
-				if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) {
-					if (!(*subpart)->Backup(Backup_Folder, tar_fork_pid, progress)) {
+				if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == part_settings->Part->Mount_Point) {
+					if (!(*subpart)->Backup(part_settings, &tar_fork_pid)) {
 						TWFunc::SetPerformanceMode(false);
-						Clean_Backup_Folder(Backup_Folder);
+						Clean_Backup_Folder(part_settings->Backup_Folder);
 						TWFunc::copy_file("/tmp/recovery.log", backup_log, 0644);
 						tw_set_default_metadata(backup_log.c_str());
 						return false;
 					}
 					sync();
 					sync();
-					if (!Make_MD5(generate_md5, Backup_Folder, (*subpart)->Backup_FileName)) {
-						TWFunc::SetPerformanceMode(false);
-						return false;
+					if (!part_settings->adbbackup) {
+						if (!Make_MD5(part_settings->generate_md5, part_settings->Backup_Folder, (*subpart)->Backup_FileName)) {
+							TWFunc::SetPerformanceMode(false);
+							return false;
+						}
 					}
 				}
 			}
@@ -573,17 +577,23 @@
 		time(&stop);
 		int backup_time = (int) difftime(stop, start);
 		LOGINFO("Partition Backup time: %d\n", backup_time);
-		if (Part->Backup_Method == 1) {
-			*file_time += backup_time;
+		if (part_settings->Part->Backup_Method == BM_FILES) {
+			part_settings->file_time += backup_time;
 		} else {
-			*img_time += backup_time;
+			part_settings->img_time += backup_time;
+
 		}
 
-		md5Success = Make_MD5(generate_md5, Backup_Folder, Part->Backup_FileName);
+		if (!part_settings->adbbackup) {
+			md5Success = Make_MD5(part_settings->generate_md5, part_settings->Backup_Folder, part_settings->Part->Backup_FileName);
+		}
+		else 
+			md5Success = true;
 		TWFunc::SetPerformanceMode(false);
+
 		return md5Success;
 	} else {
-		Clean_Backup_Folder(Backup_Folder);
+		Clean_Backup_Folder(part_settings->Backup_Folder);
 		TWFunc::copy_file("/tmp/recovery.log", backup_log, 0644);
 		tw_set_default_metadata(backup_log.c_str());
 		TWFunc::SetPerformanceMode(false);
@@ -648,12 +658,12 @@
 	return 0;
 }
 
-int TWPartitionManager::Run_Backup(void) {
-	int check, do_md5, partition_count = 0, disable_free_space_check = 0;
-	string Backup_Folder, Backup_Name, Full_Backup_Path, Backup_List, backup_path;
-	unsigned long long total_bytes = 0, file_bytes = 0, img_bytes = 0, free_space = 0, img_bytes_remaining, file_bytes_remaining, subpart_size;
-	unsigned long img_time = 0, file_time = 0;
-	TWPartition* backup_part = NULL;
+int TWPartitionManager::Run_Backup(bool adbbackup) {
+	PartitionSettings part_settings;
+	int check, partition_count = 0, disable_free_space_check = 0, do_md5 = 0;
+	int gui_adb_backup;
+	string Backup_Name, Backup_List, backup_path;
+	unsigned long long total_bytes = 0, free_space = 0, subpart_size;
 	TWPartition* storage = NULL;
 	std::vector<TWPartition*>::iterator subpart;
 	struct tm *t;
@@ -663,6 +673,19 @@
 	seconds = time(0);
 	t = localtime(&seconds);
 
+	part_settings.img_bytes_remaining = 0;
+	part_settings.file_bytes_remaining = 0;
+	part_settings.img_time = 0;
+	part_settings.file_time = 0;
+	part_settings.img_bytes = 0;
+	part_settings.file_bytes = 0;
+	part_settings.PM_Method = PM_BACKUP;
+
+	DataManager::GetValue("tw_enable_adb_backup", gui_adb_backup);
+	if (gui_adb_backup == true)
+		adbbackup = true;
+
+	part_settings.adbbackup = adbbackup;
 	time(&total_start);
 
 	Update_System_Details();
@@ -670,23 +693,26 @@
 	if (!Mount_Current_Storage(true))
 		return false;
 
+
 	DataManager::GetValue(TW_SKIP_MD5_GENERATE_VAR, do_md5);
 	if (do_md5 == 0)
-		do_md5 = true;
+		part_settings.generate_md5 = true;
 	else
-		do_md5 = false;
+		part_settings.generate_md5 = false;
 
-	DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Folder);
-	DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
-	if (Backup_Name == gui_lookup("curr_date", "(Current Date)")) {
-		Backup_Name = TWFunc::Get_Current_Date();
-	} else if (Backup_Name == gui_lookup("auto_generate", "(Auto Generate)") || Backup_Name == "0" || Backup_Name.empty()) {
+	DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder);
+	DataManager::GetValue(TW_BACKUP_NAME, part_settings.Backup_Name);
+	if (part_settings.Backup_Name == gui_lookup("curr_date", "(Current Date)")) {
+		part_settings.Backup_Name = TWFunc::Get_Current_Date();
+	} else if (part_settings.Backup_Name == gui_lookup("auto_generate", "(Auto Generate)") || part_settings.Backup_Name == "0" || part_settings.Backup_Name.empty()) {
 		TWFunc::Auto_Generate_Backup_Name();
-		DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
+		DataManager::GetValue(TW_BACKUP_NAME, part_settings.Backup_Name);
 	}
-	LOGINFO("Backup Name is: '%s'\n", Backup_Name.c_str());
-	Full_Backup_Path = Backup_Folder + "/" + Backup_Name + "/";
-	LOGINFO("Full_Backup_Path is: '%s'\n", Full_Backup_Path.c_str());
+
+	LOGINFO("Backup Name is: '%s'\n", part_settings.Backup_Name.c_str());
+	part_settings.Full_Backup_Path = part_settings.Backup_Folder + "/" + part_settings.Backup_Name + "/";
+
+	LOGINFO("Full_Backup_Path is: '%s'\n", part_settings.Full_Backup_Path.c_str());
 
 	LOGINFO("Calculating backup details...\n");
 	DataManager::GetValue("tw_backup_list", Backup_List);
@@ -694,23 +720,23 @@
 		end_pos = Backup_List.find(";", start_pos);
 		while (end_pos != string::npos && start_pos < Backup_List.size()) {
 			backup_path = Backup_List.substr(start_pos, end_pos - start_pos);
-			backup_part = Find_Partition_By_Path(backup_path);
-			if (backup_part != NULL) {
+			part_settings.Part = Find_Partition_By_Path(backup_path);
+			if (part_settings.Part != NULL) {
 				partition_count++;
-				if (backup_part->Backup_Method == 1)
-					file_bytes += backup_part->Backup_Size;
+				if (part_settings.Part->Backup_Method == BM_FILES)
+					part_settings.file_bytes += part_settings.Part->Backup_Size;
 				else
-					img_bytes += backup_part->Backup_Size;
-				if (backup_part->Has_SubPartition) {
+					part_settings.img_bytes += part_settings.Part->Backup_Size;
+				if (part_settings.Part->Has_SubPartition) {
 					std::vector<TWPartition*>::iterator subpart;
 
 					for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
-						if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_Present && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == backup_part->Mount_Point) {
+						if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_Present && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == part_settings.Part->Mount_Point) {
 							partition_count++;
-							if ((*subpart)->Backup_Method == 1)
-								file_bytes += (*subpart)->Backup_Size;
+							if ((*subpart)->Backup_Method == BM_FILES)
+								part_settings.file_bytes += (*subpart)->Backup_Size;
 							else
-								img_bytes += (*subpart)->Backup_Size;
+								part_settings.img_bytes += (*subpart)->Backup_Size;
 						}
 					}
 				}
@@ -726,8 +752,15 @@
 		gui_msg("no_partition_selected=No partitions selected for backup.");
 		return false;
 	}
-	total_bytes = file_bytes + img_bytes;
+	if (adbbackup) {
+		if (twadbbu::Write_ADB_Stream_Header(partition_count) == false) {
+			return false;
+		}
+	}
+	total_bytes = part_settings.file_bytes + part_settings.img_bytes;
 	ProgressTracking progress(total_bytes);
+	part_settings.progress = &progress;
+
 	gui_msg(Msg("total_partitions_backup= * Total number of partitions to back up: {1}")(partition_count));
 	gui_msg(Msg("total_backup_size= * Total size of all data: {1}MB")(total_bytes / 1024 / 1024));
 	storage = Find_Partition_By_Path(DataManager::GetCurrentStoragePath());
@@ -740,6 +773,10 @@
 	}
 
 	DataManager::GetValue("tw_disable_free_space", disable_free_space_check);
+
+	if (adbbackup)
+		disable_free_space_check = true;
+
 	if (!disable_free_space_check) {
 		if (free_space - (32 * 1024 * 1024) < total_bytes) {
 			// We require an extra 32MB just in case
@@ -747,12 +784,12 @@
 			return false;
 		}
 	}
-	img_bytes_remaining = img_bytes;
-	file_bytes_remaining = file_bytes;
+	part_settings.img_bytes_remaining = part_settings.img_bytes;
+	part_settings.file_bytes_remaining = part_settings.file_bytes;
 
 	gui_msg("backup_started=[BACKUP STARTED]");
-	gui_msg(Msg("backup_folder= * Backup Folder: {1}")(Full_Backup_Path));
-	if (!TWFunc::Recursive_Mkdir(Full_Backup_Path)) {
+	gui_msg(Msg("backup_folder= * Backup Folder: {1}")(part_settings.Full_Backup_Path));
+	if (!TWFunc::Recursive_Mkdir(part_settings.Full_Backup_Path)) {
 		gui_err("fail_backup_folder=Failed to make backup folder.");
 		return false;
 	}
@@ -765,9 +802,10 @@
 		if (stop_backup.get_value() != 0)
 			return -1;
 		backup_path = Backup_List.substr(start_pos, end_pos - start_pos);
-		backup_part = Find_Partition_By_Path(backup_path);
-		if (backup_part != NULL) {
-			if (!Backup_Partition(backup_part, Full_Backup_Path, do_md5, &img_time, &file_time, &progress))
+		part_settings.Part = Find_Partition_By_Path(backup_path);
+		if (part_settings.Part != NULL) {
+			if (!Backup_Partition(&part_settings))
+
 				return false;
 		} else {
 			gui_msg(Msg(msg::kError, "unable_to_locate_partition=Unable to locate '{1}' partition for backup calculations.")(backup_path));
@@ -777,26 +815,30 @@
 	}
 
 	// Average BPS
-	if (img_time == 0)
-		img_time = 1;
-	if (file_time == 0)
-		file_time = 1;
-	int img_bps = (int)img_bytes / (int)img_time;
-	unsigned long long file_bps = file_bytes / (int)file_time;
+	if (part_settings.img_time == 0)
+		part_settings.img_time = 1;
+	if (part_settings.file_time == 0)
+		part_settings.file_time = 1;
+	int img_bps = (int)part_settings.img_bytes / (int)part_settings.img_time;
+	unsigned long long file_bps = part_settings.file_bytes / (int)part_settings.file_time;
 
-	if (file_bytes != 0)
+	if (part_settings.file_bytes != 0)
 		gui_msg(Msg("avg_backup_fs=Average backup rate for file systems: {1} MB/sec")(file_bps / (1024 * 1024)));
-	if (img_bytes != 0)
+	if (part_settings.img_bytes != 0)
 		gui_msg(Msg("avg_backup_img=Average backup rate for imaged drives: {1} MB/sec")(img_bps / (1024 * 1024)));
 
 	time(&total_stop);
 	int total_time = (int) difftime(total_stop, total_start);
-	uint64_t actual_backup_size = du.Get_Folder_Size(Full_Backup_Path);
+
+	uint64_t actual_backup_size;
+	if (!adbbackup)
+		actual_backup_size = du.Get_Folder_Size(part_settings.Full_Backup_Path);
+	else
+		actual_backup_size = part_settings.file_bytes + part_settings.img_bytes;
 	actual_backup_size /= (1024LLU * 1024LLU);
 
-	int prev_img_bps, use_compression;
-	unsigned long long prev_file_bps;
-	DataManager::GetValue(TW_BACKUP_AVG_IMG_RATE, prev_img_bps);
+	int prev_img_bps = 0, use_compression = 0;
+	unsigned long long prev_file_bps = 0;
 	img_bps += (prev_img_bps * 4);
 	img_bps /= 5;
 
@@ -818,27 +860,40 @@
 	Update_System_Details();
 	UnMount_Main_Partitions();
 	gui_msg(Msg(msg::kHighlight, "backup_completed=[BACKUP COMPLETED IN {1} SECONDS]")(total_time)); // the end
-	string backup_log = Full_Backup_Path + "recovery.log";
+	string backup_log = part_settings.Full_Backup_Path + "recovery.log";
 	TWFunc::copy_file("/tmp/recovery.log", backup_log, 0644);
 	tw_set_default_metadata(backup_log.c_str());
+
+	if (part_settings.adbbackup) {
+		if (twadbbu::Write_ADB_Stream_Trailer() == false) {
+			return false;
+		}
+	}
+	part_settings.adbbackup = false;
+	DataManager::SetValue("tw_enable_adb_backup", 0);
+
 	return true;
 }
 
-bool TWPartitionManager::Restore_Partition(TWPartition* Part, const string& Restore_Name, ProgressTracking *progress) {
+bool TWPartitionManager::Restore_Partition(PartitionSettings *part_settings) {
 	time_t Start, Stop;
+
 	TWFunc::SetPerformanceMode(true);
+
 	time(&Start);
 
-	if (!Part->Restore(Restore_Name, progress)) {
+
+	if (!part_settings->Part->Restore(part_settings)) {
 		TWFunc::SetPerformanceMode(false);
 		return false;
 	}
-	if (Part->Has_SubPartition) {
+	if (part_settings->Part->Has_SubPartition) {
 		std::vector<TWPartition*>::iterator subpart;
 
 		for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
-			if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) {
-				if (!(*subpart)->Restore(Restore_Name, progress)) {
+
+			if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == part_settings->Part->Mount_Point) {
+				if (!(*subpart)->Restore(part_settings)) {
 					TWFunc::SetPerformanceMode(false);
 					return false;
 				}
@@ -847,18 +902,27 @@
 	}
 	time(&Stop);
 	TWFunc::SetPerformanceMode(false);
-	gui_msg(Msg("restore_part_done=[{1} done ({2} seconds)]")(Part->Backup_Display_Name)((int)difftime(Stop, Start)));
+	gui_msg(Msg("restore_part_done=[{1} done ({2} seconds)]")(part_settings->Part->Backup_Display_Name)((int)difftime(Stop, Start)));
+
 	return true;
 }
 
 int TWPartitionManager::Run_Restore(const string& Restore_Name) {
+	PartitionSettings part_settings;
 	int check_md5, check, partition_count = 0;
 	TWPartition* restore_part = NULL;
+
 	time_t rStart, rStop;
 	time(&rStart);
 	string Restore_List, restore_path;
 	size_t start_pos = 0, end_pos;
-	unsigned long long total_restore_size = 0, already_restored_size = 0;
+
+	part_settings.Restore_Name = Restore_Name;
+	part_settings.Part = NULL;
+	part_settings.partition_count = 0;
+	part_settings.total_restore_size = 0;
+	part_settings.adbbackup = false;
+	part_settings.PM_Method = PM_RESTORE;
 
 	gui_msg("restore_started=[RESTORE STARTED]");
 	gui_msg(Msg("restore_folder=Restore folder: '{1}'")(Restore_Name));
@@ -876,28 +940,31 @@
 	}
 	gui_msg("calc_restore=Calculating restore details...");
 	DataManager::GetValue("tw_restore_selected", Restore_List);
+
 	if (!Restore_List.empty()) {
 		end_pos = Restore_List.find(";", start_pos);
 		while (end_pos != string::npos && start_pos < Restore_List.size()) {
 			restore_path = Restore_List.substr(start_pos, end_pos - start_pos);
-			restore_part = Find_Partition_By_Path(restore_path);
-			if (restore_part != NULL) {
-				if (restore_part->Mount_Read_Only) {
-					gui_msg(Msg(msg::kError, "restore_read_only=Cannot restore {1} -- mounted read only.")(restore_part->Backup_Display_Name));
+			part_settings.Part = Find_Partition_By_Path(restore_path);
+			if (part_settings.Part != NULL) {
+				part_settings.Backup_FileName = part_settings.Part->Backup_Name + "." +  part_settings.Part->Current_File_System + ".win";
+				if (part_settings.Part->Mount_Read_Only) {
+					gui_msg(Msg(msg::kError, "restore_read_only=Cannot restore {1} -- mounted read only.")(part_settings.Part->Backup_Display_Name));
 					return false;
 				}
-				if (check_md5 > 0 && !restore_part->Check_MD5(Restore_Name))
+
+				if (check_md5 > 0 && !part_settings.Part->Check_MD5(Restore_Name))
 					return false;
-				partition_count++;
-				total_restore_size += restore_part->Get_Restore_Size(Restore_Name);
-				if (restore_part->Has_SubPartition) {
+				part_settings.partition_count++;
+				part_settings.total_restore_size += part_settings.Part->Get_Restore_Size(&part_settings);
+				if (part_settings.Part->Has_SubPartition) {
 					std::vector<TWPartition*>::iterator subpart;
 
 					for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
-						if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == restore_part->Mount_Point) {
+						if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == part_settings.Part->Mount_Point) {
 							if (check_md5 > 0 && !(*subpart)->Check_MD5(Restore_Name))
 								return false;
-							total_restore_size += (*subpart)->Get_Restore_Size(Restore_Name);
+							part_settings.total_restore_size += (*subpart)->Get_Restore_Size(&part_settings);
 						}
 					}
 				}
@@ -909,25 +976,29 @@
 		}
 	}
 
-	if (partition_count == 0) {
+	if (part_settings.partition_count == 0) {
 		gui_err("no_part_restore=No partitions selected for restore.");
 		return false;
 	}
 
-	gui_msg(Msg("restore_part_count=Restoring {1} partitions...")(partition_count));
-	gui_msg(Msg("total_restore_size=Total restore size is {1}MB")(total_restore_size / 1048576));
+	gui_msg(Msg("restore_part_count=Restoring {1} partitions...")(part_settings.partition_count));
+	gui_msg(Msg("total_restore_size=Total restore size is {1}MB")(part_settings.total_restore_size / 1048576));
 	DataManager::SetProgress(0.0);
-	ProgressTracking progress(total_restore_size);
+	ProgressTracking progress(part_settings.total_restore_size);
+	part_settings.progress = &progress;
 
 	start_pos = 0;
 	if (!Restore_List.empty()) {
 		end_pos = Restore_List.find(";", start_pos);
 		while (end_pos != string::npos && start_pos < Restore_List.size()) {
 			restore_path = Restore_List.substr(start_pos, end_pos - start_pos);
-			restore_part = Find_Partition_By_Path(restore_path);
-			if (restore_part != NULL) {
-				partition_count++;
-				if (!Restore_Partition(restore_part, Restore_Name, &progress))
+
+			part_settings.Part = Find_Partition_By_Path(restore_path);
+			if (part_settings.Part != NULL) {
+				part_settings.partition_count++;
+				part_settings.Backup_FileName = part_settings.Part->Backup_Name + "." +  part_settings.Part->Current_File_System + ".win";
+				part_settings.Full_Backup_Path = part_settings.Backup_Folder + "/" + part_settings.Backup_FileName + "/";
+				if (!Restore_Partition(&part_settings))
 					return false;
 			} else {
 				gui_msg(Msg(msg::kError, "restore_unable_locate=Unable to locate '{1}' partition for restoring.")(restore_path));
@@ -942,6 +1013,7 @@
 	time(&rStop);
 	gui_msg(Msg(msg::kHighlight, "restore_completed=[RESTORE COMPLETED IN {1} SECONDS]")((int)difftime(rStop,rStart)));
 	DataManager::SetValue("tw_file_progress", "");
+
 	return true;
 }
 
@@ -2170,21 +2242,23 @@
 	return false;
 }
 
-bool TWPartitionManager::Flash_Image(string Filename) {
+bool TWPartitionManager::Flash_Image(PartitionSettings *part_settings) {
 	int check, partition_count = 0;
 	TWPartition* flash_part = NULL;
-	string Flash_List, flash_path;
+	string Flash_List, flash_path, full_filename;
 	size_t start_pos = 0, end_pos = 0;
 
-	gui_msg("image_flash_start=[IMAGE FLASH STARTED]");
-	gui_msg(Msg("img_to_flash=Image to flash: '{1}'")(Filename));
+	full_filename = part_settings->Restore_Name + "/" + part_settings->Backup_FileName;
 
-	if (!TWFunc::Path_Exists(Filename)) {
-		if (!Mount_By_Path(Filename, true)) {
+	gui_msg("image_flash_start=[IMAGE FLASH STARTED]");
+	gui_msg(Msg("img_to_flash=Image to flash: '{1}'")(full_filename));
+
+	if (!TWFunc::Path_Exists(full_filename)) {
+		if (!Mount_By_Path(full_filename, true)) {
 			return false;
 		}
-		if (!TWFunc::Path_Exists(Filename)) {
-			gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")(Filename));
+		if (!TWFunc::Path_Exists(full_filename)) {
+			gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")(full_filename));
 			return false;
 		}
 	}
@@ -2218,7 +2292,7 @@
 
 	DataManager::SetProgress(0.0);
 	if (flash_part) {
-		if (!flash_part->Flash_Image(Filename))
+		if (!flash_part->Flash_Image(part_settings))
 			return false;
 	} else {
 		gui_err("invalid_flash=Invalid flash partition specified.");
diff --git a/partitions.hpp b/partitions.hpp
index 1ba0691..7052546 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -35,18 +35,46 @@
 	unsigned int selected;
 };
 
+enum PartitionManager_Op {                                                         // PartitionManager Restore Mode for Raw_Read_Write()
+	PM_BACKUP = 0,
+	PM_RESTORE = 1,
+};
+
+class TWPartition;
+
+struct PartitionSettings {                                                         // Settings for backup session
+	TWPartition* Part;                                                         // Partition to pass to the partition backup loop
+	std::string Backup_Folder;                                                 // Backup folder to put backup into
+	std::string Full_Backup_Path;                                              // Path to the current backup storage setting
+	std::string Backup_Name;                                                   // Name of partition
+	std::string Restore_Name;                                                  // Path to restore folder
+	std::string Backup_FileName;                                               // Name of the file to restore
+	bool adbbackup;                                                            // tell the system we are backing up over adb
+	bool adb_compression;                                                      // 0 == uncompressed, 1 == compressed
+	bool generate_md5;                                                         // tell system to create md5 for partitions
+	uint64_t total_restore_size;                                               // Total size of restored backup
+	uint64_t img_bytes_remaining;                                              // remaining img/emmc bytes to backup for progress indicator
+	uint64_t file_bytes_remaining;                                             // remaining file bytes to backup for progress indicator
+	uint64_t img_time;                                                         // used to calculate how fast we backup images
+	uint64_t file_time;                                                        // used to calculate how fast we backup files
+	uint64_t img_bytes;                                                        // total image bytes of all emmc partitions
+	uint64_t file_bytes;                                                       // total file bytes of all file based partitions
+	int partition_count;                                                       // Number of partitions to restore
+	ProgressTracking *progress;
+	enum PartitionManager_Op PM_Method;                                        //Current operation of backup or restore
+};
+
+enum Backup_Method_enum {
+	BM_NONE = 0,
+	BM_FILES = 1,
+	BM_DD = 2,
+	BM_FLASH_UTILS = 3,
+};
+
 // Partition class
 class TWPartition
 {
 public:
-	enum Backup_Method_enum {
-		NONE = 0,
-		FILES = 1,
-		DD = 2,
-		FLASH_UTILS = 3,
-	};
-
-public:
 	TWPartition();
 	virtual ~TWPartition();
 
@@ -65,18 +93,19 @@
 	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(const string& backup_folder, pid_t &tar_fork_pid, ProgressTracking *progress); // Backs up the partition to the folder specified
+	bool Backup(PartitionSettings *part_settings, 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(const string& restore_folder, ProgressTracking *progress);   // Restores the partition using the backup folder provided
-	unsigned long long Get_Restore_Size(const string& restore_folder);        // Returns the overall restore size of the backup
+	bool Restore(PartitionSettings *part_settings);                           // Restores the partition using the backup folder provided
+	unsigned long long Get_Restore_Size(PartitionSettings *part_settings);// Returns the overall restore size of the backup
 	string Backup_Method_By_Name();                                           // Returns a string of the backup method for human readable output
 	bool Decrypt(string Password);                                            // Decrypts the partition, return 0 for failure and -1 for success
 	bool Wipe_Encryption();                                                   // Ignores wipe commands for /data/media devices and formats the original block device
 	void Check_FS_Type();                                                     // Checks the fs type using blkid, does not do anything on MTD / yaffs2 because this crashes on some devices
 	bool Update_Size(bool Display_Error);                                     // Updates size information
 	void Recreate_Media_Folder();                                             // Recreates the /data/media folder
-	bool Flash_Image(const string& Filename);                                        // Flashes an image to the partition
+	bool Flash_Image(PartitionSettings *part_settings);                                        // Flashes an image to the partition
 	void Change_Mount_Read_Only(bool new_value);                              // Changes Mount_Read_Only to new_value
+	bool Is_Read_Only();                                                      // Check if system is read-only in TWRP
 	int Check_Lifetime_Writes();
 	int Decrypt_Adopted();
 	void Revert_Adopted();
@@ -85,6 +114,7 @@
 public:
 	string Current_File_System;                                               // Current file system
 	string Actual_Block_Device;                                               // Actual block device (one of primary, alternate, or decrypted)
+	string Backup_Display_Name;                                               // Name displayed in the partition list for backup selection
 	string MTD_Name;                                                          // Name of the partition for MTD devices
 	bool Is_Present;                                                          // Indicates if the partition is currently present as a block device
 	string Crypto_Key_Location;                                               // Location of the crypto key used for decrypting encrypted data partitions
@@ -123,13 +153,13 @@
 	bool Wipe_NTFS();                                                         // Uses mkntfs to wipe
 	bool Wipe_Data_Without_Wiping_Media();                                    // Uses rm -rf to wipe but does not wipe /data/media
 	bool Wipe_Data_Without_Wiping_Media_Func(const string& parent);           // Uses rm -rf to wipe but does not wipe /data/media
-	bool Backup_Tar(const string& backup_folder, ProgressTracking *progress, pid_t &tar_fork_pid); // Backs up using tar for file systems
-	bool Backup_Image(const string& backup_folder, ProgressTracking *progress); // Backs up using raw read/write for emmc memory types
-	bool Raw_Read_Write(const string& input_file, const string& output_file, const unsigned long long input_size, ProgressTracking *progress);
-	bool Backup_Dump_Image(const string& backup_folder, ProgressTracking *progress); // Backs up using dump_image for MTD memory types
-	string Get_Restore_File_System(const string& restore_folder);             // Returns the file system that was in place at the time of the backup
-	bool Restore_Tar(const string& restore_folder, const string& Restore_File_System, ProgressTracking *progress); // Restore using tar for file systems
-	bool Restore_Image(const string& restore_folder, const string& Restore_File_System, ProgressTracking *progress); // Restore using raw read/write for images
+	bool Backup_Tar(PartitionSettings *part_settings, pid_t *tar_fork_pid);   // Backs up using tar for file systems
+	bool Backup_Image(PartitionSettings *part_settings);                      // Backs up using raw read/write for emmc memory types
+	bool Raw_Read_Write(PartitionSettings *part_settings);
+	bool Backup_Dump_Image(PartitionSettings *part_settings);                 // Backs up using dump_image for MTD memory types
+	string Get_Restore_File_System(PartitionSettings *part_settings);         // Returns the file system that was in place at the time of the backup
+	bool Restore_Tar(PartitionSettings *part_settings);                       // Restore using tar for file systems
+	bool Restore_Image(PartitionSettings *part_settings);                     // Restore using dd for images
 	bool Get_Size_Via_statfs(bool Display_Error);                             // Get Partition size, used, and free space using statfs
 	bool Get_Size_Via_df(bool Display_Error);                                 // Get Partition size, used, and free space using df command
 	bool Make_Dir(string Path, bool Display_Error);                           // Creates a directory if it doesn't already exist
@@ -170,7 +200,6 @@
 	bool Mount_To_Decrypt;                                                    // Mount this partition during decrypt (/vendor, /firmware, etc in case we need proprietary libs or firmware files)
 	string Display_Name;                                                      // Display name for the GUI
 	string Backup_Name;                                                       // Backup name -- used for backup filenames
-	string Backup_Display_Name;                                               // Name displayed in the partition list for backup selection
 	string Storage_Name;                                                      // Name displayed in the partition list for storage selection
 	string Backup_FileName;                                                   // Actual backup filename
 	Backup_Method_enum Backup_Method;                                         // Method used for backup
@@ -214,8 +243,10 @@
 	int Mount_Settings_Storage(bool Display_Error);                           // Mounts the settings file storage location (usually internal)
 	TWPartition* Find_Partition_By_Path(string Path);                         // Returns a pointer to a partition based on path
 	int Check_Backup_Name(bool Display_Error);                                // Checks the current backup name to ensure that it is valid
-	int Run_Backup();                                                         // Initiates a backup in the current storage
+	int Run_Backup(bool adbbackup);                                           // Initiates a backup in the current storage
 	int Run_Restore(const string& Restore_Name);                              // Restores a backup
+	bool Write_ADB_Stream_Header(uint64_t partition_count);                   // Write ADB header over twrpbu FIFO
+	bool Write_ADB_Stream_Trailer();                                          // Write ADB trailer over twrpbu FIFO
 	void Set_Restore_Files(string Restore_Name);                              // Used to gather a list of available backup partitions for the user to select for a restore
 	int Wipe_By_Path(string Path);                                            // Wipes a partition based on path
 	int Wipe_By_Path(string Path, string New_File_System);                    // Wipes a partition based on path
@@ -250,21 +281,21 @@
 	bool Add_MTP_Storage(unsigned int Storage_ID);                            // Adds or removes an MTP Storage partition
 	bool Remove_MTP_Storage(string Mount_Point);                              // Adds or removes an MTP Storage partition
 	bool Remove_MTP_Storage(unsigned int Storage_ID);                         // Adds or removes an MTP Storage partition
-	bool Flash_Image(string Filename);                                        // Flashes an image to a selected partition from the partition list
 	void Translate_Partition(const char* path, const char* resource_name, const char* default_value);
 	void Translate_Partition(const char* path, const char* resource_name, const char* default_value, const char* storage_resource_name, const char* storage_default_value);
 	void Translate_Partition_Display_Names();                                 // Updates display names based on translations
 	void Decrypt_Adopted();                                                   // Attempt to identy and decrypt any adopted storage partitions
 	void Remove_Partition_By_Path(string Path);                               // Removes / erases a partition entry from the partition list
 
+	bool Flash_Image(PartitionSettings *part_settings);                        // Flashes an image to a selected partition from the partition list
+	bool Restore_Partition(struct PartitionSettings *part_settings);                  // Restore the partitions based on type
 	TWAtomicInt stop_backup;
 
 private:
 	void Setup_Settings_Storage_Partition(TWPartition* Part);                 // Sets up settings storage
 	void Setup_Android_Secure_Location(TWPartition* Part);                    // Sets up .android_secure if needed
 	bool Make_MD5(bool generate_md5, string Backup_Folder, string Backup_Filename); // Generates an MD5 after a backup is made
-	bool Backup_Partition(TWPartition* Part, const string& Backup_Folder, bool generate_md5, unsigned long *img_time, unsigned long *file_time, ProgressTracking *progress);
-	bool Restore_Partition(TWPartition* Part, const string& Restore_Name, ProgressTracking *progress);
+	bool Backup_Partition(struct PartitionSettings *part_settings);                  // Backup the partitions based on type
 	void Output_Partition(TWPartition* Part);                                 // Outputs partition details to the log
 	TWPartition* Find_Partition_By_MTP_Storage_ID(unsigned int Storage_ID);   // Returns a pointer to a partition based on MTP Storage ID
 	bool Add_Remove_MTP_Storage(TWPartition* Part, int message_type);         // Adds or removes an MTP Storage partition
@@ -273,7 +304,8 @@
 	pid_t mtppid;
 	bool mtp_was_enabled;
 	int mtp_write_fd;
-	pid_t tar_fork_pid;
+	pid_t tar_fork_pid;                                                       // PID of twrpTar fork
+	Backup_Method_enum Backup_Method;                                         // Method used for backup
 
 private:
 	std::vector<TWPartition*> Partitions;                                     // Vector list of all partitions
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index cba396a..3ec4c03 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -4,6 +4,7 @@
 
 #dummy file to trigger required modules
 include $(CLEAR_VARS)
+
 LOCAL_MODULE := teamwin
 LOCAL_MODULE_TAGS := eng
 LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
@@ -13,6 +14,7 @@
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/dump_image
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/flash_image
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/erase_image
+RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/bu
 ifneq ($(TW_USE_TOOLBOX), true)
 	RELINK_SOURCE_FILES += $(TARGET_OUT_OPTIONAL_EXECUTABLES)/busybox
 else
@@ -77,6 +79,7 @@
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libminzip.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmtdutils.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libtar.so
+RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libtwadbbu.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libutil-linux.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libblkid.so
 RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmmcutils.so
@@ -225,7 +228,6 @@
     endif
 endif
 TWRP_AUTOGEN := $(intermediates)/teamwin
-
 GEN := $(intermediates)/teamwin
 $(GEN): $(RELINK)
 $(GEN): $(RELINK_SOURCE_FILES) $(call intermediates-dir-for,EXECUTABLES,recovery)/recovery
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 1c633e7..8cc094f 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -151,7 +151,7 @@
 		return true;
 }
 
-int TWFunc::Get_File_Type(string fn) {
+Archive_Type TWFunc::Get_File_Type(string fn) {
 	string::size_type i = 0;
 	int firstbyte = 0, secondbyte = 0;
 	char header[3];
@@ -164,13 +164,10 @@
 	secondbyte = header[++i] & 0xff;
 
 	if (firstbyte == 0x1f && secondbyte == 0x8b)
-		return 1; // Compressed
+		return COMPRESSED;
 	else if (firstbyte == 0x4f && secondbyte == 0x41)
-		return 2; // Encrypted
-	else
-		return 0; // Unknown
-
-	return 0;
+		return ENCRYPTED;
+	return UNCOMPRESSED; // default
 }
 
 int TWFunc::Try_Decrypting_File(string fn, string password) {
@@ -752,7 +749,7 @@
 	while ((de = readdir(d)) != NULL) {
 		Filename = Restore_Path;
 		Filename += de->d_name;
-		if (TWFunc::Get_File_Type(Filename) == 2) {
+		if (TWFunc::Get_File_Type(Filename) == ENCRYPTED) {
 			if (TWFunc::Try_Decrypting_File(Filename, Password) < 2) {
 				DataManager::SetValue("tw_restore_password", ""); // Clear the bad password
 				DataManager::SetValue("tw_restore_display", "");  // Also clear the display mask
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 3f9b2ff..550c946 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -34,6 +34,13 @@
 	rb_download,
 } RebootCommand;
 
+enum Archive_Type {
+	UNCOMPRESSED = 0,
+	COMPRESSED,
+	ENCRYPTED,
+	COMPRESSED_ENCRYPTED
+};
+
 // Partition class
 class TWFunc
 {
@@ -46,7 +53,7 @@
 	static int Exec_Cmd(const string& cmd);                                     //execute a command
 	static int Wait_For_Child(pid_t pid, int *status, string Child_Name);       // Waits for pid to exit and checks exit status
 	static bool Path_Exists(string Path);                                       // Returns true if the path exists
-	static int Get_File_Type(string fn); // Determines file type, 0 for unknown, 1 for gzip, 2 for OAES encrypted
+	static Archive_Type Get_File_Type(string fn);                               // Determines file type, 0 for unknown, 1 for gzip, 2 for OAES encrypted
 	static int Try_Decrypting_File(string fn, string password); // -1 for some error, 0 for failed to decrypt, 1 for decrypted, 3 for decrypted and found gzip format
 	static unsigned long Get_File_Size(const string& Path);                            // Returns the size of a file
 	static std::string Remove_Trailing_Slashes(const std::string& path, bool leaveLast = false); // Normalizes the path, e.g /data//media/ -> /data/media
diff --git a/twrpDigest.cpp b/twrpDigest.cpp
index 0dd3ea9..ab8f456 100644
--- a/twrpDigest.cpp
+++ b/twrpDigest.cpp
@@ -48,13 +48,47 @@
 	md5fn = fn;
 }
 
+void twrpDigest::initMD5(void) {
+	MD5Init(&md5c);
+	md5string = "";
+}
+
+int twrpDigest::updateMD5stream(unsigned char* stream, int len) {
+	if (md5fn.empty()) {
+		MD5Update(&md5c, stream, len);
+	}
+	else {
+		return -1;
+	}
+	return 0;
+}
+
+void twrpDigest::finalizeMD5stream() {
+	MD5Final(md5sum, &md5c);
+}
+
+string twrpDigest::createMD5string() {
+	int i;
+	char hex[3];
+
+	for (i = 0; i < 16; ++i) {
+		snprintf(hex, 3, "%02x", md5sum[i]);
+		md5string += hex;
+	}
+	if (!md5fn.empty()) {
+		md5string += "  ";
+		md5string += basename((char*) md5fn.c_str());
+		md5string +=  + "\n";
+	}
+	return md5string;
+}
+
 int twrpDigest::computeMD5(void) {
 	string line;
-	struct MD5Context md5c;
 	FILE *file;
 	int len;
 	unsigned char buf[1024];
-	MD5Init(&md5c);
+	initMD5();
 	file = fopen(md5fn.c_str(), "rb");
 	if (file == NULL)
 		return -1;
@@ -67,21 +101,13 @@
 }
 
 int twrpDigest::write_md5digest(void) {
-	int i;
-	string md5string, md5file;
-	char hex[3];
+	string md5file, md5str;
 	md5file = md5fn + ".md5";
 
-	for (i = 0; i < 16; ++i) {
-		snprintf(hex, 3, "%02x", md5sum[i]);
-		md5string += hex;
-	}
-	md5string += "  ";
-	md5string += basename((char*) md5fn.c_str());
-	md5string +=  + "\n";
-	TWFunc::write_file(md5file, md5string);
+	md5str = createMD5string();
+	TWFunc::write_file(md5file, md5str);
 	tw_set_default_metadata(md5file.c_str());
-	LOGINFO("MD5 for %s: %s\n", md5fn.c_str(), md5string.c_str());
+	LOGINFO("MD5 for %s: %s\n", md5fn.c_str(), md5str.c_str());
 	return 0;
 }
 
@@ -124,7 +150,7 @@
 	string buf;
 	char hex[3];
 	int i, ret;
-	string md5string;
+	string md5str;
 
 	ret = read_md5digest();
 	if (ret != 0)
@@ -136,9 +162,9 @@
 	computeMD5();
 	for (i = 0; i < 16; ++i) {
 		snprintf(hex, 3, "%02x", md5sum[i]);
-		md5string += hex;
+		md5str += hex;
 	}
-	if (tokens.at(0) != md5string) {
+	if (tokens.at(0) != md5str) {
 		gui_err("md5_fail=MD5 does not match");
 		return -2;
 	}
diff --git a/twrpDigest.hpp b/twrpDigest.hpp
index 2c08ec5..7ec25ed 100644
--- a/twrpDigest.hpp
+++ b/twrpDigest.hpp
@@ -29,10 +29,16 @@
 	int computeMD5(void);
 	int verify_md5digest(void);
 	int write_md5digest(void);
+	int updateMD5stream(unsigned char* stream, int len);
+	void finalizeMD5stream(void);
+	string createMD5string(void);
+	void initMD5(void);
 
 private:
 	int read_md5digest(void);
+	struct MD5Context md5c;
 	string md5fn;
 	string line;
 	unsigned char md5sum[MD5LENGTH];
+	string md5string;
 };
diff --git a/twrpTar.cpp b/twrpTar.cpp
index b46f10f..dcbb282 100644
--- a/twrpTar.cpp
+++ b/twrpTar.cpp
@@ -38,9 +38,13 @@
 #include <dirent.h>
 #include <libgen.h>
 #include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <zlib.h>
+#include <semaphore.h>
 #include "twrpTar.hpp"
 #include "twcommon.h"
 #include "variables.h"
+#include "adbbu/libtwadbbu.hpp"
 #include "twrp-functions.hpp"
 #include "gui/gui.hpp"
 #include "progresstracking.hpp"
@@ -91,19 +95,30 @@
 	_exit(255);
 }
 
-int twrpTar::createTarFork(ProgressTracking *progress, pid_t &fork_pid) {
+void twrpTar::Set_Archive_Type(Archive_Type archive_type) {
+	current_archive_type = archive_type;
+}
+
+int twrpTar::createTarFork(pid_t *tar_fork_pid) {
 	int status = 0;
-	pid_t rc_pid, tar_fork_pid;
+	pid_t rc_pid;
 	int progress_pipe[2], ret;
+	char cmd[512];
 
 	file_count = 0;
 
+	if (part_settings->adbbackup) {
+		std::string Backup_FileName(tarfn);
+		if (!twadbbu::Write_TWFN(Backup_FileName, Total_Backup_Size, use_compression))
+			return -1;
+	}
+
 	if (pipe(progress_pipe) < 0) {
 		LOGINFO("Error creating progress tracking pipe\n");
 		gui_err("backup_error=Error creating backup.");
 		return -1;
 	}
-	if ((tar_fork_pid = fork()) == -1) {
+	if ((*tar_fork_pid = fork()) == -1) {
 		LOGINFO("create tar failed to fork.\n");
 		gui_err("backup_error=Error creating backup.");
 		close(progress_pipe[0]);
@@ -111,7 +126,7 @@
 		return -1;
 	}
 
-	if (tar_fork_pid == 0) {
+	if (*tar_fork_pid == 0) {
 		// Child process
 		// Child closes input side of progress pipe
 		signal(SIGUSR2, twrpTar::Signal_Kill);
@@ -254,6 +269,7 @@
 				reg.use_compression = use_compression;
 				reg.split_archives = 1;
 				reg.progress_pipe_fd = progress_pipe_fd;
+				reg.part_settings = part_settings;
 				LOGINFO("Creating unencrypted backup...\n");
 				if (createList((void*)&reg) != 0) {
 					LOGINFO("Error creating unencrypted backup.\n");
@@ -297,6 +313,7 @@
 				enc[i].use_compression = use_compression;
 				enc[i].split_archives = 1;
 				enc[i].progress_pipe_fd = progress_pipe_fd;
+				enc[i].part_settings = part_settings;
 				LOGINFO("Start encryption thread %i\n", i);
 				ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]);
 				if (ret) {
@@ -371,7 +388,8 @@
 			reg.use_compression = use_compression;
 			reg.setsize(Total_Backup_Size);
 			reg.progress_pipe_fd = progress_pipe_fd;
-			if (Total_Backup_Size > MAX_ARCHIVE_SIZE) {
+			reg.part_settings = part_settings;
+			if (Total_Backup_Size > MAX_ARCHIVE_SIZE && !part_settings->adbbackup) {
 				gui_msg("split_backup=Breaking backup file into multiple archives...");
 				reg.split_archives = 1;
 			} else {
@@ -393,8 +411,6 @@
 		unsigned long long fs, size_backup = 0, files_backup = 0, file_count = 0;
 		int first_data = 0;
 
-		fork_pid = tar_fork_pid;
-
 		// Parent closes output side
 		close(progress_pipe[1]);
 
@@ -408,14 +424,14 @@
 			} else if (first_data == 1) {
 				// Second incoming data is total size
 				first_data = 2;
-				progress->SetSizeCount(fs, file_count);
+				part_settings->progress->SetSizeCount(fs, file_count);
 			} else {
 				if (fs > 0) {
 					size_backup += fs;
-					progress->UpdateSize(size_backup);
+					part_settings->progress->UpdateSize(size_backup);
 				} else { // fs == 0 increments the file counter
 					files_backup++;
-					progress->UpdateSizeCount(size_backup, files_backup);
+					part_settings->progress->UpdateSizeCount(size_backup, files_backup);
 				}
 			}
 		}
@@ -423,29 +439,31 @@
 #ifndef BUILD_TWRPTAR_MAIN
 		DataManager::SetValue("tw_file_progress", "");
 		DataManager::SetValue("tw_size_progress", "");
-		progress->DisplayFileCount(false);
-		progress->UpdateDisplayDetails(true);
+		part_settings->progress->DisplayFileCount(false);
+		part_settings->progress->UpdateDisplayDetails(true);
 
-		InfoManager backup_info(backup_folder + partition_name + ".info");
-		backup_info.SetValue("backup_size", size_backup);
-		if (use_compression && use_encryption)
-			backup_info.SetValue("backup_type", 3);
-		else if (use_encryption)
-			backup_info.SetValue("backup_type", 2);
-		else if (use_compression)
-			backup_info.SetValue("backup_type", 1);
-		else
-			backup_info.SetValue("backup_type", 0);
-		backup_info.SetValue("file_count", files_backup);
-		backup_info.SaveValues();
+		if (!part_settings->adbbackup) {
+			InfoManager backup_info(backup_folder + partition_name + ".info");
+			backup_info.SetValue("backup_size", size_backup);
+			if (use_compression && use_encryption)
+				backup_info.SetValue("backup_type", COMPRESSED_ENCRYPTED);
+			else if (use_encryption)
+				backup_info.SetValue("backup_type", ENCRYPTED);
+			else if (use_compression)
+				backup_info.SetValue("backup_type", COMPRESSED);
+			else
+				backup_info.SetValue("backup_type", UNCOMPRESSED);
+			backup_info.SetValue("file_count", files_backup);
+			backup_info.SaveValues();
+		}
 #endif //ndef BUILD_TWRPTAR_MAIN
-		if (TWFunc::Wait_For_Child(tar_fork_pid, &status, "createTarFork()") != 0)
+		if (TWFunc::Wait_For_Child(*tar_fork_pid, &status, "createTarFork()") != 0)
 			return -1;
 	}
 	return 0;
 }
 
-int twrpTar::extractTarFork(ProgressTracking *progress) {
+int twrpTar::extractTarFork() {
 	int status = 0;
 	pid_t rc_pid, tar_fork_pid;
 	int progress_pipe[2], ret;
@@ -463,12 +481,13 @@
 		{
 			close(progress_pipe[0]);
 			progress_pipe_fd = progress_pipe[1];
-			if (TWFunc::Path_Exists(tarfn)) {
+			if (TWFunc::Path_Exists(tarfn) || part_settings->adbbackup) {
 				LOGINFO("Single archive\n");
 				if (extract() != 0)
 					_exit(-1);
-				else
+				else {
 					_exit(0);
+				}
 			} else {
 				LOGINFO("Multiple archives\n");
 				string temp;
@@ -494,6 +513,7 @@
 					tars[0].basefn = basefn;
 					tars[0].thread_id = 0;
 					tars[0].progress_pipe_fd = progress_pipe_fd;
+					tars[0].part_settings = part_settings;
 					if (extractMulti((void*)&tars[0]) != 0) {
 						LOGINFO("Error extracting split archive.\n");
 						gui_err("restore_error=Error during restore process.");
@@ -535,6 +555,7 @@
 						tars[i].setpassword(password);
 						tars[i].thread_id = i;
 						tars[i].progress_pipe_fd = progress_pipe_fd;
+						tars[i].part_settings = part_settings;
 						LOGINFO("Creating extract thread ID %i\n", i);
 						ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]);
 						if (ret) {
@@ -596,10 +617,10 @@
 			// Read progress data from children
 			while (read(progress_pipe[0], &fs, sizeof(fs)) > 0) {
 				size_backup += fs;
-				progress->UpdateSize(size_backup);
+				part_settings->progress->UpdateSize(size_backup);
 			}
 			close(progress_pipe[0]);
-			progress->UpdateDisplayDetails(true);
+			part_settings->progress->UpdateDisplayDetails(true);
 
 			if (TWFunc::Wait_For_Child(tar_fork_pid, &status, "extractTarFork()") != 0)
 				return -1;
@@ -675,18 +696,31 @@
 		gui_err("restore_error=Error during restore process.");
 		return -1;
 	}
+	if (part_settings->adbbackup) {
+		if (!twadbbu::Write_TWEOF())
+			return -1;
+	}
 	return 0;
 }
 
 int twrpTar::extract() {
-	Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
+	if (!part_settings->adbbackup)  {
+		LOGINFO("Setting archive type\n");
+		Set_Archive_Type(TWFunc::Get_File_Type(tarfn));
+	}
+	else {
+		if (part_settings->adb_compression == 1) 
+			current_archive_type = COMPRESSED;
+		else
+			current_archive_type = UNCOMPRESSED;
+	}
 
-	if (Archive_Current_Type == 1) {
+	if (current_archive_type == COMPRESSED) {
 		//if you return the extractTGZ function directly, stack crashes happen
 		LOGINFO("Extracting gzipped tar\n");
 		int ret = extractTar();
 		return ret;
-	} else if (Archive_Current_Type == 2) {
+	} else if (current_archive_type == ENCRYPTED) {
 		int ret = TWFunc::Try_Decrypting_File(tarfn, password);
 		if (ret < 1) {
 			gui_msg(Msg(msg::kError, "fail_decrypt_tar=Failed to decrypt tar file '{1}'")(tarfn));
@@ -699,7 +733,7 @@
 		}
 		if (ret == 3) {
 			LOGINFO("Extracting encrypted and compressed tar.\n");
-			Archive_Current_Type = 3;
+			current_archive_type = COMPRESSED_ENCRYPTED;
 		} else
 			LOGINFO("Extracting encrypted tar.\n");
 		return extractTar();
@@ -727,7 +761,12 @@
 	} else {
 		include_root_dir = false;
 	}
-	LOGINFO("Creating tar file '%s'\n", tarfn.c_str());
+
+	if (part_settings->adbbackup)
+	    LOGINFO("Writing tar file '%s' to adb backup\n", tarfn.c_str());
+	else
+	    LOGINFO("Creating tar file '%s'\n", tarfn.c_str());
+
 	if (createTar() != 0) {
 		LOGINFO("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
 		gui_err("backup_error=Error creating backup.");
@@ -786,7 +825,6 @@
 }
 
 void* twrpTar::createList(void *cookie) {
-
 	twrpTar* threadTar = (twrpTar*) cookie;
 	if (threadTar->tarList(threadTar->ItemList, threadTar->thread_id) != 0) {
 		LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
@@ -797,7 +835,6 @@
 }
 
 void* twrpTar::extractMulti(void *cookie) {
-
 	twrpTar* threadTar = (twrpTar*) cookie;
 	int archive_count = 0;
 	string temp = threadTar->basefn + "%i%02i";
@@ -844,7 +881,7 @@
 
 	if (use_encryption && use_compression) {
 		// Compressed and encrypted
-		Archive_Current_Type = 3;
+		current_archive_type = COMPRESSED_ENCRYPTED;
 		LOGINFO("Using encryption and compression...\n");
 		int i, pipes[4];
 
@@ -858,7 +895,7 @@
 			gui_err("backup_error=Error creating backup.");
 			return -1;
 		}
-		int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+		output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
 		if (output_fd < 0) {
 			gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
 			for (i = 0; i < 4; i++)
@@ -936,10 +973,16 @@
 		}
 	} else if (use_compression) {
 		// Compressed
-		Archive_Current_Type = 1;
+		current_archive_type = COMPRESSED;
 		LOGINFO("Using compression...\n");
 		int pigzfd[2];
-		int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+		if (part_settings->adbbackup) {
+			LOGINFO("opening TW_ADB_BACKUP compressed stream\n");
+			output_fd = open(TW_ADB_BACKUP, O_WRONLY);
+		}
+		else {
+			output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+		}
 		if (output_fd < 0) {
 			gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
 			close(pigzfd[0]);
@@ -988,10 +1031,10 @@
 		}
 	} else if (use_encryption) {
 		// Encrypted
-		Archive_Current_Type = 2;
+		current_archive_type = ENCRYPTED;
 		LOGINFO("Using encryption...\n");
 		int oaesfd[2];
-		int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+		output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
 		if (output_fd < 0) {
 			gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
 			return -1;
@@ -1041,10 +1084,22 @@
 		// Not compressed or encrypted
 		init_libtar_buffer(0, progress_pipe_fd);
 		tar_type = { open, close, read, write_tar };
-		if (tar_open(&t, charTarFile, &tar_type, O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1) {
-			LOGINFO("tar_open error opening '%s'\n", tarfn.c_str());
-			gui_err("backup_error=Error creating backup.");
-			return -1;
+		if (part_settings->adbbackup) {
+			LOGINFO("Opening TW_ADB_BACKUP uncompressed stream\n");
+			tar_type = { open, close, read, write_tar_no_buffer };
+			output_fd = open(TW_ADB_BACKUP, O_WRONLY);
+			if(tar_fdopen(&t, output_fd, charRootDir, &tar_type, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
+				close(output_fd);
+				LOGERR("tar_fdopen failed\n");
+				return -1;
+			}
+		}
+		else {
+			if (tar_open(&t, charTarFile, &tar_type, O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1) {
+				LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
+				gui_err("backup_error=Error creating backup.");
+				return -1;
+			}
 		}
 	}
 	return 0;
@@ -1055,10 +1110,10 @@
 	char* charTarFile = (char*) tarfn.c_str();
 	string Password;
 
-	if (Archive_Current_Type == 3) {
+	if (current_archive_type == COMPRESSED_ENCRYPTED) {
 		LOGINFO("Opening encrypted and compressed backup...\n");
 		int i, pipes[4];
-		int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
+		input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
 		if (input_fd < 0) {
 			gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
 			return -1;
@@ -1144,10 +1199,10 @@
 				}
 			}
 		}
-	} else if (Archive_Current_Type == 2) {
+	} else if (current_archive_type == ENCRYPTED) {
 		LOGINFO("Opening encrypted backup...\n");
 		int oaesfd[2];
-		int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
+		input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
 		if (input_fd < 0) {
 			gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
 			return -1;
@@ -1192,14 +1247,22 @@
 				return -1;
 			}
 		}
-	} else if (Archive_Current_Type == 1) {
-		LOGINFO("Opening as a gzip...\n");
+	} else if (current_archive_type == COMPRESSED) {
 		int pigzfd[2];
-		int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
+
+		LOGINFO("Opening as a gzip...\n");
+		if (part_settings->adbbackup)  {
+			LOGINFO("opening TW_ADB_RESTORE compressed stream\n");
+			input_fd = open(TW_ADB_RESTORE, O_RDONLY | O_LARGEFILE);
+		}
+		else
+			input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
+
 		if (input_fd < 0) {
 			gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
 			return -1;
 		}
+
 		if (pipe(pigzfd) < 0) {
 			LOGINFO("Error creating pipe\n");
 			gui_err("restore_error=Error during restore process.");
@@ -1218,8 +1281,8 @@
 		} else if (pigz_pid == 0) {
 			// Child
 			close(pigzfd[0]);
-			dup2(input_fd, 0); // remap input fd to stdin
 			dup2(pigzfd[1], 1); // remap stdout
+			dup2(input_fd, 0); // remap input fd to stdin
 			if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
 				close(pigzfd[1]);
 				close(input_fd);
@@ -1231,17 +1294,30 @@
 			// Parent
 			close(pigzfd[1]); // close parent output
 			fd = pigzfd[0];   // copy parent input
-			if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
+			if (tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
 				close(fd);
 				LOGINFO("tar_fdopen failed\n");
 				gui_err("restore_error=Error during restore process.");
 				return -1;
 			}
 		}
-	} else if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
-		LOGINFO("Unable to open tar archive '%s'\n", charTarFile);
-		gui_err("restore_error=Error during restore process.");
-		return -1;
+	} else  {
+		if (part_settings->adbbackup) {
+			LOGINFO("Opening TW_ADB_RESTORE uncompressed stream\n");
+			input_fd = open(TW_ADB_RESTORE, O_RDONLY);
+			if (tar_fdopen(&t, input_fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
+				LOGERR("Unable to open tar archive '%s'\n", charTarFile);
+				gui_err("restore_error=Error during restore process.");
+				return -1;
+			}
+		}
+		else {
+			if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
+				LOGERR("Unable to open tar archive '%s'\n", charTarFile);
+				gui_err("restore_error=Error during restore process.");
+				return -1;
+			}
+		}
 	}
 	return 0;
 }
@@ -1281,6 +1357,7 @@
 }
 
 int twrpTar::closeTar() {
+	LOGINFO("Closing tar\n");
 	flush_libtar_buffer(t->fd);
 	if (tar_append_eof(t) != 0) {
 		LOGINFO("tar_append_eof(): %s\n", strerror(errno));
@@ -1291,7 +1368,7 @@
 		LOGINFO("Unable to close tar archive: '%s'\n", tarfn.c_str());
 		return -1;
 	}
-	if (Archive_Current_Type > 0) {
+	if (current_archive_type > 0) {
 		close(fd);
 		int status;
 		if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
@@ -1300,19 +1377,27 @@
 			return -1;
 	}
 	free_libtar_buffer();
-	if (use_compression && !use_encryption) {
-		string gzname = tarfn + ".gz";
-		if (TWFunc::Path_Exists(gzname)) {
-			rename(gzname.c_str(), tarfn.c_str());
+	if (!part_settings->adbbackup) {
+		if (use_compression && !use_encryption) {
+			string gzname = tarfn + ".gz";
+			if (TWFunc::Path_Exists(gzname)) {
+				rename(gzname.c_str(), tarfn.c_str());
+			}
 		}
-	}
-	if (TWFunc::Get_File_Size(tarfn) == 0) {
-		gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(tarfn));
-		return -1;
-	}
+		if (TWFunc::Get_File_Size(tarfn) == 0) {
+			gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(tarfn));
+			return -1;
+		}
 #ifndef BUILD_TWRPTAR_MAIN
-	tw_set_default_metadata(tarfn.c_str());
+		tw_set_default_metadata(tarfn.c_str());
 #endif
+	}
+	else {
+		if (!twadbbu::Write_TWEOF())
+			return -1;
+	}
+	close(input_fd);
+	close(output_fd);
 	return 0;
 }
 
@@ -1335,7 +1420,7 @@
 	char* searchstr = (char*)entry.c_str();
 	int ret;
 
-	Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
+	Set_Archive_Type(TWFunc::Get_File_Type(tarfn));
 
 	if (openTar() == -1)
 		ret = 0;
@@ -1349,15 +1434,14 @@
 }
 
 unsigned long long twrpTar::get_size() {
-	if (TWFunc::Path_Exists(tarfn)) {
+	if (TWFunc::Path_Exists(tarfn) && !part_settings->adbbackup) {
 		LOGINFO("Single archive\n");
-		int type = 0;
-		return uncompressedSize(tarfn, &type);
+		return uncompressedSize(tarfn);
 	} else {
 		LOGINFO("Multiple archives\n");
 		string temp;
 		char actual_filename[255];
-		int archive_count = 0, i, type = 0, temp_type = 0;
+		int archive_count = 0;
 		unsigned long long total_restore_size = 0;
 
 		basefn = tarfn;
@@ -1365,46 +1449,45 @@
 		tarfn += "000";
 		thread_id = 0;
 		sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
-		if (!TWFunc::Path_Exists(actual_filename)) {
-			LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
-			return 0;
-		}
-		for (i = 0; i < 9; i++) {
-			archive_count = 0;
-			sprintf(actual_filename, temp.c_str(), i, archive_count);
-			while (TWFunc::Path_Exists(actual_filename)) {
-				total_restore_size += uncompressedSize(actual_filename, &temp_type);
-				if (temp_type > type)
-					type = temp_type;
-				archive_count++;
-				if (archive_count > 99)
-					break;
-				sprintf(actual_filename, temp.c_str(), i, archive_count);
+		if (!part_settings->adbbackup) {
+			if (!TWFunc::Path_Exists(actual_filename)) {
+				LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
+				return 0;
 			}
+			for (int i = 0; i < 9; i++) {
+				archive_count = 0;
+				sprintf(actual_filename, temp.c_str(), i, archive_count);
+				while (TWFunc::Path_Exists(actual_filename)) {
+					total_restore_size += uncompressedSize(actual_filename);
+					archive_count++;
+					if (archive_count > 99)
+						break;
+					sprintf(actual_filename, temp.c_str(), i, archive_count);
+				}
+			}
+	#ifndef BUILD_TWRPTAR_MAIN
+	        if (!part_settings->adbbackup) {
+			InfoManager backup_info(tarfn + ".info");
+			backup_info.SetValue("backup_size", total_restore_size);
+			backup_info.SetValue("backup_type", current_archive_type);
+			backup_info.SaveValues();
+	        }
+	#endif //ndef BUILD_TWRPTAR_MAIN
 		}
-#ifndef BUILD_TWRPTAR_MAIN
-		InfoManager backup_info(backup_folder + "/" + partition_name + ".info");
-		backup_info.SetValue("backup_size", total_restore_size);
-		backup_info.SetValue("backup_type", type);
-		backup_info.SaveValues();
-#endif //ndef BUILD_TWRPTAR_MAIN
 		return total_restore_size;
 	}
 	return 0;
 }
 
-unsigned long long twrpTar::uncompressedSize(string filename, int *archive_type) {
-	int type = 0;
+unsigned long long twrpTar::uncompressedSize(string filename) {
 	unsigned long long total_size = 0;
 	string Tar, Command, result;
 	vector<string> split;
 
-	Tar = TWFunc::Get_Filename(filename);
-	type = TWFunc::Get_File_Type(filename);
-	if (type == 0) {
+	Set_Archive_Type(TWFunc::Get_File_Type(tarfn));
+	if (current_archive_type == UNCOMPRESSED) {
 		total_size = TWFunc::Get_File_Size(filename);
-		*archive_type = 0;
-	} else if (type == 1) {
+	} else if (current_archive_type == COMPRESSED) {
 		// Compressed
 		Command = "pigz -l '" + filename + "'";
 		/* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
@@ -1421,11 +1504,9 @@
 			if (split.size() > 4)
 			total_size = atoi(split[5].c_str());
 		}
-		*archive_type = 1;
-	} else if (type == 2) {
+	} else if (current_archive_type == COMPRESSED_ENCRYPTED) {
 		// File is encrypted and may be compressed
 		int ret = TWFunc::Try_Decrypting_File(filename, password);
-		*archive_type = 2;
 		if (ret < 1) {
 			gui_msg(Msg(msg::kError, "fail_decrypt_tar=Failed to decrypt tar file '{1}'")(tarfn));
 			total_size = TWFunc::Get_File_Size(filename);
@@ -1433,7 +1514,6 @@
 			LOGERR("Decrypted file is not in tar format.\n");
 			total_size = TWFunc::Get_File_Size(filename);
 		} else if (ret == 3) {
-			*archive_type = 3;
 			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. */
diff --git a/twrpTar.hpp b/twrpTar.hpp
index 8ef5020..49d373c 100644
--- a/twrpTar.hpp
+++ b/twrpTar.hpp
@@ -29,6 +29,8 @@
 #include <vector>
 #include "twrpDU.hpp"
 #include "progresstracking.hpp"
+#include "partitions.hpp"
+#include "twrp-functions.hpp"
 
 using namespace std;
 
@@ -42,17 +44,19 @@
 	unsigned thread_id;
 };
 
+
 class twrpTar {
 public:
 	twrpTar();
 	virtual ~twrpTar();
-	int createTarFork(ProgressTracking *progress, pid_t &fork_pid);
-	int extractTarFork(ProgressTracking *progress);
+	int createTarFork(pid_t *tar_fork_pid);
+	int extractTarFork();
 	void setfn(string fn);
 	void setdir(string dir);
 	void setsize(unsigned long long backup_size);
 	void setpassword(string pass);
 	unsigned long long get_size();
+	void Set_Archive_Type(Archive_Type archive_type);
 
 public:
 	int use_encryption;
@@ -64,6 +68,7 @@
 	int progress_pipe_fd;
 	string partition_name;
 	string backup_folder;
+	PartitionSettings *part_settings;
 
 private:
 	int extract();
@@ -80,16 +85,17 @@
 	static void* createList(void *cookie);
 	static void* extractMulti(void *cookie);
 	int tarList(std::vector<TarListStruct> *TarList, unsigned thread_id);
-	unsigned long long uncompressedSize(string filename, int *archive_type);
+	unsigned long long uncompressedSize(string filename);
 	static void Signal_Kill(int signum);
 
-	int Archive_Current_Type;
+	enum Archive_Type current_archive_type;
 	unsigned long long Archive_Current_Size;
 	unsigned long long Total_Backup_Size;
 	bool include_root_dir;
 	TAR *t;
 	tartype_t tar_type; // Only used in createTar() but variable must persist while the tar is open
 	int fd;
+	int input_fd;                                                                   // this stores the fd for libtar to write to
 	pid_t pigz_pid;
 	pid_t oaes_pid;
 	unsigned long long file_count;
@@ -100,5 +106,7 @@
 	string password;
 
 	std::vector<TarListStruct> *ItemList;
+	int output_fd;                                                                  // this stores the output fd that gzip will read from
+	int adb_control_twrp_fd, adb_control_bu_fd;                                     // fds for twrp to twrp bu and bu to twrp control fifos
 	unsigned thread_id;
 };