summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTianjie Xu <xunchang@google.com>2016-10-18 23:13:07 +0200
committerTianjie Xu <xunchang@google.com>2016-10-18 23:31:04 +0200
commit8176cf232e9f613a2e500f09461fc3f448267d07 (patch)
tree7bef9898660d13fc74dbe528bc0331950fe19604
parentMerge "Change StringValue to use std::string" (diff)
parentMerge "Replace minzip with libziparchive" (diff)
downloadandroid_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.tar
android_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.tar.gz
android_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.tar.bz2
android_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.tar.lz
android_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.tar.xz
android_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.tar.zst
android_bootable_recovery-8176cf232e9f613a2e500f09461fc3f448267d07.zip
-rw-r--r--Android.mk5
-rw-r--r--applypatch/Android.mk1
-rw-r--r--install.cpp79
-rw-r--r--install.h4
-rw-r--r--minzip/Android.mk23
-rw-r--r--minzip/Bits.h357
-rw-r--r--minzip/Hash.cpp378
-rw-r--r--minzip/Hash.h194
-rw-r--r--minzip/Inlines.c25
-rw-r--r--minzip/Zip.cpp1022
-rw-r--r--minzip/Zip.h171
-rw-r--r--minzip/inline_magic.h26
-rw-r--r--otafault/Android.mk2
-rw-r--r--otafault/config.cpp20
-rw-r--r--otafault/config.h4
-rw-r--r--otautil/Android.mk35
-rw-r--r--otautil/DirUtil.cpp (renamed from minzip/DirUtil.cpp)0
-rw-r--r--otautil/DirUtil.h (renamed from minzip/DirUtil.h)0
-rw-r--r--otautil/SysUtil.cpp (renamed from minzip/SysUtil.cpp)0
-rw-r--r--otautil/SysUtil.h (renamed from minzip/SysUtil.h)0
-rw-r--r--otautil/ZipUtil.cpp121
-rw-r--r--otautil/ZipUtil.h57
-rw-r--r--recovery.cpp16
-rw-r--r--tests/Android.mk11
-rw-r--r--tests/component/verifier_test.cpp3
-rw-r--r--tests/testdata/ziptest_dummy-update.zipbin0 -> 1090065 bytes
-rw-r--r--tests/testdata/ziptest_valid.zipbin0 -> 758 bytes
-rw-r--r--tests/unit/zip_test.cpp93
-rw-r--r--updater/Android.mk4
-rw-r--r--updater/blockimg.cpp73
-rw-r--r--updater/include/updater/updater.h4
-rw-r--r--updater/install.cpp38
-rw-r--r--updater/updater.cpp53
-rw-r--r--verifier.cpp2
34 files changed, 476 insertions, 2345 deletions
diff --git a/Android.mk b/Android.mk
index 363f2df10..dbc5603d8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -77,7 +77,8 @@ LOCAL_STATIC_LIBRARIES := \
libbootloader_message \
libext4_utils_static \
libsparse_static \
- libminzip \
+ libziparchive \
+ libotautil \
libmounts \
libz \
libminadbd \
@@ -155,8 +156,8 @@ include \
$(LOCAL_PATH)/edify/Android.mk \
$(LOCAL_PATH)/minadbd/Android.mk \
$(LOCAL_PATH)/minui/Android.mk \
- $(LOCAL_PATH)/minzip/Android.mk \
$(LOCAL_PATH)/otafault/Android.mk \
+ $(LOCAL_PATH)/otautil/Android.mk \
$(LOCAL_PATH)/tests/Android.mk \
$(LOCAL_PATH)/tools/Android.mk \
$(LOCAL_PATH)/uncrypt/Android.mk \
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 77e499ec6..9bbac4410 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -80,7 +80,6 @@ LOCAL_STATIC_LIBRARIES += \
libbase \
libedify \
libotafault \
- libminzip \
libcrypto \
libbz
LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc
diff --git a/install.cpp b/install.cpp
index 83ddc4b0c..fada2de66 100644
--- a/install.cpp
+++ b/install.cpp
@@ -36,14 +36,13 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
-#include <android-base/logging.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"
@@ -78,15 +77,21 @@ static int parse_build_number(const std::string& str) {
return -1;
}
-bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data) {
- const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH);
- if (meta_entry == nullptr) {
+bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data) {
+ ZipString metadata_path(METADATA_PATH);
+ ZipEntry meta_entry;
+ if (meta_data == nullptr) {
+ LOG(ERROR) << "string* meta_data can't be nullptr";
+ return false;
+ }
+ if (FindEntry(zip, metadata_path, &meta_entry) != 0) {
LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package";
return false;
}
- meta_data->resize(meta_entry->uncompLen, '\0');
- if (!mzReadZipEntry(zip, meta_entry, &(*meta_data)[0], meta_entry->uncompLen)) {
+ meta_data->resize(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 false;
}
@@ -94,7 +99,7 @@ bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data) {
}
// 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) {
+static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::string>& log_buffer) {
std::string meta_data;
if (!read_metadata_from_package(zip, &meta_data)) {
return;
@@ -126,7 +131,7 @@ static void read_source_target_build(ZipArchive* zip, std::vector<std::string>&
// is the file descriptor the child process should use to report back the
// progress of the update.
static int
-update_binary_command(const char* path, ZipArchive* zip, int retry_count,
+update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
int status_fd, std::vector<std::string>* cmd);
#ifdef AB_OTA_UPDATER
@@ -134,7 +139,7 @@ update_binary_command(const char* path, ZipArchive* zip, int retry_count,
// Parses the metadata of the OTA package in |zip| and checks whether we are
// allowed to accept this A/B package. Downgrading is not allowed unless
// explicitly enabled in the package and only for incremental packages.
-static int check_newer_ab_build(ZipArchive* zip)
+static int check_newer_ab_build(ZipArchiveHandle zip)
{
std::string metadata_str;
if (!read_metadata_from_package(zip, &metadata_str)) {
@@ -212,7 +217,7 @@ static int check_newer_ab_build(ZipArchive* zip)
}
static int
-update_binary_command(const char* path, ZipArchive* zip, int retry_count,
+update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
int status_fd, std::vector<std::string>* cmd)
{
int ret = check_newer_ab_build(zip);
@@ -222,26 +227,27 @@ update_binary_command(const char* path, ZipArchive* zip, int retry_count,
// For A/B updates we extract the payload properties to a buffer and obtain
// the RAW payload offset in the zip file.
- const ZipEntry* properties_entry =
- mzFindZipEntry(zip, AB_OTA_PAYLOAD_PROPERTIES);
- if (!properties_entry) {
+ ZipString property_name(AB_OTA_PAYLOAD_PROPERTIES);
+ ZipEntry properties_entry;
+ if (FindEntry(zip, property_name, &properties_entry) != 0) {
LOG(ERROR) << "Can't find " << AB_OTA_PAYLOAD_PROPERTIES;
return INSTALL_CORRUPT;
}
- std::vector<unsigned char> payload_properties(
- mzGetZipEntryUncompLen(properties_entry));
- if (!mzExtractZipEntryToBuffer(zip, properties_entry,
- payload_properties.data())) {
+ std::vector<uint8_t> payload_properties(
+ properties_entry.uncompressed_length);
+ if (ExtractToMemory(zip, &properties_entry, payload_properties.data(),
+ properties_entry.uncompressed_length) != 0) {
LOG(ERROR) << "Can't extract " << AB_OTA_PAYLOAD_PROPERTIES;
return INSTALL_CORRUPT;
}
- const ZipEntry* payload_entry = mzFindZipEntry(zip, AB_OTA_PAYLOAD);
- if (!payload_entry) {
+ ZipString payload_name(AB_OTA_PAYLOAD);
+ ZipEntry payload_entry;
+ if (FindEntry(zip, payload_name, &payload_entry) != 0) {
LOG(ERROR) << "Can't find " << AB_OTA_PAYLOAD;
return INSTALL_CORRUPT;
}
- long payload_offset = mzGetZipEntryOffset(payload_entry);
+ long payload_offset = payload_entry.offset;
*cmd = {
"/sbin/update_engine_sideload",
android::base::StringPrintf("--payload=file://%s", path),
@@ -256,13 +262,13 @@ update_binary_command(const char* path, ZipArchive* zip, int retry_count,
#else // !AB_OTA_UPDATER
static int
-update_binary_command(const char* path, ZipArchive* zip, int retry_count,
+update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
int status_fd, std::vector<std::string>* cmd)
{
// On traditional updates we extract the update binary from the package.
- const ZipEntry* binary_entry =
- mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
- if (binary_entry == NULL) {
+ ZipString binary_name(ASSUMED_UPDATE_BINARY_NAME);
+ ZipEntry binary_entry;
+ if (FindEntry(zip, binary_name, &binary_entry) != 0) {
return INSTALL_CORRUPT;
}
@@ -273,11 +279,12 @@ update_binary_command(const char* path, ZipArchive* zip, int retry_count,
PLOG(ERROR) << "Can't make " << binary;
return INSTALL_ERROR;
}
- bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
+ int error = ExtractEntryToFile(zip, &binary_entry, fd);
close(fd);
- 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;
}
@@ -295,7 +302,7 @@ update_binary_command(const char* path, ZipArchive* zip, int retry_count,
// 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);
@@ -305,7 +312,6 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
std::vector<std::string> args;
int ret = update_binary_command(path, zip, retry_count, pipefd[1], &args);
- mzCloseZipArchive(zip);
if (ret) {
close(pipefd[0]);
close(pipefd[1]);
@@ -485,13 +491,14 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
}
// Try to open the package.
- ZipArchive zip;
- int err = mzOpenZipArchive(map.addr, map.length, &zip);
+ ZipArchiveHandle zip;
+ int 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;
}
@@ -501,12 +508,12 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
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/install.h b/install.h
index 14de22556..7f66a51ca 100644
--- a/install.h
+++ b/install.h
@@ -18,9 +18,9 @@
#define RECOVERY_INSTALL_H_
#include <string>
+#include <ziparchive/zip_archive.h>
#include "common.h"
-#include "minzip/Zip.h"
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED,
INSTALL_RETRY };
@@ -36,6 +36,6 @@ bool verify_package(const unsigned char* package_data, size_t package_size);
// Read meta data file of the package, write its content in the string pointed by meta_data.
// Return true if succeed, otherwise return false.
-bool read_metadata_from_package(ZipArchive* zip, std::string* meta_data);
+bool read_metadata_from_package(ZipArchiveHandle zip, std::string* meta_data);
#endif // RECOVERY_INSTALL_H_
diff --git a/minzip/Android.mk b/minzip/Android.mk
deleted file mode 100644
index 6dbfee993..000000000
--- 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 f96e6c443..000000000
--- 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 ac08935d4..000000000
--- 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 e83eac414..000000000
--- 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 91f87751d..000000000
--- 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 b887b8466..000000000
--- 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 c932c1178..000000000
--- 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 59c659f77..000000000
--- 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 82c267101..71c2c62f6 100644
--- a/otafault/Android.mk
+++ b/otafault/Android.mk
@@ -17,7 +17,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
otafault_static_libs := \
- libminzip \
+ libziparchive \
libz \
libselinux \
libbase \
diff --git a/otafault/config.cpp b/otafault/config.cpp
index b4567392d..ee4ef8911 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 @@ bool should_fault_inject(const char* io_type) {
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 fault_fname(const char* io_type) {
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 4430be3fb..c048617c2 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 000000000..3acfa533e
--- /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
index e08e360c0..e08e360c0 100644
--- a/minzip/DirUtil.cpp
+++ b/otautil/DirUtil.cpp
diff --git a/minzip/DirUtil.h b/otautil/DirUtil.h
index 85b83c387..85b83c387 100644
--- a/minzip/DirUtil.h
+++ b/otautil/DirUtil.h
diff --git a/minzip/SysUtil.cpp b/otautil/SysUtil.cpp
index 4cdd60d9f..4cdd60d9f 100644
--- a/minzip/SysUtil.cpp
+++ b/otautil/SysUtil.cpp
diff --git a/minzip/SysUtil.h b/otautil/SysUtil.h
index 7adff1e54..7adff1e54 100644
--- a/minzip/SysUtil.h
+++ b/otautil/SysUtil.h
diff --git a/otautil/ZipUtil.cpp b/otautil/ZipUtil.cpp
new file mode 100644
index 000000000..714c956ed
--- /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 000000000..cda405c2a
--- /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 3b1305e61..88c77d2f8 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -53,6 +53,7 @@
#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 "common.h"
@@ -63,8 +64,7 @@
#include "install.h"
#include "minadbd/minadbd.h"
#include "minui/minui.h"
-#include "minzip/DirUtil.h"
-#include "minzip/Zip.h"
+#include "otautil/DirUtil.h"
#include "roots.h"
#include "ui.h"
#include "screen_ui.h"
@@ -936,19 +936,19 @@ static bool check_wipe_package(size_t wipe_package_size) {
}
// Extract metadata
- ZipArchive zip;
- int err = mzOpenZipArchive(reinterpret_cast<unsigned char*>(&wipe_package[0]),
- wipe_package.size(), &zip);
+ ZipArchiveHandle zip;
+ int err = OpenArchiveFromMemory(reinterpret_cast<void*>(&wipe_package[0]),
+ wipe_package.size(), "wipe_package", &zip);
if (err != 0) {
- LOG(ERROR) << "Can't open wipe package";
+ LOG(ERROR) << "Can't open wipe package : " << ErrorCodeString(err);
return false;
}
std::string metadata;
if (!read_metadata_from_package(&zip, &metadata)) {
- mzCloseZipArchive(&zip);
+ CloseArchive(zip);
return false;
}
- mzCloseZipArchive(&zip);
+ CloseArchive(zip);
// Check metadata
std::vector<std::string> lines = android::base::Split(metadata, "\n");
diff --git a/tests/Android.mk b/tests/Android.mk
index ef822d1d1..abe6b6d68 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -24,11 +24,18 @@ LOCAL_MODULE := recovery_unit_test
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 @@ LOCAL_STATIC_LIBRARIES := \
libupdater \
libverifier \
libminui \
- libminzip \
+ libotautil \
libmounts \
liblog \
libselinux \
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 6a3eebf29..7f9a71408 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 000000000..6976bf155
--- /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 000000000..9e7cb7800
--- /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 000000000..b617446b8
--- /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/updater/Android.mk b/updater/Android.mk
index 33e97385e..3c1d0d41f 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -25,7 +25,9 @@ tune2fs_static_libraries := \
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 5f9b437fe..f08ca5b0c 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 @@ struct RangeSet {
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 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
// rss and signals the condition again.
struct NewThreadInfo {
- ZipArchive* za;
- const ZipEntry* entry;
+ ZipArchiveHandle za;
+ ZipEntry entry;
RangeSinkState* rss;
@@ -309,7 +309,7 @@ struct NewThreadInfo {
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 bool receive_new_data(const unsigned char* data, int size, void* cookie)
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 @@ struct Command {
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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
}
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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
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 d3a09b93d..f4a2fe874 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 d723b3880..a41c5db3c 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 @@ Value* PackageExtractDirFn(const char* name, State* state,
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 @@ Value* PackageExtractFileFn(const char* name, State* state,
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 @@ Value* PackageExtractFileFn(const char* name, State* state,
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* PackageExtractFileFn(const char* name, State* state,
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 47696b80c..7327c52e3 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 @@ int main(int argc, char** argv) {
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);
-
- const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
- if (script_entry == NULL) {
- printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename);
+ ota_io_init(za);
+
+ 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 @@ int main(int argc, char** argv) {
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 @@ int main(int argc, char** argv) {
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 @@ int main(int argc, char** argv) {
}
}
+ 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 401bd7e3e..82cdd3bc7 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -184,7 +184,7 @@ int verify_file(unsigned char* addr, size_t length,
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";