Coverage Report

Created: 2025-07-18 06:12

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