Don't use zip_fopen in zip_source_zip, use new internal function _zip_source_zip_new in both. Fix errors in zip_close by also using _zip_source_zip_new. Other semi-related bug fixes. --HG-- branch : HEAD
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4780b71..9cde52d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt
@@ -115,7 +115,9 @@ zip_source_pop.c zip_source_read.c zip_source_stat.c + zip_source_window.c zip_source_zip.c + zip_source_zip_new.c zip_stat.c zip_stat_index.c zip_stat_init.c
diff --git a/lib/Makefile.am b/lib/Makefile.am index 388d53a..9ecf677 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am
@@ -73,7 +73,9 @@ zip_source_pop.c \ zip_source_read.c \ zip_source_stat.c \ + zip_source_window.c \ zip_source_zip.c \ + zip_source_zip_new.c \ zip_set_name.c \ zip_stat.c \ zip_stat_index.c \
diff --git a/lib/zip_close.c b/lib/zip_close.c index 14b257d..f815723 100644 --- a/lib/zip_close.c +++ b/lib/zip_close.c
@@ -175,8 +175,10 @@ if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) _zip_dirent_torrent_normalize(&de); - if (za->entry[i].changes.valid & ZIP_DIRENT_COMP_METHOD) + if (za->entry[i].changes.valid & ZIP_DIRENT_COMP_METHOD) { de.settable.comp_method = za->entry[i].changes.comp_method; + de.settable.valid |= ZIP_DIRENT_COMP_METHOD; + } /* use it as central directory entry */ memcpy(cd->entry+j, &de, sizeof(cd->entry[j])); @@ -192,6 +194,8 @@ de.settable.filename = strdup(za->cdir->entry[i].settable.filename); cd->entry[j].settable.filename = za->cdir->entry[i].settable.filename; } + de.settable.valid |= ZIP_DIRENT_FILENAME; + cd->entry[j].settable.valid |= ZIP_DIRENT_FILENAME; } } else { @@ -259,7 +263,7 @@ zs = NULL; if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { - if ((zs=zip_source_zip(za, za, i, 0, 0, -1)) == NULL) { + if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, -1, NULL)) == NULL) { error = 1; break; } @@ -375,6 +379,11 @@ st.comp_method = ZIP_CM_STORE; } + if ((de->settable.valid & ZIP_DIRENT_COMP_METHOD) == 0 || de->settable.comp_method == ZIP_CM_DEFAULT) { + de->settable.valid |= ZIP_DIRENT_COMP_METHOD; + de->settable.comp_method = ZIP_CM_DEFLATE; + } + if (st.comp_method != de->settable.comp_method) { struct zip_source *s_store, *s_crc; zip_compression_implementation comp_impl;
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c index dce5b34..23ec350 100644 --- a/lib/zip_dirent.c +++ b/lib/zip_dirent.c
@@ -175,6 +175,7 @@ void _zip_dirent_init(struct zip_dirent *de) { + de->settable.valid = 0; de->settable.comp_method = 0; de->settable.filename = NULL; de->settable.extrafield = NULL;
diff --git a/lib/zip_file_get_offset.c b/lib/zip_file_get_offset.c index ca45d3c..17a47b8 100644 --- a/lib/zip_file_get_offset.c +++ b/lib/zip_file_get_offset.c
@@ -51,7 +51,7 @@ */ unsigned int -_zip_file_get_offset(struct zip *za, int idx) +_zip_file_get_offset(struct zip *za, int idx, struct zip_error *ze) { struct zip_dirent de; unsigned int offset; @@ -59,11 +59,11 @@ offset = za->cdir->entry[idx].offset; if (fseeko(za->zp, offset, SEEK_SET) != 0) { - _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + _zip_error_set(ze, ZIP_ER_SEEK, errno); return 0; } - if (_zip_dirent_read(&de, za->zp, NULL, NULL, 1, &za->error) != 0) + if (_zip_dirent_read(&de, za->zp, NULL, NULL, 1, ze) != 0) return 0; offset += LENTRYSIZE + strlen(de.settable.filename) + de.settable.extrafield_len;
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c index 74cc6e6..657ed01 100644 --- a/lib/zip_fopen_index_encrypted.c +++ b/lib/zip_fopen_index_encrypted.c
@@ -48,96 +48,10 @@ const char *password) { struct zip_file *zf; - zip_compression_implementation comp_impl; - zip_encryption_implementation enc_impl; - struct zip_source *src, *s2; - zip_uint64_t start; - struct zip_stat st; + struct zip_source *src; - if (fileno >= za->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + if ((src=_zip_source_zip_new(za, za, fileno, flags, 0, 0, password)) == NULL) return NULL; - } - - if ((flags & ZIP_FL_UNCHANGED) == 0 - && ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) { - _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); - return NULL; - } - - if (fileno >= za->cdir->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return NULL; - } - - if (flags & ZIP_FL_ENCRYPTED) - flags |= ZIP_FL_COMPRESSED; - - zip_stat_index(za, fileno, flags, &st); - - enc_impl = NULL; - if ((flags & ZIP_FL_ENCRYPTED) == 0) { - if (st.encryption_method != ZIP_EM_NONE) { - if (password == NULL) { - _zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0); - return NULL; - } - if ((enc_impl=zip_get_encryption_implementation( - st.encryption_method)) == NULL) { - _zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); - return NULL; - } - } - } - - comp_impl = NULL; - if ((flags & ZIP_FL_COMPRESSED) == 0) { - if (st.comp_method != ZIP_CM_STORE) { - if ((comp_impl=zip_get_compression_implementation( - st.comp_method)) == NULL) { - _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); - return NULL; - } - } - } - - if ((start=_zip_file_get_offset(za, fileno)) == 0) - return NULL; - - if (st.comp_size == 0) { - if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL) - return NULL; - } - else { - if ((src=_zip_source_file_or_p(za, NULL, za->zp, start, st.comp_size, - 0, &st)) == NULL) - return NULL; - if (enc_impl) { - if ((s2=enc_impl(za, src, st.encryption_method, 0, password)) == NULL) { - zip_source_free(src); - /* XXX: set error (how?) */ - return NULL; - } - src = s2; - } - if (comp_impl) { - if ((s2=comp_impl(za, src, st.comp_method, 0)) == NULL) { - zip_source_free(src); - /* XXX: set error (how?) */ - return NULL; - } - src = s2; - } - if ((flags & ZIP_FL_COMPRESSED) == 0 - || st.comp_method == ZIP_CM_STORE ) { - if ((s2=zip_source_crc(za, src, 1)) == NULL) { - zip_source_free(src); - /* XXX: set error (how?) */ - return NULL; - } - src = s2; - } - } if (zip_source_open(src) < 0) { _zip_error_set_from_source(&za->error, src); @@ -145,7 +59,10 @@ return NULL; } - zf = _zip_file_new(za); + if ((zf=_zip_file_new(za)) == NULL) { + zip_source_free(src); + return NULL; + } zf->src = src;
diff --git a/lib/zip_source_window.c b/lib/zip_source_window.c new file mode 100644 index 0000000..0f8f1a9 --- /dev/null +++ b/lib/zip_source_window.c
@@ -0,0 +1,149 @@ +/* + zip_source_window.c -- return part of lower source + Copyright (C) 2012 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at <libzip@nih.at> + + 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. + 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. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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 <stdlib.h> +#include <string.h> + +#include "zipint.h" + +struct window { + zip_uint64_t skip; + zip_uint64_t len; + zip_uint64_t left; + int e[2]; +}; + +static zip_int64_t window_read(struct zip_source *, void *, void *, + zip_uint64_t, enum zip_source_cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_window(struct zip *za, struct zip_source *src, zip_uint64_t start, zip_uint64_t len) +{ + struct window *ctx; + + if (src == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((ctx=(struct window *)malloc(sizeof(*ctx))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + ctx->skip = start; + ctx->len = len; + ctx->left = len; + + return zip_source_layered(za, src, window_read, ctx); +} + + + +static zip_int64_t +window_read(struct zip_source *src, void *_ctx, void *data, + zip_uint64_t len, enum zip_source_cmd cmd) +{ + struct window *ctx; + zip_int64_t i, n; + char b[8192]; + + ctx = (struct window *)_ctx; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + for (n=0; n<ctx->skip; n+=i) { + i = (ctx->skip-n > sizeof(b) ? sizeof(b) : ctx->skip-n); + if ((i=zip_source_read(src, b, i)) < 0) + return ZIP_SOURCE_ERR_LOWER; + if (i==0) { + ctx->e[0] = ZIP_ER_EOF; + ctx->e[1] = 0; + return -1; + } + } + return 0; + + case ZIP_SOURCE_READ: + if (len > ctx->left) + len = ctx->left; + + if (len <= 0) + return 0; + + if ((n=zip_source_read(src, data, len)) < 0) + return ZIP_SOURCE_ERR_LOWER; + + ctx->left -= n; + + if (n == 0) { + if (ctx->left > 0) { + ctx->e[0] = ZIP_ER_EOF; + ctx->e[1] = 0; + return -1; + } + } + return n; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_STAT: + { + struct zip_stat *st; + + st = (struct zip_stat *)data; + + st->size = ctx->len; + st->valid |= ZIP_STAT_SIZE; + st->valid &= ~(ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE); + } + return 0; + + case ZIP_SOURCE_ERROR: + memcpy(data, ctx->e, sizeof(ctx->e)); + return 0; + + case ZIP_SOURCE_FREE: + free(ctx); + return 0; + + default: + return -1; + } + +}
diff --git a/lib/zip_source_zip.c b/lib/zip_source_zip.c index f7159b6..7426c4b 100644 --- a/lib/zip_source_zip.c +++ b/lib/zip_source_zip.c
@@ -38,153 +38,19 @@ #include "zipint.h" -struct read_zip { - struct zip_file *zf; - struct zip_stat st; - zip_uint64_t off; - zip_int64_t len; -}; - -static zip_int64_t read_zip(void *st, void *data, zip_uint64_t len, - enum zip_source_cmd cmd); - ZIP_EXTERN struct zip_source * zip_source_zip(struct zip *za, struct zip *srcza, zip_uint64_t srcidx, int flags, zip_uint64_t start, zip_int64_t len) { - struct zip_error error; - struct zip_source *zs; - struct read_zip *p; - - /* XXX: ZIP_FL_RECOMPRESS */ - - if (za == NULL) - return NULL; - - if (srcza == NULL || len < -1 || srcidx >= srcza->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return NULL; - } - - if ((flags & ZIP_FL_UNCHANGED) == 0 - && ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx)) { - _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); - return NULL; - } - if (len == 0) len = -1; - if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0) + if (start == 0 && len == -1) flags |= ZIP_FL_COMPRESSED; else flags &= ~ZIP_FL_COMPRESSED; - if ((p=(struct read_zip *)malloc(sizeof(*p))) == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - return NULL; - } - - _zip_error_copy(&error, &srcza->error); - - if (zip_stat_index(srcza, srcidx, flags, &p->st) < 0 - || (p->zf=zip_fopen_index(srcza, srcidx, flags)) == NULL) { - free(p); - _zip_error_copy(&za->error, &srcza->error); - _zip_error_copy(&srcza->error, &error); - - return NULL; - } - p->off = start; - p->len = len; - - if ((flags & ZIP_FL_COMPRESSED) == 0) { - p->st.size = p->st.comp_size = len; - p->st.comp_method = ZIP_CM_STORE; - p->st.crc = 0; - } - - if ((zs=zip_source_function(za, read_zip, p)) == NULL) { - free(p); - return NULL; - } - - return zs; -} - - - -static zip_int64_t -read_zip(void *state, void *data, zip_uint64_t len, enum zip_source_cmd cmd) -{ - struct read_zip *z; - char b[8192], *buf; - int i; - zip_uint64_t n; - - z = (struct read_zip *)state; - buf = (char *)data; - - switch (cmd) { - case ZIP_SOURCE_OPEN: - for (n=0; n<z->off; n+= i) { - i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n); - if ((i=zip_fread(z->zf, b, i)) < 0) { - zip_fclose(z->zf); - z->zf = NULL; - return -1; - } - } - return 0; - - case ZIP_SOURCE_READ: - if (z->len != -1) - n = len > z->len ? z->len : len; - else - n = len; - - - if ((i=zip_fread(z->zf, buf, n)) < 0) - return -1; - - if (z->len != -1) - z->len -= i; - - return i; - - case ZIP_SOURCE_CLOSE: - return 0; - - case ZIP_SOURCE_STAT: - if (len < sizeof(z->st)) - return -1; - len = sizeof(z->st); - - memcpy(data, &z->st, len); - return len; - - case ZIP_SOURCE_ERROR: - { - int *e; - - if (len < sizeof(int)*2) - return -1; - - e = (int *)data; - zip_file_error_get(z->zf, e, e+1); - } - return sizeof(int)*2; - - case ZIP_SOURCE_FREE: - zip_fclose(z->zf); - free(z); - return 0; - - default: - ; - } - - return -1; + return _zip_source_zip_new(za, srcza, srcidx, flags, start, len, NULL); }
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c new file mode 100644 index 0000000..b5364a1 --- /dev/null +++ b/lib/zip_source_zip_new.c
@@ -0,0 +1,175 @@ +/* + zip_source_zip_new.c -- prepare data structures for zip_fopen/zip_source_zip + Copyright (C) 2012 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at <libzip@nih.at> + + 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. + 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. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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 <stdlib.h> + +#include "zipint.h" + + + +struct zip_source * +_zip_source_zip_new(struct zip *za, struct zip *srcza, zip_uint64_t srcidx, int flags, + zip_uint64_t start, zip_int64_t len, const char *password) +{ + zip_compression_implementation comp_impl; + zip_encryption_implementation enc_impl; + struct zip_source *src, *s2; + zip_uint64_t offset; + struct zip_stat st; + + if (za == NULL) + return NULL; + + if (srcza == NULL || len < -1 || srcidx >= srcza->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && (ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx) || srcza->entry[srcidx].state == ZIP_ST_DELETED)) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return NULL; + } + + if (srcza->cdir == NULL || srcidx >= srcza->cdir->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (flags & ZIP_FL_ENCRYPTED) + flags |= ZIP_FL_COMPRESSED; + + if ((start > 0 || len > 0) && (flags & ZIP_FL_COMPRESSED)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if (zip_stat_index(srcza, srcidx, flags, &st) < 0) { + _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); + return NULL; + } + + if (len == -1) + len = 0; + + /* overflow or past end of file */ + if ((start > 0 || len > 0) && (start+len < start || start+len > st.size)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + enc_impl = NULL; + if (((flags & ZIP_FL_ENCRYPTED) == 0) && (st.encryption_method != ZIP_EM_NONE)) { + if (password == NULL) { + _zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0); + return NULL; + } + if ((enc_impl=zip_get_encryption_implementation( + st.encryption_method)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); + return NULL; + } + } + + comp_impl = NULL; + if ((flags & ZIP_FL_COMPRESSED) == 0) { + if (st.comp_method != ZIP_CM_STORE) { + if ((comp_impl=zip_get_compression_implementation( + st.comp_method)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); + return NULL; + } + } + } + + if ((offset=_zip_file_get_offset(srcza, srcidx, &za->error)) == 0) + return NULL; + + if (st.comp_size == 0) { + if ((src=zip_source_buffer(za, NULL, 0, 0)) == NULL) + return NULL; + } + else { + if (start+len > 0 && enc_impl == NULL && comp_impl == NULL) { + if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset+start, + len ? len : st.size-start, + 0, &st)) == NULL) + return NULL; + } + else { + if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset, st.comp_size, + 0, &st)) == NULL) + return NULL; + } + + if (enc_impl) { + if ((s2=enc_impl(za, src, st.encryption_method, 0, password)) == NULL) { + zip_source_free(src); + /* XXX: set error (how?) */ + return NULL; + } + src = s2; + } + if (comp_impl) { + if ((s2=comp_impl(za, src, st.comp_method, 0)) == NULL) { + zip_source_free(src); + /* XXX: set error (how?) */ + return NULL; + } + src = s2; + } + if (((flags & ZIP_FL_COMPRESSED) == 0 || st.comp_method == ZIP_CM_STORE) + && (len == 0 || start+len == st.comp_size)) { + /* when reading the whole file, check for crc errors */ + if ((s2=zip_source_crc(za, src, 1)) == NULL) { + zip_source_free(src); + /* XXX: set error (how?) */ + return NULL; + } + src = s2; + } + + if (start+len > 0 && (comp_impl || enc_impl)) { + if ((s2=zip_source_window(za, src, start, len ? len : st.size-start)) == NULL) { + zip_source_free(src); + /* XXX: set error (how?) (why?) */ + return NULL; + } + src = s2; + } + } + + return src; +}
diff --git a/lib/zipint.h b/lib/zipint.h index 8d0da0b..b39b786 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -160,6 +160,8 @@ ZIP_EXTERN zip_int64_t zip_source_read(struct zip_source *, void *, zip_uint64_t); ZIP_EXTERN int zip_source_stat(struct zip_source *, struct zip_stat *); +ZIP_EXTERN struct zip_source *zip_source_window(struct zip *, struct zip_source *, + zip_uint64_t, zip_uint64_t); /* This function will probably remain private. It is not needed to @@ -335,7 +337,7 @@ const char *_zip_error_strerror(struct zip_error *); int _zip_file_fillbuf(void *, size_t, struct zip_file *); -unsigned int _zip_file_get_offset(struct zip *, int); +unsigned int _zip_file_get_offset(struct zip *, int, struct zip_error *); int _zip_filerange_crc(FILE *, off_t, off_t, uLong *, struct zip_error *); @@ -350,6 +352,8 @@ zip_uint64_t, zip_int64_t, int, const struct zip_stat *); struct zip_source *_zip_source_new(struct zip *); +struct zip_source *_zip_source_zip_new(struct zip *, struct zip *, zip_uint64_t, int, + zip_uint64_t, zip_int64_t, const char *); int _zip_changed(struct zip *, int *); void _zip_free(struct zip *);