Attempt to set the proper uid/gid/contexts on new files and dirs

Files and folders that we create during backups, copy log, or MTP
operations often do not have the proper uid/gid/contexts assigned.
We will attempt to read the proper contexts from the settings
storage path and assign those same contexts to any files or dirs
that we create.

Change-Id: I769f9479854122b49b499de2175e6e2d026f8afd
diff --git a/Android.mk b/Android.mk
index e909baa..2a10877 100644
--- a/Android.mk
+++ b/Android.mk
@@ -449,8 +449,8 @@
 LOCAL_MODULE := libaosprecovery
 LOCAL_MODULE_TAGS := eng optional
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/libmincrypt/includes
-LOCAL_SRC_FILES := adb_install.cpp asn1_decoder.cpp bootloader.cpp mtdutils/mtdutils.c legacy_property_service.c verifier.cpp
-LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils libfusesideload libmincrypttwrp
+LOCAL_SRC_FILES := adb_install.cpp asn1_decoder.cpp bootloader.cpp mtdutils/mtdutils.c legacy_property_service.c verifier.cpp set_metadata.c
+LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils libfusesideload libmincrypttwrp libselinux
 
 ifneq ($(BOARD_RECOVERY_BLDRMSG_OFFSET),)
     LOCAL_CFLAGS += -DBOARD_RECOVERY_BLDRMSG_OFFSET=$(BOARD_RECOVERY_BLDRMSG_OFFSET)
diff --git a/data.cpp b/data.cpp
index 0d05c3d..88bc86a 100644
--- a/data.cpp
+++ b/data.cpp
@@ -46,6 +46,7 @@
 #include "gui/blanktimer.hpp"
 #endif
 #include "find_file.hpp"
+#include "set_metadata.h"
 
 #ifdef TW_USE_MODEL_HARDWARE_ID_FOR_DEVICE_ID
 	#include "cutils/properties.h"
@@ -333,6 +334,7 @@
 		}
 	}
 	fclose(out);
+	tw_set_default_metadata(mBackingFile.c_str());
 #endif // ifdef TW_OEM_BUILD
 	return 0;
 }
diff --git a/gui/Android.mk b/gui/Android.mk
index 479bc76..d7a605e 100644
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -33,7 +33,7 @@
   LOCAL_SRC_FILES += hardwarekeyboard.cpp
 endif
 
-LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libminzip
+LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libminzip libaosprecovery
 LOCAL_MODULE := libguitwrp
 
 # Use this flag to create a build that simulates threaded actions like installing zips, backups, restores, and wipes for theme testing
diff --git a/gui/action.cpp b/gui/action.cpp
index 6b8565a..d72b331 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -52,6 +52,7 @@
 #include "cutils/properties.h"
 #include "../minadbd/adb.h"
 #include "../adb_install.h"
+#include "../set_metadata.h"
 
 int TWinstall_zip(const char* path, int* wipe_cache);
 void run_script(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5, const char *str6, const char *str7, int request_confirm);
@@ -503,6 +504,7 @@
 			PartitionManager.Mount_Current_Storage(true);
 			dst = DataManager::GetCurrentStoragePath() + "/recovery.log";
 			TWFunc::copy_file("/tmp/recovery.log", dst.c_str(), 0755);
+			tw_set_default_metadata(dst.c_str());
 			sync();
 			gui_print("Copied recovery log to %s.\n", DataManager::GetCurrentStoragePath().c_str());
 		} else
@@ -1222,6 +1224,12 @@
 							int check = 0;
 							std::string theme_path;
 
+							if (tw_get_default_metadata(DataManager::GetSettingsStoragePath().c_str()) != 0) {
+								LOGERR("Failed to get default contexts and file mode for storage files.\n");
+							} else {
+								LOGINFO("Got default contexts and file mode for storage files.\n");
+							}
+
 							theme_path = DataManager::GetSettingsStoragePath();
 							if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
 								LOGERR("Unable to mount %s during reload function startup.\n", theme_path.c_str());
diff --git a/infomanager.cpp b/infomanager.cpp
index 080fe1d..864c431 100644
--- a/infomanager.cpp
+++ b/infomanager.cpp
@@ -39,6 +39,7 @@
 #include "infomanager.hpp"
 #include "twcommon.h"
 #include "partitions.hpp"
+#include "set_metadata.h"
 
 using namespace std;
 
@@ -97,7 +98,7 @@
 		return -1;
 
 	PartitionManager.Mount_By_Path(File, true);
-LOGINFO("InfoManager saving '%s'\n", File.c_str());
+	LOGINFO("InfoManager saving '%s'\n", File.c_str());
 	FILE* out = fopen(File.c_str(), "wb");
 	if (!out)
 		return -1;
@@ -112,6 +113,7 @@
 		fwrite(iter->second.c_str(), 1, length, out);
 	}
 	fclose(out);
+	tw_set_default_metadata(File.c_str());
 	return 0;
 }
 
diff --git a/mtp/Android.mk b/mtp/Android.mk
index 809a29a..283a283 100755
--- a/mtp/Android.mk
+++ b/mtp/Android.mk
@@ -29,7 +29,7 @@
     twrpMtp.cpp \
     mtp_MtpDatabase.cpp \
     node.cpp
-LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libstlport libdl libcutils libutils
+LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libstlport libdl libcutils libutils libaosprecovery
 
 ifneq ($(TW_MTP_DEVICE),)
 	LOCAL_CFLAGS += -DUSB_MTP_DEVICE=$(TW_MTP_DEVICE)
@@ -66,5 +66,5 @@
     twrpMtp.cpp \
     mtp_MtpDatabase.cpp \
     node.cpp
-LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libstlport libdl libcutils libutils
+LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libstlport libdl libcutils libutils libaosprecovery
 include $(BUILD_EXECUTABLE)
diff --git a/mtp/MtpServer.cpp b/mtp/MtpServer.cpp
index 66a6414..f4af2b9 100755
--- a/mtp/MtpServer.cpp
+++ b/mtp/MtpServer.cpp
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <dirent.h>
 #include "../twcommon.h"
+#include "../set_metadata.h"
 #include <cutils/properties.h>
 
 #include "MtpTypes.h"
@@ -1002,6 +1003,7 @@
 			return MTP_RESPONSE_GENERAL_ERROR;
 		}
 		chown((const char *)path, getuid(), mFileGroup);
+		tw_set_default_metadata((const char *)path);
 
 		// SendObject does not get sent for directories, so call endSendObject here instead
 		mDatabase->lockMutex();
@@ -1073,6 +1075,7 @@
 		ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
 	}
 	close(mfr.fd);
+	tw_set_default_metadata((const char *)mSendObjectFilePath);
 
 	if (ret < 0) {
 		unlink(mSendObjectFilePath);
diff --git a/partition.cpp b/partition.cpp
index d84e48f..b3c436f 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -42,6 +42,7 @@
 #include "twrpDU.hpp"
 #include "fixPermissions.hpp"
 #include "infomanager.hpp"
+#include "set_metadata.h"
 extern "C" {
 	#include "mtdutils/mtdutils.h"
 	#include "mtdutils/mounts.h"
@@ -1748,6 +1749,7 @@
 	Command = "dd if=" + Actual_Block_Device + " of='" + Full_FileName + "'" + " bs=" + DD_BS + " count=1";
 	LOGINFO("Backup command: '%s'\n", Command.c_str());
 	TWFunc::Exec_Cmd(Command);
+	tw_set_default_metadata(Full_FileName.c_str());
 	if (TWFunc::Get_File_Size(Full_FileName) == 0) {
 		LOGERR("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str());
 		return false;
@@ -1771,6 +1773,7 @@
 	Command = "dump_image " + MTD_Name + " '" + Full_FileName + "'";
 	LOGINFO("Backup command: '%s'\n", Command.c_str());
 	TWFunc::Exec_Cmd(Command);
+	tw_set_default_metadata(Full_FileName.c_str());
 	if (TWFunc::Get_File_Size(Full_FileName) == 0) {
 		// Actual size may not match backup size due to bad blocks on MTD devices so just check for 0 bytes
 		LOGERR("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str());
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 437ed2f..92b2875 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -38,6 +38,7 @@
 #include "fixPermissions.hpp"
 #include "twrpDigest.hpp"
 #include "twrpDU.hpp"
+#include "set_metadata.h"
 
 #ifdef TW_HAS_MTP
 #include "mtp/mtp_MtpServer.hpp"
@@ -757,6 +758,7 @@
 	gui_print_color("highlight", "[BACKUP COMPLETED IN %d SECONDS]\n\n", total_time); // the end
 	string backup_log = Full_Backup_Path + "recovery.log";
 	TWFunc::copy_file("/tmp/recovery.log", backup_log, 0644);
+	tw_set_default_metadata(backup_log.c_str());
 	return true;
 }
 
diff --git a/set_metadata.c b/set_metadata.c
new file mode 100644
index 0000000..f4e0de2
--- /dev/null
+++ b/set_metadata.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 The 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.
+ */
+
+/*
+ * The purpose of these functions is to try to get and set the proper
+ * file permissions, SELinux contexts, owner, and group so that these
+ * files are accessible when we boot up to normal Android via MTP and to
+ * file manager apps. During early boot we try to read the contexts and
+ * owner / group info from /data/media or from /data/media/0 and store
+ * them in static variables. From there, we'll try to set the same
+ * contexts, owner, and group information on most files we create during
+ * operations like backups, copying the log, and MTP operations.
+ */
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "selinux/selinux.h"
+
+static security_context_t selinux_context;
+struct stat s;
+static int has_stat = 0;
+
+int tw_get_context(const char* filename) {
+	if (lgetfilecon(filename, &selinux_context) >= 0) {
+		printf("tw_get_context got selinux context: %s\n", selinux_context);
+		return 0;
+	} else {
+		printf("tw_get_context failed to get selinux context");
+		selinux_context = NULL;
+	}
+	return -1;
+}
+
+int tw_get_stat(const char* filename) {
+	if (lstat(filename, &s) == 0) {
+		has_stat = 1;
+		return 0;
+	}
+	printf("tw_get_stat failed to lstat '%s'\n", filename);
+	return -1;
+}
+
+int tw_get_default_metadata(const char* filename) {
+	if (tw_get_context(filename) == 0 && tw_get_stat(filename) == 0)
+		return 0;
+	return -1;
+}
+
+// Most of this logging is disabled to prevent log spam if we are trying
+// to set contexts and permissions on file systems that do not support
+// these types of things (e.g. vfat / FAT / FAT32).
+int tw_set_default_metadata(const char* filename) {
+	int ret = 0;
+	struct stat st;
+
+	if (selinux_context == NULL) {
+		//printf("selinux_context was null, '%s'\n", filename);
+		ret = -1;
+	} else if (lsetfilecon(filename, selinux_context) < 0) {
+		//printf("Failed to set default contexts on '%s'.\n", filename);
+		ret = -1;
+	}
+
+	if (lstat(filename, &st) == 0 && st.st_mode & S_IFREG && chmod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) < 0) {
+		//printf("Failed to chmod '%s'\n", filename);
+		ret = -1;
+	}
+
+	if (has_stat && chown(filename, s.st_uid, s.st_gid) < 0) {
+		//printf("Failed to lchown '%s'.\n", filename);
+		ret = -1;
+	}
+	//printf("Done trying to set defaults on '%s'\n");
+	return ret;
+}
diff --git a/set_metadata.h b/set_metadata.h
new file mode 100644
index 0000000..835c31c
--- /dev/null
+++ b/set_metadata.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 The 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.
+ */
+
+/*
+ * The purpose of these functions is to try to get and set the proper
+ * file permissions, SELinux contexts, owner, and group so that these
+ * files are accessible when we boot up to normal Android via MTP and to
+ * file manager apps. During early boot we try to read the contexts and
+ * owner / group info from /data/media or from /data/media/0 and store
+ * them in static variables. From there, we'll try to set the same
+ * contexts, owner, and group information on most files we create during
+ * operations like backups, copying the log, and MTP operations.
+ */
+
+#ifndef _RECOVERY_SET_CONTEXTS_H
+#define _RECOVERY_SET_CONTEXTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/stat.h>
+#include "selinux/selinux.h"
+
+int tw_get_default_metadata(const char* filename);
+int tw_set_default_metadata(const char* filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_RECOVERY_SET_CONTEXTS_H
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 9611424..b51024c 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -54,6 +54,7 @@
 
 extern "C" {
 	#include "libcrecovery/common.h"
+	#include "set_metadata.h"
 }
 
 /* Execute a command */
@@ -406,9 +407,13 @@
 	while (pos != string::npos)
 	{
 		wholePath = pathCpy.substr(0, pos);
-		if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST) {
-			LOGERR("Unable to create folder: %s  (errno=%d)\n", wholePath.c_str(), errno);
-			return false;
+		if (!TWFunc::Path_Exists(wholePath)) {
+			if (mkdir(wholePath.c_str(), 0777)) {
+				LOGERR("Unable to create folder: %s  (errno=%d)\n", wholePath.c_str(), errno);
+				return false;
+			} else {
+				tw_set_default_metadata(wholePath.c_str());
+			}
 		}
 
 		pos = pathCpy.find("/", pos + 1);
diff --git a/twrp.cpp b/twrp.cpp
index a633bec..f76ab64 100644
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -35,6 +35,7 @@
 
 extern "C" {
 #include "gui/gui.h"
+#include "set_metadata.h"
 }
 #include "twcommon.h"
 #include "twrp-functions.hpp"
@@ -274,6 +275,12 @@
 		if (gui_startPage("decrypt") != 0) {
 			LOGERR("Failed to start decrypt GUI page.\n");
 		}
+	} else if (datamedia) {
+		if (tw_get_default_metadata(DataManager::GetSettingsStoragePath().c_str()) != 0) {
+			LOGERR("Failed to get default contexts and file mode for storage files.\n");
+		} else {
+			LOGINFO("Got default contexts and file mode for storage files.\n");
+		}
 	}
 
 	// Read the settings file
diff --git a/twrpDigest.cpp b/twrpDigest.cpp
index 0693c55..c3cff71 100644
--- a/twrpDigest.cpp
+++ b/twrpDigest.cpp
@@ -40,6 +40,7 @@
 #include "variables.h"
 #include "twrp-functions.hpp"
 #include "twrpDigest.hpp"
+#include "set_metadata.h"
 
 using namespace std;
 
@@ -79,6 +80,7 @@
 	md5string += basename((char*) md5fn.c_str());
 	md5string +=  + "\n";
 	TWFunc::write_file(md5file, md5string);
+	tw_set_default_metadata(md5file.c_str());
 	LOGINFO("MD5 for %s: %s\n", md5fn.c_str(), md5string.c_str());
 	return 0;
 }
diff --git a/twrpTar.cpp b/twrpTar.cpp
index b5d66d3..968b6b9 100644
--- a/twrpTar.cpp
+++ b/twrpTar.cpp
@@ -21,6 +21,7 @@
 	#include "libtar/libtar.h"
 	#include "twrpTar.h"
 	#include "tarWrite.h"
+	#include "set_metadata.h"
 }
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -1242,6 +1243,7 @@
 		LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
 		return -1;
 	}
+	tw_set_default_metadata(tarfn.c_str());
 	return 0;
 }