Merge "Fix applypatch_check failure when applying update on angler"
diff --git a/Android.mk b/Android.mk
index e502d9e..2a3438f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -41,7 +41,6 @@
 LOCAL_SRC_FILES := \
     adb_install.cpp \
     asn1_decoder.cpp \
-    bootloader.cpp \
     device.cpp \
     fuse_sdcard_provider.cpp \
     install.cpp \
@@ -75,9 +74,11 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libbatterymonitor \
+    libbootloader_message \
     libext4_utils_static \
     libsparse_static \
-    libminzip \
+    libziparchive \
+    libotautil \
     libmounts \
     libz \
     libminadbd \
@@ -149,14 +150,16 @@
 LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
-include $(LOCAL_PATH)/minui/Android.mk \
-    $(LOCAL_PATH)/minzip/Android.mk \
+include \
+    $(LOCAL_PATH)/applypatch/Android.mk \
+    $(LOCAL_PATH)/bootloader_message/Android.mk \
+    $(LOCAL_PATH)/edify/Android.mk \
+    $(LOCAL_PATH)/minui/Android.mk \
     $(LOCAL_PATH)/minadbd/Android.mk \
+    $(LOCAL_PATH)/otafault/Android.mk \
+    $(LOCAL_PATH)/otautil/Android.mk \
     $(LOCAL_PATH)/tests/Android.mk \
     $(LOCAL_PATH)/tools/Android.mk \
-    $(LOCAL_PATH)/edify/Android.mk \
     $(LOCAL_PATH)/uncrypt/Android.mk \
-    $(LOCAL_PATH)/otafault/Android.mk \
     $(LOCAL_PATH)/updater/Android.mk \
     $(LOCAL_PATH)/update_verifier/Android.mk \
-    $(LOCAL_PATH)/applypatch/Android.mk
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 77e499e..9bbac44 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -80,7 +80,6 @@
     libbase \
     libedify \
     libotafault \
-    libminzip \
     libcrypto \
     libbz
 LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc
diff --git a/bootloader.h b/bootloader.h
index 1801705..9c84a1c 100644
--- a/bootloader.h
+++ b/bootloader.h
@@ -14,158 +14,5 @@
  * limitations under the License.
  */
 
-#ifndef _RECOVERY_BOOTLOADER_H
-#define _RECOVERY_BOOTLOADER_H
-
-#include <assert.h>
-
-/* Bootloader Message (2-KiB)
- *
- * This structure describes the content of a block in flash
- * that is used for recovery and the bootloader to talk to
- * each other.
- *
- * The command field is updated by linux when it wants to
- * reboot into recovery or to update radio or bootloader firmware.
- * It is also updated by the bootloader when firmware update
- * is complete (to boot into recovery for any final cleanup)
- *
- * The status field is written by the bootloader after the
- * completion of an "update-radio" or "update-hboot" command.
- *
- * The recovery field is only written by linux and used
- * for the system to send a message to recovery or the
- * other way around.
- *
- * The stage field is written by packages which restart themselves
- * multiple times, so that the UI can reflect which invocation of the
- * package it is.  If the value is of the format "#/#" (eg, "1/3"),
- * the UI will add a simple indicator of that status.
- *
- * We used to have slot_suffix field for A/B boot control metadata in
- * this struct, which gets unintentionally cleared by recovery or
- * uncrypt. Move it into struct bootloader_message_ab to avoid the
- * issue.
- */
-struct bootloader_message {
-    char command[32];
-    char status[32];
-    char recovery[768];
-
-    // The 'recovery' field used to be 1024 bytes.  It has only ever
-    // been used to store the recovery command line, so 768 bytes
-    // should be plenty.  We carve off the last 256 bytes to store the
-    // stage string (for multistage packages) and possible future
-    // expansion.
-    char stage[32];
-
-    // The 'reserved' field used to be 224 bytes when it was initially
-    // carved off from the 1024-byte recovery field. Bump it up to
-    // 1184-byte so that the entire bootloader_message struct rounds up
-    // to 2048-byte.
-    char reserved[1184];
-};
-
-/**
- * We must be cautious when changing the bootloader_message struct size,
- * because A/B-specific fields may end up with different offsets.
- */
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message) == 2048,
-              "struct bootloader_message size changes, which may break A/B devices");
-#endif
-
-/**
- * The A/B-specific bootloader message structure (4-KiB).
- *
- * We separate A/B boot control metadata from the regular bootloader
- * message struct and keep it here. Everything that's A/B-specific
- * stays after struct bootloader_message, which should be managed by
- * the A/B-bootloader or boot control HAL.
- *
- * The slot_suffix field is used for A/B implementations where the
- * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
- * commandline parameter. This is used by fs_mgr to mount /system and
- * other partitions with the slotselect flag set in fstab. A/B
- * implementations are free to use all 32 bytes and may store private
- * data past the first NUL-byte in this field. It is encouraged, but
- * not mandatory, to use 'struct bootloader_control' described below.
- */
-struct bootloader_message_ab {
-    struct bootloader_message message;
-    char slot_suffix[32];
-
-    // Round up the entire struct to 4096-byte.
-    char reserved[2016];
-};
-
-/**
- * Be cautious about the struct size change, in case we put anything post
- * bootloader_message_ab struct (b/29159185).
- */
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message_ab) == 4096,
-              "struct bootloader_message_ab size changes");
-#endif
-
-#define BOOT_CTRL_MAGIC   0x42414342 /* Bootloader Control AB */
-#define BOOT_CTRL_VERSION 1
-
-struct slot_metadata {
-    // Slot priority with 15 meaning highest priority, 1 lowest
-    // priority and 0 the slot is unbootable.
-    uint8_t priority : 4;
-    // Number of times left attempting to boot this slot.
-    uint8_t tries_remaining : 3;
-    // 1 if this slot has booted successfully, 0 otherwise.
-    uint8_t successful_boot : 1;
-    // 1 if this slot is corrupted from a dm-verity corruption, 0
-    // otherwise.
-    uint8_t verity_corrupted : 1;
-    // Reserved for further use.
-    uint8_t reserved : 7;
-} __attribute__((packed));
-
-/* Bootloader Control AB
- *
- * This struct can be used to manage A/B metadata. It is designed to
- * be put in the 'slot_suffix' field of the 'bootloader_message'
- * structure described above. It is encouraged to use the
- * 'bootloader_control' structure to store the A/B metadata, but not
- * mandatory.
- */
-struct bootloader_control {
-    // NUL terminated active slot suffix.
-    char slot_suffix[4];
-    // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
-    uint32_t magic;
-    // Version of struct being used (see BOOT_CTRL_VERSION).
-    uint8_t version;
-    // Number of slots being managed.
-    uint8_t nb_slot : 3;
-    // Number of times left attempting to boot recovery.
-    uint8_t recovery_tries_remaining : 3;
-    // Ensure 4-bytes alignment for slot_info field.
-    uint8_t reserved0[2];
-    // Per-slot information.  Up to 4 slots.
-    struct slot_metadata slot_info[4];
-    // Reserved for further use.
-    uint8_t reserved1[8];
-    // CRC32 of all 28 bytes preceding this field (little endian
-    // format).
-    uint32_t crc32_le;
-} __attribute__((packed));
-
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_control) ==
-              sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
-              "struct bootloader_control has wrong size");
-#endif
-
-/* Read and write the bootloader command from the "misc" partition.
- * These return zero on success.
- */
-int get_bootloader_message(struct bootloader_message *out);
-int set_bootloader_message(const struct bootloader_message *in);
-
-#endif
+// TODO: Remove this file once we remove all places that include this file.
+#include "bootloader_message/include/bootloader_message/bootloader_message.h"
diff --git a/bootloader_message/Android.mk b/bootloader_message/Android.mk
new file mode 100644
index 0000000..815ac67
--- /dev/null
+++ b/bootloader_message/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := bootloader_message.cpp
+LOCAL_MODULE := libbootloader_message
+LOCAL_STATIC_LIBRARIES := libbase libfs_mgr
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+include $(BUILD_STATIC_LIBRARY)
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
new file mode 100644
index 0000000..59c2b2e
--- /dev/null
+++ b/bootloader_message/bootloader_message.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <bootloader_message/bootloader_message.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <fs_mgr.h>
+
+static struct fstab* read_fstab(std::string* err) {
+  std::string ro_hardware = android::base::GetProperty("ro.hardware", "");
+  if (ro_hardware.empty()) {
+    *err = "failed to get ro.hardware";
+    return nullptr;
+  }
+  // The fstab path is always "/fstab.${ro.hardware}".
+  std::string fstab_path = "/fstab." + ro_hardware;
+  struct fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str());
+  if (fstab == nullptr) {
+    *err = "failed to read " + fstab_path;
+  }
+  return fstab;
+}
+
+static std::string get_misc_blk_device(std::string* err) {
+  struct fstab* fstab = read_fstab(err);
+  if (fstab == nullptr) {
+    return "";
+  }
+  fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+  if (record == nullptr) {
+    *err = "failed to find /misc partition";
+    return "";
+  }
+  return record->blk_device;
+}
+
+// In recovery mode, recovery can get started and try to access the misc
+// device before the kernel has actually created it.
+static bool wait_for_device(const std::string& blk_device, std::string* err) {
+  int tries = 0;
+  int ret;
+  err->clear();
+  do {
+    ++tries;
+    struct stat buf;
+    ret = stat(blk_device.c_str(), &buf);
+    if (ret == -1) {
+      *err += android::base::StringPrintf("failed to stat %s try %d: %s\n",
+                                          blk_device.c_str(), tries, strerror(errno));
+      sleep(1);
+    }
+  } while (ret && tries < 10);
+
+  if (ret) {
+    *err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str());
+  }
+  return ret == 0;
+}
+
+static bool read_misc_partition(void* p, size_t size, size_t offset, std::string* err) {
+  std::string misc_blk_device = get_misc_blk_device(err);
+  if (misc_blk_device.empty()) {
+    return false;
+  }
+  if (!wait_for_device(misc_blk_device, err)) {
+    return false;
+  }
+  android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
+  if (fd.get() == -1) {
+    *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
+    *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  if (!android::base::ReadFully(fd.get(), p, size)) {
+    *err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  return true;
+}
+
+static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) {
+  std::string misc_blk_device = get_misc_blk_device(err);
+  if (misc_blk_device.empty()) {
+    return false;
+  }
+  android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC));
+  if (fd.get() == -1) {
+    *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
+    *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  if (!android::base::WriteFully(fd.get(), p, size)) {
+    *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  // TODO: O_SYNC and fsync duplicates each other?
+  if (fsync(fd.get()) == -1) {
+    *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
+                                       strerror(errno));
+    return false;
+  }
+  return true;
+}
+
+bool read_bootloader_message(bootloader_message* boot, std::string* err) {
+  return read_misc_partition(boot, sizeof(*boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
+}
+
+bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
+  return write_misc_partition(&boot, sizeof(boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
+}
+
+bool clear_bootloader_message(std::string* err) {
+  bootloader_message boot = {};
+  return write_bootloader_message(boot, err);
+}
+
+bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
+  bootloader_message boot = {};
+  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
+  strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
+  for (const auto& s : options) {
+    strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
+    if (s.back() != '\n') {
+      strlcat(boot.recovery, "\n", sizeof(boot.recovery));
+    }
+  }
+  return write_bootloader_message(boot, err);
+}
+
+bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
+  package_data->resize(size);
+  return read_misc_partition(&(*package_data)[0], size, WIPE_PACKAGE_OFFSET_IN_MISC, err);
+}
+
+bool write_wipe_package(const std::string& package_data, std::string* err) {
+  return write_misc_partition(package_data.data(), package_data.size(),
+                              WIPE_PACKAGE_OFFSET_IN_MISC, err);
+}
+
+extern "C" bool write_bootloader_message(const char* options) {
+  std::string err;
+  return write_bootloader_message({options}, &err);
+}
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
new file mode 100644
index 0000000..07ecf85
--- /dev/null
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef _BOOTLOADER_MESSAGE_H
+#define _BOOTLOADER_MESSAGE_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+// Spaces used by misc partition are as below:
+// 0   - 2K     Bootloader Message
+// 2K  - 16K    Used by Vendor's bootloader (the 2K - 4K range may be optionally used
+//              as bootloader_message_ab struct)
+// 16K - 64K    Used by uncrypt and recovery to store wipe_package for A/B devices
+// Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
+// are not configurable without changing all of them.
+static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
+static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
+
+/* Bootloader Message (2-KiB)
+ *
+ * This structure describes the content of a block in flash
+ * that is used for recovery and the bootloader to talk to
+ * each other.
+ *
+ * The command field is updated by linux when it wants to
+ * reboot into recovery or to update radio or bootloader firmware.
+ * It is also updated by the bootloader when firmware update
+ * is complete (to boot into recovery for any final cleanup)
+ *
+ * The status field is written by the bootloader after the
+ * completion of an "update-radio" or "update-hboot" command.
+ *
+ * The recovery field is only written by linux and used
+ * for the system to send a message to recovery or the
+ * other way around.
+ *
+ * The stage field is written by packages which restart themselves
+ * multiple times, so that the UI can reflect which invocation of the
+ * package it is.  If the value is of the format "#/#" (eg, "1/3"),
+ * the UI will add a simple indicator of that status.
+ *
+ * We used to have slot_suffix field for A/B boot control metadata in
+ * this struct, which gets unintentionally cleared by recovery or
+ * uncrypt. Move it into struct bootloader_message_ab to avoid the
+ * issue.
+ */
+struct bootloader_message {
+    char command[32];
+    char status[32];
+    char recovery[768];
+
+    // The 'recovery' field used to be 1024 bytes.  It has only ever
+    // been used to store the recovery command line, so 768 bytes
+    // should be plenty.  We carve off the last 256 bytes to store the
+    // stage string (for multistage packages) and possible future
+    // expansion.
+    char stage[32];
+
+    // The 'reserved' field used to be 224 bytes when it was initially
+    // carved off from the 1024-byte recovery field. Bump it up to
+    // 1184-byte so that the entire bootloader_message struct rounds up
+    // to 2048-byte.
+    char reserved[1184];
+};
+
+/**
+ * We must be cautious when changing the bootloader_message struct size,
+ * because A/B-specific fields may end up with different offsets.
+ */
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct bootloader_message) == 2048,
+              "struct bootloader_message size changes, which may break A/B devices");
+#endif
+
+/**
+ * The A/B-specific bootloader message structure (4-KiB).
+ *
+ * We separate A/B boot control metadata from the regular bootloader
+ * message struct and keep it here. Everything that's A/B-specific
+ * stays after struct bootloader_message, which should be managed by
+ * the A/B-bootloader or boot control HAL.
+ *
+ * The slot_suffix field is used for A/B implementations where the
+ * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
+ * commandline parameter. This is used by fs_mgr to mount /system and
+ * other partitions with the slotselect flag set in fstab. A/B
+ * implementations are free to use all 32 bytes and may store private
+ * data past the first NUL-byte in this field. It is encouraged, but
+ * not mandatory, to use 'struct bootloader_control' described below.
+ */
+struct bootloader_message_ab {
+    struct bootloader_message message;
+    char slot_suffix[32];
+
+    // Round up the entire struct to 4096-byte.
+    char reserved[2016];
+};
+
+/**
+ * Be cautious about the struct size change, in case we put anything post
+ * bootloader_message_ab struct (b/29159185).
+ */
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct bootloader_message_ab) == 4096,
+              "struct bootloader_message_ab size changes");
+#endif
+
+#define BOOT_CTRL_MAGIC   0x42414342 /* Bootloader Control AB */
+#define BOOT_CTRL_VERSION 1
+
+struct slot_metadata {
+    // Slot priority with 15 meaning highest priority, 1 lowest
+    // priority and 0 the slot is unbootable.
+    uint8_t priority : 4;
+    // Number of times left attempting to boot this slot.
+    uint8_t tries_remaining : 3;
+    // 1 if this slot has booted successfully, 0 otherwise.
+    uint8_t successful_boot : 1;
+    // 1 if this slot is corrupted from a dm-verity corruption, 0
+    // otherwise.
+    uint8_t verity_corrupted : 1;
+    // Reserved for further use.
+    uint8_t reserved : 7;
+} __attribute__((packed));
+
+/* Bootloader Control AB
+ *
+ * This struct can be used to manage A/B metadata. It is designed to
+ * be put in the 'slot_suffix' field of the 'bootloader_message'
+ * structure described above. It is encouraged to use the
+ * 'bootloader_control' structure to store the A/B metadata, but not
+ * mandatory.
+ */
+struct bootloader_control {
+    // NUL terminated active slot suffix.
+    char slot_suffix[4];
+    // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
+    uint32_t magic;
+    // Version of struct being used (see BOOT_CTRL_VERSION).
+    uint8_t version;
+    // Number of slots being managed.
+    uint8_t nb_slot : 3;
+    // Number of times left attempting to boot recovery.
+    uint8_t recovery_tries_remaining : 3;
+    // Ensure 4-bytes alignment for slot_info field.
+    uint8_t reserved0[2];
+    // Per-slot information.  Up to 4 slots.
+    struct slot_metadata slot_info[4];
+    // Reserved for further use.
+    uint8_t reserved1[8];
+    // CRC32 of all 28 bytes preceding this field (little endian
+    // format).
+    uint32_t crc32_le;
+} __attribute__((packed));
+
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct bootloader_control) ==
+              sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
+              "struct bootloader_control has wrong size");
+#endif
+#ifdef __cplusplus
+
+#include <string>
+#include <vector>
+
+bool read_bootloader_message(bootloader_message* boot, std::string* err);
+bool write_bootloader_message(const bootloader_message& boot, std::string* err);
+bool write_bootloader_message(const std::vector<std::string>& options, std::string* err);
+bool clear_bootloader_message(std::string* err);
+
+bool read_wipe_package(std::string* package_data, size_t size, std::string* err);
+bool write_wipe_package(const std::string& package_data, std::string* err);
+
+#else
+
+#include <stdbool.h>
+
+// C Interface.
+bool write_bootloader_message(const char* options);
+
+#endif  // ifdef __cplusplus
+
+#endif  // _BOOTLOADER_MESSAGE_H
diff --git a/install.cpp b/install.cpp
index 72c922d..c987152 100644
--- a/install.cpp
+++ b/install.cpp
@@ -32,13 +32,13 @@
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <ziparchive/zip_archive.h>
 
 #include "common.h"
 #include "error_code.h"
 #include "install.h"
 #include "minui/minui.h"
-#include "minzip/SysUtil.h"
-#include "minzip/Zip.h"
+#include "otautil/SysUtil.h"
 #include "roots.h"
 #include "ui.h"
 #include "verifier.h"
@@ -72,15 +72,17 @@
 }
 
 // Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
-static void read_source_target_build(ZipArchive* zip, std::vector<std::string>& log_buffer) {
-    const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH);
-    if (meta_entry == nullptr) {
+static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::string>& log_buffer) {
+    ZipString metadata_path(METADATA_PATH);
+    ZipEntry meta_entry;
+    if (FindEntry(zip, metadata_path, &meta_entry) != 0) {
         LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package";
         return;
     }
 
-    std::string meta_data(meta_entry->uncompLen, '\0');
-    if (!mzReadZipEntry(zip, meta_entry, &meta_data[0], meta_entry->uncompLen)) {
+    std::string meta_data(meta_entry.uncompressed_length, '\0');
+    if (ExtractToMemory(zip, &meta_entry, reinterpret_cast<uint8_t*>(&meta_data[0]),
+                        meta_entry.uncompressed_length) != 0) {
         LOG(ERROR) << "Failed to read metadata in update package";
         return;
     }
@@ -109,15 +111,14 @@
 
 // If the package contains an update binary, extract it and run it.
 static int
-try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
+try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
                   std::vector<std::string>& log_buffer, int retry_count)
 {
     read_source_target_build(zip, log_buffer);
 
-    const ZipEntry* binary_entry =
-            mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
-    if (binary_entry == NULL) {
-        mzCloseZipArchive(zip);
+    ZipString binary_name(ASSUMED_UPDATE_BINARY_NAME);
+    ZipEntry binary_entry;
+    if (FindEntry(zip, binary_name, &binary_entry) != 0) {
         return INSTALL_CORRUPT;
     }
 
@@ -126,15 +127,14 @@
     int fd = creat(binary, 0755);
     if (fd < 0) {
         PLOG(ERROR) << "Can't make " << binary;
-        mzCloseZipArchive(zip);
         return INSTALL_ERROR;
     }
-    bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
+    int error = ExtractEntryToFile(zip, &binary_entry, fd);
     close(fd);
-    mzCloseZipArchive(zip);
 
-    if (!ok) {
-        LOG(ERROR) << "Can't copy " << ASSUMED_UPDATE_BINARY_NAME;
+    if (error != 0) {
+        LOG(ERROR) << "Can't copy " << ASSUMED_UPDATE_BINARY_NAME
+                   << " : " << ErrorCodeString(error);
         return INSTALL_ERROR;
     }
 
@@ -326,13 +326,14 @@
     }
 
     // Try to open the package.
-    ZipArchive zip;
-    err = mzOpenZipArchive(map.addr, map.length, &zip);
+    ZipArchiveHandle zip;
+    err = OpenArchiveFromMemory(map.addr, map.length, path, &zip);
     if (err != 0) {
-        LOG(ERROR) << "Can't open " << path;
+        LOG(ERROR) << "Can't open " << path << " : " << ErrorCodeString(err);
         log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
 
         sysReleaseMap(&map);
+        CloseArchive(zip);
         return INSTALL_CORRUPT;
     }
 
@@ -342,12 +343,12 @@
         ui->Print("Retry attempt: %d\n", retry_count);
     }
     ui->SetEnableReboot(false);
-    int result = try_update_binary(path, &zip, wipe_cache, log_buffer, retry_count);
+    int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count);
     ui->SetEnableReboot(true);
     ui->Print("\n");
 
     sysReleaseMap(&map);
-
+    CloseArchive(zip);
     return result;
 }
 
diff --git a/minzip/Android.mk b/minzip/Android.mk
deleted file mode 100644
index 6dbfee9..0000000
--- a/minzip/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	Hash.cpp \
-	SysUtil.cpp \
-	DirUtil.cpp \
-	Inlines.c \
-	Zip.cpp
-
-LOCAL_C_INCLUDES := \
-	external/zlib \
-	external/safe-iop/include
-
-LOCAL_STATIC_LIBRARIES := libselinux libbase
-
-LOCAL_MODULE := libminzip
-
-LOCAL_CLANG := true
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/minzip/Bits.h b/minzip/Bits.h
deleted file mode 100644
index f96e6c4..0000000
--- a/minzip/Bits.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Some handy functions for manipulating bits and bytes.
- */
-#ifndef _MINZIP_BITS
-#define _MINZIP_BITS
-
-#include "inline_magic.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-/*
- * Get 1 byte.  (Included to make the code more legible.)
- */
-INLINE unsigned char get1(unsigned const char* pSrc)
-{
-    return *pSrc;
-}
-
-/*
- * Get 2 big-endian bytes.
- */
-INLINE unsigned short get2BE(unsigned char const* pSrc)
-{
-    unsigned short result;
-
-    result = *pSrc++ << 8;
-    result |= *pSrc++;
-
-    return result;
-}
-
-/*
- * Get 4 big-endian bytes.
- */
-INLINE unsigned int get4BE(unsigned char const* pSrc)
-{
-    unsigned int result;
-
-    result = *pSrc++ << 24;
-    result |= *pSrc++ << 16;
-    result |= *pSrc++ << 8;
-    result |= *pSrc++;
-
-    return result;
-}
-
-/*
- * Get 8 big-endian bytes.
- */
-INLINE unsigned long long get8BE(unsigned char const* pSrc)
-{
-    unsigned long long result;
-
-    result = (unsigned long long) *pSrc++ << 56;
-    result |= (unsigned long long) *pSrc++ << 48;
-    result |= (unsigned long long) *pSrc++ << 40;
-    result |= (unsigned long long) *pSrc++ << 32;
-    result |= (unsigned long long) *pSrc++ << 24;
-    result |= (unsigned long long) *pSrc++ << 16;
-    result |= (unsigned long long) *pSrc++ << 8;
-    result |= (unsigned long long) *pSrc++;
-
-    return result;
-}
-
-/*
- * Get 2 little-endian bytes.
- */
-INLINE unsigned short get2LE(unsigned char const* pSrc)
-{
-    unsigned short result;
-
-    result = *pSrc++;
-    result |= *pSrc++ << 8;
-
-    return result;
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-INLINE unsigned int get4LE(unsigned char const* pSrc)
-{
-    unsigned int result;
-
-    result = *pSrc++;
-    result |= *pSrc++ << 8;
-    result |= *pSrc++ << 16;
-    result |= *pSrc++ << 24;
-
-    return result;
-}
-
-/*
- * Get 8 little-endian bytes.
- */
-INLINE unsigned long long get8LE(unsigned char const* pSrc)
-{
-    unsigned long long result;
-
-    result = (unsigned long long) *pSrc++;
-    result |= (unsigned long long) *pSrc++ << 8;
-    result |= (unsigned long long) *pSrc++ << 16;
-    result |= (unsigned long long) *pSrc++ << 24;
-    result |= (unsigned long long) *pSrc++ << 32;
-    result |= (unsigned long long) *pSrc++ << 40;
-    result |= (unsigned long long) *pSrc++ << 48;
-    result |= (unsigned long long) *pSrc++ << 56;
-
-    return result;
-}
-
-/*
- * Grab 1 byte and advance the data pointer.
- */
-INLINE unsigned char read1(unsigned const char** ppSrc)
-{
-    return *(*ppSrc)++;
-}
-
-/*
- * Grab 2 big-endian bytes and advance the data pointer.
- */
-INLINE unsigned short read2BE(unsigned char const** ppSrc)
-{
-    unsigned short result;
-
-    result = *(*ppSrc)++ << 8;
-    result |= *(*ppSrc)++;
-
-    return result;
-}
-
-/*
- * Grab 4 big-endian bytes and advance the data pointer.
- */
-INLINE unsigned int read4BE(unsigned char const** ppSrc)
-{
-    unsigned int result;
-
-    result = *(*ppSrc)++ << 24;
-    result |= *(*ppSrc)++ << 16;
-    result |= *(*ppSrc)++ << 8;
-    result |= *(*ppSrc)++;
-
-    return result;
-}
-
-/*
- * Get 8 big-endian bytes.
- */
-INLINE unsigned long long read8BE(unsigned char const** ppSrc)
-{
-    unsigned long long result;
-
-    result = (unsigned long long) *(*ppSrc)++ << 56;
-    result |= (unsigned long long) *(*ppSrc)++ << 48;
-    result |= (unsigned long long) *(*ppSrc)++ << 40;
-    result |= (unsigned long long) *(*ppSrc)++ << 32;
-    result |= (unsigned long long) *(*ppSrc)++ << 24;
-    result |= (unsigned long long) *(*ppSrc)++ << 16;
-    result |= (unsigned long long) *(*ppSrc)++ << 8;
-    result |= (unsigned long long) *(*ppSrc)++;
-
-    return result;
-}
-
-/*
- * Grab 2 little-endian bytes and advance the data pointer.
- */
-INLINE unsigned short read2LE(unsigned char const** ppSrc)
-{
-    unsigned short result;
-
-    result = *(*ppSrc)++;
-    result |= *(*ppSrc)++ << 8;
-
-    return result;
-}
-
-/*
- * Grab 4 little-endian bytes and advance the data pointer.
- */
-INLINE unsigned int read4LE(unsigned char const** ppSrc)
-{
-    unsigned int result;
-
-    result = *(*ppSrc)++;
-    result |= *(*ppSrc)++ << 8;
-    result |= *(*ppSrc)++ << 16;
-    result |= *(*ppSrc)++ << 24;
-
-    return result;
-}
-
-/*
- * Get 8 little-endian bytes.
- */
-INLINE unsigned long long read8LE(unsigned char const** ppSrc)
-{
-    unsigned long long result;
-
-    result = (unsigned long long) *(*ppSrc)++;
-    result |= (unsigned long long) *(*ppSrc)++ << 8;
-    result |= (unsigned long long) *(*ppSrc)++ << 16;
-    result |= (unsigned long long) *(*ppSrc)++ << 24;
-    result |= (unsigned long long) *(*ppSrc)++ << 32;
-    result |= (unsigned long long) *(*ppSrc)++ << 40;
-    result |= (unsigned long long) *(*ppSrc)++ << 48;
-    result |= (unsigned long long) *(*ppSrc)++ << 56;
-
-    return result;
-}
-
-/*
- * Skip over a UTF-8 string.
- */
-INLINE void skipUtf8String(unsigned char const** ppSrc)
-{
-    unsigned int length = read4BE(ppSrc);
-
-    (*ppSrc) += length;
-}
-
-/*
- * Read a UTF-8 string into a fixed-size buffer, and null-terminate it.
- *
- * Returns the length of the original string.
- */
-INLINE int readUtf8String(unsigned char const** ppSrc, char* buf, size_t bufLen)
-{
-    unsigned int length = read4BE(ppSrc);
-    size_t copyLen = (length < bufLen) ? length : bufLen-1;
-
-    memcpy(buf, *ppSrc, copyLen);
-    buf[copyLen] = '\0';
-
-    (*ppSrc) += length;
-    return length;
-}
-
-/*
- * Read a UTF-8 string into newly-allocated storage, and null-terminate it.
- *
- * Returns the string and its length.  (The latter is probably unnecessary
- * for the way we're using UTF8.)
- */
-INLINE char* readNewUtf8String(unsigned char const** ppSrc, size_t* pLength)
-{
-    unsigned int length = read4BE(ppSrc);
-    char* buf;
-
-    buf = (char*) malloc(length+1);
-
-    memcpy(buf, *ppSrc, length);
-    buf[length] = '\0';
-
-    (*ppSrc) += length;
-
-    *pLength = length;
-    return buf;
-}
-
-
-/*
- * Set 1 byte.  (Included to make the code more legible.)
- */
-INLINE void set1(unsigned char* buf, unsigned char val)
-{
-    *buf = (unsigned char)(val);
-}
-
-/*
- * Set 2 big-endian bytes.
- */
-INLINE void set2BE(unsigned char* buf, unsigned short val)
-{
-    *buf++ = (unsigned char)(val >> 8);
-    *buf = (unsigned char)(val);
-}
-
-/*
- * Set 4 big-endian bytes.
- */
-INLINE void set4BE(unsigned char* buf, unsigned int val)
-{
-    *buf++ = (unsigned char)(val >> 24);
-    *buf++ = (unsigned char)(val >> 16);
-    *buf++ = (unsigned char)(val >> 8);
-    *buf = (unsigned char)(val);
-}
-
-/*
- * Set 8 big-endian bytes.
- */
-INLINE void set8BE(unsigned char* buf, unsigned long long val)
-{
-    *buf++ = (unsigned char)(val >> 56);
-    *buf++ = (unsigned char)(val >> 48);
-    *buf++ = (unsigned char)(val >> 40);
-    *buf++ = (unsigned char)(val >> 32);
-    *buf++ = (unsigned char)(val >> 24);
-    *buf++ = (unsigned char)(val >> 16);
-    *buf++ = (unsigned char)(val >> 8);
-    *buf = (unsigned char)(val);
-}
-
-/*
- * Set 2 little-endian bytes.
- */
-INLINE void set2LE(unsigned char* buf, unsigned short val)
-{
-    *buf++ = (unsigned char)(val);
-    *buf = (unsigned char)(val >> 8);
-}
-
-/*
- * Set 4 little-endian bytes.
- */
-INLINE void set4LE(unsigned char* buf, unsigned int val)
-{
-    *buf++ = (unsigned char)(val);
-    *buf++ = (unsigned char)(val >> 8);
-    *buf++ = (unsigned char)(val >> 16);
-    *buf = (unsigned char)(val >> 24);
-}
-
-/*
- * Set 8 little-endian bytes.
- */
-INLINE void set8LE(unsigned char* buf, unsigned long long val)
-{
-    *buf++ = (unsigned char)(val);
-    *buf++ = (unsigned char)(val >> 8);
-    *buf++ = (unsigned char)(val >> 16);
-    *buf++ = (unsigned char)(val >> 24);
-    *buf++ = (unsigned char)(val >> 32);
-    *buf++ = (unsigned char)(val >> 40);
-    *buf++ = (unsigned char)(val >> 48);
-    *buf = (unsigned char)(val >> 56);
-}
-
-/*
- * Stuff a UTF-8 string into the buffer.
- */
-INLINE void setUtf8String(unsigned char* buf, const unsigned char* str)
-{
-    unsigned int strLen = strlen((const char*)str);
-
-    set4BE(buf, strLen);
-    memcpy(buf + sizeof(unsigned int), str, strLen);
-}
-
-#endif /*_MINZIP_BITS*/
diff --git a/minzip/Hash.cpp b/minzip/Hash.cpp
deleted file mode 100644
index ac08935..0000000
--- a/minzip/Hash.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Hash table.  The dominant calls are add and lookup, with removals
- * happening very infrequently.  We use probing, and don't worry much
- * about tombstone removal.
- */
-#include <stdlib.h>
-#include <assert.h>
-
-#include <android-base/logging.h>
-
-#include "Hash.h"
-
-/* table load factor, i.e. how full can it get before we resize */
-//#define LOAD_NUMER  3       // 75%
-//#define LOAD_DENOM  4
-#define LOAD_NUMER  5       // 62.5%
-#define LOAD_DENOM  8
-//#define LOAD_NUMER  1       // 50%
-//#define LOAD_DENOM  2
-
-/*
- * Compute the capacity needed for a table to hold "size" elements.
- */
-size_t mzHashSize(size_t size) {
-    return (size * LOAD_DENOM) / LOAD_NUMER +1;
-}
-
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-unsigned int roundUpPower2(unsigned int val)
-{
-    val--;
-    val |= val >> 1;
-    val |= val >> 2;
-    val |= val >> 4;
-    val |= val >> 8;
-    val |= val >> 16;
-    val++;
-
-    return val;
-}
-
-/*
- * Create and initialize a hash table.
- */
-HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc)
-{
-    HashTable* pHashTable;
-
-    assert(initialSize > 0);
-
-    pHashTable = (HashTable*) malloc(sizeof(*pHashTable));
-    if (pHashTable == NULL)
-        return NULL;
-
-    pHashTable->tableSize = roundUpPower2(initialSize);
-    pHashTable->numEntries = pHashTable->numDeadEntries = 0;
-    pHashTable->freeFunc = freeFunc;
-    pHashTable->pEntries =
-        (HashEntry*) calloc((size_t)pHashTable->tableSize, sizeof(HashTable));
-    if (pHashTable->pEntries == NULL) {
-        free(pHashTable);
-        return NULL;
-    }
-
-    return pHashTable;
-}
-
-/*
- * Clear out all entries.
- */
-void mzHashTableClear(HashTable* pHashTable)
-{
-    HashEntry* pEnt;
-    int i;
-
-    pEnt = pHashTable->pEntries;
-    for (i = 0; i < pHashTable->tableSize; i++, pEnt++) {
-        if (pEnt->data == HASH_TOMBSTONE) {
-            // nuke entry
-            pEnt->data = NULL;
-        } else if (pEnt->data != NULL) {
-            // call free func then nuke entry
-            if (pHashTable->freeFunc != NULL)
-                (*pHashTable->freeFunc)(pEnt->data);
-            pEnt->data = NULL;
-        }
-    }
-
-    pHashTable->numEntries = 0;
-    pHashTable->numDeadEntries = 0;
-}
-
-/*
- * Free the table.
- */
-void mzHashTableFree(HashTable* pHashTable)
-{
-    if (pHashTable == NULL)
-        return;
-    mzHashTableClear(pHashTable);
-    free(pHashTable->pEntries);
-    free(pHashTable);
-}
-
-#ifndef NDEBUG
-/*
- * Count up the number of tombstone entries in the hash table.
- */
-static int countTombStones(HashTable* pHashTable)
-{
-    int i, count;
-
-    for (count = i = 0; i < pHashTable->tableSize; i++) {
-        if (pHashTable->pEntries[i].data == HASH_TOMBSTONE)
-            count++;
-    }
-    return count;
-}
-#endif
-
-/*
- * Resize a hash table.  We do this when adding an entry increased the
- * size of the table beyond its comfy limit.
- *
- * This essentially requires re-inserting all elements into the new storage.
- *
- * If multiple threads can access the hash table, the table's lock should
- * have been grabbed before issuing the "lookup+add" call that led to the
- * resize, so we don't have a synchronization problem here.
- */
-static bool resizeHash(HashTable* pHashTable, int newSize)
-{
-    HashEntry* pNewEntries;
-    int i;
-
-    assert(countTombStones(pHashTable) == pHashTable->numDeadEntries);
-
-    pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashTable));
-    if (pNewEntries == NULL)
-        return false;
-
-    for (i = 0; i < pHashTable->tableSize; i++) {
-        void* data = pHashTable->pEntries[i].data;
-        if (data != NULL && data != HASH_TOMBSTONE) {
-            int hashValue = pHashTable->pEntries[i].hashValue;
-            int newIdx;
-
-            /* probe for new spot, wrapping around */
-            newIdx = hashValue & (newSize-1);
-            while (pNewEntries[newIdx].data != NULL)
-                newIdx = (newIdx + 1) & (newSize-1);
-
-            pNewEntries[newIdx].hashValue = hashValue;
-            pNewEntries[newIdx].data = data;
-        }
-    }
-
-    free(pHashTable->pEntries);
-    pHashTable->pEntries = pNewEntries;
-    pHashTable->tableSize = newSize;
-    pHashTable->numDeadEntries = 0;
-
-    assert(countTombStones(pHashTable) == 0);
-    return true;
-}
-
-/*
- * Look up an entry.
- *
- * We probe on collisions, wrapping around the table.
- */
-void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
-    HashCompareFunc cmpFunc, bool doAdd)
-{
-    HashEntry* pEntry;
-    HashEntry* pEnd;
-    void* result = NULL;
-
-    assert(pHashTable->tableSize > 0);
-    assert(item != HASH_TOMBSTONE);
-    assert(item != NULL);
-
-    /* jump to the first entry and probe for a match */
-    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
-    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
-    while (pEntry->data != NULL) {
-        if (pEntry->data != HASH_TOMBSTONE &&
-            pEntry->hashValue == itemHash &&
-            (*cmpFunc)(pEntry->data, item) == 0)
-        {
-            /* match */
-            break;
-        }
-
-        pEntry++;
-        if (pEntry == pEnd) {     /* wrap around to start */
-            if (pHashTable->tableSize == 1)
-                break;      /* edge case - single-entry table */
-            pEntry = pHashTable->pEntries;
-        }
-    }
-
-    if (pEntry->data == NULL) {
-        if (doAdd) {
-            pEntry->hashValue = itemHash;
-            pEntry->data = item;
-            pHashTable->numEntries++;
-
-            /*
-             * We've added an entry.  See if this brings us too close to full.
-             */
-            if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM
-                > pHashTable->tableSize * LOAD_NUMER)
-            {
-                if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) {
-                    /* don't really have a way to indicate failure */
-                    LOG(FATAL) << "Hash resize failure";
-                }
-                /* note "pEntry" is now invalid */
-            }
-
-            /* full table is bad -- search for nonexistent never halts */
-            assert(pHashTable->numEntries < pHashTable->tableSize);
-            result = item;
-        } else {
-            assert(result == NULL);
-        }
-    } else {
-        result = pEntry->data;
-    }
-
-    return result;
-}
-
-/*
- * Remove an entry from the table.
- *
- * Does NOT invoke the "free" function on the item.
- */
-bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item)
-{
-    HashEntry* pEntry;
-    HashEntry* pEnd;
-
-    assert(pHashTable->tableSize > 0);
-
-    /* jump to the first entry and probe for a match */
-    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
-    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
-    while (pEntry->data != NULL) {
-        if (pEntry->data == item) {
-            pEntry->data = HASH_TOMBSTONE;
-            pHashTable->numEntries--;
-            pHashTable->numDeadEntries++;
-            return true;
-        }
-
-        pEntry++;
-        if (pEntry == pEnd) {     /* wrap around to start */
-            if (pHashTable->tableSize == 1)
-                break;      /* edge case - single-entry table */
-            pEntry = pHashTable->pEntries;
-        }
-    }
-
-    return false;
-}
-
-/*
- * Execute a function on every entry in the hash table.
- *
- * If "func" returns a nonzero value, terminate early and return the value.
- */
-int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg)
-{
-    int i, val;
-
-    for (i = 0; i < pHashTable->tableSize; i++) {
-        HashEntry* pEnt = &pHashTable->pEntries[i];
-
-        if (pEnt->data != NULL && pEnt->data != HASH_TOMBSTONE) {
-            val = (*func)(pEnt->data, arg);
-            if (val != 0)
-                return val;
-        }
-    }
-
-    return 0;
-}
-
-
-/*
- * Look up an entry, counting the number of times we have to probe.
- *
- * Returns -1 if the entry wasn't found.
- */
-int countProbes(HashTable* pHashTable, unsigned int itemHash, const void* item,
-    HashCompareFunc cmpFunc)
-{
-    HashEntry* pEntry;
-    HashEntry* pEnd;
-    int count = 0;
-
-    assert(pHashTable->tableSize > 0);
-    assert(item != HASH_TOMBSTONE);
-    assert(item != NULL);
-
-    /* jump to the first entry and probe for a match */
-    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
-    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
-    while (pEntry->data != NULL) {
-        if (pEntry->data != HASH_TOMBSTONE &&
-            pEntry->hashValue == itemHash &&
-            (*cmpFunc)(pEntry->data, item) == 0)
-        {
-            /* match */
-            break;
-        }
-
-        pEntry++;
-        if (pEntry == pEnd) {     /* wrap around to start */
-            if (pHashTable->tableSize == 1)
-                break;      /* edge case - single-entry table */
-            pEntry = pHashTable->pEntries;
-        }
-
-        count++;
-    }
-    if (pEntry->data == NULL)
-        return -1;
-
-    return count;
-}
-
-/*
- * Evaluate the amount of probing required for the specified hash table.
- *
- * We do this by running through all entries in the hash table, computing
- * the hash value and then doing a lookup.
- *
- * The caller should lock the table before calling here.
- */
-void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
-    HashCompareFunc cmpFunc)
-{
-    int numEntries, minProbe, maxProbe, totalProbe;
-    HashIter iter;
-
-    numEntries = maxProbe = totalProbe = 0;
-    minProbe = 65536*32767;
-
-    for (mzHashIterBegin(pHashTable, &iter); !mzHashIterDone(&iter);
-        mzHashIterNext(&iter))
-    {
-        const void* data = (const void*)mzHashIterData(&iter);
-        int count;
-
-        count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
-
-        numEntries++;
-
-        if (count < minProbe)
-            minProbe = count;
-        if (count > maxProbe)
-            maxProbe = count;
-        totalProbe += count;
-    }
-
-    LOG(VERBOSE) << "Probe: min=" << minProbe << ", max=" << maxProbe << ", total="
-                 << totalProbe <<" in " << numEntries << " (" << pHashTable->tableSize
-                 << "), avg=" << (float) totalProbe / (float) numEntries;
-}
diff --git a/minzip/Hash.h b/minzip/Hash.h
deleted file mode 100644
index e83eac4..0000000
--- a/minzip/Hash.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * General purpose hash table, used for finding classes, methods, etc.
- *
- * When the number of elements reaches 3/4 of the table's capacity, the
- * table will be resized.
- */
-#ifndef _MINZIP_HASH
-#define _MINZIP_HASH
-
-#include "inline_magic.h"
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* compute the hash of an item with a specific type */
-typedef unsigned int (*HashCompute)(const void* item);
-
-/*
- * Compare a hash entry with a "loose" item after their hash values match.
- * Returns { <0, 0, >0 } depending on ordering of items (same semantics
- * as strcmp()).
- */
-typedef int (*HashCompareFunc)(const void* tableItem, const void* looseItem);
-
-/*
- * This function will be used to free entries in the table.  This can be
- * NULL if no free is required, free(), or a custom function.
- */
-typedef void (*HashFreeFunc)(void* ptr);
-
-/*
- * Used by mzHashForeach().
- */
-typedef int (*HashForeachFunc)(void* data, void* arg);
-
-/*
- * One entry in the hash table.  "data" values are expected to be (or have
- * the same characteristics as) valid pointers.  In particular, a NULL
- * value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates
- * a no-longer-used slot that must be stepped over during probing.
- *
- * Attempting to add a NULL or tombstone value is an error.
- *
- * When an entry is released, we will call (HashFreeFunc)(entry->data).
- */
-typedef struct HashEntry {
-    unsigned int hashValue;
-    void* data;
-} HashEntry;
-
-#define HASH_TOMBSTONE ((void*) 0xcbcacccd)     // invalid ptr value
-
-/*
- * Expandable hash table.
- *
- * This structure should be considered opaque.
- */
-typedef struct HashTable {
-    int         tableSize;          /* must be power of 2 */
-    int         numEntries;         /* current #of "live" entries */
-    int         numDeadEntries;     /* current #of tombstone entries */
-    HashEntry*  pEntries;           /* array on heap */
-    HashFreeFunc freeFunc;
-} HashTable;
-
-/*
- * Create and initialize a HashTable structure, using "initialSize" as
- * a basis for the initial capacity of the table.  (The actual initial
- * table size may be adjusted upward.)  If you know exactly how many
- * elements the table will hold, pass the result from mzHashSize() in.)
- *
- * Returns "false" if unable to allocate the table.
- */
-HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc);
-
-/*
- * Compute the capacity needed for a table to hold "size" elements.  Use
- * this when you know ahead of time how many elements the table will hold.
- * Pass this value into mzHashTableCreate() to ensure that you can add
- * all elements without needing to reallocate the table.
- */
-size_t mzHashSize(size_t size);
-
-/*
- * Clear out a hash table, freeing the contents of any used entries.
- */
-void mzHashTableClear(HashTable* pHashTable);
-
-/*
- * Free a hash table.
- */
-void mzHashTableFree(HashTable* pHashTable);
-
-/*
- * Get #of entries in hash table.
- */
-INLINE int mzHashTableNumEntries(HashTable* pHashTable) {
-    return pHashTable->numEntries;
-}
-
-/*
- * Get total size of hash table (for memory usage calculations).
- */
-INLINE int mzHashTableMemUsage(HashTable* pHashTable) {
-    return sizeof(HashTable) + pHashTable->tableSize * sizeof(HashEntry);
-}
-
-/*
- * Look up an entry in the table, possibly adding it if it's not there.
- *
- * If "item" is not found, and "doAdd" is false, NULL is returned.
- * Otherwise, a pointer to the found or added item is returned.  (You can
- * tell the difference by seeing if return value == item.)
- *
- * An "add" operation may cause the entire table to be reallocated.
- */
-void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
-    HashCompareFunc cmpFunc, bool doAdd);
-
-/*
- * Remove an item from the hash table, given its "data" pointer.  Does not
- * invoke the "free" function; just detaches it from the table.
- */
-bool mzHashTableRemove(HashTable* pHashTable, unsigned int hash, void* item);
-
-/*
- * Execute "func" on every entry in the hash table.
- *
- * If "func" returns a nonzero value, terminate early and return the value.
- */
-int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg);
-
-/*
- * An alternative to mzHashForeach(), using an iterator.
- *
- * Use like this:
- *   HashIter iter;
- *   for (mzHashIterBegin(hashTable, &iter); !mzHashIterDone(&iter);
- *       mzHashIterNext(&iter))
- *   {
- *       MyData* data = (MyData*)mzHashIterData(&iter);
- *   }
- */
-typedef struct HashIter {
-    void*       data;
-    HashTable*  pHashTable;
-    int         idx;
-} HashIter;
-INLINE void mzHashIterNext(HashIter* pIter) {
-    int i = pIter->idx +1;
-    int lim = pIter->pHashTable->tableSize;
-    for ( ; i < lim; i++) {
-        void* data = pIter->pHashTable->pEntries[i].data;
-        if (data != NULL && data != HASH_TOMBSTONE)
-            break;
-    }
-    pIter->idx = i;
-}
-INLINE void mzHashIterBegin(HashTable* pHashTable, HashIter* pIter) {
-    pIter->pHashTable = pHashTable;
-    pIter->idx = -1;
-    mzHashIterNext(pIter);
-}
-INLINE bool mzHashIterDone(HashIter* pIter) {
-    return (pIter->idx >= pIter->pHashTable->tableSize);
-}
-INLINE void* mzHashIterData(HashIter* pIter) {
-    assert(pIter->idx >= 0 && pIter->idx < pIter->pHashTable->tableSize);
-    return pIter->pHashTable->pEntries[pIter->idx].data;
-}
-
-
-/*
- * Evaluate hash table performance by examining the number of times we
- * have to probe for an entry.
- *
- * The caller should lock the table beforehand.
- */
-typedef unsigned int (*HashCalcFunc)(const void* item);
-void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
-    HashCompareFunc cmpFunc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*_MINZIP_HASH*/
diff --git a/minzip/Inlines.c b/minzip/Inlines.c
deleted file mode 100644
index 91f8775..0000000
--- a/minzip/Inlines.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-/* Make sure that non-inlined versions of INLINED-marked functions
- * exist so that debug builds (which don't generally do inlining)
- * don't break.
- */
-#define MINZIP_GENERATE_INLINES 1
-#include "Bits.h"
-#include "Hash.h"
-#include "SysUtil.h"
-#include "Zip.h"
diff --git a/minzip/Zip.cpp b/minzip/Zip.cpp
deleted file mode 100644
index b887b84..0000000
--- a/minzip/Zip.cpp
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Simple Zip file support.
- */
-#include "safe_iop.h"
-#include "zlib.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdint.h>     // for uintptr_t
-#include <stdlib.h>
-#include <sys/stat.h>   // for S_ISLNK()
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <assert.h>
-#include <selinux/label.h>
-#include <selinux/selinux.h>
-
-#include "Zip.h"
-#include "Bits.h"
-#include "DirUtil.h"
-
-#define SORT_ENTRIES 1
-
-/*
- * Offset and length constants (java.util.zip naming convention).
- */
-enum {
-    CENSIG = 0x02014b50,      // PK12
-    CENHDR = 46,
-
-    CENVEM =  4,
-    CENVER =  6,
-    CENFLG =  8,
-    CENHOW = 10,
-    CENTIM = 12,
-    CENCRC = 16,
-    CENSIZ = 20,
-    CENLEN = 24,
-    CENNAM = 28,
-    CENEXT = 30,
-    CENCOM = 32,
-    CENDSK = 34,
-    CENATT = 36,
-    CENATX = 38,
-    CENOFF = 42,
-
-    ENDSIG = 0x06054b50,     // PK56
-    ENDHDR = 22,
-
-    ENDSUB =  8,
-    ENDTOT = 10,
-    ENDSIZ = 12,
-    ENDOFF = 16,
-    ENDCOM = 20,
-
-    EXTSIG = 0x08074b50,     // PK78
-    EXTHDR = 16,
-
-    EXTCRC =  4,
-    EXTSIZ =  8,
-    EXTLEN = 12,
-
-    LOCSIG = 0x04034b50,      // PK34
-    LOCHDR = 30,
-
-    LOCVER =  4,
-    LOCFLG =  6,
-    LOCHOW =  8,
-    LOCTIM = 10,
-    LOCCRC = 14,
-    LOCSIZ = 18,
-    LOCLEN = 22,
-    LOCNAM = 26,
-    LOCEXT = 28,
-
-    STORED = 0,
-    DEFLATED = 8,
-
-    CENVEM_UNIX = 3 << 8,   // the high byte of CENVEM
-};
-
-
-/*
- * For debugging, dump the contents of a ZipEntry.
- */
-#if 0
-static void dumpEntry(const ZipEntry* pEntry)
-{
-    LOGI(" %p '%.*s'\n", pEntry->fileName,pEntry->fileNameLen,pEntry->fileName);
-    LOGI("   off=%u comp=%u uncomp=%u how=%d\n", pEntry->offset,
-        pEntry->compLen, pEntry->uncompLen, pEntry->compression);
-}
-#endif
-
-/*
- * (This is a mzHashTableLookup callback.)
- *
- * Compare two ZipEntry structs, by name.
- */
-static int hashcmpZipEntry(const void* ventry1, const void* ventry2)
-{
-    const ZipEntry* entry1 = (const ZipEntry*) ventry1;
-    const ZipEntry* entry2 = (const ZipEntry*) ventry2;
-
-    if (entry1->fileNameLen != entry2->fileNameLen)
-        return entry1->fileNameLen - entry2->fileNameLen;
-    return memcmp(entry1->fileName, entry2->fileName, entry1->fileNameLen);
-}
-
-/*
- * (This is a mzHashTableLookup callback.)
- *
- * find a ZipEntry struct by name.
- */
-static int hashcmpZipName(const void* ventry, const void* vname)
-{
-    const ZipEntry* entry = (const ZipEntry*) ventry;
-    const char* name = (const char*) vname;
-    unsigned int nameLen = strlen(name);
-
-    if (entry->fileNameLen != nameLen)
-        return entry->fileNameLen - nameLen;
-    return memcmp(entry->fileName, name, nameLen);
-}
-
-/*
- * Compute the hash code for a ZipEntry filename.
- *
- * Not expected to be compatible with any other hash function, so we init
- * to 2 to ensure it doesn't happen to match.
- */
-static unsigned int computeHash(const char* name, int nameLen)
-{
-    unsigned int hash = 2;
-
-    while (nameLen--)
-        hash = hash * 31 + *name++;
-
-    return hash;
-}
-
-static void addEntryToHashTable(HashTable* pHash, ZipEntry* pEntry)
-{
-    unsigned int itemHash = computeHash(pEntry->fileName, pEntry->fileNameLen);
-    const ZipEntry* found;
-
-    found = (const ZipEntry*)mzHashTableLookup(pHash,
-                itemHash, pEntry, hashcmpZipEntry, true);
-    if (found != pEntry) {
-        LOG(WARNING) << "WARNING: duplicate entry '" << std::string(found->fileName,
-                     found->fileNameLen) << "' in Zip";
-
-        /* keep going */
-    }
-}
-
-static int validFilename(const char *fileName, unsigned int fileNameLen)
-{
-    // Forbid super long filenames.
-    if (fileNameLen >= PATH_MAX) {
-        LOG(WARNING) << "Filename too long (" << fileNameLen << " chatacters)";
-        return 0;
-    }
-
-    // Require all characters to be printable ASCII (no NUL, no UTF-8, etc).
-    unsigned int i;
-    for (i = 0; i < fileNameLen; ++i) {
-        if (fileName[i] < 32 || fileName[i] >= 127) {
-            LOG(WARNING) << android::base::StringPrintf(
-                    "Filename contains invalid character '\%02x'\n", fileName[i]);
-            return 0;
-        }
-    }
-
-    return 1;
-}
-
-/*
- * Parse the contents of a Zip archive.  After confirming that the file
- * is in fact a Zip, we scan out the contents of the central directory and
- * store it in a hash table.
- *
- * Returns "true" on success.
- */
-static bool parseZipArchive(ZipArchive* pArchive)
-{
-    bool result = false;
-    const unsigned char* ptr;
-    unsigned int i, numEntries, cdOffset;
-    unsigned int val;
-
-    /*
-     * The first 4 bytes of the file will either be the local header
-     * signature for the first file (LOCSIG) or, if the archive doesn't
-     * have any files in it, the end-of-central-directory signature (ENDSIG).
-     */
-    val = get4LE(pArchive->addr);
-    if (val == ENDSIG) {
-        LOG(WARNING) << "Found Zip archive, but it looks empty";
-        goto bail;
-    } else if (val != LOCSIG) {
-        LOG(WARNING) << android::base::StringPrintf("Not a Zip archive (found 0x%08x)\n", val);
-        goto bail;
-    }
-
-    /*
-     * Find the EOCD.  We'll find it immediately unless they have a file
-     * comment.
-     */
-    ptr = pArchive->addr + pArchive->length - ENDHDR;
-
-    while (ptr >= (const unsigned char*) pArchive->addr) {
-        if (*ptr == (ENDSIG & 0xff) && get4LE(ptr) == ENDSIG)
-            break;
-        ptr--;
-    }
-    if (ptr < (const unsigned char*) pArchive->addr) {
-        LOG(WARNING) << "Could not find end-of-central-directory in Zip";
-        goto bail;
-    }
-
-    /*
-     * There are two interesting items in the EOCD block: the number of
-     * entries in the file, and the file offset of the start of the
-     * central directory.
-     */
-    numEntries = get2LE(ptr + ENDSUB);
-    cdOffset = get4LE(ptr + ENDOFF);
-
-    LOG(VERBOSE) << "numEntries=" << numEntries << " cdOffset=" << cdOffset;
-    if (numEntries == 0 || cdOffset >= pArchive->length) {
-        LOG(WARNING) << "Invalid entries=" << numEntries << " offset=" << cdOffset
-                     << " (len=" << pArchive->length << ")";
-        goto bail;
-    }
-
-    /*
-     * Create data structures to hold entries.
-     */
-    pArchive->numEntries = numEntries;
-    pArchive->pEntries = (ZipEntry*) calloc(numEntries, sizeof(ZipEntry));
-    pArchive->pHash = mzHashTableCreate(mzHashSize(numEntries), NULL);
-    if (pArchive->pEntries == NULL || pArchive->pHash == NULL)
-        goto bail;
-
-    ptr = pArchive->addr + cdOffset;
-    for (i = 0; i < numEntries; i++) {
-        ZipEntry* pEntry;
-        unsigned int fileNameLen, extraLen, commentLen, localHdrOffset;
-        const unsigned char* localHdr;
-        const char *fileName;
-
-        if (ptr + CENHDR > (const unsigned char*)pArchive->addr + pArchive->length) {
-            LOG(WARNING) << "Ran off the end (at " << i << ")";
-            goto bail;
-        }
-        if (get4LE(ptr) != CENSIG) {
-            LOG(WARNING) << "Missed a central dir sig (at " << i << ")";
-            goto bail;
-        }
-
-        localHdrOffset = get4LE(ptr + CENOFF);
-        fileNameLen = get2LE(ptr + CENNAM);
-        extraLen = get2LE(ptr + CENEXT);
-        commentLen = get2LE(ptr + CENCOM);
-        fileName = (const char*)ptr + CENHDR;
-        if (fileName + fileNameLen > (const char*)pArchive->addr + pArchive->length) {
-            LOG(WARNING) << "Filename ran off the end (at " << i << ")";
-            goto bail;
-        }
-        if (!validFilename(fileName, fileNameLen)) {
-            LOG(WARNING) << "Invalid filename (at " << i << ")";
-            goto bail;
-        }
-
-#if SORT_ENTRIES
-        /* Figure out where this entry should go (binary search).
-         */
-        if (i > 0) {
-            int low, high;
-
-            low = 0;
-            high = i - 1;
-            while (low <= high) {
-                int mid;
-                int diff;
-                int diffLen;
-
-                mid = low + ((high - low) / 2); // avoid overflow
-
-                if (pArchive->pEntries[mid].fileNameLen < fileNameLen) {
-                    diffLen = pArchive->pEntries[mid].fileNameLen;
-                } else {
-                    diffLen = fileNameLen;
-                }
-                diff = strncmp(pArchive->pEntries[mid].fileName, fileName,
-                        diffLen);
-                if (diff == 0) {
-                    diff = pArchive->pEntries[mid].fileNameLen - fileNameLen;
-                }
-                if (diff < 0) {
-                    low = mid + 1;
-                } else if (diff > 0) {
-                    high = mid - 1;
-                } else {
-                    high = mid;
-                    break;
-                }
-            }
-
-            unsigned int target = high + 1;
-            assert(target <= i);
-            if (target != i) {
-                /* It belongs somewhere other than at the end of
-                 * the list.  Make some room at [target].
-                 */
-                memmove(pArchive->pEntries + target + 1,
-                        pArchive->pEntries + target,
-                        (i - target) * sizeof(ZipEntry));
-            }
-            pEntry = &pArchive->pEntries[target];
-        } else {
-            pEntry = &pArchive->pEntries[0];
-        }
-#else
-        pEntry = &pArchive->pEntries[i];
-#endif
-        pEntry->fileNameLen = fileNameLen;
-        pEntry->fileName = fileName;
-
-        pEntry->compLen = get4LE(ptr + CENSIZ);
-        pEntry->uncompLen = get4LE(ptr + CENLEN);
-        pEntry->compression = get2LE(ptr + CENHOW);
-        pEntry->modTime = get4LE(ptr + CENTIM);
-        pEntry->crc32 = get4LE(ptr + CENCRC);
-
-        /* These two are necessary for finding the mode of the file.
-         */
-        pEntry->versionMadeBy = get2LE(ptr + CENVEM);
-        if ((pEntry->versionMadeBy & 0xff00) != 0 &&
-                (pEntry->versionMadeBy & 0xff00) != CENVEM_UNIX)
-        {
-            LOG(WARNING) << android::base::StringPrintf(
-                    "Incompatible \"version made by\": 0x%02x (at %d)\n",
-                    pEntry->versionMadeBy >> 8, i);
-            goto bail;
-        }
-        pEntry->externalFileAttributes = get4LE(ptr + CENATX);
-
-        // Perform pArchive->addr + localHdrOffset, ensuring that it won't
-        // overflow. This is needed because localHdrOffset is untrusted.
-        if (!safe_add((uintptr_t *)&localHdr, (uintptr_t)pArchive->addr,
-            (uintptr_t)localHdrOffset)) {
-            LOG(WARNING) << "Integer overflow adding in parseZipArchive";
-            goto bail;
-        }
-        if ((uintptr_t)localHdr + LOCHDR >
-            (uintptr_t)pArchive->addr + pArchive->length) {
-            LOG(WARNING) << "Bad offset to local header: " << localHdrOffset
-                         << " (at " << i << ")";
-            goto bail;
-        }
-        if (get4LE(localHdr) != LOCSIG) {
-            LOG(WARNING) << "Missed a local header sig (at " << i << ")";
-            goto bail;
-        }
-        pEntry->offset = localHdrOffset + LOCHDR
-            + get2LE(localHdr + LOCNAM) + get2LE(localHdr + LOCEXT);
-        if (!safe_add(NULL, pEntry->offset, pEntry->compLen)) {
-            LOG(WARNING) << "Integer overflow adding in parseZipArchive";
-            goto bail;
-        }
-        if ((size_t)pEntry->offset + pEntry->compLen > pArchive->length) {
-            LOG(WARNING) << "Data ran off the end (at " << i << ")";
-            goto bail;
-        }
-
-#if !SORT_ENTRIES
-        /* Add to hash table; no need to lock here.
-         * Can't do this now if we're sorting, because entries
-         * will move around.
-         */
-        addEntryToHashTable(pArchive->pHash, pEntry);
-#endif
-
-        //dumpEntry(pEntry);
-        ptr += CENHDR + fileNameLen + extraLen + commentLen;
-    }
-
-#if SORT_ENTRIES
-    /* If we're sorting, we have to wait until all entries
-     * are in their final places, otherwise the pointers will
-     * probably point to the wrong things.
-     */
-    for (i = 0; i < numEntries; i++) {
-        /* Add to hash table; no need to lock here.
-         */
-        addEntryToHashTable(pArchive->pHash, &pArchive->pEntries[i]);
-    }
-#endif
-
-    result = true;
-
-bail:
-    if (!result) {
-        mzHashTableFree(pArchive->pHash);
-        pArchive->pHash = NULL;
-    }
-    return result;
-}
-
-/*
- * Open a Zip archive and scan out the contents.
- *
- * The easiest way to do this is to mmap() the whole thing and do the
- * traditional backward scan for central directory.  Since the EOCD is
- * a relatively small bit at the end, we should end up only touching a
- * small set of pages.
- *
- * This will be called on non-Zip files, especially during startup, so
- * we don't want to be too noisy about failures.  (Do we want a "quiet"
- * flag?)
- *
- * On success, we fill out the contents of "pArchive".
- */
-int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive)
-{
-    int err;
-
-    if (length < ENDHDR) {
-        err = -1;
-        LOG(WARNING) << "Archive " << pArchive << " is too small to be zip ("
-                     << length << ")";
-        goto bail;
-    }
-
-    pArchive->addr = addr;
-    pArchive->length = length;
-
-    if (!parseZipArchive(pArchive)) {
-        err = -1;
-        LOG(WARNING) << "Parsing archive " << pArchive << " failed";
-        goto bail;
-    }
-
-    err = 0;
-
-bail:
-    if (err != 0)
-        mzCloseZipArchive(pArchive);
-    return err;
-}
-
-/*
- * Close a ZipArchive, closing the file and freeing the contents.
- *
- * NOTE: the ZipArchive may not have been fully created.
- */
-void mzCloseZipArchive(ZipArchive* pArchive)
-{
-    LOG(VERBOSE) << "Closing archive " << pArchive;
-
-    free(pArchive->pEntries);
-
-    mzHashTableFree(pArchive->pHash);
-
-    pArchive->pHash = NULL;
-    pArchive->pEntries = NULL;
-}
-
-/*
- * Find a matching entry.
- *
- * Returns NULL if no matching entry found.
- */
-const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
-        const char* entryName)
-{
-    unsigned int itemHash = computeHash(entryName, strlen(entryName));
-
-    return (const ZipEntry*)mzHashTableLookup(pArchive->pHash,
-                itemHash, (char*) entryName, hashcmpZipName, false);
-}
-
-/*
- * Return true if the entry is a symbolic link.
- */
-static bool mzIsZipEntrySymlink(const ZipEntry* pEntry)
-{
-    if ((pEntry->versionMadeBy & 0xff00) == CENVEM_UNIX) {
-        return S_ISLNK(pEntry->externalFileAttributes >> 16);
-    }
-    return false;
-}
-
-/* Call processFunction on the uncompressed data of a STORED entry.
- */
-static bool processStoredEntry(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
-    void *cookie)
-{
-    return processFunction(pArchive->addr + pEntry->offset, pEntry->uncompLen, cookie);
-}
-
-static bool processDeflatedEntry(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
-    void *cookie)
-{
-    bool success = false;
-    unsigned long totalOut = 0;
-    unsigned char procBuf[32 * 1024];
-    z_stream zstream;
-    int zerr;
-
-    /*
-     * Initialize the zlib stream.
-     */
-    memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = pArchive->addr + pEntry->offset;
-    zstream.avail_in = pEntry->compLen;
-    zstream.next_out = (Bytef*) procBuf;
-    zstream.avail_out = sizeof(procBuf);
-    zstream.data_type = Z_UNKNOWN;
-
-    /*
-     * Use the undocumented "negative window bits" feature to tell zlib
-     * that there's no zlib header waiting for it.
-     */
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        if (zerr == Z_VERSION_ERROR) {
-            LOG(ERROR) << "Installed zlib is not compatible with linked version ("
-                       << ZLIB_VERSION << ")";
-        } else {
-            LOG(ERROR) << "Call to inflateInit2 failed (zerr=" << zerr << ")";
-        }
-        goto bail;
-    }
-
-    /*
-     * Loop while we have data.
-     */
-    do {
-        /* uncompress the data */
-        zerr = inflate(&zstream, Z_NO_FLUSH);
-        if (zerr != Z_OK && zerr != Z_STREAM_END) {
-            LOG(WARNING) << "zlib inflate call failed (zerr=" << zerr << ")";
-            goto z_bail;
-        }
-
-        /* write when we're full or when we're done */
-        if (zstream.avail_out == 0 ||
-            (zerr == Z_STREAM_END && zstream.avail_out != sizeof(procBuf)))
-        {
-            long procSize = zstream.next_out - procBuf;
-            LOG(VERBOSE) << "+++ processing " << procSize << " bytes";
-            bool ret = processFunction(procBuf, procSize, cookie);
-            if (!ret) {
-                LOG(WARNING) << "Process function elected to fail (in inflate)";
-                goto z_bail;
-            }
-
-            zstream.next_out = procBuf;
-            zstream.avail_out = sizeof(procBuf);
-        }
-    } while (zerr == Z_OK);
-
-    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
-
-    // success!
-    totalOut = zstream.total_out;
-    success = true;
-
-z_bail:
-    inflateEnd(&zstream);        /* free up any allocated structures */
-
-bail:
-    if (totalOut != pEntry->uncompLen) {
-        if (success) {       // error already shown?
-            LOG(WARNING) << "Size mismatch on inflated file (" << totalOut << " vs "
-                         << pEntry->uncompLen << ")";
-        }
-        return false;
-    }
-    return true;
-}
-
-/*
- * Stream the uncompressed data through the supplied function,
- * passing cookie to it each time it gets called.  processFunction
- * may be called more than once.
- *
- * If processFunction returns false, the operation is abandoned and
- * mzProcessZipEntryContents() immediately returns false.
- *
- * This is useful for calculating the hash of an entry's uncompressed contents.
- */
-bool mzProcessZipEntryContents(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
-    void *cookie)
-{
-    bool ret = false;
-
-    switch (pEntry->compression) {
-    case STORED:
-        ret = processStoredEntry(pArchive, pEntry, processFunction, cookie);
-        break;
-    case DEFLATED:
-        ret = processDeflatedEntry(pArchive, pEntry, processFunction, cookie);
-        break;
-    default:
-        LOG(ERROR) << "Unsupported compression type " << pEntry->compression
-                   << " for entry '" << pEntry->fileName << "'";
-        break;
-    }
-
-    return ret;
-}
-
-typedef struct {
-    char *buf;
-    int bufLen;
-} CopyProcessArgs;
-
-static bool copyProcessFunction(const unsigned char *data, int dataLen,
-        void *cookie)
-{
-    CopyProcessArgs *args = (CopyProcessArgs *)cookie;
-    if (dataLen <= args->bufLen) {
-        memcpy(args->buf, data, dataLen);
-        args->buf += dataLen;
-        args->bufLen -= dataLen;
-        return true;
-    }
-    return false;
-}
-
-/*
- * Read an entry into a buffer allocated by the caller.
- */
-bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
-        char *buf, int bufLen)
-{
-    CopyProcessArgs args;
-    bool ret;
-
-    args.buf = buf;
-    args.bufLen = bufLen;
-    ret = mzProcessZipEntryContents(pArchive, pEntry, copyProcessFunction,
-            (void *)&args);
-    if (!ret) {
-        LOG(ERROR) << "Can't extract entry to buffer";
-        return false;
-    }
-    return true;
-}
-
-static bool writeProcessFunction(const unsigned char *data, int dataLen,
-                                 void *cookie)
-{
-    int fd = (int)(intptr_t)cookie;
-    if (dataLen == 0) {
-        return true;
-    }
-    ssize_t soFar = 0;
-    while (true) {
-        ssize_t n = TEMP_FAILURE_RETRY(write(fd, data+soFar, dataLen-soFar));
-        if (n <= 0) {
-            PLOG(ERROR) << "Error writing " << dataLen-soFar << " bytes from zip file from "
-                        << data+soFar;
-            return false;
-        } else if (n > 0) {
-            soFar += n;
-            if (soFar == dataLen) return true;
-            if (soFar > dataLen) {
-                LOG(ERROR) << "write overrun?  (" << soFar << " bytes instead of "
-                           << dataLen << ")";
-                return false;
-            }
-        }
-    }
-}
-
-/*
- * Uncompress "pEntry" in "pArchive" to "fd" at the current offset.
- */
-bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, int fd)
-{
-    bool ret = mzProcessZipEntryContents(pArchive, pEntry, writeProcessFunction,
-                                         (void*)(intptr_t)fd);
-    if (!ret) {
-        LOG(ERROR) << "Can't extract entry to file.";
-        return false;
-    }
-    return true;
-}
-
-typedef struct {
-    unsigned char* buffer;
-    long len;
-} BufferExtractCookie;
-
-static bool bufferProcessFunction(const unsigned char *data, int dataLen,
-    void *cookie) {
-    BufferExtractCookie *bec = (BufferExtractCookie*)cookie;
-
-    memmove(bec->buffer, data, dataLen);
-    bec->buffer += dataLen;
-    bec->len -= dataLen;
-
-    return true;
-}
-
-/*
- * Uncompress "pEntry" in "pArchive" to buffer, which must be large
- * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
- */
-bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, unsigned char *buffer)
-{
-    BufferExtractCookie bec;
-    bec.buffer = buffer;
-    bec.len = mzGetZipEntryUncompLen(pEntry);
-
-    bool ret = mzProcessZipEntryContents(pArchive, pEntry,
-        bufferProcessFunction, (void*)&bec);
-    if (!ret || bec.len != 0) {
-        LOG(ERROR) << "Can't extract entry to memory buffer.";
-        return false;
-    }
-    return true;
-}
-
-
-/* Helper state to make path translation easier and less malloc-happy.
- */
-typedef struct {
-    const char *targetDir;
-    const char *zipDir;
-    char *buf;
-    int targetDirLen;
-    int zipDirLen;
-    int bufLen;
-} MzPathHelper;
-
-/* Given the values of targetDir and zipDir in the helper,
- * return the target filename of the provided entry.
- * The helper must be initialized first.
- */
-static const char *targetEntryPath(MzPathHelper *helper, ZipEntry *pEntry)
-{
-    int needLen;
-    bool firstTime = (helper->buf == NULL);
-
-    /* target file <-- targetDir + / + entry[zipDirLen:]
-     */
-    needLen = helper->targetDirLen + 1 +
-            pEntry->fileNameLen - helper->zipDirLen + 1;
-    if (firstTime || needLen > helper->bufLen) {
-        char *newBuf;
-
-        needLen *= 2;
-        newBuf = (char *)realloc(helper->buf, needLen);
-        if (newBuf == NULL) {
-            return NULL;
-        }
-        helper->buf = newBuf;
-        helper->bufLen = needLen;
-    }
-
-    /* Every path will start with the target path and a slash.
-     */
-    if (firstTime) {
-        char *p = helper->buf;
-        memcpy(p, helper->targetDir, helper->targetDirLen);
-        p += helper->targetDirLen;
-        if (p == helper->buf || p[-1] != '/') {
-            helper->targetDirLen += 1;
-            *p++ = '/';
-        }
-    }
-
-    /* Replace the custom part of the path with the appropriate
-     * part of the entry's path.
-     */
-    char *epath = helper->buf + helper->targetDirLen;
-    memcpy(epath, pEntry->fileName + helper->zipDirLen,
-            pEntry->fileNameLen - helper->zipDirLen);
-    epath += pEntry->fileNameLen - helper->zipDirLen;
-    *epath = '\0';
-
-    return helper->buf;
-}
-
-/*
- * Inflate all entries under zipDir to the directory specified by
- * targetDir, which must exist and be a writable directory.
- *
- * The immediate children of zipDir will become the immediate
- * children of targetDir; e.g., if the archive contains the entries
- *
- *     a/b/c/one
- *     a/b/c/two
- *     a/b/c/d/three
- *
- * and mzExtractRecursive(a, "a/b/c", "/tmp") is called, the resulting
- * files will be
- *
- *     /tmp/one
- *     /tmp/two
- *     /tmp/d/three
- *
- * Returns true on success, false on failure.
- */
-bool mzExtractRecursive(const ZipArchive *pArchive,
-                        const char *zipDir, const char *targetDir,
-                        const struct utimbuf *timestamp,
-                        void (*callback)(const char *fn, void *), void *cookie,
-                        struct selabel_handle *sehnd)
-{
-    if (zipDir[0] == '/') {
-        LOG(ERROR) << "mzExtractRecursive(): zipDir must be a relative path.";
-        return false;
-    }
-    if (targetDir[0] != '/') {
-        LOG(ERROR) << "mzExtractRecursive(): targetDir must be an absolute path.\n";
-        return false;
-    }
-
-    unsigned int zipDirLen;
-    char *zpath;
-
-    zipDirLen = strlen(zipDir);
-    zpath = (char *)malloc(zipDirLen + 2);
-    if (zpath == NULL) {
-        LOG(ERROR) << "Can't allocate " << (zipDirLen + 2) << " bytes for zip path";
-        return false;
-    }
-    /* If zipDir is empty, we'll extract the entire zip file.
-     * Otherwise, canonicalize the path.
-     */
-    if (zipDirLen > 0) {
-        /* Make sure there's (hopefully, exactly one) slash at the
-         * end of the path.  This way we don't need to worry about
-         * accidentally extracting "one/twothree" when a path like
-         * "one/two" is specified.
-         */
-        memcpy(zpath, zipDir, zipDirLen);
-        if (zpath[zipDirLen-1] != '/') {
-            zpath[zipDirLen++] = '/';
-        }
-    }
-    zpath[zipDirLen] = '\0';
-
-    /* Set up the helper structure that we'll use to assemble paths.
-     */
-    MzPathHelper helper;
-    helper.targetDir = targetDir;
-    helper.targetDirLen = strlen(helper.targetDir);
-    helper.zipDir = zpath;
-    helper.zipDirLen = strlen(helper.zipDir);
-    helper.buf = NULL;
-    helper.bufLen = 0;
-
-    /* Walk through the entries and extract anything whose path begins
-     * with zpath.
-    //TODO: since the entries are sorted, binary search for the first match
-    //      and stop after the first non-match.
-     */
-    unsigned int i;
-    bool seenMatch = false;
-    int ok = true;
-    int extractCount = 0;
-    for (i = 0; i < pArchive->numEntries; i++) {
-        ZipEntry *pEntry = pArchive->pEntries + i;
-        if (pEntry->fileNameLen < zipDirLen) {
-       //TODO: look out for a single empty directory entry that matches zpath, but
-       //      missing the trailing slash.  Most zip files seem to include
-       //      the trailing slash, but I think it's legal to leave it off.
-       //      e.g., zpath "a/b/", entry "a/b", with no children of the entry.
-            /* No chance of matching.
-             */
-#if SORT_ENTRIES
-            if (seenMatch) {
-                /* Since the entries are sorted, we can give up
-                 * on the first mismatch after the first match.
-                 */
-                break;
-            }
-#endif
-            continue;
-        }
-        /* If zpath is empty, this strncmp() will match everything,
-         * which is what we want.
-         */
-        if (strncmp(pEntry->fileName, zpath, zipDirLen) != 0) {
-#if SORT_ENTRIES
-            if (seenMatch) {
-                /* Since the entries are sorted, we can give up
-                 * on the first mismatch after the first match.
-                 */
-                break;
-            }
-#endif
-            continue;
-        }
-        /* This entry begins with zipDir, so we'll extract it.
-         */
-        seenMatch = true;
-
-        /* Find the target location of the entry.
-         */
-        const char *targetFile = targetEntryPath(&helper, pEntry);
-        if (targetFile == NULL) {
-            LOG(ERROR) << "Can't assemble target path for \"" << std::string(pEntry->fileName,
-                       pEntry->fileNameLen) << "\"";
-            ok = false;
-            break;
-        }
-
-#define UNZIP_DIRMODE 0755
-#define UNZIP_FILEMODE 0644
-        /*
-         * Create the file or directory. We ignore directory entries
-         * because we recursively create paths to each file entry we encounter
-         * in the zip archive anyway.
-         *
-         * NOTE: A "directory entry" in a zip archive is just a zero length
-         * entry that ends in a "/". They're not mandatory and many tools get
-         * rid of them. We need to process them only if we want to preserve
-         * empty directories from the archive.
-         */
-        if (pEntry->fileName[pEntry->fileNameLen-1] != '/') {
-            /* This is not a directory.  First, make sure that
-             * the containing directory exists.
-             */
-            int ret = dirCreateHierarchy(
-                    targetFile, UNZIP_DIRMODE, timestamp, true, sehnd);
-            if (ret != 0) {
-                PLOG(ERROR) << "Can't create containing directory for \"" << targetFile << "\"";
-                ok = false;
-                break;
-            }
-
-            /*
-             * The entry is a regular file or a symlink. Open the target for writing.
-             *
-             * TODO: This behavior for symlinks seems rather bizarre. For a
-             * symlink foo/bar/baz -> foo/tar/taz, we will create a file called
-             * "foo/bar/baz" whose contents are the literal "foo/tar/taz". We
-             * warn about this for now and preserve older behavior.
-             */
-            if (mzIsZipEntrySymlink(pEntry)) {
-                LOG(ERROR) << "Symlink entry \"" << std::string(pEntry->fileName,
-                           pEntry->fileNameLen) << "\" will be output as a regular file.";
-            }
-
-            char *secontext = NULL;
-
-            if (sehnd) {
-                selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
-                setfscreatecon(secontext);
-            }
-
-            int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC,
-                UNZIP_FILEMODE);
-
-            if (secontext) {
-                freecon(secontext);
-                setfscreatecon(NULL);
-            }
-
-            if (fd < 0) {
-                PLOG(ERROR) << "Can't create target file \"" << targetFile << "\"";
-                ok = false;
-                break;
-            }
-
-            bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
-            if (ok) {
-                ok = (fsync(fd) == 0);
-            }
-            if (close(fd) != 0) {
-                ok = false;
-            }
-            if (!ok) {
-                LOG(ERROR) << "Error extracting \"" << targetFile << "\"";
-                ok = false;
-                break;
-            }
-
-            if (timestamp != NULL && utime(targetFile, timestamp)) {
-                LOG(ERROR) << "Error touching \"" << targetFile << "\"";
-                ok = false;
-                break;
-            }
-
-            LOG(VERBOSE) <<"Extracted file \"" << targetFile << "\"";
-            ++extractCount;
-        }
-
-        if (callback != NULL) callback(targetFile, cookie);
-    }
-
-    LOG(VERBOSE) << "Extracted " << extractCount << " file(s)";
-
-    free(helper.buf);
-    free(zpath);
-
-    return ok;
-}
diff --git a/minzip/Zip.h b/minzip/Zip.h
deleted file mode 100644
index c932c11..0000000
--- a/minzip/Zip.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Simple Zip archive support.
- */
-#ifndef _MINZIP_ZIP
-#define _MINZIP_ZIP
-
-#include "inline_magic.h"
-
-#include <stdlib.h>
-#include <utime.h>
-
-#include "Hash.h"
-#include "SysUtil.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct selabel_handle;
-
-/*
- * One entry in the Zip archive.  Treat this as opaque -- use accessors below.
- *
- * TODO: we're now keeping the pages mapped so we don't have to copy the
- * filename.  We can change the accessors to retrieve the various pieces
- * directly from the source file instead of copying them out, for a very
- * slight speed hit and a modest reduction in memory usage.
- */
-typedef struct ZipEntry {
-    unsigned int fileNameLen;
-    const char*  fileName;       // not null-terminated
-    uint32_t     offset;
-    uint32_t     compLen;
-    uint32_t     uncompLen;
-    int          compression;
-    long         modTime;
-    long         crc32;
-    int          versionMadeBy;
-    long         externalFileAttributes;
-} ZipEntry;
-
-/*
- * One Zip archive.  Treat as opaque.
- */
-typedef struct ZipArchive {
-    unsigned int   numEntries;
-    ZipEntry*      pEntries;
-    HashTable*     pHash;          // maps file name to ZipEntry
-    unsigned char* addr;
-    size_t         length;
-} ZipArchive;
-
-/*
- * Represents a non-NUL-terminated string,
- * which is how entry names are stored.
- */
-typedef struct {
-    const char *str;
-    size_t len;
-} UnterminatedString;
-
-/*
- * Open a Zip archive.
- *
- * On success, returns 0 and populates "pArchive".  Returns nonzero errno
- * value on failure.
- */
-int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive);
-
-/*
- * Close archive, releasing resources associated with it.
- *
- * Depending on the implementation this could unmap pages used by classes
- * stored in a Jar.  This should only be done after unloading classes.
- */
-void mzCloseZipArchive(ZipArchive* pArchive);
-
-
-/*
- * Find an entry in the Zip archive, by name.
- */
-const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
-        const char* entryName);
-
-INLINE uint32_t mzGetZipEntryOffset(const ZipEntry* pEntry) {
-    return pEntry->offset;
-}
-INLINE uint32_t mzGetZipEntryUncompLen(const ZipEntry* pEntry) {
-    return pEntry->uncompLen;
-}
-
-/*
- * Type definition for the callback function used by
- * mzProcessZipEntryContents().
- */
-typedef bool (*ProcessZipEntryContentsFunction)(const unsigned char *data,
-    int dataLen, void *cookie);
-
-/*
- * Stream the uncompressed data through the supplied function,
- * passing cookie to it each time it gets called.  processFunction
- * may be called more than once.
- *
- * If processFunction returns false, the operation is abandoned and
- * mzProcessZipEntryContents() immediately returns false.
- *
- * This is useful for calculating the hash of an entry's uncompressed contents.
- */
-bool mzProcessZipEntryContents(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
-    void *cookie);
-
-/*
- * Read an entry into a buffer allocated by the caller.
- */
-bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
-        char* buf, int bufLen);
-
-/*
- * Inflate and write an entry to a file.
- */
-bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, int fd);
-
-/*
- * Inflate and write an entry to a memory buffer, which must be long
- * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
- */
-bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
-    const ZipEntry *pEntry, unsigned char* buffer);
-
-/*
- * Inflate all files under zipDir to the directory specified by
- * targetDir, which must exist and be a writable directory.
- *
- * Directory entries and symlinks are not extracted.
- *
- *
- * The immediate children of zipDir will become the immediate
- * children of targetDir; e.g., if the archive contains the entries
- *
- *     a/b/c/one
- *     a/b/c/two
- *     a/b/c/d/three
- *
- * and mzExtractRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
- * files will be
- *
- *     /tmp/one
- *     /tmp/two
- *     /tmp/d/three
- *
- * If timestamp is non-NULL, file timestamps will be set accordingly.
- *
- * If callback is non-NULL, it will be invoked with each unpacked file.
- *
- * Returns true on success, false on failure.
- */
-bool mzExtractRecursive(const ZipArchive *pArchive,
-        const char *zipDir, const char *targetDir,
-        const struct utimbuf *timestamp,
-        void (*callback)(const char *fn, void*), void *cookie,
-        struct selabel_handle *sehnd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*_MINZIP_ZIP*/
diff --git a/minzip/inline_magic.h b/minzip/inline_magic.h
deleted file mode 100644
index 59c659f..0000000
--- a/minzip/inline_magic.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef MINZIP_INLINE_MAGIC_H_
-#define MINZIP_INLINE_MAGIC_H_
-
-#ifndef MINZIP_GENERATE_INLINES
-#define INLINE extern inline __attribute((__gnu_inline__))
-#else
-#define INLINE
-#endif
-
-#endif  // MINZIP_INLINE_MAGIC_H_
diff --git a/otafault/Android.mk b/otafault/Android.mk
index 82c2671..71c2c62 100644
--- a/otafault/Android.mk
+++ b/otafault/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 otafault_static_libs := \
-    libminzip \
+    libziparchive \
     libz \
     libselinux \
     libbase \
diff --git a/otafault/config.cpp b/otafault/config.cpp
index b456739..ee4ef89 100644
--- a/otafault/config.cpp
+++ b/otafault/config.cpp
@@ -21,21 +21,21 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
+#include <ziparchive/zip_archive.h>
 
-#include "minzip/Zip.h"
 #include "config.h"
 #include "ota_io.h"
 
 #define OTAIO_MAX_FNAME_SIZE 128
 
-static ZipArchive* archive;
+static ZipArchiveHandle archive;
 static std::map<std::string, bool> should_inject_cache;
 
 static std::string get_type_path(const char* io_type) {
     return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type);
 }
 
-void ota_io_init(ZipArchive* za) {
+void ota_io_init(ZipArchiveHandle za) {
     archive = za;
     ota_set_fault_files();
 }
@@ -50,9 +50,11 @@
     if (should_inject_cache.find(type_path) != should_inject_cache.end()) {
         return should_inject_cache[type_path];
     }
-    const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
-    should_inject_cache[type_path] = entry != nullptr;
-    return entry != NULL;
+    ZipString zip_type_path(type_path.c_str());
+    ZipEntry entry;
+    int status = FindEntry(archive, zip_type_path, &entry);
+    should_inject_cache[type_path] = (status == 0);
+    return (status == 0);
 }
 
 bool should_hit_cache() {
@@ -63,7 +65,9 @@
     std::string type_path = get_type_path(io_type);
     std::string fname;
     fname.resize(OTAIO_MAX_FNAME_SIZE);
-    const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
-    mzReadZipEntry(archive, entry, &fname[0], OTAIO_MAX_FNAME_SIZE);
+    ZipString zip_type_path(type_path.c_str());
+    ZipEntry entry;
+    int status = FindEntry(archive, zip_type_path, &entry);
+    ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(&fname[0]), OTAIO_MAX_FNAME_SIZE);
     return fname;
 }
diff --git a/otafault/config.h b/otafault/config.h
index 4430be3..c048617 100644
--- a/otafault/config.h
+++ b/otafault/config.h
@@ -41,7 +41,7 @@
 
 #include <stdbool.h>
 
-#include "minzip/Zip.h"
+#include <ziparchive/zip_archive.h>
 
 #define OTAIO_BASE_DIR ".libotafault"
 #define OTAIO_READ "READ"
@@ -52,7 +52,7 @@
 /*
  * Initialize libotafault by providing a reference to the OTA package.
  */
-void ota_io_init(ZipArchive* za);
+void ota_io_init(ZipArchiveHandle zip);
 
 /*
  * Return true if a config file is present for the given IO type.
diff --git a/otautil/Android.mk b/otautil/Android.mk
new file mode 100644
index 0000000..3acfa53
--- /dev/null
+++ b/otautil/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    SysUtil.cpp \
+    DirUtil.cpp \
+    ZipUtil.cpp
+
+LOCAL_C_INCLUDES := \
+    external/zlib \
+    external/safe-iop/include
+
+LOCAL_STATIC_LIBRARIES := libselinux libbase
+
+LOCAL_MODULE := libotautil
+
+LOCAL_CLANG := true
+
+LOCAL_CFLAGS += -Werror -Wall
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/minzip/DirUtil.cpp b/otautil/DirUtil.cpp
similarity index 100%
rename from minzip/DirUtil.cpp
rename to otautil/DirUtil.cpp
diff --git a/minzip/DirUtil.h b/otautil/DirUtil.h
similarity index 100%
rename from minzip/DirUtil.h
rename to otautil/DirUtil.h
diff --git a/minzip/SysUtil.cpp b/otautil/SysUtil.cpp
similarity index 100%
rename from minzip/SysUtil.cpp
rename to otautil/SysUtil.cpp
diff --git a/minzip/SysUtil.h b/otautil/SysUtil.h
similarity index 100%
rename from minzip/SysUtil.h
rename to otautil/SysUtil.h
diff --git a/otautil/ZipUtil.cpp b/otautil/ZipUtil.cpp
new file mode 100644
index 0000000..714c956
--- /dev/null
+++ b/otautil/ZipUtil.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "ZipUtil.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <utime.h>
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
+#include <ziparchive/zip_archive.h>
+
+#include "DirUtil.h"
+
+static constexpr mode_t UNZIP_DIRMODE = 0755;
+static constexpr mode_t UNZIP_FILEMODE = 0644;
+
+bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
+                             const std::string& dest_path, const struct utimbuf* timestamp,
+                             struct selabel_handle* sehnd) {
+    if (!zip_path.empty() && zip_path[0] == '/') {
+        LOG(ERROR) << "ExtractPackageRecursive(): zip_path must be a relative path " << zip_path;
+        return false;
+    }
+    if (dest_path.empty() || dest_path[0] != '/') {
+        LOG(ERROR) << "ExtractPackageRecursive(): dest_path must be an absolute path " << dest_path;
+        return false;
+    }
+
+    void* cookie;
+    std::string target_dir(dest_path);
+    if (dest_path.back() != '/') {
+        target_dir += '/';
+    }
+    std::string prefix_path(zip_path);
+    if (!zip_path.empty() && zip_path.back() != '/') {
+        prefix_path += '/';
+    }
+    const ZipString zip_prefix(prefix_path.c_str());
+
+    int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
+    if (ret != 0) {
+        LOG(ERROR) << "failed to start iterating zip entries.";
+        return false;
+    }
+
+    std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
+    ZipEntry entry;
+    ZipString name;
+    int extractCount = 0;
+    while (Next(cookie, &entry, &name) == 0) {
+        std::string entry_name(name.name, name.name + name.name_length);
+        CHECK_LE(prefix_path.size(), entry_name.size());
+        std::string path = target_dir + entry_name.substr(prefix_path.size());
+        // Skip dir.
+        if (path.back() == '/') {
+            continue;
+        }
+        //TODO(b/31917448) handle the symlink.
+
+        if (dirCreateHierarchy(path.c_str(), UNZIP_DIRMODE, timestamp, true, sehnd) != 0) {
+            LOG(ERROR) << "failed to create dir for " << path;
+            return false;
+        }
+
+        char *secontext = NULL;
+        if (sehnd) {
+            selabel_lookup(sehnd, &secontext, path.c_str(), UNZIP_FILEMODE);
+            setfscreatecon(secontext);
+        }
+        android::base::unique_fd fd(open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, UNZIP_FILEMODE));
+        if (fd == -1) {
+            PLOG(ERROR) << "Can't create target file \"" << path << "\"";
+            return false;
+        }
+        if (secontext) {
+            freecon(secontext);
+            setfscreatecon(NULL);
+        }
+
+        int err = ExtractEntryToFile(zip, &entry, fd);
+        if (err != 0) {
+            LOG(ERROR) << "Error extracting \"" << path << "\" : " << ErrorCodeString(err);
+            return false;
+        }
+
+        if (fsync(fd) != 0) {
+            PLOG(ERROR) << "Error syncing file descriptor when extracting \"" << path << "\"";
+            return false;
+        }
+
+        if (timestamp != nullptr && utime(path.c_str(), timestamp)) {
+            PLOG(ERROR) << "Error touching \"" << path << "\"";
+            return false;
+        }
+
+        LOG(INFO) << "Extracted file \"" << path << "\"";
+        ++extractCount;
+    }
+
+    LOG(INFO) << "Extracted " << extractCount << " file(s)";
+    return true;
+}
diff --git a/otautil/ZipUtil.h b/otautil/ZipUtil.h
new file mode 100644
index 0000000..cda405c
--- /dev/null
+++ b/otautil/ZipUtil.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _OTAUTIL_ZIPUTIL_H
+#define _OTAUTIL_ZIPUTIL_H
+
+#include <utime.h>
+
+#include <string>
+
+#include <selinux/label.h>
+#include <ziparchive/zip_archive.h>
+
+/*
+ * Inflate all files under zip_path to the directory specified by
+ * dest_path, which must exist and be a writable directory. The zip_path
+ * is allowed to be an empty string, in which case the whole package
+ * will be extracted.
+ *
+ * Directory entries are not extracted.
+ *
+ * The immediate children of zip_path will become the immediate
+ * children of dest_path; e.g., if the archive contains the entries
+ *
+ *     a/b/c/one
+ *     a/b/c/two
+ *     a/b/c/d/three
+ *
+ * and ExtractPackageRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
+ * files will be
+ *
+ *     /tmp/one
+ *     /tmp/two
+ *     /tmp/d/three
+ *
+ * If timestamp is non-NULL, file timestamps will be set accordingly.
+ *
+ * Returns true on success, false on failure.
+ */
+bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
+                             const std::string& dest_path, const struct utimbuf* timestamp,
+                             struct selabel_handle* sehnd);
+
+#endif // _OTAUTIL_ZIPUTIL_H
diff --git a/recovery.cpp b/recovery.cpp
index 9cf63c4..343d123 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -46,15 +46,16 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <cutils/properties.h> /* for property_list */
 #include <healthd/BatteryMonitor.h>
 #include <private/android_logger.h> /* private pmsg functions */
 #include <selinux/label.h>
 #include <selinux/selinux.h>
+#include <ziparchive/zip_archive.h>
 
 #include "adb_install.h"
-#include "bootloader.h"
 #include "common.h"
 #include "device.h"
 #include "error_code.h"
@@ -63,7 +64,7 @@
 #include "install.h"
 #include "minadbd/minadbd.h"
 #include "minui/minui.h"
-#include "minzip/DirUtil.h"
+#include "otautil/DirUtil.h"
 #include "roots.h"
 #include "ui.h"
 #include "screen_ui.h"
@@ -84,7 +85,7 @@
   { "shutdown_after", no_argument, NULL, 'p' },
   { "reason", required_argument, NULL, 'r' },
   { "security", no_argument, NULL, 'e'},
-  { "brick", no_argument, NULL, 0 },
+  { "wipe_ab", no_argument, NULL, 0 },
   { NULL, 0, NULL, 0 },
 };
 
@@ -111,7 +112,7 @@
 // So we should check battery with a slightly lower limitation.
 static const int BATTERY_OK_PERCENTAGE = 20;
 static const int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15;
-constexpr const char* RECOVERY_BRICK = "/etc/recovery.brick";
+constexpr const char* RECOVERY_WIPE = "/etc/recovery.wipe";
 
 RecoveryUI* ui = NULL;
 static const char* locale = "en_US";
@@ -300,9 +301,13 @@
 //   - the contents of COMMAND_FILE (one per line)
 static void
 get_args(int *argc, char ***argv) {
-    struct bootloader_message boot;
-    memset(&boot, 0, sizeof(boot));
-    get_bootloader_message(&boot);  // this may fail, leaving a zeroed structure
+    bootloader_message boot = {};
+    std::string err;
+    if (!read_bootloader_message(&boot, &err)) {
+        LOG(ERROR) << err;
+        // If fails, leave a zeroed bootloader_message.
+        memset(&boot, 0, sizeof(boot));
+    }
     stage = strndup(boot.stage, sizeof(boot.stage));
 
     if (boot.command[0] != 0) {
@@ -367,16 +372,20 @@
         strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
         strlcat(boot.recovery, "\n", sizeof(boot.recovery));
     }
-    set_bootloader_message(&boot);
+    if (!write_bootloader_message(boot, &err)) {
+        LOG(ERROR) << err;
+    }
 }
 
 static void
 set_sdcard_update_bootloader_message() {
-    struct bootloader_message boot;
-    memset(&boot, 0, sizeof(boot));
+    bootloader_message boot = {};
     strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
     strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
-    set_bootloader_message(&boot);
+    std::string err;
+    if (!write_bootloader_message(boot, &err)) {
+        LOG(ERROR) << err;
+    }
 }
 
 // Read from kernel log into buffer and write out to file.
@@ -527,9 +536,11 @@
     copy_logs();
 
     // Reset to normal system boot so recovery won't cycle indefinitely.
-    struct bootloader_message boot;
-    memset(&boot, 0, sizeof(boot));
-    set_bootloader_message(&boot);
+    bootloader_message boot = {};
+    std::string err;
+    if (!write_bootloader_message(boot, &err)) {
+        LOG(ERROR) << err;
+    }
 
     // Remove the command file, so recovery won't repeat indefinitely.
     if (has_cache) {
@@ -897,15 +908,15 @@
     return true;
 }
 
-// Brick the current device, with a secure wipe of all the partitions in
-// RECOVERY_BRICK.
-static bool brick_device() {
+// Wipe the current A/B device, with a secure wipe of all the partitions in
+// RECOVERY_WIPE.
+static bool wipe_ab_device() {
     ui->SetBackground(RecoveryUI::ERASING);
     ui->SetProgressType(RecoveryUI::INDETERMINATE);
 
     std::string partition_list;
-    if (!android::base::ReadFileToString(RECOVERY_BRICK, &partition_list)) {
-        LOG(ERROR) << "failed to read \"" << RECOVERY_BRICK << "\"";
+    if (!android::base::ReadFileToString(RECOVERY_WIPE, &partition_list)) {
+        LOG(ERROR) << "failed to read \"" << RECOVERY_WIPE << "\"";
         return false;
     }
 
@@ -1310,7 +1321,7 @@
 }
 
 static void set_retry_bootloader_message(int retry_count, int argc, char** argv) {
-    struct bootloader_message boot {};
+    bootloader_message boot = {};
     strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
     strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
 
@@ -1329,7 +1340,10 @@
         snprintf(buffer, sizeof(buffer), "--retry_count=%d\n", retry_count+1);
         strlcat(boot.recovery, buffer, sizeof(boot.recovery));
     }
-    set_bootloader_message(&boot);
+    std::string err;
+    if (!write_bootloader_message(boot, &err)) {
+        LOG(ERROR) << err;
+    }
 }
 
 static ssize_t logbasename(
@@ -1427,7 +1441,7 @@
     const char *update_package = NULL;
     bool should_wipe_data = false;
     bool should_wipe_cache = false;
-    bool should_brick = false;
+    bool should_wipe_ab = false;
     bool show_text = false;
     bool sideload = false;
     bool sideload_auto_reboot = false;
@@ -1461,8 +1475,8 @@
         case 'r': reason = optarg; break;
         case 'e': security_update = true; break;
         case 0: {
-            if (strcmp(OPTIONS[option_index].name, "brick") == 0) {
-                should_brick = true;
+            if (strcmp(OPTIONS[option_index].name, "wipe_ab") == 0) {
+                should_wipe_ab = true;
                 break;
             }
             break;
@@ -1608,8 +1622,8 @@
         if (!wipe_cache(false, device)) {
             status = INSTALL_ERROR;
         }
-    } else if (should_brick) {
-        if (!brick_device()) {
+    } else if (should_wipe_ab) {
+        if (!wipe_ab_device()) {
             status = INSTALL_ERROR;
         }
     } else if (sideload) {
diff --git a/tests/Android.mk b/tests/Android.mk
index ef822d1..abe6b6d 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -24,11 +24,18 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_STATIC_LIBRARIES := \
     libverifier \
-    libminui
+    libminui \
+    libotautil \
+    libziparchive \
+    libutils \
+    libz \
+    libselinux \
+    libbase
 
 LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp
 LOCAL_SRC_FILES += unit/recovery_test.cpp
 LOCAL_SRC_FILES += unit/locale_test.cpp
+LOCAL_SRC_FILES += unit/zip_test.cpp
 LOCAL_C_INCLUDES := bootable/recovery
 LOCAL_SHARED_LIBRARIES := liblog
 include $(BUILD_NATIVE_TEST)
@@ -62,7 +69,7 @@
     libupdater \
     libverifier \
     libminui \
-    libminzip \
+    libotautil \
     libmounts \
     liblog \
     libselinux \
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 6a3eebf..7f9a714 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -29,10 +29,11 @@
 #include <openssl/sha.h>
 
 #include <android-base/stringprintf.h>
+#include <ziparchive/zip_archive.h>
 
 #include "common.h"
 #include "common/test_constants.h"
-#include "minzip/SysUtil.h"
+#include "otautil/SysUtil.h"
 #include "ui.h"
 #include "verifier.h"
 
diff --git a/tests/testdata/ziptest_dummy-update.zip b/tests/testdata/ziptest_dummy-update.zip
new file mode 100644
index 0000000..6976bf1
--- /dev/null
+++ b/tests/testdata/ziptest_dummy-update.zip
Binary files differ
diff --git a/tests/testdata/ziptest_valid.zip b/tests/testdata/ziptest_valid.zip
new file mode 100644
index 0000000..9e7cb78
--- /dev/null
+++ b/tests/testdata/ziptest_valid.zip
Binary files differ
diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp
new file mode 100644
index 0000000..b617446
--- /dev/null
+++ b/tests/unit/zip_test.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <otautil/SysUtil.h>
+#include <otautil/ZipUtil.h>
+#include <ziparchive/zip_archive.h>
+
+static const std::string DATA_PATH(getenv("ANDROID_DATA"));
+static const std::string TESTDATA_PATH("/recovery/testdata/");
+
+static const std::vector<uint8_t> kATxtContents {
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+    '\n'
+};
+
+static const std::vector<uint8_t> kBTxtContents {
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+    '\n'
+};
+
+TEST(otazip, ExtractPackageRecursive) {
+    TemporaryDir td;
+    ASSERT_NE(td.path, nullptr);
+    ZipArchiveHandle handle;
+    std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_valid.zip";
+    ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+    // Extract the whole package into a temp directory.
+    ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr);
+    // Make sure all the files are extracted correctly.
+    std::string path(td.path);
+    android::base::unique_fd fd(open((path + "/a.txt").c_str(), O_RDONLY));
+    ASSERT_NE(fd, -1);
+    std::vector<uint8_t> read_data;
+    read_data.resize(kATxtContents.size());
+    // The content of the file is the same as expected.
+    ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size()));
+    ASSERT_EQ(0, memcmp(read_data.data(), kATxtContents.data(), kATxtContents.size()));
+
+    fd.reset(open((path + "/b.txt").c_str(), O_RDONLY));
+    ASSERT_NE(fd, -1);
+    fd.reset(open((path + "/b/c.txt").c_str(), O_RDONLY));
+    ASSERT_NE(fd, -1);
+    fd.reset(open((path + "/b/d.txt").c_str(), O_RDONLY));
+    ASSERT_NE(fd, -1);
+    read_data.resize(kBTxtContents.size());
+    ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size()));
+    ASSERT_EQ(0, memcmp(read_data.data(), kBTxtContents.data(), kBTxtContents.size()));
+}
+
+TEST(otazip, OpenFromMemory) {
+    MemMapping map;
+    std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_dummy-update.zip";
+    ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map));
+    // Map an update package into memory and open the archive from there.
+    ZipArchiveHandle handle;
+    ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle));
+    static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary";
+    ZipString binary_path(BINARY_PATH);
+    ZipEntry binary_entry;
+    // Make sure the package opens correctly and its entry can be read.
+    ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
+    TemporaryFile tmp_binary;
+    ASSERT_NE(-1, tmp_binary.fd);
+    ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
+}
+
diff --git a/uncrypt/Android.mk b/uncrypt/Android.mk
index 3613799..59084b0 100644
--- a/uncrypt/Android.mk
+++ b/uncrypt/Android.mk
@@ -15,27 +15,17 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := bootloader_message_writer.cpp
-LOCAL_MODULE := libbootloader_message_writer
-LOCAL_STATIC_LIBRARIES := libbase libfs_mgr
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
 
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := uncrypt.cpp
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
 LOCAL_MODULE := uncrypt
-LOCAL_STATIC_LIBRARIES := libbootloader_message_writer \
-                          libbase \
-                          liblog \
-                          libfs_mgr \
-                          libcutils
+LOCAL_STATIC_LIBRARIES := \
+    libbootloader_message \
+    libbase \
+    liblog \
+    libfs_mgr \
+    libcutils
 LOCAL_CFLAGS := -Werror
 LOCAL_INIT_RC := uncrypt.rc
 
diff --git a/uncrypt/bootloader_message_writer.cpp b/uncrypt/bootloader_message_writer.cpp
deleted file mode 100644
index db52121..0000000
--- a/uncrypt/bootloader_message_writer.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <fs_mgr.h>
-
-#include "bootloader.h"
-
-static struct fstab* read_fstab(std::string* err) {
-  std::string ro_hardware = android::base::GetProperty("ro.hardware", "");
-  if (ro_hardware.empty()) {
-    *err = "failed to get ro.hardware";
-    return nullptr;
-  }
-  // The fstab path is always "/fstab.${ro.hardware}".
-  std::string fstab_path = "/fstab." + ro_hardware;
-  struct fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str());
-  if (fstab == nullptr) {
-    *err = "failed to read " + fstab_path;
-  }
-  return fstab;
-}
-
-static std::string get_misc_blk_device(std::string* err) {
-  struct fstab* fstab = read_fstab(err);
-  if (fstab == nullptr) {
-    return "";
-  }
-  fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
-  if (record == nullptr) {
-    *err = "failed to find /misc partition";
-    return "";
-  }
-  return record->blk_device;
-}
-
-static bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
-  std::string misc_blk_device = get_misc_blk_device(err);
-  if (misc_blk_device.empty()) {
-    return false;
-  }
-  android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC));
-  if (fd.get() == -1) {
-    *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
-                                       strerror(errno));
-    return false;
-  }
-  if (!android::base::WriteFully(fd.get(), &boot, sizeof(boot))) {
-    *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
-                                       strerror(errno));
-    return false;
-  }
-  // TODO: O_SYNC and fsync duplicates each other?
-  if (fsync(fd.get()) == -1) {
-    *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
-                                       strerror(errno));
-    return false;
-  }
-  return true;
-}
-
-bool clear_bootloader_message(std::string* err) {
-  bootloader_message boot = {};
-  return write_bootloader_message(boot, err);
-}
-
-bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
-  bootloader_message boot = {};
-  strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
-  strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
-  for (const auto& s : options) {
-    strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
-    if (s.back() != '\n') {
-      strlcat(boot.recovery, "\n", sizeof(boot.recovery));
-    }
-  }
-  return write_bootloader_message(boot, err);
-}
-
-extern "C" bool write_bootloader_message(const char* options) {
-  std::string err;
-  return write_bootloader_message({options}, &err);
-}
diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp
index c77e987..8b4d8ef 100644
--- a/uncrypt/uncrypt.cpp
+++ b/uncrypt/uncrypt.cpp
@@ -111,7 +111,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <bootloader_message_writer.h>
+#include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
 #include <cutils/sockets.h>
 #include <fs_mgr.h>
diff --git a/updater/Android.mk b/updater/Android.mk
index 33e9738..3c1d0d4 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -25,7 +25,9 @@
 updater_common_static_libraries := \
     libapplypatch \
     libedify \
-    libminzip \
+    libziparchive \
+    libotautil \
+    libutils \
     libmounts \
     libotafault \
     libext4_utils_static \
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 5f9b437..f08ca5b 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -33,21 +33,21 @@
 #include <unistd.h>
 #include <fec/io.h>
 
-#include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <ziparchive/zip_archive.h>
 
 #include "applypatch/applypatch.h"
 #include "edify/expr.h"
 #include "error_code.h"
 #include "updater/install.h"
 #include "openssl/sha.h"
-#include "minzip/Hash.h"
 #include "ota_io.h"
 #include "print_sha1.h"
 #include "updater/updater.h"
@@ -71,7 +71,7 @@
 
 static CauseCode failure_type = kNoCause;
 static bool is_retry = false;
-static std::map<std::string, RangeSet> stash_map;
+static std::unordered_map<std::string, RangeSet> stash_map;
 
 static void parse_range(const std::string& range_text, RangeSet& rs) {
 
@@ -300,8 +300,8 @@
 // rss and signals the condition again.
 
 struct NewThreadInfo {
-    ZipArchive* za;
-    const ZipEntry* entry;
+    ZipArchiveHandle za;
+    ZipEntry entry;
 
     RangeSinkState* rss;
 
@@ -309,7 +309,7 @@
     pthread_cond_t cv;
 };
 
-static bool receive_new_data(const unsigned char* data, int size, void* cookie) {
+static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
     NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie);
 
     while (size > 0) {
@@ -342,7 +342,7 @@
 
 static void* unzip_new_data(void* cookie) {
     NewThreadInfo* nti = (NewThreadInfo*) cookie;
-    mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
+    ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti);
     return nullptr;
 }
 
@@ -1351,28 +1351,6 @@
     CommandFunction f;
 };
 
-// CompareCommands and CompareCommandNames are for the hash table
-
-static int CompareCommands(const void* c1, const void* c2) {
-    return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name);
-}
-
-static int CompareCommandNames(const void* c1, const void* c2) {
-    return strcmp(((const Command*) c1)->name, (const char*) c2);
-}
-
-// HashString is used to hash command names for the hash table
-
-static unsigned int HashString(const char *s) {
-    unsigned int hash = 0;
-    if (s) {
-        while (*s) {
-            hash = hash * 33 + *s++;
-        }
-    }
-    return hash;
-}
-
 // args:
 //    - block device (or file) to modify in-place
 //    - transfer list (blob)
@@ -1429,21 +1407,23 @@
     }
 
     FILE* cmd_pipe = ui->cmd_pipe;
-    ZipArchive* za = ui->package_zip;
+    ZipArchiveHandle za = ui->package_zip;
 
     if (cmd_pipe == nullptr || za == nullptr) {
         return StringValue("");
     }
 
-    const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data.c_str());
-    if (patch_entry == nullptr) {
+    ZipString path_data(patch_data_fn->data.c_str());
+    ZipEntry patch_entry;
+    if (FindEntry(za, path_data, &patch_entry) != 0) {
         fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data.c_str());
         return StringValue("");
     }
 
-    params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry);
-    const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data.c_str());
-    if (new_entry == nullptr) {
+    params.patch_start = ui->package_zip_addr + patch_entry.offset;
+    ZipString new_data(new_data_fn->data.c_str());
+    ZipEntry new_entry;
+    if (FindEntry(za, new_data, &new_entry) != 0) {
         fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str());
         return StringValue("");
     }
@@ -1526,13 +1506,15 @@
         start += 2;
     }
 
-    // Build a hash table of the available commands
-    HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr);
-    std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree);
-
+    // Build a map of the available commands
+    std::unordered_map<std::string, const Command*> cmd_map;
     for (size_t i = 0; i < cmdcount; ++i) {
-        unsigned int cmdhash = HashString(commands[i].name);
-        mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true);
+        if (cmd_map.find(commands[i].name) != cmd_map.end()) {
+            fprintf(stderr, "Error: command [%s] already exists in the cmd map.\n",
+                    commands[i].name);
+            return StringValue(strdup(""));
+        }
+        cmd_map[commands[i].name] = &commands[i];
     }
 
     int rc = -1;
@@ -1549,16 +1531,13 @@
         params.cmdname = params.tokens[params.cpos++].c_str();
         params.cmdline = line_str.c_str();
 
-        unsigned int cmdhash = HashString(params.cmdname);
-        const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash,
-                const_cast<char*>(params.cmdname), CompareCommandNames,
-                false));
-
-        if (cmd == nullptr) {
+        if (cmd_map.find(params.cmdname) == cmd_map.end()) {
             fprintf(stderr, "unexpected command [%s]\n", params.cmdname);
             goto pbiudone;
         }
 
+        const Command* cmd = cmd_map[params.cmdname];
+
         if (cmd->f != nullptr && cmd->f(params) == -1) {
             fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str());
             goto pbiudone;
diff --git a/updater/include/updater/updater.h b/updater/include/updater/updater.h
index d3a09b9..f4a2fe8 100644
--- a/updater/include/updater/updater.h
+++ b/updater/include/updater/updater.h
@@ -18,11 +18,11 @@
 #define _UPDATER_UPDATER_H_
 
 #include <stdio.h>
-#include "minzip/Zip.h"
+#include <ziparchive/zip_archive.h>
 
 typedef struct {
     FILE* cmd_pipe;
-    ZipArchive* package_zip;
+    ZipArchiveHandle package_zip;
     int version;
 
     uint8_t* package_zip_addr;
diff --git a/updater/install.cpp b/updater/install.cpp
index d723b38..a41c5db 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -33,6 +33,7 @@
 #include <sys/xattr.h>
 #include <time.h>
 #include <unistd.h>
+#include <utime.h>
 
 #include <memory>
 #include <string>
@@ -48,14 +49,16 @@
 #include <openssl/sha.h>
 #include <selinux/label.h>
 #include <selinux/selinux.h>
+#include <ziparchive/zip_archive.h>
 
 #include "applypatch/applypatch.h"
 #include "bootloader.h"
 #include "edify/expr.h"
 #include "error_code.h"
-#include "minzip/DirUtil.h"
 #include "mounts.h"
 #include "ota_io.h"
+#include "otautil/DirUtil.h"
+#include "otautil/ZipUtil.h"
 #include "print_sha1.h"
 #include "tune2fs.h"
 #include "updater/updater.h"
@@ -465,14 +468,13 @@
     char* dest_path;
     if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
 
-    ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
+    ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
 
     // To create a consistent system image, never use the clock for timestamps.
     struct utimbuf timestamp = { 1217592000, 1217592000 };  // 8/1/2008 default
 
-    bool success = mzExtractRecursive(za, zip_path, dest_path,
-                                      &timestamp,
-                                      NULL, NULL, sehandle);
+    bool success = ExtractPackageRecursive(za, zip_path, dest_path, &timestamp, sehandle);
+
     free(zip_path);
     free(dest_path);
     return StringValue(success ? "t" : "");
@@ -495,14 +497,15 @@
     if (argc == 2) {
         // The two-argument version extracts to a file.
 
-        ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
+        ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
 
         char* zip_path;
         char* dest_path;
         if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
 
-        const ZipEntry* entry = mzFindZipEntry(za, zip_path);
-        if (entry == NULL) {
+        ZipString zip_string_path(zip_path);
+        ZipEntry entry;
+        if (FindEntry(za, zip_string_path, &entry) != 0) {
             printf("%s: no %s in package\n", name, zip_path);
             goto done2;
         }
@@ -514,7 +517,7 @@
                 printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno));
                 goto done2;
             }
-            success = mzExtractZipEntryToFile(za, entry, fd);
+            success = ExtractEntryToFile(za, &entry, fd);
             if (ota_fsync(fd) == -1) {
                 printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno));
                 success = false;
@@ -538,16 +541,21 @@
 
         Value* v = new Value(VAL_INVALID, "");
 
-        ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
-        const ZipEntry* entry = mzFindZipEntry(za, zip_path);
-        if (entry == NULL) {
+        ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
+        ZipString zip_string_path(zip_path);
+        ZipEntry entry;
+        if (FindEntry(za, zip_string_path, &entry) != 0) {
             printf("%s: no %s in package\n", name, zip_path);
             goto done1;
         }
 
-        v->data.resize(mzGetZipEntryUncompLen(entry));
-        success = mzExtractZipEntryToBuffer(za, entry,
-                reinterpret_cast<unsigned char *>(&v->data[0]));
+        v->data.resize(entry.uncompressed_length);
+        if (ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&v->data[0]),
+                            v->data.size()) != 0) {
+            printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size());
+        } else {
+            success = true;
+        }
 
       done1:
         free(zip_path);
diff --git a/updater/updater.cpp b/updater/updater.cpp
index 47696b8..7327c52 100644
--- a/updater/updater.cpp
+++ b/updater/updater.cpp
@@ -21,14 +21,17 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <string>
+
 #include <android-base/strings.h>
 #include <selinux/label.h>
 #include <selinux/selinux.h>
+#include <ziparchive/zip_archive.h>
 
 #include "config.h"
 #include "edify/expr.h"
-#include "minzip/SysUtil.h"
-#include "minzip/Zip.h"
+#include "otautil/DirUtil.h"
+#include "otautil/SysUtil.h"
 #include "updater/blockimg.h"
 #include "updater/install.h"
 
@@ -82,28 +85,35 @@
         printf("failed to map package %s\n", argv[3]);
         return 3;
     }
-    ZipArchive za;
-    int err;
-    err = mzOpenZipArchive(map.addr, map.length, &za);
-    if (err != 0) {
+    ZipArchiveHandle za;
+    int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za);
+    if (open_err != 0) {
         printf("failed to open package %s: %s\n",
-               argv[3], strerror(err));
+               argv[3], ErrorCodeString(open_err));
+        CloseArchive(za);
         return 3;
     }
-    ota_io_init(&za);
+    ota_io_init(za);
 
-    const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
-    if (script_entry == NULL) {
-        printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename);
+    ZipString script_name(SCRIPT_NAME);
+    ZipEntry script_entry;
+    int find_err = FindEntry(za, script_name, &script_entry);
+    if (find_err != 0) {
+        printf("failed to find %s in %s: %s\n", SCRIPT_NAME, package_filename,
+               ErrorCodeString(find_err));
+        CloseArchive(za);
         return 4;
     }
 
-    char* script = reinterpret_cast<char*>(malloc(script_entry->uncompLen+1));
-    if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
-        printf("failed to read script from package\n");
+    std::string script;
+    script.resize(script_entry.uncompressed_length);
+    int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast<uint8_t*>(&script[0]),
+                                      script_entry.uncompressed_length);
+    if (extract_err != 0) {
+        printf("failed to read script from package: %s\n", ErrorCodeString(extract_err));
+        CloseArchive(za);
         return 5;
     }
-    script[script_entry->uncompLen] = '\0';
 
     // Configure edify's functions.
 
@@ -116,9 +126,10 @@
 
     Expr* root;
     int error_count = 0;
-    int error = parse_string(script, &root, &error_count);
+    int error = parse_string(script.c_str(), &root, &error_count);
     if (error != 0 || error_count > 0) {
         printf("%d parse errors\n", error_count);
+        CloseArchive(za);
         return 6;
     }
 
@@ -136,7 +147,7 @@
 
     UpdaterInfo updater_info;
     updater_info.cmd_pipe = cmd_pipe;
-    updater_info.package_zip = &za;
+    updater_info.package_zip = za;
     updater_info.version = atoi(version);
     updater_info.package_zip_addr = map.addr;
     updater_info.package_zip_len = map.length;
@@ -187,16 +198,18 @@
             }
         }
 
+        if (updater_info.package_zip) {
+            CloseArchive(updater_info.package_zip);
+        }
         return 7;
     } else {
         fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str());
     }
 
     if (updater_info.package_zip) {
-        mzCloseZipArchive(updater_info.package_zip);
+        CloseArchive(updater_info.package_zip);
     }
     sysReleaseMap(&map);
-    free(script);
 
     return 0;
 }
diff --git a/verifier.cpp b/verifier.cpp
index 401bd7e..82cdd3b 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -184,7 +184,7 @@
         if (eocd[i  ] == 0x50 && eocd[i+1] == 0x4b &&
             eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
             // if the sequence $50 $4b $05 $06 appears anywhere after
-            // the real one, minzip will find the later (wrong) one,
+            // the real one, libziparchive will find the later (wrong) one,
             // which could be exploitable.  Fail verification if
             // this sequence occurs anywhere after the real one.
             LOG(ERROR) << "EOCD marker occurs after start of EOCD";