1 /*
   2  * Copyright (c) 1995, 2009, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * Support for reading ZIP/JAR files.
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <stddef.h>
  33 #include <string.h>
  34 #include <fcntl.h>
  35 #include <limits.h>
  36 #include <time.h>
  37 #include <ctype.h>
  38 #include <assert.h>
  39 
  40 #include "jni.h"
  41 #include "jni_util.h"
  42 #include "jlong.h"
  43 #include "jvm.h"
  44 #include "io_util.h"
  45 #include "io_util_md.h"
  46 #include "zip_util.h"
  47 #include "zlib.h"
  48 
  49 /* USE_MMAP means mmap the CEN & ENDHDR part of the zip file. */
  50 #ifdef USE_MMAP
  51 #include <sys/mman.h>
  52 #endif
  53 
  54 #define MAXREFS 0xFFFF  /* max number of open zip file references */
  55 
  56 #define MCREATE()      JVM_RawMonitorCreate()
  57 #define MLOCK(lock)    JVM_RawMonitorEnter(lock)
  58 #define MUNLOCK(lock)  JVM_RawMonitorExit(lock)
  59 #define MDESTROY(lock) JVM_RawMonitorDestroy(lock)
  60 
  61 #define CENSIZE(cen) (CENHDR + CENNAM(cen) + CENEXT(cen) + CENCOM(cen))
  62 
  63 static jzfile *zfiles = 0;      /* currently open zip files */
  64 static void *zfiles_lock = 0;
  65 
  66 static void freeCEN(jzfile *);
  67 
  68 #ifndef PATH_MAX
  69 #define PATH_MAX 1024
  70 #endif
  71 
  72 static jint INITIAL_META_COUNT = 2;   /* initial number of entries in meta name array */
  73 
  74 /*
  75  * The ZFILE_* functions exist to provide some platform-independence with
  76  * respect to file access needs.
  77  */
  78 
  79 /*
  80  * Opens the named file for reading, returning a ZFILE.
  81  *
  82  * Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c.
  83  * This function does not take JNIEnv* and uses CreateFile (instead of
  84  * CreateFileW).  The expectation is that this function will be called only
  85  * from ZIP_Open_Generic, which in turn is used by the JVM, where we do not
  86  * need to concern ourselves with wide chars.
  87  */
  88 static ZFILE
  89 ZFILE_Open(const char *fname, int flags) {
  90 #ifdef WIN32
  91     const DWORD access =
  92         (flags & O_RDWR)   ? (GENERIC_WRITE | GENERIC_READ) :
  93         (flags & O_WRONLY) ?  GENERIC_WRITE :
  94         GENERIC_READ;
  95     const DWORD sharing =
  96         FILE_SHARE_READ | FILE_SHARE_WRITE;
  97     const DWORD disposition =
  98         /* Note: O_TRUNC overrides O_CREAT */
  99         (flags & O_TRUNC) ? CREATE_ALWAYS :
 100         (flags & O_CREAT) ? OPEN_ALWAYS   :
 101         OPEN_EXISTING;
 102     const DWORD  maybeWriteThrough =
 103         (flags & (O_SYNC | O_DSYNC)) ?
 104         FILE_FLAG_WRITE_THROUGH :
 105         FILE_ATTRIBUTE_NORMAL;
 106     const DWORD maybeDeleteOnClose =
 107         (flags & O_TEMPORARY) ?
 108         FILE_FLAG_DELETE_ON_CLOSE :
 109         FILE_ATTRIBUTE_NORMAL;
 110     const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
 111 
 112     return (jlong) CreateFile(
 113         fname,          /* Wide char path name */
 114         access,         /* Read and/or write permission */
 115         sharing,        /* File sharing flags */
 116         NULL,           /* Security attributes */
 117         disposition,        /* creation disposition */
 118         flagsAndAttributes, /* flags and attributes */
 119         NULL);
 120 #else
 121     return JVM_Open(fname, flags, 0);
 122 #endif
 123 }
 124 
 125 /*
 126  * The io_util_md.h files do not provide IO_CLOSE, hence we use platform
 127  * specifics.
 128  */
 129 static void
 130 ZFILE_Close(ZFILE zfd) {
 131 #ifdef WIN32
 132     CloseHandle((HANDLE) zfd);
 133 #else
 134     JVM_Close(zfd);
 135 #endif
 136 }
 137 
 138 static int
 139 ZFILE_read(ZFILE zfd, char *buf, jint nbytes) {
 140 #ifdef WIN32
 141     return (int) IO_Read(zfd, buf, nbytes);
 142 #else
 143     /*
 144      * Calling JVM_Read will return JVM_IO_INTR when Thread.interrupt is called
 145      * only on Solaris. Continue reading jar file in this case is the best
 146      * thing to do since zip file reading is relatively fast and it is very onerous
 147      * for a interrupted thread to deal with this kind of hidden I/O. However, handling
 148      * JVM_IO_INTR is tricky and could cause undesired side effect. So we decided
 149      * to simply call "read" on Solaris/Linux. See details in bug 6304463.
 150      */
 151     return read(zfd, buf, nbytes);
 152 #endif
 153 }
 154 
 155 /*
 156  * Initialize zip file support. Return 0 if successful otherwise -1
 157  * if could not be initialized.
 158  */
 159 static jint
 160 InitializeZip()
 161 {
 162     static jboolean inited = JNI_FALSE;
 163 
 164     // Initialize errno to 0.  It may be set later (e.g. during memory
 165     // allocation) but we can disregard previous values.
 166     errno = 0;
 167 
 168     if (inited)
 169         return 0;
 170     zfiles_lock = MCREATE();
 171     if (zfiles_lock == 0) {
 172         return -1;
 173     }
 174     inited = JNI_TRUE;
 175 
 176     return 0;
 177 }
 178 
 179 /*
 180  * Reads len bytes of data into buf.
 181  * Returns 0 if all bytes could be read, otherwise returns -1.
 182  */
 183 static int
 184 readFully(ZFILE zfd, void *buf, jlong len) {
 185   char *bp = (char *) buf;
 186 
 187   while (len > 0) {
 188         jlong limit = ((((jlong) 1) << 31) - 1);
 189         jint count = (len < limit) ?
 190             (jint) len :
 191             (jint) limit;
 192         jint n = ZFILE_read(zfd, bp, count);
 193         if (n > 0) {
 194             bp += n;
 195             len -= n;
 196         } else if (n == JVM_IO_ERR && errno == EINTR) {
 197           /* Retry after EINTR (interrupted by signal).
 198              We depend on the fact that JVM_IO_ERR == -1. */
 199             continue;
 200         } else { /* EOF or IO error */
 201             return -1;
 202         }
 203     }
 204     return 0;
 205 }
 206 
 207 /*
 208  * Reads len bytes of data from the specified offset into buf.
 209  * Returns 0 if all bytes could be read, otherwise returns -1.
 210  */
 211 static int
 212 readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset)
 213 {
 214     if (IO_Lseek(zfd, offset, SEEK_SET) == -1) {
 215         return -1; /* lseek failure. */
 216     }
 217 
 218     return readFully(zfd, buf, len);
 219 }
 220 
 221 /*
 222  * Allocates a new zip file object for the specified file name.
 223  * Returns the zip file object or NULL if not enough memory.
 224  */
 225 static jzfile *
 226 allocZip(const char *name)
 227 {
 228     jzfile *zip;
 229     if (((zip = calloc(1, sizeof(jzfile))) != NULL) &&
 230         ((zip->name = strdup(name))        != NULL) &&
 231         ((zip->lock = MCREATE())           != NULL)) {
 232         zip->zfd = -1;
 233         return zip;
 234     }
 235 
 236     if (zip != NULL) {
 237         free(zip->name);
 238         free(zip);
 239     }
 240     return NULL;
 241 }
 242 
 243 /*
 244  * Frees all native resources owned by the specified zip file object.
 245  */
 246 static void
 247 freeZip(jzfile *zip)
 248 {
 249     /* First free any cached jzentry */
 250     ZIP_FreeEntry(zip,0);
 251     if (zip->lock != NULL) MDESTROY(zip->lock);
 252     free(zip->name);
 253     freeCEN(zip);
 254 
 255 #ifdef USE_MMAP
 256     if (zip->usemmap) {
 257         if (zip->maddr != NULL)
 258             munmap((char *)zip->maddr, zip->mlen);
 259     } else
 260 #endif
 261     {
 262         free(zip->cencache.data);
 263     }
 264     if (zip->comment != NULL)
 265         free(zip->comment);
 266     if (zip->zfd != -1) ZFILE_Close(zip->zfd);
 267     free(zip);
 268 }
 269 
 270 /* The END header is followed by a variable length comment of size < 64k. */
 271 static const jlong END_MAXLEN = 0xFFFF + ENDHDR;
 272 
 273 #define READBLOCKSZ 128
 274 
 275 static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) {
 276     /* ENDSIG matched, however the size of file comment in it does not
 277        match the real size. One "common" cause for this problem is some
 278        "extra" bytes are padded at the end of the zipfile.
 279        Let's do some extra verification, we don't care about the performance
 280        in this situation.
 281      */
 282     jlong cenpos = endpos - ENDSIZ(endbuf);
 283     jlong locpos = cenpos - ENDOFF(endbuf);
 284     char buf[4];
 285     return (cenpos >= 0 &&
 286             locpos >= 0 &&
 287             readFullyAt(zip->zfd, buf, sizeof(buf), cenpos) != -1 &&
 288             GETSIG(buf) == CENSIG &&
 289             readFullyAt(zip->zfd, buf, sizeof(buf), locpos) != -1 &&
 290             GETSIG(buf) == LOCSIG);
 291 }
 292 
 293 /*
 294  * Searches for end of central directory (END) header. The contents of
 295  * the END header will be read and placed in endbuf. Returns the file
 296  * position of the END header, otherwise returns -1 if the END header
 297  * was not found or an error occurred.
 298  */
 299 static jlong
 300 findEND(jzfile *zip, void *endbuf)
 301 {
 302     char buf[READBLOCKSZ];
 303     jlong pos;
 304     const jlong len = zip->len;
 305     const ZFILE zfd = zip->zfd;
 306     const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0;
 307     const jlong minPos = minHDR - (sizeof(buf)-ENDHDR);
 308     jint clen;
 309 
 310     for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) {
 311 
 312         int i;
 313         jlong off = 0;
 314         if (pos < 0) {
 315             /* Pretend there are some NUL bytes before start of file */
 316             off = -pos;
 317             memset(buf, '\0', (size_t)off);
 318         }
 319 
 320         if (readFullyAt(zfd, buf + off, sizeof(buf) - off,
 321                         pos + off) == -1) {
 322             return -1;  /* System error */
 323         }
 324 
 325         /* Now scan the block backwards for END header signature */
 326         for (i = sizeof(buf) - ENDHDR; i >= 0; i--) {
 327             if (buf[i+0] == 'P'    &&
 328                 buf[i+1] == 'K'    &&
 329                 buf[i+2] == '\005' &&
 330                 buf[i+3] == '\006' &&
 331                 ((pos + i + ENDHDR + ENDCOM(buf + i) == len)
 332                  || verifyEND(zip, pos + i, buf + i))) {
 333                 /* Found END header */
 334                 memcpy(endbuf, buf + i, ENDHDR);
 335 
 336                 clen = ENDCOM(endbuf);
 337                 if (clen != 0) {
 338                     zip->comment = malloc(clen + 1);
 339                     if (zip->comment == NULL) {
 340                         return -1;
 341                     }
 342                     if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR)
 343                         == -1) {
 344                         free(zip->comment);
 345                         zip->comment = NULL;
 346                         return -1;
 347                     }
 348                     zip->comment[clen] = '\0';
 349                     zip->clen = clen;
 350                 }
 351                 return pos + i;
 352             }
 353         }
 354     }
 355 
 356     return -1; /* END header not found */
 357 }
 358 
 359 /*
 360  * Searches for the ZIP64 end of central directory (END) header. The
 361  * contents of the ZIP64 END header will be read and placed in end64buf.
 362  * Returns the file position of the ZIP64 END header, otherwise returns
 363  * -1 if the END header was not found or an error occurred.
 364  *
 365  * The ZIP format specifies the "position" of each related record as
 366  *   ...
 367  *   [central directory]
 368  *   [zip64 end of central directory record]
 369  *   [zip64 end of central directory locator]
 370  *   [end of central directory record]
 371  *
 372  * The offset of zip64 end locator can be calculated from endpos as
 373  * "endpos - ZIP64_LOCHDR".
 374  * The "offset" of zip64 end record is stored in zip64 end locator.
 375  */
 376 static jlong
 377 findEND64(jzfile *zip, void *end64buf, jlong endpos)
 378 {
 379     char loc64[ZIP64_LOCHDR];
 380     jlong end64pos;
 381     if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {
 382         return -1;    // end64 locator not found
 383     }
 384     end64pos = ZIP64_LOCOFF(loc64);
 385     if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) {
 386         return -1;    // end64 record not found
 387     }
 388     return end64pos;
 389 }
 390 
 391 /*
 392  * Returns a hash code value for a C-style NUL-terminated string.
 393  */
 394 static unsigned int
 395 hash(const char *s)
 396 {
 397     int h = 0;
 398     while (*s != '\0')
 399         h = 31*h + *s++;
 400     return h;
 401 }
 402 
 403 /*
 404  * Returns a hash code value for a string of a specified length.
 405  */
 406 static unsigned int
 407 hashN(const char *s, int length)
 408 {
 409     int h = 0;
 410     while (length-- > 0)
 411         h = 31*h + *s++;
 412     return h;
 413 }
 414 
 415 static unsigned int
 416 hash_append(unsigned int hash, char c)
 417 {
 418     return ((int)hash)*31 + c;
 419 }
 420 
 421 /*
 422  * Returns true if the specified entry's name begins with the string
 423  * "META-INF/" irrespective of case.
 424  */
 425 static int
 426 isMetaName(const char *name, int length)
 427 {
 428     const char *s;
 429     if (length < (int)sizeof("META-INF/") - 1)
 430         return 0;
 431     for (s = "META-INF/"; *s != '\0'; s++) {
 432         char c = *name++;
 433         // Avoid toupper; it's locale-dependent
 434         if (c >= 'a' && c <= 'z') c += 'A' - 'a';
 435         if (*s != c)
 436             return 0;
 437     }
 438     return 1;
 439 }
 440 
 441 /*
 442  * Increases the capacity of zip->metanames.
 443  * Returns non-zero in case of allocation error.
 444  */
 445 static int
 446 growMetaNames(jzfile *zip)
 447 {
 448     jint i;
 449     /* double the meta names array */
 450     const jint new_metacount = zip->metacount << 1;
 451     zip->metanames =
 452         realloc(zip->metanames, new_metacount * sizeof(zip->metanames[0]));
 453     if (zip->metanames == NULL) return -1;
 454     for (i = zip->metacount; i < new_metacount; i++)
 455         zip->metanames[i] = NULL;
 456     zip->metacurrent = zip->metacount;
 457     zip->metacount = new_metacount;
 458     return 0;
 459 }
 460 
 461 /*
 462  * Adds name to zip->metanames.
 463  * Returns non-zero in case of allocation error.
 464  */
 465 static int
 466 addMetaName(jzfile *zip, const char *name, int length)
 467 {
 468     jint i;
 469     if (zip->metanames == NULL) {
 470       zip->metacount = INITIAL_META_COUNT;
 471       zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0]));
 472       if (zip->metanames == NULL) return -1;
 473       zip->metacurrent = 0;
 474     }
 475 
 476     i = zip->metacurrent;
 477 
 478     /* current meta name array isn't full yet. */
 479     if (i < zip->metacount) {
 480       zip->metanames[i] = (char *) malloc(length+1);
 481       if (zip->metanames[i] == NULL) return -1;
 482       memcpy(zip->metanames[i], name, length);
 483       zip->metanames[i][length] = '\0';
 484       zip->metacurrent++;
 485       return 0;
 486     }
 487 
 488     /* No free entries in zip->metanames? */
 489     if (growMetaNames(zip) != 0) return -1;
 490     return addMetaName(zip, name, length);
 491 }
 492 
 493 static void
 494 freeMetaNames(jzfile *zip)
 495 {
 496     if (zip->metanames) {
 497         jint i;
 498         for (i = 0; i < zip->metacount; i++)
 499             free(zip->metanames[i]);
 500         free(zip->metanames);
 501         zip->metanames = NULL;
 502     }
 503 }
 504 
 505 /* Free Zip data allocated by readCEN() */
 506 static void
 507 freeCEN(jzfile *zip)
 508 {
 509     free(zip->entries); zip->entries = NULL;
 510     free(zip->table);   zip->table   = NULL;
 511     freeMetaNames(zip);
 512 }
 513 
 514 /*
 515  * Counts the number of CEN headers in a central directory extending
 516  * from BEG to END.  Might return a bogus answer if the zip file is
 517  * corrupt, but will not crash.
 518  */
 519 static jint
 520 countCENHeaders(unsigned char *beg, unsigned char *end)
 521 {
 522     jint count = 0;
 523     ptrdiff_t i;
 524     for (i = 0; i + CENHDR < end - beg; i += CENSIZE(beg + i))
 525         count++;
 526     return count;
 527 }
 528 
 529 #define ZIP_FORMAT_ERROR(message) \
 530 if (1) { zip->msg = message; goto Catch; } else ((void)0)
 531 
 532 /*
 533  * Reads zip file central directory. Returns the file position of first
 534  * CEN header, otherwise returns -1 if an error occured. If zip->msg != NULL
 535  * then the error was a zip format error and zip->msg has the error text.
 536  * Always pass in -1 for knownTotal; it's used for a recursive call.
 537  */
 538 static jlong
 539 readCEN(jzfile *zip, jint knownTotal)
 540 {
 541     /* Following are unsigned 32-bit */
 542     jlong endpos, end64pos, cenpos, cenlen, cenoff;
 543     /* Following are unsigned 16-bit */
 544     jint total, tablelen, i, j;
 545     unsigned char *cenbuf = NULL;
 546     unsigned char *cenend;
 547     unsigned char *cp;
 548 #ifdef USE_MMAP
 549     static jlong pagesize;
 550     jlong offset;
 551 #endif
 552     unsigned char endbuf[ENDHDR];
 553     jint endhdrlen = ENDHDR;
 554     jzcell *entries;
 555     jint *table;
 556 
 557     /* Clear previous zip error */
 558     zip->msg = NULL;
 559     /* Get position of END header */
 560     if ((endpos = findEND(zip, endbuf)) == -1)
 561         return -1; /* no END header or system error */
 562 
 563     if (endpos == 0) return 0;  /* only END header present */
 564 
 565     freeCEN(zip);
 566    /* Get position and length of central directory */
 567     cenlen = ENDSIZ(endbuf);
 568     cenoff = ENDOFF(endbuf);
 569     total  = ENDTOT(endbuf);
 570     if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL ||
 571         total == ZIP64_MAGICCOUNT) {
 572         unsigned char end64buf[ZIP64_ENDHDR];
 573         if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {
 574             cenlen = ZIP64_ENDSIZ(end64buf);
 575             cenoff = ZIP64_ENDOFF(end64buf);
 576             total = (jint)ZIP64_ENDTOT(end64buf);
 577             endpos = end64pos;
 578             endhdrlen = ZIP64_ENDHDR;
 579         }
 580     }
 581 
 582     if (cenlen > endpos)
 583         ZIP_FORMAT_ERROR("invalid END header (bad central directory size)");
 584     cenpos = endpos - cenlen;
 585 
 586     /* Get position of first local file (LOC) header, taking into
 587      * account that there may be a stub prefixed to the zip file. */
 588     zip->locpos = cenpos - cenoff;
 589     if (zip->locpos < 0)
 590         ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");
 591 
 592 #ifdef USE_MMAP
 593     if (zip->usemmap) {
 594       /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
 595        * read the jar file contents. However, this greatly increased the perceived
 596        * footprint numbers because the mmap'ed pages were adding into the totals shown
 597        * by 'ps' and 'top'. We switched to mmaping only the central directory of jar
 598        * file while calling 'read' to read the rest of jar file. Here are a list of
 599        * reasons apart from above of why we are doing so:
 600        * 1. Greatly reduces mmap overhead after startup complete;
 601        * 2. Avoids dual path code maintainance;
 602        * 3. Greatly reduces risk of address space (not virtual memory) exhaustion.
 603        */
 604         if (pagesize == 0) {
 605             pagesize = (jlong)sysconf(_SC_PAGESIZE);
 606             if (pagesize == 0) goto Catch;
 607         }
 608         if (cenpos > pagesize) {
 609             offset = cenpos & ~(pagesize - 1);
 610         } else {
 611             offset = 0;
 612         }
 613         /* When we are not calling recursively, knownTotal is -1. */
 614         if (knownTotal == -1) {
 615             void* mappedAddr;
 616             /* Mmap the CEN and END part only. We have to figure
 617                out the page size in order to make offset to be multiples of
 618                page size.
 619             */
 620             zip->mlen = cenpos - offset + cenlen + endhdrlen;
 621             zip->offset = offset;
 622             mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
 623             zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
 624                 (unsigned char*)mappedAddr;
 625 
 626             if (zip->maddr == NULL) {
 627                 jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");
 628                 goto Catch;
 629             }
 630         }
 631         cenbuf = zip->maddr + cenpos - offset;
 632     } else
 633 #endif
 634     {
 635         if ((cenbuf = malloc((size_t) cenlen)) == NULL ||
 636             (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))
 637         goto Catch;
 638     }
 639 
 640     cenend = cenbuf + cenlen;
 641 
 642     /* Initialize zip file data structures based on the total number
 643      * of central directory entries as stored in ENDTOT.  Since this
 644      * is a 2-byte field, but we (and other zip implementations)
 645      * support approx. 2**31 entries, we do not trust ENDTOT, but
 646      * treat it only as a strong hint.  When we call ourselves
 647      * recursively, knownTotal will have the "true" value.
 648      *
 649      * Keep this path alive even with the Zip64 END support added, just
 650      * for zip files that have more than 0xffff entries but don't have
 651      * the Zip64 enabled.
 652      */
 653     total = (knownTotal != -1) ? knownTotal : total;
 654     entries  = zip->entries  = calloc(total, sizeof(entries[0]));
 655     tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions
 656     table    = zip->table    = malloc(tablelen * sizeof(table[0]));
 657     if (entries == NULL || table == NULL) goto Catch;
 658     for (j = 0; j < tablelen; j++)
 659         table[j] = ZIP_ENDCHAIN;
 660 
 661     /* Iterate through the entries in the central directory */
 662     for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {
 663         /* Following are unsigned 16-bit */
 664         jint method, nlen;
 665         unsigned int hsh;
 666 
 667         if (i >= total) {
 668             /* This will only happen if the zip file has an incorrect
 669              * ENDTOT field, which usually means it contains more than
 670              * 65535 entries. */
 671             cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend));
 672             goto Finally;
 673         }
 674 
 675         method = CENHOW(cp);
 676         nlen   = CENNAM(cp);
 677 
 678         if (GETSIG(cp) != CENSIG)
 679             ZIP_FORMAT_ERROR("invalid CEN header (bad signature)");
 680         if (CENFLG(cp) & 1)
 681             ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)");
 682         if (method != STORED && method != DEFLATED)
 683             ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)");
 684         if (cp + CENHDR + nlen > cenend)
 685             ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
 686 
 687         /* if the entry is metadata add it to our metadata names */
 688         if (isMetaName((char *)cp+CENHDR, nlen))
 689             if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0)
 690                 goto Catch;
 691 
 692         /* Record the CEN offset and the name hash in our hash cell. */
 693         entries[i].cenpos = cenpos + (cp - cenbuf);
 694         entries[i].hash = hashN((char *)cp+CENHDR, nlen);
 695 
 696         /* Add the entry to the hash table */
 697         hsh = entries[i].hash % tablelen;
 698         entries[i].next = table[hsh];
 699         table[hsh] = i;
 700     }
 701     if (cp != cenend)
 702         ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
 703 
 704     zip->total = i;
 705     goto Finally;
 706 
 707  Catch:
 708     freeCEN(zip);
 709     cenpos = -1;
 710 
 711  Finally:
 712 #ifdef USE_MMAP
 713     if (!zip->usemmap)
 714 #endif
 715         free(cenbuf);
 716 
 717     return cenpos;
 718 }
 719 
 720 /*
 721  * Opens a zip file with the specified mode. Returns the jzfile object
 722  * or NULL if an error occurred. If a zip error occurred then *pmsg will
 723  * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be
 724  * set to NULL.
 725  */
 726 jzfile *
 727 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified)
 728 {
 729     jzfile *zip = NULL;
 730 
 731     /* Clear zip error message */
 732     if (pmsg != 0) {
 733         *pmsg = NULL;
 734     }
 735 
 736     zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
 737 
 738     if (zip == NULL && *pmsg == NULL) {
 739         ZFILE zfd = ZFILE_Open(name, mode);
 740         zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
 741     }
 742     return zip;
 743 }
 744 
 745 /*
 746  * Returns the jzfile corresponding to the given file name from the cache of
 747  * zip files, or NULL if the file is not in the cache.  If the name is longer
 748  * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
 749  * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL.
 750  */
 751 jzfile *
 752 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
 753 {
 754     static char errbuf[256];
 755     char buf[PATH_MAX];
 756     jzfile *zip;
 757 
 758     if (InitializeZip()) {
 759         return NULL;
 760     }
 761 
 762     /* Clear zip error message */
 763     if (pmsg != 0) {
 764         *pmsg = NULL;
 765     }
 766 
 767     if (strlen(name) >= PATH_MAX) {
 768         if (pmsg) {
 769             *pmsg = "zip file name too long";
 770         }
 771         return NULL;
 772     }
 773     strcpy(buf, name);
 774     JVM_NativePath(buf);
 775     name = buf;
 776 
 777     MLOCK(zfiles_lock);
 778     for (zip = zfiles; zip != NULL; zip = zip->next) {
 779         if (strcmp(name, zip->name) == 0
 780             && (zip->lastModified == lastModified || zip->lastModified == 0)
 781             && zip->refs < MAXREFS) {
 782             zip->refs++;
 783             break;
 784         }
 785     }
 786     MUNLOCK(zfiles_lock);
 787     return zip;
 788 }
 789 
 790 /*
 791  * Reads data from the given file descriptor to create a jzfile, puts the
 792  * jzfile in a cache, and returns that jzfile.  Returns NULL in case of error.
 793  * If a zip error occurs, then *pmsg will be set to the error message text if
 794  * pmsg != 0. Otherwise, *pmsg will be set to NULL.
 795  */
 796 
 797 jzfile *
 798 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
 799 {
 800     return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
 801 }
 802 
 803 jzfile *
 804 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
 805                  jboolean usemmap)
 806 {
 807     static char errbuf[256];
 808     jlong len;
 809     jzfile *zip;
 810 
 811     if ((zip = allocZip(name)) == NULL) {
 812         return NULL;
 813     }
 814 
 815 #ifdef USE_MMAP
 816     zip->usemmap = usemmap;
 817 #endif
 818     zip->refs = 1;
 819     zip->lastModified = lastModified;
 820 
 821     if (zfd == -1) {
 822         if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
 823             *pmsg = errbuf;
 824         freeZip(zip);
 825         return NULL;
 826     }
 827 
 828     len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
 829     if (len <= 0) {
 830         if (len == 0) { /* zip file is empty */
 831             if (pmsg) {
 832                 *pmsg = "zip file is empty";
 833             }
 834         } else { /* error */
 835             if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
 836                 *pmsg = errbuf;
 837         }
 838         ZFILE_Close(zfd);
 839         freeZip(zip);
 840         return NULL;
 841     }
 842 
 843     zip->zfd = zfd;
 844     if (readCEN(zip, -1) < 0) {
 845         /* An error occurred while trying to read the zip file */
 846         if (pmsg != 0) {
 847             /* Set the zip error message */
 848             *pmsg = zip->msg;
 849         }
 850         freeZip(zip);
 851         return NULL;
 852     }
 853     MLOCK(zfiles_lock);
 854     zip->next = zfiles;
 855     zfiles = zip;
 856     MUNLOCK(zfiles_lock);
 857 
 858     return zip;
 859 }
 860 
 861 /*
 862  * Opens a zip file for reading. Returns the jzfile object or NULL
 863  * if an error occurred. If a zip error occurred then *msg will be
 864  * set to the error message text if msg != 0. Otherwise, *msg will be
 865  * set to NULL.
 866  */
 867 jzfile * JNICALL
 868 ZIP_Open(const char *name, char **pmsg)
 869 {
 870     return ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);
 871 }
 872 
 873 /*
 874  * Closes the specified zip file object.
 875  */
 876 void JNICALL
 877 ZIP_Close(jzfile *zip)
 878 {
 879     MLOCK(zfiles_lock);
 880     if (--zip->refs > 0) {
 881         /* Still more references so just return */
 882         MUNLOCK(zfiles_lock);
 883         return;
 884     }
 885     /* No other references so close the file and remove from list */
 886     if (zfiles == zip) {
 887         zfiles = zfiles->next;
 888     } else {
 889         jzfile *zp;
 890         for (zp = zfiles; zp->next != 0; zp = zp->next) {
 891             if (zp->next == zip) {
 892                 zp->next = zip->next;
 893                 break;
 894             }
 895         }
 896     }
 897     MUNLOCK(zfiles_lock);
 898     freeZip(zip);
 899     return;
 900 }
 901 
 902 /* Empirically, most CEN headers are smaller than this. */
 903 #define AMPLE_CEN_HEADER_SIZE 160
 904 
 905 /* A good buffer size when we want to read CEN headers sequentially. */
 906 #define CENCACHE_PAGESIZE 8192
 907 
 908 static char *
 909 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
 910 {
 911     jint censize;
 912     ZFILE zfd = zip->zfd;
 913     char *cen;
 914     if (bufsize > zip->len - cenpos)
 915         bufsize = (jint)(zip->len - cenpos);
 916     if ((cen = malloc(bufsize)) == NULL)       goto Catch;
 917     if (readFullyAt(zfd, cen, bufsize, cenpos) == -1)     goto Catch;
 918     censize = CENSIZE(cen);
 919     if (censize <= bufsize) return cen;
 920     if ((cen = realloc(cen, censize)) == NULL)              goto Catch;
 921     if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch;
 922     return cen;
 923 
 924  Catch:
 925     free(cen);
 926     return NULL;
 927 }
 928 
 929 static char *
 930 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
 931 {
 932     cencache *cache = &zip->cencache;
 933     char *cen;
 934     if (cache->data != NULL
 935         && (cenpos >= cache->pos)
 936         && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
 937     {
 938         cen = cache->data + cenpos - cache->pos;
 939         if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
 940             /* A cache hit */
 941             return cen;
 942     }
 943 
 944     if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
 945         return NULL;
 946     free(cache->data);
 947     cache->data = cen;
 948     cache->pos  = cenpos;
 949     return cen;
 950 }
 951 
 952 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
 953 
 954 /*
 955  * Return a new initialized jzentry corresponding to a given hash cell.
 956  * In case of error, returns NULL.
 957  * We already sanity-checked all the CEN headers for ZIP format errors
 958  * in readCEN(), so we don't check them again here.
 959  * The ZIP lock should be held here.
 960  */
 961 static jzentry *
 962 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
 963 {
 964     jlong locoff;
 965     jint nlen, elen, clen;
 966     jzentry *ze;
 967     char *cen;
 968 
 969     if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
 970     ze->name    = NULL;
 971     ze->extra   = NULL;
 972     ze->comment = NULL;
 973 
 974 #ifdef USE_MMAP
 975     if (zip->usemmap) {
 976         cen = (char*) zip->maddr + zc->cenpos - zip->offset;
 977     } else
 978 #endif
 979     {
 980         if (accessHint == ACCESS_RANDOM)
 981             cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
 982         else
 983             cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
 984         if (cen == NULL) goto Catch;
 985     }
 986 
 987     nlen      = CENNAM(cen);
 988     elen      = CENEXT(cen);
 989     clen      = CENCOM(cen);
 990     ze->time  = CENTIM(cen);
 991     ze->size  = CENLEN(cen);
 992     ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
 993     ze->crc   = CENCRC(cen);
 994     locoff    = CENOFF(cen);
 995     ze->pos   = -(zip->locpos + locoff);
 996     ze->flag  = CENFLG(cen);
 997 
 998     if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
 999     memcpy(ze->name, cen + CENHDR, nlen);
1000     ze->name[nlen] = '\0';
1001     if (elen > 0) {
1002         char *extra = cen + CENHDR + nlen;
1003 
1004         /* This entry has "extra" data */
1005         if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1006         ze->extra[0] = (unsigned char) elen;
1007         ze->extra[1] = (unsigned char) (elen >> 8);
1008         memcpy(ze->extra+2, extra, elen);
1009         if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1010             locoff == ZIP64_MAGICVAL) {
1011             jint off = 0;
1012             while ((off + 4) < elen) {    // spec: HeaderID+DataSize+Data
1013                 jint sz = SH(extra, off + 2);
1014                 if (SH(extra, off) == ZIP64_EXTID) {
1015                     off += 4;
1016                     if (ze->size == ZIP64_MAGICVAL) {
1017                         // if invalid zip64 extra fields, just skip
1018                         if (sz < 8 || (off + 8) > elen)
1019                             break;
1020                         ze->size = LL(extra, off);
1021                         sz -= 8;
1022                         off += 8;
1023                     }
1024                     if (ze->csize == ZIP64_MAGICVAL) {
1025                         if (sz < 8 || (off + 8) > elen)
1026                             break;
1027                         ze->csize = LL(extra, off);
1028                         sz -= 8;
1029                         off += 8;
1030                     }
1031                     if (locoff == ZIP64_MAGICVAL) {
1032                         if (sz < 8 || (off + 8) > elen)
1033                             break;
1034                         ze->pos = -(zip->locpos +  LL(extra, off));
1035                         sz -= 8;
1036                         off += 8;
1037                     }
1038                     break;
1039                 }
1040                 off += (sz + 4);
1041             }
1042         }
1043     }
1044 
1045     if (clen > 0) {
1046         /* This entry has a comment */
1047         if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1048         memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1049         ze->comment[clen] = '\0';
1050     }
1051     goto Finally;
1052 
1053  Catch:
1054     free(ze->name);
1055     free(ze->extra);
1056     free(ze->comment);
1057     free(ze);
1058     ze = NULL;
1059 
1060  Finally:
1061 #ifdef USE_MMAP
1062     if (!zip->usemmap)
1063 #endif
1064         if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1065     return ze;
1066 }
1067 
1068 /*
1069  * Free the given jzentry.
1070  * In fact we maintain a one-entry cache of the most recently used
1071  * jzentry for each zip.  This optimizes a common access pattern.
1072  */
1073 
1074 void
1075 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1076 {
1077     jzentry *last;
1078     ZIP_Lock(jz);
1079     last = jz->cache;
1080     jz->cache = ze;
1081     ZIP_Unlock(jz);
1082     if (last != NULL) {
1083         /* Free the previously cached jzentry */
1084         free(last->name);
1085         if (last->extra)   free(last->extra);
1086         if (last->comment) free(last->comment);
1087         free(last);
1088     }
1089 }
1090 
1091 /*
1092  * Returns the zip entry corresponding to the specified name, or
1093  * NULL if not found.
1094  */
1095 jzentry *
1096 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1097 {
1098     unsigned int hsh = hash(name);
1099     jint idx;
1100     jzentry *ze = 0;
1101 
1102     ZIP_Lock(zip);
1103     if (zip->total == 0) {
1104         goto Finally;
1105     }
1106 
1107     idx = zip->table[hsh % zip->tablelen];
1108 
1109     /*
1110      * This while loop is an optimization where a double lookup
1111      * for name and name+/ is being performed. The name char
1112      * array has enough room at the end to try again with a
1113      * slash appended if the first table lookup does not succeed.
1114      */
1115     while(1) {
1116 
1117         /* Check the cached entry first */
1118         ze = zip->cache;
1119         if (ze && strcmp(ze->name,name) == 0) {
1120             /* Cache hit!  Remove and return the cached entry. */
1121             zip->cache = 0;
1122             ZIP_Unlock(zip);
1123             return ze;
1124         }
1125         ze = 0;
1126 
1127         /*
1128          * Search down the target hash chain for a cell whose
1129          * 32 bit hash matches the hashed name.
1130          */
1131         while (idx != ZIP_ENDCHAIN) {
1132             jzcell *zc = &zip->entries[idx];
1133 
1134             if (zc->hash == hsh) {
1135                 /*
1136                  * OK, we've found a ZIP entry whose 32 bit hashcode
1137                  * matches the name we're looking for.  Try to read
1138                  * its entry information from the CEN.  If the CEN
1139                  * name matches the name we're looking for, we're
1140                  * done.
1141                  * If the names don't match (which should be very rare)
1142                  * we keep searching.
1143                  */
1144                 ze = newEntry(zip, zc, ACCESS_RANDOM);
1145                 if (ze && strcmp(ze->name, name)==0) {
1146                     break;
1147                 }
1148                 if (ze != 0) {
1149                     /* We need to release the lock across the free call */
1150                     ZIP_Unlock(zip);
1151                     ZIP_FreeEntry(zip, ze);
1152                     ZIP_Lock(zip);
1153                 }
1154                 ze = 0;
1155             }
1156             idx = zc->next;
1157         }
1158 
1159         /* Entry found, return it */
1160         if (ze != 0) {
1161             break;
1162         }
1163 
1164         /* If no real length was passed in, we are done */
1165         if (ulen == 0) {
1166             break;
1167         }
1168 
1169         /* Slash is already there? */
1170         if (name[ulen-1] == '/') {
1171             break;
1172         }
1173 
1174         /* Add slash and try once more */
1175         name[ulen] = '/';
1176         name[ulen+1] = '\0';
1177         hsh = hash_append(hsh, '/');
1178         idx = zip->table[hsh % zip->tablelen];
1179         ulen = 0;
1180     }
1181 
1182 Finally:
1183     ZIP_Unlock(zip);
1184     return ze;
1185 }
1186 
1187 /*
1188  * Returns the n'th (starting at zero) zip file entry, or NULL if the
1189  * specified index was out of range.
1190  */
1191 jzentry * JNICALL
1192 ZIP_GetNextEntry(jzfile *zip, jint n)
1193 {
1194     jzentry *result;
1195     if (n < 0 || n >= zip->total) {
1196         return 0;
1197     }
1198     ZIP_Lock(zip);
1199     result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1200     ZIP_Unlock(zip);
1201     return result;
1202 }
1203 
1204 /*
1205  * Locks the specified zip file for reading.
1206  */
1207 void
1208 ZIP_Lock(jzfile *zip)
1209 {
1210     MLOCK(zip->lock);
1211 }
1212 
1213 /*
1214  * Unlocks the specified zip file.
1215  */
1216 void
1217 ZIP_Unlock(jzfile *zip)
1218 {
1219     MUNLOCK(zip->lock);
1220 }
1221 
1222 /*
1223  * Returns the offset of the entry data within the zip file.
1224  * Returns -1 if an error occurred, in which case zip->msg will
1225  * contain the error text.
1226  */
1227 jlong
1228 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1229 {
1230     /* The Zip file spec explicitly allows the LOC extra data size to
1231      * be different from the CEN extra data size, although the JDK
1232      * never creates such zip files.  Since we cannot trust the CEN
1233      * extra data size, we need to read the LOC to determine the entry
1234      * data offset.  We do this lazily to avoid touching the virtual
1235      * memory page containing the LOC when initializing jzentry
1236      * objects.  (This speeds up javac by a factor of 10 when the JDK
1237      * is installed on a very slow filesystem.)
1238      */
1239     if (entry->pos <= 0) {
1240         unsigned char loc[LOCHDR];
1241         if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1242             zip->msg = "error reading zip file";
1243             return -1;
1244         }
1245         if (GETSIG(loc) != LOCSIG) {
1246             zip->msg = "invalid LOC header (bad signature)";
1247             return -1;
1248         }
1249         entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1250     }
1251     return entry->pos;
1252 }
1253 
1254 /*
1255  * Reads bytes from the specified zip entry. Assumes that the zip
1256  * file had been previously locked with ZIP_Lock(). Returns the
1257  * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1258  * then a zip error occurred and zip->msg contains the error text.
1259  *
1260  * The current implementation does not support reading an entry that
1261  * has the size bigger than 2**32 bytes in ONE invocation.
1262  */
1263 jint
1264 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1265 {
1266     jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1267     jlong start;
1268 
1269     /* Clear previous zip error */
1270     zip->msg = NULL;
1271 
1272     /* Check specified position */
1273     if (pos < 0 || pos > entry_size - 1) {
1274         zip->msg = "ZIP_Read: specified offset out of range";
1275         return -1;
1276     }
1277 
1278     /* Check specified length */
1279     if (len <= 0)
1280         return 0;
1281     if (len > entry_size - pos)
1282         len = (jint)(entry_size - pos);
1283 
1284     /* Get file offset to start reading data */
1285     start = ZIP_GetEntryDataOffset(zip, entry);
1286     if (start < 0)
1287         return -1;
1288     start += pos;
1289 
1290     if (start + len > zip->len) {
1291         zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1292         return -1;
1293     }
1294 
1295     if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1296         zip->msg = "ZIP_Read: error reading zip file";
1297         return -1;
1298     }
1299     return len;
1300 }
1301 
1302 
1303 /* The maximum size of a stack-allocated buffer.
1304  */
1305 #define BUF_SIZE 4096
1306 
1307 /*
1308  * This function is used by the runtime system to load compressed entries
1309  * from ZIP/JAR files specified in the class path. It is defined here
1310  * so that it can be dynamically loaded by the runtime if the zip library
1311  * is found.
1312  *
1313  * The current implementation does not support reading an entry that
1314  * has the size bigger than 2**32 bytes in ONE invocation.
1315  */
1316 jboolean
1317 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1318 {
1319     z_stream strm;
1320     char tmp[BUF_SIZE];
1321     jlong pos = 0;
1322     jlong count = entry->csize;
1323 
1324     *msg = 0; /* Reset error message */
1325 
1326     if (count == 0) {
1327         *msg = "inflateFully: entry not compressed";
1328         return JNI_FALSE;
1329     }
1330 
1331     memset(&strm, 0, sizeof(z_stream));
1332     if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1333         *msg = strm.msg;
1334         return JNI_FALSE;
1335     }
1336 
1337     strm.next_out = buf;
1338     strm.avail_out = (uInt)entry->size;
1339 
1340     while (count > 0) {
1341         jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1342         ZIP_Lock(zip);
1343         n = ZIP_Read(zip, entry, pos, tmp, n);
1344         ZIP_Unlock(zip);
1345         if (n <= 0) {
1346             if (n == 0) {
1347                 *msg = "inflateFully: Unexpected end of file";
1348             }
1349             inflateEnd(&strm);
1350             return JNI_FALSE;
1351         }
1352         pos += n;
1353         count -= n;
1354         strm.next_in = (Bytef *)tmp;
1355         strm.avail_in = n;
1356         do {
1357             switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1358             case Z_OK:
1359                 break;
1360             case Z_STREAM_END:
1361                 if (count != 0 || strm.total_out != entry->size) {
1362                     *msg = "inflateFully: Unexpected end of stream";
1363                     inflateEnd(&strm);
1364                     return JNI_FALSE;
1365                 }
1366                 break;
1367             default:
1368                 break;
1369             }
1370         } while (strm.avail_in > 0);
1371     }
1372     inflateEnd(&strm);
1373     return JNI_TRUE;
1374 }
1375 
1376 /*
1377  * The current implementation does not support reading an entry that
1378  * has the size bigger than 2**32 bytes in ONE invocation.
1379  */
1380 jzentry * JNICALL
1381 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1382 {
1383     jzentry *entry = ZIP_GetEntry(zip, name, 0);
1384     if (entry) {
1385         *sizeP = (jint)entry->size;
1386         *nameLenP = strlen(entry->name);
1387     }
1388     return entry;
1389 }
1390 
1391 /*
1392  * Reads a zip file entry into the specified byte array
1393  * When the method completes, it releases the jzentry.
1394  * Note: this is called from the separately delivered VM (hotspot/classic)
1395  * so we have to be careful to maintain the expected behaviour.
1396  */
1397 jboolean JNICALL
1398 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1399 {
1400     char *msg;
1401 
1402     strcpy(entryname, entry->name);
1403     if (entry->csize == 0) {
1404         /* Entry is stored */
1405         jlong pos = 0;
1406         jlong size = entry->size;
1407         while (pos < size) {
1408             jint n;
1409             jlong limit = ((((jlong) 1) << 31) - 1);
1410             jint count = (size - pos < limit) ?
1411                 /* These casts suppress a VC++ Internal Compiler Error */
1412                 (jint) (size - pos) :
1413                 (jint) limit;
1414             ZIP_Lock(zip);
1415             n = ZIP_Read(zip, entry, pos, buf, count);
1416             msg = zip->msg;
1417             ZIP_Unlock(zip);
1418             if (n == -1) {
1419                 jio_fprintf(stderr, "%s: %s\n", zip->name,
1420                             msg != 0 ? msg : strerror(errno));
1421                 return JNI_FALSE;
1422             }
1423             buf += n;
1424             pos += n;
1425         }
1426     } else {
1427         /* Entry is compressed */
1428         int ok = InflateFully(zip, entry, buf, &msg);
1429         if (!ok) {
1430             if ((msg == NULL) || (*msg == 0)) {
1431                 msg = zip->msg;
1432             }
1433             jio_fprintf(stderr, "%s: %s\n", zip->name,
1434                         msg != 0 ? msg : strerror(errno));
1435             return JNI_FALSE;
1436         }
1437     }
1438 
1439     ZIP_FreeEntry(zip, entry);
1440 
1441     return JNI_TRUE;
1442 }