Mercurial > embed
diff libzip/lib/zip_close.c @ 56:056ee6b5913e
libzip: update to 1.3.0, closes #654
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 10 Oct 2017 20:43:12 +0200 |
parents | 2306f4b04790 |
children |
line wrap: on
line diff
--- a/libzip/lib/zip_close.c Fri Sep 22 14:07:40 2017 +0200 +++ b/libzip/lib/zip_close.c Tue Oct 10 20:43:12 2017 +0200 @@ -1,6 +1,6 @@ /* zip_close.c -- close zip archive and update changes - Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2016 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> @@ -51,15 +51,11 @@ #endif -/* max deflate size increase: size + ceil(size/16k)*5+6 */ -#define MAX_DEFLATE_SIZE_32 4293656963u - static int add_data(zip_t *, zip_source_t *, zip_dirent_t *); static int copy_data(zip_t *, zip_uint64_t); -static int copy_source(zip_t *, zip_source_t *); +static int copy_source(zip_t *, zip_source_t *, zip_int64_t); static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t); - ZIP_EXTERN int zip_close(zip_t *za) { @@ -124,17 +120,20 @@ free(filelist); return -1; } - + + _zip_progress_start(za->progress); error = 0; for (j=0; j<survivors; j++) { int new_data; zip_entry_t *entry; zip_dirent_t *de; + _zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j+1) / (double)survivors); + i = filelist[j].idx; entry = za->entry+i; - new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD)); + new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD)); /* create new local directory entry */ if (entry->changes == NULL) { @@ -222,6 +221,8 @@ return -1; } + _zip_progress_end(za->progress); + zip_discard(za); return 0; @@ -231,13 +232,15 @@ static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) { - zip_int64_t offstart, offdata, offend; + zip_int64_t offstart, offdata, offend, data_length; struct zip_stat st; - zip_source_t *s2; + zip_source_t *src_final, *src_tmp; int ret; int is_zip64; zip_flags_t flags; - + zip_int8_t compression_flags; + bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt; + if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&za->error, src); return -1; @@ -259,95 +262,176 @@ st.valid &= ~ZIP_STAT_COMP_SIZE; } + if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) { + st.valid |= ZIP_STAT_ENCRYPTION_METHOD; + st.encryption_method = ZIP_EM_NONE; + } flags = ZIP_EF_LOCAL; - if ((st.valid & ZIP_STAT_SIZE) == 0) + if ((st.valid & ZIP_STAT_SIZE) == 0) { flags |= ZIP_FL_FORCE_ZIP64; + data_length = -1; + } else { de->uncomp_size = st.size; + /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */ + data_length = (zip_int64_t)st.size; if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) { - if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32) - || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method)))) + zip_uint64_t max_size; + + switch (ZIP_CM_ACTUAL(de->comp_method)) { + case ZIP_CM_BZIP2: + /* computed by looking at increase of 10 random files of size 1MB when + * compressed with bzip2, rounded up: 1.006 */ + max_size = 4269351188u; + break; + + case ZIP_CM_DEFLATE: + /* max deflate size increase: size + ceil(size/16k)*5+6 */ + max_size = 4293656963u; + break; + + case ZIP_CM_STORE: + max_size = 0xffffffffu; + break; + + default: + max_size = 0; + } + + if (st.size > max_size) { flags |= ZIP_FL_FORCE_ZIP64; + } } else de->comp_size = st.comp_size; } if ((offstart = zip_source_tell_write(za->src)) < 0) { + _zip_error_set_from_source(&za->error, za->src); return -1; } /* as long as we don't support non-seekable output, clear data descriptor bit */ de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR; - if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) + if ((is_zip64=_zip_dirent_write(za, de, flags)) < 0) { return -1; + } + needs_recompress = st.comp_method != ZIP_CM_ACTUAL(de->comp_method); + needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE); + needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress; + needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE); - if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) { - zip_source_t *s_store, *s_crc; - zip_compression_implementation comp_impl; + needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method); + needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE); + needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE); + + src_final = src; + zip_source_keep(src_final); + + if (needs_decrypt) { + zip_encryption_implementation impl; - 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 -1; - } - if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) { - /* error set by comp_impl */ - return -1; - } + if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) { + zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); + zip_source_free(src_final); + return -1; } - else { - /* to have the same reference count to src as in the case where it's not stored */ - zip_source_keep(src); - s_store = src; + if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) { + /* error set by impl */ + zip_source_free(src_final); + return -1; } - s_crc = zip_source_crc(za, s_store, 0); - zip_source_free(s_store); - if (s_crc == NULL) { + zip_source_free(src_final); + src_final = src_tmp; + } + + if (needs_decompress) { + if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) { + zip_source_free(src_final); + return -1; + } + + zip_source_free(src_final); + src_final = src_tmp; + } + + if (needs_crc) { + if ((src_tmp = zip_source_crc(za, src_final, 0)) == NULL) { + zip_source_free(src_final); return -1; } - if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { - if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) { - zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); - zip_source_free(s_crc); - return -1; - } - s2 = comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE); - zip_source_free(s_crc); - if (s2 == NULL) { - return -1; - } + zip_source_free(src_final); + src_final = src_tmp; + } + + if (needs_compress) { + if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) { + zip_source_free(src_final); + return -1; } - else { - s2 = s_crc; - } - } - else { - zip_source_keep(src); - s2 = src; + + zip_source_free(src_final); + src_final = src_tmp; } + + if (needs_encrypt) { + zip_encryption_implementation impl; + const char *password = NULL; + + if (de->password) { + password = de->password; + } else if (za->default_password) { + password = za->default_password; + } + + if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) { + zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); + zip_source_free(src_final); + return -1; + } + if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) { + /* error set by impl */ + zip_source_free(src_final); + return -1; + } + + zip_source_free(src_final); + src_final = src_tmp; + } + + if ((offdata = zip_source_tell_write(za->src)) < 0) { + _zip_error_set_from_source(&za->error, za->src); return -1; } - ret = copy_source(za, s2); + ret = copy_source(za, src_final, data_length); - if (zip_source_stat(s2, &st) < 0) + if (zip_source_stat(src_final, &st) < 0) { + _zip_error_set_from_source(&za->error, src_final); ret = -1; + } - zip_source_free(s2); + if ((compression_flags = zip_source_get_compression_flags(src_final)) < 0) { + _zip_error_set_from_source(&za->error, src_final); + ret = -1; + } - if (ret < 0) + zip_source_free(src_final); + + if (ret < 0) { return -1; + } if ((offend = zip_source_tell_write(za->src)) < 0) { + _zip_error_set_from_source(&za->error, za->src); return -1; } @@ -371,7 +455,9 @@ de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = (zip_uint64_t)(offend - offdata); - + de->bitflags = (zip_uint16_t)((de->bitflags & (zip_uint16_t)~6) | ((zip_uint8_t)compression_flags << 1)); + _zip_dirent_set_version_needed(de, (flags & ZIP_FL_FORCE_ZIP64) != 0); + if ((ret=_zip_dirent_write(za, de, flags)) < 0) return -1; @@ -380,7 +466,6 @@ zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return -1; } - if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) { _zip_error_set_from_source(&za->error, za->src); @@ -396,6 +481,7 @@ { zip_uint8_t buf[BUFSIZE]; size_t n; + double total = (double)len; while (len > 0) { n = len > sizeof(buf) ? sizeof(buf) : len; @@ -408,6 +494,8 @@ } len -= n; + + _zip_progress_update(za->progress, (total - (double)len) / total); } return 0; @@ -415,10 +503,10 @@ static int -copy_source(zip_t *za, zip_source_t *src) +copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) { zip_uint8_t buf[BUFSIZE]; - zip_int64_t n; + zip_int64_t n, current; int ret; if (zip_source_open(src) < 0) { @@ -427,11 +515,16 @@ } ret = 0; + current = 0; while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { if (_zip_write(za, buf, (zip_uint64_t)n) < 0) { ret = -1; break; } + if (n == sizeof(buf) && za->progress && data_length > 0) { + current += n; + _zip_progress_update(za->progress, (double)current/(double)data_length); + } } if (n < 0) { @@ -444,7 +537,6 @@ return ret; } - static int write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {