am e5d5ac76: minor recovery changes

* commit 'e5d5ac76cc8e5d11867aeff6a1d068215c1c3a7c':
  minor recovery changes
diff --git a/Android.mk b/Android.mk
index 7e48e7f..21e6946 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,6 +28,12 @@
 LOCAL_STATIC_LIBRARIES += libext4_utils libz
 endif
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 # This binary is in the recovery ramdisk, which is otherwise a copy of root.
 # It gets copied there in config/Makefile.  LOCAL_MODULE_TAGS suppresses
 # a (redundant) copy of the binary in /system/bin for user builds.
@@ -40,11 +46,17 @@
 else
   LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
 endif
-LOCAL_STATIC_LIBRARIES += libext4_utils libz
-LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt libminadbd
+LOCAL_STATIC_LIBRARIES += libext4_utils
+LOCAL_STATIC_LIBRARIES += libminzip libz libmtdutils libmincrypt libminadbd
 LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils
 LOCAL_STATIC_LIBRARIES += libstdc++ libc
 
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 LOCAL_C_INCLUDES += system/extras/ext4_utils
 
 include $(BUILD_EXECUTABLE)
diff --git a/applypatch/NOTICE b/applypatch/NOTICE
new file mode 100644
index 0000000..6156a0c
--- /dev/null
+++ b/applypatch/NOTICE
@@ -0,0 +1,41 @@
+Copyright (C) 2009 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.
+
+
+bsdiff.c
+bspatch.c
+
+Copyright 2003-2005 Colin Percival
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted providing that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c
index 1060913..00004e9 100644
--- a/applypatch/applypatch.c
+++ b/applypatch/applypatch.c
@@ -30,10 +30,16 @@
 #include "mtdutils/mtdutils.h"
 #include "edify/expr.h"
 
-int SaveFileContents(const char* filename, FileContents file);
 static int LoadPartitionContents(const char* filename, FileContents* file);
-int ParseSha1(const char* str, uint8_t* digest);
 static ssize_t FileSink(unsigned char* data, ssize_t len, void* token);
+static int GenerateTarget(FileContents* source_file,
+                          const Value* source_patch_value,
+                          FileContents* copy_file,
+                          const Value* copy_patch_value,
+                          const char* source_filename,
+                          const char* target_filename,
+                          const uint8_t target_sha1[SHA_DIGEST_SIZE],
+                          size_t target_size);
 
 static int mtd_partitions_scanned = 0;
 
@@ -113,11 +119,6 @@
     }
 }
 
-void FreeFileContents(FileContents* file) {
-    if (file) free(file->data);
-    free(file);
-}
-
 // Load the contents of an MTD or EMMC partition into the provided
 // FileContents.  filename should be a string of the form
 // "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..."  (or
@@ -322,7 +323,7 @@
 
 // Save the contents of the given FileContents object under the given
 // filename.  Return 0 on success.
-int SaveFileContents(const char* filename, FileContents file) {
+int SaveFileContents(const char* filename, const FileContents* file) {
     int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
     if (fd < 0) {
         printf("failed to open \"%s\" for write: %s\n",
@@ -330,10 +331,10 @@
         return -1;
     }
 
-    ssize_t bytes_written = FileSink(file.data, file.size, &fd);
-    if (bytes_written != file.size) {
+    ssize_t bytes_written = FileSink(file->data, file->size, &fd);
+    if (bytes_written != file->size) {
         printf("short write of \"%s\" (%ld bytes of %ld) (%s)\n",
-               filename, (long)bytes_written, (long)file.size,
+               filename, (long)bytes_written, (long)file->size,
                strerror(errno));
         close(fd);
         return -1;
@@ -341,11 +342,11 @@
     fsync(fd);
     close(fd);
 
-    if (chmod(filename, file.st.st_mode) != 0) {
+    if (chmod(filename, file->st.st_mode) != 0) {
         printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
         return -1;
     }
-    if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) {
+    if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) {
         printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
         return -1;
     }
@@ -471,7 +472,7 @@
 // Search an array of sha1 strings for one matching the given sha1.
 // Return the index of the match on success, or -1 if no match is
 // found.
-int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
+int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str,
                       int num_patches) {
     int i;
     uint8_t patch_sha1[SHA_DIGEST_SIZE];
@@ -503,6 +504,7 @@
                "sha1 sums; checking cache\n", filename);
 
         free(file.data);
+        file.data = NULL;
 
         // If the source file is missing or corrupted, it might be because
         // we were killed in the middle of patching it.  A copy of it
@@ -631,9 +633,10 @@
 
     FileContents copy_file;
     FileContents source_file;
+    copy_file.data = NULL;
+    source_file.data = NULL;
     const Value* source_patch_value = NULL;
     const Value* copy_patch_value = NULL;
-    int made_copy = 0;
 
     // We try to load the target file into the source_file object.
     if (LoadFileContents(target_filename, &source_file,
@@ -643,6 +646,7 @@
             // has the desired hash, nothing for us to do.
             printf("\"%s\" is already target; no patch needed\n",
                    target_filename);
+            free(source_file.data);
             return 0;
         }
     }
@@ -653,6 +657,7 @@
         // Need to load the source file:  either we failed to load the
         // target file, or we did but it's different from the source file.
         free(source_file.data);
+        source_file.data = NULL;
         LoadFileContents(source_filename, &source_file,
                          RETOUCH_DO_MASK);
     }
@@ -667,6 +672,7 @@
 
     if (source_patch_value == NULL) {
         free(source_file.data);
+        source_file.data = NULL;
         printf("source file is bad; trying copy\n");
 
         if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file,
@@ -685,16 +691,36 @@
         if (copy_patch_value == NULL) {
             // fail.
             printf("copy file doesn't match source SHA-1s either\n");
+            free(copy_file.data);
             return 1;
         }
     }
 
+    int result = GenerateTarget(&source_file, source_patch_value,
+                                &copy_file, copy_patch_value,
+                                source_filename, target_filename,
+                                target_sha1, target_size);
+    free(source_file.data);
+    free(copy_file.data);
+
+    return result;
+}
+
+static int GenerateTarget(FileContents* source_file,
+                          const Value* source_patch_value,
+                          FileContents* copy_file,
+                          const Value* copy_patch_value,
+                          const char* source_filename,
+                          const char* target_filename,
+                          const uint8_t target_sha1[SHA_DIGEST_SIZE],
+                          size_t target_size) {
     int retry = 1;
     SHA_CTX ctx;
     int output;
     MemorySinkInfo msi;
     FileContents* source_to_use;
     char* outname;
+    int made_copy = 0;
 
     // assume that target_filename (eg "/system/app/Foo.apk") is located
     // on the same filesystem as its top-level directory ("/system").
@@ -723,7 +749,7 @@
 
             // We still write the original source to cache, in case
             // the partition write is interrupted.
-            if (MakeFreeSpaceOnCache(source_file.size) < 0) {
+            if (MakeFreeSpaceOnCache(source_file->size) < 0) {
                 printf("not enough free space on /cache\n");
                 return 1;
             }
@@ -763,7 +789,7 @@
                     return 1;
                 }
 
-                if (MakeFreeSpaceOnCache(source_file.size) < 0) {
+                if (MakeFreeSpaceOnCache(source_file->size) < 0) {
                     printf("not enough free space on /cache\n");
                     return 1;
                 }
@@ -782,10 +808,10 @@
 
         const Value* patch;
         if (source_patch_value != NULL) {
-            source_to_use = &source_file;
+            source_to_use = source_file;
             patch = source_patch_value;
         } else {
-            source_to_use = &copy_file;
+            source_to_use = copy_file;
             patch = copy_patch_value;
         }
 
diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h
index a78c89b..fb58843 100644
--- a/applypatch/applypatch.h
+++ b/applypatch/applypatch.h
@@ -62,9 +62,9 @@
 
 int LoadFileContents(const char* filename, FileContents* file,
                      int retouch_flag);
-int SaveFileContents(const char* filename, FileContents file);
+int SaveFileContents(const char* filename, const FileContents* file);
 void FreeFileContents(FileContents* file);
-int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
+int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str,
                       int num_patches);
 
 // bsdiff.c
diff --git a/etc/init.rc b/etc/init.rc
index bf4ce62..89a161e 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -22,9 +22,9 @@
     write /sys/class/android_usb/android0/idVendor 18D1
     write /sys/class/android_usb/android0/idProduct D001
     write /sys/class/android_usb/android0/functions adb
-    write /sys/class/android_usb/android0/iManufacturer $ro.product.manufacturer
-    write /sys/class/android_usb/android0/iProduct $ro.product.model
-    write /sys/class/android_usb/android0/iSerial $ro.serialno
+    write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
+    write /sys/class/android_usb/android0/iProduct ${ro.product.model}
+    write /sys/class/android_usb/android0/iSerial ${ro.serialno}
 
 
 on boot
diff --git a/minelf/Retouch.c b/minelf/Retouch.c
index 33809cd..d75eec1 100644
--- a/minelf/Retouch.c
+++ b/minelf/Retouch.c
@@ -194,213 +194,3 @@
     if (retouch_offset != NULL) *retouch_offset = offset_candidate;
     return RETOUCH_DATA_MATCHED;
 }
-
-// On success, _override is set to the offset that was actually applied.
-// This implies that once we randomize to an offset we stick with it.
-// This in turn is necessary in order to guarantee recovery after crash.
-bool retouch_one_library(const char *binary_name,
-                         const char *binary_sha1,
-                         int32_t retouch_offset,
-                         int32_t *retouch_offset_override) {
-    bool success = true;
-    int result;
-
-    FileContents file;
-    file.data = NULL;
-
-    char binary_name_atomic[strlen(binary_name)+10];
-    strcpy(binary_name_atomic, binary_name);
-    strcat(binary_name_atomic, ".atomic");
-
-    // We need a path that exists for calling statfs() later.
-    //
-    // Assume that binary_name (eg "/system/app/Foo.apk") is located
-    // on the same filesystem as its top-level directory ("/system").
-    char target_fs[strlen(binary_name)+1];
-    char* slash = strchr(binary_name+1, '/');
-    if (slash != NULL) {
-        int count = slash - binary_name;
-        strncpy(target_fs, binary_name, count);
-        target_fs[count] = '\0';
-    } else {
-        strcpy(target_fs, binary_name);
-    }
-
-    result = LoadFileContents(binary_name, &file, RETOUCH_DONT_MASK);
-
-    if (result == 0) {
-        // Figure out the *apparent* offset to which this file has been
-        // retouched. If it looks good, we will skip processing (we might
-        // have crashed and during this recovery pass we don't want to
-        // overwrite a valuable saved file in /cache---which would happen
-        // if we blindly retouch everything again). NOTE: This implies
-        // that we might have to override the supplied retouch offset. We
-        // can do the override only once though: everything should match
-        // afterward.
-
-        int32_t inferred_offset;
-        int retouch_probe_result = retouch_mask_data(file.data,
-                                                     file.size,
-                                                     NULL,
-                                                     &inferred_offset);
-
-        if (retouch_probe_result == RETOUCH_DATA_MATCHED) {
-            if ((retouch_offset == inferred_offset) ||
-                ((retouch_offset != 0 && inferred_offset != 0) &&
-                 (retouch_offset_override != NULL))) {
-                // This file is OK already and we are allowed to override.
-                // Let's just return the offset override value. It is critical
-                // to skip regardless of override: a broken file might need
-                // recovery down the list and we should not mess up the saved
-                // copy by doing unnecessary retouching.
-                //
-                // NOTE: If retouching was already started with a different
-                // value, we will not be allowed to override. This happens
-                // if on the retouch list there is a patched binary (which is
-                // masked in apply_patch()) before there is a non-patched
-                // binary.
-                if (retouch_offset_override != NULL)
-                    *retouch_offset_override = inferred_offset;
-                success = true;
-                goto out;
-            } else {
-                // Retouch to zero (mask the retouching), to make sure that
-                // the SHA-1 check will pass below.
-                int32_t zero = 0;
-                retouch_mask_data(file.data, file.size, &zero, NULL);
-                SHA(file.data, file.size, file.sha1);
-            }
-        }
-
-        if (retouch_probe_result == RETOUCH_DATA_NOTAPPLICABLE) {
-            // In the case of not retouchable, fake it. We do not want
-            // to do the normal processing and overwrite the backup file:
-            // we might be recovering!
-            //
-            // We return a zero override, which tells the caller that we
-            // simply skipped the file.
-            if (retouch_offset_override != NULL)
-                *retouch_offset_override = 0;
-            success = true;
-            goto out;
-        }
-
-        // If we get here, either there was a mismatch in the offset, or
-        // the file has not been processed yet. Continue with normal
-        // processing.
-    }
-
-    if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) {
-        free(file.data);
-        printf("Attempting to recover source from '%s' ...\n",
-               CACHE_TEMP_SOURCE);
-        result = LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK);
-        if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) {
-            printf(" failed.\n");
-            success = false;
-            goto out;
-        }
-        printf(" succeeded.\n");
-    }
-
-    // Retouch in-memory before worrying about backing up the original.
-    //
-    // Recovery steps will be oblivious to the actual retouch offset used,
-    // so might as well write out the already-retouched copy. Then, in the
-    // usual case, we will just swap the file locally, with no more writes
-    // needed. In the no-free-space case, we will then write the same to the
-    // original location.
-
-    result = retouch_mask_data(file.data, file.size, &retouch_offset, NULL);
-    if (result != RETOUCH_DATA_MATCHED) {
-        success = false;
-        goto out;
-    }
-    if (retouch_offset_override != NULL)
-        *retouch_offset_override = retouch_offset;
-
-    // How much free space do we need?
-    bool enough_space = false;
-    size_t free_space = FreeSpaceForFile(target_fs);
-    // 50% margin when estimating the space needed.
-    enough_space = (free_space > (file.size * 3 / 2));
-
-    // The experts say we have to allow for a retry of the
-    // whole process to avoid filesystem weirdness.
-    int retry = 1;
-    bool made_copy = false;
-    do {
-        // First figure out where to store a copy of the original.
-        // Ideally leave the original itself intact until the
-        // atomic swap. If no room on the same partition, fall back
-        // to the cache partition and remove the original.
-
-        if (!enough_space) {
-            printf("Target is %ldB; free space is %ldB: not enough.\n",
-                   (long)file.size, (long)free_space);
-
-            retry = 0;
-            if (MakeFreeSpaceOnCache(file.size) < 0) {
-                printf("Not enough free space on '/cache'.\n");
-                success = false;
-                goto out;
-            }
-            if (SaveFileContents(CACHE_TEMP_SOURCE, file) < 0) {
-                printf("Failed to back up source file.\n");
-                success = false;
-                goto out;
-            }
-            made_copy = true;
-            unlink(binary_name);
-
-            size_t free_space = FreeSpaceForFile(target_fs);
-            printf("(now %ld bytes free for target)\n", (long)free_space);
-        }
-
-        result = SaveFileContents(binary_name_atomic, file);
-        if (result != 0) {
-            // Maybe the filesystem was optimistic: retry.
-            enough_space = false;
-            unlink(binary_name_atomic);
-            printf("Saving the retouched contents failed; retrying.\n");
-            continue;
-        }
-
-        // Succeeded; no need to retry.
-        break;
-    } while (retry-- > 0);
-
-    // Give the .atomic file the same owner, group, and mode of the
-    // original source file.
-    if (chmod(binary_name_atomic, file.st.st_mode) != 0) {
-        printf("chmod of \"%s\" failed: %s\n",
-               binary_name_atomic, strerror(errno));
-        success = false;
-        goto out;
-    }
-    if (chown(binary_name_atomic, file.st.st_uid, file.st.st_gid) != 0) {
-        printf("chown of \"%s\" failed: %s\n",
-               binary_name_atomic,
-               strerror(errno));
-        success = false;
-        goto out;
-    }
-
-    // Finally, rename the .atomic file to replace the target file.
-    if (rename(binary_name_atomic, binary_name) != 0) {
-        printf("rename of .atomic to \"%s\" failed: %s\n",
-               binary_name, strerror(errno));
-        success = false;
-        goto out;
-    }
-
-    // If this run created a copy, and we're here, we can delete it.
-    if (made_copy) unlink(CACHE_TEMP_SOURCE);
-
-  out:
-    // clean up
-    free(file.data);
-    unlink(binary_name_atomic);
-
-    return success;
-}
diff --git a/minelf/Retouch.h b/minelf/Retouch.h
index 048d78e..13bacd5 100644
--- a/minelf/Retouch.h
+++ b/minelf/Retouch.h
@@ -25,12 +25,6 @@
   uint32_t blob_size; /* in bytes, located right before this struct */
 } retouch_info_t __attribute__((packed));
 
-// Retouch a file. Use CACHED_SOURCE_TEMP to store a copy.
-bool retouch_one_library(const char *binary_name,
-                         const char *binary_sha1,
-                         int32_t retouch_offset,
-                         int32_t *retouch_offset_override);
-
 #define RETOUCH_DONT_MASK           0
 #define RETOUCH_DO_MASK             1
 
diff --git a/minzip/Android.mk b/minzip/Android.mk
index b1ee674..6c1d096 100644
--- a/minzip/Android.mk
+++ b/minzip/Android.mk
@@ -11,7 +11,13 @@
 LOCAL_C_INCLUDES += \
 	external/zlib \
 	external/safe-iop/include
-	
+
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif
+
 LOCAL_MODULE := libminzip
 
 LOCAL_CFLAGS += -Wall
diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c
index 20c89cd..0d49b57 100644
--- a/minzip/DirUtil.c
+++ b/minzip/DirUtil.c
@@ -54,7 +54,8 @@
 
 int
 dirCreateHierarchy(const char *path, int mode,
-        const struct utimbuf *timestamp, bool stripFileName)
+        const struct utimbuf *timestamp, bool stripFileName,
+        struct selabel_handle *sehnd)
 {
     DirStatus ds;
 
@@ -144,7 +145,25 @@
         } else if (ds == DMISSING) {
             int err;
 
+#ifdef HAVE_SELINUX
+            char *secontext = NULL;
+
+            if (sehnd) {
+                selabel_lookup(sehnd, &secontext, cpath, mode);
+                setfscreatecon(secontext);
+            }
+#endif
+
             err = mkdir(cpath, mode);
+
+#ifdef HAVE_SELINUX
+
+            if (secontext) {
+                freecon(secontext);
+                setfscreatecon(NULL);
+            }
+#endif
+
             if (err != 0) {
                 free(cpath);
                 return -1;
diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h
index 0d5ea7c..f8be640 100644
--- a/minzip/DirUtil.h
+++ b/minzip/DirUtil.h
@@ -24,6 +24,13 @@
 extern "C" {
 #endif
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#else
+struct selabel_handle;
+#endif
+
 /* Like "mkdir -p", try to guarantee that all directories
  * specified in path are present, creating as many directories
  * as necessary.  The specified mode is passed to all mkdir
@@ -38,7 +45,8 @@
  * (usually if some element of path is not a directory).
  */
 int dirCreateHierarchy(const char *path, int mode,
-        const struct utimbuf *timestamp, bool stripFileName);
+        const struct utimbuf *timestamp, bool stripFileName,
+        struct selabel_handle* sehnd);
 
 /* rm -rf <path>
  */
diff --git a/minzip/Zip.c b/minzip/Zip.c
index 46d2f82..54d5d55 100644
--- a/minzip/Zip.c
+++ b/minzip/Zip.c
@@ -930,7 +930,8 @@
 bool mzExtractRecursive(const ZipArchive *pArchive,
                         const char *zipDir, const char *targetDir,
                         int flags, const struct utimbuf *timestamp,
-                        void (*callback)(const char *fn, void *), void *cookie)
+                        void (*callback)(const char *fn, void *), void *cookie,
+                        struct selabel_handle *sehnd)
 {
     if (zipDir[0] == '/') {
         LOGE("mzExtractRecursive(): zipDir must be a relative path.\n");
@@ -1045,7 +1046,7 @@
         if (pEntry->fileName[pEntry->fileNameLen-1] == '/') {
             if (!(flags & MZ_EXTRACT_FILES_ONLY)) {
                 int ret = dirCreateHierarchy(
-                        targetFile, UNZIP_DIRMODE, timestamp, false);
+                        targetFile, UNZIP_DIRMODE, timestamp, false, sehnd);
                 if (ret != 0) {
                     LOGE("Can't create containing directory for \"%s\": %s\n",
                             targetFile, strerror(errno));
@@ -1059,7 +1060,7 @@
              * the containing directory exists.
              */
             int ret = dirCreateHierarchy(
-                    targetFile, UNZIP_DIRMODE, timestamp, true);
+                    targetFile, UNZIP_DIRMODE, timestamp, true, sehnd);
             if (ret != 0) {
                 LOGE("Can't create containing directory for \"%s\": %s\n",
                         targetFile, strerror(errno));
@@ -1113,7 +1114,25 @@
                 /* The entry is a regular file.
                  * Open the target for writing.
                  */
+
+#ifdef HAVE_SELINUX
+                char *secontext = NULL;
+
+                if (sehnd) {
+                    selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
+                    setfscreatecon(secontext);
+                }
+#endif
+
                 int fd = creat(targetFile, UNZIP_FILEMODE);
+
+#ifdef HAVE_SELINUX
+                if (secontext) {
+                    freecon(secontext);
+                    setfscreatecon(NULL);
+                }
+#endif
+
                 if (fd < 0) {
                     LOGE("Can't create target file \"%s\": %s\n",
                             targetFile, strerror(errno));
diff --git a/minzip/Zip.h b/minzip/Zip.h
index 739dbf5..4bb9ef6 100644
--- a/minzip/Zip.h
+++ b/minzip/Zip.h
@@ -18,6 +18,13 @@
 extern "C" {
 #endif
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#else
+struct selabel_handle;
+#endif
+
 /*
  * One entry in the Zip archive.  Treat this as opaque -- use accessors below.
  *
@@ -212,7 +219,8 @@
 bool mzExtractRecursive(const ZipArchive *pArchive,
         const char *zipDir, const char *targetDir,
         int flags, const struct utimbuf *timestamp,
-        void (*callback)(const char *fn, void*), void *cookie);
+        void (*callback)(const char *fn, void*), void *cookie,
+        struct selabel_handle *sehnd);
 
 #ifdef __cplusplus
 }
diff --git a/mtdutils/flash_image.c b/mtdutils/flash_image.c
index c776876..a39d600 100644
--- a/mtdutils/flash_image.c
+++ b/mtdutils/flash_image.c
@@ -42,7 +42,7 @@
     }
 
     fprintf(stderr, "%s\n", buf);
-    LOGE("%s\n", buf);
+    ALOGE("%s\n", buf);
     exit(1);
 }
 
@@ -74,23 +74,23 @@
 
     MtdReadContext *in = mtd_read_partition(partition);
     if (in == NULL) {
-        LOGW("error opening %s: %s\n", argv[1], strerror(errno));
+        ALOGW("error opening %s: %s\n", argv[1], strerror(errno));
         // just assume it needs re-writing
     } else {
         char check[HEADER_SIZE];
         int checklen = mtd_read_data(in, check, sizeof(check));
         if (checklen <= 0) {
-            LOGW("error reading %s: %s\n", argv[1], strerror(errno));
+            ALOGW("error reading %s: %s\n", argv[1], strerror(errno));
             // just assume it needs re-writing
         } else if (checklen == headerlen && !memcmp(header, check, headerlen)) {
-            LOGI("header is the same, not flashing %s\n", argv[1]);
+            ALOGI("header is the same, not flashing %s\n", argv[1]);
             return 0;
         }
         mtd_read_close(in);
     }
 
     // Skip the header (we'll come back to it), write everything else
-    LOGI("flashing %s from %s\n", argv[1], argv[2]);
+    ALOGI("flashing %s from %s\n", argv[1], argv[2]);
 
     MtdWriteContext *out = mtd_write_partition(partition);
     if (out == NULL) die("error writing %s", argv[1]);
diff --git a/recovery.cpp b/recovery.cpp
index 2b5c65c..ce4358a 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -45,6 +45,8 @@
 #include "minadbd/adb.h"
 }
 
+struct selabel_handle *sehandle;
+
 static const struct option OPTIONS[] = {
   { "send_intent", required_argument, NULL, 's' },
   { "update_package", required_argument, NULL, 'u' },
@@ -140,7 +142,7 @@
 
     // When writing, try to create the containing directory, if necessary.
     // Use generous permissions, the system (init.rc) will reset them.
-    if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1);
+    if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1, sehandle);
 
     FILE *fp = fopen(path, mode);
     return fp;
@@ -684,6 +686,10 @@
                 break;
 
             case Device::APPLY_EXT:
+                // Some packages expect /cache to be mounted (eg,
+                // standard incremental packages expect to use /cache
+                // as scratch space).
+                ensure_path_mounted(CACHE_ROOT);
                 status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device);
                 if (status == INSTALL_SUCCESS && wipe_cache) {
                     ui->Print("\n-- Wiping cache (at package request)...\n");
@@ -803,6 +809,19 @@
         }
     }
 
+#ifdef HAVE_SELINUX
+    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");
+        ui->Print("Warning:  No file_contexts\n");
+    }
+#endif
+
     device->StartRecovery();
 
     printf("Command:");
diff --git a/roots.cpp b/roots.cpp
index 9345cb0..ca37cf1 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -31,6 +31,8 @@
 static int num_volumes = 0;
 static Volume* device_volumes = NULL;
 
+extern struct selabel_handle *sehandle;
+
 static int parse_options(char* options, Volume* volume) {
     char* option;
     while ((option = strtok(options, ","))) {
@@ -269,7 +271,7 @@
     }
 
     if (strcmp(v->fs_type, "ext4") == 0) {
-        int result = make_ext4fs(v->device, v->length);
+        int result = make_ext4fs(v->device, v->length, volume, sehandle);
         if (result != 0) {
             LOGE("format_volume: make_extf4fs failed on %s\n", v->device);
             return -1;
diff --git a/updater/Android.mk b/updater/Android.mk
index 8d731db..f8ccb76 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -24,6 +24,12 @@
 LOCAL_STATIC_LIBRARIES += libext4_utils libz
 endif
 
+ifeq ($(HAVE_SELINUX), true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
 LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
 LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
 LOCAL_STATIC_LIBRARIES += libmincrypt libbz
diff --git a/updater/install.c b/updater/install.c
index f68bd03..f981017 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -33,7 +33,6 @@
 #include "edify/expr.h"
 #include "mincrypt/sha.h"
 #include "minzip/DirUtil.h"
-#include "minelf/Retouch.h"
 #include "mtdutils/mounts.h"
 #include "mtdutils/mtdutils.h"
 #include "updater.h"
@@ -79,8 +78,24 @@
         goto done;
     }
 
+#ifdef HAVE_SELINUX
+    char *secontext = NULL;
+
+    if (sehandle) {
+        selabel_lookup(sehandle, &secontext, mount_point, 0755);
+        setfscreatecon(secontext);
+    }
+#endif
+
     mkdir(mount_point, 0755);
 
+#ifdef HAVE_SELINUX
+    if (secontext) {
+        freecon(secontext);
+        setfscreatecon(NULL);
+    }
+#endif
+
     if (strcmp(partition_type, "MTD") == 0) {
         mtd_scan_partitions();
         const MtdPartition* mtd;
@@ -177,23 +192,25 @@
 }
 
 
-// format(fs_type, partition_type, location, fs_size)
+// format(fs_type, partition_type, location, fs_size, mount_point)
 //
-//    fs_type="yaffs2" partition_type="MTD"     location=partition fs_size=<bytes>
-//    fs_type="ext4"   partition_type="EMMC"    location=device    fs_size=<bytes>
+//    fs_type="yaffs2" partition_type="MTD"     location=partition fs_size=<bytes> mount_point=<location>
+//    fs_type="ext4"   partition_type="EMMC"    location=device    fs_size=<bytes> mount_point=<location>
 //    if fs_size == 0, then make_ext4fs uses the entire partition.
 //    if fs_size > 0, that is the size to use
 //    if fs_size < 0, then reserve that many bytes at the end of the partition
 Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
-    if (argc != 4) {
-        return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
+    if (argc != 5) {
+        return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
     }
     char* fs_type;
     char* partition_type;
     char* location;
     char* fs_size;
-    if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &fs_size) < 0) {
+    char* mount_point;
+
+    if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) {
         return NULL;
     }
 
@@ -211,6 +228,11 @@
         goto done;
     }
 
+    if (strlen(mount_point) == 0) {
+        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
+        goto done;
+    }
+
     if (strcmp(partition_type, "MTD") == 0) {
         mtd_scan_partitions();
         const MtdPartition* mtd = mtd_find_partition_by_name(location);
@@ -240,7 +262,7 @@
         result = location;
 #ifdef USE_EXT4
     } else if (strcmp(fs_type, "ext4") == 0) {
-        int status = make_ext4fs(location, atoll(fs_size));
+        int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle);
         if (status != 0) {
             fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
                     name, status, location);
@@ -347,7 +369,7 @@
 
     bool success = mzExtractRecursive(za, zip_path, dest_path,
                                       MZ_EXTRACT_FILES_ONLY, &timestamp,
-                                      NULL, NULL);
+                                      NULL, NULL, sehandle);
     free(zip_path);
     free(dest_path);
     return StringValue(strdup(success ? "t" : ""));
@@ -435,121 +457,6 @@
 }
 
 
-// retouch_binaries(lib1, lib2, ...)
-Value* RetouchBinariesFn(const char* name, State* state,
-                         int argc, Expr* argv[]) {
-    UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
-
-    char **retouch_entries  = ReadVarArgs(state, argc, argv);
-    if (retouch_entries == NULL) {
-        return StringValue(strdup("t"));
-    }
-
-    // some randomness from the clock
-    int32_t override_base;
-    bool override_set = false;
-    int32_t random_base = time(NULL) % 1024;
-    // some more randomness from /dev/random
-    FILE *f_random = fopen("/dev/random", "rb");
-    uint16_t random_bits = 0;
-    if (f_random != NULL) {
-        fread(&random_bits, 2, 1, f_random);
-        random_bits = random_bits % 1024;
-        fclose(f_random);
-    }
-    random_base = (random_base + random_bits) % 1024;
-    fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base);
-    fprintf(ui->cmd_pipe, "ui_print\n");
-
-    // make sure we never randomize to zero; this let's us look at a file
-    // and know for sure whether it has been processed; important in the
-    // crash recovery process
-    if (random_base == 0) random_base = 1;
-    // make sure our randomization is page-aligned
-    random_base *= -0x1000;
-    override_base = random_base;
-
-    int i = 0;
-    bool success = true;
-    while (i < (argc - 1)) {
-        success = success && retouch_one_library(retouch_entries[i],
-                                                 retouch_entries[i+1],
-                                                 random_base,
-                                                 override_set ?
-                                                   NULL :
-                                                   &override_base);
-        if (!success)
-            ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]);
-
-        free(retouch_entries[i]);
-        free(retouch_entries[i+1]);
-        i += 2;
-
-        if (success && override_base != 0) {
-            random_base = override_base;
-            override_set = true;
-        }
-    }
-    if (i < argc) {
-        free(retouch_entries[i]);
-        success = false;
-    }
-    free(retouch_entries);
-
-    if (!success) {
-      Value* v = malloc(sizeof(Value));
-      v->type = VAL_STRING;
-      v->data = NULL;
-      v->size = -1;
-      return v;
-    }
-    return StringValue(strdup("t"));
-}
-
-
-// undo_retouch_binaries(lib1, lib2, ...)
-Value* UndoRetouchBinariesFn(const char* name, State* state,
-                             int argc, Expr* argv[]) {
-    UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
-
-    char **retouch_entries  = ReadVarArgs(state, argc, argv);
-    if (retouch_entries == NULL) {
-        return StringValue(strdup("t"));
-    }
-
-    int i = 0;
-    bool success = true;
-    int32_t override_base;
-    while (i < (argc-1)) {
-        success = success && retouch_one_library(retouch_entries[i],
-                                                 retouch_entries[i+1],
-                                                 0 /* undo => offset==0 */,
-                                                 NULL);
-        if (!success)
-            ErrorAbort(state, "Failed to unretouch '%s'.",
-                       retouch_entries[i]);
-
-        free(retouch_entries[i]);
-        free(retouch_entries[i+1]);
-        i += 2;
-    }
-    if (i < argc) {
-        free(retouch_entries[i]);
-        success = false;
-    }
-    free(retouch_entries);
-
-    if (!success) {
-      Value* v = malloc(sizeof(Value));
-      v->type = VAL_STRING;
-      v->data = NULL;
-      v->size = -1;
-      return v;
-    }
-    return StringValue(strdup("t"));
-}
-
-
 // symlink target src1 src2 ...
 //    unlinks any previously existing src1, src2, etc before creating symlinks.
 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
@@ -566,21 +473,27 @@
         return NULL;
     }
 
+    int bad = 0;
     int i;
     for (i = 0; i < argc-1; ++i) {
         if (unlink(srcs[i]) < 0) {
             if (errno != ENOENT) {
                 fprintf(stderr, "%s: failed to remove %s: %s\n",
                         name, srcs[i], strerror(errno));
+                ++bad;
             }
         }
         if (symlink(target, srcs[i]) < 0) {
             fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
                     name, srcs[i], target, strerror(errno));
+            ++bad;
         }
         free(srcs[i]);
     }
     free(srcs);
+    if (bad) {
+        return ErrorAbort(state, "%s: some symlinks failed", name);
+    }
     return StringValue(strdup(""));
 }
 
@@ -599,6 +512,7 @@
 
     char* end;
     int i;
+    int bad = 0;
 
     int uid = strtoul(args[0], &end, 0);
     if (*end != '\0' || args[0][0] == 0) {
@@ -640,10 +554,12 @@
             if (chown(args[i], uid, gid) < 0) {
                 fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n",
                         name, args[i], uid, gid, strerror(errno));
+                ++bad;
             }
             if (chmod(args[i], mode) < 0) {
                 fprintf(stderr, "%s: chmod of %s to %o failed: %s\n",
                         name, args[i], mode, strerror(errno));
+                ++bad;
             }
         }
     }
@@ -655,6 +571,10 @@
     }
     free(args);
 
+    if (bad) {
+        free(result);
+        return ErrorAbort(state, "%s: some changes failed", name);
+    }
     return StringValue(result);
 }
 
@@ -1190,8 +1110,6 @@
     RegisterFunction("delete_recursive", DeleteFn);
     RegisterFunction("package_extract_dir", PackageExtractDirFn);
     RegisterFunction("package_extract_file", PackageExtractFileFn);
-    RegisterFunction("retouch_binaries", RetouchBinariesFn);
-    RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);
     RegisterFunction("symlink", SymlinkFn);
     RegisterFunction("set_perm", SetPermFn);
     RegisterFunction("set_perm_recursive", SetPermFn);
diff --git a/updater/updater.c b/updater/updater.c
index aa626d2..5f15808 100644
--- a/updater/updater.c
+++ b/updater/updater.c
@@ -32,6 +32,8 @@
 // (Note it's "updateR-script", not the older "update-script".)
 #define SCRIPT_NAME "META-INF/com/google/android/updater-script"
 
+struct selabel_handle *sehandle;
+
 int main(int argc, char** argv) {
     // Various things log information to stdout or stderr more or less
     // at random.  The log file makes more sense if buffering is
@@ -103,6 +105,19 @@
         return 6;
     }
 
+#ifdef HAVE_SELINUX
+    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");
+        fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
+    }
+#endif
+
     // Evaluate the parsed script.
 
     UpdaterInfo updater_info;
diff --git a/updater/updater.h b/updater/updater.h
index bd60dc1..a00872c 100644
--- a/updater/updater.h
+++ b/updater/updater.h
@@ -20,10 +20,19 @@
 #include <stdio.h>
 #include "minzip/Zip.h"
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#else
+struct selabel_handle;
+#endif
+
 typedef struct {
     FILE* cmd_pipe;
     ZipArchive* package_zip;
     int version;
 } UpdaterInfo;
 
+extern struct selabel_handle *sehandle;
+
 #endif