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
This commit is contained in:
parent
2b17b24ae5
commit
8cf5c8f60f
33 changed files with 447 additions and 2321 deletions
|
@ -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 \
|
||||
|
|
|
@ -80,7 +80,6 @@ LOCAL_STATIC_LIBRARIES += \
|
|||
libbase \
|
||||
libedify \
|
||||
libotafault \
|
||||
libminzip \
|
||||
libcrypto \
|
||||
libbz
|
||||
LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc
|
||||
|
|
45
install.cpp
45
install.cpp
|
@ -32,13 +32,13 @@
|
|||
#include <android-base/parseint.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "error_code.h"
|
||||
#include "install.h"
|
||||
#include "minui/minui.h"
|
||||
#include "minzip/SysUtil.h"
|
||||
#include "minzip/Zip.h"
|
||||
#include "otautil/SysUtil.h"
|
||||
#include "roots.h"
|
||||
#include "ui.h"
|
||||
#include "verifier.h"
|
||||
|
@ -72,15 +72,17 @@ 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<std::string>& log_buffer) {
|
||||
const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH);
|
||||
if (meta_entry == nullptr) {
|
||||
static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::string>& log_buffer) {
|
||||
ZipString metadata_path(METADATA_PATH);
|
||||
ZipEntry meta_entry;
|
||||
if (FindEntry(zip, metadata_path, &meta_entry) != 0) {
|
||||
LOG(ERROR) << "Failed to find " << METADATA_PATH << " in update package";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string meta_data(meta_entry->uncompLen, '\0');
|
||||
if (!mzReadZipEntry(zip, meta_entry, &meta_data[0], meta_entry->uncompLen)) {
|
||||
std::string meta_data(meta_entry.uncompressed_length, '\0');
|
||||
if (ExtractToMemory(zip, &meta_entry, reinterpret_cast<uint8_t*>(&meta_data[0]),
|
||||
meta_entry.uncompressed_length) != 0) {
|
||||
LOG(ERROR) << "Failed to read metadata in update package";
|
||||
return;
|
||||
}
|
||||
|
@ -109,15 +111,14 @@ static void read_source_target_build(ZipArchive* zip, std::vector<std::string>&
|
|||
|
||||
// If the package contains an update binary, extract it and run it.
|
||||
static int
|
||||
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
|
||||
try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
|
||||
std::vector<std::string>& log_buffer, int retry_count)
|
||||
{
|
||||
read_source_target_build(zip, log_buffer);
|
||||
|
||||
const ZipEntry* binary_entry =
|
||||
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
|
||||
if (binary_entry == NULL) {
|
||||
mzCloseZipArchive(zip);
|
||||
ZipString binary_name(ASSUMED_UPDATE_BINARY_NAME);
|
||||
ZipEntry binary_entry;
|
||||
if (FindEntry(zip, binary_name, &binary_entry) != 0) {
|
||||
return INSTALL_CORRUPT;
|
||||
}
|
||||
|
||||
|
@ -126,15 +127,14 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
357
minzip/Bits.h
357
minzip/Bits.h
|
@ -1,357 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Some handy functions for manipulating bits and bytes.
|
||||
*/
|
||||
#ifndef _MINZIP_BITS
|
||||
#define _MINZIP_BITS
|
||||
|
||||
#include "inline_magic.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Get 1 byte. (Included to make the code more legible.)
|
||||
*/
|
||||
INLINE unsigned char get1(unsigned const char* pSrc)
|
||||
{
|
||||
return *pSrc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 2 big-endian bytes.
|
||||
*/
|
||||
INLINE unsigned short get2BE(unsigned char const* pSrc)
|
||||
{
|
||||
unsigned short result;
|
||||
|
||||
result = *pSrc++ << 8;
|
||||
result |= *pSrc++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 4 big-endian bytes.
|
||||
*/
|
||||
INLINE unsigned int get4BE(unsigned char const* pSrc)
|
||||
{
|
||||
unsigned int result;
|
||||
|
||||
result = *pSrc++ << 24;
|
||||
result |= *pSrc++ << 16;
|
||||
result |= *pSrc++ << 8;
|
||||
result |= *pSrc++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 8 big-endian bytes.
|
||||
*/
|
||||
INLINE unsigned long long get8BE(unsigned char const* pSrc)
|
||||
{
|
||||
unsigned long long result;
|
||||
|
||||
result = (unsigned long long) *pSrc++ << 56;
|
||||
result |= (unsigned long long) *pSrc++ << 48;
|
||||
result |= (unsigned long long) *pSrc++ << 40;
|
||||
result |= (unsigned long long) *pSrc++ << 32;
|
||||
result |= (unsigned long long) *pSrc++ << 24;
|
||||
result |= (unsigned long long) *pSrc++ << 16;
|
||||
result |= (unsigned long long) *pSrc++ << 8;
|
||||
result |= (unsigned long long) *pSrc++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 2 little-endian bytes.
|
||||
*/
|
||||
INLINE unsigned short get2LE(unsigned char const* pSrc)
|
||||
{
|
||||
unsigned short result;
|
||||
|
||||
result = *pSrc++;
|
||||
result |= *pSrc++ << 8;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 4 little-endian bytes.
|
||||
*/
|
||||
INLINE unsigned int get4LE(unsigned char const* pSrc)
|
||||
{
|
||||
unsigned int result;
|
||||
|
||||
result = *pSrc++;
|
||||
result |= *pSrc++ << 8;
|
||||
result |= *pSrc++ << 16;
|
||||
result |= *pSrc++ << 24;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 8 little-endian bytes.
|
||||
*/
|
||||
INLINE unsigned long long get8LE(unsigned char const* pSrc)
|
||||
{
|
||||
unsigned long long result;
|
||||
|
||||
result = (unsigned long long) *pSrc++;
|
||||
result |= (unsigned long long) *pSrc++ << 8;
|
||||
result |= (unsigned long long) *pSrc++ << 16;
|
||||
result |= (unsigned long long) *pSrc++ << 24;
|
||||
result |= (unsigned long long) *pSrc++ << 32;
|
||||
result |= (unsigned long long) *pSrc++ << 40;
|
||||
result |= (unsigned long long) *pSrc++ << 48;
|
||||
result |= (unsigned long long) *pSrc++ << 56;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab 1 byte and advance the data pointer.
|
||||
*/
|
||||
INLINE unsigned char read1(unsigned const char** ppSrc)
|
||||
{
|
||||
return *(*ppSrc)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab 2 big-endian bytes and advance the data pointer.
|
||||
*/
|
||||
INLINE unsigned short read2BE(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned short result;
|
||||
|
||||
result = *(*ppSrc)++ << 8;
|
||||
result |= *(*ppSrc)++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab 4 big-endian bytes and advance the data pointer.
|
||||
*/
|
||||
INLINE unsigned int read4BE(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned int result;
|
||||
|
||||
result = *(*ppSrc)++ << 24;
|
||||
result |= *(*ppSrc)++ << 16;
|
||||
result |= *(*ppSrc)++ << 8;
|
||||
result |= *(*ppSrc)++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 8 big-endian bytes.
|
||||
*/
|
||||
INLINE unsigned long long read8BE(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned long long result;
|
||||
|
||||
result = (unsigned long long) *(*ppSrc)++ << 56;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 48;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 40;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 32;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 24;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 16;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 8;
|
||||
result |= (unsigned long long) *(*ppSrc)++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab 2 little-endian bytes and advance the data pointer.
|
||||
*/
|
||||
INLINE unsigned short read2LE(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned short result;
|
||||
|
||||
result = *(*ppSrc)++;
|
||||
result |= *(*ppSrc)++ << 8;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab 4 little-endian bytes and advance the data pointer.
|
||||
*/
|
||||
INLINE unsigned int read4LE(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned int result;
|
||||
|
||||
result = *(*ppSrc)++;
|
||||
result |= *(*ppSrc)++ << 8;
|
||||
result |= *(*ppSrc)++ << 16;
|
||||
result |= *(*ppSrc)++ << 24;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 8 little-endian bytes.
|
||||
*/
|
||||
INLINE unsigned long long read8LE(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned long long result;
|
||||
|
||||
result = (unsigned long long) *(*ppSrc)++;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 8;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 16;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 24;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 32;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 40;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 48;
|
||||
result |= (unsigned long long) *(*ppSrc)++ << 56;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip over a UTF-8 string.
|
||||
*/
|
||||
INLINE void skipUtf8String(unsigned char const** ppSrc)
|
||||
{
|
||||
unsigned int length = read4BE(ppSrc);
|
||||
|
||||
(*ppSrc) += length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a UTF-8 string into a fixed-size buffer, and null-terminate it.
|
||||
*
|
||||
* Returns the length of the original string.
|
||||
*/
|
||||
INLINE int readUtf8String(unsigned char const** ppSrc, char* buf, size_t bufLen)
|
||||
{
|
||||
unsigned int length = read4BE(ppSrc);
|
||||
size_t copyLen = (length < bufLen) ? length : bufLen-1;
|
||||
|
||||
memcpy(buf, *ppSrc, copyLen);
|
||||
buf[copyLen] = '\0';
|
||||
|
||||
(*ppSrc) += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a UTF-8 string into newly-allocated storage, and null-terminate it.
|
||||
*
|
||||
* Returns the string and its length. (The latter is probably unnecessary
|
||||
* for the way we're using UTF8.)
|
||||
*/
|
||||
INLINE char* readNewUtf8String(unsigned char const** ppSrc, size_t* pLength)
|
||||
{
|
||||
unsigned int length = read4BE(ppSrc);
|
||||
char* buf;
|
||||
|
||||
buf = (char*) malloc(length+1);
|
||||
|
||||
memcpy(buf, *ppSrc, length);
|
||||
buf[length] = '\0';
|
||||
|
||||
(*ppSrc) += length;
|
||||
|
||||
*pLength = length;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set 1 byte. (Included to make the code more legible.)
|
||||
*/
|
||||
INLINE void set1(unsigned char* buf, unsigned char val)
|
||||
{
|
||||
*buf = (unsigned char)(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 2 big-endian bytes.
|
||||
*/
|
||||
INLINE void set2BE(unsigned char* buf, unsigned short val)
|
||||
{
|
||||
*buf++ = (unsigned char)(val >> 8);
|
||||
*buf = (unsigned char)(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 4 big-endian bytes.
|
||||
*/
|
||||
INLINE void set4BE(unsigned char* buf, unsigned int val)
|
||||
{
|
||||
*buf++ = (unsigned char)(val >> 24);
|
||||
*buf++ = (unsigned char)(val >> 16);
|
||||
*buf++ = (unsigned char)(val >> 8);
|
||||
*buf = (unsigned char)(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 8 big-endian bytes.
|
||||
*/
|
||||
INLINE void set8BE(unsigned char* buf, unsigned long long val)
|
||||
{
|
||||
*buf++ = (unsigned char)(val >> 56);
|
||||
*buf++ = (unsigned char)(val >> 48);
|
||||
*buf++ = (unsigned char)(val >> 40);
|
||||
*buf++ = (unsigned char)(val >> 32);
|
||||
*buf++ = (unsigned char)(val >> 24);
|
||||
*buf++ = (unsigned char)(val >> 16);
|
||||
*buf++ = (unsigned char)(val >> 8);
|
||||
*buf = (unsigned char)(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 2 little-endian bytes.
|
||||
*/
|
||||
INLINE void set2LE(unsigned char* buf, unsigned short val)
|
||||
{
|
||||
*buf++ = (unsigned char)(val);
|
||||
*buf = (unsigned char)(val >> 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 4 little-endian bytes.
|
||||
*/
|
||||
INLINE void set4LE(unsigned char* buf, unsigned int val)
|
||||
{
|
||||
*buf++ = (unsigned char)(val);
|
||||
*buf++ = (unsigned char)(val >> 8);
|
||||
*buf++ = (unsigned char)(val >> 16);
|
||||
*buf = (unsigned char)(val >> 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set 8 little-endian bytes.
|
||||
*/
|
||||
INLINE void set8LE(unsigned char* buf, unsigned long long val)
|
||||
{
|
||||
*buf++ = (unsigned char)(val);
|
||||
*buf++ = (unsigned char)(val >> 8);
|
||||
*buf++ = (unsigned char)(val >> 16);
|
||||
*buf++ = (unsigned char)(val >> 24);
|
||||
*buf++ = (unsigned char)(val >> 32);
|
||||
*buf++ = (unsigned char)(val >> 40);
|
||||
*buf++ = (unsigned char)(val >> 48);
|
||||
*buf = (unsigned char)(val >> 56);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff a UTF-8 string into the buffer.
|
||||
*/
|
||||
INLINE void setUtf8String(unsigned char* buf, const unsigned char* str)
|
||||
{
|
||||
unsigned int strLen = strlen((const char*)str);
|
||||
|
||||
set4BE(buf, strLen);
|
||||
memcpy(buf + sizeof(unsigned int), str, strLen);
|
||||
}
|
||||
|
||||
#endif /*_MINZIP_BITS*/
|
378
minzip/Hash.cpp
378
minzip/Hash.cpp
|
@ -1,378 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Hash table. The dominant calls are add and lookup, with removals
|
||||
* happening very infrequently. We use probing, and don't worry much
|
||||
* about tombstone removal.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "Hash.h"
|
||||
|
||||
/* table load factor, i.e. how full can it get before we resize */
|
||||
//#define LOAD_NUMER 3 // 75%
|
||||
//#define LOAD_DENOM 4
|
||||
#define LOAD_NUMER 5 // 62.5%
|
||||
#define LOAD_DENOM 8
|
||||
//#define LOAD_NUMER 1 // 50%
|
||||
//#define LOAD_DENOM 2
|
||||
|
||||
/*
|
||||
* Compute the capacity needed for a table to hold "size" elements.
|
||||
*/
|
||||
size_t mzHashSize(size_t size) {
|
||||
return (size * LOAD_DENOM) / LOAD_NUMER +1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Round up to the next highest power of 2.
|
||||
*
|
||||
* Found on http://graphics.stanford.edu/~seander/bithacks.html.
|
||||
*/
|
||||
unsigned int roundUpPower2(unsigned int val)
|
||||
{
|
||||
val--;
|
||||
val |= val >> 1;
|
||||
val |= val >> 2;
|
||||
val |= val >> 4;
|
||||
val |= val >> 8;
|
||||
val |= val >> 16;
|
||||
val++;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and initialize a hash table.
|
||||
*/
|
||||
HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc)
|
||||
{
|
||||
HashTable* pHashTable;
|
||||
|
||||
assert(initialSize > 0);
|
||||
|
||||
pHashTable = (HashTable*) malloc(sizeof(*pHashTable));
|
||||
if (pHashTable == NULL)
|
||||
return NULL;
|
||||
|
||||
pHashTable->tableSize = roundUpPower2(initialSize);
|
||||
pHashTable->numEntries = pHashTable->numDeadEntries = 0;
|
||||
pHashTable->freeFunc = freeFunc;
|
||||
pHashTable->pEntries =
|
||||
(HashEntry*) calloc((size_t)pHashTable->tableSize, sizeof(HashTable));
|
||||
if (pHashTable->pEntries == NULL) {
|
||||
free(pHashTable);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pHashTable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear out all entries.
|
||||
*/
|
||||
void mzHashTableClear(HashTable* pHashTable)
|
||||
{
|
||||
HashEntry* pEnt;
|
||||
int i;
|
||||
|
||||
pEnt = pHashTable->pEntries;
|
||||
for (i = 0; i < pHashTable->tableSize; i++, pEnt++) {
|
||||
if (pEnt->data == HASH_TOMBSTONE) {
|
||||
// nuke entry
|
||||
pEnt->data = NULL;
|
||||
} else if (pEnt->data != NULL) {
|
||||
// call free func then nuke entry
|
||||
if (pHashTable->freeFunc != NULL)
|
||||
(*pHashTable->freeFunc)(pEnt->data);
|
||||
pEnt->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pHashTable->numEntries = 0;
|
||||
pHashTable->numDeadEntries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the table.
|
||||
*/
|
||||
void mzHashTableFree(HashTable* pHashTable)
|
||||
{
|
||||
if (pHashTable == NULL)
|
||||
return;
|
||||
mzHashTableClear(pHashTable);
|
||||
free(pHashTable->pEntries);
|
||||
free(pHashTable);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
* Count up the number of tombstone entries in the hash table.
|
||||
*/
|
||||
static int countTombStones(HashTable* pHashTable)
|
||||
{
|
||||
int i, count;
|
||||
|
||||
for (count = i = 0; i < pHashTable->tableSize; i++) {
|
||||
if (pHashTable->pEntries[i].data == HASH_TOMBSTONE)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Resize a hash table. We do this when adding an entry increased the
|
||||
* size of the table beyond its comfy limit.
|
||||
*
|
||||
* This essentially requires re-inserting all elements into the new storage.
|
||||
*
|
||||
* If multiple threads can access the hash table, the table's lock should
|
||||
* have been grabbed before issuing the "lookup+add" call that led to the
|
||||
* resize, so we don't have a synchronization problem here.
|
||||
*/
|
||||
static bool resizeHash(HashTable* pHashTable, int newSize)
|
||||
{
|
||||
HashEntry* pNewEntries;
|
||||
int i;
|
||||
|
||||
assert(countTombStones(pHashTable) == pHashTable->numDeadEntries);
|
||||
|
||||
pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashTable));
|
||||
if (pNewEntries == NULL)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < pHashTable->tableSize; i++) {
|
||||
void* data = pHashTable->pEntries[i].data;
|
||||
if (data != NULL && data != HASH_TOMBSTONE) {
|
||||
int hashValue = pHashTable->pEntries[i].hashValue;
|
||||
int newIdx;
|
||||
|
||||
/* probe for new spot, wrapping around */
|
||||
newIdx = hashValue & (newSize-1);
|
||||
while (pNewEntries[newIdx].data != NULL)
|
||||
newIdx = (newIdx + 1) & (newSize-1);
|
||||
|
||||
pNewEntries[newIdx].hashValue = hashValue;
|
||||
pNewEntries[newIdx].data = data;
|
||||
}
|
||||
}
|
||||
|
||||
free(pHashTable->pEntries);
|
||||
pHashTable->pEntries = pNewEntries;
|
||||
pHashTable->tableSize = newSize;
|
||||
pHashTable->numDeadEntries = 0;
|
||||
|
||||
assert(countTombStones(pHashTable) == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an entry.
|
||||
*
|
||||
* We probe on collisions, wrapping around the table.
|
||||
*/
|
||||
void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
|
||||
HashCompareFunc cmpFunc, bool doAdd)
|
||||
{
|
||||
HashEntry* pEntry;
|
||||
HashEntry* pEnd;
|
||||
void* result = NULL;
|
||||
|
||||
assert(pHashTable->tableSize > 0);
|
||||
assert(item != HASH_TOMBSTONE);
|
||||
assert(item != NULL);
|
||||
|
||||
/* jump to the first entry and probe for a match */
|
||||
pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
|
||||
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
|
||||
while (pEntry->data != NULL) {
|
||||
if (pEntry->data != HASH_TOMBSTONE &&
|
||||
pEntry->hashValue == itemHash &&
|
||||
(*cmpFunc)(pEntry->data, item) == 0)
|
||||
{
|
||||
/* match */
|
||||
break;
|
||||
}
|
||||
|
||||
pEntry++;
|
||||
if (pEntry == pEnd) { /* wrap around to start */
|
||||
if (pHashTable->tableSize == 1)
|
||||
break; /* edge case - single-entry table */
|
||||
pEntry = pHashTable->pEntries;
|
||||
}
|
||||
}
|
||||
|
||||
if (pEntry->data == NULL) {
|
||||
if (doAdd) {
|
||||
pEntry->hashValue = itemHash;
|
||||
pEntry->data = item;
|
||||
pHashTable->numEntries++;
|
||||
|
||||
/*
|
||||
* We've added an entry. See if this brings us too close to full.
|
||||
*/
|
||||
if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM
|
||||
> pHashTable->tableSize * LOAD_NUMER)
|
||||
{
|
||||
if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) {
|
||||
/* don't really have a way to indicate failure */
|
||||
LOG(FATAL) << "Hash resize failure";
|
||||
}
|
||||
/* note "pEntry" is now invalid */
|
||||
}
|
||||
|
||||
/* full table is bad -- search for nonexistent never halts */
|
||||
assert(pHashTable->numEntries < pHashTable->tableSize);
|
||||
result = item;
|
||||
} else {
|
||||
assert(result == NULL);
|
||||
}
|
||||
} else {
|
||||
result = pEntry->data;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an entry from the table.
|
||||
*
|
||||
* Does NOT invoke the "free" function on the item.
|
||||
*/
|
||||
bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item)
|
||||
{
|
||||
HashEntry* pEntry;
|
||||
HashEntry* pEnd;
|
||||
|
||||
assert(pHashTable->tableSize > 0);
|
||||
|
||||
/* jump to the first entry and probe for a match */
|
||||
pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
|
||||
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
|
||||
while (pEntry->data != NULL) {
|
||||
if (pEntry->data == item) {
|
||||
pEntry->data = HASH_TOMBSTONE;
|
||||
pHashTable->numEntries--;
|
||||
pHashTable->numDeadEntries++;
|
||||
return true;
|
||||
}
|
||||
|
||||
pEntry++;
|
||||
if (pEntry == pEnd) { /* wrap around to start */
|
||||
if (pHashTable->tableSize == 1)
|
||||
break; /* edge case - single-entry table */
|
||||
pEntry = pHashTable->pEntries;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a function on every entry in the hash table.
|
||||
*
|
||||
* If "func" returns a nonzero value, terminate early and return the value.
|
||||
*/
|
||||
int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg)
|
||||
{
|
||||
int i, val;
|
||||
|
||||
for (i = 0; i < pHashTable->tableSize; i++) {
|
||||
HashEntry* pEnt = &pHashTable->pEntries[i];
|
||||
|
||||
if (pEnt->data != NULL && pEnt->data != HASH_TOMBSTONE) {
|
||||
val = (*func)(pEnt->data, arg);
|
||||
if (val != 0)
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Look up an entry, counting the number of times we have to probe.
|
||||
*
|
||||
* Returns -1 if the entry wasn't found.
|
||||
*/
|
||||
int countProbes(HashTable* pHashTable, unsigned int itemHash, const void* item,
|
||||
HashCompareFunc cmpFunc)
|
||||
{
|
||||
HashEntry* pEntry;
|
||||
HashEntry* pEnd;
|
||||
int count = 0;
|
||||
|
||||
assert(pHashTable->tableSize > 0);
|
||||
assert(item != HASH_TOMBSTONE);
|
||||
assert(item != NULL);
|
||||
|
||||
/* jump to the first entry and probe for a match */
|
||||
pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
|
||||
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
|
||||
while (pEntry->data != NULL) {
|
||||
if (pEntry->data != HASH_TOMBSTONE &&
|
||||
pEntry->hashValue == itemHash &&
|
||||
(*cmpFunc)(pEntry->data, item) == 0)
|
||||
{
|
||||
/* match */
|
||||
break;
|
||||
}
|
||||
|
||||
pEntry++;
|
||||
if (pEntry == pEnd) { /* wrap around to start */
|
||||
if (pHashTable->tableSize == 1)
|
||||
break; /* edge case - single-entry table */
|
||||
pEntry = pHashTable->pEntries;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
if (pEntry->data == NULL)
|
||||
return -1;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the amount of probing required for the specified hash table.
|
||||
*
|
||||
* We do this by running through all entries in the hash table, computing
|
||||
* the hash value and then doing a lookup.
|
||||
*
|
||||
* The caller should lock the table before calling here.
|
||||
*/
|
||||
void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
|
||||
HashCompareFunc cmpFunc)
|
||||
{
|
||||
int numEntries, minProbe, maxProbe, totalProbe;
|
||||
HashIter iter;
|
||||
|
||||
numEntries = maxProbe = totalProbe = 0;
|
||||
minProbe = 65536*32767;
|
||||
|
||||
for (mzHashIterBegin(pHashTable, &iter); !mzHashIterDone(&iter);
|
||||
mzHashIterNext(&iter))
|
||||
{
|
||||
const void* data = (const void*)mzHashIterData(&iter);
|
||||
int count;
|
||||
|
||||
count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
|
||||
|
||||
numEntries++;
|
||||
|
||||
if (count < minProbe)
|
||||
minProbe = count;
|
||||
if (count > maxProbe)
|
||||
maxProbe = count;
|
||||
totalProbe += count;
|
||||
}
|
||||
|
||||
LOG(VERBOSE) << "Probe: min=" << minProbe << ", max=" << maxProbe << ", total="
|
||||
<< totalProbe <<" in " << numEntries << " (" << pHashTable->tableSize
|
||||
<< "), avg=" << (float) totalProbe / (float) numEntries;
|
||||
}
|
194
minzip/Hash.h
194
minzip/Hash.h
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* Copyright 2007 The Android Open Source Project
|
||||
*
|
||||
* General purpose hash table, used for finding classes, methods, etc.
|
||||
*
|
||||
* When the number of elements reaches 3/4 of the table's capacity, the
|
||||
* table will be resized.
|
||||
*/
|
||||
#ifndef _MINZIP_HASH
|
||||
#define _MINZIP_HASH
|
||||
|
||||
#include "inline_magic.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* compute the hash of an item with a specific type */
|
||||
typedef unsigned int (*HashCompute)(const void* item);
|
||||
|
||||
/*
|
||||
* Compare a hash entry with a "loose" item after their hash values match.
|
||||
* Returns { <0, 0, >0 } depending on ordering of items (same semantics
|
||||
* as strcmp()).
|
||||
*/
|
||||
typedef int (*HashCompareFunc)(const void* tableItem, const void* looseItem);
|
||||
|
||||
/*
|
||||
* This function will be used to free entries in the table. This can be
|
||||
* NULL if no free is required, free(), or a custom function.
|
||||
*/
|
||||
typedef void (*HashFreeFunc)(void* ptr);
|
||||
|
||||
/*
|
||||
* Used by mzHashForeach().
|
||||
*/
|
||||
typedef int (*HashForeachFunc)(void* data, void* arg);
|
||||
|
||||
/*
|
||||
* One entry in the hash table. "data" values are expected to be (or have
|
||||
* the same characteristics as) valid pointers. In particular, a NULL
|
||||
* value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates
|
||||
* a no-longer-used slot that must be stepped over during probing.
|
||||
*
|
||||
* Attempting to add a NULL or tombstone value is an error.
|
||||
*
|
||||
* When an entry is released, we will call (HashFreeFunc)(entry->data).
|
||||
*/
|
||||
typedef struct HashEntry {
|
||||
unsigned int hashValue;
|
||||
void* data;
|
||||
} HashEntry;
|
||||
|
||||
#define HASH_TOMBSTONE ((void*) 0xcbcacccd) // invalid ptr value
|
||||
|
||||
/*
|
||||
* Expandable hash table.
|
||||
*
|
||||
* This structure should be considered opaque.
|
||||
*/
|
||||
typedef struct HashTable {
|
||||
int tableSize; /* must be power of 2 */
|
||||
int numEntries; /* current #of "live" entries */
|
||||
int numDeadEntries; /* current #of tombstone entries */
|
||||
HashEntry* pEntries; /* array on heap */
|
||||
HashFreeFunc freeFunc;
|
||||
} HashTable;
|
||||
|
||||
/*
|
||||
* Create and initialize a HashTable structure, using "initialSize" as
|
||||
* a basis for the initial capacity of the table. (The actual initial
|
||||
* table size may be adjusted upward.) If you know exactly how many
|
||||
* elements the table will hold, pass the result from mzHashSize() in.)
|
||||
*
|
||||
* Returns "false" if unable to allocate the table.
|
||||
*/
|
||||
HashTable* mzHashTableCreate(size_t initialSize, HashFreeFunc freeFunc);
|
||||
|
||||
/*
|
||||
* Compute the capacity needed for a table to hold "size" elements. Use
|
||||
* this when you know ahead of time how many elements the table will hold.
|
||||
* Pass this value into mzHashTableCreate() to ensure that you can add
|
||||
* all elements without needing to reallocate the table.
|
||||
*/
|
||||
size_t mzHashSize(size_t size);
|
||||
|
||||
/*
|
||||
* Clear out a hash table, freeing the contents of any used entries.
|
||||
*/
|
||||
void mzHashTableClear(HashTable* pHashTable);
|
||||
|
||||
/*
|
||||
* Free a hash table.
|
||||
*/
|
||||
void mzHashTableFree(HashTable* pHashTable);
|
||||
|
||||
/*
|
||||
* Get #of entries in hash table.
|
||||
*/
|
||||
INLINE int mzHashTableNumEntries(HashTable* pHashTable) {
|
||||
return pHashTable->numEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get total size of hash table (for memory usage calculations).
|
||||
*/
|
||||
INLINE int mzHashTableMemUsage(HashTable* pHashTable) {
|
||||
return sizeof(HashTable) + pHashTable->tableSize * sizeof(HashEntry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up an entry in the table, possibly adding it if it's not there.
|
||||
*
|
||||
* If "item" is not found, and "doAdd" is false, NULL is returned.
|
||||
* Otherwise, a pointer to the found or added item is returned. (You can
|
||||
* tell the difference by seeing if return value == item.)
|
||||
*
|
||||
* An "add" operation may cause the entire table to be reallocated.
|
||||
*/
|
||||
void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item,
|
||||
HashCompareFunc cmpFunc, bool doAdd);
|
||||
|
||||
/*
|
||||
* Remove an item from the hash table, given its "data" pointer. Does not
|
||||
* invoke the "free" function; just detaches it from the table.
|
||||
*/
|
||||
bool mzHashTableRemove(HashTable* pHashTable, unsigned int hash, void* item);
|
||||
|
||||
/*
|
||||
* Execute "func" on every entry in the hash table.
|
||||
*
|
||||
* If "func" returns a nonzero value, terminate early and return the value.
|
||||
*/
|
||||
int mzHashForeach(HashTable* pHashTable, HashForeachFunc func, void* arg);
|
||||
|
||||
/*
|
||||
* An alternative to mzHashForeach(), using an iterator.
|
||||
*
|
||||
* Use like this:
|
||||
* HashIter iter;
|
||||
* for (mzHashIterBegin(hashTable, &iter); !mzHashIterDone(&iter);
|
||||
* mzHashIterNext(&iter))
|
||||
* {
|
||||
* MyData* data = (MyData*)mzHashIterData(&iter);
|
||||
* }
|
||||
*/
|
||||
typedef struct HashIter {
|
||||
void* data;
|
||||
HashTable* pHashTable;
|
||||
int idx;
|
||||
} HashIter;
|
||||
INLINE void mzHashIterNext(HashIter* pIter) {
|
||||
int i = pIter->idx +1;
|
||||
int lim = pIter->pHashTable->tableSize;
|
||||
for ( ; i < lim; i++) {
|
||||
void* data = pIter->pHashTable->pEntries[i].data;
|
||||
if (data != NULL && data != HASH_TOMBSTONE)
|
||||
break;
|
||||
}
|
||||
pIter->idx = i;
|
||||
}
|
||||
INLINE void mzHashIterBegin(HashTable* pHashTable, HashIter* pIter) {
|
||||
pIter->pHashTable = pHashTable;
|
||||
pIter->idx = -1;
|
||||
mzHashIterNext(pIter);
|
||||
}
|
||||
INLINE bool mzHashIterDone(HashIter* pIter) {
|
||||
return (pIter->idx >= pIter->pHashTable->tableSize);
|
||||
}
|
||||
INLINE void* mzHashIterData(HashIter* pIter) {
|
||||
assert(pIter->idx >= 0 && pIter->idx < pIter->pHashTable->tableSize);
|
||||
return pIter->pHashTable->pEntries[pIter->idx].data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Evaluate hash table performance by examining the number of times we
|
||||
* have to probe for an entry.
|
||||
*
|
||||
* The caller should lock the table beforehand.
|
||||
*/
|
||||
typedef unsigned int (*HashCalcFunc)(const void* item);
|
||||
void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
|
||||
HashCompareFunc cmpFunc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_MINZIP_HASH*/
|
|
@ -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"
|
1022
minzip/Zip.cpp
1022
minzip/Zip.cpp
File diff suppressed because it is too large
Load diff
171
minzip/Zip.h
171
minzip/Zip.h
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Simple Zip archive support.
|
||||
*/
|
||||
#ifndef _MINZIP_ZIP
|
||||
#define _MINZIP_ZIP
|
||||
|
||||
#include "inline_magic.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include "Hash.h"
|
||||
#include "SysUtil.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct selabel_handle;
|
||||
|
||||
/*
|
||||
* One entry in the Zip archive. Treat this as opaque -- use accessors below.
|
||||
*
|
||||
* TODO: we're now keeping the pages mapped so we don't have to copy the
|
||||
* filename. We can change the accessors to retrieve the various pieces
|
||||
* directly from the source file instead of copying them out, for a very
|
||||
* slight speed hit and a modest reduction in memory usage.
|
||||
*/
|
||||
typedef struct ZipEntry {
|
||||
unsigned int fileNameLen;
|
||||
const char* fileName; // not null-terminated
|
||||
uint32_t offset;
|
||||
uint32_t compLen;
|
||||
uint32_t uncompLen;
|
||||
int compression;
|
||||
long modTime;
|
||||
long crc32;
|
||||
int versionMadeBy;
|
||||
long externalFileAttributes;
|
||||
} ZipEntry;
|
||||
|
||||
/*
|
||||
* One Zip archive. Treat as opaque.
|
||||
*/
|
||||
typedef struct ZipArchive {
|
||||
unsigned int numEntries;
|
||||
ZipEntry* pEntries;
|
||||
HashTable* pHash; // maps file name to ZipEntry
|
||||
unsigned char* addr;
|
||||
size_t length;
|
||||
} ZipArchive;
|
||||
|
||||
/*
|
||||
* Represents a non-NUL-terminated string,
|
||||
* which is how entry names are stored.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *str;
|
||||
size_t len;
|
||||
} UnterminatedString;
|
||||
|
||||
/*
|
||||
* Open a Zip archive.
|
||||
*
|
||||
* On success, returns 0 and populates "pArchive". Returns nonzero errno
|
||||
* value on failure.
|
||||
*/
|
||||
int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive);
|
||||
|
||||
/*
|
||||
* Close archive, releasing resources associated with it.
|
||||
*
|
||||
* Depending on the implementation this could unmap pages used by classes
|
||||
* stored in a Jar. This should only be done after unloading classes.
|
||||
*/
|
||||
void mzCloseZipArchive(ZipArchive* pArchive);
|
||||
|
||||
|
||||
/*
|
||||
* Find an entry in the Zip archive, by name.
|
||||
*/
|
||||
const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
|
||||
const char* entryName);
|
||||
|
||||
INLINE uint32_t mzGetZipEntryOffset(const ZipEntry* pEntry) {
|
||||
return pEntry->offset;
|
||||
}
|
||||
INLINE uint32_t mzGetZipEntryUncompLen(const ZipEntry* pEntry) {
|
||||
return pEntry->uncompLen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Type definition for the callback function used by
|
||||
* mzProcessZipEntryContents().
|
||||
*/
|
||||
typedef bool (*ProcessZipEntryContentsFunction)(const unsigned char *data,
|
||||
int dataLen, void *cookie);
|
||||
|
||||
/*
|
||||
* Stream the uncompressed data through the supplied function,
|
||||
* passing cookie to it each time it gets called. processFunction
|
||||
* may be called more than once.
|
||||
*
|
||||
* If processFunction returns false, the operation is abandoned and
|
||||
* mzProcessZipEntryContents() immediately returns false.
|
||||
*
|
||||
* This is useful for calculating the hash of an entry's uncompressed contents.
|
||||
*/
|
||||
bool mzProcessZipEntryContents(const ZipArchive *pArchive,
|
||||
const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction,
|
||||
void *cookie);
|
||||
|
||||
/*
|
||||
* Read an entry into a buffer allocated by the caller.
|
||||
*/
|
||||
bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
|
||||
char* buf, int bufLen);
|
||||
|
||||
/*
|
||||
* Inflate and write an entry to a file.
|
||||
*/
|
||||
bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
|
||||
const ZipEntry *pEntry, int fd);
|
||||
|
||||
/*
|
||||
* Inflate and write an entry to a memory buffer, which must be long
|
||||
* enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
|
||||
*/
|
||||
bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
|
||||
const ZipEntry *pEntry, unsigned char* buffer);
|
||||
|
||||
/*
|
||||
* Inflate all files under zipDir to the directory specified by
|
||||
* targetDir, which must exist and be a writable directory.
|
||||
*
|
||||
* Directory entries and symlinks are not extracted.
|
||||
*
|
||||
*
|
||||
* The immediate children of zipDir will become the immediate
|
||||
* children of targetDir; e.g., if the archive contains the entries
|
||||
*
|
||||
* a/b/c/one
|
||||
* a/b/c/two
|
||||
* a/b/c/d/three
|
||||
*
|
||||
* and mzExtractRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
|
||||
* files will be
|
||||
*
|
||||
* /tmp/one
|
||||
* /tmp/two
|
||||
* /tmp/d/three
|
||||
*
|
||||
* If timestamp is non-NULL, file timestamps will be set accordingly.
|
||||
*
|
||||
* If callback is non-NULL, it will be invoked with each unpacked file.
|
||||
*
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
const char *zipDir, const char *targetDir,
|
||||
const struct utimbuf *timestamp,
|
||||
void (*callback)(const char *fn, void*), void *cookie,
|
||||
struct selabel_handle *sehnd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_MINZIP_ZIP*/
|
|
@ -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_
|
|
@ -17,7 +17,7 @@ LOCAL_PATH := $(call my-dir)
|
|||
include $(CLEAR_VARS)
|
||||
|
||||
otafault_static_libs := \
|
||||
libminzip \
|
||||
libziparchive \
|
||||
libz \
|
||||
libselinux \
|
||||
libbase \
|
||||
|
|
|
@ -21,21 +21,21 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "minzip/Zip.h"
|
||||
#include "config.h"
|
||||
#include "ota_io.h"
|
||||
|
||||
#define OTAIO_MAX_FNAME_SIZE 128
|
||||
|
||||
static ZipArchive* archive;
|
||||
static ZipArchiveHandle archive;
|
||||
static std::map<std::string, bool> should_inject_cache;
|
||||
|
||||
static std::string get_type_path(const char* io_type) {
|
||||
return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type);
|
||||
}
|
||||
|
||||
void ota_io_init(ZipArchive* za) {
|
||||
void ota_io_init(ZipArchiveHandle za) {
|
||||
archive = za;
|
||||
ota_set_fault_files();
|
||||
}
|
||||
|
@ -50,9 +50,11 @@ bool should_fault_inject(const char* io_type) {
|
|||
if (should_inject_cache.find(type_path) != should_inject_cache.end()) {
|
||||
return should_inject_cache[type_path];
|
||||
}
|
||||
const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
|
||||
should_inject_cache[type_path] = entry != nullptr;
|
||||
return entry != NULL;
|
||||
ZipString zip_type_path(type_path.c_str());
|
||||
ZipEntry entry;
|
||||
int status = FindEntry(archive, zip_type_path, &entry);
|
||||
should_inject_cache[type_path] = (status == 0);
|
||||
return (status == 0);
|
||||
}
|
||||
|
||||
bool should_hit_cache() {
|
||||
|
@ -63,7 +65,9 @@ std::string fault_fname(const char* io_type) {
|
|||
std::string type_path = get_type_path(io_type);
|
||||
std::string fname;
|
||||
fname.resize(OTAIO_MAX_FNAME_SIZE);
|
||||
const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
|
||||
mzReadZipEntry(archive, entry, &fname[0], OTAIO_MAX_FNAME_SIZE);
|
||||
ZipString zip_type_path(type_path.c_str());
|
||||
ZipEntry entry;
|
||||
int status = FindEntry(archive, zip_type_path, &entry);
|
||||
ExtractToMemory(archive, &entry, reinterpret_cast<uint8_t*>(&fname[0]), OTAIO_MAX_FNAME_SIZE);
|
||||
return fname;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "minzip/Zip.h"
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#define OTAIO_BASE_DIR ".libotafault"
|
||||
#define OTAIO_READ "READ"
|
||||
|
@ -52,7 +52,7 @@
|
|||
/*
|
||||
* Initialize libotafault by providing a reference to the OTA package.
|
||||
*/
|
||||
void ota_io_init(ZipArchive* za);
|
||||
void ota_io_init(ZipArchiveHandle zip);
|
||||
|
||||
/*
|
||||
* Return true if a config file is present for the given IO type.
|
||||
|
|
35
otautil/Android.mk
Normal file
35
otautil/Android.mk
Normal file
|
@ -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)
|
121
otautil/ZipUtil.cpp
Normal file
121
otautil/ZipUtil.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ZipUtil.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "DirUtil.h"
|
||||
|
||||
static constexpr mode_t UNZIP_DIRMODE = 0755;
|
||||
static constexpr mode_t UNZIP_FILEMODE = 0644;
|
||||
|
||||
bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
|
||||
const std::string& dest_path, const struct utimbuf* timestamp,
|
||||
struct selabel_handle* sehnd) {
|
||||
if (!zip_path.empty() && zip_path[0] == '/') {
|
||||
LOG(ERROR) << "ExtractPackageRecursive(): zip_path must be a relative path " << zip_path;
|
||||
return false;
|
||||
}
|
||||
if (dest_path.empty() || dest_path[0] != '/') {
|
||||
LOG(ERROR) << "ExtractPackageRecursive(): dest_path must be an absolute path " << dest_path;
|
||||
return false;
|
||||
}
|
||||
|
||||
void* cookie;
|
||||
std::string target_dir(dest_path);
|
||||
if (dest_path.back() != '/') {
|
||||
target_dir += '/';
|
||||
}
|
||||
std::string prefix_path(zip_path);
|
||||
if (!zip_path.empty() && zip_path.back() != '/') {
|
||||
prefix_path += '/';
|
||||
}
|
||||
const ZipString zip_prefix(prefix_path.c_str());
|
||||
|
||||
int ret = StartIteration(zip, &cookie, &zip_prefix, nullptr);
|
||||
if (ret != 0) {
|
||||
LOG(ERROR) << "failed to start iterating zip entries.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
|
||||
ZipEntry entry;
|
||||
ZipString name;
|
||||
int extractCount = 0;
|
||||
while (Next(cookie, &entry, &name) == 0) {
|
||||
std::string entry_name(name.name, name.name + name.name_length);
|
||||
CHECK_LE(prefix_path.size(), entry_name.size());
|
||||
std::string path = target_dir + entry_name.substr(prefix_path.size());
|
||||
// Skip dir.
|
||||
if (path.back() == '/') {
|
||||
continue;
|
||||
}
|
||||
//TODO(b/31917448) handle the symlink.
|
||||
|
||||
if (dirCreateHierarchy(path.c_str(), UNZIP_DIRMODE, timestamp, true, sehnd) != 0) {
|
||||
LOG(ERROR) << "failed to create dir for " << path;
|
||||
return false;
|
||||
}
|
||||
|
||||
char *secontext = NULL;
|
||||
if (sehnd) {
|
||||
selabel_lookup(sehnd, &secontext, path.c_str(), UNZIP_FILEMODE);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
android::base::unique_fd fd(open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, UNZIP_FILEMODE));
|
||||
if (fd == -1) {
|
||||
PLOG(ERROR) << "Can't create target file \"" << path << "\"";
|
||||
return false;
|
||||
}
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
|
||||
int err = ExtractEntryToFile(zip, &entry, fd);
|
||||
if (err != 0) {
|
||||
LOG(ERROR) << "Error extracting \"" << path << "\" : " << ErrorCodeString(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fsync(fd) != 0) {
|
||||
PLOG(ERROR) << "Error syncing file descriptor when extracting \"" << path << "\"";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp != nullptr && utime(path.c_str(), timestamp)) {
|
||||
PLOG(ERROR) << "Error touching \"" << path << "\"";
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Extracted file \"" << path << "\"";
|
||||
++extractCount;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Extracted " << extractCount << " file(s)";
|
||||
return true;
|
||||
}
|
57
otautil/ZipUtil.h
Normal file
57
otautil/ZipUtil.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _OTAUTIL_ZIPUTIL_H
|
||||
#define _OTAUTIL_ZIPUTIL_H
|
||||
|
||||
#include <utime.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <selinux/label.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
/*
|
||||
* Inflate all files under zip_path to the directory specified by
|
||||
* dest_path, which must exist and be a writable directory. The zip_path
|
||||
* is allowed to be an empty string, in which case the whole package
|
||||
* will be extracted.
|
||||
*
|
||||
* Directory entries are not extracted.
|
||||
*
|
||||
* The immediate children of zip_path will become the immediate
|
||||
* children of dest_path; e.g., if the archive contains the entries
|
||||
*
|
||||
* a/b/c/one
|
||||
* a/b/c/two
|
||||
* a/b/c/d/three
|
||||
*
|
||||
* and ExtractPackageRecursive(a, "a/b/c", "/tmp", ...) is called, the resulting
|
||||
* files will be
|
||||
*
|
||||
* /tmp/one
|
||||
* /tmp/two
|
||||
* /tmp/d/three
|
||||
*
|
||||
* If timestamp is non-NULL, file timestamps will be set accordingly.
|
||||
*
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
bool ExtractPackageRecursive(ZipArchiveHandle zip, const std::string& zip_path,
|
||||
const std::string& dest_path, const struct utimbuf* timestamp,
|
||||
struct selabel_handle* sehnd);
|
||||
|
||||
#endif // _OTAUTIL_ZIPUTIL_H
|
|
@ -52,6 +52,7 @@
|
|||
#include <private/android_logger.h> /* private pmsg functions */
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "adb_install.h"
|
||||
#include "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"
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -29,10 +29,11 @@
|
|||
#include <openssl/sha.h>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common/test_constants.h"
|
||||
#include "minzip/SysUtil.h"
|
||||
#include "otautil/SysUtil.h"
|
||||
#include "ui.h"
|
||||
#include "verifier.h"
|
||||
|
||||
|
|
BIN
tests/testdata/ziptest_dummy-update.zip
vendored
Normal file
BIN
tests/testdata/ziptest_dummy-update.zip
vendored
Normal file
Binary file not shown.
BIN
tests/testdata/ziptest_valid.zip
vendored
Normal file
BIN
tests/testdata/ziptest_valid.zip
vendored
Normal file
Binary file not shown.
93
tests/unit/zip_test.cpp
Normal file
93
tests/unit/zip_test.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <android-base/test_utils.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <otautil/SysUtil.h>
|
||||
#include <otautil/ZipUtil.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
static const std::string DATA_PATH(getenv("ANDROID_DATA"));
|
||||
static const std::string TESTDATA_PATH("/recovery/testdata/");
|
||||
|
||||
static const std::vector<uint8_t> kATxtContents {
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'\n'
|
||||
};
|
||||
|
||||
static const std::vector<uint8_t> kBTxtContents {
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'\n'
|
||||
};
|
||||
|
||||
TEST(otazip, ExtractPackageRecursive) {
|
||||
TemporaryDir td;
|
||||
ASSERT_NE(td.path, nullptr);
|
||||
ZipArchiveHandle handle;
|
||||
std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_valid.zip";
|
||||
ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
|
||||
// Extract the whole package into a temp directory.
|
||||
ExtractPackageRecursive(handle, "", td.path, nullptr, nullptr);
|
||||
// Make sure all the files are extracted correctly.
|
||||
std::string path(td.path);
|
||||
android::base::unique_fd fd(open((path + "/a.txt").c_str(), O_RDONLY));
|
||||
ASSERT_NE(fd, -1);
|
||||
std::vector<uint8_t> read_data;
|
||||
read_data.resize(kATxtContents.size());
|
||||
// The content of the file is the same as expected.
|
||||
ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size()));
|
||||
ASSERT_EQ(0, memcmp(read_data.data(), kATxtContents.data(), kATxtContents.size()));
|
||||
|
||||
fd.reset(open((path + "/b.txt").c_str(), O_RDONLY));
|
||||
ASSERT_NE(fd, -1);
|
||||
fd.reset(open((path + "/b/c.txt").c_str(), O_RDONLY));
|
||||
ASSERT_NE(fd, -1);
|
||||
fd.reset(open((path + "/b/d.txt").c_str(), O_RDONLY));
|
||||
ASSERT_NE(fd, -1);
|
||||
read_data.resize(kBTxtContents.size());
|
||||
ASSERT_TRUE(android::base::ReadFully(fd.get(), read_data.data(), read_data.size()));
|
||||
ASSERT_EQ(0, memcmp(read_data.data(), kBTxtContents.data(), kBTxtContents.size()));
|
||||
}
|
||||
|
||||
TEST(otazip, OpenFromMemory) {
|
||||
MemMapping map;
|
||||
std::string zip_path = DATA_PATH + TESTDATA_PATH + "/ziptest_dummy-update.zip";
|
||||
ASSERT_EQ(0, sysMapFile(zip_path.c_str(), &map));
|
||||
// Map an update package into memory and open the archive from there.
|
||||
ZipArchiveHandle handle;
|
||||
ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_path.c_str(), &handle));
|
||||
static constexpr const char* BINARY_PATH = "META-INF/com/google/android/update-binary";
|
||||
ZipString binary_path(BINARY_PATH);
|
||||
ZipEntry binary_entry;
|
||||
// Make sure the package opens correctly and its entry can be read.
|
||||
ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
|
||||
TemporaryFile tmp_binary;
|
||||
ASSERT_NE(-1, tmp_binary.fd);
|
||||
ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
|
||||
}
|
||||
|
|
@ -25,7 +25,9 @@ tune2fs_static_libraries := \
|
|||
updater_common_static_libraries := \
|
||||
libapplypatch \
|
||||
libedify \
|
||||
libminzip \
|
||||
libziparchive \
|
||||
libotautil \
|
||||
libutils \
|
||||
libmounts \
|
||||
libotafault \
|
||||
libext4_utils_static \
|
||||
|
|
|
@ -33,21 +33,21 @@
|
|||
#include <unistd.h>
|
||||
#include <fec/io.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "applypatch/applypatch.h"
|
||||
#include "edify/expr.h"
|
||||
#include "error_code.h"
|
||||
#include "updater/install.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "minzip/Hash.h"
|
||||
#include "ota_io.h"
|
||||
#include "print_sha1.h"
|
||||
#include "updater/updater.h"
|
||||
|
@ -71,7 +71,7 @@ struct RangeSet {
|
|||
|
||||
static CauseCode failure_type = kNoCause;
|
||||
static bool is_retry = false;
|
||||
static std::map<std::string, RangeSet> stash_map;
|
||||
static std::unordered_map<std::string, RangeSet> stash_map;
|
||||
|
||||
static void parse_range(const std::string& range_text, RangeSet& rs) {
|
||||
|
||||
|
@ -300,8 +300,8 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
|
|||
// rss and signals the condition again.
|
||||
|
||||
struct NewThreadInfo {
|
||||
ZipArchive* za;
|
||||
const ZipEntry* entry;
|
||||
ZipArchiveHandle za;
|
||||
ZipEntry entry;
|
||||
|
||||
RangeSinkState* rss;
|
||||
|
||||
|
@ -309,7 +309,7 @@ struct NewThreadInfo {
|
|||
pthread_cond_t cv;
|
||||
};
|
||||
|
||||
static bool receive_new_data(const unsigned char* data, int size, void* cookie) {
|
||||
static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
|
||||
NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie);
|
||||
|
||||
while (size > 0) {
|
||||
|
@ -342,7 +342,7 @@ static bool receive_new_data(const unsigned char* data, int size, void* cookie)
|
|||
|
||||
static void* unzip_new_data(void* cookie) {
|
||||
NewThreadInfo* nti = (NewThreadInfo*) cookie;
|
||||
mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
|
||||
ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1351,28 +1351,6 @@ struct Command {
|
|||
CommandFunction f;
|
||||
};
|
||||
|
||||
// CompareCommands and CompareCommandNames are for the hash table
|
||||
|
||||
static int CompareCommands(const void* c1, const void* c2) {
|
||||
return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name);
|
||||
}
|
||||
|
||||
static int CompareCommandNames(const void* c1, const void* c2) {
|
||||
return strcmp(((const Command*) c1)->name, (const char*) c2);
|
||||
}
|
||||
|
||||
// HashString is used to hash command names for the hash table
|
||||
|
||||
static unsigned int HashString(const char *s) {
|
||||
unsigned int hash = 0;
|
||||
if (s) {
|
||||
while (*s) {
|
||||
hash = hash * 33 + *s++;
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// args:
|
||||
// - block device (or file) to modify in-place
|
||||
// - transfer list (blob)
|
||||
|
@ -1429,21 +1407,23 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
|
|||
}
|
||||
|
||||
FILE* cmd_pipe = ui->cmd_pipe;
|
||||
ZipArchive* za = ui->package_zip;
|
||||
ZipArchiveHandle za = ui->package_zip;
|
||||
|
||||
if (cmd_pipe == nullptr || za == nullptr) {
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data.c_str());
|
||||
if (patch_entry == nullptr) {
|
||||
ZipString path_data(patch_data_fn->data.c_str());
|
||||
ZipEntry patch_entry;
|
||||
if (FindEntry(za, path_data, &patch_entry) != 0) {
|
||||
fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data.c_str());
|
||||
return StringValue("");
|
||||
}
|
||||
|
||||
params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry);
|
||||
const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data.c_str());
|
||||
if (new_entry == nullptr) {
|
||||
params.patch_start = ui->package_zip_addr + patch_entry.offset;
|
||||
ZipString new_data(new_data_fn->data.c_str());
|
||||
ZipEntry new_entry;
|
||||
if (FindEntry(za, new_data, &new_entry) != 0) {
|
||||
fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str());
|
||||
return StringValue("");
|
||||
}
|
||||
|
@ -1526,13 +1506,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
|
|||
start += 2;
|
||||
}
|
||||
|
||||
// Build a hash table of the available commands
|
||||
HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr);
|
||||
std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree);
|
||||
|
||||
// Build a map of the available commands
|
||||
std::unordered_map<std::string, const Command*> cmd_map;
|
||||
for (size_t i = 0; i < cmdcount; ++i) {
|
||||
unsigned int cmdhash = HashString(commands[i].name);
|
||||
mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true);
|
||||
if (cmd_map.find(commands[i].name) != cmd_map.end()) {
|
||||
fprintf(stderr, "Error: command [%s] already exists in the cmd map.\n",
|
||||
commands[i].name);
|
||||
return StringValue(strdup(""));
|
||||
}
|
||||
cmd_map[commands[i].name] = &commands[i];
|
||||
}
|
||||
|
||||
int rc = -1;
|
||||
|
@ -1549,16 +1531,13 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg
|
|||
params.cmdname = params.tokens[params.cpos++].c_str();
|
||||
params.cmdline = line_str.c_str();
|
||||
|
||||
unsigned int cmdhash = HashString(params.cmdname);
|
||||
const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash,
|
||||
const_cast<char*>(params.cmdname), CompareCommandNames,
|
||||
false));
|
||||
|
||||
if (cmd == nullptr) {
|
||||
if (cmd_map.find(params.cmdname) == cmd_map.end()) {
|
||||
fprintf(stderr, "unexpected command [%s]\n", params.cmdname);
|
||||
goto pbiudone;
|
||||
}
|
||||
|
||||
const Command* cmd = cmd_map[params.cmdname];
|
||||
|
||||
if (cmd->f != nullptr && cmd->f(params) == -1) {
|
||||
fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str());
|
||||
goto pbiudone;
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#define _UPDATER_UPDATER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "minzip/Zip.h"
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
typedef struct {
|
||||
FILE* cmd_pipe;
|
||||
ZipArchive* package_zip;
|
||||
ZipArchiveHandle package_zip;
|
||||
int version;
|
||||
|
||||
uint8_t* package_zip_addr;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <sys/xattr.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -48,14 +49,16 @@
|
|||
#include <openssl/sha.h>
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "applypatch/applypatch.h"
|
||||
#include "bootloader.h"
|
||||
#include "edify/expr.h"
|
||||
#include "error_code.h"
|
||||
#include "minzip/DirUtil.h"
|
||||
#include "mounts.h"
|
||||
#include "ota_io.h"
|
||||
#include "otautil/DirUtil.h"
|
||||
#include "otautil/ZipUtil.h"
|
||||
#include "print_sha1.h"
|
||||
#include "tune2fs.h"
|
||||
#include "updater/updater.h"
|
||||
|
@ -465,14 +468,13 @@ Value* PackageExtractDirFn(const char* name, State* state,
|
|||
char* dest_path;
|
||||
if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
|
||||
|
||||
ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
|
||||
ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
|
||||
|
||||
// To create a consistent system image, never use the clock for timestamps.
|
||||
struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
|
||||
|
||||
bool success = mzExtractRecursive(za, zip_path, dest_path,
|
||||
×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<unsigned char *>(&v->data[0]));
|
||||
v->data.resize(entry.uncompressed_length);
|
||||
if (ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&v->data[0]),
|
||||
v->data.size()) != 0) {
|
||||
printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size());
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
|
||||
done1:
|
||||
free(zip_path);
|
||||
|
|
|
@ -21,14 +21,17 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "edify/expr.h"
|
||||
#include "minzip/SysUtil.h"
|
||||
#include "minzip/Zip.h"
|
||||
#include "otautil/DirUtil.h"
|
||||
#include "otautil/SysUtil.h"
|
||||
#include "updater/blockimg.h"
|
||||
#include "updater/install.h"
|
||||
|
||||
|
@ -82,28 +85,35 @@ int main(int argc, char** argv) {
|
|||
printf("failed to map package %s\n", argv[3]);
|
||||
return 3;
|
||||
}
|
||||
ZipArchive za;
|
||||
int err;
|
||||
err = mzOpenZipArchive(map.addr, map.length, &za);
|
||||
if (err != 0) {
|
||||
ZipArchiveHandle za;
|
||||
int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za);
|
||||
if (open_err != 0) {
|
||||
printf("failed to open package %s: %s\n",
|
||||
argv[3], strerror(err));
|
||||
argv[3], ErrorCodeString(open_err));
|
||||
CloseArchive(za);
|
||||
return 3;
|
||||
}
|
||||
ota_io_init(&za);
|
||||
ota_io_init(za);
|
||||
|
||||
const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
|
||||
if (script_entry == NULL) {
|
||||
printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename);
|
||||
ZipString script_name(SCRIPT_NAME);
|
||||
ZipEntry script_entry;
|
||||
int find_err = FindEntry(za, script_name, &script_entry);
|
||||
if (find_err != 0) {
|
||||
printf("failed to find %s in %s: %s\n", SCRIPT_NAME, package_filename,
|
||||
ErrorCodeString(find_err));
|
||||
CloseArchive(za);
|
||||
return 4;
|
||||
}
|
||||
|
||||
char* script = reinterpret_cast<char*>(malloc(script_entry->uncompLen+1));
|
||||
if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
|
||||
printf("failed to read script from package\n");
|
||||
std::string script;
|
||||
script.resize(script_entry.uncompressed_length);
|
||||
int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast<uint8_t*>(&script[0]),
|
||||
script_entry.uncompressed_length);
|
||||
if (extract_err != 0) {
|
||||
printf("failed to read script from package: %s\n", ErrorCodeString(extract_err));
|
||||
CloseArchive(za);
|
||||
return 5;
|
||||
}
|
||||
script[script_entry->uncompLen] = '\0';
|
||||
|
||||
// Configure edify's functions.
|
||||
|
||||
|
@ -116,9 +126,10 @@ 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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue