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