Kang in older minzip for building in CM9 & CM7
CM7 and CM9 do not have libselinux needed in the newer minzip.
This commit is contained in:
+5
-1
@@ -313,7 +313,6 @@ include $(BUILD_SHARED_LIBRARY)
|
||||
commands_recovery_local_path := $(LOCAL_PATH)
|
||||
include $(LOCAL_PATH)/minui/Android.mk \
|
||||
$(LOCAL_PATH)/minelf/Android.mk \
|
||||
$(LOCAL_PATH)/minzip/Android.mk \
|
||||
$(LOCAL_PATH)/minadbd/Android.mk \
|
||||
$(LOCAL_PATH)/tools/Android.mk \
|
||||
$(LOCAL_PATH)/edify/Android.mk \
|
||||
@@ -347,6 +346,11 @@ ifeq ($(TW_INCLUDE_JB_CRYPTO), true)
|
||||
include $(commands_recovery_local_path)/crypto/jb/Android.mk
|
||||
include $(commands_recovery_local_path)/crypto/fs_mgr/Android.mk
|
||||
endif
|
||||
ifeq ($(HAVE_SELINUX), true)
|
||||
include $(commands_recovery_local_path)/minzip/Android.mk
|
||||
else
|
||||
include $(commands_recovery_local_path)/minzipold/Android.mk
|
||||
endif
|
||||
ifeq ($(BUILD_ID), GINGERBREAD)
|
||||
TW_NO_EXFAT := true
|
||||
endif
|
||||
|
||||
@@ -64,6 +64,9 @@ endif
|
||||
ifneq ($(TW_NO_SCREEN_TIMEOUT),)
|
||||
LOCAL_CFLAGS += -DTW_NO_SCREEN_TIMEOUT
|
||||
endif
|
||||
ifeq ($(HAVE_SELINUX), true)
|
||||
LOCAL_CFLAGS += -DHAVE_SELINUX
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES += bionic external/stlport/stlport $(commands_recovery_local_path)/gui/devices/$(DEVICE_RESOLUTION)
|
||||
|
||||
|
||||
+6
-1
@@ -20,7 +20,6 @@ using namespace std;
|
||||
#include "rapidxml.hpp"
|
||||
using namespace rapidxml;
|
||||
extern "C" {
|
||||
#include "../minzip/Zip.h"
|
||||
#include "../minuitwrp/minui.h"
|
||||
}
|
||||
#include <string>
|
||||
@@ -37,9 +36,15 @@ extern "C" {
|
||||
#include <sstream>
|
||||
#include "pages.hpp"
|
||||
#include "blanktimer.hpp"
|
||||
#include "objects.hpp"
|
||||
#include "../data.hpp"
|
||||
extern "C" {
|
||||
#include "../twcommon.h"
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "../minzip/Zip.h"
|
||||
#else
|
||||
#include "../minzipold/Zip.h"
|
||||
#endif
|
||||
}
|
||||
#include "../twrp-functions.hpp"
|
||||
#include "../variables.h"
|
||||
|
||||
@@ -37,7 +37,11 @@ extern "C"
|
||||
{
|
||||
#include "../twcommon.h"
|
||||
#include "../minuitwrp/minui.h"
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "../minzip/Zip.h"
|
||||
#else
|
||||
#include "../minzipold/Zip.h"
|
||||
#endif
|
||||
#include <pixelflinger/pixelflinger.h>
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
#include <map>
|
||||
|
||||
extern "C" {
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "../minzip/Zip.h"
|
||||
#else
|
||||
#include "../minzipold/Zip.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace rapidxml;
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
#ifndef _PAGES_HEADER_HPP
|
||||
#define _PAGES_HEADER_HPP
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "../minzip/Zip.h"
|
||||
#else
|
||||
#include "../minzipold/Zip.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
#ifndef _RESOURCE_HEADER
|
||||
#define _RESOURCE_HEADER
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "../minzip/Zip.h"
|
||||
#else
|
||||
#include "../minzipold/Zip.h"
|
||||
#endif
|
||||
|
||||
// Base Objects
|
||||
class Resource
|
||||
{
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
Hash.c \
|
||||
SysUtil.c \
|
||||
DirUtil.c \
|
||||
Inlines.c \
|
||||
Zip.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/zlib \
|
||||
external/safe-iop/include
|
||||
|
||||
ifeq ($(HAVE_SELINUX),true)
|
||||
LOCAL_C_INCLUDES += external/libselinux/include
|
||||
LOCAL_STATIC_LIBRARIES += libselinux
|
||||
LOCAL_CFLAGS += -DHAVE_SELINUX
|
||||
endif
|
||||
|
||||
LOCAL_MODULE := libminzip
|
||||
|
||||
LOCAL_CFLAGS += -Wall
|
||||
LOCAL_SHARED_LIBRARIES := libz
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
Hash.c \
|
||||
SysUtil.c \
|
||||
DirUtil.c \
|
||||
Inlines.c \
|
||||
Zip.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/zlib \
|
||||
external/safe-iop/include
|
||||
|
||||
ifeq ($(HAVE_SELINUX),true)
|
||||
LOCAL_C_INCLUDES += external/libselinux/include
|
||||
LOCAL_STATIC_LIBRARIES += libselinux
|
||||
LOCAL_CFLAGS += -DHAVE_SELINUX
|
||||
endif
|
||||
|
||||
LOCAL_MODULE := libminzip
|
||||
|
||||
LOCAL_CFLAGS += -Wall
|
||||
LOCAL_STATIC_LIBRARIES := libz
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* 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*/
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "DirUtil.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
size_t pathLen = strlen(path);
|
||||
char *cpath = (char *)malloc(pathLen + 2);
|
||||
if (cpath == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
memcpy(cpath, path, pathLen);
|
||||
if (stripFileName) {
|
||||
/* Strip everything after the last slash.
|
||||
*/
|
||||
char *c = cpath + pathLen - 1;
|
||||
while (c != cpath && *c != '/') {
|
||||
c--;
|
||||
}
|
||||
if (c == cpath) {
|
||||
//xxx test this path
|
||||
/* No directory component. Act like the path was empty.
|
||||
*/
|
||||
errno = ENOENT;
|
||||
free(cpath);
|
||||
return -1;
|
||||
}
|
||||
c[1] = '\0'; // Terminate after the slash we found.
|
||||
} else {
|
||||
/* Make sure that the path ends in a slash.
|
||||
*/
|
||||
cpath[pathLen] = '/';
|
||||
cpath[pathLen + 1] = '\0';
|
||||
}
|
||||
|
||||
/* See if it already exists.
|
||||
*/
|
||||
ds = getPathDirStatus(cpath);
|
||||
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.
|
||||
*/
|
||||
char *p = cpath;
|
||||
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(cpath);
|
||||
if (ds == DILLEGAL) {
|
||||
/* Could happen if some other process/thread is
|
||||
* messing with the filesystem.
|
||||
*/
|
||||
free(cpath);
|
||||
return -1;
|
||||
} else if (ds == DMISSING) {
|
||||
int err;
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
char *secontext = NULL;
|
||||
|
||||
if (sehnd) {
|
||||
selabel_lookup(sehnd, &secontext, cpath, mode);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
err = mkdir(cpath, mode);
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (err != 0) {
|
||||
free(cpath);
|
||||
return -1;
|
||||
}
|
||||
if (timestamp != NULL && utime(cpath, timestamp)) {
|
||||
free(cpath);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// else, this directory already exists.
|
||||
|
||||
/* Repair the path and continue.
|
||||
*/
|
||||
*p = '/';
|
||||
}
|
||||
free(cpath);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int
|
||||
dirSetHierarchyPermissions(const char *path,
|
||||
int uid, int gid, int dirMode, int fileMode)
|
||||
{
|
||||
struct stat st;
|
||||
if (lstat(path, &st)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ignore symlinks */
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* directories and files get different permissions */
|
||||
if (chown(path, uid, gid) ||
|
||||
chmod(path, S_ISDIR(st.st_mode) ? dirMode : fileMode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* recurse over directory components */
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
DIR *dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
const struct dirent *de;
|
||||
while (errno == 0 && (de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char dn[PATH_MAX];
|
||||
snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name);
|
||||
if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) {
|
||||
errno = 0;
|
||||
} else if (errno == 0) {
|
||||
errno = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (errno != 0) {
|
||||
int save = errno;
|
||||
closedir(dir);
|
||||
errno = save;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (closedir(dir)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 <stdbool.h>
|
||||
#include <utime.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#else
|
||||
struct selabel_handle;
|
||||
#endif
|
||||
|
||||
/* Like "mkdir -p", try to guarantee that all directories
|
||||
* specified in path are present, creating as many directories
|
||||
* as necessary. The specified mode is passed to all mkdir
|
||||
* 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 <path>
|
||||
*/
|
||||
int dirUnlinkHierarchy(const char *path);
|
||||
|
||||
/* chown -R <uid>:<gid> <path>
|
||||
* chmod -R <mode> <path>
|
||||
*
|
||||
* Sets directories to <dirMode> and files to <fileMode>. Skips symlinks.
|
||||
*/
|
||||
int dirSetHierarchyPermissions(const char *path,
|
||||
int uid, int gid, int dirMode, int fileMode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MINZIP_DIRUTIL_H_
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define LOG_TAG "minzip"
|
||||
#include "Log.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);
|
||||
//LOGI("before: dead=%d\n", 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 */
|
||||
//LOGD("+++ match on entry %d\n", pEntry - pHashTable->pEntries);
|
||||
break;
|
||||
}
|
||||
|
||||
pEntry++;
|
||||
if (pEntry == pEnd) { /* wrap around to start */
|
||||
if (pHashTable->tableSize == 1)
|
||||
break; /* edge case - single-entry table */
|
||||
pEntry = pHashTable->pEntries;
|
||||
}
|
||||
|
||||
//LOGI("+++ look probing %d...\n", 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 */
|
||||
LOGE("Dalvik hash resize failure\n");
|
||||
abort();
|
||||
}
|
||||
/* note "pEntry" is now invalid */
|
||||
} else {
|
||||
//LOGW("okay %d/%d/%d\n",
|
||||
// pHashTable->numEntries, pHashTable->tableSize,
|
||||
// (pHashTable->tableSize * LOAD_NUMER) / LOAD_DENOM);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
//LOGI("+++ stepping on entry %d\n", pEntry - pHashTable->pEntries);
|
||||
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;
|
||||
}
|
||||
|
||||
//LOGI("+++ del probing %d...\n", 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;
|
||||
}
|
||||
|
||||
LOGI("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f\n",
|
||||
minProbe, maxProbe, totalProbe, numEntries, pHashTable->tableSize,
|
||||
(float) totalProbe / (float) numEntries);
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif /*_MINZIP_HASH*/
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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"
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Copyright 2005 The Android Open Source Project
|
||||
//
|
||||
// C/C++ logging functions. See the logging documentation for API details.
|
||||
//
|
||||
// We'd like these to be available from C code (in case we import some from
|
||||
// somewhere), so this has a C interface.
|
||||
//
|
||||
// The output will be correct when the log file is shared between multiple
|
||||
// threads and/or multiple processes so long as the operating system
|
||||
// supports O_APPEND. These calls have mutex-protected data structures
|
||||
// and so are NOT reentrant. Do not use LOG in a signal handler.
|
||||
//
|
||||
#ifndef _MINZIP_LOG_H
|
||||
#define _MINZIP_LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Normally we strip LOGV (VERBOSE messages) from release builds.
|
||||
* You can modify this (for example with "#define LOG_NDEBUG 0"
|
||||
* at the top of your source file) to change that behavior.
|
||||
*/
|
||||
#ifndef LOG_NDEBUG
|
||||
#ifdef NDEBUG
|
||||
#define LOG_NDEBUG 1
|
||||
#else
|
||||
#define LOG_NDEBUG 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the local tag used for the following simplified
|
||||
* logging macros. You can change this preprocessor definition
|
||||
* before using the other macros to change the tag.
|
||||
*/
|
||||
#ifndef LOG_TAG
|
||||
#define LOG_TAG NULL
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Simplified macro to send a verbose log message using the current LOG_TAG.
|
||||
*/
|
||||
#ifndef LOGV
|
||||
#if LOG_NDEBUG
|
||||
#define LOGV(...) ((void)0)
|
||||
#else
|
||||
#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
|
||||
|
||||
#ifndef LOGV_IF
|
||||
#if LOG_NDEBUG
|
||||
#define LOGV_IF(cond, ...) ((void)0)
|
||||
#else
|
||||
#define LOGV_IF(cond, ...) \
|
||||
( (CONDITION(cond)) \
|
||||
? ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LOGVV LOGV
|
||||
#define LOGVV_IF LOGV_IF
|
||||
|
||||
/*
|
||||
* Simplified macro to send a debug log message using the current LOG_TAG.
|
||||
*/
|
||||
#ifndef LOGD
|
||||
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef LOGD_IF
|
||||
#define LOGD_IF(cond, ...) \
|
||||
( (CONDITION(cond)) \
|
||||
? ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simplified macro to send an info log message using the current LOG_TAG.
|
||||
*/
|
||||
#ifndef LOGI
|
||||
#define LOGI(...) ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef LOGI_IF
|
||||
#define LOGI_IF(cond, ...) \
|
||||
( (CONDITION(cond)) \
|
||||
? ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simplified macro to send a warning log message using the current LOG_TAG.
|
||||
*/
|
||||
#ifndef LOGW
|
||||
#define LOGW(...) ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef LOGW_IF
|
||||
#define LOGW_IF(cond, ...) \
|
||||
( (CONDITION(cond)) \
|
||||
? ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simplified macro to send an error log message using the current LOG_TAG.
|
||||
*/
|
||||
#ifndef LOGE
|
||||
#define LOGE(...) ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef LOGE_IF
|
||||
#define LOGE_IF(cond, ...) \
|
||||
( (CONDITION(cond)) \
|
||||
? ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Conditional based on whether the current LOG_TAG is enabled at
|
||||
* verbose priority.
|
||||
*/
|
||||
#ifndef IF_LOGV
|
||||
#if LOG_NDEBUG
|
||||
#define IF_LOGV() if (false)
|
||||
#else
|
||||
#define IF_LOGV() IF_LOG(LOG_VERBOSE, LOG_TAG)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Conditional based on whether the current LOG_TAG is enabled at
|
||||
* debug priority.
|
||||
*/
|
||||
#ifndef IF_LOGD
|
||||
#define IF_LOGD() IF_LOG(LOG_DEBUG, LOG_TAG)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Conditional based on whether the current LOG_TAG is enabled at
|
||||
* info priority.
|
||||
*/
|
||||
#ifndef IF_LOGI
|
||||
#define IF_LOGI() IF_LOG(LOG_INFO, LOG_TAG)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Conditional based on whether the current LOG_TAG is enabled at
|
||||
* warn priority.
|
||||
*/
|
||||
#ifndef IF_LOGW
|
||||
#define IF_LOGW() IF_LOG(LOG_WARN, LOG_TAG)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Conditional based on whether the current LOG_TAG is enabled at
|
||||
* error priority.
|
||||
*/
|
||||
#ifndef IF_LOGE
|
||||
#define IF_LOGE() IF_LOG(LOG_ERROR, LOG_TAG)
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Basic log message macro.
|
||||
*
|
||||
* Example:
|
||||
* LOG(LOG_WARN, NULL, "Failed with error %d", errno);
|
||||
*
|
||||
* The second argument may be NULL or "" to indicate the "global" tag.
|
||||
*
|
||||
* Non-gcc probably won't have __FUNCTION__. It's not vital. gcc also
|
||||
* offers __PRETTY_FUNCTION__, which is rather more than we need.
|
||||
*/
|
||||
#ifndef LOG
|
||||
#define LOG(priority, tag, ...) \
|
||||
LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Log macro that allows you to specify a number for the priority.
|
||||
*/
|
||||
#ifndef LOG_PRI
|
||||
#define LOG_PRI(priority, tag, ...) \
|
||||
printf(tag ": " __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Conditional given a desired logging priority and tag.
|
||||
*/
|
||||
#ifndef IF_LOG
|
||||
#define IF_LOG(priority, tag) \
|
||||
if (1)
|
||||
#endif
|
||||
|
||||
#endif // _MINZIP_LOG_H
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* System utilities.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LOG_TAG "minzip"
|
||||
#include "Log.h"
|
||||
#include "SysUtil.h"
|
||||
|
||||
/*
|
||||
* Having trouble finding a portable way to get this. sysconf(_SC_PAGE_SIZE)
|
||||
* seems appropriate, but we don't have that on the device. Some systems
|
||||
* have getpagesize(2), though the linux man page has some odd cautions.
|
||||
*/
|
||||
#define DEFAULT_PAGE_SIZE 4096
|
||||
|
||||
|
||||
/*
|
||||
* Create an anonymous shared memory segment large enough to hold "length"
|
||||
* bytes. The actual segment may be larger because mmap() operates on
|
||||
* page boundaries (usually 4K).
|
||||
*/
|
||||
static void* sysCreateAnonShmem(size_t length)
|
||||
{
|
||||
void* ptr;
|
||||
|
||||
ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANON, -1, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
LOGW("mmap(%d, RW, SHARED|ANON) failed: %s\n", (int) length,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
|
||||
{
|
||||
off_t start, end;
|
||||
size_t length;
|
||||
|
||||
assert(start_ != NULL);
|
||||
assert(length_ != NULL);
|
||||
|
||||
start = lseek(fd, 0L, SEEK_CUR);
|
||||
end = lseek(fd, 0L, SEEK_END);
|
||||
(void) lseek(fd, start, SEEK_SET);
|
||||
|
||||
if (start == (off_t) -1 || end == (off_t) -1) {
|
||||
LOGE("could not determine length of file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = end - start;
|
||||
if (length == 0) {
|
||||
LOGE("file is empty\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*start_ = start;
|
||||
*length_ = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull the contents of a file into an new shared memory segment. We grab
|
||||
* everything from fd's current offset on.
|
||||
*
|
||||
* We need to know the length ahead of time so we can allocate a segment
|
||||
* of sufficient size.
|
||||
*/
|
||||
int sysLoadFileInShmem(int fd, MemMapping* pMap)
|
||||
{
|
||||
off_t start;
|
||||
size_t length, actual;
|
||||
void* memPtr;
|
||||
|
||||
assert(pMap != NULL);
|
||||
|
||||
if (getFileStartAndLength(fd, &start, &length) < 0)
|
||||
return -1;
|
||||
|
||||
memPtr = sysCreateAnonShmem(length);
|
||||
if (memPtr == NULL)
|
||||
return -1;
|
||||
|
||||
actual = read(fd, memPtr, length);
|
||||
if (actual != length) {
|
||||
LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
|
||||
sysReleaseShmem(pMap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pMap->baseAddr = pMap->addr = memPtr;
|
||||
pMap->baseLength = pMap->length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map a file (from fd's current offset) into a shared, read-only memory
|
||||
* segment. The file offset must be a multiple of the page size.
|
||||
*
|
||||
* On success, returns 0 and fills out "pMap". On failure, returns a nonzero
|
||||
* value and does not disturb "pMap".
|
||||
*/
|
||||
int sysMapFileInShmem(int fd, MemMapping* pMap)
|
||||
{
|
||||
off_t start;
|
||||
size_t length;
|
||||
void* memPtr;
|
||||
|
||||
assert(pMap != NULL);
|
||||
|
||||
if (getFileStartAndLength(fd, &start, &length) < 0)
|
||||
return -1;
|
||||
|
||||
memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
|
||||
if (memPtr == MAP_FAILED) {
|
||||
LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", (int) length,
|
||||
fd, (int) start, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pMap->baseAddr = pMap->addr = memPtr;
|
||||
pMap->baseLength = pMap->length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map part of a file (from fd's current offset) into a shared, read-only
|
||||
* memory segment.
|
||||
*
|
||||
* On success, returns 0 and fills out "pMap". On failure, returns a nonzero
|
||||
* value and does not disturb "pMap".
|
||||
*/
|
||||
int sysMapFileSegmentInShmem(int fd, off_t start, long length,
|
||||
MemMapping* pMap)
|
||||
{
|
||||
off_t dummy;
|
||||
size_t fileLength, actualLength;
|
||||
off_t actualStart;
|
||||
int adjust;
|
||||
void* memPtr;
|
||||
|
||||
assert(pMap != NULL);
|
||||
|
||||
if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
|
||||
return -1;
|
||||
|
||||
if (start + length > (long)fileLength) {
|
||||
LOGW("bad segment: st=%d len=%ld flen=%d\n",
|
||||
(int) start, length, (int) fileLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* adjust to be page-aligned */
|
||||
adjust = start % DEFAULT_PAGE_SIZE;
|
||||
actualStart = start - adjust;
|
||||
actualLength = length + adjust;
|
||||
|
||||
memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
|
||||
fd, actualStart);
|
||||
if (memPtr == MAP_FAILED) {
|
||||
LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n",
|
||||
(int) actualLength, fd, (int) actualStart, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pMap->baseAddr = memPtr;
|
||||
pMap->baseLength = actualLength;
|
||||
pMap->addr = (char*)memPtr + adjust;
|
||||
pMap->length = length;
|
||||
|
||||
LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n",
|
||||
(int) start, (int) length,
|
||||
pMap->baseAddr, (int) pMap->baseLength,
|
||||
pMap->addr, (int) pMap->length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a memory mapping.
|
||||
*/
|
||||
void sysReleaseShmem(MemMapping* pMap)
|
||||
{
|
||||
if (pMap->baseAddr == NULL && pMap->baseLength == 0)
|
||||
return;
|
||||
|
||||
if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
|
||||
LOGW("munmap(%p, %d) failed: %s\n",
|
||||
pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
|
||||
} else {
|
||||
LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength);
|
||||
pMap->baseAddr = NULL;
|
||||
pMap->baseLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* System utilities.
|
||||
*/
|
||||
#ifndef _MINZIP_SYSUTIL
|
||||
#define _MINZIP_SYSUTIL
|
||||
|
||||
#include "inline_magic.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* Use this to keep track of mapped segments.
|
||||
*/
|
||||
typedef struct MemMapping {
|
||||
void* addr; /* start of data */
|
||||
size_t length; /* length of data */
|
||||
|
||||
void* baseAddr; /* page-aligned base address */
|
||||
size_t baseLength; /* length of mapping */
|
||||
} MemMapping;
|
||||
|
||||
/* copy a map */
|
||||
INLINE void sysCopyMap(MemMapping* dst, const MemMapping* src) {
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a file into a new shared memory segment. All data from the current
|
||||
* offset to the end of the file is pulled in.
|
||||
*
|
||||
* The segment is read-write, allowing VM fixups. (It should be modified
|
||||
* to support .gz/.zip compressed data.)
|
||||
*
|
||||
* On success, "pMap" is filled in, and zero is returned.
|
||||
*/
|
||||
int sysLoadFileInShmem(int fd, MemMapping* pMap);
|
||||
|
||||
/*
|
||||
* Map a file (from fd's current offset) into a shared,
|
||||
* read-only memory segment.
|
||||
*
|
||||
* On success, "pMap" is filled in, and zero is returned.
|
||||
*/
|
||||
int sysMapFileInShmem(int fd, MemMapping* pMap);
|
||||
|
||||
/*
|
||||
* Like sysMapFileInShmem, but on only part of a file.
|
||||
*/
|
||||
int sysMapFileSegmentInShmem(int fd, off_t start, long length,
|
||||
MemMapping* pMap);
|
||||
|
||||
/*
|
||||
* Release the pages associated with a shared memory segment.
|
||||
*
|
||||
* This does not free "pMap"; it just releases the memory.
|
||||
*/
|
||||
void sysReleaseShmem(MemMapping* pMap);
|
||||
|
||||
#endif /*_MINZIP_SYSUTIL*/
|
||||
+1168
File diff suppressed because it is too large
Load Diff
+229
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#else
|
||||
struct selabel_handle;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* One entry in the Zip archive. Treat this as opaque -- use accessors below.
|
||||
*
|
||||
* 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
|
||||
long offset;
|
||||
long compLen;
|
||||
long uncompLen;
|
||||
int compression;
|
||||
long modTime;
|
||||
long crc32;
|
||||
int versionMadeBy;
|
||||
long externalFileAttributes;
|
||||
} ZipEntry;
|
||||
|
||||
/*
|
||||
* One Zip archive. Treat as opaque.
|
||||
*/
|
||||
typedef struct ZipArchive {
|
||||
int fd;
|
||||
unsigned int numEntries;
|
||||
ZipEntry* pEntries;
|
||||
HashTable* pHash; // maps file name to ZipEntry
|
||||
MemMapping map;
|
||||
} 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(const char* fileName, 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);
|
||||
|
||||
/*
|
||||
* Get the number of entries in the Zip archive.
|
||||
*/
|
||||
INLINE unsigned int mzZipEntryCount(const ZipArchive* pArchive) {
|
||||
return pArchive->numEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get an entry by index. Returns NULL if the index is out-of-bounds.
|
||||
*/
|
||||
INLINE const ZipEntry*
|
||||
mzGetZipEntryAt(const ZipArchive* pArchive, unsigned int index)
|
||||
{
|
||||
if (index < pArchive->numEntries) {
|
||||
return pArchive->pEntries + index;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the index number of an entry in the archive.
|
||||
*/
|
||||
INLINE unsigned int
|
||||
mzGetZipEntryIndex(const ZipArchive *pArchive, const ZipEntry *pEntry) {
|
||||
return pEntry - pArchive->pEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple accessors.
|
||||
*/
|
||||
INLINE UnterminatedString mzGetZipEntryFileName(const ZipEntry* pEntry) {
|
||||
UnterminatedString ret;
|
||||
ret.str = pEntry->fileName;
|
||||
ret.len = pEntry->fileNameLen;
|
||||
return ret;
|
||||
}
|
||||
INLINE long mzGetZipEntryOffset(const ZipEntry* pEntry) {
|
||||
return pEntry->offset;
|
||||
}
|
||||
INLINE long mzGetZipEntryUncompLen(const ZipEntry* pEntry) {
|
||||
return pEntry->uncompLen;
|
||||
}
|
||||
INLINE long mzGetZipEntryModTime(const ZipEntry* pEntry) {
|
||||
return pEntry->modTime;
|
||||
}
|
||||
INLINE long mzGetZipEntryCrc32(const ZipEntry* pEntry) {
|
||||
return pEntry->crc32;
|
||||
}
|
||||
bool mzIsZipEntrySymlink(const ZipEntry* pEntry);
|
||||
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Check the CRC on this entry; return true if it is correct.
|
||||
* May do other internal checks as well.
|
||||
*/
|
||||
bool mzIsZipEntryIntact(const ZipArchive *pArchive, const ZipEntry *pEntry);
|
||||
|
||||
/*
|
||||
* 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 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
|
||||
*
|
||||
* flags is zero or more of the following:
|
||||
*
|
||||
* MZ_EXTRACT_FILES_ONLY - only unpack files, not directories or symlinks
|
||||
* MZ_EXTRACT_DRY_RUN - don't do anything, but do invoke the callback
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
enum { MZ_EXTRACT_FILES_ONLY = 1, MZ_EXTRACT_DRY_RUN = 2 };
|
||||
bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
const char *zipDir, const char *targetDir,
|
||||
int flags, const struct utimbuf *timestamp,
|
||||
void (*callback)(const char *fn, void*), void *cookie,
|
||||
struct selabel_handle *sehnd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_MINZIP_ZIP*/
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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_
|
||||
@@ -14,8 +14,13 @@
|
||||
#include "mincrypt/rsa.h"
|
||||
#include "mincrypt/sha.h"
|
||||
#include "minui/minui.h"
|
||||
#ifdef HAVE_SELINUX
|
||||
#include "minzip/SysUtil.h"
|
||||
#include "minzip/Zip.h"
|
||||
#else
|
||||
#include "minzipold/SysUtil.h"
|
||||
#include "minzipold/Zip.h"
|
||||
#endif
|
||||
#include "mtdutils/mounts.h"
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "verifier.h"
|
||||
|
||||
Reference in New Issue
Block a user