zip_source rototil checkpoint commit -- XXX does not work yet - Add functions for each command, use these exclusively. - Put logic for layered sources into these functions. - New constructor for layered sources, and new callback signature. - Use sources for compression in zip_close. - zip_source_crc can now validate, returning error on EOF for crc/size mismatch. Known bugs: - deflate uncompressing resulst in zlib data error. - deflate compressing gets in tight loop on EOF --HG-- branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am index 7aa49ad..f4f6d65 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am
@@ -55,14 +55,20 @@ zip_set_default_password.c \ zip_set_file_comment.c \ zip_source_buffer.c \ - zip_source_call.c \ + zip_source_close.c \ zip_source_crc.c \ zip_source_deflate.c \ + zip_source_error.c \ zip_source_file.c \ zip_source_filep.c \ zip_source_free.c \ zip_source_function.c \ + zip_source_layered.c \ + zip_source_open.c \ zip_source_pkware.c \ + zip_source_pop.c \ + zip_source_read.c \ + zip_source_stat.c \ zip_source_zip.c \ zip_set_name.c \ zip_stat.c \
diff --git a/lib/zip.h b/lib/zip.h index 9a44fdf..4863e22 100644 --- a/lib/zip.h +++ b/lib/zip.h
@@ -168,9 +168,11 @@ ZIP_SOURCE_CLOSE, /* reading is done */ ZIP_SOURCE_STAT, /* get meta information */ ZIP_SOURCE_ERROR, /* get error information */ - ZIP_SOURCE_FREE /* cleanup and free resources */ + ZIP_SOURCE_FREE, /* cleanup and free resources */ }; +#define ZIP_SOURCE_ERR_LOWER -2 + #define ZIP_STAT_NAME 0x0001 #define ZIP_STAT_INDEX 0x0002 #define ZIP_STAT_SIZE 0x0004 @@ -198,6 +200,9 @@ typedef zip_int64_t (*zip_source_callback)(void *, void *, zip_uint64_t, enum zip_source_cmd); +typedef zip_int64_t (*zip_source_layered_callback)(struct zip_source *, void *, + void *, zip_uint64_t, + enum zip_source_cmd); typedef struct zip_source *(*zip_compression_implementation)(struct zip *, struct zip_source *, zip_uint16_t, int); @@ -250,12 +255,13 @@ const char *, int); ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, zip_uint64_t, int); -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *, void *, - zip_uint64_t, enum zip_source_cmd); -ZIP_EXTERN struct zip_source *zip_source_crc(struct zip *, struct zip_source *); +ZIP_EXTERN int zip_source_close(struct zip_source *); +ZIP_EXTERN struct zip_source *zip_source_crc(struct zip *, struct zip_source *, + int); ZIP_EXTERN struct zip_source *zip_source_deflate(struct zip *, struct zip_source *, zip_uint16_t, int); +ZIP_EXTERN void zip_source_error(struct zip_source *, int *, 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 *, @@ -263,10 +269,19 @@ 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_layered(struct zip *, + struct zip_source *, + zip_source_layered_callback, + void *); +ZIP_EXTERN int zip_source_open(struct zip_source *); 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_pop(struct zip_source *); +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_zip(struct zip *, struct zip *, zip_uint64_t, int, zip_uint64_t, zip_int64_t);
diff --git a/lib/zip_close.c b/lib/zip_close.c index 5b45623..f6474b9 100644 --- a/lib/zip_close.c +++ b/lib/zip_close.c
@@ -44,12 +44,9 @@ static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, FILE *); -static int add_data_comp(struct zip_source *, struct zip_stat *, - FILE *, struct zip_error *); -static int add_data_uncomp(struct zip *, struct zip_source *, - struct zip_stat *, FILE *); -static void ch_set_error(struct zip_error *, struct zip_source *); static int copy_data(FILE *, off_t, FILE *, struct zip_error *); +static int copy_source(struct zip *, struct zip_source *, struct zip_stat *, + FILE *); static int write_cdir(struct zip *, struct zip_cdir *, FILE *); static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); static char *_zip_create_temp_output(struct zip *, FILE **); @@ -237,8 +234,13 @@ if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { error = 1; + if (zs) + zip_source_free(zs); break; } + if (zs) + zip_source_free(zs); + cd->entry[j].last_mod = de.last_mod; cd->entry[j].comp_method = de.comp_method; cd->entry[j].comp_size = de.comp_size; @@ -318,15 +320,12 @@ { off_t offstart, offend; struct zip_stat st; + struct zip_source *s2; + zip_compression_implementation comp_impl; + int ret; - if (zip_source_call(src, &st, sizeof(st), - ZIP_SOURCE_STAT) < (zip_int64_t)sizeof(st)) { - ch_set_error(&za->error, src); - return -1; - } - - if (zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { - ch_set_error(&za->error, src); + if (zip_source_stat(src, &st) < 0) { + _zip_error_set_from_source(&za->error, src); return -1; } @@ -335,19 +334,39 @@ if (_zip_dirent_write(de, ft, 1, &za->error) < 0) return -1; - if (st.comp_method != ZIP_CM_STORE) { - if (add_data_comp(src, &st, ft, &za->error) < 0) + /* XXX: deflate 0-byte files for torrentzip? */ + if (((st.valid & ZIP_STAT_COMP_METHOD) == 0 + || st.comp_method == ZIP_CM_STORE) + && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { + comp_impl = NULL; + if ((comp_impl=zip_get_compression_implementation(ZIP_CM_DEFLATE)) + == NULL) { + _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return -1; + } + if ((s2=comp_impl(za, src, ZIP_CM_DEFLATE, ZIP_CODEC_ENCODE)) + == NULL) { + /* XXX: set error? */ + zip_source_free(src); + return -1; + } } - else { - if (add_data_uncomp(za, src, &st, ft) < 0) - return -1; + else + s2 = src; + + ret = copy_source(za, s2, &st, ft); + + while (s2 != src) { + if ((s2=zip_source_pop(s2)) == NULL) { + /* XXX: set erorr */ + ret = -1; + break; + } } - if (zip_source_call(src, NULL, 0, ZIP_SOURCE_CLOSE) < 0) { - ch_set_error(&za->error, src); + if (ret < 0) return -1; - } + offend = ftello(ft); @@ -380,133 +399,6 @@ static int -add_data_comp(struct zip_source *src, struct zip_stat *st, FILE *ft, - struct zip_error *error) -{ - char buf[BUFSIZE]; - zip_int64_t n; - - st->comp_size = 0; - while ((n=zip_source_call(src, buf, sizeof(buf), ZIP_SOURCE_READ)) > 0) { - if (fwrite(buf, 1, n, ft) != (size_t)n) { - _zip_error_set(error, ZIP_ER_WRITE, errno); - return -1; - } - - st->comp_size += n; - } - if (n < 0) { - ch_set_error(error, src); - return -1; - } - - return 0; -} - - - -static int -add_data_uncomp(struct zip *za, struct zip_source *src, - struct zip_stat *st, FILE *ft) -{ - char b1[BUFSIZE], b2[BUFSIZE]; - int end, flush, ret; - zip_int64_t n; - zip_uint64_t n2; - z_stream zstr; - int mem_level; - - st->comp_method = ZIP_CM_DEFLATE; - st->comp_size = st->size = 0; - st->crc = crc32(0, NULL, 0); - - zstr.zalloc = Z_NULL; - zstr.zfree = Z_NULL; - zstr.opaque = NULL; - zstr.avail_in = 0; - zstr.avail_out = 0; - - if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) - mem_level = TORRENT_MEM_LEVEL; - else - mem_level = MAX_MEM_LEVEL; - - /* -MAX_WBITS: undocumented feature of zlib to _not_ write a zlib header */ - deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, mem_level, - Z_DEFAULT_STRATEGY); - - zstr.next_out = (Bytef *)b2; - zstr.avail_out = sizeof(b2); - zstr.avail_in = 0; - - flush = 0; - end = 0; - while (!end) { - if (zstr.avail_in == 0 && !flush) { - if ((n=zip_source_call(src, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) { - ch_set_error(&za->error, src); - deflateEnd(&zstr); - return -1; - } - if (n > 0) { - zstr.avail_in = n; - zstr.next_in = (Bytef *)b1; - st->size += n; - st->crc = crc32(st->crc, (Bytef *)b1, n); - } - else - flush = Z_FINISH; - } - - ret = deflate(&zstr, flush); - if (ret != Z_OK && ret != Z_STREAM_END) { - _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); - return -1; - } - - if (zstr.avail_out != sizeof(b2)) { - n2 = sizeof(b2) - zstr.avail_out; - - if (fwrite(b2, 1, n2, ft) != n2) { - _zip_error_set(&za->error, ZIP_ER_WRITE, errno); - return -1; - } - - zstr.next_out = (Bytef *)b2; - zstr.avail_out = sizeof(b2); - st->comp_size += n2; - } - - if (ret == Z_STREAM_END) { - deflateEnd(&zstr); - end = 1; - } - } - - return 0; -} - - - -static void -ch_set_error(struct zip_error *error, struct zip_source *src) -{ - int e[2]; - - if ((zip_source_call(src, e, sizeof(e), - ZIP_SOURCE_ERROR)) < (zip_int64_t)sizeof(e)) { - error->zip_err = ZIP_ER_INTERNAL; - error->sys_err = 0; - } - else { - error->zip_err = e[0]; - error->sys_err = e[1]; - } -} - - - -static int copy_data(FILE *fs, off_t len, FILE *ft, struct zip_error *error) { char buf[BUFSIZE]; @@ -540,6 +432,48 @@ static int +copy_source(struct zip *za, struct zip_source *src, struct zip_stat *st, + FILE *ft) +{ + char buf[BUFSIZE]; + zip_int64_t n; + int ret; + + if (zip_source_open(src) < 0) { + _zip_error_set_from_source(&za->error, src); + return -1; + } + + st->comp_size = 0; + ret = 0; + while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { + if (fwrite(buf, 1, n, ft) != (size_t)n) { + _zip_error_set(&za->error, ZIP_ER_WRITE, errno); + ret = -1; + break; + } + + st->comp_size += n; + } + + if (n < 0) { + if (ret == 0) + _zip_error_set_from_source(&za->error, src); + ret = -1; + } + + if (zip_source_close(src) < 0) { + if (ret == 0) + _zip_error_set_from_source(&za->error, src); + ret = -1; + } + + return ret; +} + + + +static int write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) { off_t offset;
diff --git a/lib/zip_error.c b/lib/zip_error.c index 59aeea8..b8d907a 100644 --- a/lib/zip_error.c +++ b/lib/zip_error.c
@@ -1,6 +1,6 @@ /* zip_error.c -- struct zip_error helper functions - 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> @@ -105,8 +105,8 @@ void _zip_error_set_from_source(struct zip_error *err, struct zip_source *src) { - int e[2]; + int ze, se; - zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR); - _zip_error_set(err, e[0], e[1]); + zip_source_error(src, &ze, &se); + _zip_error_set(err, ze, se); }
diff --git a/lib/zip_fopen_index_encrypted.c b/lib/zip_fopen_index_encrypted.c index 142976c..aab8955 100644 --- a/lib/zip_fopen_index_encrypted.c +++ b/lib/zip_fopen_index_encrypted.c
@@ -132,7 +132,7 @@ } if ((flags & ZIP_FL_COMPRESSED) == 0 || st.comp_method == ZIP_CM_STORE ) { - if ((s2=zip_source_crc(za, src)) == NULL) { + if ((s2=zip_source_crc(za, src, 1)) == NULL) { zip_source_free(src); /* XXX: set error (how?) */ return NULL; @@ -141,13 +141,8 @@ } } - if (zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { - int e[2]; - - if (zip_source_call(src, e, sizeof(e), ZIP_SOURCE_ERROR) < 0) - _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); - else - _zip_error_set(&za->error, e[0], e[1]); + if (zip_source_open(src) < 0) { + _zip_error_set_from_source(&za->error, src); zip_source_free(src); return NULL; }
diff --git a/lib/zip_fread.c b/lib/zip_fread.c index aab0097..8235c6d 100644 --- a/lib/zip_fread.c +++ b/lib/zip_fread.c
@@ -56,31 +56,10 @@ if ((zf->eof) || (toread == 0)) return 0; - if ((n=zip_source_call(zf->src, outbuf, toread, ZIP_SOURCE_READ)) < 0) { + if ((n=zip_source_read(zf->src, outbuf, toread)) < 0) { _zip_error_set_from_source(&zf->error, zf->src); return -1; } - if (n == 0) { - struct zip_stat st; - - if (zip_source_call(zf->src, &st, sizeof(st), ZIP_SOURCE_STAT) < 0) { - _zip_error_set_from_source(&zf->error, zf->src); - return -1; - } - - zf->eof = 1; - - if ((st.valid & ZIP_STAT_SIZE) && zf->size != st.size) { - _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); - return -1; - } - - if ((st.valid & ZIP_STAT_CRC) && zf->crc != st.crc) { - _zip_error_set(&zf->error, ZIP_ER_CRC, 0); - return -1; - } - } - return n; }
diff --git a/lib/zip_source_buffer.c b/lib/zip_source_buffer.c index eee9138..af8bf19 100644 --- a/lib/zip_source_buffer.c +++ b/lib/zip_source_buffer.c
@@ -126,9 +126,10 @@ zip_stat_init(st); st->mtime = z->mtime; st->size = z->end - z->data; + st->comp_size = st->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; - st->valid = ZIP_STAT_MTIME|ZIP_STAT_SIZE + st->valid = ZIP_STAT_MTIME|ZIP_STAT_SIZE|ZIP_STAT_COMP_SIZE |ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD; return sizeof(*st);
diff --git a/lib/zip_source_call.c b/lib/zip_source_close.c similarity index 71% copy from lib/zip_source_call.c copy to lib/zip_source_close.c index 0454e0a..a889b97 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_close.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_close.c -- close zip_source (stop reading) Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -37,9 +37,28 @@ -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN int +zip_source_close(struct zip_source *src) { - return src->f(src->ud, data, len, cmd); + int ret; + + /* XXX: Should we even allow ZIP_SOURCE_CLOSE to return an error? */ + + if (src->src == NULL) + return src->cb.f(src->ud, NULL, 0, ZIP_SOURCE_CLOSE); + + ret = src->cb.l(src->src, src->ud, NULL, 0, ZIP_SOURCE_CLOSE); + if (ret < 0) { + if (ret == ZIP_SOURCE_ERR_LOWER) + src->error_source = ZIP_LES_LOWER; + else + src->error_source = ZIP_LES_UPPER; + } + + if (zip_source_close(src->src) < 0) { + src->error_source = ZIP_LES_LOWER; + return -1; + } + + return ret < 0 ? -1 : 0; }
diff --git a/lib/zip_source_crc.c b/lib/zip_source_crc.c index dddd75e..7ffbfea 100644 --- a/lib/zip_source_crc.c +++ b/lib/zip_source_crc.c
@@ -1,5 +1,5 @@ /* - zip_source_crc.c -- pass-through source that calculates CRC32 + zip_source_crc.c -- pass-through source that calculates CRC32 and size Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -39,18 +39,20 @@ #include "zipint.h" struct crc { - struct zip_source *src; int eof; + int validate; + int e[2]; zip_uint64_t size; zip_uint32_t crc; }; -static zip_int64_t crc_read(void *, void *, zip_uint64_t, enum zip_source_cmd); +static zip_int64_t crc_read(struct zip_source *, void *, void * + , zip_uint64_t, enum zip_source_cmd); ZIP_EXTERN struct zip_source * -zip_source_crc(struct zip *za, struct zip_source *src) +zip_source_crc(struct zip *za, struct zip_source *src, int validate) { struct crc *ctx; @@ -64,16 +66,16 @@ return NULL; } - ctx->src = src; + ctx->validate = validate; - - return zip_source_function(za, crc_read, ctx); + return zip_source_layered(za, src, crc_read, ctx); } static zip_int64_t -crc_read(void *_ctx, void *data, zip_uint64_t len, enum zip_source_cmd cmd) +crc_read(struct zip_source *src, void *_ctx, void *data, + zip_uint64_t len, enum zip_source_cmd cmd) { struct crc *ctx; zip_int64_t n; @@ -82,9 +84,6 @@ switch (cmd) { case ZIP_SOURCE_OPEN: - if (zip_source_call(ctx->src, data, len, cmd) < 0) - return -1; - ctx->eof = 0; ctx->crc = crc32(0, NULL, 0); ctx->size = 0; @@ -95,11 +94,31 @@ if (ctx->eof || len == 0) return 0; - if ((n=zip_source_call(ctx->src, data, len, cmd)) < 0) - return -1; + if ((n=zip_source_read(src, data, len)) < 0) + return ZIP_SOURCE_ERR_LOWER; - if (n == 0) + if (n == 0) { ctx->eof = 1; + if (ctx->validate) { + struct zip_stat st; + + if (zip_source_stat(src, &st) < 0) + return ZIP_SOURCE_ERR_LOWER; + + if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { + ctx->e[0] = ZIP_ER_CRC; + ctx->e[1] = 0; + + return -1; + } + if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { + ctx->e[0] = ZIP_ER_INCONS; + ctx->e[1] = 0; + + return -1; + } + } + } else { ctx->size += n; ctx->crc = crc32(ctx->crc, data, n); @@ -107,14 +126,10 @@ return n; case ZIP_SOURCE_CLOSE: - if (zip_source_call(ctx->src, data, len, cmd) < 0) - return -1; return 0; case ZIP_SOURCE_STAT: - if (zip_source_call(ctx->src, data, len, cmd) < 0) - return -1; - else { + { struct zip_stat *st; st = (struct zip_stat *)data; @@ -130,15 +145,15 @@ return 0; case ZIP_SOURCE_ERROR: - return zip_source_call(ctx->src, data, len, cmd); + memcpy(data, ctx->e, sizeof(ctx->e)); + return 0; case ZIP_SOURCE_FREE: - zip_source_call(ctx->src, data, len, cmd); free(ctx); return 0; default: - return zip_source_call(ctx->src, data, len, cmd); + return -1; } }
diff --git a/lib/zip_source_deflate.c b/lib/zip_source_deflate.c index 22db543..e349470 100644 --- a/lib/zip_source_deflate.c +++ b/lib/zip_source_deflate.c
@@ -39,7 +39,6 @@ #include "zipint.h" struct deflate { - struct zip_source *src; int e[2]; int eof; @@ -49,12 +48,15 @@ z_stream zstr; }; -static zip_int64_t compress_read(struct deflate *, void *, zip_uint64_t); -static zip_int64_t decompress_read(struct deflate *, void *, zip_uint64_t); -static zip_int64_t deflate_compress(void *, void *, zip_uint64_t, - enum zip_source_cmd); -static zip_int64_t deflate_decompress(void *, void *, zip_uint64_t, - enum zip_source_cmd); +static zip_int64_t compress_read(struct zip_source *, struct deflate *, + void *, zip_uint64_t); +static zip_int64_t decompress_read(struct zip_source *, struct deflate *, + void *, zip_uint64_t); +static zip_int64_t deflate_compress(struct zip_source *, void *, void *, + zip_uint64_t, enum zip_source_cmd); +static zip_int64_t deflate_decompress(struct zip_source *, void *, void *, + zip_uint64_t, enum zip_source_cmd); +static void deflate_free(struct deflate *); @@ -63,6 +65,7 @@ zip_uint16_t cm, int flags) { struct deflate *ctx; + struct zip_source *s2; if (za == NULL || src == NULL || cm != ZIP_CM_DEFLATE) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); @@ -74,7 +77,6 @@ return NULL; } - ctx->src = src; ctx->e[0] = ctx->e[1] = 0; ctx->eof = 0; if (flags & ZIP_CODEC_ENCODE) { @@ -84,15 +86,22 @@ ctx->mem_level = MAX_MEM_LEVEL; } - return zip_source_function(za, ((flags & ZIP_CODEC_ENCODE) - ? deflate_compress : deflate_decompress), - ctx); + if ((s2=zip_source_layered(za, src, + ((flags & ZIP_CODEC_ENCODE) + ? deflate_compress : deflate_decompress), + ctx)) == NULL) { + deflate_free(ctx); + return NULL; + } + + return s2; } static zip_int64_t -compress_read(struct deflate *ctx, void *data, zip_uint64_t len) +compress_read(struct zip_source *src, struct deflate *ctx, + void *data, zip_uint64_t len) { int end, ret; zip_int64_t n; @@ -128,10 +137,9 @@ 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); + if ((n=zip_source_read(src, ctx->buffer, + sizeof(ctx->buffer))) < 0) { + zip_source_error(src, ctx->e, ctx->e+1); end = 1; break; } @@ -168,7 +176,8 @@ static zip_int64_t -decompress_read(struct deflate *ctx, void *data, zip_uint64_t len) +decompress_read(struct zip_source *src, struct deflate *ctx, + void *data, zip_uint64_t len) { int end, ret; zip_int64_t n; @@ -197,10 +206,9 @@ 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); + if ((n=zip_source_read(src, ctx->buffer, + sizeof(ctx->buffer))) < 0) { + zip_source_error(src, ctx->e, ctx->e+1); end = 1; break; } @@ -233,8 +241,8 @@ static zip_int64_t -deflate_compress(void *ud, void *data, zip_uint64_t len, - enum zip_source_cmd cmd) +deflate_compress(struct zip_source *src, void *ud, void *data, + zip_uint64_t len, enum zip_source_cmd cmd) { struct deflate *ctx; int ret; @@ -243,7 +251,6 @@ switch (cmd) { case ZIP_SOURCE_OPEN: - ctx->zstr.zalloc = Z_NULL; ctx->zstr.zfree = Z_NULL; ctx->zstr.opaque = NULL; @@ -257,33 +264,19 @@ 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); + return compress_read(src, 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; @@ -300,16 +293,11 @@ 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); + deflate_free(ctx); return 0; default: @@ -317,14 +305,13 @@ ctx->e[1] = 0; return -1; } - } static zip_int64_t -deflate_decompress(void *ud, void *data, zip_uint64_t len, - enum zip_source_cmd cmd) +deflate_decompress(struct zip_source *src, void *ud, void *data, + zip_uint64_t len, enum zip_source_cmd cmd) { struct deflate *ctx; zip_int64_t n; @@ -334,17 +321,6 @@ 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; @@ -356,29 +332,19 @@ 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); + return decompress_read(src, 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; @@ -398,7 +364,6 @@ case ZIP_SOURCE_FREE: /* XXX: inflateEnd if close was not called */ - zip_source_call(ctx->src, data, len, cmd); free(ctx); return 0; @@ -409,3 +374,12 @@ } } + + + +static void +deflate_free(struct deflate *ctx) +{ + /* XXX: deflateEnd if close was not called */ + free(ctx); +}
diff --git a/lib/zip_source_call.c b/lib/zip_source_error.c similarity index 65% copy from lib/zip_source_call.c copy to lib/zip_source_error.c index 0454e0a..db9265f 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_error.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_error.c -- get last error from zip_source Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -37,9 +37,50 @@ -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN void +zip_source_error(struct zip_source *src, int *ze, int *se) { - return src->f(src->ud, data, len, cmd); + int e[2]; + + if (src->src == NULL) { + } + else { + switch (src->error_source) { + case ZIP_LES_NONE: + if (src->src == NULL) { + if (src->cb.f(src->ud, e, sizeof(e), ZIP_SOURCE_ERROR) < 0) { + e[0] = ZIP_ER_INTERNAL; + e[1] = 0; + } + } + else + e[0] = e[1] = 0; + break; + + case ZIP_LES_INVAL: + e[0] = ZIP_ER_INVAL; + e[1] = 0; + break; + + case ZIP_LES_LOWER: + return zip_source_error(src->src, ze, se); + + case ZIP_LES_UPPER: + if (src->cb.l(src->src, src->ud, e, sizeof(e), + ZIP_SOURCE_ERROR) < 0) { + e[0] = ZIP_ER_INTERNAL; + e[1] = 0; + } + break; + + default: + e[0] = ZIP_ER_INTERNAL; + e[1] = 0; + } + } + + if (ze) + *ze = e[0]; + if (se) + *se = e[1]; }
diff --git a/lib/zip_source_free.c b/lib/zip_source_free.c index 7a1632f..1e6ffe1 100644 --- a/lib/zip_source_free.c +++ b/lib/zip_source_free.c
@@ -1,6 +1,6 @@ /* zip_source_free.c -- free zip data source - 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> @@ -40,12 +40,17 @@ ZIP_EXTERN void -zip_source_free(struct zip_source *source) +zip_source_free(struct zip_source *src) { - if (source == NULL) + if (src == NULL) return; - (void)source->f(source->ud, NULL, 0, ZIP_SOURCE_FREE); + if (src->src) { + (void)src->cb.l(src->src, src->ud, NULL, 0, ZIP_SOURCE_FREE); + zip_source_free(src->src); + } + else + (void)src->cb.f(src->ud, NULL, 0, ZIP_SOURCE_FREE); - free(source); + free(src); }
diff --git a/lib/zip_source_function.c b/lib/zip_source_function.c index 91b183c..0e75686 100644 --- a/lib/zip_source_function.c +++ b/lib/zip_source_function.c
@@ -1,6 +1,6 @@ /* zip_source_function.c -- create zip data source from callback function - 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> @@ -52,7 +52,8 @@ return NULL; } - zs->f = zcb; + zs->src = NULL; + zs->cb.f = zcb; zs->ud = ud; return zs;
diff --git a/lib/zip_source_call.c b/lib/zip_source_layered.c similarity index 75% copy from lib/zip_source_call.c copy to lib/zip_source_layered.c index 0454e0a..433c77a 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_layered.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_layered.c -- create layered source Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -33,13 +33,30 @@ +#include <stdlib.h> + #include "zipint.h" -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN struct zip_source * +zip_source_layered(struct zip *za, struct zip_source *src, + zip_source_layered_callback cb, void *ud) { - return src->f(src->ud, data, len, cmd); + struct zip_source *zs; + + if (za == NULL) + return NULL; + + if ((zs=(struct zip_source *)malloc(sizeof(*zs))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + zs->src = src; + zs->cb.l = cb; + zs->ud = ud; + zs->error_source = ZIP_LES_NONE; + + return zs; }
diff --git a/lib/zip_source_call.c b/lib/zip_source_open.c similarity index 72% copy from lib/zip_source_call.c copy to lib/zip_source_open.c index 0454e0a..9923bda 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_open.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_open.c -- open zip_source (prepare for reading) Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -37,9 +37,30 @@ -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN int +zip_source_open(struct zip_source *src) { - return src->f(src->ud, data, len, cmd); + zip_int64_t ret; + + if (src->src == NULL) + return src->cb.f(src->ud, NULL, 0, ZIP_SOURCE_OPEN); + + if (zip_source_open(src->src) < 0) { + src->error_source = ZIP_LES_LOWER; + return -1; + } + + ret = src->cb.l(src->src, src->ud, NULL, 0, ZIP_SOURCE_OPEN); + + if (ret < 0) { + (void)zip_source_close(src->src); + + if (ret == ZIP_SOURCE_ERR_LOWER) + src->error_source = ZIP_LES_LOWER; + else + src->error_source = ZIP_LES_UPPER; + return -1; + } + + return 0; }
diff --git a/lib/zip_source_pkware.c b/lib/zip_source_pkware.c index 36424cd..c7736a9 100644 --- a/lib/zip_source_pkware.c +++ b/lib/zip_source_pkware.c
@@ -39,7 +39,6 @@ #include "zipint.h" struct trad_pkware { - struct zip_source *src; int e[2]; zip_uint32_t key[3]; @@ -58,8 +57,10 @@ static void decrypt(struct trad_pkware *, zip_uint8_t *, const zip_uint8_t *, zip_uint64_t, int); -static int decrypt_header(struct trad_pkware *); -static zip_int64_t pkware_decrypt(void *, void *, zip_uint64_t, enum zip_source_cmd); +static int decrypt_header(struct zip_source *, struct trad_pkware *); +static zip_int64_t pkware_decrypt(struct zip_source *, void *, void *, + zip_uint64_t, enum zip_source_cmd); +static void pkware_free(struct trad_pkware *); @@ -68,6 +69,7 @@ zip_uint16_t em, int flags, const char *password) { struct trad_pkware *ctx; + struct zip_source *s2; if (za == NULL || password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) { @@ -87,7 +89,6 @@ return NULL; } - ctx->src = src; ctx->e[0] = ctx->e[1] = 0; ctx->key[0] = KEY0; @@ -95,7 +96,12 @@ ctx->key[2] = KEY2; decrypt(ctx, NULL, (const zip_uint8_t *)password, strlen(password), 1); - return zip_source_function(za, pkware_decrypt, ctx); + if ((s2=zip_source_layered(za, src, pkware_decrypt, ctx)) == NULL) { + pkware_free(ctx); + return NULL; + } + + return s2; } @@ -133,15 +139,15 @@ static int -decrypt_header(struct trad_pkware *ctx) +decrypt_header(struct zip_source *src, struct trad_pkware *ctx) { zip_uint8_t header[HEADERLEN]; struct zip_stat st; zip_int64_t n; unsigned short dostime, dosdate; - 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); + if ((n=zip_source_read(src, header, HEADERLEN)) < 0) { + zip_source_error(src, ctx->e, ctx->e+1); return -1; } @@ -153,9 +159,8 @@ decrypt(ctx, header, header, HEADERLEN, 0); - if (zip_source_call(ctx->src, &st, sizeof(st), ZIP_SOURCE_STAT) < 0) { + if (zip_source_stat(src, &st) < 0) { /* stat failed, skip password validation */ - return 0; } @@ -174,7 +179,8 @@ static zip_int64_t -pkware_decrypt(void *ud, void *data, zip_uint64_t len, enum zip_source_cmd cmd) +pkware_decrypt(struct zip_source *src, void *ud, void *data, + zip_uint64_t len, enum zip_source_cmd cmd) { struct trad_pkware *ctx; zip_int64_t n; @@ -183,57 +189,41 @@ 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) + if (decrypt_header(src, 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; - } + if ((n=zip_source_read(src, data, len)) < 0) + return ZIP_SOURCE_ERR_LOWER; + decrypt(ud, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n, 0); 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; st->valid |= ZIP_STAT_ENCRYPTION_METHOD; + /* XXX: deduce HEADERLEN from size for uncompressed */ if (st->valid & ZIP_STAT_COMP_SIZE) 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); + pkware_free(ctx); return 0; default: @@ -242,3 +232,11 @@ return -1; } } + + + +static void +pkware_free(struct trad_pkware *ctx) +{ + free(ctx); +}
diff --git a/lib/zip_source_call.c b/lib/zip_source_pop.c similarity index 82% rename from lib/zip_source_call.c rename to lib/zip_source_pop.c index 0454e0a..7352251 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_pop.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_pop.c -- pop top layer from zip data source Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -33,13 +33,25 @@ +#include <stdlib.h> + #include "zipint.h" -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN struct zip_source * +zip_source_pop(struct zip_source *src) { - return src->f(src->ud, data, len, cmd); + struct zip_source *lower; + + if (src == NULL) + return NULL; + + lower = src->src; + + (void)src->cb.f(src->ud, NULL, 0, ZIP_SOURCE_FREE); + + free(src); + + return lower; }
diff --git a/lib/zip_source_call.c b/lib/zip_source_read.c similarity index 72% copy from lib/zip_source_call.c copy to lib/zip_source_read.c index 0454e0a..ef7147d 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_read.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_read.c -- read data from zip_source Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -37,9 +37,28 @@ -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN zip_int64_t +zip_source_read(struct zip_source *src, void *data, zip_uint64_t len) { - return src->f(src->ud, data, len, cmd); + zip_int64_t ret; + + if (len > ZIP_INT64_MAX || (len > 0 && data == NULL)) { + src->error_source = ZIP_LES_INVAL; + return -1; + } + + if (src->src == NULL) + return src->cb.f(src->ud, data, len, ZIP_SOURCE_READ); + + ret = src->cb.l(src->src, src->ud, data, len, ZIP_SOURCE_READ); + + if (ret < 0) { + if (ret == ZIP_SOURCE_ERR_LOWER) + src->error_source = ZIP_LES_LOWER; + else + src->error_source = ZIP_LES_UPPER; + return -1; + } + + return ret; }
diff --git a/lib/zip_source_call.c b/lib/zip_source_stat.c similarity index 69% copy from lib/zip_source_call.c copy to lib/zip_source_stat.c index 0454e0a..2166074 100644 --- a/lib/zip_source_call.c +++ b/lib/zip_source_stat.c
@@ -1,5 +1,5 @@ /* - zip_source_deflate.c -- deflate (de)compressoin routines + zip_source_stat.c -- get meta information from zip_source Copyright (C) 2009 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. @@ -37,9 +37,36 @@ -ZIP_EXTERN zip_int64_t zip_source_call(struct zip_source *src, void *data, - zip_uint64_t len, - enum zip_source_cmd cmd) +ZIP_EXTERN int +zip_source_stat(struct zip_source *src, struct zip_stat *st) { - return src->f(src->ud, data, len, cmd); + zip_int64_t ret; + + if (st == NULL) { + src->error_source = ZIP_LES_INVAL; + return -1; + } + + if (src->src == NULL) { + if (src->cb.f(src->ud, st, sizeof(*st), ZIP_SOURCE_STAT) < 0) + return -1; + return 0; + } + + if (zip_source_stat(src->src, st) < 0) { + src->error_source = ZIP_LES_LOWER; + return -1; + } + + ret = src->cb.l(src->src, src->ud, st, sizeof(*st), ZIP_SOURCE_STAT); + + if (ret < 0) { + if (ret == ZIP_SOURCE_ERR_LOWER) + src->error_source = ZIP_LES_LOWER; + else + src->error_source = ZIP_LES_UPPER; + return -1; + } + + return 0; }
diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c index e4d84a2..0e15b55 100644 --- a/lib/zip_stat_index.c +++ b/lib/zip_stat_index.c
@@ -54,8 +54,7 @@ if ((flags & ZIP_FL_UNCHANGED) == 0 && ZIP_ENTRY_DATA_CHANGED(za->entry+index)) { - if (zip_source_call(za->entry[index].source, - st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { + if (zip_source_stat(za->entry[index].source, st) < 0) { _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); return -1; }
diff --git a/lib/zip_unchange_data.c b/lib/zip_unchange_data.c index 0249ba5..431f2d0 100644 --- a/lib/zip_unchange_data.c +++ b/lib/zip_unchange_data.c
@@ -41,8 +41,7 @@ _zip_unchange_data(struct zip_entry *ze) { if (ze->source) { - (void)ze->source->f(ze->source->ud, NULL, 0, ZIP_SOURCE_FREE); - free(ze->source); + zip_source_free(ze->source); ze->source = NULL; }
diff --git a/lib/zipint.h b/lib/zipint.h index decd334..a5363db 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -88,10 +88,9 @@ enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED, ZIP_ST_ADDED, ZIP_ST_RENAMED }; -/* constants for struct zip_file's member flags */ +/* error source for layered sources */ -#define ZIP_ZF_EOF 1 /* EOF reached */ -#define ZIP_ZF_CRC 2 /* compute and compare CRC */ +enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL }; /* directory entry: general purpose bit flags */ @@ -183,8 +182,12 @@ struct zip_source { struct zip_source *src; - zip_source_callback f; + union { + zip_source_callback f; + zip_source_layered_callback l; + } cb; void *ud; + enum zip_les error_source; }; /* entry in zip archive directory */