Coverage Report

Created: 2025-08-03 07:00

/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.08k
zip_close(zip_t *za) {
54
5.08k
    zip_uint64_t i, j, survivors, unchanged_offset;
55
5.08k
    zip_int64_t off;
56
5.08k
    int error;
57
5.08k
    zip_filelist_t *filelist;
58
5.08k
    int changed;
59
60
5.08k
    if (za == NULL)
61
0
        return -1;
62
63
5.08k
    changed = _zip_changed(za, &survivors);
64
65
5.08k
    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
619
        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
619
        zip_discard(za);
76
619
        return 0;
77
619
    }
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.46k
    if (!changed && survivors > 0) {
81
3.48k
        zip_discard(za);
82
3.48k
        return 0;
83
3.48k
    }
84
85
978
    if (survivors > za->nentry) {
86
0
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
87
0
        return -1;
88
0
    }
89
90
978
    if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL)
91
0
        return -1;
92
93
978
    unchanged_offset = ZIP_UINT64_MAX;
94
    /* create list of files with index into original archive  */
95
1.95k
    for (i = j = 0; i < za->nentry; i++) {
96
978
        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
978
        if (za->entry[i].deleted) {
100
0
            continue;
101
0
        }
102
103
978
        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
978
        filelist[j].idx = i;
110
978
        filelist[j].name = zip_get_name(za, i, 0);
111
978
        j++;
112
978
    }
113
978
    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
978
    if (ZIP_WANT_TORRENTZIP(za)) {
120
0
        qsort(filelist, (size_t)survivors, sizeof(filelist[0]), torrentzip_compare_names);
121
0
    }
122
123
978
    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
978
    else {
127
978
        if (unchanged_offset == ZIP_UINT64_MAX) {
128
            /* we're keeping all file data, find the end of the last one */
129
978
            zip_uint64_t last_index = ZIP_UINT64_MAX;
130
978
            unchanged_offset = 0;
131
132
1.95k
            for (i = 0; i < za->nentry; i++) {
133
978
                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
978
            }
140
978
            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
978
        }
147
978
        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
978
    }
154
978
    if (unchanged_offset == 0) {
155
978
        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
978
    }
161
162
978
    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
978
    error = 0;
169
1.95k
    for (j = 0; j < survivors; j++) {
170
978
        int new_data;
171
978
        zip_entry_t *entry;
172
978
        zip_dirent_t *de;
173
174
978
        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
978
        i = filelist[j].idx;
181
978
        entry = za->entry + i;
182
183
978
        if (entry->orig != NULL && entry->orig->offset < unchanged_offset) {
184
            /* already implicitly copied by cloning */
185
0
            continue;
186
0
        }
187
188
978
        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
978
        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
978
        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
978
        de = entry->changes;
205
206
978
        if (_zip_read_local_ef(za, i) < 0) {
207
0
            error = 1;
208
0
            break;
209
0
        }
210
211
978
        if (ZIP_WANT_TORRENTZIP(za)) {
212
0
            zip_dirent_torrentzip_normalize(entry->changes);
213
0
        }
214
215
978
        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
978
        de->offset = (zip_uint64_t)off;
221
222
978
        if (new_data) {
223
978
            zip_source_t *zs;
224
225
978
            zs = NULL;
226
978
            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
978
            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
978
            if (zs)
241
0
                zip_source_free(zs);
242
978
        }
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
978
    }
277
278
978
    if (!error) {
279
978
        if (write_cdir(za, filelist, survivors) < 0)
280
0
            error = 1;
281
978
    }
282
283
978
    free(filelist);
284
285
978
    if (!error) {
286
978
        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
978
        _zip_progress_end(za->progress);
291
978
    }
292
293
978
    if (error) {
294
0
        zip_source_rollback_write(za->src);
295
0
        return -1;
296
0
    }
297
298
978
    zip_discard(za);
299
300
978
    return 0;
301
978
}
302
303
304
978
static int add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
305
978
    zip_int64_t offstart, offdata, offend, data_length;
306
978
    zip_stat_t st;
307
978
    zip_file_attributes_t attributes;
308
978
    zip_source_t *src_final, *src_tmp;
309
978
    int ret;
310
978
    int is_zip64;
311
978
    zip_flags_t flags;
312
978
    bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
313
978
    bool dirent_changed;
314
978
    bool have_dos_time = false;
315
978
    time_t mtime_before_copy;
316
317
978
    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
978
    de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
323
324
978
    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
978
    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
978
    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
978
    else {
337
        /* we'll recompress */
338
978
        st.valid &= ~ZIP_STAT_COMP_SIZE;
339
978
    }
340
341
978
    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
978
    flags = ZIP_EF_LOCAL;
347
348
978
    if (st.valid & ZIP_STAT_CRC) {
349
0
        de->crc = st.crc;
350
0
    }
351
352
978
    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
978
    else {
358
978
        de->uncomp_size = st.size;
359
        /* this is technically incorrect (copy_source counts compressed data), but it's the best we have */
360
978
        data_length = (zip_int64_t)st.size;
361
362
978
        if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
363
978
            zip_uint64_t max_compressed_size;
364
978
            zip_uint16_t compression_method = ZIP_CM_ACTUAL(de->comp_method);
365
366
978
            if (compression_method == ZIP_CM_STORE) {
367
0
                max_compressed_size = st.size;
368
0
            }
369
978
            else {
370
978
                zip_compression_algorithm_t *algorithm = _zip_get_compression_algorithm(compression_method, true);
371
978
                if (algorithm == NULL) {
372
0
                    max_compressed_size = ZIP_UINT64_MAX;
373
0
                }
374
978
                else {
375
978
                    max_compressed_size = algorithm->maximum_compressed_size(st.size);
376
978
                }
377
978
            }
378
379
978
            if (max_compressed_size > 0xffffffffu) {
380
                /* TODO: not valid for torrentzip */
381
0
                flags |= ZIP_FL_FORCE_ZIP64;
382
0
            }
383
978
        }
384
0
        else {
385
0
            de->comp_size = st.comp_size;
386
0
            data_length = (zip_int64_t)st.comp_size;
387
0
        }
388
978
    }
389
390
978
    if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
391
978
        int ret2 = zip_source_get_dos_time(src, &de->last_mod);
392
978
        if (ret2 < 0) {
393
0
            zip_error_set_from_source(&za->error, src);
394
0
            return -1;
395
0
        }
396
978
        if (ret2 == 1) {
397
0
            have_dos_time = true;
398
0
        }
399
978
        else {
400
978
            if (st.valid & ZIP_STAT_MTIME) {
401
978
                mtime_before_copy = st.mtime;
402
978
            }
403
0
            else {
404
0
                time(&mtime_before_copy);
405
0
            }
406
978
            if (_zip_u2d_time(mtime_before_copy, &de->last_mod, &za->error) < 0) {
407
0
                return -1;
408
0
            }
409
978
        }
410
978
    }
411
412
978
    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
978
    needs_recompress = ZIP_WANT_TORRENTZIP(za) || st.comp_method != ZIP_CM_ACTUAL(de->comp_method);
418
978
    needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);
419
    /* in these cases we can compute the CRC ourselves, so we do */
420
978
    needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
421
978
    needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
422
423
978
    needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);
424
978
    needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);
425
978
    needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);
426
427
978
    src_final = src;
428
978
    zip_source_keep(src_final);
429
430
978
    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
978
    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
978
    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
978
    if (needs_crc) {
462
978
        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
978
        src_final = src_tmp;
468
978
    }
469
470
978
    if (needs_compress) {
471
978
        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
978
        src_final = src_tmp;
477
978
    }
478
479
480
978
    if (needs_encrypt) {
481
978
        zip_encryption_implementation impl;
482
978
        const char *password = NULL;
483
484
978
        if (de->password) {
485
978
            password = de->password;
486
978
        }
487
0
        else if (za->default_password) {
488
0
            password = za->default_password;
489
0
        }
490
491
978
        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
978
        if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
498
450
            de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
499
500
            /* PKWare encryption uses last_mod, make sure it gets the right value. */
501
450
            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
450
        }
509
510
978
        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
978
        src_final = src_tmp;
517
978
    }
518
519
978
    if (!ZIP_WANT_TORRENTZIP(za)) {
520
978
        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
978
        _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0);
526
978
    }
527
528
    /* as long as we don't support non-seekable output, clear data descriptor bit */
529
978
    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
978
    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
978
    ret = copy_source(za, src_final, src, data_length);
541
542
978
    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
978
    if (!ZIP_WANT_TORRENTZIP(za)) {
548
978
        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
978
    }
553
554
978
    zip_source_free(src_final);
555
556
978
    if (ret < 0) {
557
0
        return -1;
558
0
    }
559
560
978
    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
978
    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
978
    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
978
    de->comp_method = st.comp_method;
572
978
    de->crc = st.crc;
573
978
    de->uncomp_size = st.size;
574
978
    de->comp_size = (zip_uint64_t)(offend - offdata);
575
576
978
    if (!ZIP_WANT_TORRENTZIP(za)) {
577
978
        dirent_changed |= _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0);
578
579
978
        if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0 && !have_dos_time) {
580
978
            if (st.valid & ZIP_STAT_MTIME) {
581
978
                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
978
            }
588
978
        }
589
978
    }
590
591
978
    if (dirent_changed) {
592
978
        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
978
        if ((ret = _zip_dirent_write(za, de, flags)) < 0)
598
0
            return -1;
599
600
978
        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
978
        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
978
    }
611
612
978
    if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
613
450
        if (write_data_descriptor(za, de, is_zip64) < 0) {
614
0
            return -1;
615
0
        }
616
450
    }
617
618
978
    return 0;
619
978
}
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
978
copy_source(zip_t *za, zip_source_t *src, zip_source_t *src_for_length, zip_int64_t data_length) {
660
978
    DEFINE_BYTE_ARRAY(buf, BUFSIZE);
661
978
    zip_int64_t n, current;
662
978
    int ret;
663
664
978
    if (zip_source_open(src) < 0) {
665
0
        zip_error_set_from_source(&za->error, src);
666
0
        return -1;
667
0
    }
668
669
978
    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
978
    ret = 0;
675
978
    current = 0;
676
18.9k
    while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {
677
17.9k
        if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
678
0
            ret = -1;
679
0
            break;
680
0
        }
681
17.9k
        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
17.9k
    }
696
697
978
    if (n < 0) {
698
0
        zip_error_set_from_source(&za->error, src);
699
0
        ret = -1;
700
0
    }
701
702
978
    byte_array_fini(buf);
703
704
978
    zip_source_close(src);
705
706
978
    return ret;
707
978
}
708
709
static int
710
978
write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {
711
978
    if (zip_source_tell_write(za->src) < 0) {
712
0
        return -1;
713
0
    }
714
715
978
    if (_zip_cdir_write(za, filelist, survivors) < 0) {
716
0
        return -1;
717
0
    }
718
719
978
    if (zip_source_tell_write(za->src) < 0) {
720
0
        return -1;
721
0
    }
722
723
978
    return 0;
724
978
}
725
726
727
int
728
5.08k
_zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {
729
5.08k
    int changed;
730
5.08k
    zip_uint64_t i, survivors;
731
732
5.08k
    changed = 0;
733
5.08k
    survivors = 0;
734
735
5.08k
    if (za->comment_changed || (ZIP_WANT_TORRENTZIP(za) && !ZIP_IS_TORRENTZIP(za))) {
736
0
        changed = 1;
737
0
    }
738
739
57.1k
    for (i = 0; i < za->nentry; i++) {
740
52.0k
        if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
741
978
            changed = 1;
742
978
        }
743
52.0k
        if (!za->entry[i].deleted) {
744
52.0k
            survivors++;
745
52.0k
        }
746
52.0k
    }
747
748
5.08k
    if (survivorsp) {
749
5.08k
        *survivorsp = survivors;
750
5.08k
    }
751
752
5.08k
    return changed;
753
5.08k
}
754
755
static int
756
450
write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {
757
450
    zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);
758
450
    int ret = 0;
759
760
450
    if (buffer == NULL) {
761
0
        zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
762
0
        return -1;
763
0
    }
764
765
450
    _zip_buffer_put(buffer, DATADES_MAGIC, 4);
766
450
    _zip_buffer_put_32(buffer, de->crc);
767
450
    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
450
    else {
772
450
        _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
773
450
        _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
774
450
    }
775
776
450
    if (!_zip_buffer_ok(buffer)) {
777
0
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
778
0
        ret = -1;
779
0
    }
780
450
    else {
781
450
        ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));
782
450
    }
783
784
450
    _zip_buffer_free(buffer);
785
786
450
    return ret;
787
450
}
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
}