--- embedaddon/php/ext/zip/lib/zip_close.c 2012/02/21 23:48:05 1.1.1.1 +++ embedaddon/php/ext/zip/lib/zip_close.c 2013/07/22 01:32:11 1.1.1.2 @@ -1,6 +1,6 @@ /* zip_close.c -- close zip archive and update changes - Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at @@ -33,26 +33,28 @@ +#include "zipint.h" + #include #include #include #include +#ifdef HAVE_UNISTD_H +#include +#endif #include #include +#ifdef PHP_WIN32 +#include +#include +#endif -#include "zipint.h" - static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, FILE *); -static int add_data_comp(zip_source_callback, void *, struct zip_stat *, - FILE *, struct zip_error *); -static int add_data_uncomp(struct zip *, zip_source_callback, void *, - struct zip_stat *, FILE *); -static void ch_set_error(struct zip_error *, zip_source_callback, void *); static int copy_data(FILE *, off_t, FILE *, struct zip_error *); +static int copy_source(struct zip *, struct zip_source *, FILE *); static int write_cdir(struct zip *, struct zip_cdir *, FILE *); static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); -static int _zip_changed(struct zip *, int *); static char *_zip_create_temp_output(struct zip *, FILE **); static int _zip_torrentzip_cmp(const void *, const void *); @@ -72,7 +74,9 @@ zip_close(struct zip *za) int i, j, error; char *temp; FILE *out; +#ifndef PHP_WIN32 mode_t mask; +#endif struct zip_cdir *cd; struct zip_dirent de; struct filelist *filelist; @@ -99,7 +103,7 @@ zip_close(struct zip *za) } _zip_free(za); return 0; - } + } if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) == NULL) @@ -126,12 +130,12 @@ zip_close(struct zip *za) cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; } else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { - if (_zip_cdir_set_comment(cd, za) == -1) { - _zip_cdir_free(cd); + if (_zip_cdir_set_comment(cd, za) == -1) { + _zip_cdir_free(cd); free(filelist); - return -1; + return -1; + } } - } if ((temp=_zip_create_temp_output(za, &out)) == NULL) { _zip_cdir_free(cd); @@ -160,9 +164,10 @@ zip_close(struct zip *za) for (j=0; jentry+i) || new_torrentzip) { - _zip_dirent_init(&de); if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) _zip_dirent_torrent_normalize(&de); @@ -188,7 +193,7 @@ zip_close(struct zip *za) } else { /* copy existing directory entries */ - if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) { + if ((NULL == za->zp) || (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0)) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); error = 1; break; @@ -198,8 +203,7 @@ zip_close(struct zip *za) error = 1; break; } - memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); - + memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { de.crc = za->cdir->entry[i].crc; de.comp_size = za->cdir->entry[i].comp_size; @@ -220,6 +224,22 @@ zip_close(struct zip *za) cd->entry[j].filename_len = de.filename_len; } + if (za->entry[i].ch_extra_len != -1) { + free(de.extrafield); + if ((de.extrafield=malloc(za->entry[i].ch_extra_len)) == NULL) { + error = 1; + break; + } + memcpy(de.extrafield, za->entry[i].ch_extra, za->entry[i].ch_extra_len); + de.extrafield_len = za->entry[i].ch_extra_len; + /* as the rest of cd entries, its malloc/free is done by za */ + /* TODO unsure if this should also be set in the CD -- + * not done for now + cd->entry[j].extrafield = za->entry[i].ch_extra; + cd->entry[j].extrafield_len = za->entry[i].ch_extra_len; + */ + } + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 && za->entry[i].ch_comment_len != -1) { /* as the rest of cd entries, its malloc/free is done by za */ @@ -234,16 +254,22 @@ zip_close(struct zip *za) zs = NULL; if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { - if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) == NULL) { - error = 1; - break; - } + if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) + == NULL) { + error = 1; + break; + } } 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; @@ -291,27 +317,27 @@ zip_close(struct zip *za) free(temp); return -1; } - - if (za->zp) { - fclose(za->zp); - za->zp = NULL; - reopen_on_error = 1; + + if (za->zp) { + fclose(za->zp); + za->zp = NULL; + reopen_on_error = 1; } if (_zip_rename(temp, za->zn) != 0) { - _zip_error_set(&za->error, ZIP_ER_RENAME, errno); - remove(temp); - free(temp); - if (reopen_on_error) { - /* ignore errors, since we're already in an error case */ - za->zp = fopen(za->zn, "rb"); - } - return -1; + _zip_error_set(&za->error, ZIP_ER_RENAME, errno); + remove(temp); + free(temp); + if (reopen_on_error) { + /* ignore errors, since we're already in an error case */ + za->zp = fopen(za->zn, "rb"); } + return -1; + } +#ifndef PHP_WIN32 mask = umask(0); umask(mask); chmod(za->zn, 0666&~mask); - if (za->ch_comment) - free(za->ch_comment); +#endif _zip_free(za); free(temp); @@ -322,45 +348,69 @@ zip_close(struct zip *za) static int -add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft) +add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, + FILE *ft) { - off_t offstart, offend; - zip_source_callback cb; - void *ud; + off_t offstart, offdata, offend; struct zip_stat st; - - cb = zs->f; - ud = zs->ud; - - if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) { - ch_set_error(&za->error, cb, ud); + struct zip_source *s2; + zip_compression_implementation comp_impl; + int ret; + + if (zip_source_stat(src, &st) < 0) { + _zip_error_set_from_source(&za->error, src); return -1; } - if (cb(ud, NULL, 0, ZIP_SOURCE_OPEN) < 0) { - ch_set_error(&za->error, cb, ud); - return -1; - } - offstart = ftello(ft); if (_zip_dirent_write(de, ft, 1, &za->error) < 0) return -1; - if (st.comp_method != ZIP_CM_STORE) { - if (add_data_comp(cb, ud, &st, ft, &za->error) < 0) - return -1; + if ((s2=zip_source_crc(za, src, 0)) == NULL) { + zip_source_pop(s2); + return -1; } - else { - if (add_data_uncomp(za, cb, ud, &st, ft) < 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); + zip_source_pop(s2); return -1; + } + if ((s2=comp_impl(za, s2, ZIP_CM_DEFLATE, ZIP_CODEC_ENCODE)) + == NULL) { + /* XXX: set error? */ + zip_source_pop(s2); + return -1; + } } + else + s2 = src; - if (cb(ud, NULL, 0, ZIP_SOURCE_CLOSE) < 0) { - ch_set_error(&za->error, cb, ud); - return -1; + offdata = ftello(ft); + + ret = copy_source(za, s2, ft); + + if (zip_source_stat(s2, &st) < 0) + ret = -1; + + while (s2 != src) { + if ((s2=zip_source_pop(s2)) == NULL) { + /* XXX: set erorr */ + ret = -1; + break; + } } + if (ret < 0) + return -1; + offend = ftello(ft); if (fseeko(ft, offstart, SEEK_SET) < 0) { @@ -368,19 +418,18 @@ add_data(struct zip *za, struct zip_source *zs, struct return -1; } - de->last_mod = st.mtime; de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; - de->comp_size = st.comp_size; + de->comp_size = offend - offdata; if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) _zip_dirent_torrent_normalize(de); if (_zip_dirent_write(de, ft, 1, &za->error) < 0) return -1; - + if (fseeko(ft, offend, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; @@ -392,133 +441,6 @@ add_data(struct zip *za, struct zip_source *zs, struct static int -add_data_comp(zip_source_callback cb, void *ud, struct zip_stat *st,FILE *ft, - struct zip_error *error) -{ - char buf[BUFSIZE]; - ssize_t n; - - st->comp_size = 0; - while ((n=cb(ud, 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, cb, ud); - return -1; - } - - return 0; -} - - - -static int -add_data_uncomp(struct zip *za, zip_source_callback cb, void *ud, - struct zip_stat *st, FILE *ft) -{ - char b1[BUFSIZE], b2[BUFSIZE]; - int end, flush, ret; - ssize_t n; - size_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.next_in = NULL; - zstr.avail_in = 0; - - flush = 0; - end = 0; - while (!end) { - if (zstr.avail_in == 0 && !flush) { - if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) { - ch_set_error(&za->error, cb, ud); - 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, zip_source_callback cb, void *ud) -{ - int e[2]; - - if ((cb(ud, e, sizeof(e), ZIP_SOURCE_ERROR)) < (ssize_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]; @@ -552,6 +474,40 @@ copy_data(FILE *fs, off_t len, FILE *ft, struct zip_er static int +copy_source(struct zip *za, struct zip_source *src, 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; + } + + 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; + } + } + + if (n < 0) { + if (ret == 0) + _zip_error_set_from_source(&za->error, src); + ret = -1; + } + + zip_source_close(src); + + return ret; +} + + + +static int write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) { off_t offset; @@ -613,7 +569,7 @@ _zip_cdir_set_comment(struct zip_cdir *dest, struct zi -static int +int _zip_changed(struct zip *za, int *survivorsp) { int changed, i, survivors; @@ -626,13 +582,15 @@ _zip_changed(struct zip *za, int *survivorsp) for (i=0; inentry; i++) { if ((za->entry[i].state != ZIP_ST_UNCHANGED) + || (za->entry[i].ch_extra_len != -1) || (za->entry[i].ch_comment_len != -1)) changed = 1; if (za->entry[i].state != ZIP_ST_DELETED) survivors++; } - *survivorsp = survivors; + if (survivorsp) + *survivorsp = survivors; return changed; } @@ -668,6 +626,10 @@ _zip_create_temp_output(struct zip *za, FILE **outp) return NULL; } #ifdef PHP_WIN32 + /* + According to Pierre Joye, Windows in some environments per + default creates text files, so force binary mode. + */ _setmode(_fileno(tfp), _O_BINARY ); #endif