"Fossies" - the Fresh Open Source Software Archive

Member "libzip-1.5.2/lib/zip_open.c" (12 Mar 2019, 23560 Bytes) of package /linux/misc/libzip-1.5.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zip_open.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.1_vs_1.5.2.

    1 /*
    2   zip_open.c -- open zip archive by name
    3   Copyright (C) 1999-2018 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 #include <limits.h>
   36 #include <stdio.h>
   37 #include <stdlib.h>
   38 #include <string.h>
   39 #include <sys/stat.h>
   40 
   41 #include "zipint.h"
   42 
   43 typedef enum {
   44     EXISTS_ERROR = -1,
   45     EXISTS_NOT = 0,
   46     EXISTS_EMPTY,
   47     EXISTS_NONEMPTY,
   48 } exists_t;
   49 static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);
   50 static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);
   51 static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);
   52 static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error);
   53 static int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *);
   54 static unsigned char *_zip_memmem(const unsigned char *, size_t, const unsigned char *, size_t);
   55 static zip_cdir_t *_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error);
   56 static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
   57 static zip_cdir_t *_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
   58 
   59 
   60 ZIP_EXTERN zip_t *
   61 zip_open(const char *fn, int _flags, int *zep) {
   62     zip_t *za;
   63     zip_source_t *src;
   64     struct zip_error error;
   65 
   66     zip_error_init(&error);
   67     if ((src = zip_source_file_create(fn, 0, -1, &error)) == NULL) {
   68     _zip_set_open_error(zep, &error, 0);
   69     zip_error_fini(&error);
   70     return NULL;
   71     }
   72 
   73     if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {
   74     zip_source_free(src);
   75     _zip_set_open_error(zep, &error, 0);
   76     zip_error_fini(&error);
   77     return NULL;
   78     }
   79 
   80     zip_error_fini(&error);
   81     return za;
   82 }
   83 
   84 
   85 ZIP_EXTERN zip_t *
   86 zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error) {
   87     static zip_int64_t needed_support_read = -1;
   88     static zip_int64_t needed_support_write = -1;
   89 
   90     unsigned int flags;
   91     zip_int64_t supported;
   92     exists_t exists;
   93 
   94     if (_flags < 0 || src == NULL) {
   95     zip_error_set(error, ZIP_ER_INVAL, 0);
   96     return NULL;
   97     }
   98     flags = (unsigned int)_flags;
   99 
  100     supported = zip_source_supports(src);
  101     if (needed_support_read == -1) {
  102     needed_support_read = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_STAT, -1);
  103     needed_support_write = zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1);
  104     }
  105     if ((supported & needed_support_read) != needed_support_read) {
  106     zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
  107     return NULL;
  108     }
  109     if ((supported & needed_support_write) != needed_support_write) {
  110     flags |= ZIP_RDONLY;
  111     }
  112 
  113     if ((flags & (ZIP_RDONLY | ZIP_TRUNCATE)) == (ZIP_RDONLY | ZIP_TRUNCATE)) {
  114     zip_error_set(error, ZIP_ER_RDONLY, 0);
  115     return NULL;
  116     }
  117 
  118     exists = _zip_file_exists(src, error);
  119     switch (exists) {
  120     case EXISTS_ERROR:
  121     return NULL;
  122 
  123     case EXISTS_NOT:
  124     if ((flags & ZIP_CREATE) == 0) {
  125         zip_error_set(error, ZIP_ER_NOENT, 0);
  126         return NULL;
  127     }
  128     return _zip_allocate_new(src, flags, error);
  129 
  130     default: {
  131     zip_t *za;
  132     if (flags & ZIP_EXCL) {
  133         zip_error_set(error, ZIP_ER_EXISTS, 0);
  134         return NULL;
  135     }
  136     if (zip_source_open(src) < 0) {
  137         _zip_error_set_from_source(error, src);
  138         return NULL;
  139     }
  140 
  141     if (flags & ZIP_TRUNCATE) {
  142         za = _zip_allocate_new(src, flags, error);
  143     }
  144     else {
  145         /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */
  146         za = _zip_open(src, flags, error);
  147     }
  148 
  149     if (za == NULL) {
  150         zip_source_close(src);
  151         return NULL;
  152     }
  153     return za;
  154     }
  155     }
  156 }
  157 
  158 
  159 zip_t *
  160 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) {
  161     zip_t *za;
  162     zip_cdir_t *cdir;
  163     struct zip_stat st;
  164     zip_uint64_t len, idx;
  165 
  166     zip_stat_init(&st);
  167     if (zip_source_stat(src, &st) < 0) {
  168     _zip_error_set_from_source(error, src);
  169     return NULL;
  170     }
  171     if ((st.valid & ZIP_STAT_SIZE) == 0) {
  172     zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);
  173     return NULL;
  174     }
  175     len = st.size;
  176 
  177     /* treat empty files as empty archives */
  178     if (len == 0) {
  179     if ((za = _zip_allocate_new(src, flags, error)) == NULL) {
  180         return NULL;
  181     }
  182 
  183     return za;
  184     }
  185 
  186     if ((za = _zip_allocate_new(src, flags, error)) == NULL) {
  187     return NULL;
  188     }
  189 
  190     if ((cdir = _zip_find_central_dir(za, len)) == NULL) {
  191     _zip_error_copy(error, &za->error);
  192     /* keep src so discard does not get rid of it */
  193     zip_source_keep(src);
  194     zip_discard(za);
  195     return NULL;
  196     }
  197 
  198     za->entry = cdir->entry;
  199     za->nentry = cdir->nentry;
  200     za->nentry_alloc = cdir->nentry_alloc;
  201     za->comment_orig = cdir->comment;
  202 
  203     free(cdir);
  204 
  205     _zip_hash_reserve_capacity(za->names, za->nentry, &za->error);
  206 
  207     for (idx = 0; idx < za->nentry; idx++) {
  208     const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);
  209     if (name == NULL) {
  210         /* keep src so discard does not get rid of it */
  211         zip_source_keep(src);
  212         zip_discard(za);
  213         return NULL;
  214     }
  215 
  216     if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) {
  217         if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) {
  218         _zip_error_copy(error, &za->error);
  219         /* keep src so discard does not get rid of it */
  220         zip_source_keep(src);
  221         zip_discard(za);
  222         return NULL;
  223         }
  224     }
  225     }
  226 
  227     za->ch_flags = za->flags;
  228 
  229     return za;
  230 }
  231 
  232 
  233 void
  234 _zip_set_open_error(int *zep, const zip_error_t *err, int ze) {
  235     if (err) {
  236     ze = zip_error_code_zip(err);
  237     if (zip_error_system_type(err) == ZIP_ET_SYS) {
  238         errno = zip_error_code_system(err);
  239     }
  240     }
  241 
  242     if (zep)
  243     *zep = ze;
  244 }
  245 
  246 
  247 /* _zip_readcdir:
  248    tries to find a valid end-of-central-directory at the beginning of
  249    buf, and then the corresponding central directory entries.
  250    Returns a struct zip_cdir which contains the central directory
  251    entries, or NULL if unsuccessful. */
  252 
  253 static zip_cdir_t *
  254 _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error) {
  255     zip_cdir_t *cd;
  256     zip_uint16_t comment_len;
  257     zip_uint64_t i, left;
  258     zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);
  259     zip_buffer_t *cd_buffer;
  260 
  261     if (_zip_buffer_left(buffer) < EOCDLEN) {
  262     /* not enough bytes left for comment */
  263     zip_error_set(error, ZIP_ER_NOZIP, 0);
  264     return NULL;
  265     }
  266 
  267     /* check for end-of-central-dir magic */
  268     if (memcmp(_zip_buffer_get(buffer, 4), EOCD_MAGIC, 4) != 0) {
  269     zip_error_set(error, ZIP_ER_NOZIP, 0);
  270     return NULL;
  271     }
  272 
  273     if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {
  274     _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);
  275     cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error);
  276     }
  277     else {
  278     _zip_buffer_set_offset(buffer, eocd_offset);
  279     cd = _zip_read_eocd(buffer, buf_offset, za->flags, error);
  280     }
  281 
  282     if (cd == NULL)
  283     return NULL;
  284 
  285     _zip_buffer_set_offset(buffer, eocd_offset + 20);
  286     comment_len = _zip_buffer_get_16(buffer);
  287 
  288     if (cd->offset + cd->size > buf_offset + eocd_offset) {
  289     /* cdir spans past EOCD record */
  290     zip_error_set(error, ZIP_ER_INCONS, 0);
  291     _zip_cdir_free(cd);
  292     return NULL;
  293     }
  294 
  295     if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
  296     zip_uint64_t tail_len;
  297 
  298     _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
  299     tail_len = _zip_buffer_left(buffer);
  300 
  301     if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
  302         zip_error_set(error, ZIP_ER_INCONS, 0);
  303         _zip_cdir_free(cd);
  304         return NULL;
  305     }
  306 
  307     if (comment_len) {
  308         if ((cd->comment = _zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
  309         _zip_cdir_free(cd);
  310         return NULL;
  311         }
  312     }
  313     }
  314 
  315     if (cd->offset >= buf_offset) {
  316     zip_uint8_t *data;
  317     /* if buffer already read in, use it */
  318     _zip_buffer_set_offset(buffer, cd->offset - buf_offset);
  319 
  320     if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
  321         zip_error_set(error, ZIP_ER_INCONS, 0);
  322         _zip_cdir_free(cd);
  323         return NULL;
  324     }
  325     if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
  326         zip_error_set(error, ZIP_ER_MEMORY, 0);
  327         _zip_cdir_free(cd);
  328         return NULL;
  329     }
  330     }
  331     else {
  332     cd_buffer = NULL;
  333 
  334     if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
  335         _zip_error_set_from_source(error, za->src);
  336         _zip_cdir_free(cd);
  337         return NULL;
  338     }
  339 
  340     /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */
  341     if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {
  342         zip_error_set(error, ZIP_ER_NOZIP, 0);
  343         _zip_cdir_free(cd);
  344         return NULL;
  345     }
  346     }
  347 
  348     left = (zip_uint64_t)cd->size;
  349     i = 0;
  350     while (left > 0) {
  351     bool grown = false;
  352     zip_int64_t entry_size;
  353 
  354     if (i == cd->nentry) {
  355         /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */
  356         /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */
  357 
  358         if (cd->is_zip64 || left < CDENTRYSIZE) {
  359         break;
  360         }
  361 
  362         if (!_zip_cdir_grow(cd, 0x10000, error)) {
  363         _zip_cdir_free(cd);
  364         _zip_buffer_free(cd_buffer);
  365         return NULL;
  366         }
  367         grown = true;
  368     }
  369 
  370     if ((cd->entry[i].orig = _zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, error)) < 0) {
  371         if (grown && zip_error_code_zip(error) == ZIP_ER_NOZIP) {
  372         zip_error_set(error, ZIP_ER_INCONS, 0);
  373         }
  374         _zip_cdir_free(cd);
  375         _zip_buffer_free(cd_buffer);
  376         return NULL;
  377     }
  378     i++;
  379     left -= (zip_uint64_t)entry_size;
  380     }
  381 
  382     if (i != cd->nentry || left > 0) {
  383     zip_error_set(error, ZIP_ER_INCONS, 0);
  384     _zip_buffer_free(cd_buffer);
  385     _zip_cdir_free(cd);
  386     return NULL;
  387     }
  388 
  389     if (za->open_flags & ZIP_CHECKCONS) {
  390     bool ok;
  391 
  392     if (cd_buffer) {
  393         ok = _zip_buffer_eof(cd_buffer);
  394     }
  395     else {
  396         zip_int64_t offset = zip_source_tell(za->src);
  397 
  398         if (offset < 0) {
  399         _zip_error_set_from_source(error, za->src);
  400         _zip_cdir_free(cd);
  401         return NULL;
  402         }
  403         ok = ((zip_uint64_t)offset == cd->offset + cd->size);
  404     }
  405 
  406     if (!ok) {
  407         zip_error_set(error, ZIP_ER_INCONS, 0);
  408         _zip_buffer_free(cd_buffer);
  409         _zip_cdir_free(cd);
  410         return NULL;
  411     }
  412     }
  413 
  414     _zip_buffer_free(cd_buffer);
  415     return cd;
  416 }
  417 
  418 
  419 /* _zip_checkcons:
  420    Checks the consistency of the central directory by comparing central
  421    directory entries with local headers and checking for plausible
  422    file and header offsets. Returns -1 if not plausible, else the
  423    difference between the lowest and the highest fileposition reached */
  424 
  425 static zip_int64_t
  426 _zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error) {
  427     zip_uint64_t i;
  428     zip_uint64_t min, max, j;
  429     struct zip_dirent temp;
  430 
  431     _zip_dirent_init(&temp);
  432     if (cd->nentry) {
  433     max = cd->entry[0].orig->offset;
  434     min = cd->entry[0].orig->offset;
  435     }
  436     else
  437     min = max = 0;
  438 
  439     for (i = 0; i < cd->nentry; i++) {
  440     if (cd->entry[i].orig->offset < min)
  441         min = cd->entry[i].orig->offset;
  442     if (min > (zip_uint64_t)cd->offset) {
  443         zip_error_set(error, ZIP_ER_NOZIP, 0);
  444         return -1;
  445     }
  446 
  447     j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
  448     if (j > max)
  449         max = j;
  450     if (max > (zip_uint64_t)cd->offset) {
  451         zip_error_set(error, ZIP_ER_NOZIP, 0);
  452         return -1;
  453     }
  454 
  455     if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {
  456         _zip_error_set_from_source(error, za->src);
  457         return -1;
  458     }
  459 
  460     if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) {
  461         _zip_dirent_finalize(&temp);
  462         return -1;
  463     }
  464 
  465     if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
  466         zip_error_set(error, ZIP_ER_INCONS, 0);
  467         _zip_dirent_finalize(&temp);
  468         return -1;
  469     }
  470 
  471     cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
  472     cd->entry[i].orig->local_extra_fields_read = 1;
  473     temp.extra_fields = NULL;
  474 
  475     _zip_dirent_finalize(&temp);
  476     }
  477 
  478     return (max - min) < ZIP_INT64_MAX ? (zip_int64_t)(max - min) : ZIP_INT64_MAX;
  479 }
  480 
  481 
  482 /* _zip_headercomp:
  483    compares a central directory entry and a local file header
  484    Return 0 if they are consistent, -1 if not. */
  485 
  486 static int
  487 _zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local) {
  488     if ((central->version_needed < local->version_needed)
  489 #if 0
  490     /* some zip-files have different values in local
  491        and global headers for the bitflags */
  492     || (central->bitflags != local->bitflags)
  493 #endif
  494     || (central->comp_method != local->comp_method) || (central->last_mod != local->last_mod) || !_zip_string_equal(central->filename, local->filename))
  495     return -1;
  496 
  497     if ((central->crc != local->crc) || (central->comp_size != local->comp_size) || (central->uncomp_size != local->uncomp_size)) {
  498     /* InfoZip stores valid values in local header even when data descriptor is used.
  499        This is in violation of the appnote. */
  500     if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0))
  501         return -1;
  502     }
  503 
  504     return 0;
  505 }
  506 
  507 
  508 static zip_t *
  509 _zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error) {
  510     zip_t *za;
  511 
  512     if ((za = _zip_new(error)) == NULL) {
  513     return NULL;
  514     }
  515 
  516     za->src = src;
  517     za->open_flags = flags;
  518     if (flags & ZIP_RDONLY) {
  519     za->flags |= ZIP_AFL_RDONLY;
  520     za->ch_flags |= ZIP_AFL_RDONLY;
  521     }
  522     return za;
  523 }
  524 
  525 
  526 /*
  527  * tests for file existence
  528  */
  529 static exists_t
  530 _zip_file_exists(zip_source_t *src, zip_error_t *error) {
  531     struct zip_stat st;
  532 
  533     zip_stat_init(&st);
  534     if (zip_source_stat(src, &st) != 0) {
  535     zip_error_t *src_error = zip_source_error(src);
  536     if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) {
  537         return EXISTS_NOT;
  538     }
  539     _zip_error_copy(error, src_error);
  540     return EXISTS_ERROR;
  541     }
  542 
  543     return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
  544 }
  545 
  546 
  547 static zip_cdir_t *
  548 _zip_find_central_dir(zip_t *za, zip_uint64_t len) {
  549     zip_cdir_t *cdir, *cdirnew;
  550     zip_uint8_t *match;
  551     zip_int64_t buf_offset;
  552     zip_uint64_t buflen;
  553     zip_int64_t a;
  554     zip_int64_t best;
  555     zip_error_t error;
  556     zip_buffer_t *buffer;
  557 
  558     if (len < EOCDLEN) {
  559     zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
  560     return NULL;
  561     }
  562 
  563     buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);
  564     if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {
  565     zip_error_t *src_error = zip_source_error(za->src);
  566     if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {
  567         /* seek before start of file on my machine */
  568         _zip_error_copy(&za->error, src_error);
  569         return NULL;
  570     }
  571     }
  572     if ((buf_offset = zip_source_tell(za->src)) < 0) {
  573     _zip_error_set_from_source(&za->error, za->src);
  574     return NULL;
  575     }
  576 
  577     if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
  578     return NULL;
  579     }
  580 
  581     best = -1;
  582     cdir = NULL;
  583     if (buflen >= CDBUFSIZE) {
  584     /* EOCD64 locator is before EOCD, so leave place for it */
  585     _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
  586     }
  587     zip_error_set(&error, ZIP_ER_NOZIP, 0);
  588 
  589     match = _zip_buffer_get(buffer, 0);
  590     while ((match = _zip_memmem(match, _zip_buffer_left(buffer) - (EOCDLEN - 4), (const unsigned char *)EOCD_MAGIC, 4)) != NULL) {
  591     _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
  592     if ((cdirnew = _zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &error)) != NULL) {
  593         if (cdir) {
  594         if (best <= 0) {
  595             best = _zip_checkcons(za, cdir, &error);
  596         }
  597 
  598         a = _zip_checkcons(za, cdirnew, &error);
  599         if (best < a) {
  600             _zip_cdir_free(cdir);
  601             cdir = cdirnew;
  602             best = a;
  603         }
  604         else {
  605             _zip_cdir_free(cdirnew);
  606         }
  607         }
  608         else {
  609         cdir = cdirnew;
  610         if (za->open_flags & ZIP_CHECKCONS)
  611             best = _zip_checkcons(za, cdir, &error);
  612         else {
  613             best = 0;
  614         }
  615         }
  616         cdirnew = NULL;
  617     }
  618 
  619     match++;
  620     _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
  621     }
  622 
  623     _zip_buffer_free(buffer);
  624 
  625     if (best < 0) {
  626     _zip_error_copy(&za->error, &error);
  627     _zip_cdir_free(cdir);
  628     return NULL;
  629     }
  630 
  631     return cdir;
  632 }
  633 
  634 
  635 static unsigned char *
  636 _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen) {
  637     const unsigned char *p;
  638 
  639     if ((biglen < littlelen) || (littlelen == 0))
  640     return NULL;
  641     p = big - 1;
  642     while ((p = (const unsigned char *)memchr(p + 1, little[0], (size_t)(big - (p + 1)) + (size_t)(biglen - littlelen) + 1)) != NULL) {
  643     if (memcmp(p + 1, little + 1, littlelen - 1) == 0)
  644         return (unsigned char *)p;
  645     }
  646 
  647     return NULL;
  648 }
  649 
  650 
  651 static zip_cdir_t *
  652 _zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) {
  653     zip_cdir_t *cd;
  654     zip_uint64_t i, nentry, size, offset, eocd_offset;
  655 
  656     if (_zip_buffer_left(buffer) < EOCDLEN) {
  657     zip_error_set(error, ZIP_ER_INCONS, 0);
  658     return NULL;
  659     }
  660 
  661     eocd_offset = _zip_buffer_offset(buffer);
  662 
  663     _zip_buffer_get(buffer, 4); /* magic already verified */
  664 
  665     if (_zip_buffer_get_32(buffer) != 0) {
  666     zip_error_set(error, ZIP_ER_MULTIDISK, 0);
  667     return NULL;
  668     }
  669 
  670     /* number of cdir-entries on this disk */
  671     i = _zip_buffer_get_16(buffer);
  672     /* number of cdir-entries */
  673     nentry = _zip_buffer_get_16(buffer);
  674 
  675     if (nentry != i) {
  676     zip_error_set(error, ZIP_ER_NOZIP, 0);
  677     return NULL;
  678     }
  679 
  680     size = _zip_buffer_get_32(buffer);
  681     offset = _zip_buffer_get_32(buffer);
  682 
  683     if (offset + size < offset) {
  684     zip_error_set(error, ZIP_ER_SEEK, EFBIG);
  685     return NULL;
  686     }
  687 
  688     if (offset + size > buf_offset + eocd_offset) {
  689     /* cdir spans past EOCD record */
  690     zip_error_set(error, ZIP_ER_INCONS, 0);
  691     return NULL;
  692     }
  693 
  694     if ((flags & ZIP_CHECKCONS) && offset + size != buf_offset + eocd_offset) {
  695     zip_error_set(error, ZIP_ER_INCONS, 0);
  696     return NULL;
  697     }
  698 
  699     if ((cd = _zip_cdir_new(nentry, error)) == NULL)
  700     return NULL;
  701 
  702     cd->is_zip64 = false;
  703     cd->size = size;
  704     cd->offset = offset;
  705 
  706     return cd;
  707 }
  708 
  709 
  710 static zip_cdir_t *
  711 _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) {
  712     zip_cdir_t *cd;
  713     zip_uint64_t offset;
  714     zip_uint8_t eocd[EOCD64LEN];
  715     zip_uint64_t eocd_offset;
  716     zip_uint64_t size, nentry, i, eocdloc_offset;
  717     bool free_buffer;
  718     zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64;
  719 
  720     eocdloc_offset = _zip_buffer_offset(buffer);
  721 
  722     _zip_buffer_get(buffer, 4); /* magic already verified */
  723 
  724     num_disks = _zip_buffer_get_16(buffer);
  725     eocd_disk = _zip_buffer_get_16(buffer);
  726     eocd_offset = _zip_buffer_get_64(buffer);
  727 
  728     if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
  729     zip_error_set(error, ZIP_ER_SEEK, EFBIG);
  730     return NULL;
  731     }
  732 
  733     if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
  734     zip_error_set(error, ZIP_ER_INCONS, 0);
  735     return NULL;
  736     }
  737 
  738     if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
  739     _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
  740     free_buffer = false;
  741     }
  742     else {
  743     if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
  744         _zip_error_set_from_source(error, src);
  745         return NULL;
  746     }
  747     if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
  748         return NULL;
  749     }
  750     free_buffer = true;
  751     }
  752 
  753     if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
  754     zip_error_set(error, ZIP_ER_INCONS, 0);
  755     if (free_buffer) {
  756         _zip_buffer_free(buffer);
  757     }
  758     return NULL;
  759     }
  760 
  761     size = _zip_buffer_get_64(buffer);
  762 
  763     if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
  764     zip_error_set(error, ZIP_ER_INCONS, 0);
  765     if (free_buffer) {
  766         _zip_buffer_free(buffer);
  767     }
  768     return NULL;
  769     }
  770 
  771     _zip_buffer_get(buffer, 4); /* skip version made by/needed */
  772 
  773     num_disks64 = _zip_buffer_get_32(buffer);
  774     eocd_disk64 = _zip_buffer_get_32(buffer);
  775 
  776     /* if eocd values are 0xffff, we have to use eocd64 values.
  777        otherwise, if the values are not the same, it's inconsistent;
  778        in any case, if the value is not 0, we don't support it */
  779     if (num_disks == 0xffff) {
  780     num_disks = num_disks64;
  781     }
  782     if (eocd_disk == 0xffff) {
  783     eocd_disk = eocd_disk64;
  784     }
  785     if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
  786     zip_error_set(error, ZIP_ER_INCONS, 0);
  787     if (free_buffer) {
  788         _zip_buffer_free(buffer);
  789     }
  790     return NULL;
  791     }
  792     if (num_disks != 0 || eocd_disk != 0) {
  793     zip_error_set(error, ZIP_ER_MULTIDISK, 0);
  794     if (free_buffer) {
  795         _zip_buffer_free(buffer);
  796     }
  797     return NULL;
  798     }
  799 
  800     nentry = _zip_buffer_get_64(buffer);
  801     i = _zip_buffer_get_64(buffer);
  802 
  803     if (nentry != i) {
  804     zip_error_set(error, ZIP_ER_MULTIDISK, 0);
  805     if (free_buffer) {
  806         _zip_buffer_free(buffer);
  807     }
  808     return NULL;
  809     }
  810 
  811     size = _zip_buffer_get_64(buffer);
  812     offset = _zip_buffer_get_64(buffer);
  813 
  814     if (!_zip_buffer_ok(buffer)) {
  815     zip_error_set(error, ZIP_ER_INTERNAL, 0);
  816     if (free_buffer) {
  817         _zip_buffer_free(buffer);
  818     }
  819     return NULL;
  820     }
  821 
  822     if (free_buffer) {
  823     _zip_buffer_free(buffer);
  824     }
  825 
  826     if (offset > ZIP_INT64_MAX || offset + size < offset) {
  827     zip_error_set(error, ZIP_ER_SEEK, EFBIG);
  828     return NULL;
  829     }
  830     if (offset + size > buf_offset + eocd_offset) {
  831     /* cdir spans past EOCD record */
  832     zip_error_set(error, ZIP_ER_INCONS, 0);
  833     return NULL;
  834     }
  835     if ((flags & ZIP_CHECKCONS) && offset + size != buf_offset + eocd_offset) {
  836     zip_error_set(error, ZIP_ER_INCONS, 0);
  837     return NULL;
  838     }
  839 
  840     if ((cd = _zip_cdir_new(nentry, error)) == NULL)
  841     return NULL;
  842 
  843     cd->is_zip64 = true;
  844     cd->size = size;
  845     cd->offset = offset;
  846 
  847     return cd;
  848 }