summaryrefslogtreecommitdiffstats
path: root/minzip
diff options
context:
space:
mode:
Diffstat (limited to 'minzip')
-rw-r--r--minzip/DirUtil.c58
-rw-r--r--minzip/DirUtil.h8
-rw-r--r--minzip/SysUtil.c239
-rw-r--r--minzip/SysUtil.h55
-rw-r--r--minzip/Zip.c160
-rw-r--r--minzip/Zip.h23
6 files changed, 215 insertions, 328 deletions
diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c
index 8dd5da1da..fe2c880ac 100644
--- a/minzip/DirUtil.c
+++ b/minzip/DirUtil.c
@@ -234,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/minzip/DirUtil.h b/minzip/DirUtil.h
index a5cfa761b..85a00128b 100644
--- a/minzip/DirUtil.h
+++ b/minzip/DirUtil.h
@@ -48,14 +48,6 @@ int dirCreateHierarchy(const char *path, int mode,
*/
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
diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c
index 31c76d6d4..ac6f5c33f 100644
--- a/minzip/SysUtil.c
+++ b/minzip/SysUtil.c
@@ -8,42 +8,17 @@
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
-#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
-
-
-/*
- * 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;
@@ -74,48 +49,13 @@ static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
}
/*
- * 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;
-
- pMap->baseAddr = pMap->addr = memPtr;
- pMap->baseLength = pMap->length = length;
-
- actual = TEMP_FAILURE_RETRY(read(fd, memPtr, length));
- if (actual != length) {
- LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
- sysReleaseShmem(pMap);
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Map a file (from fd's current offset) into a shared, read-only memory
+ * Map a file (from fd's current offset) into a private, 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)
+static int sysMapFD(int fd, MemMapping* pMap)
{
off_t start;
size_t length;
@@ -126,87 +66,148 @@ int sysMapFileInShmem(int fd, MemMapping* pMap)
if (getFileStartAndLength(fd, &start, &length) < 0)
return -1;
- memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
+ memPtr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, start);
if (memPtr == MAP_FAILED) {
- LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", (int) length,
+ LOGW("mmap(%d, R, PRIVATE, %d, %d) failed: %s\n", (int) length,
fd, (int) start, strerror(errno));
return -1;
}
- pMap->baseAddr = pMap->addr = memPtr;
- pMap->baseLength = pMap->length = length;
+ pMap->addr = memPtr;
+ pMap->length = length;
+ pMap->range_count = 1;
+ pMap->ranges = malloc(sizeof(MappedRange));
+ pMap->ranges[0].addr = memPtr;
+ pMap->ranges[0].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)
+static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
{
- off_t dummy;
- size_t fileLength, actualLength;
- off_t actualStart;
- int adjust;
- void* memPtr;
-
- assert(pMap != NULL);
+ 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) {
+ LOGW("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;
+ }
+ }
- if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
+ if (fscanf(mapf, "%zu %u\n%u\n", &size, &blksize, &range_count) != 3) {
+ LOGW("failed to parse block map header\n");
return -1;
+ }
- if (start + length > (long)fileLength) {
- LOGW("bad segment: st=%d len=%ld flen=%d\n",
- (int) start, length, (int) fileLength);
+ blocks = ((size-1) / blksize) + 1;
+
+ pMap->range_count = range_count;
+ pMap->ranges = malloc(range_count * sizeof(MappedRange));
+ memset(pMap->ranges, 0, range_count * sizeof(MappedRange));
+
+ // 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) {
+ LOGW("failed to reserve address space: %s\n", strerror(errno));
return -1;
}
- /* adjust to be page-aligned */
- adjust = start % DEFAULT_PAGE_SIZE;
- actualStart = start - adjust;
- actualLength = length + adjust;
+ pMap->ranges[range_count-1].addr = reserve;
+ pMap->ranges[range_count-1].length = blocks * blksize;
- 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));
+ int fd = open(block_dev, O_RDONLY);
+ if (fd < 0) {
+ LOGW("failed to open block device %s: %s\n", block_dev, strerror(errno));
return -1;
}
- pMap->baseAddr = memPtr;
- pMap->baseLength = actualLength;
- pMap->addr = (char*)memPtr + adjust;
- pMap->length = length;
+ unsigned char* next = reserve;
+ for (i = 0; i < range_count; ++i) {
+ int start, end;
+ if (fscanf(mapf, "%d %d\n", &start, &end) != 2) {
+ LOGW("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) {
+ LOGW("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->addr = reserve;
+ pMap->length = size;
- 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);
+ LOGI("mmapped %d ranges\n", range_count);
return 0;
}
+int sysMapFile(const char* fn, MemMapping* pMap)
+{
+ memset(pMap, 0, sizeof(*pMap));
+
+ if (fn && fn[0] == '@') {
+ // A map of blocks
+ FILE* mapf = fopen(fn+1, "r");
+ if (mapf == NULL) {
+ LOGV("Unable to open '%s': %s\n", fn+1, strerror(errno));
+ return -1;
+ }
+
+ if (sysMapBlockFile(mapf, pMap) != 0) {
+ LOGW("Map of '%s' failed\n", fn);
+ return -1;
+ }
+
+ fclose(mapf);
+ } else {
+ // This is a regular file.
+ int fd = open(fn, O_RDONLY, 0);
+ if (fd < 0) {
+ LOGE("Unable to open '%s': %s\n", fn, strerror(errno));
+ return -1;
+ }
+
+ if (sysMapFD(fd, pMap) != 0) {
+ LOGE("Map of '%s' failed\n", fn);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ }
+ 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) {
+ LOGW("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/minzip/SysUtil.h b/minzip/SysUtil.h
index ec3a4bcfb..7adff1e54 100644
--- a/minzip/SysUtil.h
+++ b/minzip/SysUtil.h
@@ -6,56 +6,47 @@
#ifndef _MINZIP_SYSUTIL
#define _MINZIP_SYSUTIL
-#include "inline_magic.h"
-
+#include <stdio.h>
#include <sys/types.h>
+#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/minzip/Zip.c b/minzip/Zip.c
index 439e5d9cd..70aff00cd 100644
--- a/minzip/Zip.c
+++ b/minzip/Zip.c
@@ -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,7 +196,7 @@ 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");
goto bail;
@@ -209,14 +209,14 @@ 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) {
+ if (ptr < (const unsigned char*) pArchive->addr) {
LOGI("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,7 +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;
}
@@ -352,15 +352,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;
}
@@ -374,7 +374,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;
}
@@ -427,50 +427,30 @@ bail:
*
* 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) {
- err = -1;
- LOGW("Map of '%s' failed\n", fileName);
- goto bail;
- }
-
- if (map.length < ENDHDR) {
+ if (length < ENDHDR) {
err = -1;
LOGV("File '%s' too small to be zip (%zd)\n", fileName, map.length);
goto bail;
}
- if (!parseZipArchive(pArchive, &map)) {
+ pArchive->addr = addr;
+ pArchive->length = length;
+
+ if (!parseZipArchive(pArchive)) {
err = -1;
LOGV("Parsing '%s' failed\n", fileName);
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;
}
@@ -483,16 +463,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;
}
@@ -528,29 +502,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,
@@ -573,8 +525,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;
@@ -598,25 +550,6 @@ 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) {
@@ -676,12 +609,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive,
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:
ret = processStoredEntry(pArchive, pEntry, processFunction, cookie);
@@ -695,8 +622,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive,
break;
}
- /* restore file offset */
- lseek(pArchive->fd, oldOff, SEEK_SET);
return ret;
}
@@ -772,13 +697,15 @@ bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
static bool writeProcessFunction(const unsigned char *data, int dataLen,
void *cookie)
{
- int fd = (int)cookie;
-
+ int fd = (int)(intptr_t)cookie;
+ if (dataLen == 0) {
+ return true;
+ }
ssize_t soFar = 0;
while (true) {
ssize_t n = write(fd, data+soFar, dataLen-soFar);
if (n <= 0) {
- LOGE("Error writing %ld bytes from zip file from %p: %s\n",
+ LOGE("Error writing %zd bytes from zip file from %p: %s\n",
dataLen-soFar, data+soFar, strerror(errno));
if (errno != EINTR) {
return false;
@@ -787,7 +714,7 @@ static bool writeProcessFunction(const unsigned char *data, int dataLen,
soFar += n;
if (soFar == dataLen) return true;
if (soFar > dataLen) {
- LOGE("write overrun? (%ld bytes instead of %d)\n",
+ LOGE("write overrun? (%zd bytes instead of %d)\n",
soFar, dataLen);
return false;
}
@@ -802,7 +729,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;
@@ -810,6 +737,23 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
return true;
}
+/*
+ * Obtain a pointer to the in-memory representation of a stored entry.
+ */
+bool mzGetStoredEntry(const ZipArchive *pArchive,
+ const ZipEntry *pEntry, unsigned char **addr, size_t *length)
+{
+ if (pEntry->compression != STORED) {
+ LOGE("Can't getStoredEntry for '%s'; not stored\n",
+ pEntry->fileName);
+ return false;
+ }
+
+ *addr = pArchive->addr + pEntry->offset;
+ *length = pEntry->uncompLen;
+ return true;
+}
+
typedef struct {
unsigned char* buffer;
long len;
@@ -1123,7 +1067,8 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
setfscreatecon(secontext);
}
- int fd = creat(targetFile, UNZIP_FILEMODE);
+ int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC
+ , UNZIP_FILEMODE);
if (secontext) {
freecon(secontext);
@@ -1138,7 +1083,12 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
}
bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
- close(fd);
+ if (ok) {
+ ok = (fsync(fd) == 0);
+ }
+ if (close(fd) != 0) {
+ ok = false;
+ }
if (!ok) {
LOGE("Error extracting \"%s\"\n", targetFile);
ok = false;
diff --git a/minzip/Zip.h b/minzip/Zip.h
index c94282827..2054b38a4 100644
--- a/minzip/Zip.h
+++ b/minzip/Zip.h
@@ -46,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;
/*
@@ -68,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.
@@ -183,6 +183,17 @@ bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
const ZipEntry *pEntry, unsigned char* buffer);
/*
+ * Return a pointer and length for a given entry. The returned region
+ * should be valid until pArchive is closed, and should be treated as
+ * read-only.
+ *
+ * Only makes sense for entries which are stored (ie, not compressed).
+ * No guarantees are made regarding alignment of the returned pointer.
+ */
+bool mzGetStoredEntry(const ZipArchive *pArchive,
+ const ZipEntry* pEntry, unsigned char **addr, size_t *length);
+
+/*
* Inflate all entries under zipDir to the directory specified by
* targetDir, which must exist and be a writable directory.
*