Track backup and restore progress

Track backup and restore progress based on the sizes of the files
as they are being added to the tar backup file. Update the
progress bar based on the sizes of the files.

Change-Id: Idf649efa1db3e91830b4b2add86203a3f30042ff
diff --git a/Android.mk b/Android.mk
index 1b4cb07..c864ff0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,7 +24,8 @@
     twrpTar.cpp \
 	twrpDU.cpp \
     twrpDigest.cpp \
-    find_file.cpp
+    find_file.cpp \
+    infomanager.cpp
 
 LOCAL_SRC_FILES += \
     data.cpp \
diff --git a/gui/devices/1024x600/res/ui.xml b/gui/devices/1024x600/res/ui.xml
index d547719..4795ce0 100755
--- a/gui/devices/1024x600/res/ui.xml
+++ b/gui/devices/1024x600/res/ui.xml
@@ -2304,6 +2304,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col1_x%" y="%row2_text_y%" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col_right_x%" y="%row2_text_y%" placement="1" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2679,6 +2691,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/1024x768/res/ui.xml b/gui/devices/1024x768/res/ui.xml
index f404b46..d041c50 100644
--- a/gui/devices/1024x768/res/ui.xml
+++ b/gui/devices/1024x768/res/ui.xml
@@ -2304,6 +2304,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col1_x%" y="%row2_text_y%" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col_right_x%" y="%row2_text_y%" placement="1" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2679,6 +2691,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml
index 28130b7..f95ae09 100644
--- a/gui/devices/1080x1920/res/ui.xml
+++ b/gui/devices/1080x1920/res/ui.xml
@@ -2056,6 +2056,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2429,6 +2441,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/1200x1920/res/ui.xml b/gui/devices/1200x1920/res/ui.xml
index d198139..0630e10 100644
--- a/gui/devices/1200x1920/res/ui.xml
+++ b/gui/devices/1200x1920/res/ui.xml
@@ -2059,6 +2059,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2432,6 +2444,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/1280x800/res/ui.xml b/gui/devices/1280x800/res/ui.xml
index 21fc3b7..fdd2059 100644
--- a/gui/devices/1280x800/res/ui.xml
+++ b/gui/devices/1280x800/res/ui.xml
@@ -2304,6 +2304,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col1_x%" y="%row2_text_y%" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col_right_x%" y="%row2_text_y%" placement="1" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2679,6 +2691,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/1600x2560/res/ui.xml b/gui/devices/1600x2560/res/ui.xml
index b6ca28c..95ef1d1 100644
--- a/gui/devices/1600x2560/res/ui.xml
+++ b/gui/devices/1600x2560/res/ui.xml
@@ -2061,6 +2061,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2434,6 +2446,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -3902,7 +3920,7 @@
 				<resource base="slider" used="slider-used" touch="slider-touch" />
 				<action function="page">filemanageracction</action>
 			</object>
-			
+
 			<object type="text" color="%text_color%">
 				<font resource="font" />
 				<placement x="%center_x%" y="%slider_text_y%" placement="4" />
@@ -3918,7 +3936,7 @@
 				<touch key="home" />
 				<action function="page">main</action>
 			</object>
-				
+
 			<object type="template" name="footer" />
 		</page>
 
diff --git a/gui/devices/1920x1200/res/ui.xml b/gui/devices/1920x1200/res/ui.xml
index 5ee5b46..2622a88 100644
--- a/gui/devices/1920x1200/res/ui.xml
+++ b/gui/devices/1920x1200/res/ui.xml
@@ -2304,6 +2304,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col1_x%" y="%row2_text_y%" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col_right_x%" y="%row2_text_y%" placement="1" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2679,6 +2691,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/2560x1600/res/ui.xml b/gui/devices/2560x1600/res/ui.xml
index 25b8619..06880b2 100644
--- a/gui/devices/2560x1600/res/ui.xml
+++ b/gui/devices/2560x1600/res/ui.xml
@@ -2304,6 +2304,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col1_x%" y="%row2_text_y%" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col_right_x%" y="%row2_text_y%" placement="1" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2679,6 +2691,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/320x480/res/ui.xml b/gui/devices/320x480/res/ui.xml
index 369b994..fff8533 100644
--- a/gui/devices/320x480/res/ui.xml
+++ b/gui/devices/320x480/res/ui.xml
@@ -2043,6 +2043,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2416,6 +2428,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml
index 72b44e5..6baa702 100644
--- a/gui/devices/480x800/res/ui.xml
+++ b/gui/devices/480x800/res/ui.xml
@@ -2043,6 +2043,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2416,6 +2428,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/480x854/res/ui.xml b/gui/devices/480x854/res/ui.xml
index 5026f40..4f5a7c9 100644
--- a/gui/devices/480x854/res/ui.xml
+++ b/gui/devices/480x854/res/ui.xml
@@ -2042,6 +2042,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2415,6 +2427,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/540x960/res/ui.xml b/gui/devices/540x960/res/ui.xml
index bd39a18..11c9490 100644
--- a/gui/devices/540x960/res/ui.xml
+++ b/gui/devices/540x960/res/ui.xml
@@ -2043,6 +2043,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2416,6 +2428,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/720x1280/res/ui.xml b/gui/devices/720x1280/res/ui.xml
index c9e6862..1575485 100644
--- a/gui/devices/720x1280/res/ui.xml
+++ b/gui/devices/720x1280/res/ui.xml
@@ -2056,6 +2056,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2429,6 +2441,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/800x1280/res/ui.xml b/gui/devices/800x1280/res/ui.xml
index b4cbb50..abd62de 100755
--- a/gui/devices/800x1280/res/ui.xml
+++ b/gui/devices/800x1280/res/ui.xml
@@ -2044,6 +2044,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row3_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2417,6 +2429,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/gui/devices/800x480/res/ui.xml b/gui/devices/800x480/res/ui.xml
index 272bf64..6a2c08f 100755
--- a/gui/devices/800x480/res/ui.xml
+++ b/gui/devices/800x480/res/ui.xml
@@ -2312,6 +2312,18 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col1_x%" y="%row2_text_y%" />
+				<text>%tw_file_progress%</text>
+			</object>
+
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%col_right_x%" y="%row2_text_y%" placement="1" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
@@ -2687,6 +2699,12 @@
 				<text>%tw_operation% %tw_partition%</text>
 			</object>
 
+			<object type="text" color="%text_color%">
+				<font resource="font" />
+				<placement x="%center_x%" y="%row2_text_y%" placement="5" />
+				<text>%tw_size_progress%</text>
+			</object>
+
 			<object type="template" name="action_page_console" />
 
 			<object type="template" name="progress_bar" />
diff --git a/infomanager.cpp b/infomanager.cpp
new file mode 100644
index 0000000..080fe1d
--- /dev/null
+++ b/infomanager.cpp
@@ -0,0 +1,206 @@
+/*
+	Copyright 2012 bigbiff/Dees_Troy TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <linux/input.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <string>
+#include <utility>
+#include <map>
+#include <fstream>
+#include <sstream>
+
+#include "infomanager.hpp"
+#include "twcommon.h"
+#include "partitions.hpp"
+
+using namespace std;
+
+InfoManager::InfoManager(const string filename) {
+	File = filename;
+}
+
+InfoManager::~InfoManager(void) {
+	mValues.clear();
+}
+
+int InfoManager::LoadValues(void) {
+	string str;
+
+	// Read in the file, if possible
+	FILE* in = fopen(File.c_str(), "rb");
+	if (!in) {
+		LOGINFO("InfoManager file '%s' not found.\n", File.c_str());
+		return -1;
+	} else {
+		LOGINFO("InfoManager loading from '%s'.\n", File.c_str());
+	}
+
+	while (!feof(in)) {
+		string Name;
+		string Value;
+		unsigned short length;
+		char array[512];
+
+		if (fread(&length, 1, sizeof(unsigned short), in) != sizeof(unsigned short))	goto error;
+		if (length >= 512)																goto error;
+		if (fread(array, 1, length, in) != length)										goto error;
+		Name = array;
+
+		if (fread(&length, 1, sizeof(unsigned short), in) != sizeof(unsigned short))	goto error;
+		if (length >= 512)																goto error;
+		if (fread(array, 1, length, in) != length)										goto error;
+		Value = array;
+
+		map<string, string>::iterator pos;
+
+		pos = mValues.find(Name);
+		if (pos != mValues.end()) {
+			pos->second = Value;
+		} else {
+			mValues.insert(make_pair(Name, Value));
+		}
+	}
+error:
+	fclose(in);
+	return 0;
+}
+
+int InfoManager::SaveValues(void) {
+	if (File.empty())
+		return -1;
+
+	PartitionManager.Mount_By_Path(File, true);
+LOGINFO("InfoManager saving '%s'\n", File.c_str());
+	FILE* out = fopen(File.c_str(), "wb");
+	if (!out)
+		return -1;
+
+	map<string, string>::iterator iter;
+	for (iter = mValues.begin(); iter != mValues.end(); ++iter) {
+		unsigned short length = (unsigned short) iter->first.length() + 1;
+		fwrite(&length, 1, sizeof(unsigned short), out);
+		fwrite(iter->first.c_str(), 1, length, out);
+		length = (unsigned short) iter->second.length() + 1;
+		fwrite(&length, 1, sizeof(unsigned short), out);
+		fwrite(iter->second.c_str(), 1, length, out);
+	}
+	fclose(out);
+	return 0;
+}
+
+int InfoManager::GetValue(const string varName, string& value) {
+	string localStr = varName;
+
+	map<string, string>::iterator pos;
+	pos = mValues.find(localStr);
+	if (pos == mValues.end())
+		return -1;
+
+	value = pos->second;
+	return 0;
+}
+
+int InfoManager::GetValue(const string varName, int& value) {
+	string data;
+
+	if (GetValue(varName,data) != 0)
+		return -1;
+
+	value = atoi(data.c_str());
+	return 0;
+}
+
+int InfoManager::GetValue(const string varName, float& value) {
+	string data;
+
+	if (GetValue(varName,data) != 0)
+		return -1;
+
+	value = atof(data.c_str());
+	return 0;
+}
+
+unsigned long long InfoManager::GetValue(const string varName, unsigned long long& value) {
+	string data;
+
+	if (GetValue(varName,data) != 0)
+		return -1;
+
+	value = strtoull(data.c_str(), NULL, 10);
+	return 0;
+}
+
+// This function will return an empty string if the value doesn't exist
+string InfoManager::GetStrValue(const string varName) {
+	string retVal;
+
+	GetValue(varName, retVal);
+	return retVal;
+}
+
+// This function will return 0 if the value doesn't exist
+int InfoManager::GetIntValue(const string varName) {
+	string retVal;
+	GetValue(varName, retVal);
+	return atoi(retVal.c_str());
+}
+
+int InfoManager::SetValue(const string varName, string value) {
+	// Don't allow empty values or numerical starting values
+	if (varName.empty() || (varName[0] >= '0' && varName[0] <= '9'))
+		return -1;
+
+	map<string, string>::iterator pos;
+	pos = mValues.find(varName);
+	if (pos == mValues.end())
+		mValues.insert(make_pair(varName, value));
+	else
+		pos->second = value;
+
+	return 0;
+}
+
+int InfoManager::SetValue(const string varName, int value) {
+	ostringstream valStr;
+	valStr << value;
+	return SetValue(varName, valStr.str());
+}
+
+int InfoManager::SetValue(const string varName, float value) {
+	ostringstream valStr;
+	valStr << value;
+	return SetValue(varName, valStr.str());
+}
+
+int InfoManager::SetValue(const string varName, unsigned long long value) {
+	ostringstream valStr;
+	valStr << value;
+	return SetValue(varName, valStr.str());
+}
diff --git a/infomanager.hpp b/infomanager.hpp
new file mode 100644
index 0000000..de8aef4
--- /dev/null
+++ b/infomanager.hpp
@@ -0,0 +1,58 @@
+/*
+	Copyright 2012 bigbiff/Dees_Troy TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _INFOMANAGER_HPP_HEADER
+#define _INFOMANAGER_HPP_HEADER
+
+#include <string>
+#include <utility>
+#include <map>
+
+using namespace std;
+
+class InfoManager
+{
+public:
+	InfoManager(const string filename);
+	virtual ~InfoManager();
+	int LoadValues();
+	int SaveValues();
+
+	// Core get routines
+	int GetValue(const string varName, string& value);
+	int GetValue(const string varName, int& value);
+	int GetValue(const string varName, float& value);
+	unsigned long long GetValue(const string varName, unsigned long long& value);
+
+	string GetStrValue(const string varName);
+	int GetIntValue(const string varName);
+
+	// Core set routines
+	int SetValue(const string varName, string value);
+	int SetValue(const string varName, int value);
+	int SetValue(const string varName, float value);
+	int SetValue(const string varName, unsigned long long value);
+
+private:
+	string File;
+	map<string, string> mValues;
+
+};
+
+#endif // _DATAMANAGER_HPP_HEADER
+
diff --git a/libtar/extract.c b/libtar/extract.c
index 4526c98..e605aca 100644
--- a/libtar/extract.c
+++ b/libtar/extract.c
@@ -94,7 +94,7 @@
 
 /* switchboard */
 int
-tar_extract_file(TAR *t, char *realname, char *prefix)
+tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd)
 {
 	int i;
 	char *lnp;
@@ -141,7 +141,7 @@
 	}
 	else /* if (TH_ISREG(t)) */ {
 		printf("reg\n");
-		i = tar_extract_regfile(t, realname);
+		i = tar_extract_regfile(t, realname, progress_fd);
 	}
 
 	if (i != 0) {
@@ -189,7 +189,7 @@
 
 /* extract regular file */
 int
-tar_extract_regfile(TAR *t, char *realname)
+tar_extract_regfile(TAR *t, char *realname, const int *progress_fd)
 {
 	//mode_t mode;
 	size_t size;
@@ -285,6 +285,11 @@
 	printf("### done extracting %s\n", filename);
 #endif
 
+	if (*progress_fd != 0) {
+		unsigned long long file_size = (unsigned long long)(size);
+		write(*progress_fd, &file_size, sizeof(file_size));
+	}
+
 	return 0;
 }
 
diff --git a/libtar/libtar.h b/libtar/libtar.h
index 91523d0..e3154ae 100644
--- a/libtar/libtar.h
+++ b/libtar/libtar.h
@@ -226,7 +226,7 @@
 /***** extract.c ***********************************************************/
 
 /* sequentially extract next file from t */
-int tar_extract_file(TAR *t, char *realname, char *prefix);
+int tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd);
 
 /* extract different file types */
 int tar_extract_dir(TAR *t, char *realname);
@@ -237,7 +237,7 @@
 int tar_extract_fifo(TAR *t, char *realname);
 
 /* for regfiles, we need to extract the content blocks as well */
-int tar_extract_regfile(TAR *t, char *realname);
+int tar_extract_regfile(TAR *t, char *realname, const int *progress_fd);
 int tar_skip_regfile(TAR *t);
 
 
@@ -294,7 +294,7 @@
 
 /* extract groups of files */
 int tar_extract_glob(TAR *t, char *globname, char *prefix);
-int tar_extract_all(TAR *t, char *prefix);
+int tar_extract_all(TAR *t, char *prefix, const int *progress_fd);
 
 /* add a whole tree of files */
 int tar_append_tree(TAR *t, char *realdir, char *savedir, char *exclude);
diff --git a/libtar/wrapper.c b/libtar/wrapper.c
index 708c845..82f045f 100644
--- a/libtar/wrapper.c
+++ b/libtar/wrapper.c
@@ -27,7 +27,7 @@
 {
 	char *filename;
 	char buf[MAXPATHLEN];
-	int i;
+	int i, fd = 0;
 
 	while ((i = th_read(t)) == 0)
 	{
@@ -44,7 +44,7 @@
 			snprintf(buf, sizeof(buf), "%s/%s", prefix, filename);
 		else
 			strlcpy(buf, filename, sizeof(buf));
-		if (tar_extract_file(t, filename, prefix) != 0)
+		if (tar_extract_file(t, filename, prefix, &fd) != 0)
 			return -1;
 	}
 
@@ -53,7 +53,7 @@
 
 
 int
-tar_extract_all(TAR *t, char *prefix)
+tar_extract_all(TAR *t, char *prefix, const int *progress_fd)
 {
 	char *filename;
 	char buf[MAXPATHLEN];
@@ -80,7 +80,7 @@
 		       "\"%s\")\n", buf);
 #endif
 		printf("item name: '%s'\n", filename);
-		if (tar_extract_file(t, buf, prefix) != 0)
+		if (tar_extract_file(t, buf, prefix, progress_fd) != 0)
 			return -1;
 	}
 	return (i == 1 ? 0 : -1);
diff --git a/partition.cpp b/partition.cpp
index 3765431..1a62bba 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -41,6 +41,7 @@
 #include "twrpTar.hpp"
 #include "twrpDU.hpp"
 #include "fixPermissions.hpp"
+#include "infomanager.hpp"
 extern "C" {
 	#include "mtdutils/mtdutils.h"
 	#include "mtdutils/mounts.h"
@@ -1284,9 +1285,9 @@
 	return false;
 }
 
-bool TWPartition::Backup(string backup_folder) {
+bool TWPartition::Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size) {
 	if (Backup_Method == FILES)
-		return Backup_Tar(backup_folder);
+		return Backup_Tar(backup_folder, overall_size, other_backups_size);
 	else if (Backup_Method == DD)
 		return Backup_DD(backup_folder);
 	else if (Backup_Method == FLASH_UTILS)
@@ -1343,13 +1344,32 @@
 	return false;
 }
 
-bool TWPartition::Restore(string restore_folder) {
-	size_t first_period, second_period;
+bool TWPartition::Restore(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) {
 	string Restore_File_System;
 
 	TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring");
 	LOGINFO("Restore filename is: %s\n", Backup_FileName.c_str());
 
+	Restore_File_System = Get_Restore_File_System(restore_folder);
+
+	if (Is_File_System(Restore_File_System))
+		return Restore_Tar(restore_folder, Restore_File_System, total_restore_size, already_restored_size);
+	else if (Is_Image(Restore_File_System)) {
+		*already_restored_size += TWFunc::Get_File_Size(Backup_Name);
+		if (Restore_File_System == "emmc")
+			return Restore_DD(restore_folder, total_restore_size, already_restored_size);
+		else if (Restore_File_System == "mtd" || Restore_File_System == "bml")
+			return Restore_Flash_Image(restore_folder, total_restore_size, already_restored_size);
+	}
+
+	LOGERR("Unknown restore method for '%s'\n", Mount_Point.c_str());
+	return false;
+}
+
+string TWPartition::Get_Restore_File_System(string restore_folder) {
+	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(".");
 	if (first_period == string::npos) {
@@ -1364,18 +1384,7 @@
 	}
 	Restore_File_System.resize(second_period);
 	LOGINFO("Restore file system is: '%s'.\n", Restore_File_System.c_str());
-
-	if (Is_File_System(Restore_File_System))
-		return Restore_Tar(restore_folder, Restore_File_System);
-	else if (Is_Image(Restore_File_System)) {
-		if (Restore_File_System == "emmc")
-			return Restore_DD(restore_folder);
-		else if (Restore_File_System == "mtd" || Restore_File_System == "bml")
-			return Restore_Flash_Image(restore_folder);
-	}
-
-	LOGERR("Unknown restore method for '%s'\n", Mount_Point.c_str());
-	return false;
+	return Restore_File_System;
 }
 
 string TWPartition::Backup_Method_By_Name() {
@@ -1709,7 +1718,7 @@
 #endif // ifdef TW_OEM_BUILD
 }
 
-bool TWPartition::Backup_Tar(string backup_folder) {
+bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size) {
 	char back_name[255], split_index[5];
 	string Full_FileName, Split_FileName, Tar_Args, Command;
 	int use_compression, use_encryption = 0, index, backup_count;
@@ -1749,7 +1758,9 @@
 	tar.setdir(Backup_Path);
 	tar.setfn(Full_FileName);
 	tar.setsize(Backup_Size);
-	if (tar.createTarFork() != 0)
+	tar.partition_name = Backup_Name;
+	tar.backup_folder = backup_folder;
+	if (tar.createTarFork(overall_size, other_backups_size) != 0)
 		return false;
 	return true;
 }
@@ -1804,7 +1815,40 @@
 	return true;
 }
 
-bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System) {
+unsigned long long TWPartition::Get_Restore_Size(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;
+		}
+	}
+	string Full_FileName, Restore_File_System = Get_Restore_File_System(restore_folder);
+
+	Full_FileName = restore_folder + "/" + Backup_FileName;
+
+	if (Is_Image(Restore_File_System)) {
+		Restore_Size = TWFunc::Get_File_Size(Full_FileName);
+		return Restore_Size;
+	}
+
+	twrpTar tar;
+	tar.setdir(Backup_Path);
+	tar.setfn(Full_FileName);
+	tar.backup_name = Backup_Name;
+#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
+	string Password;
+	DataManager::GetValue("tw_restore_password", Password);
+	if (!Password.empty())
+		tar.setpassword(Password);
+#endif
+	tar.partition_name = Backup_Name;
+	tar.backup_folder = restore_folder;
+	Restore_Size = tar.get_size();
+	return Restore_Size;
+}
+
+bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) {
 	string Full_FileName, Command;
 	int index = 0;
 	char split_index[5];
@@ -1842,7 +1886,7 @@
 	if (!Password.empty())
 		tar.setpassword(Password);
 #endif
-	if (tar.extractTarFork() != 0)
+	if (tar.extractTarFork(total_restore_size, already_restored_size) != 0)
 		ret = false;
 	else
 		ret = true;
@@ -1868,8 +1912,10 @@
 	return ret;
 }
 
-bool TWPartition::Restore_DD(string restore_folder) {
+bool TWPartition::Restore_DD(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) {
 	string Full_FileName, Command;
+	double display_percent, progress_percent;
+	char size_progress[1024];
 
 	TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring");
 	Full_FileName = restore_folder + "/" + Backup_FileName;
@@ -1890,11 +1936,19 @@
 	Command = "dd bs=4096 if='" + Full_FileName + "' of=" + Actual_Block_Device;
 	LOGINFO("Restore command: '%s'\n", Command.c_str());
 	TWFunc::Exec_Cmd(Command);
+	display_percent = (double)(Restore_Size + *already_restored_size) / (double)(*total_restore_size) * 100;
+	sprintf(size_progress, "%lluMB of %lluMB, %i%%", (Restore_Size + *already_restored_size) / 1048576, *total_restore_size / 1048576, (int)(display_percent));
+	DataManager::SetValue("tw_size_progress", size_progress);
+	progress_percent = (display_percent / 100);
+	DataManager::SetProgress((float)(progress_percent));
+	*already_restored_size += Restore_Size;
 	return true;
 }
 
-bool TWPartition::Restore_Flash_Image(string restore_folder) {
+bool TWPartition::Restore_Flash_Image(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) {
 	string Full_FileName, Command;
+	double display_percent, progress_percent;
+	char size_progress[1024];
 
 	gui_print("Restoring %s...\n", Display_Name.c_str());
 	Full_FileName = restore_folder + "/" + Backup_FileName;
@@ -1905,6 +1959,12 @@
 	Command = "flash_image " + MTD_Name + " '" + Full_FileName + "'";
 	LOGINFO("Restore command: '%s'\n", Command.c_str());
 	TWFunc::Exec_Cmd(Command);
+	display_percent = (double)(Restore_Size + *already_restored_size) / (double)(*total_restore_size) * 100;
+	sprintf(size_progress, "%lluMB of %lluMB, %i%%", (Restore_Size + *already_restored_size) / 1048576, *total_restore_size / 1048576, (int)(display_percent));
+	DataManager::SetValue("tw_size_progress", size_progress);
+	progress_percent = (display_percent / 100);
+	DataManager::SetProgress((float)(progress_percent));
+	*already_restored_size += Restore_Size;
 	return true;
 }
 
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index df623fa..de727f4 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -599,6 +599,7 @@
 	unsigned long total_time, remain_time, section_time;
 	int use_compression, backup_time;
 	float pos;
+	unsigned long long total_size, current_size;
 
 	if (Part == NULL)
 		return true;
@@ -615,7 +616,10 @@
 	total_time = (*img_bytes / (unsigned long)img_bps) + (*file_bytes / (unsigned long)file_bps);
 	remain_time = (*img_bytes_remaining / (unsigned long)img_bps) + (*file_bytes_remaining / (unsigned long)file_bps);
 
-	pos = (total_time - remain_time) / (float) total_time;
+	//pos = (total_time - remain_time) / (float) total_time;
+	total_size = *file_bytes + *img_bytes;
+	current_size = *file_bytes + *img_bytes - *file_bytes_remaining - *img_bytes_remaining;
+	pos = ((float)(current_size) / (float)(total_size));
 	DataManager::SetProgress(pos);
 
 	LOGINFO("Estimated total time: %lu\nEstimated remaining time: %lu\n", total_time, remain_time);
@@ -628,17 +632,20 @@
 
 	// Set the position
 	pos = section_time / (float) total_time;
-	DataManager::ShowProgress(pos, section_time);
+	//DataManager::ShowProgress(pos, section_time);
 
 	time(&start);
 
-	if (Part->Backup(Backup_Folder)) {
+	if (Part->Backup(Backup_Folder, &total_size, &current_size)) {
+		current_size += Part->Backup_Size;
+		pos = (float)((float)(current_size) / (float)(total_size));
+		DataManager::SetProgress(pos);
 		if (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))
+					if (!(*subpart)->Backup(Backup_Folder, &total_size, &current_size))
 						return false;
 					sync();
 					sync();
@@ -649,6 +656,9 @@
 					} else {
 						*img_bytes_remaining -= (*subpart)->Backup_Size;
 					}
+					current_size += Part->Backup_Size;
+					pos = (float)(current_size / total_size);
+					DataManager::SetProgress(pos);
 				}
 			}
 		}
@@ -833,18 +843,18 @@
 	return true;
 }
 
-bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count) {
+bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) {
 	time_t Start, Stop;
 	time(&Start);
-	DataManager::ShowProgress(1.0 / (float)partition_count, 150);
-	if (!Part->Restore(Restore_Name))
+	//DataManager::ShowProgress(1.0 / (float)partition_count, 150);
+	if (!Part->Restore(Restore_Name, total_restore_size, already_restored_size))
 		return false;
 	if (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))
+				if (!(*subpart)->Restore(Restore_Name, total_restore_size, already_restored_size))
 					return false;
 			}
 		}
@@ -861,6 +871,7 @@
 	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;
 
 	gui_print("\n[RESTORE STARTED]\n\n");
 	gui_print("Restore folder: '%s'\n", Restore_Name.c_str());
@@ -876,6 +887,7 @@
 	} else {
 		gui_print("Skipping MD5 check based on user setting.\n");
 	}
+	gui_print("Calculating restore details...\n");
 	DataManager::GetValue("tw_restore_selected", Restore_List);
 	if (!Restore_List.empty()) {
 		end_pos = Restore_List.find(";", start_pos);
@@ -886,6 +898,7 @@
 				partition_count++;
 				if (check_md5 > 0 && !restore_part->Check_MD5(Restore_Name))
 					return false;
+				total_restore_size += restore_part->Get_Restore_Size(Restore_Name);
 				if (restore_part->Has_SubPartition) {
 					std::vector<TWPartition*>::iterator subpart;
 
@@ -893,6 +906,7 @@
 						if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == restore_part->Mount_Point) {
 							if (check_md5 > 0 && !(*subpart)->Check_MD5(Restore_Name))
 								return false;
+							total_restore_size += (*subpart)->Get_Restore_Size(Restore_Name);
 						}
 					}
 				}
@@ -910,7 +924,9 @@
 	}
 
 	gui_print("Restoring %i partitions...\n", partition_count);
+	gui_print("Total restore size is %lluMB\n", total_restore_size / 1048576);
 	DataManager::SetProgress(0.0);
+
 	start_pos = 0;
 	if (!Restore_List.empty()) {
 		end_pos = Restore_List.find(";", start_pos);
@@ -919,7 +935,7 @@
 			restore_part = Find_Partition_By_Path(restore_path);
 			if (restore_part != NULL) {
 				partition_count++;
-				if (!Restore_Partition(restore_part, Restore_Name, partition_count))
+				if (!Restore_Partition(restore_part, Restore_Name, partition_count, &total_restore_size, &already_restored_size))
 					return false;
 			} else {
 				LOGERR("Unable to locate '%s' partition for restoring.\n", restore_path.c_str());
@@ -933,6 +949,7 @@
 	UnMount_Main_Partitions();
 	time(&rStop);
 	gui_print_color("highlight", "[RESTORE COMPLETED IN %d SECONDS]\n\n",(int)difftime(rStop,rStart));
+	DataManager::SetValue("tw_file_progress", "");
 	return true;
 }
 
diff --git a/partitions.hpp b/partitions.hpp
index 73ff1fb..0d74315 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -57,9 +57,10 @@
 	bool Wipe_AndSec();                                                       // Wipes android secure
 	bool Can_Repair();                                                        // Checks to see if we have everything needed to be able to repair the current file system
 	bool Repair();                                                            // Repairs the current file system
-	bool Backup(string backup_folder);                                        // Backs up the partition to the folder specified
+	bool Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size); // Backs up the partition to the folder specified
 	bool Check_MD5(string restore_folder);                                    // Checks MD5 of a backup
-	bool Restore(string restore_folder);                                      // Restores the partition using the backup folder provided
+	bool Restore(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restores the partition using the backup folder provided
+	unsigned long long Get_Restore_Size(string restore_folder);               // 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
@@ -94,12 +95,13 @@
 	bool Wipe_RMRF();                                                         // Uses rm -rf to wipe
 	bool Wipe_F2FS();                                                         // Uses mkfs.f2fs to wipe
 	bool Wipe_Data_Without_Wiping_Media();                                    // Uses rm -rf to wipe but does not wipe /data/media
-	bool Backup_Tar(string backup_folder);                                    // Backs up using tar for file systems
+	bool Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size); // Backs up using tar for file systems
 	bool Backup_DD(string backup_folder);                                     // Backs up using dd for emmc memory types
 	bool Backup_Dump_Image(string backup_folder);                             // Backs up using dump_image for MTD memory types
-	bool Restore_Tar(string restore_folder, string Restore_File_System);      // Restore using tar for file systems
-	bool Restore_DD(string restore_folder);                                   // Restore using dd for emmc memory types
-	bool Restore_Flash_Image(string restore_folder);                          // Restore using flash_image for MTD memory types
+	string Get_Restore_File_System(string restore_folder);                    // Returns the file system that was in place at the time of the backup
+	bool Restore_Tar(string restore_folder, string Restore_File_System, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restore using tar for file systems
+	bool Restore_DD(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restore using dd for emmc memory types
+	bool Restore_Flash_Image(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restore using flash_image for MTD memory types
 	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
@@ -131,6 +133,7 @@
 	unsigned long long Used;                                                  // Overall used space
 	unsigned long long Free;                                                  // Overall free space
 	unsigned long long Backup_Size;                                           // Backup size -- may be different than used space especially when /data/media is present
+	unsigned long long Restore_Size;                                          // Restore size of the current restore operation
 	bool Can_Be_Encrypted;                                                    // This partition might be encrypted, affects error handling, can only be true if crypto support is compiled in
 	bool Is_Encrypted;                                                        // This partition is thought to be encrypted -- it wouldn't mount for some reason, only avialble with crypto support
 	bool Is_Decrypted;                                                        // This partition has successfully been decrypted
@@ -227,7 +230,7 @@
 	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, string Backup_Folder, bool generate_md5, unsigned long long* img_bytes_remaining, unsigned long long* file_bytes_remaining, unsigned long *img_time, unsigned long *file_time, unsigned long long *img_bytes, unsigned long long *file_bytes);
-	bool Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count);
+	bool Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count, const unsigned long long *total_restore_size, unsigned long long *already_restored_size);
 	void Output_Partition(TWPartition* Part);
 	TWPartition* Find_Next_Storage(string Path, string Exclude);
 	int Open_Lun_File(string Partition_Path, string Lun_File);
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 2128c96..db98a36 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -299,6 +299,30 @@
 	return res;
 }
 
+vector<string> TWFunc::split_string(const string &in, char del, bool skip_empty) {
+	vector<string> res;
+
+	if (in.empty() || del == '\0')
+		return res;
+
+	string field;
+	istringstream f(in);
+	if (del == '\n') {
+		while(getline(f, field)) {
+			if (field.empty() && skip_empty)
+				continue;
+		res.push_back(field);
+		}
+	} else {
+		while(getline(f, field, del)) {
+			if (field.empty() && skip_empty)
+				continue;
+			res.push_back(field);
+		}
+	}
+	return res;
+}
+
 #ifndef BUILD_TWRPTAR_MAIN
 
 // Returns "/path" from a full /path/to/file.name
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index ff11763..284a297 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -50,6 +50,7 @@
 	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(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
+	static vector<string> split_string(const string &in, char del, bool skip_empty);
 
 #ifndef BUILD_TWRPTAR_MAIN
 	static void install_htc_dumlock(void);                                      // Installs HTC Dumlock
diff --git a/twrpTar.cpp b/twrpTar.cpp
index 7f00da5..28ac91a 100644
--- a/twrpTar.cpp
+++ b/twrpTar.cpp
@@ -40,6 +40,10 @@
 #include "twcommon.h"
 #include "variables.h"
 #include "twrp-functions.hpp"
+#ifndef BUILD_TWRPTAR_MAIN
+#include "data.hpp"
+#include "infomanager.hpp"
+#endif //ndef BUILD_TWRPTAR_MAIN
 
 using namespace std;
 
@@ -75,20 +79,35 @@
 	password = pass;
 }
 
-int twrpTar::createTarFork() {
+int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size) {
 	int status = 0;
 	pid_t pid, rc_pid;
+	int progress_pipe[2], ret;
+
+	file_count = 0;
+
+	if (pipe(progress_pipe) < 0) {
+		LOGERR("Error creating progress tracking pipe\n");
+		return -1;
+	}
 	if ((pid = fork()) == -1) {
 		LOGINFO("create tar failed to fork.\n");
+		close(progress_pipe[0]);
+		close(progress_pipe[1]);
 		return -1;
 	}
 	if (pid == 0) {
 		// Child process
+
+		// Child closes input side of progress pipe
+		close(progress_pipe[0]);
+		progress_pipe_fd = progress_pipe[1];
+
 		if (use_encryption || userdata_encryption) {
 			LOGINFO("Using encryption\n");
 			DIR* d;
 			struct dirent* de;
-			unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1;
+			unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1, total_size;
 			unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1;
 			int item_len, ret, thread_error = 0;
 			std::vector<TarListStruct> RegularList;
@@ -110,6 +129,7 @@
 			d = opendir(tardir.c_str());
 			if (d == NULL) {
 				LOGERR("error opening '%s'\n", tardir.c_str());
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
 			// Figure out the size of all data to be encrypted and create a list of unencrypted files
@@ -121,11 +141,15 @@
 				if (de->d_type == DT_DIR) {
 					item_len = strlen(de->d_name);
 					if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
-						if (Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id) < 0) {
+						ret = Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id);
+						if (ret < 0) {
 							LOGERR("Error in Generate_TarList with regular list!\n");
 							closedir(d);
+							close(progress_pipe_fd);
+							close(progress_pipe[1]);
 							_exit(-1);
 						}
+						file_count = (unsigned long long)(ret);
 						regular_size += du.Get_Folder_Size(FileName);
 					} else {
 						encrypt_size += du.Get_Folder_Size(FileName);
@@ -152,6 +176,7 @@
 			d = opendir(tardir.c_str());
 			if (d == NULL) {
 				LOGERR("error opening '%s'\n", tardir.c_str());
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
 			// Divide up the encrypted file list for threading
@@ -166,11 +191,14 @@
 						// Do nothing, we added these to RegularList earlier
 					} else {
 						FileName = tardir + "/" + de->d_name;
-						if (Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id) < 0) {
+						ret = Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id);
+						if (ret < 0) {
 							LOGERR("Error in Generate_TarList with encrypted list!\n");
 							closedir(d);
+							close(progress_pipe[1]);
 							_exit(-1);
 						}
+						file_count += (unsigned long long)(ret);
 					}
 				} else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
 					stat(FileName.c_str(), &st);
@@ -179,17 +207,26 @@
 					TarItem.fn = FileName;
 					TarItem.thread_id = enc_thread_id;
 					EncryptList.push_back(TarItem);
+					file_count++;
 				}
 			}
 			closedir(d);
 			if (enc_thread_id != core_count) {
 				LOGERR("Error dividing up threads for encryption, %i threads for %i cores!\n", enc_thread_id, core_count);
-				if (enc_thread_id > core_count)
+				if (enc_thread_id > core_count) {
+					close(progress_pipe[1]);
 					_exit(-1);
-				else
+				} else {
 					LOGERR("Continuining anyway.");
+				}
 			}
 
+			// Send file count to parent
+			write(progress_pipe_fd, &file_count, sizeof(file_count));
+			// Send backup size to parent
+			total_size = regular_size + encrypt_size;
+			write(progress_pipe_fd, &total_size, sizeof(total_size));
+
 			if (userdata_encryption) {
 				// Create a backup of unencrypted data
 				reg.setfn(tarfn);
@@ -198,23 +235,28 @@
 				reg.use_encryption = 0;
 				reg.use_compression = use_compression;
 				reg.split_archives = 1;
+				reg.progress_pipe_fd = progress_pipe_fd;
 				LOGINFO("Creating unencrypted backup...\n");
 				if (createList((void*)&reg) != 0) {
 					LOGERR("Error creating unencrypted backup.\n");
+					close(progress_pipe[1]);
 					_exit(-1);
 				}
 			}
 
 			if (pthread_attr_init(&tattr)) {
 				LOGERR("Unable to pthread_attr_init\n");
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
 			if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
 				LOGERR("Error setting pthread_attr_setdetachstate\n");
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
 			if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
 				LOGERR("Error setting pthread_attr_setscope\n");
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
 			/*if (pthread_attr_setstacksize(&tattr, 524288)) {
@@ -232,12 +274,14 @@
 				enc[i].setpassword(password);
 				enc[i].use_compression = use_compression;
 				enc[i].split_archives = 1;
+				enc[i].progress_pipe_fd = progress_pipe_fd;
 				LOGINFO("Start encryption thread %i\n", i);
 				ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]);
 				if (ret) {
-					LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).", i, ret);
+					LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).\n", i, ret);
 					if (createList((void*)&enc[i]) != 0) {
 						LOGERR("Error creating encrypted backup %i.\n", i);
+						close(progress_pipe[1]);
 						_exit(-1);
 					} else {
 						enc[i].thread_id = i + 1;
@@ -252,6 +296,7 @@
 				if (enc[i].thread_id == i) {
 					if (pthread_join(enc_thread[i], &thread_return)) {
 						LOGERR("Error joining thread %i\n", i);
+						close(progress_pipe[1]);
 						_exit(-1);
 					} else {
 						LOGINFO("Joined thread %i.\n", i);
@@ -259,6 +304,7 @@
 						if (ret != 0) {
 							thread_error = 1;
 							LOGERR("Thread %i returned an error %i.\n", i, ret);
+							close(progress_pipe[1]);
 							_exit(-1);
 						}
 					}
@@ -268,21 +314,28 @@
 			}
 			if (thread_error) {
 				LOGERR("Error returned by one or more threads.\n");
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
 			LOGINFO("Finished encrypted backup.\n");
+			close(progress_pipe[1]);
 			_exit(0);
 		} else {
+			// Not encrypted
 			std::vector<TarListStruct> FileList;
 			unsigned thread_id = 0;
 			unsigned long long target_size = 0;
 			twrpTar reg;
+			int ret;
 
 			// Generate list of files to back up
-			if (Generate_TarList(tardir, &FileList, &target_size, &thread_id) < 0) {
+			ret = Generate_TarList(tardir, &FileList, &target_size, &thread_id);
+			if (ret < 0) {
 				LOGERR("Error in Generate_TarList!\n");
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
+			file_count = (unsigned long long)(ret);
 			// Create a backup
 			reg.setfn(tarfn);
 			reg.ItemList = &FileList;
@@ -290,6 +343,7 @@
 			reg.use_encryption = 0;
 			reg.use_compression = use_compression;
 			reg.setsize(Total_Backup_Size);
+			reg.progress_pipe_fd = progress_pipe_fd;
 			if (Total_Backup_Size > MAX_ARCHIVE_SIZE) {
 				gui_print("Breaking backup file into multiple archives...\n");
 				reg.split_archives = 1;
@@ -297,28 +351,96 @@
 				reg.split_archives = 0;
 			}
 			LOGINFO("Creating backup...\n");
+			write(progress_pipe_fd, &file_count, sizeof(file_count));
+			write(progress_pipe_fd, &Total_Backup_Size, sizeof(Total_Backup_Size));
 			if (createList((void*)&reg) != 0) {
 				LOGERR("Error creating backup.\n");
+				close(progress_pipe[1]);
 				_exit(-1);
 			}
+			close(progress_pipe[1]);
 			_exit(0);
 		}
 	} else {
+		// Parent side
+		unsigned long long fs, size_backup, files_backup, total_backup_size;
+		int first_data = 0;
+		double display_percent, progress_percent;
+		char file_progress[1024];
+		char size_progress[1024];
+		files_backup = 0;
+		size_backup = 0;
+
+		// Parent closes output side
+		close(progress_pipe[1]);
+
+		// Read progress data from children
+		while (read(progress_pipe[0], &fs, sizeof(fs)) > 0) {
+			if (first_data == 0) {
+				// First incoming data is the file count
+				file_count = fs;
+				if (file_count == 0) file_count = 1; // prevent division by 0 below
+				first_data = 1;
+			} else if (first_data == 1) {
+				// Second incoming data is total size
+				total_backup_size = fs;
+				first_data = 2;
+			} else {
+				files_backup++;
+				size_backup += fs;
+				display_percent = (double)(files_backup) / (double)(file_count) * 100;
+				sprintf(file_progress, "%llu of %llu files, %i%%", files_backup, file_count, (int)(display_percent));
+#ifndef BUILD_TWRPTAR_MAIN
+				DataManager::SetValue("tw_file_progress", file_progress);
+				display_percent = (double)(size_backup + *other_backups_size) / (double)(*overall_size) * 100;
+				sprintf(size_progress, "%lluMB of %lluMB, %i%%", (size_backup + *other_backups_size) / 1048576, *overall_size / 1048576, (int)(display_percent));
+				DataManager::SetValue("tw_size_progress", size_progress);
+				progress_percent = (display_percent / 100);
+				DataManager::SetProgress((float)(progress_percent));
+#endif //ndef BUILD_TWRPTAR_MAIN
+			}
+		}
+		close(progress_pipe[0]);
+#ifndef BUILD_TWRPTAR_MAIN
+		DataManager::SetValue("tw_file_progress", "");
+		DataManager::SetValue("tw_size_progress", "");
+
+		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();
+#endif //ndef BUILD_TWRPTAR_MAIN
 		if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0)
 			return -1;
 	}
 	return 0;
 }
 
-int twrpTar::extractTarFork() {
+int twrpTar::extractTarFork(const unsigned long long *overall_size, unsigned long long *other_backups_size) {
 	int status = 0;
 	pid_t pid, rc_pid;
+	int progress_pipe[2], ret;
+
+	if (pipe(progress_pipe) < 0) {
+		LOGERR("Error creating progress tracking pipe\n");
+		return -1;
+	}
 
 	pid = fork();
 	if (pid >= 0) // fork was successful
 	{
 		if (pid == 0) // child process
 		{
+			close(progress_pipe[0]);
+			progress_pipe_fd = progress_pipe[1];
 			if (TWFunc::Path_Exists(tarfn)) {
 				LOGINFO("Single archive\n");
 				if (extract() != 0)
@@ -340,14 +462,17 @@
 				tarfn += "000";
 				if (!TWFunc::Path_Exists(tarfn)) {
 					LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
+					close(progress_pipe_fd);
 					_exit(-1);
 				}
 				if (TWFunc::Get_File_Type(tarfn) != 2) {
 					LOGINFO("First tar file '%s' not encrypted\n", tarfn.c_str());
 					tars[0].basefn = basefn;
 					tars[0].thread_id = 0;
+					tars[0].progress_pipe_fd = progress_pipe_fd;
 					if (extractMulti((void*)&tars[0]) != 0) {
 						LOGERR("Error extracting split archive.\n");
+						close(progress_pipe_fd);
 						_exit(-1);
 					}
 				} else {
@@ -356,18 +481,22 @@
 				// Start threading encrypted restores
 				if (pthread_attr_init(&tattr)) {
 					LOGERR("Unable to pthread_attr_init\n");
+					close(progress_pipe_fd);
 					_exit(-1);
 				}
 				if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
 					LOGERR("Error setting pthread_attr_setdetachstate\n");
+					close(progress_pipe_fd);
 					_exit(-1);
 				}
 				if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
 					LOGERR("Error setting pthread_attr_setscope\n");
+					close(progress_pipe_fd);
 					_exit(-1);
 				}
 				/*if (pthread_attr_setstacksize(&tattr, 524288)) {
 					LOGERR("Error setting pthread_attr_setstacksize\n");
+					close(progress_pipe_fd);
 					_exit(-1);
 				}*/
 				for (i = start_thread_id; i < 9; i++) {
@@ -377,12 +506,14 @@
 						tars[i].basefn = basefn;
 						tars[i].setpassword(password);
 						tars[i].thread_id = i;
+						tars[i].progress_pipe_fd = progress_pipe_fd;
 						LOGINFO("Creating extract thread ID %i\n", i);
 						ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]);
 						if (ret) {
-							LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).", i, ret);
+							LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).\n", i, ret);
 							if (extractMulti((void*)&tars[i]) != 0) {
 								LOGERR("Error extracting backup in thread %i.\n", i);
+								close(progress_pipe_fd);
 								_exit(-1);
 							} else {
 								tars[i].thread_id = i + 1;
@@ -397,6 +528,7 @@
 					if (tars[i].thread_id == i) {
 						if (pthread_join(tar_thread[i], &thread_return)) {
 							LOGERR("Error joining thread %i\n", i);
+							close(progress_pipe_fd);
 							_exit(-1);
 						} else {
 							LOGINFO("Joined thread %i.\n", i);
@@ -404,6 +536,7 @@
 							if (ret != 0) {
 								thread_error = 1;
 								LOGERR("Thread %i returned an error %i.\n", i, ret);
+								close(progress_pipe_fd);
 								_exit(-1);
 							}
 						}
@@ -413,20 +546,49 @@
 				}
 				if (thread_error) {
 					LOGERR("Error returned by one or more threads.\n");
+					close(progress_pipe_fd);
 					_exit(-1);
 				}
-				LOGINFO("Finished encrypted backup.\n");
+				LOGINFO("Finished encrypted restore.\n");
+				close(progress_pipe_fd);
 				_exit(0);
 			}
 		}
 		else // parent process
 		{
+			unsigned long long fs, size_backup;
+			double display_percent, progress_percent;
+			char size_progress[1024];
+			size_backup = 0;
+
+			// Parent closes output side
+			close(progress_pipe[1]);
+
+			// Read progress data from children
+			while (read(progress_pipe[0], &fs, sizeof(fs)) > 0) {
+				size_backup += fs;
+				display_percent = (double)(size_backup + *other_backups_size) / (double)(*overall_size) * 100;
+				sprintf(size_progress, "%lluMB of %lluMB, %i%%", (size_backup + *other_backups_size) / 1048576, *overall_size / 1048576, (int)(display_percent));
+				progress_percent = (display_percent / 100);
+#ifndef BUILD_TWRPTAR_MAIN
+				DataManager::SetValue("tw_size_progress", size_progress);
+				DataManager::SetProgress((float)(progress_percent));
+#endif //ndef BUILD_TWRPTAR_MAIN
+			}
+			close(progress_pipe[0]);
+#ifndef BUILD_TWRPTAR_MAIN
+			DataManager::SetValue("tw_file_progress", "");
+#endif //ndef BUILD_TWRPTAR_MAIN
+			*other_backups_size += size_backup;
+
 			if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0)
 				return -1;
 		}
 	}
 	else // fork has failed
 	{
+		close(progress_pipe[0]);
+		close(progress_pipe[1]);
 		LOGINFO("extract tar failed to fork.\n");
 		return -1;
 	}
@@ -440,6 +602,8 @@
 	string FileName;
 	struct TarListStruct TarItem;
 	string::size_type i;
+	int ret, file_count;
+	file_count = 0;
 
 	d = opendir(Path.c_str());
 	if (d == NULL) {
@@ -456,13 +620,17 @@
 		TarItem.thread_id = *thread_id;
 		if (de->d_type == DT_DIR) {
 			TarList->push_back(TarItem);
-			if (Generate_TarList(FileName, TarList, Target_Size, thread_id) < 0)
+			ret = Generate_TarList(FileName, TarList, Target_Size, thread_id);
+			if (ret < 0)
 				return -1;
+			file_count += ret;
 		} else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
 			stat(FileName.c_str(), &st);
 			TarList->push_back(TarItem);
-			if (de->d_type == DT_REG)
+			if (de->d_type == DT_REG) {
+				file_count++;
 				Archive_Current_Size += st.st_size;
+			}
 			if (Archive_Current_Size != 0 && *Target_Size != 0 && Archive_Current_Size > *Target_Size) {
 				*thread_id = *thread_id + 1;
 				Archive_Current_Size = 0;
@@ -470,14 +638,14 @@
 		}
 	}
 	closedir(d);
-	return 0;
+	return file_count;
 }
 
 int twrpTar::extractTar() {
 	char* charRootDir = (char*) tardir.c_str();
 	if (openTar() == -1)
 		return -1;
-	if (tar_extract_all(t, charRootDir) != 0) {
+	if (tar_extract_all(t, charRootDir, &progress_pipe_fd) != 0) {
 		LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
 		return -1;
 	}
@@ -525,6 +693,7 @@
 	string temp;
 	char actual_filename[PATH_MAX];
 	char *ptr;
+	unsigned long long fs;
 
 	if (split_archives) {
 		basefn = tarfn;
@@ -547,7 +716,8 @@
 			strcpy(buf, TarList->at(i).fn.c_str());
 			lstat(buf, &st);
 			if (S_ISREG(st.st_mode)) { // item is a regular file
-				if (split_archives && Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
+				fs = (unsigned long long)(st.st_size);
+				if (split_archives && Archive_Current_Size + fs > MAX_ARCHIVE_SIZE) {
 					if (closeTar() != 0) {
 						LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
 						return -3;
@@ -566,7 +736,8 @@
 					}
 					Archive_Current_Size = 0;
 				}
-				Archive_Current_Size += (unsigned long long)(st.st_size);
+				Archive_Current_Size += fs;
+				write(progress_pipe_fd, &fs, sizeof(fs));
 			}
 			LOGINFO("addFile '%s' including root: %i\n", buf, include_root_dir);
 			if (addFile(buf, include_root_dir) != 0) {
@@ -1106,6 +1277,116 @@
 	return ret;
 }
 
+unsigned long long twrpTar::get_size() {
+	if (TWFunc::Path_Exists(tarfn)) {
+		LOGINFO("Single archive\n");
+		int type = 0;
+		return uncompressedSize(tarfn, &type);
+	} else {
+		LOGINFO("Multiple archives\n");
+		string temp;
+		char actual_filename[255];
+		int archive_count = 0, i, type = 0, temp_type = 0;
+		unsigned long long total_restore_size = 0;
+
+		basefn = tarfn;
+		temp = basefn + "%i%02i";
+		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);
+			}
+		}
+#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 total_size = 0;
+	string Tar, Command, result;
+	vector<string> split;
+
+	Tar = TWFunc::Get_Filename(filename);
+	type = TWFunc::Get_File_Type(filename);
+	if (type == 0) {
+		total_size = TWFunc::Get_File_Size(filename);
+		*archive_type = 0;
+	} else if (type == 1) {
+		// Compressed
+		Command = "pigz -l '" + filename + "'";
+		/* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
+		we get the uncompressed size at once. */
+		TWFunc::Exec_Cmd(Command, result);
+		if (!result.empty()) {
+			/* Expected output:
+			compressed original  reduced name
+			95855838   179403776 -1.3%   data.yaffs2.win
+			^
+			split[5]
+			*/
+			split = TWFunc::split_string(result, ' ', true);
+			if (split.size() > 4)
+			total_size = atoi(split[5].c_str());
+		}
+		*archive_type = 1;
+	} else if (type == 2) {
+		// File is encrypted and may be compressed
+		int ret = TWFunc::Try_Decrypting_File(filename, password);
+		*archive_type = 2;
+		if (ret < 1) {
+			LOGERR("Failed to decrypt tar file '%s'\n", filename.c_str());
+			total_size = TWFunc::Get_File_Size(filename);
+		} else if (ret == 1) {
+			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. */
+			TWFunc::Exec_Cmd(Command, result);
+			if (!result.empty()) {
+				LOGINFO("result was: '%s'\n", result.c_str());
+				/* Expected output:
+				compressed original  reduced name
+				95855838   179403776 -1.3%   data.yaffs2.win
+				^
+				split[5]
+				*/
+				split = TWFunc::split_string(result, ' ', true);
+				if (split.size() > 4)
+				total_size = atoi(split[5].c_str());
+			}
+		} else {
+			total_size = TWFunc::Get_File_Size(filename);
+		}
+	}
+
+	return total_size;
+}
+
 extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
 	return (ssize_t) write_libtar_buffer(fd, buffer, size);
 }
diff --git a/twrpTar.hpp b/twrpTar.hpp
index 443e5f4..7994752 100644
--- a/twrpTar.hpp
+++ b/twrpTar.hpp
@@ -45,12 +45,13 @@
 public:
 	twrpTar();
 	virtual ~twrpTar();
-	int createTarFork();
-	int extractTarFork();
+	int createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size);
+	int extractTarFork(const unsigned long long *overall_size, unsigned long long *other_backups_size);
 	void setfn(string fn);
 	void setdir(string dir);
 	void setsize(unsigned long long backup_size);
 	void setpassword(string pass);
+	unsigned long long get_size();
 
 public:
 	int use_encryption;
@@ -59,6 +60,9 @@
 	int split_archives;
 	int has_data_media;
 	string backup_name;
+	int progress_pipe_fd;
+	string partition_name;
+	string backup_folder;
 
 private:
 	int extract();
@@ -75,6 +79,7 @@
 	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);
 
 	int Archive_Current_Type;
 	unsigned long long Archive_Current_Size;
@@ -84,6 +89,7 @@
 	int fd;
 	pid_t pigz_pid;
 	pid_t oaes_pid;
+	unsigned long long file_count;
 
 	string tardir;
 	string tarfn;
diff --git a/twrpTarMain/twrpTarMain.cpp b/twrpTarMain/twrpTarMain.cpp
index b28a42e..c1705c7 100644
--- a/twrpTarMain/twrpTarMain.cpp
+++ b/twrpTarMain/twrpTarMain.cpp
@@ -47,6 +47,7 @@
 	int i, action = 0;
 	unsigned j;
 	string Directory, Tar_Filename;
+	unsigned long long temp1 = 0, temp2 = 0;
 #ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
 	string Password;
 #endif
@@ -142,14 +143,14 @@
 	}
 #endif
 	if (action == 1) {
-		if (tar.createTarFork() != 0) {
+		if (tar.createTarFork(&temp1, &temp2) != 0) {
 			sync();
 			return -1;
 		}
 		sync();
 		printf("\n\ntar created successfully.\n");
 	} else if (action == 2) {
-		if (tar.extractTarFork() != 0) {
+		if (tar.extractTarFork(&temp1, &temp2) != 0) {
 			sync();
 			return -1;
 		}