From 8cf5c8f60f51049278b08ae4cbc31df397b651fd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 8 Sep 2016 20:10:11 -0700 Subject: Replace minzip with libziparchive Clean up the duplicated codes that handle the zip files in bootable/recovery; and rename the library of the remaining utility functions to libotautil. Test: Update package installed successfully on angler. Bug: 19472796 Change-Id: Iea8962fcf3004473cb0322b6bb3a9ea3ca7f679e --- Android.mk | 5 +- applypatch/Android.mk | 1 - install.cpp | 45 +- minzip/Android.mk | 23 - minzip/Bits.h | 357 ----------- minzip/DirUtil.cpp | 218 ------- minzip/DirUtil.h | 54 -- minzip/Hash.cpp | 378 ------------ minzip/Hash.h | 194 ------ minzip/Inlines.c | 25 - minzip/SysUtil.cpp | 212 ------- minzip/SysUtil.h | 52 -- minzip/Zip.cpp | 1022 ------------------------------- minzip/Zip.h | 171 ------ minzip/inline_magic.h | 26 - otafault/Android.mk | 2 +- otafault/config.cpp | 20 +- otafault/config.h | 4 +- otautil/Android.mk | 35 ++ otautil/DirUtil.cpp | 218 +++++++ otautil/DirUtil.h | 54 ++ otautil/SysUtil.cpp | 212 +++++++ otautil/SysUtil.h | 52 ++ otautil/ZipUtil.cpp | 121 ++++ otautil/ZipUtil.h | 57 ++ recovery.cpp | 3 +- tests/Android.mk | 11 +- tests/component/verifier_test.cpp | 3 +- tests/testdata/ziptest_dummy-update.zip | Bin 0 -> 1090065 bytes tests/testdata/ziptest_valid.zip | Bin 0 -> 758 bytes tests/unit/zip_test.cpp | 93 +++ updater/Android.mk | 4 +- updater/blockimg.cpp | 73 +-- updater/include/updater/updater.h | 4 +- updater/install.cpp | 38 +- updater/updater.cpp | 53 +- verifier.cpp | 2 +- 37 files changed, 984 insertions(+), 2858 deletions(-) delete mode 100644 minzip/Android.mk delete mode 100644 minzip/Bits.h delete mode 100644 minzip/DirUtil.cpp delete mode 100644 minzip/DirUtil.h delete mode 100644 minzip/Hash.cpp delete mode 100644 minzip/Hash.h delete mode 100644 minzip/Inlines.c delete mode 100644 minzip/SysUtil.cpp delete mode 100644 minzip/SysUtil.h delete mode 100644 minzip/Zip.cpp delete mode 100644 minzip/Zip.h delete mode 100644 minzip/inline_magic.h create mode 100644 otautil/Android.mk create mode 100644 otautil/DirUtil.cpp create mode 100644 otautil/DirUtil.h create mode 100644 otautil/SysUtil.cpp create mode 100644 otautil/SysUtil.h create mode 100644 otautil/ZipUtil.cpp create mode 100644 otautil/ZipUtil.h create mode 100644 tests/testdata/ziptest_dummy-update.zip create mode 100644 tests/testdata/ziptest_valid.zip create mode 100644 tests/unit/zip_test.cpp diff --git a/Android.mk b/Android.mk index e502d9e6b..68f069d6a 100644 --- a/Android.mk +++ b/Android.mk @@ -77,7 +77,8 @@ LOCAL_STATIC_LIBRARIES := \ libbatterymonitor \ libext4_utils_static \ libsparse_static \ - libminzip \ + libziparchive \ + libotautil \ libmounts \ libz \ libminadbd \ @@ -150,7 +151,7 @@ LOCAL_CFLAGS := -Werror include $(BUILD_STATIC_LIBRARY) include $(LOCAL_PATH)/minui/Android.mk \ - $(LOCAL_PATH)/minzip/Android.mk \ + $(LOCAL_PATH)/otautil/Android.mk \ $(LOCAL_PATH)/minadbd/Android.mk \ $(LOCAL_PATH)/tests/Android.mk \ $(LOCAL_PATH)/tools/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 72c922d5c..c98715231 100644 --- a/install.cpp +++ b/install.cpp @@ -32,13 +32,13 @@ #include #include #include +#include #include "common.h" #include "error_code.h" #include "install.h" #include "minui/minui.h" -#include "minzip/SysUtil.h" -#include "minzip/Zip.h" +#include "otautil/SysUtil.h" #include "roots.h" #include "ui.h" #include "verifier.h" @@ -72,15 +72,17 @@ static int parse_build_number(const std::string& str) { } // 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& log_buffer) { - const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH); - if (meta_entry == nullptr) { +static void read_source_target_build(ZipArchiveHandle zip, std::vector& log_buffer) { + ZipString metadata_path(METADATA_PATH); + ZipEntry meta_entry; + if (FindEntry(zip, metadata_path, &meta_entry) != 0) { LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package"; return; } - std::string meta_data(meta_entry->uncompLen, '\0'); - if (!mzReadZipEntry(zip, meta_entry, &meta_data[0], meta_entry->uncompLen)) { + std::string meta_data(meta_entry.uncompressed_length, '\0'); + if (ExtractToMemory(zip, &meta_entry, reinterpret_cast(&meta_data[0]), + meta_entry.uncompressed_length) != 0) { LOG(ERROR) << "Failed to read metadata in update package"; return; } @@ -109,15 +111,14 @@ static void read_source_target_build(ZipArchive* zip, std::vector& // 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& log_buffer, int retry_count) { read_source_target_build(zip, log_buffer); - const ZipEntry* binary_entry = - mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); - if (binary_entry == NULL) { - mzCloseZipArchive(zip); + ZipString binary_name(ASSUMED_UPDATE_BINARY_NAME); + ZipEntry binary_entry; + if (FindEntry(zip, binary_name, &binary_entry) != 0) { return INSTALL_CORRUPT; } @@ -126,15 +127,14 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, int fd = creat(binary, 0755); if (fd < 0) { PLOG(ERROR) << "Can't make " << binary; - mzCloseZipArchive(zip); return INSTALL_ERROR; } - bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); + int error = ExtractEntryToFile(zip, &binary_entry, fd); close(fd); - mzCloseZipArchive(zip); - if (!ok) { - LOG(ERROR) << "Can't copy " << ASSUMED_UPDATE_BINARY_NAME; + if (error != 0) { + LOG(ERROR) << "Can't copy " << ASSUMED_UPDATE_BINARY_NAME + << " : " << ErrorCodeString(error); return INSTALL_ERROR; } @@ -326,13 +326,14 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, } // Try to open the package. - ZipArchive zip; - err = mzOpenZipArchive(map.addr, map.length, &zip); + ZipArchiveHandle zip; + err = OpenArchiveFromMemory(map.addr, map.length, path, &zip); if (err != 0) { - LOG(ERROR) << "Can't open " << path; + LOG(ERROR) << "Can't open " << path << " : " << ErrorCodeString(err); log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure)); sysReleaseMap(&map); + CloseArchive(zip); return INSTALL_CORRUPT; } @@ -342,12 +343,12 @@ 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/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 -#include - -/* - * 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/DirUtil.cpp b/minzip/DirUtil.cpp deleted file mode 100644 index e08e360c0..000000000 --- a/minzip/DirUtil.cpp +++ /dev/null @@ -1,218 +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. - */ - -#include "DirUtil.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus; - -static DirStatus -getPathDirStatus(const char *path) -{ - struct stat st; - int err; - - err = stat(path, &st); - if (err == 0) { - /* Something's there; make sure it's a directory. - */ - if (S_ISDIR(st.st_mode)) { - return DDIR; - } - errno = ENOTDIR; - return DILLEGAL; - } else if (errno != ENOENT) { - /* Something went wrong, or something in the path - * is bad. Can't do anything in this situation. - */ - return DILLEGAL; - } - return DMISSING; -} - -int -dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName, - struct selabel_handle *sehnd) -{ - DirStatus ds; - - /* Check for an empty string before we bother - * making any syscalls. - */ - if (path[0] == '\0') { - errno = ENOENT; - return -1; - } - // Allocate a path that we can modify; stick a slash on - // the end to make things easier. - std::string cpath = path; - if (stripFileName) { - // Strip everything after the last slash. - size_t pos = cpath.rfind('/'); - if (pos == std::string::npos) { - errno = ENOENT; - return -1; - } - cpath.resize(pos + 1); - } else { - // Make sure that the path ends in a slash. - cpath.push_back('/'); - } - - /* See if it already exists. - */ - ds = getPathDirStatus(cpath.c_str()); - if (ds == DDIR) { - return 0; - } else if (ds == DILLEGAL) { - return -1; - } - - /* Walk up the path from the root and make each level. - * If a directory already exists, no big deal. - */ - const char *path_start = &cpath[0]; - char *p = &cpath[0]; - while (*p != '\0') { - /* Skip any slashes, watching out for the end of the string. - */ - while (*p != '\0' && *p == '/') { - p++; - } - if (*p == '\0') { - break; - } - - /* Find the end of the next path component. - * We know that we'll see a slash before the NUL, - * because we added it, above. - */ - while (*p != '/') { - p++; - } - *p = '\0'; - - /* Check this part of the path and make a new directory - * if necessary. - */ - ds = getPathDirStatus(path_start); - if (ds == DILLEGAL) { - /* Could happen if some other process/thread is - * messing with the filesystem. - */ - return -1; - } else if (ds == DMISSING) { - int err; - - char *secontext = NULL; - - if (sehnd) { - selabel_lookup(sehnd, &secontext, path_start, mode); - setfscreatecon(secontext); - } - - err = mkdir(path_start, mode); - - if (secontext) { - freecon(secontext); - setfscreatecon(NULL); - } - - if (err != 0) { - return -1; - } - if (timestamp != NULL && utime(path_start, timestamp)) { - return -1; - } - } - // else, this directory already exists. - - // Repair the path and continue. - *p = '/'; - } - return 0; -} - -int -dirUnlinkHierarchy(const char *path) -{ - struct stat st; - DIR *dir; - struct dirent *de; - int fail = 0; - - /* is it a file or directory? */ - if (lstat(path, &st) < 0) { - return -1; - } - - /* a file, so unlink it */ - if (!S_ISDIR(st.st_mode)) { - return unlink(path); - } - - /* a directory, so open handle */ - dir = opendir(path); - if (dir == NULL) { - return -1; - } - - /* recurse over components */ - errno = 0; - while ((de = readdir(dir)) != NULL) { - //TODO: don't blow the stack - char dn[PATH_MAX]; - if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { - continue; - } - snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); - if (dirUnlinkHierarchy(dn) < 0) { - fail = 1; - break; - } - errno = 0; - } - /* in case readdir or unlink_recursive failed */ - if (fail || errno < 0) { - int save = errno; - closedir(dir); - errno = save; - return -1; - } - - /* close directory handle */ - if (closedir(dir) < 0) { - return -1; - } - - /* delete target directory */ - return rmdir(path); -} diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h deleted file mode 100644 index 85b83c387..000000000 --- a/minzip/DirUtil.h +++ /dev/null @@ -1,54 +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_DIRUTIL_H_ -#define MINZIP_DIRUTIL_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct selabel_handle; - -/* Like "mkdir -p", try to guarantee that all directories - * specified in path are present, creating as many directories - * as necessary. The specified mode is passed to all mkdir - * calls; no modifications are made to umask. - * - * If stripFileName is set, everything after the final '/' - * is stripped before creating the directory hierarchy. - * - * If timestamp is non-NULL, new directories will be timestamped accordingly. - * - * Returns 0 on success; returns -1 (and sets errno) on failure - * (usually if some element of path is not a directory). - */ -int dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName, - struct selabel_handle* sehnd); - -/* rm -rf - */ -int dirUnlinkHierarchy(const char *path); - -#ifdef __cplusplus -} -#endif - -#endif // MINZIP_DIRUTIL_H_ 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 -#include - -#include - -#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 -#include -#include - -#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/SysUtil.cpp b/minzip/SysUtil.cpp deleted file mode 100644 index 2936c5ca4..000000000 --- a/minzip/SysUtil.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * System utilities. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "SysUtil.h" - -static bool sysMapFD(int fd, MemMapping* pMap) { - assert(pMap != NULL); - - struct stat sb; - if (fstat(fd, &sb) == -1) { - PLOG(ERROR) << "fstat(" << fd << ") failed"; - return false; - } - - void* memPtr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (memPtr == MAP_FAILED) { - PLOG(ERROR) << "mmap(" << sb.st_size << ", R, PRIVATE, " << fd << ", 0) failed"; - return false; - } - - pMap->addr = reinterpret_cast(memPtr); - pMap->length = sb.st_size; - pMap->range_count = 1; - pMap->ranges = reinterpret_cast(malloc(sizeof(MappedRange))); - if (pMap->ranges == NULL) { - PLOG(ERROR) << "malloc failed"; - munmap(memPtr, sb.st_size); - return false; - } - pMap->ranges[0].addr = memPtr; - pMap->ranges[0].length = sb.st_size; - - return true; -} - -static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) -{ - char block_dev[PATH_MAX+1]; - size_t size; - unsigned int blksize; - size_t blocks; - unsigned int range_count; - unsigned int i; - - if (fgets(block_dev, sizeof(block_dev), mapf) == NULL) { - PLOG(ERROR) << "failed to read block device from header"; - return -1; - } - for (i = 0; i < sizeof(block_dev); ++i) { - if (block_dev[i] == '\n') { - block_dev[i] = 0; - break; - } - } - - if (fscanf(mapf, "%zu %u\n%u\n", &size, &blksize, &range_count) != 3) { - LOG(ERROR) << "failed to parse block map header"; - return -1; - } - if (blksize != 0) { - blocks = ((size-1) / blksize) + 1; - } - if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0) { - LOG(ERROR) << "invalid data in block map file: size " << size << ", blksize " << blksize - << ", range_count " << range_count; - return -1; - } - - pMap->range_count = range_count; - pMap->ranges = reinterpret_cast(calloc(range_count, sizeof(MappedRange))); - if (pMap->ranges == NULL) { - PLOG(ERROR) << "calloc(" << range_count << ", " << sizeof(MappedRange) << ") failed"; - return -1; - } - - // Reserve enough contiguous address space for the whole file. - unsigned char* reserve = reinterpret_cast(mmap64(NULL, blocks * blksize, - PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0)); - if (reserve == MAP_FAILED) { - PLOG(ERROR) << "failed to reserve address space"; - free(pMap->ranges); - return -1; - } - - int fd = open(block_dev, O_RDONLY); - if (fd < 0) { - PLOG(ERROR) << "failed to open block device " << block_dev; - munmap(reserve, blocks * blksize); - free(pMap->ranges); - return -1; - } - - unsigned char* next = reserve; - size_t remaining_size = blocks * blksize; - bool success = true; - for (i = 0; i < range_count; ++i) { - size_t start, end; - if (fscanf(mapf, "%zu %zu\n", &start, &end) != 2) { - LOG(ERROR) << "failed to parse range " << i << " in block map"; - success = false; - break; - } - size_t length = (end - start) * blksize; - if (end <= start || (end - start) > SIZE_MAX / blksize || length > remaining_size) { - LOG(ERROR) << "unexpected range in block map: " << start << " " << end; - success = false; - break; - } - - void* addr = mmap64(next, length, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize); - if (addr == MAP_FAILED) { - PLOG(ERROR) << "failed to map block " << i; - success = false; - break; - } - pMap->ranges[i].addr = addr; - pMap->ranges[i].length = length; - - next += length; - remaining_size -= length; - } - if (success && remaining_size != 0) { - LOG(ERROR) << "ranges in block map are invalid: remaining_size = " << remaining_size; - success = false; - } - if (!success) { - close(fd); - munmap(reserve, blocks * blksize); - free(pMap->ranges); - return -1; - } - - close(fd); - pMap->addr = reserve; - pMap->length = size; - - LOG(INFO) << "mmapped " << range_count << " ranges"; - - return 0; -} - -int sysMapFile(const char* fn, MemMapping* pMap) -{ - memset(pMap, 0, sizeof(*pMap)); - - if (fn && fn[0] == '@') { - // A map of blocks - FILE* mapf = fopen(fn+1, "r"); - if (mapf == NULL) { - PLOG(ERROR) << "Unable to open '" << (fn+1) << "'"; - return -1; - } - - if (sysMapBlockFile(mapf, pMap) != 0) { - LOG(ERROR) << "Map of '" << fn << "' failed"; - fclose(mapf); - return -1; - } - - fclose(mapf); - } else { - // This is a regular file. - int fd = open(fn, O_RDONLY); - if (fd == -1) { - PLOG(ERROR) << "Unable to open '" << fn << "'"; - return -1; - } - - if (!sysMapFD(fd, pMap)) { - LOG(ERROR) << "Map of '" << fn << "' failed"; - close(fd); - return -1; - } - - close(fd); - } - return 0; -} - -/* - * Release a memory mapping. - */ -void sysReleaseMap(MemMapping* pMap) -{ - int i; - for (i = 0; i < pMap->range_count; ++i) { - if (munmap(pMap->ranges[i].addr, pMap->ranges[i].length) < 0) { - PLOG(ERROR) << "munmap(" << pMap->ranges[i].addr << ", " << pMap->ranges[i].length - << ") failed"; - } - } - free(pMap->ranges); - pMap->ranges = NULL; - pMap->range_count = 0; -} diff --git a/minzip/SysUtil.h b/minzip/SysUtil.h deleted file mode 100644 index 7adff1e54..000000000 --- a/minzip/SysUtil.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * System utilities. - */ -#ifndef _MINZIP_SYSUTIL -#define _MINZIP_SYSUTIL - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct MappedRange { - void* addr; - size_t length; -} MappedRange; - -/* - * Use this to keep track of mapped segments. - */ -typedef struct MemMapping { - unsigned char* addr; /* start of data */ - size_t length; /* length of data */ - - int range_count; - MappedRange* ranges; -} MemMapping; - -/* - * Map a file into a private, read-only memory segment. If 'fn' - * begins with an '@' character, it is a map of blocks to be mapped, - * otherwise it is treated as an ordinary file. - * - * On success, "pMap" is filled in, and zero is returned. - */ -int sysMapFile(const char* fn, MemMapping* pMap); - -/* - * Release the pages associated with a shared memory segment. - * - * This does not free "pMap"; it just releases the memory. - */ -void sysReleaseMap(MemMapping* pMap); - -#ifdef __cplusplus -} -#endif - -#endif /*_MINZIP_SYSUTIL*/ 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 -#include -#include -#include // for uintptr_t -#include -#include // for S_ISLNK() -#include - -#include - -#include -#include -#include -#include -#include - -#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 -#include - -#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 #include +#include -#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 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(&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 -#include "minzip/Zip.h" +#include #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/otautil/DirUtil.cpp b/otautil/DirUtil.cpp new file mode 100644 index 000000000..e08e360c0 --- /dev/null +++ b/otautil/DirUtil.cpp @@ -0,0 +1,218 @@ +/* + * 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. + */ + +#include "DirUtil.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus; + +static DirStatus +getPathDirStatus(const char *path) +{ + struct stat st; + int err; + + err = stat(path, &st); + if (err == 0) { + /* Something's there; make sure it's a directory. + */ + if (S_ISDIR(st.st_mode)) { + return DDIR; + } + errno = ENOTDIR; + return DILLEGAL; + } else if (errno != ENOENT) { + /* Something went wrong, or something in the path + * is bad. Can't do anything in this situation. + */ + return DILLEGAL; + } + return DMISSING; +} + +int +dirCreateHierarchy(const char *path, int mode, + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle *sehnd) +{ + DirStatus ds; + + /* Check for an empty string before we bother + * making any syscalls. + */ + if (path[0] == '\0') { + errno = ENOENT; + return -1; + } + // Allocate a path that we can modify; stick a slash on + // the end to make things easier. + std::string cpath = path; + if (stripFileName) { + // Strip everything after the last slash. + size_t pos = cpath.rfind('/'); + if (pos == std::string::npos) { + errno = ENOENT; + return -1; + } + cpath.resize(pos + 1); + } else { + // Make sure that the path ends in a slash. + cpath.push_back('/'); + } + + /* See if it already exists. + */ + ds = getPathDirStatus(cpath.c_str()); + if (ds == DDIR) { + return 0; + } else if (ds == DILLEGAL) { + return -1; + } + + /* Walk up the path from the root and make each level. + * If a directory already exists, no big deal. + */ + const char *path_start = &cpath[0]; + char *p = &cpath[0]; + while (*p != '\0') { + /* Skip any slashes, watching out for the end of the string. + */ + while (*p != '\0' && *p == '/') { + p++; + } + if (*p == '\0') { + break; + } + + /* Find the end of the next path component. + * We know that we'll see a slash before the NUL, + * because we added it, above. + */ + while (*p != '/') { + p++; + } + *p = '\0'; + + /* Check this part of the path and make a new directory + * if necessary. + */ + ds = getPathDirStatus(path_start); + if (ds == DILLEGAL) { + /* Could happen if some other process/thread is + * messing with the filesystem. + */ + return -1; + } else if (ds == DMISSING) { + int err; + + char *secontext = NULL; + + if (sehnd) { + selabel_lookup(sehnd, &secontext, path_start, mode); + setfscreatecon(secontext); + } + + err = mkdir(path_start, mode); + + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } + + if (err != 0) { + return -1; + } + if (timestamp != NULL && utime(path_start, timestamp)) { + return -1; + } + } + // else, this directory already exists. + + // Repair the path and continue. + *p = '/'; + } + return 0; +} + +int +dirUnlinkHierarchy(const char *path) +{ + struct stat st; + DIR *dir; + struct dirent *de; + int fail = 0; + + /* is it a file or directory? */ + if (lstat(path, &st) < 0) { + return -1; + } + + /* a file, so unlink it */ + if (!S_ISDIR(st.st_mode)) { + return unlink(path); + } + + /* a directory, so open handle */ + dir = opendir(path); + if (dir == NULL) { + return -1; + } + + /* recurse over components */ + errno = 0; + while ((de = readdir(dir)) != NULL) { + //TODO: don't blow the stack + char dn[PATH_MAX]; + if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { + continue; + } + snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); + if (dirUnlinkHierarchy(dn) < 0) { + fail = 1; + break; + } + errno = 0; + } + /* in case readdir or unlink_recursive failed */ + if (fail || errno < 0) { + int save = errno; + closedir(dir); + errno = save; + return -1; + } + + /* close directory handle */ + if (closedir(dir) < 0) { + return -1; + } + + /* delete target directory */ + return rmdir(path); +} diff --git a/otautil/DirUtil.h b/otautil/DirUtil.h new file mode 100644 index 000000000..85b83c387 --- /dev/null +++ b/otautil/DirUtil.h @@ -0,0 +1,54 @@ +/* + * 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_DIRUTIL_H_ +#define MINZIP_DIRUTIL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct selabel_handle; + +/* Like "mkdir -p", try to guarantee that all directories + * specified in path are present, creating as many directories + * as necessary. The specified mode is passed to all mkdir + * calls; no modifications are made to umask. + * + * If stripFileName is set, everything after the final '/' + * is stripped before creating the directory hierarchy. + * + * If timestamp is non-NULL, new directories will be timestamped accordingly. + * + * Returns 0 on success; returns -1 (and sets errno) on failure + * (usually if some element of path is not a directory). + */ +int dirCreateHierarchy(const char *path, int mode, + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle* sehnd); + +/* rm -rf + */ +int dirUnlinkHierarchy(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif // MINZIP_DIRUTIL_H_ diff --git a/otautil/SysUtil.cpp b/otautil/SysUtil.cpp new file mode 100644 index 000000000..2936c5ca4 --- /dev/null +++ b/otautil/SysUtil.cpp @@ -0,0 +1,212 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * System utilities. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "SysUtil.h" + +static bool sysMapFD(int fd, MemMapping* pMap) { + assert(pMap != NULL); + + struct stat sb; + if (fstat(fd, &sb) == -1) { + PLOG(ERROR) << "fstat(" << fd << ") failed"; + return false; + } + + void* memPtr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (memPtr == MAP_FAILED) { + PLOG(ERROR) << "mmap(" << sb.st_size << ", R, PRIVATE, " << fd << ", 0) failed"; + return false; + } + + pMap->addr = reinterpret_cast(memPtr); + pMap->length = sb.st_size; + pMap->range_count = 1; + pMap->ranges = reinterpret_cast(malloc(sizeof(MappedRange))); + if (pMap->ranges == NULL) { + PLOG(ERROR) << "malloc failed"; + munmap(memPtr, sb.st_size); + return false; + } + pMap->ranges[0].addr = memPtr; + pMap->ranges[0].length = sb.st_size; + + return true; +} + +static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) +{ + char block_dev[PATH_MAX+1]; + size_t size; + unsigned int blksize; + size_t blocks; + unsigned int range_count; + unsigned int i; + + if (fgets(block_dev, sizeof(block_dev), mapf) == NULL) { + PLOG(ERROR) << "failed to read block device from header"; + return -1; + } + for (i = 0; i < sizeof(block_dev); ++i) { + if (block_dev[i] == '\n') { + block_dev[i] = 0; + break; + } + } + + if (fscanf(mapf, "%zu %u\n%u\n", &size, &blksize, &range_count) != 3) { + LOG(ERROR) << "failed to parse block map header"; + return -1; + } + if (blksize != 0) { + blocks = ((size-1) / blksize) + 1; + } + if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0) { + LOG(ERROR) << "invalid data in block map file: size " << size << ", blksize " << blksize + << ", range_count " << range_count; + return -1; + } + + pMap->range_count = range_count; + pMap->ranges = reinterpret_cast(calloc(range_count, sizeof(MappedRange))); + if (pMap->ranges == NULL) { + PLOG(ERROR) << "calloc(" << range_count << ", " << sizeof(MappedRange) << ") failed"; + return -1; + } + + // Reserve enough contiguous address space for the whole file. + unsigned char* reserve = reinterpret_cast(mmap64(NULL, blocks * blksize, + PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0)); + if (reserve == MAP_FAILED) { + PLOG(ERROR) << "failed to reserve address space"; + free(pMap->ranges); + return -1; + } + + int fd = open(block_dev, O_RDONLY); + if (fd < 0) { + PLOG(ERROR) << "failed to open block device " << block_dev; + munmap(reserve, blocks * blksize); + free(pMap->ranges); + return -1; + } + + unsigned char* next = reserve; + size_t remaining_size = blocks * blksize; + bool success = true; + for (i = 0; i < range_count; ++i) { + size_t start, end; + if (fscanf(mapf, "%zu %zu\n", &start, &end) != 2) { + LOG(ERROR) << "failed to parse range " << i << " in block map"; + success = false; + break; + } + size_t length = (end - start) * blksize; + if (end <= start || (end - start) > SIZE_MAX / blksize || length > remaining_size) { + LOG(ERROR) << "unexpected range in block map: " << start << " " << end; + success = false; + break; + } + + void* addr = mmap64(next, length, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize); + if (addr == MAP_FAILED) { + PLOG(ERROR) << "failed to map block " << i; + success = false; + break; + } + pMap->ranges[i].addr = addr; + pMap->ranges[i].length = length; + + next += length; + remaining_size -= length; + } + if (success && remaining_size != 0) { + LOG(ERROR) << "ranges in block map are invalid: remaining_size = " << remaining_size; + success = false; + } + if (!success) { + close(fd); + munmap(reserve, blocks * blksize); + free(pMap->ranges); + return -1; + } + + close(fd); + pMap->addr = reserve; + pMap->length = size; + + LOG(INFO) << "mmapped " << range_count << " ranges"; + + return 0; +} + +int sysMapFile(const char* fn, MemMapping* pMap) +{ + memset(pMap, 0, sizeof(*pMap)); + + if (fn && fn[0] == '@') { + // A map of blocks + FILE* mapf = fopen(fn+1, "r"); + if (mapf == NULL) { + PLOG(ERROR) << "Unable to open '" << (fn+1) << "'"; + return -1; + } + + if (sysMapBlockFile(mapf, pMap) != 0) { + LOG(ERROR) << "Map of '" << fn << "' failed"; + fclose(mapf); + return -1; + } + + fclose(mapf); + } else { + // This is a regular file. + int fd = open(fn, O_RDONLY); + if (fd == -1) { + PLOG(ERROR) << "Unable to open '" << fn << "'"; + return -1; + } + + if (!sysMapFD(fd, pMap)) { + LOG(ERROR) << "Map of '" << fn << "' failed"; + close(fd); + return -1; + } + + close(fd); + } + return 0; +} + +/* + * Release a memory mapping. + */ +void sysReleaseMap(MemMapping* pMap) +{ + int i; + for (i = 0; i < pMap->range_count; ++i) { + if (munmap(pMap->ranges[i].addr, pMap->ranges[i].length) < 0) { + PLOG(ERROR) << "munmap(" << pMap->ranges[i].addr << ", " << pMap->ranges[i].length + << ") failed"; + } + } + free(pMap->ranges); + pMap->ranges = NULL; + pMap->range_count = 0; +} diff --git a/otautil/SysUtil.h b/otautil/SysUtil.h new file mode 100644 index 000000000..7adff1e54 --- /dev/null +++ b/otautil/SysUtil.h @@ -0,0 +1,52 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * System utilities. + */ +#ifndef _MINZIP_SYSUTIL +#define _MINZIP_SYSUTIL + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappedRange { + void* addr; + size_t length; +} MappedRange; + +/* + * Use this to keep track of mapped segments. + */ +typedef struct MemMapping { + unsigned char* addr; /* start of data */ + size_t length; /* length of data */ + + int range_count; + MappedRange* ranges; +} MemMapping; + +/* + * Map a file into a private, read-only memory segment. If 'fn' + * begins with an '@' character, it is a map of blocks to be mapped, + * otherwise it is treated as an ordinary file. + * + * On success, "pMap" is filled in, and zero is returned. + */ +int sysMapFile(const char* fn, MemMapping* pMap); + +/* + * Release the pages associated with a shared memory segment. + * + * This does not free "pMap"; it just releases the memory. + */ +void sysReleaseMap(MemMapping* pMap); + +#ifdef __cplusplus +} +#endif + +#endif /*_MINZIP_SYSUTIL*/ 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 +#include +#include + +#include + +#include +#include +#include +#include +#include + +#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 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 + +#include + +#include +#include + +/* + * 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 9cf63c420..668ef3ca6 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -52,6 +52,7 @@ #include /* private pmsg functions */ #include #include +#include #include "adb_install.h" #include "bootloader.h" @@ -63,7 +64,7 @@ #include "install.h" #include "minadbd/minadbd.h" #include "minui/minui.h" -#include "minzip/DirUtil.h" +#include "otautil/DirUtil.h" #include "roots.h" #include "ui.h" #include "screen_ui.h" 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 #include +#include #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 Binary files /dev/null and b/tests/testdata/ziptest_dummy-update.zip differ diff --git a/tests/testdata/ziptest_valid.zip b/tests/testdata/ziptest_valid.zip new file mode 100644 index 000000000..9e7cb7800 Binary files /dev/null and b/tests/testdata/ziptest_valid.zip 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static const std::string DATA_PATH(getenv("ANDROID_DATA")); +static const std::string TESTDATA_PATH("/recovery/testdata/"); + +static const std::vector kATxtContents { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + '\n' +}; + +static const std::vector 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 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 #include -#include #include #include +#include #include #include #include #include +#include #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 stash_map; +static std::unordered_map 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(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 cmdht_holder(cmdht, mzHashTableFree); - + // Build a map of the available commands + std::unordered_map 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(mzHashTableLookup(cmdht, cmdhash, - const_cast(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 -#include "minzip/Zip.h" +#include 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 #include #include +#include #include #include @@ -48,14 +49,16 @@ #include #include #include +#include #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, - ×tamp, - NULL, NULL, sehandle); + bool success = ExtractPackageRecursive(za, zip_path, dest_path, ×tamp, 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(&v->data[0])); + v->data.resize(entry.uncompressed_length); + if (ExtractToMemory(za, &entry, reinterpret_cast(&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 #include +#include + #include #include #include +#include #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(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(&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"; -- cgit v1.2.3