Coverage Report

Created: 2026-11-12 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
14.2k
ZIP_EXTERN int zip_close(zip_t *za) {
55
14.2k
    zip_uint64_t i, j, survivors, unchanged_offset;
56
14.2k
    zip_int64_t off;
57
14.2k
    int error;
58
14.2k
    zip_filelist_t *filelist;
59
14.2k
    int changed;
60
61
14.2k
    if (za == NULL) {
62
0
        return -1;
63
0
    }
64
65
14.2k
    changed = _zip_changed(za, &survivors);
66
67
14.2k
    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
1.32k
        if ((za->open_flags & ZIP_TRUNCATE) || changed) {
70
203
            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
203
        }
77
1.32k
        zip_discard(za);
78
1.32k
        return 0;
79
1.32k
    }
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
12.9k
    if (!changed && survivors > 0) {
83
7.76k
        zip_discard(za);
84
7.76k
        return 0;
85
7.76k
    }
86
87
5.18k
    if (survivors > za->nentry) {
88
0
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
89
0
        return -1;
90
0
    }
91
92
5.18k
    if (survivors == 0) {
93
0
        filelist = NULL;
94
0
    }
95
5.18k
    else {
96
        /* This can't overflow because survivors <= za->nentry and sizeof(filelist[0]) < za->entry[0] */
97
5.18k
        if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL) {
98
0
            return -1;
99
0
        }
100
5.18k
    }
101
102
5.18k
    unchanged_offset = ZIP_UINT64_MAX;
103
    /* create list of files with index into original archive  */
104
27.9k
    for (i = j = 0; i < za->nentry; i++) {
105
22.7k
        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
22.7k
        if (za->entry[i].deleted) {
109
271
            continue;
110
271
        }
111
112
22.5k
        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
22.5k
        filelist[j].idx = i;
119
22.5k
        filelist[j].name = zip_get_name(za, i, 0);
120
22.5k
        j++;
121
22.5k
    }
122
5.18k
    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
5.18k
    if (ZIP_WANT_TORRENTZIP(za) && survivors > 1) {
129
0
        qsort(filelist, (size_t)survivors, sizeof(filelist[0]), torrentzip_compare_names);
130
0
    }
131
132
5.18k
    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
5.18k
    else {
136
5.18k
        if (unchanged_offset == ZIP_UINT64_MAX) {
137
            /* we're keeping all file data, find the end of the last one */
138
5.18k
            zip_uint64_t last_index = ZIP_UINT64_MAX;
139
5.18k
            unchanged_offset = 0;
140
141
27.9k
            for (i = 0; i < za->nentry; i++) {
142
22.7k
                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
22.7k
            }
149
5.18k
            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
5.18k
        }
156
5.18k
        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
5.18k
    }
163
5.18k
    if (unchanged_offset == 0) {
164
5.18k
        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
5.18k
    }
170
171
5.18k
    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
5.18k
    error = 0;
178
27.6k
    for (j = 0; j < survivors; j++) {
179
22.5k
        int new_data;
180
22.5k
        zip_entry_t *entry;
181
22.5k
        zip_dirent_t *de;
182
183
22.5k
        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
22.5k
        i = filelist[j].idx;
190
22.5k
        entry = za->entry + i;
191
192
22.5k
        if (entry->orig != NULL && entry->orig->offset < unchanged_offset) {
193
            /* already implicitly copied by cloning */
194
0
            continue;
195
0
        }
196
197
22.5k
        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
22.5k
        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
22.5k
        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
22.5k
        de = entry->changes;
214
215
22.5k
        if (_zip_read_local_ef(za, i) < 0) {
216
0
            error = 1;
217
0
            break;
218
0
        }
219
220
22.5k
        if (ZIP_WANT_TORRENTZIP(za)) {
221
0
            zip_dirent_torrentzip_normalize(entry->changes);
222
0
        }
223
224
22.5k
        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
22.5k
        de->offset = (zip_uint64_t)off;
230
231
22.5k
        if (new_data) {
232
22.5k
            zip_source_t *zs;
233
234
22.5k
            zs = NULL;
235
22.5k
            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
22.5k
            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
22.5k
            if (zs) {
251
0
                zip_source_free(zs);
252
0
            }
253
22.5k
        }
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
22.5k
    }
288
289
5.18k
    if (!error) {
290
5.18k
        if (write_cdir(za, filelist, survivors) < 0) {
291
0
            error = 1;
292
0
        }
293
5.18k
    }
294
295
5.18k
    free(filelist);
296
297
5.18k
    if (!error) {
298
5.18k
        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
5.18k
        _zip_progress_end(za->progress);
303
5.18k
    }
304
305
5.18k
    if (error) {
306
0
        zip_source_rollback_write(za->src);
307
0
        return -1;
308
0
    }
309
310
5.18k
    zip_discard(za);
311
312
5.18k
    return 0;
313
5.18k
}
314
315
316
22.5k
static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
317
22.5k
    zip_int64_t offstart, offdata, offend, data_length;
318
22.5k
    zip_stat_t st;
319
22.5k
    zip_file_attributes_t attributes;
320
22.5k
    zip_source_t *src_final, *src_tmp;
321
22.5k
    int ret;
322
22.5k
    int is_zip64;
323
22.5k
    zip_flags_t flags;
324
22.5k
    bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
325
22.5k
    bool dirent_changed;
326
22.5k
    bool have_dos_time = false;
327
22.5k
    time_t mtime_before_copy;
328
329
22.5k
    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
22.5k
    de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
335
336
22.5k
    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
22.5k
    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
22.5k
    else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
345
11.3k
        st.valid |= ZIP_STAT_COMP_SIZE;
346
11.3k
        st.comp_size = st.size;
347
11.3k
    }
348
11.1k
    else {
349
        /* we'll recompress */
350
11.1k
        st.valid &= ~ZIP_STAT_COMP_SIZE;
351
11.1k
    }
352
353
22.5k
    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
22.5k
    flags = ZIP_EF_LOCAL;
359
360
22.5k
    if (st.valid & ZIP_STAT_CRC) {
361
0
        de->crc = st.crc;
362
0
    }
363
364
22.5k
    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
22.5k
    else {
370
22.5k
        de->uncomp_size = st.size;
371
372
22.5k
        if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
373
11.1k
            zip_uint64_t max_compressed_size;
374
11.1k
            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
11.1k
            data_length = (zip_int64_t)st.size;
378
379
11.1k
            if (compression_method == ZIP_CM_STORE) {
380
0
                max_compressed_size = st.size;
381
0
            }
382
11.1k
            else {
383
11.1k
                zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true);
384
11.1k
                if (algorithm == NULL) {
385
0
                    max_compressed_size = ZIP_UINT64_MAX;
386
0
                }
387
11.1k
                else {
388
11.1k
                    max_compressed_size = algorithm->maximum_compressed_size(st.size);
389
11.1k
                }
390
11.1k
            }
391
392
11.1k
            if (max_compressed_size > 0xffffffffu) {
393
                /* TODO: not valid for torrentzip */
394
0
                flags |= ZIP_FL_FORCE_ZIP64;
395
0
            }
396
11.1k
        }
397
11.3k
        else {
398
11.3k
            de->comp_size = st.comp_size;
399
11.3k
            data_length = (zip_int64_t)st.comp_size;
400
11.3k
        }
401
22.5k
    }
402
403
22.5k
    if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
404
22.5k
        int ret2 = zip_source_get_dos_time(src, &de->last_mod);
405
22.5k
        if (ret2 < 0) {
406
0
            zip_error_set_from_source(&za->error, src);
407
0
            return -1;
408
0
        }
409
22.5k
        if (ret2 == 1) {
410
0
            have_dos_time = true;
411
0
        }
412
22.5k
        else {
413
22.5k
            if (st.valid & ZIP_STAT_MTIME) {
414
22.5k
                mtime_before_copy = st.mtime;
415
22.5k
            }
416
0
            else {
417
0
                time(&mtime_before_copy);
418
0
            }
419
22.5k
            if (_zip_u2d_time(mtime_before_copy, &de->last_mod, &za->error) < 0) {
420
0
                return -1;
421
0
            }
422
22.5k
        }
423
22.5k
    }
424
425
22.5k
    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
22.5k
    needs_recompress = ZIP_WANT_TORRENTZIP(za) || st.comp_method != ZIP_CM_ACTUAL(de->comp_method);
431
22.5k
    needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);
432
    /* in these cases we can compute the CRC ourselves, so we do */
433
22.5k
    needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
434
22.5k
    needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
435
436
22.5k
    needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);
437
22.5k
    needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);
438
22.5k
    needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);
439
440
22.5k
    src_final = src;
441
22.5k
    zip_source_keep(src_final);
442
443
22.5k
    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
22.5k
    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
22.5k
    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
22.5k
    if (needs_crc) {
475
22.5k
        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
22.5k
        src_final = src_tmp;
481
22.5k
    }
482
483
22.5k
    if (needs_compress) {
484
11.1k
        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
11.1k
        src_final = src_tmp;
490
11.1k
    }
491
492
493
22.5k
    if (needs_encrypt) {
494
11.2k
        zip_encryption_implementation impl;
495
11.2k
        const char *password = NULL;
496
497
11.2k
        if (de->password) {
498
11.2k
            password = de->password;
499
11.2k
        }
500
0
        else if (za->default_password) {
501
0
            password = za->default_password;
502
0
        }
503
504
11.2k
        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
11.2k
        if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
511
1.93k
            de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
512
513
            /* PKWare encryption uses last_mod, make sure it gets the right value. */
514
1.93k
            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
1.93k
        }
522
523
11.2k
        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
11.2k
        src_final = src_tmp;
530
11.2k
    }
531
532
22.5k
    if (!ZIP_WANT_TORRENTZIP(za)) {
533
22.5k
        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
22.5k
        _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0);
539
22.5k
    }
540
541
    /* as long as we don't support non-seekable output, clear data descriptor bit */
542
22.5k
    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
22.5k
    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
22.5k
    ret = copy_source(za, src_final, src, data_length);
554
555
22.5k
    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
22.5k
    if (!ZIP_WANT_TORRENTZIP(za)) {
561
22.5k
        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
22.5k
    }
566
567
22.5k
    zip_source_free(src_final);
568
569
22.5k
    if (ret < 0) {
570
0
        return -1;
571
0
    }
572
573
22.5k
    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
22.5k
    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
22.5k
    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
22.5k
    de->comp_method = st.comp_method;
585
22.5k
    de->crc = st.crc;
586
22.5k
    de->uncomp_size = st.size;
587
22.5k
    de->comp_size = (zip_uint64_t)(offend - offdata);
588
589
22.5k
    if (!ZIP_WANT_TORRENTZIP(za)) {
590
22.5k
        dirent_changed |= _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0);
591
592
22.5k
        if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0 && !have_dos_time) {
593
22.5k
            if (st.valid & ZIP_STAT_MTIME) {
594
22.5k
                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
22.5k
            }
601
22.5k
        }
602
22.5k
    }
603
604
22.5k
    if (dirent_changed) {
605
21.6k
        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
21.6k
        if ((ret = _zip_dirent_write(za, de, flags)) < 0) {
611
0
            return -1;
612
0
        }
613
614
21.6k
        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
21.6k
        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
21.6k
    }
625
626
22.5k
    if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
627
1.93k
        if (write_data_descriptor(za, de, is_zip64) < 0) {
628
0
            return -1;
629
0
        }
630
1.93k
    }
631
632
22.5k
    return 0;
633
22.5k
}
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
22.5k
static int copy_source(zip_t *za, zip_source_t *src, zip_source_t *src_for_length, zip_int64_t data_length) {
672
22.5k
    DEFINE_BYTE_ARRAY(buf, BUFSIZE);
673
22.5k
    zip_int64_t n, current;
674
22.5k
    int ret;
675
676
22.5k
    if (zip_source_open(src) < 0) {
677
0
        zip_error_set_from_source(&za->error, src);
678
0
        return -1;
679
0
    }
680
681
22.5k
    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
22.5k
    ret = 0;
687
22.5k
    current = 0;
688
37.7k
    while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {
689
15.2k
        if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
690
0
            ret = -1;
691
0
            break;
692
0
        }
693
15.2k
        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
15.2k
    }
709
710
22.5k
    if (n < 0) {
711
0
        zip_error_set_from_source(&za->error, src);
712
0
        ret = -1;
713
0
    }
714
715
22.5k
    byte_array_fini(buf);
716
717
22.5k
    zip_source_close(src);
718
719
22.5k
    return ret;
720
22.5k
}
721
722
5.18k
static int write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {
723
5.18k
    if (zip_source_tell_write(za->src) < 0) {
724
0
        return -1;
725
0
    }
726
727
5.18k
    if (_zip_cdir_write(za, filelist, survivors) < 0) {
728
0
        return -1;
729
0
    }
730
731
5.18k
    if (zip_source_tell_write(za->src) < 0) {
732
0
        return -1;
733
0
    }
734
735
5.18k
    return 0;
736
5.18k
}
737
738
739
14.2k
int _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {
740
14.2k
    int changed;
741
14.2k
    zip_uint64_t i, survivors;
742
743
14.2k
    changed = 0;
744
14.2k
    survivors = 0;
745
746
14.2k
    if (za->comment_changed || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za))) {
747
541
        changed = 1;
748
541
    }
749
750
189k
    for (i = 0; i < za->nentry; i++) {
751
175k
        if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
752
22.8k
            changed = 1;
753
22.8k
        }
754
175k
        if (!za->entry[i].deleted) {
755
174k
            survivors++;
756
174k
        }
757
175k
    }
758
759
14.2k
    if (survivorsp) {
760
14.2k
        *survivorsp = survivors;
761
14.2k
    }
762
763
14.2k
    return changed;
764
14.2k
}
765
766
1.93k
static int write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {
767
1.93k
    zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);
768
1.93k
    int ret = 0;
769
770
1.93k
    if (buffer == NULL) {
771
0
        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
772
0
        return -1;
773
0
    }
774
775
1.93k
    _zip_buffer_put(buffer, DATADES_MAGIC, 4);
776
1.93k
    _zip_buffer_put_32(buffer, de->crc);
777
1.93k
    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
1.93k
    else {
782
1.93k
        _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
783
1.93k
        _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
784
1.93k
    }
785
786
1.93k
    if (!_zip_buffer_ok(buffer)) {
787
0
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
788
0
        ret = -1;
789
0
    }
790
1.93k
    else {
791
1.93k
        ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));
792
1.93k
    }
793
794
1.93k
    _zip_buffer_free(buffer);
795
796
1.93k
    return ret;
797
1.93k
}
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
}