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/updater/updater.c b/updater/updater.c
index 58ac27f..15d3d41 100644
--- a/updater/updater.c
+++ b/updater/updater.c
@@ -17,6 +17,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <fcntl.h>
 
 #include "edify/expr.h"
 #include "updater.h"
@@ -31,6 +32,8 @@
 // Where in the package we expect to find the edify script to execute.
 // (Note it's "updateR-script", not the older "update-script".)
 #define SCRIPT_NAME "META-INF/com/google/android/updater-script"
+#define SELINUX_CONTEXTS_ZIP "file_contexts"
+#define SELINUX_CONTEXTS_TMP "/tmp/file_contexts"
 
 struct selabel_handle *sehandle;
 
@@ -87,6 +90,23 @@
     }
     script[script_entry->uncompLen] = '\0';
 
+    const ZipEntry* file_contexts_entry = mzFindZipEntry(&za, SELINUX_CONTEXTS_ZIP);
+    if (script_entry != NULL) {
+        int file_contexts_fd = creat(SELINUX_CONTEXTS_TMP, 0644);
+		if (file_contexts_fd < 0) {
+			fprintf(stderr, "Could not extract %s to '%s'\n", SELINUX_CONTEXTS_ZIP, SELINUX_CONTEXTS_TMP);
+			return 3;
+		}
+
+		int ret_val = mzExtractZipEntryToFile(&za, file_contexts_entry, file_contexts_fd);
+		close(file_contexts_fd);
+
+		if (!ret_val) {
+			fprintf(stderr, "Could not extract '%s'\n", SELINUX_CONTEXTS_ZIP);
+			return 3;
+		}
+    }
+
     // Configure edify's functions.
 
     RegisterBuiltins();
@@ -105,11 +125,19 @@
         return 6;
     }
 
-    struct selinux_opt seopts[] = {
-      { SELABEL_OPT_PATH, "/file_contexts" }
-    };
+    if (access(SELINUX_CONTEXTS_TMP, R_OK) == 0) {
+        struct selinux_opt seopts[] = {
+          { SELABEL_OPT_PATH, SELINUX_CONTEXTS_TMP }
+        };
 
-    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+        sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+    } else {
+        struct selinux_opt seopts[] = {
+          { SELABEL_OPT_PATH, "/file_contexts" }
+        };
+
+        sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+    }
 
     if (!sehandle) {
         fprintf(stderr, "Warning:  No file_contexts\n");