Extract file_contexts from zips if it exists

Update binary will now extract file_contexts if it exists in the
root of the zip to /tmp

Recovery will replace the existing /file_contexts in the ramdisk
if file_contexts exists in the root of the zip.

This ensure that the proper contexts are used during zip installs.

Change-Id: If22c41101868643b67e6dba6177677c078fcd877
diff --git a/twinstall.cpp b/twinstall.cpp
index 041c78d..8af7099 100644
--- a/twinstall.cpp
+++ b/twinstall.cpp
@@ -55,13 +55,44 @@
 
 	ret_val = mzExtractZipEntryToFile(Zip, binary_location, binary_fd);
 	close(binary_fd);
-	mzCloseZipArchive(Zip);
 
 	if (!ret_val) {
+		mzCloseZipArchive(Zip);
 		LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME);
 		return INSTALL_ERROR;
 	}
 
+	// If exists, extract file_contexts from the zip file
+	const ZipEntry* selinx_contexts = mzFindZipEntry(Zip, "file_contexts");
+	if (selinx_contexts == NULL) {
+		mzCloseZipArchive(Zip);
+		LOGINFO("Zip does not contain SELinux file_contexts file in its root.\n");
+	} else {
+		string output_filename = "/file_contexts";
+		LOGINFO("Zip contains SELinux file_contexts file in its root. Extracting to %s\n", output_filename.c_str());
+		// Delete any file_contexts
+		if (TWFunc::Path_Exists(output_filename) && unlink(output_filename.c_str()) != 0) {
+			LOGINFO("Unable to unlink '%s'\n", output_filename.c_str());
+		}
+
+		int file_contexts_fd = creat(output_filename.c_str(), 0644);
+		if (file_contexts_fd < 0) {
+			mzCloseZipArchive(Zip);
+			LOGERR("Could not extract file_contexts to '%s'\n", output_filename.c_str());
+			return INSTALL_ERROR;
+		}
+
+		ret_val = mzExtractZipEntryToFile(Zip, selinx_contexts, file_contexts_fd);
+		close(file_contexts_fd);
+
+		if (!ret_val) {
+			mzCloseZipArchive(Zip);
+			LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME);
+			return INSTALL_ERROR;
+		}
+	}
+	mzCloseZipArchive(Zip);
+
 	pipe(pipe_fd);
 
 	args[0] = Temp_Binary.c_str();