This source file includes following definitions.
- zip_open
- zip_archive_set_tempdir
- _zip_open
- set_error
- _zip_readcdir
- _zip_checkcons
- _zip_check_torrentzip
- _zip_headercomp
- _zip_allocate_new
- _zip_file_exists
- _zip_find_central_dir
- _zip_memmem
- _zip_read_eocd
- _zip_read_eocd64
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 <sys/stat.h>
37 #include <errno.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "zipint.h"
44
45 static void set_error(int *, const struct zip_error *, int);
46 static struct zip *_zip_allocate_new(const char *, unsigned int, int *);
47 static zip_int64_t _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
48 static void _zip_check_torrentzip(struct zip *, const struct zip_cdir *);
49 static struct zip_cdir *_zip_find_central_dir(FILE *, unsigned int, int *, off_t);
50 static int _zip_file_exists(const char *, unsigned int, int *);
51 static int _zip_headercomp(const struct zip_dirent *, const struct zip_dirent *);
52 static unsigned char *_zip_memmem(const unsigned char *, size_t,
53 const unsigned char *, size_t);
54 static struct zip_cdir *_zip_readcdir(FILE *, off_t, unsigned char *, const unsigned char *,
55 size_t, unsigned int, struct zip_error *);
56 static struct zip_cdir *_zip_read_eocd(const unsigned char *, const unsigned char *, off_t,
57 size_t, unsigned int, struct zip_error *);
58 static struct zip_cdir *_zip_read_eocd64(FILE *, const unsigned char *, const unsigned char *,
59 off_t, size_t, unsigned int, struct zip_error *);
60
61
62
63 ZIP_EXTERN struct zip *
64 zip_open(const char *fn, int _flags, int *zep)
65 {
66 FILE *fp;
67 unsigned int flags;
68
69 if (_flags < 0) {
70 if (zep)
71 *zep = ZIP_ER_INVAL;
72 return NULL;
73 }
74 flags = (unsigned int)_flags;
75
76 switch (_zip_file_exists(fn, flags, zep)) {
77 case -1:
78 return NULL;
79 case 0:
80 return _zip_allocate_new(fn, flags, zep);
81 default:
82 if (flags & ZIP_TRUNCATE) {
83 FILE *f;
84
85 if ((f = fopen(fn, "rb")) == NULL) {
86 set_error(zep, NULL, ZIP_ER_OPEN);
87 return NULL;
88 }
89 fclose(f);
90 return _zip_allocate_new(fn, flags, zep);
91 }
92 break;
93 }
94
95 if ((fp=fopen(fn, "rb")) == NULL) {
96 set_error(zep, NULL, ZIP_ER_OPEN);
97 return NULL;
98 }
99
100 return _zip_open(fn, fp, flags, zep);
101 }
102
103
104 ZIP_EXTERN int
105 zip_archive_set_tempdir(struct zip *za, const char *tempdir)
106 {
107 char *new_tempdir;
108
109 if (tempdir) {
110 if ((new_tempdir = strdup(tempdir)) == NULL) {
111 _zip_error_set(&za->error, ZIP_ER_MEMORY, errno);
112 return -1;
113 }
114 }
115 else
116 new_tempdir = NULL;
117
118 free(za->tempdir);
119 za->tempdir = new_tempdir;
120
121 return 0;
122 }
123
124
125 struct zip *
126 _zip_open(const char *fn, FILE *fp, unsigned int flags, int *zep)
127 {
128 struct zip *za;
129 struct zip_cdir *cdir;
130 off_t len;
131
132 if (fseeko(fp, 0, SEEK_END) < 0) {
133 *zep = ZIP_ER_SEEK;
134 return NULL;
135 }
136 len = ftello(fp);
137
138
139 if (len == 0) {
140 if ((za=_zip_allocate_new(fn, flags, zep)) == NULL)
141 fclose(fp);
142 else
143 za->zp = fp;
144 return za;
145 }
146
147 cdir = _zip_find_central_dir(fp, flags, zep, len);
148 if (cdir == NULL) {
149 fclose(fp);
150 return NULL;
151 }
152
153 if ((za=_zip_allocate_new(fn, flags, zep)) == NULL) {
154 _zip_cdir_free(cdir);
155 fclose(fp);
156 return NULL;
157 }
158
159 za->entry = cdir->entry;
160 za->nentry = cdir->nentry;
161 za->nentry_alloc = cdir->nentry_alloc;
162 za->comment_orig = cdir->comment;
163
164 za->zp = fp;
165
166 _zip_check_torrentzip(za, cdir);
167
168 za->ch_flags = za->flags;
169
170 free(cdir);
171
172 return za;
173 }
174
175
176
177 static void
178 set_error(int *zep, const struct zip_error *err, int ze)
179 {
180 int se;
181
182 if (err) {
183 _zip_error_get(err, &ze, &se);
184 if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
185 errno = se;
186 }
187
188 if (zep)
189 *zep = ze;
190 }
191
192
193
194
195
196
197
198
199
200 static struct zip_cdir *
201 _zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, const unsigned char *eocd, size_t buflen,
202 unsigned int flags, struct zip_error *error)
203 {
204 struct zip_cdir *cd;
205 const unsigned char *cdp;
206 const unsigned char **bufp;
207 zip_int64_t tail_len, comment_len;
208 zip_uint64_t i, left;
209
210 tail_len = buf + buflen - eocd - EOCDLEN;
211 if (tail_len < 0) {
212
213 _zip_error_set(error, ZIP_ER_NOZIP, 0);
214 return NULL;
215 }
216
217
218 if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
219 _zip_error_set(error, ZIP_ER_NOZIP, 0);
220 return NULL;
221 }
222
223 if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
224 _zip_error_set(error, ZIP_ER_MULTIDISK, 0);
225 return NULL;
226 }
227
228 if (eocd-EOCD64LOCLEN >= buf && memcmp(eocd-EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0)
229 cd = _zip_read_eocd64(fp, eocd-EOCD64LOCLEN, buf, buf_offset, buflen, flags, error);
230 else
231 cd = _zip_read_eocd(eocd, buf, buf_offset, buflen, flags, error);
232
233 if (cd == NULL)
234 return NULL;
235
236 cdp = eocd + 20;
237 comment_len = _zip_read2(&cdp);
238
239 if ((zip_uint64_t)cd->offset+(zip_uint64_t)cd->size > (zip_uint64_t)buf_offset + (zip_uint64_t)(eocd-buf)) {
240
241 _zip_error_set(error, ZIP_ER_INCONS, 0);
242 _zip_cdir_free(cd);
243 return NULL;
244 }
245
246 if (tail_len < comment_len || ((flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
247 _zip_error_set(error, ZIP_ER_INCONS, 0);
248 _zip_cdir_free(cd);
249 return NULL;
250 }
251
252 if (comment_len) {
253 if ((cd->comment=_zip_string_new(eocd+EOCDLEN, (zip_uint16_t)comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
254 _zip_cdir_free(cd);
255 return NULL;
256 }
257 }
258
259 if (cd->offset >= buf_offset) {
260
261 cdp = buf + (cd->offset - buf_offset);
262 bufp = &cdp;
263 }
264 else {
265
266 bufp = NULL;
267 clearerr(fp);
268 fseeko(fp, cd->offset, SEEK_SET);
269
270
271 if (ferror(fp) || (ftello(fp) != cd->offset)) {
272
273 if (ferror(fp))
274 _zip_error_set(error, ZIP_ER_SEEK, errno);
275 else
276 _zip_error_set(error, ZIP_ER_NOZIP, 0);
277 _zip_cdir_free(cd);
278 return NULL;
279 }
280 }
281
282 left = (zip_uint64_t)cd->size;
283 i=0;
284 while (i<cd->nentry && left > 0) {
285 if ((cd->entry[i].orig=_zip_dirent_new()) == NULL
286 || (_zip_dirent_read(cd->entry[i].orig, fp, bufp, &left, 0, error)) < 0) {
287 _zip_cdir_free(cd);
288 return NULL;
289 }
290 i++;
291 }
292 if (i != cd->nentry || ((flags & ZIP_CHECKCONS) && left != 0)) {
293 _zip_error_set(error, ZIP_ER_INCONS, 0);
294 _zip_cdir_free(cd);
295 return NULL;
296 }
297
298 return cd;
299 }
300
301
302
303
304
305
306
307
308
309 static zip_int64_t
310 _zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
311 {
312 zip_uint64_t i;
313 zip_uint64_t min, max, j;
314 struct zip_dirent temp;
315
316 if (cd->nentry) {
317 max = cd->entry[0].orig->offset;
318 min = cd->entry[0].orig->offset;
319 }
320 else
321 min = max = 0;
322
323 for (i=0; i<cd->nentry; i++) {
324 if (cd->entry[i].orig->offset < min)
325 min = cd->entry[i].orig->offset;
326 if (min > (zip_uint64_t)cd->offset) {
327 _zip_error_set(error, ZIP_ER_NOZIP, 0);
328 return -1;
329 }
330
331 j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
332 + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
333 if (j > max)
334 max = j;
335 if (max > (zip_uint64_t)cd->offset) {
336 _zip_error_set(error, ZIP_ER_NOZIP, 0);
337 return -1;
338 }
339
340 if (fseeko(fp, (off_t)cd->entry[i].orig->offset, SEEK_SET) != 0) {
341 _zip_error_set(error, ZIP_ER_SEEK, errno);
342 return -1;
343 }
344
345 if (_zip_dirent_read(&temp, fp, NULL, NULL, 1, error) == -1)
346 return -1;
347
348 if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
349 _zip_error_set(error, ZIP_ER_INCONS, 0);
350 _zip_dirent_finalize(&temp);
351 return -1;
352 }
353
354 cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
355 cd->entry[i].orig->local_extra_fields_read = 1;
356 temp.extra_fields = NULL;
357
358 _zip_dirent_finalize(&temp);
359 }
360
361 return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
362 }
363
364
365
366
367
368
369 static void
370 _zip_check_torrentzip(struct zip *za, const struct zip_cdir *cdir)
371 {
372 uLong crc_got, crc_should;
373 char buf[8+1];
374 char *end;
375
376 if (za->zp == NULL || cdir == NULL)
377 return;
378
379 if (_zip_string_length(cdir->comment) != TORRENT_SIG_LEN+8
380 || strncmp((const char *)cdir->comment->raw, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
381 return;
382
383 memcpy(buf, cdir->comment->raw+TORRENT_SIG_LEN, 8);
384 buf[8] = '\0';
385 errno = 0;
386 crc_should = strtoul(buf, &end, 16);
387 if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
388 return;
389
390 if (_zip_filerange_crc(za->zp, cdir->offset, cdir->size, &crc_got, NULL) < 0)
391 return;
392
393 if (crc_got == crc_should)
394 za->flags |= ZIP_AFL_TORRENT;
395 }
396
397
398
399
400
401
402
403
404 static int
405 _zip_headercomp(const struct zip_dirent *central, const struct zip_dirent *local)
406 {
407 if ((central->version_needed != local->version_needed)
408 #if 0
409
410
411 || (central->bitflags != local->bitflags)
412 #endif
413 || (central->comp_method != local->comp_method)
414 || (central->last_mod != local->last_mod)
415 || !_zip_string_equal(central->filename, local->filename))
416 return -1;
417
418
419 if ((central->crc != local->crc) || (central->comp_size != local->comp_size)
420 || (central->uncomp_size != local->uncomp_size)) {
421
422
423 if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0
424 || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0))
425 return -1;
426 }
427
428 return 0;
429 }
430
431
432
433 static struct zip *
434 _zip_allocate_new(const char *fn, unsigned int flags, int *zep)
435 {
436 struct zip *za;
437 struct zip_error error;
438
439 if ((za=_zip_new(&error)) == NULL) {
440 set_error(zep, &error, 0);
441 return NULL;
442 }
443
444 if (fn == NULL)
445 za->zn = NULL;
446 else {
447 za->zn = strdup(fn);
448 if (!za->zn) {
449 zip_discard(za);
450 set_error(zep, NULL, ZIP_ER_MEMORY);
451 return NULL;
452 }
453 }
454 za->open_flags = flags;
455 return za;
456 }
457
458
459
460 static int
461 _zip_file_exists(const char *fn, unsigned int flags, int *zep)
462 {
463 struct stat st;
464
465 if (fn == NULL) {
466 set_error(zep, NULL, ZIP_ER_INVAL);
467 return -1;
468 }
469
470 if (stat(fn, &st) != 0) {
471 if (flags & ZIP_CREATE)
472 return 0;
473 else {
474 set_error(zep, NULL, ZIP_ER_OPEN);
475 return -1;
476 }
477 }
478 else if ((flags & ZIP_EXCL)) {
479 set_error(zep, NULL, ZIP_ER_EXISTS);
480 return -1;
481 }
482
483
484
485 return 1;
486 }
487
488
489
490 static struct zip_cdir *
491 _zip_find_central_dir(FILE *fp, unsigned int flags, int *zep, off_t len)
492 {
493 struct zip_cdir *cdir, *cdirnew;
494 unsigned char *buf, *match;
495 off_t buf_offset;
496 size_t buflen;
497 zip_int64_t a, i;
498 zip_int64_t best;
499 struct zip_error zerr;
500
501 if (len < (off_t)EOCDLEN) {
502 set_error(zep, NULL, ZIP_ER_NOZIP);
503 return NULL;
504 }
505
506 i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
507 if (i == -1 && errno != EFBIG) {
508
509 set_error(zep, NULL, ZIP_ER_SEEK);
510 return NULL;
511 }
512 buf_offset = ftello(fp);
513
514
515 if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) {
516 set_error(zep, NULL, ZIP_ER_MEMORY);
517 return NULL;
518 }
519
520 clearerr(fp);
521 buflen = fread(buf, 1, CDBUFSIZE, fp);
522
523 if (ferror(fp)) {
524 set_error(zep, NULL, ZIP_ER_READ);
525 free(buf);
526 return NULL;
527 }
528
529 best = -1;
530 cdir = NULL;
531 match = buf+ (buflen < CDBUFSIZE ? 0 : EOCD64LOCLEN);
532 _zip_error_set(&zerr, ZIP_ER_NOZIP, 0);
533
534 while ((match=_zip_memmem(match, buflen-(size_t)(match-buf)-(EOCDLEN-4),
535 (const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
536
537
538 match++;
539 if ((cdirnew=_zip_readcdir(fp, buf_offset, buf, match-1, buflen, flags,
540 &zerr)) == NULL)
541 continue;
542
543 if (cdir) {
544 if (best <= 0)
545 best = _zip_checkcons(fp, cdir, &zerr);
546 a = _zip_checkcons(fp, cdirnew, &zerr);
547 if (best < a) {
548 _zip_cdir_free(cdir);
549 cdir = cdirnew;
550 best = a;
551 }
552 else
553 _zip_cdir_free(cdirnew);
554 }
555 else {
556 cdir = cdirnew;
557 if (flags & ZIP_CHECKCONS)
558 best = _zip_checkcons(fp, cdir, &zerr);
559 else
560 best = 0;
561 }
562 cdirnew = NULL;
563 }
564
565 free(buf);
566
567 if (best < 0) {
568 set_error(zep, &zerr, 0);
569 _zip_cdir_free(cdir);
570 return NULL;
571 }
572
573 return cdir;
574 }
575
576
577
578 static unsigned char *
579 _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen)
580 {
581 const unsigned char *p;
582
583 if ((biglen < littlelen) || (littlelen == 0))
584 return NULL;
585 p = big-1;
586 while ((p=(const unsigned char *)
587 memchr(p+1, little[0], (size_t)(big-(p+1))+(size_t)(biglen-littlelen)+1)) != NULL) {
588 if (memcmp(p+1, little+1, littlelen-1)==0)
589 return (unsigned char *)p;
590 }
591
592 return NULL;
593 }
594
595
596
597 static struct zip_cdir *
598 _zip_read_eocd(const unsigned char *eocd, const unsigned char *buf, off_t buf_offset, size_t buflen,
599 unsigned int flags, struct zip_error *error)
600 {
601 struct zip_cdir *cd;
602 const unsigned char *cdp;
603 zip_uint64_t i, nentry, size, offset;
604
605 if (eocd+EOCDLEN > buf+buflen) {
606 _zip_error_set(error, ZIP_ER_INCONS, 0);
607 return NULL;
608 }
609
610 cdp = eocd + 8;
611
612
613 i = _zip_read2(&cdp);
614
615 nentry = _zip_read2(&cdp);
616
617 if (nentry != i) {
618 _zip_error_set(error, ZIP_ER_NOZIP, 0);
619 return NULL;
620 }
621
622 size = _zip_read4(&cdp);
623 offset = _zip_read4(&cdp);
624
625 if (size > ZIP_OFF_MAX || offset > ZIP_OFF_MAX || offset+size > ZIP_OFF_MAX) {
626 _zip_error_set(error, ZIP_ER_SEEK, EFBIG);
627 return NULL;
628 }
629
630 if (offset+size > (zip_uint64_t)(buf_offset + (eocd-buf))) {
631
632 _zip_error_set(error, ZIP_ER_INCONS, 0);
633 return NULL;
634 }
635
636 if ((flags & ZIP_CHECKCONS) && offset+size != (zip_uint64_t)(buf_offset + (eocd-buf))) {
637 _zip_error_set(error, ZIP_ER_INCONS, 0);
638 return NULL;
639 }
640
641 if ((cd=_zip_cdir_new(nentry, error)) == NULL)
642 return NULL;
643
644 cd->size = (off_t)size;
645 cd->offset = (off_t)offset;
646
647 return cd;
648 }
649
650
651
652 static struct zip_cdir *
653 _zip_read_eocd64(FILE *f, const zip_uint8_t *eocd64loc, const zip_uint8_t *buf,
654 off_t buf_offset, size_t buflen, unsigned int flags, struct zip_error *error)
655 {
656 struct zip_cdir *cd;
657 zip_uint64_t offset;
658 const zip_uint8_t *cdp;
659 zip_uint8_t eocd[EOCD64LEN];
660 zip_uint64_t eocd_offset;
661 zip_uint64_t size, nentry, i;
662
663 cdp = eocd64loc+8;
664 eocd_offset = _zip_read8(&cdp);
665
666 if (eocd_offset > ZIP_OFF_MAX || eocd_offset + EOCD64LEN > ZIP_OFF_MAX) {
667 _zip_error_set(error, ZIP_ER_SEEK, EFBIG);
668 return NULL;
669 }
670
671 if (eocd64loc < buf || (off_t)eocd_offset+EOCD64LEN > (buf_offset+(eocd64loc-buf))) {
672 _zip_error_set(error, ZIP_ER_INCONS, 0);
673 return NULL;
674 }
675
676 if ((off_t)eocd_offset >= buf_offset && (off_t)eocd_offset+EOCD64LEN <= buf_offset+(ssize_t)buflen)
677 cdp = buf+((off_t)eocd_offset-buf_offset);
678 else {
679 if (fseeko(f, (off_t)eocd_offset, SEEK_SET) != 0) {
680 _zip_error_set(error, ZIP_ER_SEEK, errno);
681 return NULL;
682 }
683
684 clearerr(f);
685 if (fread(eocd, 1, EOCD64LEN, f) < EOCD64LEN) {
686 _zip_error_set(error, ZIP_ER_READ, errno);
687 return NULL;
688 }
689
690 if (ferror(f)) {
691 _zip_error_set(error, ZIP_ER_READ, errno);
692 return NULL;
693 }
694
695 cdp = eocd;
696 }
697
698 if (memcmp(cdp, EOCD64_MAGIC, 4) != 0) {
699 _zip_error_set(error, ZIP_ER_INCONS, 0);
700 return NULL;
701 }
702 cdp += 4;
703
704 size = _zip_read8(&cdp);
705
706 if ((flags & ZIP_CHECKCONS) && size+eocd_offset+12 != (zip_uint64_t)(buf_offset+(eocd64loc-buf))) {
707 _zip_error_set(error, ZIP_ER_INCONS, 0);
708 return NULL;
709 }
710
711 cdp += 4;
712 cdp += 8;
713
714 nentry = _zip_read8(&cdp);
715 i = _zip_read8(&cdp);
716
717 if (nentry != i) {
718 _zip_error_set(error, ZIP_ER_MULTIDISK, 0);
719 return NULL;
720 }
721
722 size = _zip_read8(&cdp);
723 offset = _zip_read8(&cdp);
724
725 if (size > ZIP_OFF_MAX || offset > ZIP_OFF_MAX || offset+size > ZIP_OFF_MAX) {
726 _zip_error_set(error, ZIP_ER_SEEK, EFBIG);
727 return NULL;
728 }
729 if ((flags & ZIP_CHECKCONS) && offset+size != eocd_offset) {
730 _zip_error_set(error, ZIP_ER_INCONS, 0);
731 return NULL;
732 }
733
734 if ((cd=_zip_cdir_new(nentry, error)) == NULL)
735 return NULL;
736
737
738 cd->size = (off_t)size;
739 cd->offset = (off_t)offset;
740
741 return cd;
742 }