root/ext/zip/lib/zip_open.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zip_open
  2. zip_archive_set_tempdir
  3. _zip_open
  4. set_error
  5. _zip_readcdir
  6. _zip_checkcons
  7. _zip_check_torrentzip
  8. _zip_headercomp
  9. _zip_allocate_new
  10. _zip_file_exists
  11. _zip_find_central_dir
  12. _zip_memmem
  13. _zip_read_eocd
  14. _zip_read_eocd64

   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 *
  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     /* 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
 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 *
 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
 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
 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
 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 *
 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     /* 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 *
 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 *
 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     /* 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 *
 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 ((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 }

/* [<][>][^][v][top][bottom][index][help] */