Coverage Report

Created: 2026-10-14 06:52

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