aboutsummaryrefslogtreecommitdiffstats
path: root/minzip
diff options
context:
space:
mode:
Diffstat (limited to 'minzip')
-rw-r--r--minzip/SysUtil.c152
-rw-r--r--minzip/SysUtil.h38
-rw-r--r--minzip/Zip.c121
-rw-r--r--minzip/Zip.h12
4 files changed, 186 insertions, 137 deletions
diff --git a/minzip/SysUtil.c b/minzip/SysUtil.c
index e6f6506..2cfa39a 100644
--- a/minzip/SysUtil.c
+++ b/minzip/SysUtil.c
@@ -8,11 +8,14 @@
#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"
@@ -46,13 +49,13 @@ static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
}
/*
- * 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;
@@ -63,33 +66,146 @@ 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;
}
+static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
+{
+ 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 (fscanf(mapf, "%d %d\n%d\n", &size, &blksize, &range_count) != 3) {
+ LOGW("failed to parse block map header\n");
+ return -1;
+ }
+
+ 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;
+ }
+
+ pMap->ranges[range_count-1].addr = reserve;
+ pMap->ranges[range_count-1].length = blocks * blksize;
+
+ 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;
+ }
+
+ 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;
+
+ 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 55cd0e7..7adff1e 100644
--- a/minzip/SysUtil.h
+++ b/minzip/SysUtil.h
@@ -6,39 +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;
-}
-
/*
- * 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);
+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 439e5d9..6752bce 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;
}
diff --git a/minzip/Zip.h b/minzip/Zip.h
index c942828..05a2e60 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.