summaryrefslogtreecommitdiffstats
path: root/minzip/Zip.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--minzip/Zip.c223
1 files changed, 68 insertions, 155 deletions
diff --git a/minzip/Zip.c b/minzip/Zip.c
index 5070104d3..40712e03a 100644
--- a/minzip/Zip.c
+++ b/minzip/Zip.c
@@ -327,10 +327,6 @@ static bool parseZipArchive(ZipArchive* pArchive)
#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;
@@ -488,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);
@@ -632,30 +628,6 @@ static bool crcProcessFunction(const unsigned char *data, int 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;
@@ -703,13 +675,11 @@ static bool writeProcessFunction(const unsigned char *data, int dataLen,
}
ssize_t soFar = 0;
while (true) {
- ssize_t n = write(fd, data+soFar, dataLen-soFar);
+ 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));
- if (errno != EINTR) {
- return false;
- }
+ return false;
} else if (n > 0) {
soFar += n;
if (soFar == dataLen) return true;
@@ -737,23 +707,6 @@ 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;
@@ -873,7 +826,7 @@ 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,
+ const struct utimbuf *timestamp,
void (*callback)(const char *fn, void *), void *cookie,
struct selabel_handle *sehnd)
{
@@ -923,8 +876,8 @@ 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;
@@ -933,10 +886,10 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
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
@@ -977,30 +930,19 @@ 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, sehnd);
- 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.
*/
@@ -1013,91 +955,62 @@ 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';
-
- /* 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.
- */
-
- char *secontext = NULL;
+ if (mzIsZipEntrySymlink(pEntry)) {
+ LOGE("Symlink entry \"%.*s\" will be output as a regular file.",
+ pEntry->fileNameLen, pEntry->fileName);
+ }
- if (sehnd) {
- selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
- setfscreatecon(secontext);
- }
+ char *secontext = NULL;
- int fd = creat(targetFile, UNZIP_FILEMODE);
+ if (sehnd) {
+ selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
+ setfscreatecon(secontext);
+ }
- if (secontext) {
- freecon(secontext);
- setfscreatecon(NULL);
- }
+ int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC,
+ UNZIP_FILEMODE);
- if (fd < 0) {
- LOGE("Can't create target file \"%s\": %s\n",
- targetFile, strerror(errno));
- ok = false;
- break;
- }
+ if (secontext) {
+ freecon(secontext);
+ setfscreatecon(NULL);
+ }
- bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
- close(fd);
- if (!ok) {
- LOGE("Error extracting \"%s\"\n", targetFile);
- ok = false;
- break;
- }
+ if (fd < 0) {
+ LOGE("Can't create target file \"%s\": %s\n",
+ targetFile, strerror(errno));
+ ok = false;
+ break;
+ }
- if (timestamp != NULL && utime(targetFile, timestamp)) {
- LOGE("Error touching \"%s\"\n", targetFile);
- 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;
+ }
- LOGV("Extracted file \"%s\"\n", targetFile);
- ++extractCount;
+ 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);