Support backup/restore of FBE policies

Change-Id: Iba8ef20f57b0fb57bb9406c53148a806441d0b59
diff --git a/crypto/ext4crypt/Android.mk b/crypto/ext4crypt/Android.mk
index 531aca1..bcbcccf 100644
--- a/crypto/ext4crypt/Android.mk
+++ b/crypto/ext4crypt/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_MODULE := libe4crypt
 LOCAL_MODULE_TAGS := eng optional
 LOCAL_CFLAGS :=
-LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp Keymaster.cpp KeyStorage.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp
+LOCAL_SRC_FILES := Decrypt.cpp Ext4Crypt.cpp Keymaster.cpp KeyStorage.cpp ScryptParameters.cpp Utils.cpp HashPassword.cpp ext4_crypt.cpp
 LOCAL_SHARED_LIBRARIES := libselinux libc libc++ libext4_utils libsoftkeymaster libbase libcrypto libcutils libkeymaster_messages libhardware libprotobuf-cpp-lite
 LOCAL_STATIC_LIBRARIES := libscrypt_static
 LOCAL_C_INCLUDES := system/extras/ext4_utils external/scrypt/lib/crypto system/security/keystore hardware/libhardware/include/hardware system/security/softkeymaster/include/keymaster system/keymaster/include
@@ -30,4 +30,15 @@
 
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := e4policyget
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := e4policyget.cpp
+LOCAL_SHARED_LIBRARIES := libe4crypt
+LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
+
+include $(BUILD_EXECUTABLE)
+
 endif
diff --git a/crypto/ext4crypt/Decrypt.cpp b/crypto/ext4crypt/Decrypt.cpp
index 6c47add..3b69d46 100644
--- a/crypto/ext4crypt/Decrypt.cpp
+++ b/crypto/ext4crypt/Decrypt.cpp
@@ -17,10 +17,12 @@
 #include "Decrypt.h"
 #include "Ext4Crypt.h"
 
+#include <map>
 #include <string>
 
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -32,6 +34,66 @@
 
 #include <android-base/file.h>
 
+// Store main DE raw ref / policy
+extern std::string de_raw_ref;
+extern std::map<userid_t, std::string> s_de_key_raw_refs;
+extern std::map<userid_t, std::string> s_ce_key_raw_refs;
+
+static bool lookup_ref_key_internal(std::map<userid_t, std::string>& key_map, const char* policy, userid_t* user_id) {
+    for (std::map<userid_t, std::string>::iterator it=key_map.begin(); it!=key_map.end(); ++it) {
+        if (strncmp(it->second.c_str(), policy, it->second.size()) == 0) {
+            *user_id = it->first;
+            return true;
+        }
+    }
+    return false;
+}
+
+extern "C" bool lookup_ref_key(const char* policy, char* policy_type) {
+    userid_t user_id = 0;
+    if (strncmp(de_raw_ref.c_str(), policy, de_raw_ref.size()) == 0) {
+        strcpy(policy_type, "1DK");
+        return true;
+    }
+    if (!lookup_ref_key_internal(s_de_key_raw_refs, policy, &user_id)) {
+        if (!lookup_ref_key_internal(s_ce_key_raw_refs, policy, &user_id)) {
+            return false;
+		} else
+		    sprintf(policy_type, "1CE%d", user_id);
+    } else
+        sprintf(policy_type, "1DE%d", user_id);
+    return true;
+}
+
+extern "C" bool lookup_ref_tar(const char* policy_type, char* policy) {
+    if (strncmp(policy_type, "1", 1) != 0) {
+        printf("Unexpected version %c\n", policy_type);
+        return false;
+    }
+    const char* ptr = policy_type + 1; // skip past the version number
+    if (strncmp(ptr, "DK", 2) == 0) {
+        strncpy(policy, de_raw_ref.data(), de_raw_ref.size());
+        return true;
+    }
+    userid_t user_id = atoi(ptr + 2);
+    std::string raw_ref;
+    if (*ptr == 'D') {
+        if (lookup_key_ref(s_de_key_raw_refs, user_id, &raw_ref)) {
+            strncpy(policy, raw_ref.data(), raw_ref.size());
+        } else
+            return false;
+    } else if (*ptr == 'C') {
+        if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
+            strncpy(policy, raw_ref.data(), raw_ref.size());
+        } else
+            return false;
+    } else {
+        printf("unknown policy type '%s'\n", policy_type);
+        return false;
+    }
+    return true;
+}
+
 int gatekeeper_device_initialize(gatekeeper_device_t **dev) {
 	int ret;
 	const hw_module_t *mod;
diff --git a/crypto/ext4crypt/Ext4Crypt.cpp b/crypto/ext4crypt/Ext4Crypt.cpp
index 423147d..8bc4199 100644
--- a/crypto/ext4crypt/Ext4Crypt.cpp
+++ b/crypto/ext4crypt/Ext4Crypt.cpp
@@ -67,6 +67,12 @@
 //static constexpr int FLAG_STORAGE_DE = 1 << 0; // moved to Decrypt.h
 //static constexpr int FLAG_STORAGE_CE = 1 << 1;
 
+// Store main DE raw ref / policy
+std::string de_raw_ref;
+// Map user ids to key references
+std::map<userid_t, std::string> s_de_key_raw_refs;
+std::map<userid_t, std::string> s_ce_key_raw_refs;
+
 namespace {
 const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder;
 const std::string device_key_path = device_key_dir + "/key";
@@ -80,9 +86,6 @@
 // Some users are ephemeral, don't try to wipe their keys from disk
 std::set<userid_t> s_ephemeral_users;
 
-// Map user ids to key references
-std::map<userid_t, std::string> s_de_key_raw_refs;
-std::map<userid_t, std::string> s_ce_key_raw_refs;
 // TODO abolish this map. Keys should not be long-lived in user memory, only kernel memory.
 // See b/26948053
 std::map<userid_t, std::string> s_ce_keys;
@@ -290,7 +293,7 @@
     return access(path.c_str(), F_OK) == 0;
 }
 
-static bool lookup_key_ref(const std::map<userid_t, std::string>& key_map, userid_t user_id,
+bool lookup_key_ref(const std::map<userid_t, std::string>& key_map, userid_t user_id,
                            std::string* raw_ref) {
     auto refi = key_map.find(user_id);
     if (refi == key_map.end()) {
@@ -379,6 +382,7 @@
     }
 
     s_global_de_initialized = true;
+    de_raw_ref = device_key_ref;
     return true;
 }
 
diff --git a/crypto/ext4crypt/Ext4Crypt.h b/crypto/ext4crypt/Ext4Crypt.h
index b05ff4d..57623e3 100644
--- a/crypto/ext4crypt/Ext4Crypt.h
+++ b/crypto/ext4crypt/Ext4Crypt.h
@@ -19,6 +19,7 @@
 
 #include <cutils/multiuser.h>
 
+#include <map>
 #include <string>
 
 __BEGIN_DECLS
@@ -40,4 +41,7 @@
 bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial, int flags);
 //bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags);
 
+bool lookup_key_ref(const std::map<userid_t, std::string>& key_map, userid_t user_id,
+                           std::string* raw_ref);
+
 __END_DECLS
diff --git a/crypto/ext4crypt/e4policyget.cpp b/crypto/ext4crypt/e4policyget.cpp
new file mode 100644
index 0000000..d217f18
--- /dev/null
+++ b/crypto/ext4crypt/e4policyget.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 Team Win Recovery Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ext4crypt_tar.h"
+
+#define EXT4_KEY_DESCRIPTOR_SIZE 8
+#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17
+
+int main(int argc, char *argv[]) {
+	bool ret = false;
+	if (argc != 2) {
+		printf("Must specify a path\n");
+		return -1;
+	} else  {
+		char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
+		if (e4crypt_policy_get(argv[1], e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		{
+			char* ptr = tar_policy;
+			memset(tar_policy, 0, sizeof(tar_policy));
+			char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+			policy_to_hex(e4crypt_policy, policy_hex);
+			printf("%s\n", policy_hex);
+		} else {
+			printf("No policy set\n");
+		}
+	}
+	return 0;
+}
diff --git a/crypto/ext4crypt/ext4_crypt.cpp b/crypto/ext4crypt/ext4_crypt.cpp
new file mode 100644
index 0000000..029db75
--- /dev/null
+++ b/crypto/ext4crypt/ext4_crypt.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* TWRP NOTE: Kanged from system/extras/ext4_utils/ext4_crypt.cpp
+ * because policy_to_hex, e4crypt_policy_set, and e4crypt_policy_get
+ * are not exposed to be used. There was also a bug in e4crypt_policy_get
+ * that may or may not be fixed in the user's local repo:
+ * https://android.googlesource.com/platform/system/extras/+/30b93dd5715abcabd621235733733c0503f9c552
+ */
+
+#include "ext4_crypt.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <asm/ioctl.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#define XATTR_NAME_ENCRYPTION_POLICY "encryption.policy"
+#define EXT4_KEYREF_DELIMITER ((char)'.')
+
+// ext4enc:TODO Include structure from somewhere sensible
+// MUST be in sync with ext4_crypto.c in kernel
+#define EXT4_KEY_DESCRIPTOR_SIZE 8
+#define EXT4_KEY_DESCRIPTOR_SIZE_HEX 17
+
+struct ext4_encryption_policy {
+    char version;
+    char contents_encryption_mode;
+    char filenames_encryption_mode;
+    char flags;
+    char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
+} __attribute__((__packed__));
+
+#define EXT4_ENCRYPTION_MODE_AES_256_XTS    1
+#define EXT4_ENCRYPTION_MODE_AES_256_CTS    4
+#define EXT4_ENCRYPTION_MODE_PRIVATE        127
+
+static int encryption_mode = EXT4_ENCRYPTION_MODE_PRIVATE;
+
+// ext4enc:TODO Get value from somewhere sensible
+#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
+#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
+
+#define HEX_LOOKUP "0123456789abcdef"
+
+extern "C" void policy_to_hex(const char* policy, char* hex) {
+    for (size_t i = 0, j = 0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++) {
+        hex[j++] = HEX_LOOKUP[(policy[i] & 0xF0) >> 4];
+        hex[j++] = HEX_LOOKUP[policy[i] & 0x0F];
+    }
+    hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX - 1] = '\0';
+}
+
+extern "C" bool e4crypt_policy_set(const char *directory, const char *policy,
+                               size_t policy_length, int contents_encryption_mode) {
+    if (contents_encryption_mode == 0)
+        contents_encryption_mode = encryption_mode;
+    if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
+		printf("policy wrong length\n");
+        LOG(ERROR) << "Policy wrong length: " << policy_length;
+        return false;
+    }
+    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+    if (fd == -1) {
+		printf("failed to open %s\n", directory);
+        PLOG(ERROR) << "Failed to open directory " << directory;
+        return false;
+    }
+
+    ext4_encryption_policy eep;
+    eep.version = 0;
+    eep.contents_encryption_mode = contents_encryption_mode;
+    eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
+    eep.flags = 0;
+    memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
+    if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
+		printf("failed to set policy for '%s' '%s'\n", directory, policy);
+        PLOG(ERROR) << "Failed to set encryption policy for " << directory;
+        close(fd);
+        return false;
+    }
+    close(fd);
+
+    char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+    policy_to_hex(policy, policy_hex);
+    LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
+    return true;
+}
+
+extern "C" bool e4crypt_policy_get(const char *directory, char *policy,
+                               size_t policy_length, int contents_encryption_mode) {
+    if (contents_encryption_mode == 0)
+        contents_encryption_mode = encryption_mode;
+    if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
+        LOG(ERROR) << "Policy wrong length: " << policy_length;
+        return false;
+    }
+
+    int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+    if (fd == -1) {
+        PLOG(ERROR) << "Failed to open directory " << directory;
+        return false;
+    }
+
+    ext4_encryption_policy eep;
+    memset(&eep, 0, sizeof(ext4_encryption_policy));
+    if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep) != 0) {
+        PLOG(ERROR) << "Failed to get encryption policy for " << directory;
+        close(fd);
+        return false;
+    }
+    close(fd);
+
+    if ((eep.version != 0)
+            || (eep.contents_encryption_mode != contents_encryption_mode)
+            || (eep.filenames_encryption_mode != EXT4_ENCRYPTION_MODE_AES_256_CTS)
+            || (eep.flags != 0)) {
+        LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
+        return false;
+    }
+    memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE);
+
+    return true;
+}
+
+extern "C" bool e4crypt_set_mode() {
+    const char* mode_file = "/data/unencrypted/mode";
+    struct stat st;
+    if (stat(mode_file, &st) != 0 || st.st_size <= 0) {
+        printf("Invalid encryption mode file %s\n", mode_file);
+        return false;
+    }
+    size_t mode_size = st.st_size;
+    char contents_encryption_mode[mode_size + 1];
+    memset((void*)contents_encryption_mode, 0, mode_size + 1);
+    int fd = open(mode_file, O_RDONLY);
+    if (fd < 0) {
+        printf("error opening '%s': %s\n", mode_file, strerror(errno));
+        return false;
+    }
+    if (read(fd, contents_encryption_mode, mode_size) != mode_size) {
+        printf("read error on '%s': %s\n", mode_file, strerror(errno));
+        close(fd);
+        return false;
+    }
+    close(fd);
+    if (!strcmp(contents_encryption_mode, "software")) {
+        encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+    } else if (!strcmp(contents_encryption_mode, "ice")) {
+        encryption_mode = EXT4_ENCRYPTION_MODE_PRIVATE;
+    } else {
+        printf("Invalid encryption mode '%s'\n", contents_encryption_mode);
+        return false;
+    }
+    printf("set encryption mode to %i\n", encryption_mode);
+    return true;
+}
diff --git a/crypto/ext4crypt/ext4crypt_tar.h b/crypto/ext4crypt/ext4crypt_tar.h
new file mode 100644
index 0000000..1c9cef0
--- /dev/null
+++ b/crypto/ext4crypt/ext4crypt_tar.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 Team Win Recovery Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXT4CRYPT_TAR_H
+#define __EXT4CRYPT_TAR_H
+
+#include <sys/cdefs.h>
+#include <stdbool.h>
+#include <cutils/multiuser.h>
+
+__BEGIN_DECLS
+
+bool lookup_ref_key(const char* policy, char* policy_type);
+bool lookup_ref_tar(const char* policy_type, char* policy);
+
+void policy_to_hex(const char* policy, char* hex);
+bool e4crypt_policy_set(const char *directory, const char *policy,
+                               size_t policy_length, int contents_encryption_mode);
+bool e4crypt_policy_get(const char *directory, char *policy,
+                               size_t policy_length, int contents_encryption_mode);
+
+bool e4crypt_set_mode();
+__END_DECLS
+
+#endif
diff --git a/libtar/Android.mk b/libtar/Android.mk
index 838b441..14c19f7 100644
--- a/libtar/Android.mk
+++ b/libtar/Android.mk
@@ -5,16 +5,21 @@
 
 LOCAL_MODULE := libtar
 LOCAL_MODULE_TAGS := eng optional
-LOCAL_CFLAGS :=
-LOCAL_SRC_FILES = append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c
+LOCAL_SRC_FILES := append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c
 LOCAL_C_INCLUDES += $(LOCAL_PATH) \
-					external/zlib
+                    external/zlib
 LOCAL_SHARED_LIBRARIES += libz libc
 
 ifeq ($(TWHAVE_SELINUX), true)
-	LOCAL_C_INCLUDES += external/libselinux/include
-	LOCAL_SHARED_LIBRARIES += libselinux
-	LOCAL_CFLAGS += -DHAVE_SELINUX
+    LOCAL_C_INCLUDES += external/libselinux/include
+    LOCAL_SHARED_LIBRARIES += libselinux
+    LOCAL_CFLAGS += -DHAVE_SELINUX
+endif
+
+ifeq ($(TW_INCLUDE_CRYPTO_FBE), true)
+    LOCAL_SHARED_LIBRARIES += libe4crypt
+    LOCAL_CFLAGS += -DHAVE_EXT4_CRYPT
+    LOCAL_C_INCLUDES += bootable/recovery/crypto/ext4crypt
 endif
 
 include $(BUILD_SHARED_LIBRARY)
@@ -24,16 +29,21 @@
 
 LOCAL_MODULE := libtar_static
 LOCAL_MODULE_TAGS := eng optional
-LOCAL_CFLAGS = 
-LOCAL_SRC_FILES = append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c
+LOCAL_SRC_FILES := append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c
 LOCAL_C_INCLUDES += $(LOCAL_PATH) \
-					external/zlib
+                    external/zlib
 LOCAL_STATIC_LIBRARIES += libz libc
 
 ifeq ($(TWHAVE_SELINUX), true)
-	LOCAL_C_INCLUDES += external/libselinux/include
-	LOCAL_STATIC_LIBRARIES += libselinux
-	LOCAL_CFLAGS += -DHAVE_SELINUX
+    LOCAL_C_INCLUDES += external/libselinux/include
+    LOCAL_STATIC_LIBRARIES += libselinux
+    LOCAL_CFLAGS += -DHAVE_SELINUX
+endif
+
+ifeq ($(TW_INCLUDE_CRYPTO_FBE), true)
+    LOCAL_SHARED_LIBRARIES += libe4crypt
+    LOCAL_CFLAGS += -DHAVE_EXT4_CRYPT
+    LOCAL_C_INCLUDES += bootable/recovery/crypto/ext4crypt
 endif
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libtar/append.c b/libtar/append.c
index 4be679c..4388297 100644
--- a/libtar/append.c
+++ b/libtar/append.c
@@ -20,6 +20,7 @@
 #include <time.h>
 #include <sys/param.h>
 #include <sys/types.h>
+#include <stdbool.h>
 
 #ifdef STDC_HEADERS
 # include <stdlib.h>
@@ -34,6 +35,10 @@
 # include "selinux/selinux.h"
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+# include "ext4crypt_tar.h"
+#endif
+
 struct tar_dev
 {
 	dev_t td_dev;
@@ -122,6 +127,33 @@
 	}
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+	if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
+	{
+		if (t->th_buf.e4crypt_policy != NULL)
+		{
+			free(t->th_buf.e4crypt_policy);
+			t->th_buf.e4crypt_policy = NULL;
+		}
+
+		char e4crypt_policy[EXT4_KEY_DESCRIPTOR_SIZE];
+		if (e4crypt_policy_get(realname, e4crypt_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		{
+			char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
+			memset(tar_policy, 0, sizeof(tar_policy));
+			char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
+			policy_to_hex(e4crypt_policy, policy_hex);
+			if (lookup_ref_key(e4crypt_policy, &tar_policy)) {
+				printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
+				t->th_buf.e4crypt_policy = strdup(tar_policy);
+			} else {
+				printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
+				return -1;
+			}
+		} // else no policy found, but this is not an error as not all dirs will have a policy
+	}
+#endif
+
 	/* check if it's a hardlink */
 #ifdef DEBUG
 	puts("tar_append_file(): checking inode cache for hardlink...");
diff --git a/libtar/block.c b/libtar/block.c
index 5d3c9d8..2fd61bb 100644
--- a/libtar/block.c
+++ b/libtar/block.c
@@ -25,6 +25,10 @@
 #define SELINUX_TAG "RHT.security.selinux="
 #define SELINUX_TAG_LEN 21
 
+// Used to identify e4crypt_policy in extended ('x')
+#define E4CRYPT_TAG "TWRP.security.e4crypt="
+#define E4CRYPT_TAG_LEN 22
+
 /* read a header block */
 /* FIXME: the return value of this function should match the return value
 	  of tar_block_read(), which is a macro which references a prototype
@@ -119,6 +123,11 @@
 	if (t->th_buf.selinux_context != NULL)
 		free(t->th_buf.selinux_context);
 #endif
+#ifdef HAVE_EXT4_CRYPT
+	if (t->th_buf.e4crypt_policy != NULL) {
+		free(t->th_buf.e4crypt_policy);
+	}
+#endif
 
 	memset(&(t->th_buf), 0, sizeof(struct tar_header));
 
@@ -283,6 +292,57 @@
 	}
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+	if(TH_ISPOLHEADER(t))
+	{
+		sz = th_get_size(t);
+
+		if(sz >= T_BLOCKSIZE) // Not supported
+		{
+#ifdef DEBUG
+			printf("    th_read(): Policy header is too long!\n");
+#endif
+		}
+		else
+		{
+			char buf[T_BLOCKSIZE];
+			i = tar_block_read(t, buf);
+			if (i != T_BLOCKSIZE)
+			{
+				if (i != -1)
+					errno = EINVAL;
+				return -1;
+			}
+
+			// To be sure
+			buf[T_BLOCKSIZE-1] = 0;
+
+			int len = strlen(buf);
+			char *start = strstr(buf, E4CRYPT_TAG);
+			if(start && start+E4CRYPT_TAG_LEN < buf+len)
+			{
+				start += E4CRYPT_TAG_LEN;
+				char *end = strchr(start, '\n');
+				if(end)
+				{
+				    t->th_buf.e4crypt_policy = strndup(start, end-start);
+#ifdef DEBUG
+				    printf("    th_read(): E4Crypt policy detected: %s\n", t->th_buf.e4crypt_policy);
+#endif
+				}
+			}
+		}
+
+		i = th_read_internal(t);
+		if (i != T_BLOCKSIZE)
+		{
+			if (i != -1)
+				errno = EINVAL;
+			return -1;
+		}
+	}
+#endif
+
 	return 0;
 }
 
@@ -457,6 +517,59 @@
 	}
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+	if((t->options & TAR_STORE_EXT4_POL) && t->th_buf.e4crypt_policy != NULL)
+	{
+#ifdef DEBUG
+		printf("th_write(): using e4crypt_policy %s\n",
+		       t->th_buf.e4crypt_policy);
+#endif
+		/* save old size and type */
+		type2 = t->th_buf.typeflag;
+		sz2 = th_get_size(t);
+
+		/* write out initial header block with fake size and type */
+		t->th_buf.typeflag = TH_POL_TYPE;
+
+		/* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */
+		//                                                       size   newline
+		sz = E4CRYPT_TAG_LEN + EXT4_KEY_DESCRIPTOR_HEX + 3  +    1;
+
+		if(sz >= 100) // another ascci digit for size
+			++sz;
+
+		if(sz >= T_BLOCKSIZE) // impossible
+		{
+			errno = EINVAL;
+			return -1;
+		}
+
+		th_set_size(t, sz);
+		th_finish(t);
+		i = tar_block_write(t, &(t->th_buf));
+		if (i != T_BLOCKSIZE)
+		{
+			if (i != -1)
+				errno = EINVAL;
+			return -1;
+		}
+
+		memset(buf, 0, T_BLOCKSIZE);
+		snprintf(buf, T_BLOCKSIZE, "%d "E4CRYPT_TAG"%s\n", (int)sz, t->th_buf.e4crypt_policy);
+		i = tar_block_write(t, &buf);
+		if (i != T_BLOCKSIZE)
+		{
+			if (i != -1)
+				errno = EINVAL;
+			return -1;
+		}
+
+		/* reset type and size to original values */
+		t->th_buf.typeflag = type2;
+		th_set_size(t, sz2);
+	}
+#endif
+
 	th_finish(t);
 
 #ifdef DEBUG
diff --git a/libtar/extract.c b/libtar/extract.c
index 6a63ff7..ba29a77 100644
--- a/libtar/extract.c
+++ b/libtar/extract.c
@@ -32,6 +32,10 @@
 # include "selinux/selinux.h"
 #endif
 
+#ifdef HAVE_EXT4_CRYPT
+# include "ext4crypt_tar.h"
+#endif
+
 const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);
 
 static int
@@ -492,7 +496,7 @@
 			}
 			else
 			{
-#ifdef DEBUG
+#if 1 //def DEBUG
 				puts("  *** using existing directory");
 #endif
 				return 1;
@@ -507,6 +511,28 @@
 		}
 	}
 
+#ifdef HAVE_EXT4_CRYPT
+	if(t->th_buf.e4crypt_policy != NULL)
+	{
+#ifdef DEBUG
+		printf("tar_extract_file(): restoring EXT4 crypt policy %s to dir %s\n", t->th_buf.e4crypt_policy, realname);
+#endif
+		char binary_policy[EXT4_KEY_DESCRIPTOR_SIZE];
+		if (!lookup_ref_tar(t->th_buf.e4crypt_policy, &binary_policy)) {
+			printf("error looking up proper e4crypt policy for '%s' - %s\n", realname, t->th_buf.e4crypt_policy);
+			return -1;
+		}
+		char policy_hex[EXT4_KEY_DESCRIPTOR_HEX];
+		policy_to_hex(binary_policy, policy_hex);
+		printf("restoring policy %s > '%s' to '%s'\n", t->th_buf.e4crypt_policy, policy_hex, realname);
+		if (!e4crypt_policy_set(realname, binary_policy, EXT4_KEY_DESCRIPTOR_SIZE, 0))
+		{
+			printf("tar_extract_file(): failed to restore EXT4 crypt policy %s to dir '%s' '%s'!!!\n", t->th_buf.e4crypt_policy, realname, policy_hex);
+			//return -1; // This may not be an error in some cases, so log and ignore
+		}
+	}
+#endif
+
 	return 0;
 }
 
diff --git a/libtar/libtar.h b/libtar/libtar.h
index 4a51375..ab5a3be 100644
--- a/libtar/libtar.h
+++ b/libtar/libtar.h
@@ -19,6 +19,11 @@
 
 #include "libtar_listhash.h"
 
+#ifdef HAVE_EXT4_CRYPT
+#define EXT4_KEY_DESCRIPTOR_SIZE 8
+#define EXT4_KEY_DESCRIPTOR_HEX 17
+#endif
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -38,6 +43,7 @@
 
 /* extended metadata for next file - used to store selinux_context */
 #define TH_EXT_TYPE		'x'
+#define TH_POL_TYPE		'p'
 
 /* our version of the tar header structure */
 struct tar_header
@@ -64,6 +70,9 @@
 #ifdef HAVE_SELINUX
 	char *selinux_context;
 #endif
+#ifdef HAVE_EXT4_CRYPT
+	char *e4crypt_policy;
+#endif
 };
 
 
@@ -108,6 +117,7 @@
 #define TAR_IGNORE_CRC		64	/* ignore CRC in file header */
 #define TAR_STORE_SELINUX	128	/* store selinux context */
 #define TAR_USE_NUMERIC_ID	256	/* favor numeric owner over names */
+#define TAR_STORE_EXT4_POL	512	/* store ext4 crypto policy */
 
 /* this is obsolete - it's here for backwards-compatibility only */
 #define TAR_IGNORE_MAGIC	0
@@ -204,6 +214,7 @@
 #define TH_ISLONGNAME(t)	((t)->th_buf.typeflag == GNU_LONGNAME_TYPE)
 #define TH_ISLONGLINK(t)	((t)->th_buf.typeflag == GNU_LONGLINK_TYPE)
 #define TH_ISEXTHEADER(t)	((t)->th_buf.typeflag == TH_EXT_TYPE)
+#define TH_ISPOLHEADER(t)	((t)->th_buf.typeflag == TH_POL_TYPE)
 
 /* decode tar header info */
 #define th_get_crc(t) oct_to_int((t)->th_buf.chksum, sizeof((t)->th_buf.chksum))
diff --git a/partition.cpp b/partition.cpp
index b764d94..5a53d61 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -60,7 +60,6 @@
 	#include "gpt/gpt.h"
 	#ifdef TW_INCLUDE_FBE
 		#include "crypto/ext4crypt/Decrypt.h"
-		//#include "crypto/ext4crypt/Ext4Crypt.h"
 	#endif
 #else
 	#define CRYPT_FOOTER_OFFSET 0x4000
@@ -532,16 +531,16 @@
 			ExcludeAll(Mount_Point + "/unencrypted");
 			//ExcludeAll(Mount_Point + "/system/users/0"); // we WILL need to retain some of this if multiple users are present or we just need to delete more folders for the extra users somewhere else
 			ExcludeAll(Mount_Point + "/misc/vold/user_keys");
-			ExcludeAll(Mount_Point + "/system_ce");
-			ExcludeAll(Mount_Point + "/system_de");
-			ExcludeAll(Mount_Point + "/misc_ce");
-			ExcludeAll(Mount_Point + "/misc_de");
+			//ExcludeAll(Mount_Point + "/system_ce");
+			//ExcludeAll(Mount_Point + "/system_de");
+			//ExcludeAll(Mount_Point + "/misc_ce");
+			//ExcludeAll(Mount_Point + "/misc_de");
 			ExcludeAll(Mount_Point + "/system/gatekeeper.password.key");
 			ExcludeAll(Mount_Point + "/system/gatekeeper.pattern.key");
 			ExcludeAll(Mount_Point + "/system/locksettings.db");
 			//ExcludeAll(Mount_Point + "/system/locksettings.db-shm"); // don't seem to need this one, but the other 2 are needed
 			ExcludeAll(Mount_Point + "/system/locksettings.db-wal");
-			ExcludeAll(Mount_Point + "/user_de");
+			//ExcludeAll(Mount_Point + "/user_de");
 			//ExcludeAll(Mount_Point + "/misc/profiles/cur/0"); // might be important later
 			ExcludeAll(Mount_Point + "/misc/gatekeeper");
 			ExcludeAll(Mount_Point + "/drm/kek.dat");
@@ -916,12 +915,9 @@
 		DataManager::SetValue("tw_has_internal", 1);
 		DataManager::SetValue("tw_has_data_media", 1);
 		backup_exclusions.add_absolute_dir("/data/data/com.google.android.music/files");
-		backup_exclusions.add_absolute_dir(Mount_Point + "/misc/vold");
-		wipe_exclusions.add_absolute_dir(Mount_Point + "/misc/vold");
-		backup_exclusions.add_absolute_dir(Mount_Point + "/.layout_version");
-		wipe_exclusions.add_absolute_dir(Mount_Point + "/.layout_version");
-		backup_exclusions.add_absolute_dir(Mount_Point + "/system/storage.xml");
-		wipe_exclusions.add_absolute_dir(Mount_Point + "/system/storage.xml");
+		ExcludeAll(Mount_Point + "/misc/vold");
+		ExcludeAll(Mount_Point + "/.layout_version");
+		ExcludeAll(Mount_Point + "/system/storage.xml");
 	} else {
 		if (Mount(true) && TWFunc::Path_Exists(Mount_Point + "/media/0")) {
 			Storage_Path = Mount_Point + "/media/0";
@@ -929,8 +925,7 @@
 			UnMount(true);
 		}
 	}
-	backup_exclusions.add_absolute_dir(Mount_Point + "/media");
-	wipe_exclusions.add_absolute_dir(Mount_Point + "/media");
+	ExcludeAll(Mount_Point + "/media");
 }
 
 void TWPartition::Find_Real_Block_Device(string& Block, bool Display_Error) {
@@ -2180,7 +2175,7 @@
 				rmdir(dir.c_str());
 			} else if (de->d_type == DT_REG || de->d_type == DT_LNK || de->d_type == DT_FIFO || de->d_type == DT_SOCK) {
 				if (!unlink(dir.c_str()))
-					LOGINFO("Unable to unlink '%s'\n", dir.c_str());
+					LOGINFO("Unable to unlink '%s': %s\n", dir.c_str(), strerror(errno));
 			}
 		}
 		closedir(d);
diff --git a/twrpTar.cpp b/twrpTar.cpp
index 3c07a97..4f9b633 100644
--- a/twrpTar.cpp
+++ b/twrpTar.cpp
@@ -53,6 +53,13 @@
 #include "set_metadata.h"
 #endif //ndef BUILD_TWRPTAR_MAIN
 
+#ifdef TW_INCLUDE_FBE
+#include "crypto/ext4crypt/ext4crypt_tar.h"
+#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_EXT4_POL
+#else
+#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX
+#endif
+
 using namespace std;
 
 twrpTar::twrpTar(void) {
@@ -72,6 +79,9 @@
 	input_fd = -1;
 	output_fd = -1;
 	backup_exclusions = NULL;
+#ifdef TW_INCLUDE_FBE
+	e4crypt_set_mode();
+#endif
 }
 
 twrpTar::~twrpTar(void) {
@@ -869,10 +879,10 @@
 int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
 	char* charTarFile = (char*) fn.c_str();
 
-	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) == -1)
+	if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) == -1)
 		return -1;
 	removeEOT(charTarFile);
-	if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
+	if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) == -1)
 		return -1;
 	for (unsigned int i = 0; i < files.size(); ++i) {
 		char* file = (char*) files.at(i).c_str();
@@ -977,7 +987,7 @@
 				fd = pipes[1];
 				init_libtar_no_buffer(progress_pipe_fd);
 				tar_type.writefunc = write_tar_no_buffer;
-				if(tar_fdopen(&t, 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) {
+				if(tar_fdopen(&t, fd, charRootDir, &tar_type, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
 					close(fd);
 					LOGINFO("tar_fdopen failed\n");
 					gui_err("backup_error=Error creating backup.");
@@ -1037,7 +1047,7 @@
 			fd = pigzfd[1];   // copy parent output
 			init_libtar_no_buffer(progress_pipe_fd);
 			tar_type.writefunc = write_tar_no_buffer;
-			if(tar_fdopen(&t, 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) {
+			if(tar_fdopen(&t, fd, charRootDir, &tar_type, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
 				close(fd);
 				LOGINFO("tar_fdopen failed\n");
 				gui_err("backup_error=Error creating backup.");
@@ -1087,7 +1097,7 @@
 			fd = oaesfd[1];   // copy parent output
 			init_libtar_no_buffer(progress_pipe_fd);
 			tar_type.writefunc = write_tar_no_buffer;
-			if(tar_fdopen(&t, 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) {
+			if(tar_fdopen(&t, fd, charRootDir, &tar_type, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
 				close(fd);
 				LOGINFO("tar_fdopen failed\n");
 				gui_err("backup_error=Error creating backup.");
@@ -1102,7 +1112,7 @@
 			LOGINFO("Opening TW_ADB_BACKUP uncompressed stream\n");
 			tar_type.writefunc = 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) {
+			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, TWTAR_FLAGS) != 0) {
 				close(output_fd);
 				LOGERR("tar_fdopen failed\n");
 				return -1;
@@ -1110,7 +1120,7 @@
 		}
 		else {
 			tar_type.writefunc = 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) {
+			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, TWTAR_FLAGS) == -1) {
 				LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
 				gui_err("backup_error=Error creating backup.");
 				return -1;
@@ -1210,7 +1220,7 @@
 				close(pipes[1]);
 				close(pipes[3]);
 				fd = pipes[2];
-				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, TWTAR_FLAGS) != 0) {
 					close(fd);
 					LOGINFO("tar_fdopen failed\n");
 					gui_err("restore_error=Error during restore process.");
@@ -1260,7 +1270,7 @@
 			// Parent
 			close(oaesfd[1]); // close parent output
 			fd = oaesfd[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, TWTAR_FLAGS) != 0) {
 				close(fd);
 				LOGINFO("tar_fdopen failed\n");
 				gui_err("restore_error=Error during restore process.");
@@ -1314,7 +1324,7 @@
 			// 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, TWTAR_FLAGS) != 0) {
 				close(fd);
 				LOGINFO("tar_fdopen failed\n");
 				gui_err("restore_error=Error during restore process.");
@@ -1325,14 +1335,14 @@
 		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) {
+			if (tar_fdopen(&t, input_fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 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) {
+			if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
 				LOGERR("Unable to open tar archive '%s'\n", charTarFile);
 				gui_err("restore_error=Error during restore process.");
 				return -1;