summaryrefslogtreecommitdiffstats
path: root/minzip/Zip.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--minzip/Zip.c164
1 files changed, 59 insertions, 105 deletions
diff --git a/minzip/Zip.c b/minzip/Zip.c
index 12e06f6d8..d3ff79be6 100644
--- a/minzip/Zip.c
+++ b/minzip/Zip.c
@@ -828,7 +828,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)
{
@@ -932,30 +932,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.
*/
@@ -968,97 +957,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 = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC
- , 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);
- if (ok) {
- ok = (fsync(fd) == 0);
- }
- if (close(fd) != 0) {
- ok = false;
- }
- 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);