Coverage Report

Created: 2026-07-30 07:17

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