Checkpoint commit of stacked sources to implement encryption/compression. Used for zip_fread. Not yet used for writing (zip_close). Traditional PKWARE encryption untested. --HG-- branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am index b6d7b13..68dbaf8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am
@@ -32,11 +32,15 @@ zip_file_strerror.c \ zip_filerange_crc.c \ zip_fopen.c \ + zip_fopen_encrypted.c \ zip_fopen_index.c \ + zip_fopen_index_encrypted.c \ zip_fread.c \ zip_free.c \ zip_get_archive_comment.c \ zip_get_archive_flag.c \ + zip_get_compression_implementation.c \ + zip_get_encryption_implementation.c \ zip_get_file_comment.c \ zip_get_num_files.c \ zip_get_name.c \ @@ -50,10 +54,13 @@ zip_set_archive_flag.c \ zip_set_file_comment.c \ zip_source_buffer.c \ + zip_source_call.c \ + zip_source_deflate.c \ zip_source_file.c \ zip_source_filep.c \ zip_source_free.c \ zip_source_function.c \ + zip_source_pkware.c \ zip_source_zip.c \ zip_set_name.c \ zip_stat.c \
diff --git a/lib/zip.h b/lib/zip.h index 03b5640..66886e1 100644 --- a/lib/zip.h +++ b/lib/zip.h
@@ -76,6 +76,12 @@ #define ZIP_AFL_TORRENT 1 /* torrent zipped */ #define ZIP_AFL_RDONLY 2 /* read only -- cannot be cleared */ + +/* flags for compression and encryption sources */ + +#define ZIP_CODEC_ENCODE 1 /* compress/encrypt */ + + /* libzip error codes */ #define ZIP_ER_OK 0 /* N No error */ @@ -105,7 +111,7 @@ #define ZIP_ER_ENCRNOTSUPP 24 /* N Encryption method not supported */ #define ZIP_ER_RDONLY 25 /* N Read-only archive */ #define ZIP_ER_NOPASSWD 26 /* N No password provided */ - +#define ZIP_ER_WRONGPASSWD 27 /* N Wrong password provided */ /* type of system error value */ @@ -165,9 +171,6 @@ ZIP_SOURCE_FREE /* cleanup and free resources */ }; -typedef ssize_t (*zip_source_callback)(void *state, void *data, - size_t len, enum zip_source_cmd cmd); - struct zip_stat { const char *name; /* name of the file */ int index; /* index within archive */ @@ -183,6 +186,16 @@ struct zip_file; struct zip_source; +typedef ssize_t (*zip_source_callback)(void *state, void *data, + size_t len, enum zip_source_cmd cmd); +typedef struct zip_source *(*zip_compression_implementation)(struct zip *, + struct zip_source *, + zip_uint16_t, int); +typedef struct zip_source *(*zip_encryption_implementation)(struct zip *, + struct zip_source *, + zip_uint16_t, int, + const char *); + ZIP_EXTERN int zip_add(struct zip *, const char *, struct zip_source *); @@ -199,10 +212,18 @@ ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *); ZIP_EXTERN const char *zip_file_strerror(struct zip_file *); ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, int); +ZIP_EXTERN struct zip_file *zip_fopen_encrypted(struct zip *, const char *, + int, const char *); ZIP_EXTERN struct zip_file *zip_fopen_index(struct zip *, int, int); +ZIP_EXTERN struct zip_file *zip_fopen_index_encrypted(struct zip *, int, int, + const char *); ZIP_EXTERN ssize_t zip_fread(struct zip_file *, void *, size_t); ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, int); ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int); +ZIP_EXTERN zip_compression_implementation zip_get_compression_implementation( + zip_uint16_t); +ZIP_EXTERN zip_encryption_implementation zip_get_encryption_implementation( + zip_uint16_t); ZIP_EXTERN const char *zip_get_file_comment(struct zip *, int, int *, int); ZIP_EXTERN const char *zip_get_name(struct zip *, int, int); ZIP_EXTERN int zip_get_num_files(struct zip *); @@ -215,6 +236,11 @@ ZIP_EXTERN int zip_set_file_comment(struct zip *, int, const char *, int); ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, zip_uint64_t, int); +ZIP_EXTERN ssize_t zip_source_call(struct zip_source *, void *, size_t, + enum zip_source_cmd); +ZIP_EXTERN struct zip_source *zip_source_deflate(struct zip *, + struct zip_source *, + zip_uint16_t, int); ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *, zip_uint64_t, zip_int64_t); ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *, @@ -222,6 +248,10 @@ ZIP_EXTERN void zip_source_free(struct zip_source *); ZIP_EXTERN struct zip_source *zip_source_function(struct zip *, zip_source_callback, void *); +ZIP_EXTERN struct zip_source *zip_source_pkware(struct zip *, + struct zip_source *, + zip_uint16_t, int, + const char *); ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *, int, int, zip_uint64_t, zip_int64_t); ZIP_EXTERN int zip_stat(struct zip *, const char *, int, struct zip_stat *);
diff --git a/lib/zip_fclose.c b/lib/zip_fclose.c index 8709362..66d74e4 100644 --- a/lib/zip_fclose.c +++ b/lib/zip_fclose.c
@@ -44,10 +44,8 @@ { int i, ret; - if (zf->zstr) - inflateEnd(zf->zstr); - free(zf->buffer); - free(zf->zstr); + if (zf->src) + zip_source_free(zf->src); for (i=0; i<zf->za->nfile; i++) { if (zf->za->file[i] == zf) {
diff --git a/lib/zip_fopen.c b/lib/zip_fopen.c index 6e2f724..5a65eba 100644 --- a/lib/zip_fopen.c +++ b/lib/zip_fopen.c
@@ -1,6 +1,6 @@ /* zip_fopen.c -- open file in zip archive for reading - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -45,5 +45,5 @@ if ((idx=zip_name_locate(za, fname, flags)) < 0) return NULL; - return zip_fopen_index(za, idx, flags); + return zip_fopen_index_encrypted(za, idx, flags, za->default_password); }
diff --git a/lib/zip_fopen_encrypted.c b/lib/zip_fopen_encrypted.c new file mode 100644 index 0000000..0a4b131 --- /dev/null +++ b/lib/zip_fopen_encrypted.c
@@ -0,0 +1,50 @@ +/* + zip_fopen_encrypted.c -- open file for reading with password + Copyright (C) 1999-2009 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 "zipint.h" + + + +ZIP_EXTERN struct zip_file * +zip_fopen_encrypted(struct zip *za, const char *fname, int flags, + const char *password) +{ + int idx; + + if ((idx=zip_name_locate(za, fname, flags)) < 0) + return NULL; + + return zip_fopen_index_encrypted(za, idx, flags, password); +}
diff --git a/lib/zip_fopen_index.c b/lib/zip_fopen_index.c index 7f2d90a..95be69e 100644 --- a/lib/zip_fopen_index.c +++ b/lib/zip_fopen_index.c
@@ -39,183 +39,10 @@ #include "zipint.h" -static struct zip_file *_zip_file_new(struct zip *za); - ZIP_EXTERN struct zip_file * zip_fopen_index(struct zip *za, int fileno, int flags) { - int len, ret; - int zfflags; - struct zip_file *zf; - - if ((fileno < 0) || (fileno >= za->nentry)) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - 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 (za->cdir->entry[fileno].bitflags & ZIP_GPBF_ENCRYPTED) { - _zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); - return NULL; - } - - zfflags = 0; - switch (za->cdir->entry[fileno].comp_method) { - case ZIP_CM_STORE: - zfflags |= ZIP_ZF_CRC; - break; - - case ZIP_CM_DEFLATE: - if ((flags & ZIP_FL_COMPRESSED) == 0) - zfflags |= ZIP_ZF_CRC | ZIP_ZF_DECOMP; - break; - default: - if ((flags & ZIP_FL_COMPRESSED) == 0) { - _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); - return NULL; - } - break; - } - - zf = _zip_file_new(za); - - zf->flags = zfflags; - /* zf->name = za->cdir->entry[fileno].filename; */ - zf->method = za->cdir->entry[fileno].comp_method; - zf->bytes_left = za->cdir->entry[fileno].uncomp_size; - zf->cbytes_left = za->cdir->entry[fileno].comp_size; - zf->crc_orig = za->cdir->entry[fileno].crc; - - if ((zf->fpos=_zip_file_get_offset(za, fileno)) == 0) { - zip_fclose(zf); - return NULL; - } - - if ((zf->flags & ZIP_ZF_DECOMP) == 0) - zf->bytes_left = zf->cbytes_left; - else { - if ((zf->buffer=(char *)malloc(BUFSIZE)) == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - zip_fclose(zf); - return NULL; - } - - len = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); - if (len <= 0) { - _zip_error_copy(&za->error, &zf->error); - zip_fclose(zf); - return NULL; - } - - if ((zf->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - zip_fclose(zf); - return NULL; - } - zf->zstr->zalloc = Z_NULL; - zf->zstr->zfree = Z_NULL; - zf->zstr->opaque = NULL; - zf->zstr->next_in = (Bytef *)zf->buffer; - zf->zstr->avail_in = len; - - /* negative value to tell zlib that there is no header */ - if ((ret=inflateInit2(zf->zstr, -MAX_WBITS)) != Z_OK) { - _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); - zip_fclose(zf); - return NULL; - } - } - - return zf; -} - - - -int -_zip_file_fillbuf(void *buf, size_t buflen, struct zip_file *zf) -{ - int i, j; - - if (zf->error.zip_err != ZIP_ER_OK) - return -1; - - if ((zf->flags & ZIP_ZF_EOF) || zf->cbytes_left <= 0 || buflen <= 0) - return 0; - - if (fseeko(zf->za->zp, zf->fpos, SEEK_SET) < 0) { - _zip_error_set(&zf->error, ZIP_ER_SEEK, errno); - return -1; - } - if (buflen < zf->cbytes_left) - i = buflen; - else - i = zf->cbytes_left; - - j = fread(buf, 1, i, zf->za->zp); - if (j == 0) { - _zip_error_set(&zf->error, ZIP_ER_EOF, 0); - j = -1; - } - else if (j < 0) - _zip_error_set(&zf->error, ZIP_ER_READ, errno); - else { - zf->fpos += j; - zf->cbytes_left -= j; - } - - return j; -} - - - -static struct zip_file * -_zip_file_new(struct zip *za) -{ - struct zip_file *zf, **file; - int n; - - if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - return NULL; - } - - if (za->nfile >= za->nfile_alloc-1) { - n = za->nfile_alloc + 10; - file = (struct zip_file **)realloc(za->file, - n*sizeof(struct zip_file *)); - if (file == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - free(zf); - return NULL; - } - za->nfile_alloc = n; - za->file = file; - } - - za->file[za->nfile++] = zf; - - zf->za = za; - _zip_error_init(&zf->error); - zf->flags = 0; - zf->crc = crc32(0L, Z_NULL, 0); - zf->crc_orig = 0; - zf->method = -1; - zf->bytes_left = zf->cbytes_left = 0; - zf->fpos = 0; - zf->buffer = NULL; - zf->zstr = NULL; - - return zf; + return zip_fopen_index_encrypted(za, fileno, flags, za->default_password); }
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c new file mode 100644 index 0000000..ace0a5d --- /dev/null +++ b/lib/zip_fopen_index_encrypted.c
@@ -0,0 +1,179 @@ +/* + zip_fopen_index_encrypted.c -- open file for reading by index w/ password + Copyright (C) 1999-2009 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#include "zipint.h" + +static struct zip_file *_zip_file_new(struct zip *za); + + + +ZIP_EXTERN struct zip_file * +zip_fopen_index_encrypted(struct zip *za, int fileno, int flags, + const char *password) +{ + int zfflags; + 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; + + if ((fileno < 0) || (fileno >= za->nentry)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + 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); + + zfflags = 0; + if (st.comp_method == ZIP_CM_STORE || (flags & ZIP_FL_COMPRESSED) == 0) + zfflags |= ZIP_ZF_CRC; + + enc_impl = NULL; + if ((flags & ZIP_FL_ENCRYPTED) == 0) { + if (st.encryption_method != ZIP_EM_NONE) { + 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 ((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, ZIP_EM_TRAD_PKWARE, 0, password)) == NULL) { + zip_source_free(src); + return NULL; + } + src = s2; + } + if (comp_impl) { + if ((s2=comp_impl(za, src, za->cdir->entry[fileno].comp_method, + 0)) == NULL) { + zip_source_free(src); + return NULL; + } + src = s2; + } + + if (zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { + zip_source_free(src); + return NULL; + } + + zf = _zip_file_new(za); + + zf->flags = zfflags; + zf->bytes_left = za->cdir->entry[fileno].uncomp_size; + zf->crc_orig = za->cdir->entry[fileno].crc; + zf->src = src; + + return zf; +} + + + +static struct zip_file * +_zip_file_new(struct zip *za) +{ + struct zip_file *zf, **file; + int n; + + if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (za->nfile >= za->nfile_alloc-1) { + n = za->nfile_alloc + 10; + file = (struct zip_file **)realloc(za->file, + n*sizeof(struct zip_file *)); + if (file == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + free(zf); + return NULL; + } + za->nfile_alloc = n; + za->file = file; + } + + za->file[za->nfile++] = zf; + + zf->za = za; + _zip_error_init(&zf->error); + zf->flags = 0; + zf->crc = crc32(0L, Z_NULL, 0); + zf->crc_orig = 0; + zf->bytes_left = 0; + zf->src = NULL; + + return zf; +}
diff --git a/lib/zip_fread.c b/lib/zip_fread.c index 3d9d3c2..4146b68 100644 --- a/lib/zip_fread.c +++ b/lib/zip_fread.c
@@ -40,9 +40,7 @@ ZIP_EXTERN ssize_t zip_fread(struct zip_file *zf, void *outbuf, size_t toread) { - int ret; - size_t out_before, len; - int i; + ssize_t n; if (!zf) return -1; @@ -53,70 +51,34 @@ if ((zf->flags & ZIP_ZF_EOF) || (toread == 0)) return 0; - if (zf->bytes_left == 0) { + if ((n=zip_source_call(zf->src, outbuf, toread, ZIP_SOURCE_READ)) < 0) { + int e[2]; + zip_source_call(zf->src, e, sizeof(e), ZIP_SOURCE_ERROR); + _zip_error_set(&zf->error, e[0], e[1]); + return -1; + } + + if (n == 0) { zf->flags |= ZIP_ZF_EOF; + if (zf->flags & ZIP_ZF_CRC) { + if (zf->bytes_left != 0) { + _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); + return -1; + } + if (zf->crc != zf->crc_orig) { _zip_error_set(&zf->error, ZIP_ER_CRC, 0); return -1; } } - return 0; } - - if ((zf->flags & ZIP_ZF_DECOMP) == 0) { - ret = _zip_file_fillbuf(outbuf, toread, zf); - if (ret > 0) { - if (zf->flags & ZIP_ZF_CRC) - zf->crc = crc32(zf->crc, (Bytef *)outbuf, ret); - zf->bytes_left -= ret; - } - return ret; - } - - zf->zstr->next_out = (Bytef *)outbuf; - zf->zstr->avail_out = toread; - out_before = zf->zstr->total_out; - - /* endless loop until something has been accomplished */ - for (;;) { - ret = inflate(zf->zstr, Z_SYNC_FLUSH); - - switch (ret) { - case Z_OK: - case Z_STREAM_END: - /* all ok */ - /* Z_STREAM_END probably won't happen, since we didn't - have a header */ - len = zf->zstr->total_out - out_before; - if (len >= zf->bytes_left || len >= toread) { - if (zf->flags & ZIP_ZF_CRC) - zf->crc = crc32(zf->crc, (Bytef *)outbuf, len); - zf->bytes_left -= len; - return len; - } - break; - - case Z_BUF_ERROR: - if (zf->zstr->avail_in == 0) { - i = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); - if (i == 0) { - _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); - return -1; - } - else if (i < 0) - return -1; - zf->zstr->next_in = (Bytef *)zf->buffer; - zf->zstr->avail_in = i; - continue; - } - /* fallthrough */ - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_STREAM_ERROR: - case Z_MEM_ERROR: - _zip_error_set(&zf->error, ZIP_ER_ZLIB, ret); - return -1; + else { + if (zf->flags & ZIP_ZF_CRC) { + zf->bytes_left -= n; + zf->crc = crc32(zf->crc, (Bytef *)outbuf, n); } } + + return n; }
diff --git a/lib/zip_get_compression_implementation.c b/lib/zip_get_compression_implementation.c new file mode 100644 index 0000000..8d4ccb6 --- /dev/null +++ b/lib/zip_get_compression_implementation.c
@@ -0,0 +1,46 @@ +/* + zip_get_compression_implementation.c -- get compression implementation + Copyright (C) 2009 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 "zipint.h" + + + +ZIP_EXTERN zip_compression_implementation +zip_get_compression_implementation(zip_uint16_t cm) +{ + if (cm == ZIP_CM_DEFLATE) + return zip_source_deflate; + return NULL; +}
diff --git a/lib/zip_get_encryption_implementation.c b/lib/zip_get_encryption_implementation.c new file mode 100644 index 0000000..d83698c --- /dev/null +++ b/lib/zip_get_encryption_implementation.c
@@ -0,0 +1,46 @@ +/* + zip_get_encryption_implementation.c -- get encryption implementation + Copyright (C) 2009 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 "zipint.h" + + + +ZIP_EXTERN zip_encryption_implementation +zip_get_encryption_implementation(zip_uint16_t em) +{ + if (em == ZIP_EM_TRAD_PKWARE) + return zip_source_pkware; + return NULL; +}
diff --git a/lib/zip_new.c b/lib/zip_new.c index 3e8ccee..7ce1237 100644 --- a/lib/zip_new.c +++ b/lib/zip_new.c
@@ -65,6 +65,7 @@ za->nfile = za->nfile_alloc = 0; za->file = NULL; za->flags = za->ch_flags = 0; + za->default_password = NULL; return za; }
diff --git a/lib/zip_set_archive_flag.c b/lib/zip_set_archive_flag.c index dc3ef94..e0e713a 100644 --- a/lib/zip_set_archive_flag.c +++ b/lib/zip_set_archive_flag.c
@@ -40,7 +40,7 @@ ZIP_EXTERN int zip_set_archive_flag(struct zip *za, int flag, int value) { - int new_flags; + unsigned int new_flags; if (value) new_flags = za->ch_flags | flag;
diff --git a/lib/zip_source_call.c b/lib/zip_source_call.c new file mode 100644 index 0000000..c07979b --- /dev/null +++ b/lib/zip_source_call.c
@@ -0,0 +1,44 @@ +/* + zip_source_deflate.c -- deflate (de)compressoin routines + Copyright (C) 2009 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 "zipint.h" + + + +ZIP_EXTERN ssize_t zip_source_call(struct zip_source *src, void *data, + size_t len, enum zip_source_cmd cmd) +{ + return src->f(src->ud, data, len, cmd); +}
diff --git a/lib/zip_source_deflate.c b/lib/zip_source_deflate.c new file mode 100644 index 0000000..04efd4b --- /dev/null +++ b/lib/zip_source_deflate.c
@@ -0,0 +1,408 @@ +/* + zip_source_deflate.c -- deflate (de)compressoin routines + Copyright (C) 2009 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 deflate { + struct zip_source *src; + int e[2]; + + int eof; + int mem_level; + zip_uint64_t size; + zip_uint32_t crc; + char buffer[BUFSIZE]; + z_stream zstr; +}; + +static ssize_t compress_read(struct deflate *, void *, size_t); +static ssize_t decompress_read(struct deflate *, void *, size_t); +static ssize_t deflate_compress(void *, void *, size_t, enum zip_source_cmd); +static ssize_t deflate_decompress(void *, void *, size_t, enum zip_source_cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_deflate(struct zip *za, struct zip_source *src, + zip_uint16_t cm, int flags) +{ + struct deflate *ctx; + + if (za == NULL || src == NULL || cm != ZIP_CM_DEFLATE) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((ctx=(struct deflate *)malloc(sizeof(*ctx))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + ctx->src = src; + ctx->e[0] = ctx->e[1] = 0; + ctx->eof = 0; + if (flags & ZIP_CODEC_ENCODE) { + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + ctx->mem_level = TORRENT_MEM_LEVEL; + else + ctx->mem_level = MAX_MEM_LEVEL; + } + + return zip_source_function(za, ((flags & ZIP_CODEC_ENCODE) + ? deflate_compress : deflate_decompress), + ctx); +} + + + +static ssize_t +compress_read(struct deflate *ctx, void *data, size_t len) +{ + int end, ret; + ssize_t n; + size_t out_before; + + if (ctx->e[0] != 0) + return -1; + + if (ctx->eof || (len == 0)) + return 0; + + ctx->zstr.next_out = (Bytef *)data; + ctx->zstr.avail_out = len; + out_before = ctx->zstr.total_out; + + end = 0; + while (!end) { + ret = deflate(&ctx->zstr, ctx->eof ? Z_FINISH : 0); + + switch (ret) { + case Z_OK: + case Z_STREAM_END: + /* all ok */ + + if (ctx->zstr.total_out - out_before >= len) + end = 1; + break; + + case Z_BUF_ERROR: + if (ctx->zstr.avail_in == 0) { + if (ctx->eof) { + end = 1; + break; + } + + if ((n=zip_source_call(ctx->src, ctx->buffer, + sizeof(ctx->buffer), ZIP_SOURCE_READ)) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), + ZIP_SOURCE_ERROR); + end = 1; + break; + } + else if (n == 0) { + ctx->eof = 1; + ctx->size = ctx->zstr.total_in; + /* XXX: check against stat of src? */ + } + else { + ctx->crc = crc32(ctx->crc, (Bytef *)ctx->buffer, n); + ctx->zstr.next_in = (Bytef *)ctx->buffer; + ctx->zstr.avail_in = n; + } + continue; + } + /* fallthrough */ + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_MEM_ERROR: + ctx->e[0] = ZIP_ER_ZLIB; + ctx->e[1] = ret; + + end = 1; + break; + } + } + + if (ctx->zstr.total_out > out_before) + return ctx->zstr.total_out - out_before; + + return (ctx->e[0] == 0) ? 0 : -1; +} + + + +static ssize_t +decompress_read(struct deflate *ctx, void *data, size_t len) +{ + int end, ret; + ssize_t n; + + if (ctx->e[0] != 0) + return -1; + + if (ctx->eof || (len == 0)) + return 0; + + ctx->zstr.next_out = (Bytef *)data; + ctx->zstr.avail_out = len; + + end = 0; + while (!end && ctx->zstr.avail_out) { + ret = inflate(&ctx->zstr, Z_SYNC_FLUSH); + + switch (ret) { + case Z_OK: + break; + + case Z_STREAM_END: + ctx->eof = 1; + end = 1; + break; + + case Z_BUF_ERROR: + if (ctx->zstr.avail_in == 0) { + if ((n=zip_source_call(ctx->src, ctx->buffer, + sizeof(ctx->buffer), ZIP_SOURCE_READ)) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), + ZIP_SOURCE_ERROR); + end = 1; + break; + } + else if (n == 0) + ctx->eof = 1; + else { + ctx->zstr.next_in = (Bytef *)ctx->buffer; + ctx->zstr.avail_in = n; + } + continue; + } + /* fallthrough */ + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_MEM_ERROR: + ctx->e[0] = ZIP_ER_ZLIB; + ctx->e[1] = ret; + end = 1; + break; + } + } + + if (ctx->zstr.avail_out < len) + return len - ctx->zstr.avail_out; + + return (ctx->e[0] == 0) ? 0 : -1; +} + + + +static ssize_t +deflate_compress(void *ud, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct deflate *ctx; + int ret; + + ctx = (struct deflate *)ud; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + + ctx->zstr.zalloc = Z_NULL; + ctx->zstr.zfree = Z_NULL; + ctx->zstr.opaque = NULL; + ctx->zstr.avail_in = 0; + ctx->zstr.avail_out = 0; + + /* negative value to tell zlib not to write a header */ + if ((ret=deflateInit2(&ctx->zstr, Z_BEST_COMPRESSION, Z_DEFLATED, + -MAX_WBITS, ctx->mem_level, + Z_DEFAULT_STRATEGY)) != Z_OK) { + ctx->e[0] = ZIP_ER_ZLIB; + ctx->e[1] = ret; + return -1; + + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + + return 0; + } + + case ZIP_SOURCE_READ: + return compress_read(ctx, data, len); + + case ZIP_SOURCE_CLOSE: + deflateEnd(&ctx->zstr); + + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + return 0; + + case ZIP_SOURCE_STAT: + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + else { + struct zip_stat *st; + + st = (struct zip_stat *)data; + + st->comp_method = ZIP_CM_DEFLATE; + if (ctx->eof) { + st->comp_size = ctx->size; + st->crc = ctx->crc; + } + else + st->comp_size = -1; + } + return 0; + + case ZIP_SOURCE_ERROR: + if (len < sizeof(int)*2) + return -1; + + memcpy(data, ctx->e, sizeof(int)*2); + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + /* XXX: deflateEnd if close was not called */ + zip_source_call(ctx->src, data, len, cmd); + free(ctx); + return 0; + + default: + ctx->e[0] = ZIP_ER_INVAL; + ctx->e[1] = 0; + return -1; + } + +} + + + +static ssize_t +deflate_decompress(void *ud, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct deflate *ctx; + ssize_t n; + int ret; + + ctx = (struct deflate *)ud; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + + if ((n=zip_source_call(ctx->src, ctx->buffer, sizeof(ctx->buffer), + ZIP_SOURCE_READ)) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + + ctx->zstr.zalloc = Z_NULL; + ctx->zstr.zfree = Z_NULL; + ctx->zstr.opaque = NULL; + ctx->zstr.next_in = (Bytef *)ctx->buffer; + ctx->zstr.avail_in = n; + + /* negative value to tell zlib that there is no header */ + if ((ret=inflateInit2(&ctx->zstr, -MAX_WBITS)) != Z_OK) { + ctx->e[0] = ZIP_ER_ZLIB; + ctx->e[1] = ret; + + zip_source_call(ctx->src, NULL, 0, ZIP_SOURCE_CLOSE); + return -1; + } + return 0; + + case ZIP_SOURCE_READ: + return decompress_read(ctx, data, len); + + case ZIP_SOURCE_CLOSE: + inflateEnd(&ctx->zstr); + + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + return 0; + + case ZIP_SOURCE_STAT: + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + else { + struct zip_stat *st; + + st = (struct zip_stat *)data; + + st->comp_method = ZIP_CM_STORE; + if (st->comp_size > 0 && st->size > 0) + st->comp_size = st->size; + } + return 0; + + case ZIP_SOURCE_ERROR: + if (len < sizeof(int)*2) + return -1; + + memcpy(data, ctx->e, sizeof(int)*2); + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + /* XXX: inflateEnd if close was not called */ + zip_source_call(ctx->src, data, len, cmd); + free(ctx); + return 0; + + default: + ctx->e[0] = ZIP_ER_INVAL; + ctx->e[1] = 0; + return -1; + } + +}
diff --git a/lib/zip_source_file.c b/lib/zip_source_file.c index 973f133..79c8ee5 100644 --- a/lib/zip_source_file.c +++ b/lib/zip_source_file.c
@@ -1,6 +1,6 @@ /* zip_source_file.c -- create data source from file - Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -52,5 +52,5 @@ return NULL; } - return _zip_source_file_or_p(za, fname, NULL, start, len); + return _zip_source_file_or_p(za, fname, NULL, start, len, 1, NULL); }
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c index 6d13972..7ca0704 100644 --- a/lib/zip_source_filep.c +++ b/lib/zip_source_filep.c
@@ -1,6 +1,6 @@ /* zip_source_filep.c -- create data source from FILE * - Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -44,6 +44,9 @@ struct read_file { char *fname; /* name of file to copy from */ FILE *f; /* file to copy from */ + int closep; /* close f */ + struct zip_stat st; /* stat information passed in */ + zip_uint64_t off; /* start offset of */ zip_int64_t len; /* length of data to copy */ zip_int64_t remain; /* bytes remaining to be copied */ @@ -67,14 +70,15 @@ return NULL; } - return _zip_source_file_or_p(za, NULL, file, start, len); + return _zip_source_file_or_p(za, NULL, file, start, len, 1, NULL); } struct zip_source * _zip_source_file_or_p(struct zip *za, const char *fname, FILE *file, - zip_uint64_t start, zip_int64_t len) + zip_uint64_t start, zip_int64_t len, int closep, + const struct zip_stat *st) { struct read_file *f; struct zip_source *zs; @@ -100,7 +104,12 @@ f->f = file; f->off = start; f->len = (len ? len : -1); - + f->closep = f->fname ? 1 : closep; + if (st) + memcpy(&f->st, st, sizeof(f->st)); + else + zip_stat_init(&f->st); + if ((zs=zip_source_function(za, read_file, f)) == NULL) { free(f); return NULL; @@ -131,10 +140,12 @@ } } - if (fseeko(z->f, (off_t)z->off, SEEK_SET) < 0) { - z->e[0] = ZIP_ER_SEEK; - z->e[1] = errno; - return -1; + if (z->closep) { + if (fseeko(z->f, (off_t)z->off, SEEK_SET) < 0) { + z->e[0] = ZIP_ER_SEEK; + z->e[1] = errno; + return -1; + } } z->remain = z->len; return 0; @@ -144,7 +155,17 @@ n = len > z->remain ? z->remain : len; else n = len; - + + if (!z->closep) { + /* we might share this file with others, so let's be save */ + if (fseeko(z->f, (off_t)(z->off + z->len-z->remain), + SEEK_SET) < 0) { + z->e[0] = ZIP_ER_SEEK; + z->e[1] = errno; + return -1; + } + } + if ((i=fread(buf, 1, n, z->f)) < 0) { z->e[0] = ZIP_ER_READ; z->e[1] = errno; @@ -172,26 +193,29 @@ if (len < sizeof(*st)) return -1; - if (z->f) - err = fstat(fileno(z->f), &fst); - else - err = stat(z->fname, &fst); + if (z->st.size != -1) + memcpy(st, &z->st, sizeof(st)); + else { + if (z->f) + err = fstat(fileno(z->f), &fst); + else + err = stat(z->fname, &fst); - if (err != 0) { - z->e[0] = ZIP_ER_READ; /* best match */ - z->e[1] = errno; - return -1; + if (err != 0) { + z->e[0] = ZIP_ER_READ; /* best match */ + z->e[1] = errno; + return -1; + } + + st = (struct zip_stat *)data; + + zip_stat_init(st); + st->mtime = fst.st_mtime; + if (z->len != -1) + st->size = z->len; + else if ((fst.st_mode&S_IFMT) == S_IFREG) + st->size = fst.st_size; } - - st = (struct zip_stat *)data; - - zip_stat_init(st); - st->mtime = fst.st_mtime; - if (z->len != -1) - st->size = z->len; - else if ((fst.st_mode&S_IFMT) == S_IFREG) - st->size = fst.st_size; - return sizeof(*st); } @@ -204,7 +228,7 @@ case ZIP_SOURCE_FREE: free(z->fname); - if (z->f) + if (z->closep && z->f) fclose(z->f); free(z); return 0;
diff --git a/lib/zip_source_pkware.c b/lib/zip_source_pkware.c new file mode 100644 index 0000000..136f08c --- /dev/null +++ b/lib/zip_source_pkware.c
@@ -0,0 +1,223 @@ +/* + zip_source_pkware.c -- Traditional PKWARE de/encryption routines + Copyright (C) 2009 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 trad_pkware { + struct zip_source *src; + int e[2]; + + zip_uint32_t key[3]; +}; + +#define HEADERLEN 12 +#define KEY0 305419896 +#define KEY1 591751049 +#define KEY2 878082192 + + + +static void decrypt(struct trad_pkware *, zip_uint8_t *, + const zip_uint8_t *, size_t); +static int decrypt_header(struct trad_pkware *); +static ssize_t pkware_decrypt(void *, void *, size_t, enum zip_source_cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_pkware(struct zip *za, struct zip_source *src, + zip_uint16_t em, int flags, const char *password) +{ + struct trad_pkware *ctx; + + if (za == NULL || password == NULL || src == NULL + || em != ZIP_EM_TRAD_PKWARE || (flags & ZIP_CODEC_ENCODE) == 0) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((ctx=(struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + ctx->src = src; + ctx->e[0] = ctx->e[1] = 0; + + ctx->key[0] = KEY0; + ctx->key[1] = KEY1; + ctx->key[2] = KEY2; + decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password)); + + return zip_source_function(za, pkware_decrypt, ctx); +} + + + +static void +decrypt(struct trad_pkware *ctx, zip_uint8_t *out, const zip_uint8_t *in, + size_t len) +{ + zip_uint16_t clr; + size_t i; + Bytef b; + + for (i=0; i<len; i++) { + /* decrypt next byte */ + clr = ctx->key[2] || 2; + clr = (clr * (clr ^ 1)) >> 8; + clr = in[i] ^ clr; + + /* update keys */ + b = clr; + ctx->key[0] = crc32(ctx->key[0], &b, 1); + ctx->key[1] = (ctx->key[1] + (ctx->key[0] & 0xff)) * 134775813 + 1; + b = ctx->key[1] >> 24; + ctx->key[2] = crc32(ctx->key[2], &b, 1); + + /* store cleartext */ + if (out) + out[i] = clr; + } +} + + + +static int +decrypt_header(struct trad_pkware *ctx) +{ + zip_uint8_t header[HEADERLEN]; + struct zip_stat st; + ssize_t n; + + if ((n=zip_source_call(ctx->src, header, HEADERLEN, ZIP_SOURCE_READ)) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + + if (n != HEADERLEN) { + ctx->e[0] = ZIP_ER_EOF; + ctx->e[1] = 0; + return -1; + } + + decrypt(ctx, header, header, HEADERLEN); + + if (zip_source_call(ctx->src, &st, sizeof(st), ZIP_SOURCE_STAT) < 0 + || st.crc == 0) { + /* no CRC available, skip password validataion */ + return 0; + } + + if (header[HEADERLEN-1] != st.crc>>24) { + ctx->e[0] = ZIP_ER_WRONGPASSWD; + ctx->e[1] = 0; + } + + return 0; +} + + + +static ssize_t +pkware_decrypt(void *ud, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct trad_pkware *ctx; + ssize_t n; + + ctx = (struct trad_pkware *)ud; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + if (decrypt_header(ctx) < 0) + return -1; + return 0; + + case ZIP_SOURCE_READ: + if ((n=zip_source_call(ctx->src, data, len, cmd)) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + decrypt(ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (size_t)n); + return n; + + case ZIP_SOURCE_CLOSE: + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + return 0; + + case ZIP_SOURCE_STAT: + if (zip_source_call(ctx->src, data, len, cmd) < 0) { + zip_source_call(ctx->src, ctx->e, sizeof(ctx->e), ZIP_SOURCE_ERROR); + return -1; + } + else { + struct zip_stat *st; + + st = (struct zip_stat *)data; + + st->encryption_method = ZIP_EM_NONE; + if (st->comp_size > 0) + st->comp_size -= HEADERLEN; + } + return 0; + + case ZIP_SOURCE_ERROR: + if (len < sizeof(int)*2) + return -1; + + memcpy(data, ctx->e, sizeof(int)*2); + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + zip_source_call(ctx->src, data, len, cmd); + free(ud); + return 0; + + default: + ctx->e[0] = ZIP_ER_INVAL; + ctx->e[1] = 0; + return -1; + } +}
diff --git a/lib/zipint.h b/lib/zipint.h index 9f17dff..a047bcd 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -91,8 +91,7 @@ /* constants for struct zip_file's member flags */ #define ZIP_ZF_EOF 1 /* EOF reached */ -#define ZIP_ZF_DECOMP 2 /* decompress data */ -#define ZIP_ZF_CRC 4 /* compute and compare CRC */ +#define ZIP_ZF_CRC 2 /* compute and compare CRC */ /* directory entry: general purpose bit flags */ @@ -118,6 +117,8 @@ unsigned int flags; /* archive global flags */ unsigned int ch_flags; /* changed archive global flags */ + char *default_password; /* password used when no other supplied */ + struct zip_cdir *cdir; /* central directory */ char *ch_comment; /* changed archive comment */ int ch_comment_len; /* length of changed zip archive @@ -137,16 +138,11 @@ struct zip_error error; /* error information */ int flags; /* -1: eof, >0: error */ - int method; /* compression method */ - off_t fpos; /* position within zip file (fread/fwrite) */ unsigned long bytes_left; /* number of bytes left to read */ - unsigned long cbytes_left; /* number of bytes of compressed data left */ - unsigned long crc; /* CRC so far */ unsigned long crc_orig; /* CRC recorded in archive */ - - char *buffer; - z_stream *zstr; + + struct zip_source *src; /* data source */ }; /* zip archive directory entry (central or local) */ @@ -187,6 +183,7 @@ struct zip_source { + struct zip_source *src; zip_source_callback f; void *ud; }; @@ -249,7 +246,8 @@ struct zip *_zip_open(const char *, FILE *, int, int, int *); struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, - zip_uint64_t, zip_int64_t); + zip_uint64_t, zip_int64_t, int, + const struct zip_stat *); int _zip_changed(struct zip *, int *); void _zip_free(struct zip *);
diff --git a/regress/fread.c b/regress/fread.c index 2be14b2..8417170 100644 --- a/regress/fread.c +++ b/regress/fread.c
@@ -152,11 +152,14 @@ if (when_got != when_ex || ze_got != ze_ex || se_got != se_ex) { zip_error_to_str(expected, sizeof(expected), ze_ex, se_ex); zip_error_to_str(got, sizeof(got), ze_got, se_got); - printf("%s: got %s error (%s), expected %s error (%s)\n", prg, + printf("%s: %s: got %s error (%s), expected %s error (%s)\n", + prg, name, when_name[when_got], got, when_name[when_ex], expected); return 1; } + else if (getenv("VERBOSE")) + printf("%s: %s: passed\n", prg, name); return 0; }