fix slash between directories
add fixing contexts of Android directory for apps that store stuff here
fix data/data contexts to be recursive

Change-Id: I1122559c83845c3af0a351a4034cd7ad6da83fa5
diff --git a/fixPermissions.cpp b/fixPermissions.cpp
index 12ce0b5..db6e90b 100644
--- a/fixPermissions.cpp
+++ b/fixPermissions.cpp
@@ -42,13 +42,13 @@
 using namespace rapidxml;
 
 #ifdef HAVE_SELINUX
+struct selabel_handle *sehandle;
+struct selinux_opt selinux_options[] = {
+	{ SELABEL_OPT_PATH, "/file_contexts" }
+};
+
 int fixPermissions::restorecon(string entry, struct stat *sb) {
 	char *oldcontext, *newcontext;
-	struct selabel_handle *sehandle;
-	struct selinux_opt selinux_options[] = {
-		{ SELABEL_OPT_PATH, "/file_contexts" }
-	};
-	sehandle = selabel_open(SELABEL_CTX_FILE, selinux_options, 1);
 	if (lgetfilecon(entry.c_str(), &oldcontext) < 0) {
 		LOGINFO("Couldn't get selinux context for %s\n", entry.c_str());
 		return -1;
@@ -57,9 +57,11 @@
 		LOGINFO("Couldn't lookup selinux context for %s\n", entry.c_str());
 		return -1;
 	}
-	LOGINFO("Relabeling %s from %s to %s\n", entry.c_str(), oldcontext, newcontext);
-	if (lsetfilecon(entry.c_str(), newcontext) < 0) {
-		LOGINFO("Couldn't label %s with %s: %s\n", entry.c_str(), newcontext, strerror(errno));
+	if (strcmp(oldcontext, newcontext) != 0) {
+		LOGINFO("Relabeling %s from %s to %s\n", entry.c_str(), oldcontext, newcontext);
+		if (lsetfilecon(entry.c_str(), newcontext) < 0) {
+			LOGINFO("Couldn't label %s with %s: %s\n", entry.c_str(), newcontext, strerror(errno));
+		}
 	}
 	freecon(oldcontext);
 	freecon(newcontext);
@@ -67,29 +69,39 @@
 }
 
 int fixPermissions::fixDataDataContexts(void) {
+	string dir = "/data/data/";
+	sehandle = selabel_open(SELABEL_CTX_FILE, selinux_options, 1);
+	if (TWFunc::Path_Exists(dir)) {
+		fixContextsRecursively(dir, 0);
+	}
+	selabel_close(sehandle);
+	return 0;
+}
+
+int fixPermissions::fixContextsRecursively(string name, int level) {
 	DIR *d;
 	struct dirent *de;
 	struct stat sb;
-	struct selabel_handle *selinux_handle;
-	struct selinux_opt selinux_options[] = {
-		{ SELABEL_OPT_PATH, "/file_contexts" }
-	};
+	string path;
 
-	selinux_handle = selabel_open(SELABEL_CTX_FILE, selinux_options, 1);
+	if (!(d = opendir(name.c_str())))
+		return -1;
+	if (!(de = readdir(d)))
+		return -1;
 
-	if (!selinux_handle)
-		printf("No file contexts for SELinux\n");
-	else
-		printf("SELinux contexts loaded from /file_contexts\n");
-
-	d = opendir("/data/data");
-
-	while (( de = readdir(d)) != NULL) {
-		stat(de->d_name, &sb);
-		string f = "/data/data/";
-		f = f + de->d_name;
-		restorecon(f, &sb);
-	}
+	do {
+		if (de->d_type ==  DT_DIR) {
+			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+				continue;
+			path = name + "/" + de->d_name;
+			restorecon(path, &sb);
+			fixContextsRecursively(path, level + 1);
+		}
+		else {
+			path = name + "/" + de->d_name;
+			restorecon(path, &sb);
+		}
+	} while (de = readdir(d));
 	closedir(d);
 	return 0;
 }
@@ -98,24 +110,30 @@
 	DIR *d;
 	struct dirent *de;
 	struct stat sb;
-	string dir;
+	string dir, androiddir;
+	sehandle = selabel_open(SELABEL_CTX_FILE, selinux_options, 1);
 
-	if (TWFunc::Path_Exists("/data/media")) {
-		dir = "/data/media";
-	}
-	else {
+	if (TWFunc::Path_Exists("/data/media/0"))
 		dir = "/data/media/0";
-	}
+	else
+		dir = "/data/media";
 	LOGINFO("Fixing %s contexts\n", dir.c_str());
+	restorecon(dir, &sb);
 	d = opendir(dir.c_str());
 
 	while (( de = readdir(d)) != NULL) {
 		stat(de->d_name, &sb);
 		string f;
-		f = dir + de->d_name;
+		f = dir + "/" + de->d_name;
 		restorecon(f, &sb);
 	}
 	closedir(d);
+
+	androiddir = dir + "/Android/";
+	if (TWFunc::Path_Exists(androiddir)) {
+		fixContextsRecursively(androiddir, 0);
+	}
+	selabel_close(sehandle);
 	return 0;
 }
 #endif