summaryrefslogtreecommitdiffstats
path: root/lib/libarchive
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2005-01-25 06:07:28 +0000
committerkientzle <kientzle@FreeBSD.org>2005-01-25 06:07:28 +0000
commit973eae31d40e350837650e2c6e3eb0a128bc17bb (patch)
treeb51c36aedc9be9adee4b56bd2a57cbb8ef65ffc0 /lib/libarchive
parenta8e3a91bb37be12a91189861b526f6a5dfb53762 (diff)
downloadFreeBSD-src-973eae31d40e350837650e2c6e3eb0a128bc17bb.zip
FreeBSD-src-973eae31d40e350837650e2c6e3eb0a128bc17bb.tar.gz
Basic support for ZIP archives.
Only supports "deflate" and "none" compression for now. Also, add a few clarifications to the archive_read.3 manpage as requested by William Dean DeVries.
Diffstat (limited to 'lib/libarchive')
-rw-r--r--lib/libarchive/Makefile4
-rw-r--r--lib/libarchive/Makefile.am2
-rw-r--r--lib/libarchive/archive.h.in6
-rw-r--r--lib/libarchive/archive_read.336
-rw-r--r--lib/libarchive/archive_read_support_format_all.c1
-rw-r--r--lib/libarchive/archive_read_support_format_zip.c525
6 files changed, 566 insertions, 8 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index bdd4a98..ba68f5d 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -7,7 +7,7 @@
LIB= archive
-VERSION= 1.01.022
+VERSION= 1.02.002
ARCHIVE_API_FEATURE= 2
ARCHIVE_API_VERSION= 1
SHLIB_MAJOR= ${ARCHIVE_API_VERSION}
@@ -42,6 +42,7 @@ SRCS= archive.h \
archive_read_support_format_cpio.c \
archive_read_support_format_iso9660.c \
archive_read_support_format_tar.c \
+ archive_read_support_format_zip.c \
archive_string.c \
archive_string_sprintf.c \
archive_util.c \
@@ -142,6 +143,7 @@ MLINKS+= archive_read.3 archive_read_support_format_all.3
MLINKS+= archive_read.3 archive_read_support_format_cpio.3
MLINKS+= archive_read.3 archive_read_support_format_iso9660.3
MLINKS+= archive_read.3 archive_read_support_format_tar.3
+MLINKS+= archive_read.3 archive_read_support_format_zip.3
MLINKS+= archive_util.3 archive_compression.3
MLINKS+= archive_util.3 archive_compression_name.3
MLINKS+= archive_util.3 archive_errno.3
diff --git a/lib/libarchive/Makefile.am b/lib/libarchive/Makefile.am
index b7d5dd5..5ad7361 100644
--- a/lib/libarchive/Makefile.am
+++ b/lib/libarchive/Makefile.am
@@ -26,7 +26,9 @@ libarchive_a_SOURCES= \
archive_read_support_compression_none.c \
archive_read_support_format_all.c \
archive_read_support_format_cpio.c \
+ archive_read_support_format_iso9660.c \
archive_read_support_format_tar.c \
+ archive_read_support_format_zip.c \
archive_string.c \
archive_string.h \
archive_string_sprintf.c \
diff --git a/lib/libarchive/archive.h.in b/lib/libarchive/archive.h.in
index 3787dfb..1754cca 100644
--- a/lib/libarchive/archive.h.in
+++ b/lib/libarchive/archive.h.in
@@ -128,8 +128,9 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2)
#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3)
#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4)
-#define ARCHIVE_FORMAT_ISO9660 0x40000
-#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1)
+#define ARCHIVE_FORMAT_ISO9660 0x40000
+#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1)
+#define ARCHIVE_FORMAT_ZIP 0x50000
/*-
* Basic outline for reading an archive:
@@ -163,6 +164,7 @@ int archive_read_support_format_cpio(struct archive *);
int archive_read_support_format_gnutar(struct archive *);
int archive_read_support_format_iso9660(struct archive *);
int archive_read_support_format_tar(struct archive *);
+int archive_read_support_format_zip(struct archive *);
/* Open the archive using callbacks for archive I/O. */
diff --git a/lib/libarchive/archive_read.3 b/lib/libarchive/archive_read.3
index bed9c54..5d5948e3 100644
--- a/lib/libarchive/archive_read.3
+++ b/lib/libarchive/archive_read.3
@@ -39,6 +39,7 @@
.Nm archive_read_support_format_cpio ,
.Nm archive_read_support_format_iso9660 ,
.Nm archive_read_support_format_tar ,
+.Nm archive_read_support_format_zip ,
.Nm archive_read_open ,
.Nm archive_read_open_fd ,
.Nm archive_read_open_file ,
@@ -78,6 +79,8 @@
.Ft int
.Fn archive_read_support_format_tar "struct archive *"
.Ft int
+.Fn archive_read_support_format_zip "struct archive *"
+.Ft int
.Fn archive_read_open "struct archive *" "void *client_data" "archive_open_archive_callback *" "archive_read_archive_callback *" "archive_close_archive_callback *"
.Ft int
.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
@@ -122,7 +125,7 @@ Sets the block size used for reading the archive data.
This controls the size that will be used when invoking the read
callback function.
The default is 20 records or 10240 bytes for tar formats.
-.It Fn archive_read_support_comression_all , Fn archive_read_support_compression_bzip2 , Fn archive_read_support_compression_compress , Fn archive_read_support_compression_gzip , Fn archive_read_support_compression_none
+.It Fn archive_read_support_compression_all , Fn archive_read_support_compression_bzip2 , Fn archive_read_support_compression_compress , Fn archive_read_support_compression_gzip , Fn archive_read_support_compression_none
Enables auto-detection code and decompression support for the
specified compression.
Note that
@@ -131,7 +134,7 @@ is always enabled by default.
For convenience,
.Fn archive_read_support_compression_all
enables all available decompression code.
-.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar
+.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar, Fn archive_read_support_format_zip
Enables support---including auto-detection code---for the
specified archive format.
For example,
@@ -233,7 +236,9 @@ By default, they are ignored.
Note that restoring of atime is not currently supported.
.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
Existing files on disk will not be overwritten.
-By default, existing files are unlinked before the new entry is written.
+By default, existing regular files are truncated and overwritten;
+existing directories will have their permissions updated;
+other pre-existing objects are unlinked and recreated from scratch.
.It Cm ARCHIVE_EXTRACT_UNLINK
Existing files on disk will be unlinked and recreated from scratch.
By default, existing files are truncated and rewritten, but
@@ -401,9 +406,9 @@ myclose(struct archive *a, void *client_data)
Most functions return zero on success, non-zero on error.
The possible return codes include:
.Cm ARCHIVE_OK
-(the operation succeeded)
+(the operation succeeded),
.Cm ARCHIVE_WARN
-(the operation succeeded but a non-critical error was encountered)
+(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
@@ -467,3 +472,24 @@ The
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.Sh BUGS
+Directories are actually extracted in two distinct phases.
+Directories are created during
+.Fn archive_read_extract ,
+but final permissions are not set until
+.Fn archive_read_close .
+This separation is necessary to correctly handle borderline
+cases such as a non-writable directory containing
+files, but can cause unexpected results.
+In particular, directory permissions are not fully
+restored until the archive is closed.
+If you use
+.Xr chdir 2
+to change the current directory between calls to
+.Fn archive_read_extract
+or before calling
+.Fn archive_read_close ,
+you may confuse the permission-setting logic with
+the result that directory permissions are restored
+incorrectly.
+
+
diff --git a/lib/libarchive/archive_read_support_format_all.c b/lib/libarchive/archive_read_support_format_all.c
index 6c99439..3b7eaaf 100644
--- a/lib/libarchive/archive_read_support_format_all.c
+++ b/lib/libarchive/archive_read_support_format_all.c
@@ -35,5 +35,6 @@ archive_read_support_format_all(struct archive *a)
archive_read_support_format_cpio(a);
archive_read_support_format_iso9660(a);
archive_read_support_format_tar(a);
+ archive_read_support_format_zip(a);
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
new file mode 100644
index 0000000..8c2cdc7
--- /dev/null
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -0,0 +1,525 @@
+/*-
+ * Copyright (c) 2004 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct zip {
+ off_t entry_bytes_remaining;
+ off_t entry_offset;
+
+ unsigned version;
+ unsigned system;
+ unsigned flags;
+ unsigned compression;
+ const char * compression_name;
+ time_t mtime;
+ char end_of_entry;
+
+ long crc32;
+ ssize_t filename_length;
+ ssize_t extra_length;
+ off_t uncompressed_size;
+ off_t compressed_size;
+
+ unsigned char *uncompressed_buffer;
+ size_t uncompressed_buffer_size;
+#ifdef HAVE_ZLIB_H
+ z_stream stream;
+#endif
+
+ struct archive_string pathname;
+ struct archive_string extra;
+ char format_name[64];
+};
+
+#define ZIP_LENGTH_AT_END 8
+
+struct zip_file_header {
+ char signature[4];
+ char version[1];
+ char reserved[1];
+ char flags[2];
+ char compression[2];
+ char timedate[4];
+ char crc32[4];
+ char compressed_size[4];
+ char uncompressed_size[4];
+ char filename_length[2];
+ char extra_length[2];
+};
+
+const char *compression_names[] = {
+ "uncompressed",
+ "shrinking",
+ "reduced-1",
+ "reduced-2",
+ "reduced-3",
+ "reduced-4",
+ "imploded",
+ "reserved",
+ "deflation"
+};
+
+static int archive_read_format_zip_bid(struct archive *);
+static int archive_read_format_zip_cleanup(struct archive *);
+static int archive_read_format_zip_read_data(struct archive *,
+ const void **, size_t *, off_t *);
+static int archive_read_format_zip_read_header(struct archive *,
+ struct archive_entry *);
+static int i2(const char *);
+static int i4(const char *);
+static int zip_read_data_deflate(struct archive *a, const void **buff,
+ size_t *size, off_t *offset);
+static int zip_read_data_none(struct archive *a, const void **buff,
+ size_t *size, off_t *offset);
+static int zip_read_data_skip(struct archive *a, const void **buff,
+ size_t *size, off_t *offset);
+static time_t zip_time(const char *);
+
+int
+archive_read_support_format_zip(struct archive *a)
+{
+ struct zip *zip;
+ int r;
+
+ zip = malloc(sizeof(*zip));
+ memset(zip, 0, sizeof(*zip));
+
+ r = __archive_read_register_format(a,
+ zip,
+ archive_read_format_zip_bid,
+ archive_read_format_zip_read_header,
+ archive_read_format_zip_read_data,
+ archive_read_format_zip_cleanup);
+
+ if (r != ARCHIVE_OK)
+ free(zip);
+ return (ARCHIVE_OK);
+}
+
+
+static int
+archive_read_format_zip_bid(struct archive *a)
+{
+ int bytes_read;
+ int bid = 0;
+ const void *h;
+ const char *p;
+
+ if (a->archive_format == ARCHIVE_FORMAT_ZIP)
+ bid += 1;
+
+ bytes_read = (a->compression_read_ahead)(a, &h, 4);
+ if (bytes_read < 4)
+ return (-1);
+ p = h;
+
+ if (p[0] == 'P' && p[1] == 'K') {
+ bid += 16;
+ if (p[2] == '\001' && p[3] == '\002')
+ bid += 16;
+ else if (p[2] == '\003' && p[3] == '\004')
+ bid += 16;
+ else if (p[2] == '\005' && p[3] == '\006')
+ bid += 16;
+ else if (p[2] == '\007' && p[3] == '\010')
+ bid += 16;
+ }
+ return (bid);
+}
+
+static int
+archive_read_format_zip_read_header(struct archive *a,
+ struct archive_entry *entry)
+{
+ int bytes_read;
+ const void *h;
+ const struct zip_file_header *p;
+ struct zip *zip;
+
+ a->archive_format = ARCHIVE_FORMAT_ZIP;
+ if (a->archive_format_name == NULL)
+ a->archive_format_name = "ZIP";
+
+ zip = *(a->pformat_data);
+ zip->end_of_entry = 0;
+ bytes_read =
+ (a->compression_read_ahead)(a, &h, sizeof(struct zip_file_header));
+ if (bytes_read < 4)
+ return (ARCHIVE_FATAL);
+
+ p = h;
+ if (p->signature[0] != 'P' || p->signature[1] != 'K') {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad ZIP file");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (p->signature[2] == '\001' && p->signature[3] == '\002') {
+ /* Beginning of central directory. */
+ return (ARCHIVE_EOF);
+ } else if (p->signature[2] == '\003' && p->signature[3] == '\004') {
+ /* Regular file entry; fall through. */
+ } else if (p->signature[2] == '\005' && p->signature[3] == '\006') {
+ /* End-of-archive record. */
+ return (ARCHIVE_EOF);
+ } else if (p->signature[2] == '\007' && p->signature[3] == '\010') {
+ /* ??? Need to research this. ??? */
+ } else {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Damaged ZIP file or unsupported format variant (%d,%d)", p->signature[2], p->signature[3]);
+ return (ARCHIVE_FATAL);
+ }
+
+ if (bytes_read < (int)sizeof(struct zip_file_header)) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_FATAL);
+ }
+
+ zip->version = p->version[0];
+ zip->system = p->version[1];
+ zip->flags = i2(p->flags);
+ zip->compression = i2(p->compression);
+ if (zip->compression <
+ sizeof(compression_names)/sizeof(compression_names[0]))
+ zip->compression_name = compression_names[zip->compression];
+ else
+ zip->compression_name = "??";
+ zip->mtime = zip_time(p->timedate);
+ zip->crc32 = i4(p->crc32);
+ zip->filename_length = i2(p->filename_length);
+ zip->extra_length = i2(p->extra_length);
+ zip->uncompressed_size = i4(p->uncompressed_size);
+ zip->compressed_size = i4(p->compressed_size);
+
+ (a->compression_read_consume)(a, sizeof(struct zip_file_header));
+
+
+ /* Read the filename. */
+ bytes_read = (a->compression_read_ahead)(a, &h, zip->filename_length);
+ if (bytes_read < zip->filename_length) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_FATAL);
+ }
+ archive_string_ensure(&zip->pathname, zip->filename_length);
+ archive_strncpy(&zip->pathname, h, zip->filename_length);
+ (a->compression_read_consume)(a, zip->filename_length);
+ archive_entry_set_pathname(entry, zip->pathname.s);
+
+ /* Read the extra data. */
+ bytes_read = (a->compression_read_ahead)(a, &h, zip->extra_length);
+ if (bytes_read < zip->extra_length) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_FATAL);
+ }
+ /* TODO: Store the extra data somewhere? */
+ (a->compression_read_consume)(a, zip->extra_length);
+
+ /* Populate some additional entry fields: */
+ archive_entry_set_mtime(entry, zip->mtime, 0);
+ if (zip->pathname.s[archive_strlen(&zip->pathname) - 1] == '/')
+ archive_entry_set_mode(entry, S_IFDIR | 0777);
+ else
+ archive_entry_set_mode(entry, S_IFREG | 0777);
+ archive_entry_set_size(entry, zip->uncompressed_size);
+ zip->entry_bytes_remaining = zip->compressed_size;
+ zip->entry_offset = 0;
+
+ /* Set up a more descriptive format name. */
+ sprintf(zip->format_name, "ZIP %d.%d (%s)",
+ zip->version / 10, zip->version % 10,
+ zip->compression_name);
+ a->archive_format_name = zip->format_name;
+
+ return (ARCHIVE_OK);
+}
+
+/* Convert an MSDOS-style date/time into Unix-style time. */
+static time_t
+zip_time(const char *p)
+{
+ int msTime, msDate;
+ struct tm ts;
+
+ msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
+ msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
+
+ memset(&ts, 0, sizeof(ts));
+ ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
+ ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
+ ts.tm_mday = msDate & 0x1f; /* Day of month. */
+ ts.tm_hour = (msTime >> 11) & 0x1f;
+ ts.tm_min = (msTime >> 5) & 0x3f;
+ ts.tm_sec = (msTime << 1) & 0x3e;
+ ts.tm_isdst = -1;
+ return mktime(&ts);
+}
+
+static int
+archive_read_format_zip_read_data(struct archive *a,
+ const void **buff, size_t *size, off_t *offset)
+{
+ int r;
+ struct zip *zip;
+
+ zip = *(a->pformat_data);
+
+ if (!zip->end_of_entry) {
+ switch(zip->compression) {
+ case 0: /* No compression. */
+ r = zip_read_data_none(a, buff, size, offset);
+ break;
+ case 8: /* Deflate compression. */
+ r = zip_read_data_deflate(a, buff, size, offset);
+ break;
+ default: /* Unsupported compression. */
+ r = zip_read_data_skip(a, buff, size, offset);
+ /* Return a warning. */
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported ZIP compression method (%s)",
+ zip->compression_name);
+ r = ARCHIVE_WARN;
+ break;
+ }
+ } else {
+ r = ARCHIVE_EOF;
+ if (zip->flags & ZIP_LENGTH_AT_END) {
+ /* TODO: Read the "PK\007\008" trailer that follows. */
+ }
+ }
+ if (r == ARCHIVE_EOF)
+ zip->end_of_entry = 1;
+ return (r);
+}
+
+static int
+zip_read_data_none(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ struct zip *zip;
+
+ zip = *(a->pformat_data);
+
+ if (zip->entry_bytes_remaining == 0) {
+ *buff = NULL;
+ *size = 0;
+ *offset = zip->entry_offset;
+ return (ARCHIVE_EOF);
+ }
+
+ *size = (a->compression_read_ahead)(a, buff,
+ zip->entry_bytes_remaining);
+ if (*size <= 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+ }
+ if (*size > zip->entry_bytes_remaining)
+ *size = zip->entry_bytes_remaining;
+ (a->compression_read_consume)(a, *size);
+ *offset = zip->entry_offset;
+ zip->entry_offset += *size;
+ zip->entry_bytes_remaining -= *size;
+ return (ARCHIVE_OK);
+}
+
+#ifdef HAVE_ZLIB_H
+static int
+zip_read_data_deflate(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ struct zip *zip;
+ size_t bytes_read;
+ const void *compressed_buff;
+ int r;
+
+ zip = *(a->pformat_data);
+
+ /* If the buffer hasn't been allocated, allocate it now. */
+ if (zip->uncompressed_buffer == NULL) {
+ zip->uncompressed_buffer_size = 32 * 1024;
+ zip->uncompressed_buffer
+ = malloc(zip->uncompressed_buffer_size);
+ if (zip->uncompressed_buffer == NULL) {
+ archive_set_error(a, ENOMEM,
+ "No memory for ZIP decompression");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ /* If we haven't yet read any data, initialize the decompressor. */
+ if (zip->entry_bytes_remaining == zip->compressed_size) {
+ r = inflateInit2(&zip->stream,
+ -15 /* Don't check for zlib header */);
+ if (r != Z_OK) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Can't initialize ZIP decompression.");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ /* Read the next block of compressed data. */
+ bytes_read = (a->compression_read_ahead)(a, &compressed_buff,
+ zip->entry_bytes_remaining);
+ if (bytes_read <= 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file body");
+ return (ARCHIVE_FATAL);
+ }
+ if (bytes_read > zip->entry_bytes_remaining)
+ bytes_read = zip->entry_bytes_remaining;
+
+ /*
+ * A bug in zlib.h: stream.next_in should be marked 'const'
+ * but isn't (the library never alters data through the
+ * next_in pointer, only reads it). The result: this ugly
+ * cast to remove 'const'.
+ */
+ zip->stream.next_in = (void *)(uintptr_t)(const void *)compressed_buff;
+ zip->stream.avail_in = bytes_read;
+ zip->stream.total_in = 0;
+ zip->stream.next_out = zip->uncompressed_buffer;
+ zip->stream.avail_out = zip->uncompressed_buffer_size;
+ zip->stream.total_out = 0;
+
+ r = inflate(&zip->stream, 0);
+ switch (r) {
+ case Z_OK:
+ break;
+ case Z_STREAM_END:
+ zip->end_of_entry = 1;
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(a, ENOMEM,
+ "Out of memory for ZIP decompression");
+ return (ARCHIVE_FATAL);
+ default:
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "ZIP decompression failed (%d)", r);
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Consume as much as the compressor actually used. */
+ bytes_read = zip->stream.total_in;
+ (a->compression_read_consume)(a, bytes_read);
+ zip->entry_bytes_remaining -= bytes_read;
+
+
+ *offset = zip->entry_offset;
+ *size = zip->stream.total_out;
+ *buff = zip->uncompressed_buffer;
+ zip->entry_offset += *size;
+ return (ARCHIVE_OK);
+}
+#else
+static int
+zip_read_data_deflate(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ int r;
+
+ r = zip_read_data_skip(a, buff, size, offset);
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "libarchive compiled without deflate support (no libz)");
+ return (ARCHIVE_WARN);
+}
+#endif
+
+static int
+zip_read_data_skip(struct archive *a, const void **buff,
+ size_t *size, off_t *offset)
+{
+ struct zip *zip;
+
+ zip = *(a->pformat_data);
+
+ /* Return nothing gracefully. */
+ *buff = NULL;
+ *size = 0;
+ *offset = 0;
+ zip->end_of_entry = 1;
+
+ /* Skip body of entry. */
+ while (zip->entry_bytes_remaining > 0) {
+ *size = (a->compression_read_ahead)(a, buff,
+ zip->entry_bytes_remaining);
+ if (*size <= 0) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file body");
+ return (ARCHIVE_FATAL);
+ }
+ if (*size > zip->entry_bytes_remaining)
+ *size = zip->entry_bytes_remaining;
+ (a->compression_read_consume)(a, *size);
+ zip->entry_bytes_remaining -= *size;
+ zip->entry_offset += *size;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_zip_cleanup(struct archive *a)
+{
+ struct zip *zip;
+
+ zip = *(a->pformat_data);
+ if (zip->uncompressed_buffer != NULL)
+ free(zip->uncompressed_buffer);
+ archive_string_free(&(zip->pathname));
+ archive_string_free(&(zip->extra));
+ free(zip);
+ *(a->pformat_data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+i2(const char *p)
+{
+ return ((0xff & (int)p[0]) + 256 * (0xff & (int)p[1]));
+}
+
+
+static int
+i4(const char *p)
+{
+ return ((0xffff & i2(p)) + 0x10000 * (0xffff & i2(p+2)));
+}
OpenPOWER on IntegriCloud