This source file includes following definitions.
- zip_close
- add_data
- copy_data
- copy_source
- write_cdir
- _zip_changed
- _zip_create_temp_output
- _zip_torrentzip_cmp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
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
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
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
117 if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) {
118
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
125
126
127
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
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);
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
630
631
632 _setmode(_fileno(tfp), _O_BINARY );
633 #endif
634
635 *outp = tfp;
636 return temp;
637 }
638
639
640
641 static int
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 }