1 /*
2 zip_close.c -- close zip archive and update changes
3 Copyright (C) 1999-2015 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
36 #include "zipint.h"
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #ifdef HAVE_STRINGS_H
42 #include <strings.h>
43 #endif
44 #include <errno.h>
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #ifdef _WIN32
51 #include <io.h>
52 #include <fcntl.h>
53 #endif
54
55
56
57 /* max deflate size increase: size + ceil(size/16k)*5+6 */
58 #define MAX_DEFLATE_SIZE_32 4293656963u
59
60 static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, FILE *);
61 static int copy_data(FILE *, zip_uint64_t, FILE *, struct zip_error *);
62 static int copy_source(struct zip *, struct zip_source *, FILE *);
63 static int write_cdir(struct zip *, const struct zip_filelist *, zip_uint64_t, FILE *);
64 static char *_zip_create_temp_output(struct zip *, FILE **);
65 static int _zip_torrentzip_cmp(const void *, const void *);
66
67
68
69 ZIP_EXTERN int
zip_close(struct zip * za)70 zip_close(struct zip *za)
71 {
72 zip_uint64_t i, j, survivors;
73 int error;
74 char *temp;
75 FILE *out;
76 #ifndef _WIN32
77 mode_t mask;
78 #endif
79 struct zip_filelist *filelist;
80 int reopen_on_error;
81 int new_torrentzip;
82 int changed;
83
84 reopen_on_error = 0;
85
86 if (za == NULL)
87 return -1;
88
89 changed = _zip_changed(za, &survivors);
90
91 /* don't create zip files with no entries */
92 if (survivors == 0) {
93 if (za->zn && ((za->open_flags & ZIP_TRUNCATE) || (changed && za->zp))) {
94 if (remove(za->zn) != 0) {
95 _zip_error_set(&za->error, ZIP_ER_REMOVE, errno);
96 return -1;
97 }
98 }
99 zip_discard(za);
100 return 0;
101 }
102
103 if (!changed) {
104 zip_discard(za);
105 return 0;
106 }
107
108 if (survivors > za->nentry) {
109 _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
110 return -1;
111 }
112
113 if ((filelist=(struct zip_filelist *)malloc(sizeof(filelist[0])*(size_t)survivors)) == NULL)
114 return -1;
115
116 /* archive comment is special for torrentzip */
117 if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) {
118 /* TODO: use internal function when zip_set_archive_comment clears TORRENT flag */
119 if (zip_set_archive_comment(za, TORRENT_SIG "XXXXXXXX", TORRENT_SIG_LEN + TORRENT_CRC_LEN) < 0) {
120 free(filelist);
121 return -1;
122 }
123 }
124 /* TODO: if no longer torrentzip and archive comment not changed by user, delete it */
125
126
127 /* create list of files with index into original archive */
128 for (i=j=0; i<za->nentry; i++) {
129 if (za->entry[i].deleted)
130 continue;
131
132 if (j >= survivors) {
133 free(filelist);
134 _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
135 return -1;
136 }
137
138 filelist[j].idx = i;
139 filelist[j].name = zip_get_name(za, i, 0);
140 j++;
141 }
142 if (j < survivors) {
143 free(filelist);
144 _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
145 return -1;
146 }
147
148
149 if ((temp=_zip_create_temp_output(za, &out)) == NULL) {
150 free(filelist);
151 return -1;
152 }
153
154
155 if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
156 qsort(filelist, (size_t)survivors, sizeof(filelist[0]),
157 _zip_torrentzip_cmp);
158
159 new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1
160 && zip_get_archive_flag(za, ZIP_AFL_TORRENT,
161 ZIP_FL_UNCHANGED) == 0);
162 error = 0;
163 for (j=0; j<survivors; j++) {
164 int new_data;
165 struct zip_entry *entry;
166 struct zip_dirent *de;
167
168 i = filelist[j].idx;
169 entry = za->entry+i;
170
171 new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || new_torrentzip || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD));
172
173 /* create new local directory entry */
174 if (entry->changes == NULL) {
175 if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) {
176 _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
177 error = 1;
178 break;
179 }
180 }
181 de = entry->changes;
182
183 if (_zip_read_local_ef(za, i) < 0) {
184 error = 1;
185 break;
186 }
187
188 if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
189 _zip_dirent_torrent_normalize(entry->changes);
190
191
192 de->offset = (zip_uint64_t)ftello(out); /* TODO: check for errors */
193
194 if (new_data) {
195 struct zip_source *zs;
196
197 zs = NULL;
198 if (!ZIP_ENTRY_DATA_CHANGED(entry)) {
199 if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) {
200 error = 1;
201 break;
202 }
203 }
204
205 /* add_data writes dirent */
206 if (add_data(za, zs ? zs : entry->source, de, out) < 0) {
207 error = 1;
208 if (zs)
209 zip_source_free(zs);
210 break;
211 }
212 if (zs)
213 zip_source_free(zs);
214 }
215 else {
216 zip_uint64_t offset;
217
218 /* when copying data, all sizes are known -> no data descriptor needed */
219 de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
220 if (_zip_dirent_write(de, out, ZIP_FL_LOCAL, &za->error) < 0) {
221 error = 1;
222 break;
223 }
224 if ((offset=_zip_file_get_offset(za, i, &za->error)) == 0) {
225 error = 1;
226 break;
227 }
228 if ((fseeko(za->zp, (off_t)offset, SEEK_SET) < 0)) {
229 _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
230 error = 1;
231 break;
232 }
233 if (copy_data(za->zp, de->comp_size, out, &za->error) < 0) {
234 error = 1;
235 break;
236 }
237 }
238 }
239
240 if (!error) {
241 if (write_cdir(za, filelist, survivors, out) < 0)
242 error = 1;
243 }
244
245 free(filelist);
246
247 if (error) {
248 fclose(out);
249 (void)remove(temp);
250 free(temp);
251 return -1;
252 }
253
254 if (fclose(out) != 0) {
255 _zip_error_set(&za->error, ZIP_ER_CLOSE, errno);
256 (void)remove(temp);
257 free(temp);
258 return -1;
259 }
260
261 if (za->zp) {
262 fclose(za->zp);
263 za->zp = NULL;
264 reopen_on_error = 1;
265 }
266 if (_zip_rename(temp, za->zn) != 0) {
267 _zip_error_set(&za->error, ZIP_ER_RENAME, errno);
268 (void)remove(temp);
269 free(temp);
270 if (reopen_on_error) {
271 /* ignore errors, since we're already in an error case */
272 za->zp = fopen(za->zn, "rb");
273 }
274 return -1;
275 }
276 #ifndef _WIN32
277 mask = umask(0);
278 umask(mask);
279 chmod(za->zn, 0666&~mask);
280 #endif
281
282 zip_discard(za);
283 free(temp);
284
285 return 0;
286 }
287
288
289
290 static int
add_data(struct zip * za,struct zip_source * src,struct zip_dirent * de,FILE * ft)291 add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, FILE *ft)
292 {
293 off_t offstart, offdata, offend;
294 struct zip_stat st;
295 struct zip_source *s2;
296 int ret;
297 int is_zip64;
298 zip_flags_t flags;
299
300 if (zip_source_stat(src, &st) < 0) {
301 _zip_error_set_from_source(&za->error, src);
302 return -1;
303 }
304
305 if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {
306 st.valid |= ZIP_STAT_COMP_METHOD;
307 st.comp_method = ZIP_CM_STORE;
308 }
309
310 if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)
311 de->comp_method = st.comp_method;
312 else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
313 st.valid |= ZIP_STAT_COMP_SIZE;
314 st.comp_size = st.size;
315 }
316 else {
317 /* we'll recompress */
318 st.valid &= ~ZIP_STAT_COMP_SIZE;
319 }
320
321
322 flags = ZIP_EF_LOCAL;
323
324 if ((st.valid & ZIP_STAT_SIZE) == 0)
325 flags |= ZIP_FL_FORCE_ZIP64;
326 else {
327 de->uncomp_size = st.size;
328
329 if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
330 if (( ((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32)
331 || (de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method))))
332 flags |= ZIP_FL_FORCE_ZIP64;
333 }
334 else
335 de->comp_size = st.comp_size;
336 }
337
338
339 offstart = ftello(ft);
340
341 /* as long as we don't support non-seekable output, clear data descriptor bit */
342 de->bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
343 if ((is_zip64=_zip_dirent_write(de, ft, flags, &za->error)) < 0)
344 return -1;
345
346
347 if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) {
348 struct zip_source *s_store, *s_crc;
349 zip_compression_implementation comp_impl;
350
351 if (st.comp_method != ZIP_CM_STORE) {
352 if ((comp_impl=_zip_get_compression_implementation(st.comp_method)) == NULL) {
353 _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
354 return -1;
355 }
356 if ((s_store=comp_impl(za, src, st.comp_method, ZIP_CODEC_DECODE)) == NULL) {
357 /* error set by comp_impl */
358 return -1;
359 }
360 }
361 else
362 s_store = src;
363
364 if ((s_crc=zip_source_crc(za, s_store, 0)) == NULL) {
365 if (s_store != src)
366 zip_source_pop(s_store);
367 return -1;
368 }
369
370 /* TODO: deflate 0-byte files for torrentzip? */
371 if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) {
372 if ((comp_impl=_zip_get_compression_implementation(de->comp_method)) == NULL) {
373 _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
374 zip_source_pop(s_crc);
375 if (s_store != src)
376 zip_source_pop(s_store);
377 return -1;
378 }
379 if ((s2=comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE)) == NULL) {
380 zip_source_pop(s_crc);
381 if (s_store != src)
382 zip_source_pop(s_store);
383 return -1;
384 }
385 }
386 else
387 s2 = s_crc;
388 }
389 else
390 s2 = src;
391
392 offdata = ftello(ft);
393
394 ret = copy_source(za, s2, ft);
395
396 if (zip_source_stat(s2, &st) < 0)
397 ret = -1;
398
399 while (s2 != src) {
400 if ((s2=zip_source_pop(s2)) == NULL) {
401 /* TODO: set erorr */
402 ret = -1;
403 break;
404 }
405 }
406
407 if (ret < 0)
408 return -1;
409
410 offend = ftello(ft);
411
412 if (fseeko(ft, offstart, SEEK_SET) < 0) {
413 _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
414 return -1;
415 }
416
417 if ((st.valid & (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD|ZIP_STAT_CRC|ZIP_STAT_SIZE)) {
418 _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
419 return -1;
420 }
421
422 if (st.valid & ZIP_STAT_MTIME)
423 de->last_mod = st.mtime;
424 else
425 time(&de->last_mod);
426 de->comp_method = st.comp_method;
427 de->crc = st.crc;
428 de->uncomp_size = st.size;
429 de->comp_size = (zip_uint64_t)(offend - offdata);
430
431 if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
432 _zip_dirent_torrent_normalize(de);
433
434 if ((ret=_zip_dirent_write(de, ft, flags, &za->error)) < 0)
435 return -1;
436
437 if (is_zip64 != ret) {
438 /* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
439 _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
440 return -1;
441 }
442
443
444 if (fseeko(ft, offend, SEEK_SET) < 0) {
445 _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
446 return -1;
447 }
448
449 return 0;
450 }
451
452
453
454 static int
copy_data(FILE * fs,zip_uint64_t len,FILE * ft,struct zip_error * error)455 copy_data(FILE *fs, zip_uint64_t len, FILE *ft, struct zip_error *error)
456 {
457 char buf[BUFSIZE];
458 size_t n, nn;
459
460 if (len == 0)
461 return 0;
462
463 while (len > 0) {
464 nn = len > sizeof(buf) ? sizeof(buf) : len > SIZE_MAX ? SIZE_MAX : (size_t)len;
465 if ((n=fread(buf, 1, nn, fs)) == 0) {
466 if (ferror(fs)) {
467 _zip_error_set(error, ZIP_ER_READ, errno);
468 return -1;
469 }
470 else {
471 _zip_error_set(error, ZIP_ER_EOF, 0);
472 return -1;
473 }
474 }
475
476 if (fwrite(buf, 1, n, ft) != (size_t)n) {
477 _zip_error_set(error, ZIP_ER_WRITE, errno);
478 return -1;
479 }
480
481 len -= n;
482 }
483
484 return 0;
485 }
486
487
488
489 static int
copy_source(struct zip * za,struct zip_source * src,FILE * ft)490 copy_source(struct zip *za, struct zip_source *src, FILE *ft)
491 {
492 char buf[BUFSIZE];
493 zip_int64_t n;
494 int ret;
495
496 if (zip_source_open(src) < 0) {
497 _zip_error_set_from_source(&za->error, src);
498 return -1;
499 }
500
501 ret = 0;
502 while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) {
503 if (fwrite(buf, 1, (size_t)n, ft) != (size_t)n) {
504 _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
505 ret = -1;
506 break;
507 }
508 }
509
510 if (n < 0) {
511 if (ret == 0)
512 _zip_error_set_from_source(&za->error, src);
513 ret = -1;
514 }
515
516 zip_source_close(src);
517
518 return ret;
519 }
520
521
522
523 static int
write_cdir(struct zip * za,const struct zip_filelist * filelist,zip_uint64_t survivors,FILE * out)524 write_cdir(struct zip *za, const struct zip_filelist *filelist, zip_uint64_t survivors, FILE *out)
525 {
526 off_t cd_start, end;
527 zip_int64_t size;
528 uLong crc;
529 char buf[TORRENT_CRC_LEN+1];
530
531 cd_start = ftello(out);
532
533 if ((size=_zip_cdir_write(za, filelist, survivors, out)) < 0)
534 return -1;
535
536 end = ftello(out);
537
538 if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0)
539 return 0;
540
541
542 /* fix up torrentzip comment */
543
544 if (_zip_filerange_crc(out, cd_start, size, &crc, &za->error) < 0)
545 return -1;
546
547 snprintf(buf, sizeof(buf), "%08lX", (long)crc);
548
549 if (fseeko(out, end-TORRENT_CRC_LEN, SEEK_SET) < 0) {
550 _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
551 return -1;
552 }
553
554 if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) {
555 _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
556 return -1;
557 }
558
559 return 0;
560 }
561
562
563
564 int
_zip_changed(const struct zip * za,zip_uint64_t * survivorsp)565 _zip_changed(const struct zip *za, zip_uint64_t *survivorsp)
566 {
567 int changed;
568 zip_uint64_t i, survivors;
569
570 changed = 0;
571 survivors = 0;
572
573 if (za->comment_changed || za->ch_flags != za->flags)
574 changed = 1;
575
576 for (i=0; i<za->nentry; i++) {
577 if (za->entry[i].deleted || za->entry[i].source || (za->entry[i].changes && za->entry[i].changes->changed != 0))
578 changed = 1;
579 if (!za->entry[i].deleted)
580 survivors++;
581 }
582
583 if (survivorsp)
584 *survivorsp = survivors;
585
586 return changed;
587 }
588
589
590
591 static char *
_zip_create_temp_output(struct zip * za,FILE ** outp)592 _zip_create_temp_output(struct zip *za, FILE **outp)
593 {
594 char *temp;
595 int tfd;
596 FILE *tfp;
597
598 if (za->tempdir) {
599 if ((temp=(char *)malloc(strlen(za->tempdir)+13)) == NULL) {
600 _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
601 return NULL;
602 }
603 sprintf(temp, "%s/.zip.XXXXXX", za->tempdir);
604 }
605 else {
606 if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) {
607 _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
608 return NULL;
609 }
610 sprintf(temp, "%s.XXXXXX", za->zn);
611 }
612
613 if ((tfd=mkstemp(temp)) == -1) {
614 _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno);
615 free(temp);
616 return NULL;
617 }
618
619 if ((tfp=fdopen(tfd, "r+b")) == NULL) {
620 _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno);
621 close(tfd);
622 (void)remove(temp);
623 free(temp);
624 return NULL;
625 }
626
627 #ifdef _WIN32
628 /*
629 According to Pierre Joye, Windows in some environments per
630 default creates text files, so force binary mode.
631 */
632 _setmode(_fileno(tfp), _O_BINARY );
633 #endif
634
635 *outp = tfp;
636 return temp;
637 }
638
639
640
641 static int
_zip_torrentzip_cmp(const void * a,const void * b)642 _zip_torrentzip_cmp(const void *a, const void *b)
643 {
644 const char *aname = ((const struct zip_filelist *)a)->name;
645 const char *bname = ((const struct zip_filelist *)b)->name;
646
647 if (aname == NULL)
648 return (bname != NULL) * -1;
649 else if (bname == NULL)
650 return 1;
651
652 return strcasecmp(aname, bname);
653 }
654