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