diff --git a/libs/minzip/Bits.h b/libs/minzip/Bits.h old mode 100644 new mode 100755 diff --git a/libs/minzip/DirUtil.c b/libs/minzip/DirUtil.c old mode 100644 new mode 100755 index 20c89cd..97cb2e0 --- a/libs/minzip/DirUtil.c +++ b/libs/minzip/DirUtil.c @@ -54,7 +54,8 @@ getPathDirStatus(const char *path) int dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName) + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle *sehnd) { DirStatus ds; @@ -84,7 +85,7 @@ dirCreateHierarchy(const char *path, int mode, c--; } if (c == cpath) { -//xxx test this path + //xxx test this path /* No directory component. Act like the path was empty. */ errno = ENOENT; @@ -144,7 +145,20 @@ dirCreateHierarchy(const char *path, int mode, } else if (ds == DMISSING) { int err; + char *secontext = NULL; + + if (sehnd) { + selabel_lookup(sehnd, &secontext, cpath, mode); + setfscreatecon(secontext); + } + err = mkdir(cpath, mode); + + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } + if (err != 0) { free(cpath); return -1; @@ -192,7 +206,7 @@ dirUnlinkHierarchy(const char *path) /* recurse over components */ errno = 0; while ((de = readdir(dir)) != NULL) { -//TODO: don't blow the stack + //TODO: don't blow the stack char dn[PATH_MAX]; if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { continue; @@ -220,61 +234,3 @@ dirUnlinkHierarchy(const char *path) /* 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; -} diff --git a/libs/minzip/DirUtil.h b/libs/minzip/DirUtil.h old mode 100644 new mode 100755 index 5d881f5..85a0012 --- a/libs/minzip/DirUtil.h +++ b/libs/minzip/DirUtil.h @@ -20,6 +20,13 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + /* 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 @@ -34,18 +41,15 @@ * (usually if some element of path is not a directory). */ int dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName); + const struct utimbuf *timestamp, bool stripFileName, + struct selabel_handle* sehnd); /* rm -rf */ int dirUnlinkHierarchy(const char *path); -/* chown -R : - * chmod -R - * - * Sets directories to and files to . Skips symlinks. - */ -int dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode); +#ifdef __cplusplus +} +#endif #endif // MINZIP_DIRUTIL_H_ diff --git a/libs/minzip/Hash.c b/libs/minzip/Hash.c old mode 100644 new mode 100755 index 8c6ca9b..49bcb31 --- a/libs/minzip/Hash.c +++ b/libs/minzip/Hash.c @@ -140,7 +140,6 @@ static bool resizeHash(HashTable* pHashTable, int newSize) int i; assert(countTombStones(pHashTable) == pHashTable->numDeadEntries); - //LOGI("before: dead=%d\n", pHashTable->numDeadEntries); pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashTable)); if (pNewEntries == NULL) @@ -196,7 +195,6 @@ void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item (*cmpFunc)(pEntry->data, item) == 0) { /* match */ - //LOGD("+++ match on entry %d\n", pEntry - pHashTable->pEntries); break; } @@ -206,8 +204,6 @@ void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item break; /* edge case - single-entry table */ pEntry = pHashTable->pEntries; } - - //LOGI("+++ look probing %d...\n", pEntry - pHashTable->pEntries); } if (pEntry->data == NULL) { @@ -228,10 +224,6 @@ void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item 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 */ @@ -264,7 +256,6 @@ bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item) 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++; @@ -277,8 +268,6 @@ bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item) break; /* edge case - single-entry table */ pEntry = pHashTable->pEntries; } - - //LOGI("+++ del probing %d...\n", pEntry - pHashTable->pEntries); } return false; @@ -372,7 +361,7 @@ void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc, { const void* data = (const void*)mzHashIterData(&iter); int count; - + count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc); numEntries++; @@ -384,7 +373,7 @@ void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc, totalProbe += count; } - LOGI("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f\n", + LOGV("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f\n", minProbe, maxProbe, totalProbe, numEntries, pHashTable->tableSize, (float) totalProbe / (float) numEntries); } diff --git a/libs/minzip/Hash.h b/libs/minzip/Hash.h old mode 100644 new mode 100755 index 8194537..e83eac4 --- a/libs/minzip/Hash.h +++ b/libs/minzip/Hash.h @@ -15,6 +15,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* compute the hash of an item with a specific type */ typedef unsigned int (*HashCompute)(const void* item); @@ -183,4 +187,8 @@ typedef unsigned int (*HashCalcFunc)(const void* item); void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc, HashCompareFunc cmpFunc); +#ifdef __cplusplus +} +#endif + #endif /*_MINZIP_HASH*/ diff --git a/libs/minzip/Inlines.c b/libs/minzip/Inlines.c old mode 100644 new mode 100755 diff --git a/libs/minzip/Log.h b/libs/minzip/Log.h old mode 100644 new mode 100755 index 988aee4..36e62f5 --- a/libs/minzip/Log.h +++ b/libs/minzip/Log.h @@ -18,9 +18,6 @@ // --------------------------------------------------------------------- -#define NDEBUG -#define LOG_NDEBUG 1 - /* * Normally we strip LOGV (VERBOSE messages) from release builds. * You can modify this (for example with "#define LOG_NDEBUG 0" diff --git a/libs/minzip/SysUtil.c b/libs/minzip/SysUtil.c old mode 100644 new mode 100755 index 49a2522..09ec876 --- a/libs/minzip/SysUtil.c +++ b/libs/minzip/SysUtil.c @@ -3,210 +3,173 @@ * * System utilities. */ -#include +#include +#include +#include +#include +#include #include -#include +#include #include #include -#include -#include -#include +#include +#include +#include -#define LOG_TAG "minzip" +#define LOG_TAG "sysutil" #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 +static bool sysMapFD(int fd, MemMapping* pMap) { + assert(pMap != NULL); + struct stat sb; + if (fstat(fd, &sb) == -1) { + LOGE("fstat(%d) failed: %s\n", fd, strerror(errno)); + return false; + } -/* - * 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; + void* memPtr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (memPtr == MAP_FAILED) { + LOGE("mmap(%d, R, PRIVATE, %d, 0) failed: %s\n", (int) sb.st_size, fd, strerror(errno)); + return false; } - return ptr; + pMap->addr = memPtr; + pMap->length = sb.st_size; + pMap->range_count = 1; + pMap->ranges = malloc(sizeof(MappedRange)); + pMap->ranges[0].addr = memPtr; + pMap->ranges[0].length = sb.st_size; + + return true; } -static int getFileStartAndLength(int fd, off_t *start_, size_t *length_) +static int sysMapBlockFile(FILE* mapf, MemMapping* pMap) { - 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"); + char block_dev[PATH_MAX+1]; + size_t size; + unsigned int blksize; + unsigned int blocks; + unsigned int range_count; + unsigned int i; + + if (fgets(block_dev, sizeof(block_dev), mapf) == NULL) { + LOGE("failed to read block device from header\n"); return -1; } + for (i = 0; i < sizeof(block_dev); ++i) { + if (block_dev[i] == '\n') { + block_dev[i] = 0; + break; + } + } - length = end - start; - if (length == 0) { - LOGE("file is empty\n"); + if (fscanf(mapf, "%zu %u\n%u\n", &size, &blksize, &range_count) != 3) { + LOGE("failed to parse block map header\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; + blocks = ((size-1) / blksize) + 1; - assert(pMap != NULL); - - if (getFileStartAndLength(fd, &start, &length) < 0) - return -1; - - memPtr = sysCreateAnonShmem(length); - if (memPtr == NULL) - return -1; + pMap->range_count = range_count; + pMap->ranges = malloc(range_count * sizeof(MappedRange)); + memset(pMap->ranges, 0, range_count * sizeof(MappedRange)); - actual = read(fd, memPtr, length); - if (actual != length) { - LOGE("only read %d of %d bytes\n", (int) actual, (int) length); - sysReleaseShmem(pMap); + // Reserve enough contiguous address space for the whole file. + unsigned char* reserve; + reserve = mmap64(NULL, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (reserve == MAP_FAILED) { + LOGE("failed to reserve address space: %s\n", strerror(errno)); return -1; } - pMap->baseAddr = pMap->addr = memPtr; - pMap->baseLength = pMap->length = length; + pMap->ranges[range_count-1].addr = reserve; + pMap->ranges[range_count-1].length = blocks * blksize; - 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) + int fd = open(block_dev, O_RDONLY); + if (fd < 0) { + LOGE("failed to open block device %s: %s\n", block_dev, strerror(errno)); 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; + unsigned char* next = reserve; + for (i = 0; i < range_count; ++i) { + int start, end; + if (fscanf(mapf, "%d %d\n", &start, &end) != 2) { + LOGE("failed to parse range %d in block map\n", i); + return -1; + } + + void* addr = mmap64(next, (end-start)*blksize, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize); + if (addr == MAP_FAILED) { + LOGE("failed to map block %d: %s\n", i, strerror(errno)); + return -1; + } + pMap->ranges[i].addr = addr; + pMap->ranges[i].length = (end-start)*blksize; + + next += pMap->ranges[i].length; } - pMap->baseAddr = pMap->addr = memPtr; - pMap->baseLength = pMap->length = length; + pMap->addr = reserve; + pMap->length = size; + + LOGI("mmapped %d ranges\n", range_count); 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) +int sysMapFile(const char* fn, 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; + memset(pMap, 0, sizeof(*pMap)); + + if (fn && fn[0] == '@') { + // A map of blocks + FILE* mapf = fopen(fn+1, "r"); + if (mapf == NULL) { + LOGE("Unable to open '%s': %s\n", fn+1, strerror(errno)); + return -1; + } + + if (sysMapBlockFile(mapf, pMap) != 0) { + LOGE("Map of '%s' failed\n", fn); + return -1; + } + + fclose(mapf); + } else { + // This is a regular file. + int fd = open(fn, O_RDONLY); + if (fd == -1) { + LOGE("Unable to open '%s': %s\n", fn, strerror(errno)); + return -1; + } + + if (!sysMapFD(fd, pMap)) { + LOGE("Map of '%s' failed\n", fn); + close(fd); + return -1; + } + + close(fd); } - - 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) +void sysReleaseMap(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; + int i; + for (i = 0; i < pMap->range_count; ++i) { + if (munmap(pMap->ranges[i].addr, pMap->ranges[i].length) < 0) { + LOGE("munmap(%p, %d) failed: %s\n", + pMap->ranges[i].addr, (int)pMap->ranges[i].length, strerror(errno)); + } } + free(pMap->ranges); + pMap->ranges = NULL; + pMap->range_count = 0; } - diff --git a/libs/minzip/SysUtil.h b/libs/minzip/SysUtil.h old mode 100644 new mode 100755 index ec3a4bc..7adff1e --- a/libs/minzip/SysUtil.h +++ b/libs/minzip/SysUtil.h @@ -6,56 +6,47 @@ #ifndef _MINZIP_SYSUTIL #define _MINZIP_SYSUTIL -#include "inline_magic.h" - +#include #include +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappedRange { + void* addr; + size_t length; +} MappedRange; + /* * Use this to keep track of mapped segments. */ typedef struct MemMapping { - void* addr; /* start of data */ - size_t length; /* length of data */ + unsigned char* addr; /* start of data */ + size_t length; /* length of data */ - void* baseAddr; /* page-aligned base address */ - size_t baseLength; /* length of mapping */ + int range_count; + MappedRange* ranges; } 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. + * Map a file into a private, read-only memory segment. If 'fn' + * begins with an '@' character, it is a map of blocks to be mapped, + * otherwise it is treated as an ordinary file. * * On success, "pMap" is filled in, and zero is returned. */ -int 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); +int sysMapFile(const char* fn, MemMapping* pMap); /* * Release the pages associated with a shared memory segment. * * This does not free "pMap"; it just releases the memory. */ -void sysReleaseShmem(MemMapping* pMap); +void sysReleaseMap(MemMapping* pMap); + +#ifdef __cplusplus +} +#endif #endif /*_MINZIP_SYSUTIL*/ diff --git a/libs/minzip/Zip.c b/libs/minzip/Zip.c old mode 100644 new mode 100755 index 5ca3dd6..bdb565c --- a/libs/minzip/Zip.c +++ b/libs/minzip/Zip.c @@ -4,7 +4,7 @@ * Simple Zip file support. */ #include "safe_iop.h" -#include +#include "zlib.h" #include #include @@ -41,7 +41,7 @@ enum { CENSIZ = 20, CENLEN = 24, CENNAM = 28, - CENEXT = 30, + CENEXT = 30, CENCOM = 32, CENDSK = 34, CENATT = 36, @@ -66,13 +66,13 @@ enum { LOCSIG = 0x04034b50, // PK34 LOCHDR = 30, - + LOCVER = 4, LOCFLG = 6, LOCHOW = 8, LOCTIM = 10, LOCCRC = 14, - LOCSIZ = 18, + LOCSIZ = 18, LOCLEN = 22, LOCNAM = 26, LOCEXT = 28, @@ -184,7 +184,7 @@ static int validFilename(const char *fileName, unsigned int fileNameLen) * * Returns "true" on success. */ -static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) +static bool parseZipArchive(ZipArchive* pArchive) { bool result = false; const unsigned char* ptr; @@ -196,12 +196,12 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) * signature for the first file (LOCSIG) or, if the archive doesn't * have any files in it, the end-of-central-directory signature (ENDSIG). */ - val = get4LE(pMap->addr); + val = get4LE(pArchive->addr); if (val == ENDSIG) { - LOGI("Found Zip archive, but it looks empty\n"); + LOGW("Found Zip archive, but it looks empty\n"); goto bail; } else if (val != LOCSIG) { - LOGV("Not a Zip archive (found 0x%08x)\n", val); + LOGW("Not a Zip archive (found 0x%08x)\n", val); goto bail; } @@ -209,15 +209,15 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) * Find the EOCD. We'll find it immediately unless they have a file * comment. */ - ptr = pMap->addr + pMap->length - ENDHDR; + ptr = pArchive->addr + pArchive->length - ENDHDR; - while (ptr >= (const unsigned char*) pMap->addr) { + while (ptr >= (const unsigned char*) pArchive->addr) { if (*ptr == (ENDSIG & 0xff) && get4LE(ptr) == ENDSIG) break; ptr--; } - if (ptr < (const unsigned char*) pMap->addr) { - LOGI("Could not find end-of-central-directory in Zip\n"); + if (ptr < (const unsigned char*) pArchive->addr) { + LOGW("Could not find end-of-central-directory in Zip\n"); goto bail; } @@ -230,9 +230,9 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) cdOffset = get4LE(ptr + ENDOFF); LOGVV("numEntries=%d cdOffset=%d\n", numEntries, cdOffset); - if (numEntries == 0 || cdOffset >= pMap->length) { + if (numEntries == 0 || cdOffset >= pArchive->length) { LOGW("Invalid entries=%d offset=%d (len=%zd)\n", - numEntries, cdOffset, pMap->length); + numEntries, cdOffset, pArchive->length); goto bail; } @@ -245,14 +245,14 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) if (pArchive->pEntries == NULL || pArchive->pHash == NULL) goto bail; - ptr = pMap->addr + cdOffset; + ptr = pArchive->addr + cdOffset; for (i = 0; i < numEntries; i++) { ZipEntry* pEntry; unsigned int fileNameLen, extraLen, commentLen, localHdrOffset; const unsigned char* localHdr; const char *fileName; - if (ptr + CENHDR > (const unsigned char*)pMap->addr + pMap->length) { + if (ptr + CENHDR > (const unsigned char*)pArchive->addr + pArchive->length) { LOGW("Ran off the end (at %d)\n", i); goto bail; } @@ -266,9 +266,7 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) extraLen = get2LE(ptr + CENEXT); commentLen = get2LE(ptr + CENCOM); fileName = (const char*)ptr + CENHDR; - - - if (fileName + fileNameLen > (const char*)pMap->addr + pMap->length) { + if (fileName + fileNameLen > (const char*)pArchive->addr + pArchive->length) { LOGW("Filename ran off the end (at %d)\n", i); goto bail; } @@ -329,10 +327,6 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) #else pEntry = &pArchive->pEntries[i]; #endif - - //LOGI("%d: localHdr=%d fnl=%d el=%d cl=%d\n", - // i, localHdrOffset, fileNameLen, extraLen, commentLen); - pEntry->fileNameLen = fileNameLen; pEntry->fileName = fileName; @@ -354,15 +348,15 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) } pEntry->externalFileAttributes = get4LE(ptr + CENATX); - // Perform pMap->addr + localHdrOffset, ensuring that it won't + // Perform pArchive->addr + localHdrOffset, ensuring that it won't // overflow. This is needed because localHdrOffset is untrusted. - if (!safe_add((uintptr_t *)&localHdr, (uintptr_t)pMap->addr, + if (!safe_add((uintptr_t *)&localHdr, (uintptr_t)pArchive->addr, (uintptr_t)localHdrOffset)) { LOGW("Integer overflow adding in parseZipArchive\n"); goto bail; } if ((uintptr_t)localHdr + LOCHDR > - (uintptr_t)pMap->addr + pMap->length) { + (uintptr_t)pArchive->addr + pArchive->length) { LOGW("Bad offset to local header: %d (at %d)\n", localHdrOffset, i); goto bail; } @@ -376,7 +370,7 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) LOGW("Integer overflow adding in parseZipArchive\n"); goto bail; } - if ((size_t)pEntry->offset + pEntry->compLen > pMap->length) { + if ((size_t)pEntry->offset + pEntry->compLen > pArchive->length) { LOGW("Data ran off the end (at %d)\n", i); goto bail; } @@ -429,50 +423,30 @@ static bool parseZipArchive(ZipArchive* pArchive, const MemMapping* pMap) * * On success, we fill out the contents of "pArchive". */ -int mzOpenZipArchive(const char* fileName, ZipArchive* pArchive) +int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive) { - MemMapping map; int err; - LOGV("Opening archive '%s' %p\n", fileName, pArchive); - - map.addr = NULL; - memset(pArchive, 0, sizeof(*pArchive)); - - pArchive->fd = open(fileName, O_RDONLY, 0); - if (pArchive->fd < 0) { - err = errno ? errno : -1; - LOGV("Unable to open '%s': %s\n", fileName, strerror(err)); - goto bail; - } - - if (sysMapFileInShmem(pArchive->fd, &map) != 0) { + if (length < ENDHDR) { err = -1; - LOGW("Map of '%s' failed\n", fileName); + LOGW("Archive %p is too small to be zip (%zd)\n", pArchive, length); goto bail; } - if (map.length < ENDHDR) { - err = -1; - LOGV("File '%s' too small to be zip (%zd)\n", fileName, map.length); - goto bail; - } + pArchive->addr = addr; + pArchive->length = length; - if (!parseZipArchive(pArchive, &map)) { + if (!parseZipArchive(pArchive)) { err = -1; - LOGV("Parsing '%s' failed\n", fileName); + LOGW("Parsing archive %p failed\n", pArchive); goto bail; } err = 0; - sysCopyMap(&pArchive->map, &map); - map.addr = NULL; bail: if (err != 0) mzCloseZipArchive(pArchive); - if (map.addr != NULL) - sysReleaseShmem(&map); return err; } @@ -485,16 +459,10 @@ void mzCloseZipArchive(ZipArchive* pArchive) { LOGV("Closing archive %p\n", pArchive); - if (pArchive->fd >= 0) - close(pArchive->fd); - if (pArchive->map.addr != NULL) - sysReleaseShmem(&pArchive->map); - free(pArchive->pEntries); mzHashTableFree(pArchive->pHash); - pArchive->fd = -1; pArchive->pHash = NULL; pArchive->pEntries = NULL; } @@ -516,7 +484,7 @@ const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive, /* * Return true if the entry is a symbolic link. */ -bool mzIsZipEntrySymlink(const ZipEntry* pEntry) +static bool mzIsZipEntrySymlink(const ZipEntry* pEntry) { if ((pEntry->versionMadeBy & 0xff00) == CENVEM_UNIX) { return S_ISLNK(pEntry->externalFileAttributes >> 16); @@ -530,29 +498,7 @@ static bool processStoredEntry(const ZipArchive *pArchive, const ZipEntry *pEntry, ProcessZipEntryContentsFunction processFunction, void *cookie) { - size_t bytesLeft = pEntry->compLen; - while (bytesLeft > 0) { - unsigned char buf[32 * 1024]; - ssize_t n; - size_t count; - bool ret; - - count = bytesLeft; - if (count > sizeof(buf)) { - count = sizeof(buf); - } - n = read(pArchive->fd, buf, count); - if (n < 0 || (size_t)n != count) { - LOGE("Can't read %zu bytes from zip file: %ld\n", count, n); - return false; - } - ret = processFunction(buf, n, cookie); - if (!ret) { - return false; - } - bytesLeft -= count; - } - return true; + return processFunction(pArchive->addr + pEntry->offset, pEntry->uncompLen, cookie); } static bool processDeflatedEntry(const ZipArchive *pArchive, @@ -560,7 +506,6 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, void *cookie) { long result = -1; - unsigned char readBuf[32 * 1024]; unsigned char procBuf[32 * 1024]; z_stream zstream; int zerr; @@ -575,8 +520,8 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; + zstream.next_in = pArchive->addr + pEntry->offset; + zstream.avail_in = pEntry->compLen; zstream.next_out = (Bytef*) procBuf; zstream.avail_out = sizeof(procBuf); zstream.data_type = Z_UNKNOWN; @@ -600,29 +545,10 @@ static bool processDeflatedEntry(const ZipArchive *pArchive, * Loop while we have data. */ do { - /* read as much as we can */ - if (zstream.avail_in == 0) { - long getSize = (compRemaining > (long)sizeof(readBuf)) ? - (long)sizeof(readBuf) : compRemaining; - LOGVV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - int cc = read(pArchive->fd, readBuf, getSize); - if (cc != (int) getSize) { - LOGW("inflate read failed (%d vs %ld)\n", cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; - } - /* uncompress the data */ zerr = inflate(&zstream, Z_NO_FLUSH); if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOGD("zlib inflate call failed (zerr=%d)\n", zerr); + LOGW("zlib inflate call failed (zerr=%d)\n", zerr); goto z_bail; } @@ -676,13 +602,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive, void *cookie) { bool ret = false; - off_t oldOff; - - /* save current offset */ - oldOff = lseek(pArchive->fd, 0, SEEK_CUR); - - /* Seek to the beginning of the entry's compressed data. */ - lseek(pArchive->fd, pEntry->offset, SEEK_SET); switch (pEntry->compression) { case STORED: @@ -697,42 +616,9 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive, break; } - /* restore file offset */ - lseek(pArchive->fd, oldOff, SEEK_SET); return ret; } -static bool crcProcessFunction(const unsigned char *data, int dataLen, - void *crc) -{ - *(unsigned long *)crc = crc32(*(unsigned long *)crc, data, dataLen); - return true; -} - -/* - * 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) -{ - unsigned long crc; - bool ret; - - crc = crc32(0L, Z_NULL, 0); - ret = mzProcessZipEntryContents(pArchive, pEntry, crcProcessFunction, - (void *)&crc); - if (!ret) { - LOGE("Can't calculate CRC for entry\n"); - return false; - } - if (crc != (unsigned long)pEntry->crc32) { - LOGW("CRC for entry %.*s (0x%08lx) != expected (0x%08lx)\n", - pEntry->fileNameLen, pEntry->fileName, crc, pEntry->crc32); - return false; - } - return true; -} - typedef struct { char *buf; int bufLen; @@ -759,7 +645,7 @@ bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry, { CopyProcessArgs args; bool ret; - + args.buf = buf; args.bufLen = bufLen; ret = mzProcessZipEntryContents(pArchive, pEntry, copyProcessFunction, @@ -772,15 +658,29 @@ bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry, } static bool writeProcessFunction(const unsigned char *data, int dataLen, - void *fd) + void *cookie) { - ssize_t n = write((int)fd, data, dataLen); - if (n != dataLen) { - LOGE("Can't write %d bytes (only %ld) from zip file: %s\n", - dataLen, n, strerror(errno)); - return false; + int fd = (int)(intptr_t)cookie; + if (dataLen == 0) { + return true; + } + ssize_t soFar = 0; + while (true) { + ssize_t n = TEMP_FAILURE_RETRY(write(fd, data+soFar, dataLen-soFar)); + if (n <= 0) { + LOGE("Error writing %zd bytes from zip file from %p: %s\n", + dataLen-soFar, data+soFar, strerror(errno)); + return false; + } else if (n > 0) { + soFar += n; + if (soFar == dataLen) return true; + if (soFar > dataLen) { + LOGE("write overrun? (%zd bytes instead of %d)\n", + soFar, dataLen); + return false; + } + } } - return true; } /* @@ -790,7 +690,7 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive, const ZipEntry *pEntry, int fd) { bool ret = mzProcessZipEntryContents(pArchive, pEntry, writeProcessFunction, - (void *)fd); + (void*)(intptr_t)fd); if (!ret) { LOGE("Can't extract entry to file.\n"); return false; @@ -798,6 +698,43 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive, return true; } +typedef struct { + unsigned char* buffer; + long len; +} BufferExtractCookie; + +static bool bufferProcessFunction(const unsigned char *data, int dataLen, + void *cookie) { + BufferExtractCookie *bec = (BufferExtractCookie*)cookie; + + memmove(bec->buffer, data, dataLen); + bec->buffer += dataLen; + bec->len -= dataLen; + + return true; +} + +/* + * Uncompress "pEntry" in "pArchive" to buffer, which must be large + * enough to hold mzGetZipEntryUncomplen(pEntry) bytes. + */ +bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive, + const ZipEntry *pEntry, unsigned char *buffer) +{ + BufferExtractCookie bec; + bec.buffer = buffer; + bec.len = mzGetZipEntryUncompLen(pEntry); + + bool ret = mzProcessZipEntryContents(pArchive, pEntry, + bufferProcessFunction, (void*)&bec); + if (!ret || bec.len != 0) { + LOGE("Can't extract entry to memory buffer.\n"); + return false; + } + return true; +} + + /* Helper state to make path translation easier and less malloc-happy. */ typedef struct { @@ -880,8 +817,9 @@ static const char *targetEntryPath(MzPathHelper *helper, ZipEntry *pEntry) */ 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) + const struct utimbuf *timestamp, + void (*callback)(const char *fn, void *), void *cookie, + struct selabel_handle *sehnd) { if (zipDir[0] == '/') { LOGE("mzExtractRecursive(): zipDir must be a relative path.\n"); @@ -929,19 +867,20 @@ bool mzExtractRecursive(const ZipArchive *pArchive, /* Walk through the entries and extract anything whose path begins * with zpath. -//TODO: since the entries are sorted, binary search for the first match -// and stop after the first non-match. + //TODO: since the entries are sorted, binary search for the first match + // and stop after the first non-match. */ unsigned int i; bool seenMatch = false; int ok = true; + int extractCount = 0; for (i = 0; i < pArchive->numEntries; i++) { ZipEntry *pEntry = pArchive->pEntries + i; if (pEntry->fileNameLen < zipDirLen) { -//TODO: look out for a single empty directory entry that matches zpath, but -// missing the trailing slash. Most zip files seem to include -// the trailing slash, but I think it's legal to leave it off. -// e.g., zpath "a/b/", entry "a/b", with no children of the entry. + //TODO: look out for a single empty directory entry that matches zpath, but + // missing the trailing slash. Most zip files seem to include + // the trailing slash, but I think it's legal to leave it off. + // e.g., zpath "a/b/", entry "a/b", with no children of the entry. /* No chance of matching. */ #if SORT_ENTRIES @@ -982,35 +921,24 @@ bool mzExtractRecursive(const ZipArchive *pArchive, break; } - /* With DRY_RUN set, invoke the callback but don't do anything else. - */ - if (flags & MZ_EXTRACT_DRY_RUN) { - if (callback != NULL) callback(targetFile, cookie); - continue; - } - - /* Create the file or directory. - */ #define UNZIP_DIRMODE 0755 #define UNZIP_FILEMODE 0644 - if (pEntry->fileName[pEntry->fileNameLen-1] == '/') { - if (!(flags & MZ_EXTRACT_FILES_ONLY)) { - int ret = dirCreateHierarchy( - targetFile, UNZIP_DIRMODE, timestamp, false); - if (ret != 0) { - LOGE("Can't create containing directory for \"%s\": %s\n", - targetFile, strerror(errno)); - ok = false; - break; - } - LOGD("Extracted dir \"%s\"\n", targetFile); - } - } else { + /* + * Create the file or directory. We ignore directory entries + * because we recursively create paths to each file entry we encounter + * in the zip archive anyway. + * + * NOTE: A "directory entry" in a zip archive is just a zero length + * entry that ends in a "/". They're not mandatory and many tools get + * rid of them. We need to process them only if we want to preserve + * empty directories from the archive. + */ + if (pEntry->fileName[pEntry->fileNameLen-1] != '/') { /* This is not a directory. First, make sure that * the containing directory exists. */ int ret = dirCreateHierarchy( - targetFile, UNZIP_DIRMODE, timestamp, true); + targetFile, UNZIP_DIRMODE, timestamp, true, sehnd); if (ret != 0) { LOGE("Can't create containing directory for \"%s\": %s\n", targetFile, strerror(errno)); @@ -1018,81 +946,69 @@ bool mzExtractRecursive(const ZipArchive *pArchive, break; } - /* With FILES_ONLY set, we need to ignore metadata entirely, - * so treat symlinks as regular files. + /* + * The entry is a regular file or a symlink. Open the target for writing. + * + * TODO: This behavior for symlinks seems rather bizarre. For a + * symlink foo/bar/baz -> foo/tar/taz, we will create a file called + * "foo/bar/baz" whose contents are the literal "foo/tar/taz". We + * warn about this for now and preserve older behavior. */ - if (!(flags & MZ_EXTRACT_FILES_ONLY) && mzIsZipEntrySymlink(pEntry)) { - /* The entry is a symbolic link. - * The relative target of the symlink is in the - * data section of this entry. - */ - if (pEntry->uncompLen == 0) { - LOGE("Symlink entry \"%s\" has no target\n", - targetFile); - ok = false; - break; - } - char *linkTarget = malloc(pEntry->uncompLen + 1); - if (linkTarget == NULL) { - ok = false; - break; - } - ok = mzReadZipEntry(pArchive, pEntry, linkTarget, - pEntry->uncompLen); - if (!ok) { - LOGE("Can't read symlink target for \"%s\"\n", - targetFile); - free(linkTarget); - break; - } - linkTarget[pEntry->uncompLen] = '\0'; + if (mzIsZipEntrySymlink(pEntry)) { + LOGE("Symlink entry \"%.*s\" will be output as a regular file.", + pEntry->fileNameLen, pEntry->fileName); + } - /* Make the link. - */ - ret = symlink(linkTarget, targetFile); - if (ret != 0) { - LOGE("Can't symlink \"%s\" to \"%s\": %s\n", - targetFile, linkTarget, strerror(errno)); - free(linkTarget); - ok = false; - break; - } - LOGD("Extracted symlink \"%s\" -> \"%s\"\n", - targetFile, linkTarget); - free(linkTarget); - } else { - /* The entry is a regular file. - * Open the target for writing. - */ - int fd = creat(targetFile, UNZIP_FILEMODE); - if (fd < 0) { - LOGE("Can't create target file \"%s\": %s\n", - targetFile, strerror(errno)); - ok = false; - break; - } + char *secontext = NULL; - bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd); - close(fd); - if (!ok) { - LOGE("Error extracting \"%s\"\n", targetFile); - ok = false; - break; - } + if (sehnd) { + selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE); + setfscreatecon(secontext); + } - if (timestamp != NULL && utime(targetFile, timestamp)) { - LOGE("Error touching \"%s\"\n", targetFile); - ok = false; - break; - } + int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC, + UNZIP_FILEMODE); + + if (secontext) { + freecon(secontext); + setfscreatecon(NULL); + } + + if (fd < 0) { + LOGE("Can't create target file \"%s\": %s\n", + targetFile, strerror(errno)); + ok = false; + break; + } + + bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd); + if (ok) { + ok = (fsync(fd) == 0); + } + if (close(fd) != 0) { + ok = false; + } + if (!ok) { + LOGE("Error extracting \"%s\"\n", targetFile); + ok = false; + break; + } - LOGD("Extracted file \"%s\"\n", targetFile); + if (timestamp != NULL && utime(targetFile, timestamp)) { + LOGE("Error touching \"%s\"\n", targetFile); + ok = false; + break; } + + LOGV("Extracted file \"%s\"\n", targetFile); + ++extractCount; } if (callback != NULL) callback(targetFile, cookie); } + LOGV("Extracted %d file(s)\n", extractCount); + free(helper.buf); free(zpath); diff --git a/libs/minzip/Zip.h b/libs/minzip/Zip.h old mode 100644 new mode 100755 index 1c1df2f..86d8db5 --- a/libs/minzip/Zip.h +++ b/libs/minzip/Zip.h @@ -14,6 +14,13 @@ #include "Hash.h" #include "SysUtil.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + /* * One entry in the Zip archive. Treat this as opaque -- use accessors below. * @@ -39,11 +46,11 @@ typedef struct 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; + unsigned int numEntries; + ZipEntry* pEntries; + HashTable* pHash; // maps file name to ZipEntry + unsigned char* addr; + size_t length; } ZipArchive; /* @@ -61,7 +68,7 @@ typedef struct { * On success, returns 0 and populates "pArchive". Returns nonzero errno * value on failure. */ -int mzOpenZipArchive(const char* fileName, ZipArchive* pArchive); +int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive); /* * Close archive, releasing resources associated with it. @@ -78,56 +85,12 @@ void mzCloseZipArchive(ZipArchive* pArchive); 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 @@ -156,12 +119,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive, 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. */ @@ -169,9 +126,19 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive, const ZipEntry *pEntry, int fd); /* - * Inflate all entries under zipDir to the directory specified by + * 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 * @@ -186,21 +153,20 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive, * /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); + const struct utimbuf *timestamp, + void (*callback)(const char *fn, void*), void *cookie, + struct selabel_handle *sehnd); + +#ifdef __cplusplus +} +#endif #endif /*_MINZIP_ZIP*/ diff --git a/libs/minzip/inline_magic.h b/libs/minzip/inline_magic.h old mode 100644 new mode 100755 index 8c185e1..59c659f --- a/libs/minzip/inline_magic.h +++ b/libs/minzip/inline_magic.h @@ -18,7 +18,7 @@ #define MINZIP_INLINE_MAGIC_H_ #ifndef MINZIP_GENERATE_INLINES -#define INLINE extern __inline__ +#define INLINE extern inline __attribute((__gnu_inline__)) #else #define INLINE #endif