Coverage Report

Created: 2025-11-09 06:16

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