CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/ext/libzip/zip_close.c
Views: 1401
1
/*
2
zip_close.c -- close zip archive and update changes
3
Copyright (C) 1999-2020 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 <[email protected]>
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, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == 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_size;
337
338
switch (ZIP_CM_ACTUAL(de->comp_method)) {
339
case ZIP_CM_BZIP2:
340
/* computed by looking at increase of 10 random files of size 1MB when
341
* compressed with bzip2, rounded up: 1.006 */
342
max_size = 4269351188u;
343
break;
344
345
case ZIP_CM_DEFLATE:
346
/* max deflate size increase: size + ceil(size/16k)*5+6 */
347
max_size = 4293656963u;
348
break;
349
350
case ZIP_CM_STORE:
351
max_size = 0xffffffffu;
352
break;
353
354
default:
355
max_size = 0;
356
}
357
358
if (st.size > max_size) {
359
flags |= ZIP_FL_FORCE_ZIP64;
360
}
361
}
362
else
363
de->comp_size = st.comp_size;
364
}
365
366
if ((offstart = zip_source_tell_write(za->src)) < 0) {
367
_zip_error_set_from_source(&za->error, za->src);
368
return -1;
369
}
370
371
/* as long as we don't support non-seekable output, clear data descriptor bit */
372
de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
373
if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) {
374
return -1;
375
}
376
377
needs_recompress = st.comp_method != ZIP_CM_ACTUAL(de->comp_method);
378
needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);
379
needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;
380
needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);
381
382
needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);
383
needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);
384
needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);
385
386
src_final = src;
387
zip_source_keep(src_final);
388
389
if (needs_decrypt) {
390
zip_encryption_implementation impl;
391
392
if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {
393
zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
394
zip_source_free(src_final);
395
return -1;
396
}
397
if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) {
398
/* error set by impl */
399
zip_source_free(src_final);
400
return -1;
401
}
402
403
zip_source_free(src_final);
404
src_final = src_tmp;
405
}
406
407
if (needs_decompress) {
408
if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) {
409
zip_source_free(src_final);
410
return -1;
411
}
412
413
zip_source_free(src_final);
414
src_final = src_tmp;
415
}
416
417
if (needs_crc) {
418
if ((src_tmp = zip_source_crc(za, src_final, 0)) == NULL) {
419
zip_source_free(src_final);
420
return -1;
421
}
422
423
zip_source_free(src_final);
424
src_final = src_tmp;
425
}
426
427
if (needs_compress) {
428
if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) {
429
zip_source_free(src_final);
430
return -1;
431
}
432
433
zip_source_free(src_final);
434
src_final = src_tmp;
435
}
436
437
438
if (needs_encrypt) {
439
zip_encryption_implementation impl;
440
const char *password = NULL;
441
442
if (de->password) {
443
password = de->password;
444
}
445
else if (za->default_password) {
446
password = za->default_password;
447
}
448
449
if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) {
450
zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
451
zip_source_free(src_final);
452
return -1;
453
}
454
if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) {
455
/* error set by impl */
456
zip_source_free(src_final);
457
return -1;
458
}
459
if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
460
de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
461
}
462
463
zip_source_free(src_final);
464
src_final = src_tmp;
465
}
466
467
468
if ((offdata = zip_source_tell_write(za->src)) < 0) {
469
_zip_error_set_from_source(&za->error, za->src);
470
return -1;
471
}
472
473
ret = copy_source(za, src_final, data_length);
474
475
if (zip_source_stat(src_final, &st) < 0) {
476
_zip_error_set_from_source(&za->error, src_final);
477
ret = -1;
478
}
479
480
if (zip_source_get_file_attributes(src_final, &attributes) != 0) {
481
_zip_error_set_from_source(&za->error, src_final);
482
ret = -1;
483
}
484
485
zip_source_free(src_final);
486
487
if (ret < 0) {
488
return -1;
489
}
490
491
if ((offend = zip_source_tell_write(za->src)) < 0) {
492
_zip_error_set_from_source(&za->error, za->src);
493
return -1;
494
}
495
496
if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) {
497
_zip_error_set_from_source(&za->error, za->src);
498
return -1;
499
}
500
501
if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) {
502
zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
503
return -1;
504
}
505
506
if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {
507
if (st.valid & ZIP_STAT_MTIME)
508
de->last_mod = st.mtime;
509
else
510
time(&de->last_mod);
511
}
512
de->comp_method = st.comp_method;
513
de->crc = st.crc;
514
de->uncomp_size = st.size;
515
de->comp_size = (zip_uint64_t)(offend - offdata);
516
_zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed);
517
518
if ((ret = _zip_dirent_write(za, de, flags)) < 0)
519
return -1;
520
521
if (is_zip64 != ret) {
522
/* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
523
zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
524
return -1;
525
}
526
527
if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {
528
_zip_error_set_from_source(&za->error, za->src);
529
return -1;
530
}
531
532
if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
533
if (write_data_descriptor(za, de, is_zip64) < 0) {
534
return -1;
535
}
536
}
537
538
return 0;
539
}
540
541
542
static int
543
copy_data(zip_t *za, zip_uint64_t len) {
544
DEFINE_BYTE_ARRAY(buf, BUFSIZE);
545
size_t n;
546
double total = (double)len;
547
548
if (!byte_array_init(buf, BUFSIZE)) {
549
zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
550
return -1;
551
}
552
553
while (len > 0) {
554
n = len > BUFSIZE ? BUFSIZE : len;
555
if (_zip_read(za->src, buf, n, &za->error) < 0) {
556
byte_array_fini(buf);
557
return -1;
558
}
559
560
if (_zip_write(za, buf, n) < 0) {
561
byte_array_fini(buf);
562
return -1;
563
}
564
565
len -= n;
566
567
if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) {
568
zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
569
return -1;
570
}
571
}
572
573
byte_array_fini(buf);
574
return 0;
575
}
576
577
578
static int
579
copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {
580
DEFINE_BYTE_ARRAY(buf, BUFSIZE);
581
zip_int64_t n, current;
582
int ret;
583
584
if (zip_source_open(src) < 0) {
585
_zip_error_set_from_source(&za->error, src);
586
return -1;
587
}
588
589
if (!byte_array_init(buf, BUFSIZE)) {
590
zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
591
return -1;
592
}
593
594
ret = 0;
595
current = 0;
596
while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {
597
if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
598
ret = -1;
599
break;
600
}
601
if (n == BUFSIZE && za->progress && data_length > 0) {
602
current += n;
603
if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) {
604
zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
605
ret = -1;
606
break;
607
}
608
}
609
}
610
611
if (n < 0) {
612
_zip_error_set_from_source(&za->error, src);
613
ret = -1;
614
}
615
616
byte_array_fini(buf);
617
618
zip_source_close(src);
619
620
return ret;
621
}
622
623
static int
624
write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {
625
zip_int64_t cd_start, end, size;
626
627
if ((cd_start = zip_source_tell_write(za->src)) < 0) {
628
return -1;
629
}
630
631
if ((size = _zip_cdir_write(za, filelist, survivors)) < 0) {
632
return -1;
633
}
634
635
if ((end = zip_source_tell_write(za->src)) < 0) {
636
return -1;
637
}
638
639
return 0;
640
}
641
642
643
int
644
_zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {
645
int changed;
646
zip_uint64_t i, survivors;
647
648
changed = 0;
649
survivors = 0;
650
651
if (za->comment_changed || za->ch_flags != za->flags) {
652
changed = 1;
653
}
654
655
for (i = 0; i < za->nentry; i++) {
656
if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {
657
changed = 1;
658
}
659
if (!za->entry[i].deleted) {
660
survivors++;
661
}
662
}
663
664
if (survivorsp) {
665
*survivorsp = survivors;
666
}
667
668
return changed;
669
}
670
671
static int
672
write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {
673
zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);
674
int ret = 0;
675
676
if (buffer == NULL) {
677
zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
678
return -1;
679
}
680
681
_zip_buffer_put(buffer, DATADES_MAGIC, 4);
682
_zip_buffer_put_32(buffer, de->crc);
683
if (is_zip64) {
684
_zip_buffer_put_64(buffer, de->comp_size);
685
_zip_buffer_put_64(buffer, de->uncomp_size);
686
}
687
else {
688
_zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
689
_zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
690
}
691
692
if (!_zip_buffer_ok(buffer)) {
693
zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
694
ret = -1;
695
}
696
else {
697
ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));
698
}
699
700
_zip_buffer_free(buffer);
701
702
return ret;
703
}
704
705