2 zip_close.c -- close zip archive and update changes
3 Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 static int add_data(zip_t *, zip_source_t *, zip_dirent_t *, zip_uint32_t);
46 static int copy_data(zip_t *, zip_uint64_t);
47 static int copy_source(zip_t *, zip_source_t *, zip_int64_t);
48 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);
49 static int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64);
52 zip_close(zip_t *za) {
53 zip_uint64_t i, j, survivors, unchanged_offset;
56 zip_filelist_t *filelist;
62 changed = _zip_changed(za, &survivors);
64 /* don't create zip files with no entries */
66 if ((za->open_flags & ZIP_TRUNCATE) || changed) {
67 if (zip_source_remove(za->src) < 0) {
68 if (!((zip_error_code_zip(zip_source_error(za->src)) == ZIP_ER_REMOVE) && (zip_error_code_system(zip_source_error(za->src)) == ENOENT))) {
69 _zip_error_set_from_source(&za->error, za->src);
83 if (survivors > za->nentry) {
84 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
88 if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL)
91 unchanged_offset = ZIP_UINT64_MAX;
92 /* create list of files with index into original archive */
93 for (i = j = 0; i < za->nentry; i++) {
94 if (za->entry[i].orig != NULL && ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
95 unchanged_offset = ZIP_MIN(unchanged_offset, za->entry[i].orig->offset);
97 if (za->entry[i].deleted) {
101 if (j >= survivors) {
103 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
112 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
116 if ((zip_source_supports(za->src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING)) == 0) {
117 unchanged_offset = 0;
120 if (unchanged_offset == ZIP_UINT64_MAX) {
121 /* we're keeping all file data, find the end of the last one */
122 zip_uint64_t last_index = ZIP_UINT64_MAX;
123 unchanged_offset = 0;
125 for (i = 0; i < za->nentry; i++) {
126 if (za->entry[i].orig != NULL) {
127 if (za->entry[i].orig->offset >= unchanged_offset) {
128 unchanged_offset = za->entry[i].orig->offset;
133 if (last_index != ZIP_UINT64_MAX) {
134 if ((unchanged_offset = _zip_file_get_end(za, last_index, &za->error)) == 0) {
140 if (unchanged_offset > 0) {
141 if (zip_source_begin_write_cloning(za->src, unchanged_offset) < 0) {
142 /* cloning not supported, need to copy everything */
143 unchanged_offset = 0;
147 if (unchanged_offset == 0) {
148 if (zip_source_begin_write(za->src) < 0) {
149 _zip_error_set_from_source(&za->error, za->src);
155 if (_zip_progress_start(za->progress) != 0) {
156 zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
157 zip_source_rollback_write(za->src);
162 for (j = 0; j < survivors; j++) {
167 if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) {
168 zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
174 entry = za->entry + i;
176 if (entry->orig != NULL && entry->orig->offset < unchanged_offset) {
177 /* already implicitly copied by cloning */
181 new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD));
183 /* create new local directory entry */
184 if (entry->changes == NULL) {
185 if ((entry->changes = _zip_dirent_clone(entry->orig)) == NULL) {
186 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
193 if (_zip_read_local_ef(za, i) < 0) {
198 if ((off = zip_source_tell_write(za->src)) < 0) {
199 _zip_error_set_from_source(&za->error, za->src);
203 de->offset = (zip_uint64_t)off;
209 if (!ZIP_ENTRY_DATA_CHANGED(entry)) {
210 if ((zs = _zip_source_zip_new(za, i, ZIP_FL_UNCHANGED, 0, 0, NULL, &za->error)) == NULL) {
216 /* add_data writes dirent */
217 if (add_data(za, zs ? zs : entry->source, de, entry->changes ? entry->changes->changed : 0) < 0) {
229 if (de->encryption_method != ZIP_EM_TRAD_PKWARE) {
230 /* when copying data, all sizes are known -> no data descriptor needed */
231 /* except for PKWare encryption, where removing the data descriptor breaks password validation */
232 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
234 if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {
238 if ((offset = _zip_file_get_offset(za, i, &za->error)) == 0) {
242 if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {
243 _zip_error_set_from_source(&za->error, za->src);
247 if (copy_data(za, de->comp_size) < 0) {
252 if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
253 if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) {
262 if (write_cdir(za, filelist, survivors) < 0)
269 if (zip_source_commit_write(za->src) != 0) {
270 _zip_error_set_from_source(&za->error, za->src);
273 _zip_progress_end(za->progress);
277 zip_source_rollback_write(za->src);
288 add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) {
289 zip_int64_t offstart, offdata, offend, data_length;
291 zip_file_attributes_t attributes;
292 zip_source_t *src_final, *src_tmp;
296 bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
298 if (zip_source_stat(src, &st) < 0) {
299 _zip_error_set_from_source(&za->error, src);
303 if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {
304 st.valid |= ZIP_STAT_COMP_METHOD;
305 st.comp_method = ZIP_CM_STORE;
308 if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)
309 de->comp_method = st.comp_method;
310 else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
311 st.valid |= ZIP_STAT_COMP_SIZE;
312 st.comp_size = st.size;
315 /* we'll recompress */
316 st.valid &= ~ZIP_STAT_COMP_SIZE;
319 if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) {
320 st.valid |= ZIP_STAT_ENCRYPTION_METHOD;
321 st.encryption_method = ZIP_EM_NONE;
324 flags = ZIP_EF_LOCAL;
326 if ((st.valid & ZIP_STAT_SIZE) == 0) {
327 flags |= ZIP_FL_FORCE_ZIP64;
331 de->uncomp_size = st.size;
332 /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */
333 data_length = (zip_int64_t)st.size;
335 if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
336 zip_uint64_t max_compressed_size;
337 zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method);
339 if (compression_method == ZIP_CM_STORE) {
340 max_compressed_size = st.size;
343 zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true);
344 if (algorithm == NULL) {
345 max_compressed_size = ZIP_UINT64_MAX;
348 max_compressed_size = algorithm->maximum_compressed_size(st.size);
352 if (max_compressed_size > 0xffffffffu) {
353 flags |= ZIP_FL_FORCE_ZIP64;
357 de->comp_size = st.comp_size;
358 data_length = (zip_int64_t)st.comp_size;
362 if ((offstart = zip_source_tell_write(za->src)) < 0) {
363 _zip_error_set_from_source(&za->error, za->src);
367 /* as long as we don't support non-seekable output, clear data descriptor bit */
368 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
369 if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) {
373 needs_recompress = st.comp_method != ZIP_CM_ACTUAL(de->comp_method);
374 needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);
375 /* in these cases we can compute the CRC ourselves, so we do */
376 needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
377 needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
379 needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);
380 needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);
381 needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);
384 zip_source_keep(src_final);
387 zip_encryption_implementation impl;
389 if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
390 zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
391 zip_source_free(src_final);
394 if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) {
395 /* error set by impl */
396 zip_source_free(src_final);
400 zip_source_free(src_final);
404 if (needs_decompress) {
405 if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) {
406 zip_source_free(src_final);
410 zip_source_free(src_final);
415 if ((src_tmp = zip_source_crc_create(src_final, 0, &za->error)) == NULL) {
416 zip_source_free(src_final);
420 zip_source_free(src_final);
424 if (needs_compress) {
425 if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) {
426 zip_source_free(src_final);
430 zip_source_free(src_final);
436 zip_encryption_implementation impl;
437 const char *password = NULL;
440 password = de->password;
442 else if (za->default_password) {
443 password = za->default_password;
446 if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) {
447 zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
448 zip_source_free(src_final);
452 if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
453 de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
455 /* PKWare encryption uses last_mod, make sure it gets the right value. */
456 if (de->changed & ZIP_DIRENT_LAST_MOD) {
458 zip_stat_init(&st_mtime);
459 st_mtime.valid = ZIP_STAT_MTIME;
460 st_mtime.mtime = de->last_mod;
461 if ((src_tmp = _zip_source_window_new(src_final, 0, -1, &st_mtime, NULL, NULL, 0, &za->error)) == NULL) {
462 zip_source_free(src_final);
465 zip_source_free(src_final);
470 if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) {
471 /* error set by impl */
472 zip_source_free(src_final);
476 zip_source_free(src_final);
481 if ((offdata = zip_source_tell_write(za->src)) < 0) {
482 _zip_error_set_from_source(&za->error, za->src);
486 ret = copy_source(za, src_final, data_length);
488 if (zip_source_stat(src_final, &st) < 0) {
489 _zip_error_set_from_source(&za->error, src_final);
493 if (zip_source_get_file_attributes(src_final, &attributes) != 0) {
494 _zip_error_set_from_source(&za->error, src_final);
498 zip_source_free(src_final);
504 if ((offend = zip_source_tell_write(za->src)) < 0) {
505 _zip_error_set_from_source(&za->error, za->src);
509 if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) {
510 _zip_error_set_from_source(&za->error, za->src);
514 if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) {
515 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
519 if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
520 if (st.valid & ZIP_STAT_MTIME)
521 de->last_mod = st.mtime;
525 de->comp_method = st.comp_method;
527 de->uncomp_size = st.size;
528 de->comp_size = (zip_uint64_t)(offend - offdata);
529 _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed);
531 if ((ret = _zip_dirent_write(za, de, flags)) < 0)
534 if (is_zip64 != ret) {
535 /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
536 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
540 if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {
541 _zip_error_set_from_source(&za->error, za->src);
545 if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
546 if (write_data_descriptor(za, de, is_zip64) < 0) {
556 copy_data(zip_t *za, zip_uint64_t len) {
557 DEFINE_BYTE_ARRAY(buf, BUFSIZE);
559 double total = (double)len;
561 if (!byte_array_init(buf, BUFSIZE)) {
562 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
567 n = len > BUFSIZE ? BUFSIZE : len;
568 if (_zip_read(za->src, buf, n, &za->error) < 0) {
569 byte_array_fini(buf);
573 if (_zip_write(za, buf, n) < 0) {
574 byte_array_fini(buf);
580 if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) {
581 zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
586 byte_array_fini(buf);
592 copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {
593 DEFINE_BYTE_ARRAY(buf, BUFSIZE);
594 zip_int64_t n, current;
597 if (zip_source_open(src) < 0) {
598 _zip_error_set_from_source(&za->error, src);
602 if (!byte_array_init(buf, BUFSIZE)) {
603 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
609 while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {
610 if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
614 if (n == BUFSIZE && za->progress && data_length > 0) {
616 if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) {
617 zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
625 _zip_error_set_from_source(&za->error, src);
629 byte_array_fini(buf);
631 zip_source_close(src);
637 write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {
638 if (zip_source_tell_write(za->src) < 0) {
642 if (_zip_cdir_write(za, filelist, survivors) < 0) {
646 if (zip_source_tell_write(za->src) < 0) {
655 _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {
657 zip_uint64_t i, survivors;
662 if (za->comment_changed || za->ch_flags != za->flags) {
666 for (i = 0; i < za->nentry; i++) {
667 if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
670 if (!za->entry[i].deleted) {
676 *survivorsp = survivors;
683 write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {
684 zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);
687 if (buffer == NULL) {
688 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
692 _zip_buffer_put(buffer, DATADES_MAGIC, 4);
693 _zip_buffer_put_32(buffer, de->crc);
695 _zip_buffer_put_64(buffer, de->comp_size);
696 _zip_buffer_put_64(buffer, de->uncomp_size);
699 _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
700 _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
703 if (!_zip_buffer_ok(buffer)) {
704 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
708 ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));
711 _zip_buffer_free(buffer);