Bump to 1.10.1
[platform/upstream/libzip.git] / lib / zip_close.c
1 /*
2   zip_close.c -- close zip archive and update changes
3   Copyright (C) 1999-2022 Dieter Baron and Thomas Klausner
4
5   This file is part of libzip, a library to manipulate ZIP archives.
6   The authors can be contacted at <info@libzip.org>
7
8   Redistribution and use in source and binary forms, with or without
9   modification, are permitted provided that the following conditions
10   are met:
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
16      distribution.
17   3. The names of the authors may not be used to endorse or promote
18      products derived from this software without specific prior
19      written permission.
20
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.
32 */
33
34
35 #include "zipint.h"
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #ifdef _WIN32
40 #include <fcntl.h>
41 #include <io.h>
42 #endif
43
44
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 torrentzip_compare_names(const void *a, const void *b);
49 static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);
50 static int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64);
51
52 ZIP_EXTERN int
53 zip_close(zip_t *za) {
54     zip_uint64_t i, j, survivors, unchanged_offset;
55     zip_int64_t off;
56     int error;
57     zip_filelist_t *filelist;
58     int changed;
59
60     if (za == NULL)
61         return -1;
62
63     changed = _zip_changed(za, &survivors);
64
65     if (survivors == 0 && !(za->ch_flags & ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE)) {
66         /* don't create zip files with no entries */
67         if ((za->open_flags & ZIP_TRUNCATE) || changed) {
68             if (zip_source_remove(za->src) < 0) {
69                 if (!((zip_error_code_zip(zip_source_error(za->src)) == ZIP_ER_REMOVE) && (zip_error_code_system(zip_source_error(za->src)) == ENOENT))) {
70                     zip_error_set_from_source(&za->error, za->src);
71                     return -1;
72                 }
73             }
74         }
75         zip_discard(za);
76         return 0;
77     }
78
79     /* Always write empty archive if we are told to keep it, otherwise it wouldn't be created if the file doesn't already exist. */
80     if (!changed && survivors > 0) {
81         zip_discard(za);
82         return 0;
83     }
84
85     if (survivors > za->nentry) {
86         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
87         return -1;
88     }
89
90     if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL)
91         return -1;
92
93     unchanged_offset = ZIP_UINT64_MAX;
94     /* create list of files with index into original archive  */
95     for (i = j = 0; i < za->nentry; i++) {
96         if (za->entry[i].orig != NULL && ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
97             unchanged_offset = ZIP_MIN(unchanged_offset, za->entry[i].orig->offset);
98         }
99         if (za->entry[i].deleted) {
100             continue;
101         }
102
103         if (j >= survivors) {
104             free(filelist);
105             zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
106             return -1;
107         }
108
109         filelist[j].idx = i;
110         filelist[j].name = zip_get_name(za, i, 0);
111         j++;
112     }
113     if (j < survivors) {
114         free(filelist);
115         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
116         return -1;
117     }
118
119     if (ZIP_WANT_TORRENTZIP(za)) {
120         qsort(filelist, (size_t)survivors, sizeof(filelist[0]), torrentzip_compare_names);
121     }
122
123     if (ZIP_WANT_TORRENTZIP(za) || (zip_source_supports(za->src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING)) == 0) {
124         unchanged_offset = 0;
125     }
126     else {
127         if (unchanged_offset == ZIP_UINT64_MAX) {
128             /* we're keeping all file data, find the end of the last one */
129             zip_uint64_t last_index = ZIP_UINT64_MAX;
130             unchanged_offset = 0;
131
132             for (i = 0; i < za->nentry; i++) {
133                 if (za->entry[i].orig != NULL) {
134                     if (za->entry[i].orig->offset >= unchanged_offset) {
135                         unchanged_offset = za->entry[i].orig->offset;
136                         last_index = i;
137                     }
138                 }
139             }
140             if (last_index != ZIP_UINT64_MAX) {
141                 if ((unchanged_offset = _zip_file_get_end(za, last_index, &za->error)) == 0) {
142                     free(filelist);
143                     return -1;
144                 }
145             }
146         }
147         if (unchanged_offset > 0) {
148             if (zip_source_begin_write_cloning(za->src, unchanged_offset) < 0) {
149                 /* cloning not supported, need to copy everything */
150                 unchanged_offset = 0;
151             }
152         }
153     }
154     if (unchanged_offset == 0) {
155         if (zip_source_begin_write(za->src) < 0) {
156             zip_error_set_from_source(&za->error, za->src);
157             free(filelist);
158             return -1;
159         }
160     }
161
162     if (_zip_progress_start(za->progress) != 0) {
163         zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
164         zip_source_rollback_write(za->src);
165         free(filelist);
166         return -1;
167     }
168     error = 0;
169     for (j = 0; j < survivors; j++) {
170         int new_data;
171         zip_entry_t *entry;
172         zip_dirent_t *de;
173
174         if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) {
175             zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
176             error = 1;
177             break;
178         }
179
180         i = filelist[j].idx;
181         entry = za->entry + i;
182
183         if (entry->orig != NULL && entry->orig->offset < unchanged_offset) {
184             /* already implicitly copied by cloning */
185             continue;
186         }
187
188         new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD)) || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za));
189
190         /* create new local directory entry */
191         if (entry->changes == NULL) {
192             if ((entry->changes = _zip_dirent_clone(entry->orig)) == NULL) {
193                 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
194                 error = 1;
195                 break;
196             }
197         }
198         de = entry->changes;
199
200         if (_zip_read_local_ef(za, i) < 0) {
201             error = 1;
202             break;
203         }
204
205         if (ZIP_WANT_TORRENTZIP(za)) {
206             zip_dirent_torrentzip_normalize(entry->changes);
207         }
208
209         if ((off = zip_source_tell_write(za->src)) < 0) {
210             zip_error_set_from_source(&za->error, za->src);
211             error = 1;
212             break;
213         }
214         de->offset = (zip_uint64_t)off;
215
216         if (new_data) {
217             zip_source_t *zs;
218
219             zs = NULL;
220             if (!ZIP_ENTRY_DATA_CHANGED(entry)) {
221                 if ((zs = zip_source_zip_file_create(za, i, ZIP_FL_UNCHANGED, 0, -1, NULL, &za->error)) == NULL) {
222                     error = 1;
223                     break;
224                 }
225             }
226
227             /* add_data writes dirent */
228             if (add_data(za, zs ? zs : entry->source, de, entry->changes ? entry->changes->changed : 0) < 0) {
229                 error = 1;
230                 if (zs)
231                     zip_source_free(zs);
232                 break;
233             }
234             if (zs)
235                 zip_source_free(zs);
236         }
237         else {
238             zip_uint64_t offset;
239
240             if (de->encryption_method != ZIP_EM_TRAD_PKWARE) {
241                 /* when copying data, all sizes are known -> no data descriptor needed */
242                 /* except for PKWare encryption, where removing the data descriptor breaks password validation */
243                 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
244             }
245             if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {
246                 error = 1;
247                 break;
248             }
249             if ((offset = _zip_file_get_offset(za, i, &za->error)) == 0) {
250                 error = 1;
251                 break;
252             }
253             if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {
254                 zip_error_set_from_source(&za->error, za->src);
255                 error = 1;
256                 break;
257             }
258             if (copy_data(za, de->comp_size) < 0) {
259                 error = 1;
260                 break;
261             }
262
263             if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
264                 if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) {
265                     error = 1;
266                     break;
267                 }
268             }
269         }
270     }
271
272     if (!error) {
273         if (write_cdir(za, filelist, survivors) < 0)
274             error = 1;
275     }
276
277     free(filelist);
278
279     if (!error) {
280         if (zip_source_commit_write(za->src) != 0) {
281             zip_error_set_from_source(&za->error, za->src);
282             error = 1;
283         }
284         _zip_progress_end(za->progress);
285     }
286
287     if (error) {
288         zip_source_rollback_write(za->src);
289         return -1;
290     }
291
292     zip_discard(za);
293
294     return 0;
295 }
296
297
298 static int
299 add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) {
300     zip_int64_t offstart, offdata, offend, data_length;
301     zip_stat_t st;
302     zip_file_attributes_t attributes;
303     zip_source_t *src_final, *src_tmp;
304     int ret;
305     int is_zip64;
306     zip_flags_t flags;
307     bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
308
309     if (zip_source_stat(src, &st) < 0) {
310         zip_error_set_from_source(&za->error, src);
311         return -1;
312     }
313
314     if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {
315         st.valid |= ZIP_STAT_COMP_METHOD;
316         st.comp_method = ZIP_CM_STORE;
317     }
318
319     if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)
320         de->comp_method = st.comp_method;
321     else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
322         st.valid |= ZIP_STAT_COMP_SIZE;
323         st.comp_size = st.size;
324     }
325     else {
326         /* we'll recompress */
327         st.valid &= ~ZIP_STAT_COMP_SIZE;
328     }
329
330     if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) {
331         st.valid |= ZIP_STAT_ENCRYPTION_METHOD;
332         st.encryption_method = ZIP_EM_NONE;
333     }
334
335     flags = ZIP_EF_LOCAL;
336
337     if ((st.valid & ZIP_STAT_SIZE) == 0) {
338         /* TODO: not valid for torrentzip */
339         flags |= ZIP_FL_FORCE_ZIP64;
340         data_length = -1;
341     }
342     else {
343         de->uncomp_size = st.size;
344         /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */
345         data_length = (zip_int64_t)st.size;
346
347         if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
348             zip_uint64_t max_compressed_size;
349             zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method);
350
351             if (compression_method == ZIP_CM_STORE) {
352                 max_compressed_size = st.size;
353             }
354             else {
355                 zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true);
356                 if (algorithm == NULL) {
357                     max_compressed_size = ZIP_UINT64_MAX;
358                 }
359                 else {
360                     max_compressed_size = algorithm->maximum_compressed_size(st.size);
361                 }
362             }
363
364             if (max_compressed_size > 0xffffffffu) {
365                 /* TODO: not valid for torrentzip */
366                 flags |= ZIP_FL_FORCE_ZIP64;
367             }
368         }
369         else {
370             de->comp_size = st.comp_size;
371             data_length = (zip_int64_t)st.comp_size;
372         }
373     }
374
375     if ((offstart = zip_source_tell_write(za->src)) < 0) {
376         zip_error_set_from_source(&za->error, za->src);
377         return -1;
378     }
379
380     /* as long as we don't support non-seekable output, clear data descriptor bit */
381     de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
382     if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) {
383         return -1;
384     }
385
386     needs_recompress = ZIP_WANT_TORRENTZIP(za) || st.comp_method != ZIP_CM_ACTUAL(de->comp_method);
387     needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);
388     /* in these cases we can compute the CRC ourselves, so we do */
389     needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
390     needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
391
392     needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);
393     needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);
394     needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);
395
396     src_final = src;
397     zip_source_keep(src_final);
398
399     if (!needs_decrypt && st.encryption_method == ZIP_EM_TRAD_PKWARE && (de->changed & ZIP_DIRENT_LAST_MOD)) {
400         /* PKWare encryption uses the last modification time for password verification, therefore we can't change it without re-encrypting. Ignoring the requested modification time change seems more sensible than failing to close the archive. */
401          de->changed &= ~ZIP_DIRENT_LAST_MOD;
402     }
403
404     if (needs_decrypt) {
405         zip_encryption_implementation impl;
406
407         if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
408             zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
409             zip_source_free(src_final);
410             return -1;
411         }
412         if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) {
413             /* error set by impl */
414             zip_source_free(src_final);
415             return -1;
416         }
417
418         src_final = src_tmp;
419     }
420
421     if (needs_decompress) {
422         if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) {
423             zip_source_free(src_final);
424             return -1;
425         }
426
427         src_final = src_tmp;
428     }
429
430     if (needs_crc) {
431         if ((src_tmp = zip_source_crc_create(src_final, 0, &za->error)) == NULL) {
432             zip_source_free(src_final);
433             return -1;
434         }
435
436         src_final = src_tmp;
437     }
438
439     if (needs_compress) {
440         if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) {
441             zip_source_free(src_final);
442             return -1;
443         }
444
445         src_final = src_tmp;
446     }
447
448
449     if (needs_encrypt) {
450         zip_encryption_implementation impl;
451         const char *password = NULL;
452
453         if (de->password) {
454             password = de->password;
455         }
456         else if (za->default_password) {
457             password = za->default_password;
458         }
459
460         if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) {
461             zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
462             zip_source_free(src_final);
463             return -1;
464         }
465
466         if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
467             de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
468
469             /* PKWare encryption uses last_mod, make sure it gets the right value. */
470             if (de->changed & ZIP_DIRENT_LAST_MOD) {
471                 zip_stat_t st_mtime;
472                 zip_stat_init(&st_mtime);
473                 st_mtime.valid = ZIP_STAT_MTIME;
474                 st_mtime.mtime = de->last_mod;
475                 if ((src_tmp = _zip_source_window_new(src_final, 0, -1, &st_mtime, 0, NULL, NULL, 0, true, &za->error)) == NULL) {
476                     zip_source_free(src_final);
477                     return -1;
478                 }
479                 src_final = src_tmp;
480             }
481         }
482
483         if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) {
484             /* error set by impl */
485             zip_source_free(src_final);
486             return -1;
487         }
488
489         src_final = src_tmp;
490     }
491
492
493     if ((offdata = zip_source_tell_write(za->src)) < 0) {
494         zip_error_set_from_source(&za->error, za->src);
495         return -1;
496     }
497
498     ret = copy_source(za, src_final, data_length);
499
500     if (zip_source_stat(src_final, &st) < 0) {
501         zip_error_set_from_source(&za->error, src_final);
502         ret = -1;
503     }
504
505     if (zip_source_get_file_attributes(src_final, &attributes) != 0) {
506         zip_error_set_from_source(&za->error, src_final);
507         ret = -1;
508     }
509
510     zip_source_free(src_final);
511
512     if (ret < 0) {
513         return -1;
514     }
515
516     if ((offend = zip_source_tell_write(za->src)) < 0) {
517         zip_error_set_from_source(&za->error, za->src);
518         return -1;
519     }
520
521     if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) {
522         zip_error_set_from_source(&za->error, za->src);
523         return -1;
524     }
525
526     if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) {
527         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
528         return -1;
529     }
530
531     if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
532         if (st.valid & ZIP_STAT_MTIME)
533             de->last_mod = st.mtime;
534         else
535             time(&de->last_mod);
536     }
537     de->comp_method = st.comp_method;
538     de->crc = st.crc;
539     de->uncomp_size = st.size;
540     de->comp_size = (zip_uint64_t)(offend - offdata);
541     _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed);
542
543     if (ZIP_WANT_TORRENTZIP(za)) {
544         zip_dirent_torrentzip_normalize(de);
545     }
546
547     if ((ret = _zip_dirent_write(za, de, flags)) < 0)
548         return -1;
549
550     if (is_zip64 != ret) {
551         /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
552         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
553         return -1;
554     }
555
556     if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {
557         zip_error_set_from_source(&za->error, za->src);
558         return -1;
559     }
560
561     if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
562         if (write_data_descriptor(za, de, is_zip64) < 0) {
563             return -1;
564         }
565     }
566
567     return 0;
568 }
569
570
571 static int
572 copy_data(zip_t *za, zip_uint64_t len) {
573     DEFINE_BYTE_ARRAY(buf, BUFSIZE);
574     double total = (double)len;
575
576     if (!byte_array_init(buf, BUFSIZE)) {
577         zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
578         return -1;
579     }
580
581     while (len > 0) {
582         zip_uint64_t n = ZIP_MIN(len, BUFSIZE);
583
584         if (_zip_read(za->src, buf, n, &za->error) < 0) {
585             byte_array_fini(buf);
586             return -1;
587         }
588
589         if (_zip_write(za, buf, n) < 0) {
590             byte_array_fini(buf);
591             return -1;
592         }
593
594         len -= n;
595
596         if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) {
597             zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
598             return -1;
599         }
600     }
601
602     byte_array_fini(buf);
603     return 0;
604 }
605
606
607 static int
608 copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {
609     DEFINE_BYTE_ARRAY(buf, BUFSIZE);
610     zip_int64_t n, current;
611     int ret;
612
613     if (zip_source_open(src) < 0) {
614         zip_error_set_from_source(&za->error, src);
615         return -1;
616     }
617
618     if (!byte_array_init(buf, BUFSIZE)) {
619         zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
620         return -1;
621     }
622
623     ret = 0;
624     current = 0;
625     while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {
626         if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
627             ret = -1;
628             break;
629         }
630         if (n == BUFSIZE && za->progress && data_length > 0) {
631             current += n;
632             if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) {
633                 zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
634                 ret = -1;
635                 break;
636             }
637         }
638     }
639
640     if (n < 0) {
641         zip_error_set_from_source(&za->error, src);
642         ret = -1;
643     }
644
645     byte_array_fini(buf);
646
647     zip_source_close(src);
648
649     return ret;
650 }
651
652 static int
653 write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {
654     if (zip_source_tell_write(za->src) < 0) {
655         return -1;
656     }
657
658     if (_zip_cdir_write(za, filelist, survivors) < 0) {
659         return -1;
660     }
661
662     if (zip_source_tell_write(za->src) < 0) {
663         return -1;
664     }
665
666     return 0;
667 }
668
669
670 int
671 _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {
672     int changed;
673     zip_uint64_t i, survivors;
674
675     changed = 0;
676     survivors = 0;
677
678     if (za->comment_changed || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za))) {
679         changed = 1;
680     }
681
682     for (i = 0; i < za->nentry; i++) {
683         if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
684             changed = 1;
685         }
686         if (!za->entry[i].deleted) {
687             survivors++;
688         }
689     }
690
691     if (survivorsp) {
692         *survivorsp = survivors;
693     }
694
695     return changed;
696 }
697
698 static int
699 write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {
700     zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);
701     int ret = 0;
702
703     if (buffer == NULL) {
704         zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
705         return -1;
706     }
707
708     _zip_buffer_put(buffer, DATADES_MAGIC, 4);
709     _zip_buffer_put_32(buffer, de->crc);
710     if (is_zip64) {
711         _zip_buffer_put_64(buffer, de->comp_size);
712         _zip_buffer_put_64(buffer, de->uncomp_size);
713     }
714     else {
715         _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
716         _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
717     }
718
719     if (!_zip_buffer_ok(buffer)) {
720         zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
721         ret = -1;
722     }
723     else {
724         ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));
725     }
726
727     _zip_buffer_free(buffer);
728
729     return ret;
730 }
731
732
733 static int torrentzip_compare_names(const void *a, const void *b) {
734     const char *aname = ((const zip_filelist_t *)a)->name;
735     const char *bname = ((const zip_filelist_t *)b)->name;
736
737     if (aname == NULL) {
738         return (bname != NULL) * -1;
739     }
740     else if (bname == NULL) {
741         return 1;
742     }
743
744     return strcasecmp(aname, bname);
745 }