1 /*
2 zip_open.c -- open zip archive by name
3 Copyright (C) 1999-2012 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 <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 *
zip_open(const char * fn,int _flags,int * zep)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
zip_archive_set_tempdir(struct zip * za,const char * tempdir)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 *
_zip_open(const char * fn,FILE * fp,unsigned int flags,int * zep)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 /* treat empty files as empty archives */
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
set_error(int * zep,const struct zip_error * err,int ze)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 /* _zip_readcdir:
195 tries to find a valid end-of-central-directory at the beginning of
196 buf, and then the corresponding central directory entries.
197 Returns a struct zip_cdir which contains the central directory
198 entries, or NULL if unsuccessful. */
199
200 static struct zip_cdir *
_zip_readcdir(FILE * fp,off_t buf_offset,unsigned char * buf,const unsigned char * eocd,size_t buflen,unsigned int flags,struct zip_error * error)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 /* not enough bytes left for comment */
213 _zip_error_set(error, ZIP_ER_NOZIP, 0);
214 return NULL;
215 }
216
217 /* check for end-of-central-dir magic */
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 /* cdir spans past EOCD record */
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 /* if buffer already read in, use it */
261 cdp = buf + (cd->offset - buf_offset);
262 bufp = &cdp;
263 }
264 else {
265 /* go to start of cdir and read it entry by entry */
266 bufp = NULL;
267 clearerr(fp);
268 fseeko(fp, cd->offset, SEEK_SET);
269 /* possible consistency check: cd->offset =
270 len-(cd->size+cd->comment_len+EOCDLEN) ? */
271 if (ferror(fp) || (ftello(fp) != cd->offset)) {
272 /* seek error or offset of cdir wrong */
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 /* _zip_checkcons:
304 Checks the consistency of the central directory by comparing central
305 directory entries with local headers and checking for plausible
306 file and header offsets. Returns -1 if not plausible, else the
307 difference between the lowest and the highest fileposition reached */
308
309 static zip_int64_t
_zip_checkcons(FILE * fp,struct zip_cdir * cd,struct zip_error * error)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 /* _zip_check_torrentzip:
367 check whether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
368
369 static void
_zip_check_torrentzip(struct zip * za,const struct zip_cdir * cdir)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 /* _zip_headercomp:
401 compares a central directory entry and a local file header
402 Return 0 if they are consistent, -1 if not. */
403
404 static int
_zip_headercomp(const struct zip_dirent * central,const struct zip_dirent * local)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 /* some zip-files have different values in local
410 and global headers for the bitflags */
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 /* InfoZip stores valid values in local header even when data descriptor is used.
422 This is in violation of the appnote. */
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 *
_zip_allocate_new(const char * fn,unsigned int flags,int * zep)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
_zip_file_exists(const char * fn,unsigned int flags,int * zep)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 /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
483 just like open() */
484
485 return 1;
486 }
487
488
489
490 static struct zip_cdir *
_zip_find_central_dir(FILE * fp,unsigned int flags,int * zep,off_t len)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 /* seek before start of file on my machine */
509 set_error(zep, NULL, ZIP_ER_SEEK);
510 return NULL;
511 }
512 buf_offset = ftello(fp);
513
514 /* 64k is too much for stack */
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 /* found match -- check, if good */
537 /* to avoid finding the same match all over again */
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 *
_zip_memmem(const unsigned char * big,size_t biglen,const unsigned char * little,size_t littlelen)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 *
_zip_read_eocd(const unsigned char * eocd,const unsigned char * buf,off_t buf_offset,size_t buflen,unsigned int flags,struct zip_error * error)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 /* number of cdir-entries on this disk */
613 i = _zip_read2(&cdp);
614 /* number of cdir-entries */
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 /* cdir spans past EOCD record */
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 *
_zip_read_eocd64(FILE * f,const zip_uint8_t * eocd64loc,const zip_uint8_t * buf,off_t buf_offset,size_t buflen,unsigned int flags,struct zip_error * error)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; /* skip version made by/needed */
712 cdp += 8; /* skip num disks */
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 (offset+size > buf_offset + eocd_offset) {
730 /* cdir spans past EOCD record */
731 _zip_error_set(error, ZIP_ER_INCONS, 0);
732 return NULL;
733 }
734 if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
735 _zip_error_set(error, ZIP_ER_INCONS, 0);
736 return NULL;
737 }
738
739 if ((cd=_zip_cdir_new(nentry, error)) == NULL)
740 return NULL;
741
742
743 cd->size = (off_t)size;
744 cd->offset = (off_t)offset;
745
746 return cd;
747 }
748