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     if (entries == NULL || table == NULL) goto Catch;
 663     for (j = 0; j < tablelen; j++)
 664         table[j] = ZIP_ENDCHAIN;
 665 
 666     /* Iterate through the entries in the central directory */
 667     for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {
 668         /* Following are unsigned 16-bit */
 669         jint method, nlen;
 670         unsigned int hsh;
 671 
 672         if (i >= total) {
 673             /* This will only happen if the zip file has an incorrect
 674              * ENDTOT field, which usually means it contains more than
 675              * 65535 entries. */
 676             cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend));
 677             goto Finally;
 678         }
 679 
 680         method = CENHOW(cp);
 681         nlen   = CENNAM(cp);
 682 
 683         if (GETSIG(cp) != CENSIG)
 684             ZIP_FORMAT_ERROR("invalid CEN header (bad signature)");
 685         if (CENFLG(cp) & 1)
 686             ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)");
 687         if (method != STORED && method != DEFLATED)
 688             ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)");
 689         if (cp + CENHDR + nlen > cenend)
 690             ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
 691 
 692         /* if the entry is metadata add it to our metadata names */
 693         if (isMetaName((char *)cp+CENHDR, nlen))
 694             if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0)
 695                 goto Catch;
 696 
 697         /* Record the CEN offset and the name hash in our hash cell. */
 698         entries[i].cenpos = cenpos + (cp - cenbuf);
 699         entries[i].hash = hashN((char *)cp+CENHDR, nlen);
 700 
 701         /* Add the entry to the hash table */
 702         hsh = entries[i].hash % tablelen;
 703         entries[i].next = table[hsh];
 704         table[hsh] = i;
 705     }
 706     if (cp != cenend)
 707         ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
 708 
 709     zip->total = i;
 710     goto Finally;
 711 
 712  Catch:
 713     freeCEN(zip);
 714     cenpos = -1;
 715 
 716  Finally:
 717 #ifdef USE_MMAP
 718     if (!zip->usemmap)
 719 #endif
 720         free(cenbuf);
 721 
 722     return cenpos;
 723 }
 724 
 725 /*
 726  * Opens a zip file with the specified mode. Returns the jzfile object
 727  * or NULL if an error occurred. If a zip error occurred then *pmsg will
 728  * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be
 729  * set to NULL. Caller is responsible to free the error message.
 730  */
 731 jzfile *
 732 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified)
 733 {
 734     jzfile *zip = NULL;
 735 
 736     /* Clear zip error message */
 737     if (pmsg != 0) {
 738         *pmsg = NULL;
 739     }
 740 
 741     zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
 742 
 743     if (zip == NULL && *pmsg == NULL) {
 744         ZFILE zfd = ZFILE_Open(name, mode);
 745         zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
 746     }
 747     return zip;
 748 }
 749 
 750 /*
 751  * Returns the jzfile corresponding to the given file name from the cache of
 752  * zip files, or NULL if the file is not in the cache.  If the name is longer
 753  * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
 754  * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller
 755  * is responsible to free the error message.
 756  */
 757 jzfile *
 758 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
 759 {
 760     char buf[PATH_MAX];
 761     jzfile *zip;
 762 
 763     if (InitializeZip()) {
 764         return NULL;
 765     }
 766 
 767     /* Clear zip error message */
 768     if (pmsg != 0) {
 769         *pmsg = NULL;
 770     }
 771 
 772     if (strlen(name) >= PATH_MAX) {
 773         if (pmsg) {
 774             *pmsg = strdup("zip file name too long");
 775         }
 776         return NULL;
 777     }
 778     strcpy(buf, name);
 779     JVM_NativePath(buf);
 780     name = buf;
 781 
 782     MLOCK(zfiles_lock);
 783     for (zip = zfiles; zip != NULL; zip = zip->next) {
 784         if (strcmp(name, zip->name) == 0
 785             && (zip->lastModified == lastModified || zip->lastModified == 0)
 786             && zip->refs < MAXREFS) {
 787             zip->refs++;
 788             break;
 789         }
 790     }
 791     MUNLOCK(zfiles_lock);
 792     return zip;
 793 }
 794 
 795 /*
 796  * Reads data from the given file descriptor to create a jzfile, puts the
 797  * jzfile in a cache, and returns that jzfile.  Returns NULL in case of error.
 798  * If a zip error occurs, then *pmsg will be set to the error message text if
 799  * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to
 800  * free the error message.
 801  */
 802 
 803 jzfile *
 804 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
 805 {
 806     return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
 807 }
 808 
 809 jzfile *
 810 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
 811                  jboolean usemmap)
 812 {
 813     char errbuf[256];
 814     jlong len;
 815     jzfile *zip;
 816 
 817     if ((zip = allocZip(name)) == NULL) {
 818         return NULL;
 819     }
 820 
 821 #ifdef USE_MMAP
 822     zip->usemmap = usemmap;
 823 #endif
 824     zip->refs = 1;
 825     zip->lastModified = lastModified;
 826 
 827     if (zfd == -1) {
 828         if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
 829             *pmsg = strdup(errbuf);
 830         freeZip(zip);
 831         return NULL;
 832     }
 833 
 834     // Assumption, zfd refers to start of file. Trivially, reuse errbuf.
 835     if (readFully(zfd, errbuf, 4) != -1) {  // errors will be handled later
 836         if (GETSIG(errbuf) == LOCSIG)
 837             zip->locsig = JNI_TRUE;
 838         else
 839             zip->locsig = JNI_FALSE;
 840     }
 841 
 842     len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
 843     if (len <= 0) {
 844         if (len == 0) { /* zip file is empty */
 845             if (pmsg) {
 846                 *pmsg = strdup("zip file is empty");
 847             }
 848         } else { /* error */
 849             if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
 850                 *pmsg = strdup(errbuf);
 851         }
 852         ZFILE_Close(zfd);
 853         freeZip(zip);
 854         return NULL;
 855     }
 856 
 857     zip->zfd = zfd;
 858     if (readCEN(zip, -1) < 0) {
 859         /* An error occurred while trying to read the zip file */
 860         if (pmsg != 0) {
 861             /* Set the zip error message */
 862             if (zip->msg != NULL)
 863                 *pmsg = strdup(zip->msg);
 864         }
 865         freeZip(zip);
 866         return NULL;
 867     }
 868     MLOCK(zfiles_lock);
 869     zip->next = zfiles;
 870     zfiles = zip;
 871     MUNLOCK(zfiles_lock);
 872 
 873     return zip;
 874 }
 875 
 876 /*
 877  * Opens a zip file for reading. Returns the jzfile object or NULL
 878  * if an error occurred. If a zip error occurred then *msg will be
 879  * set to the error message text if msg != 0. Otherwise, *msg will be
 880  * set to NULL. Caller doesn't need to free the error message.
 881  */
 882 jzfile * JNICALL
 883 ZIP_Open(const char *name, char **pmsg)
 884 {
 885     jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);
 886     if (file == NULL && pmsg != NULL && *pmsg != NULL) {
 887         free(*pmsg);
 888         *pmsg = "Zip file open error";
 889     }
 890     return file;
 891 }
 892 
 893 /*
 894  * Closes the specified zip file object.
 895  */
 896 void JNICALL
 897 ZIP_Close(jzfile *zip)
 898 {
 899     MLOCK(zfiles_lock);
 900     if (--zip->refs > 0) {
 901         /* Still more references so just return */
 902         MUNLOCK(zfiles_lock);
 903         return;
 904     }
 905     /* No other references so close the file and remove from list */
 906     if (zfiles == zip) {
 907         zfiles = zfiles->next;
 908     } else {
 909         jzfile *zp;
 910         for (zp = zfiles; zp->next != 0; zp = zp->next) {
 911             if (zp->next == zip) {
 912                 zp->next = zip->next;
 913                 break;
 914             }
 915         }
 916     }
 917     MUNLOCK(zfiles_lock);
 918     freeZip(zip);
 919     return;
 920 }
 921 
 922 /* Empirically, most CEN headers are smaller than this. */
 923 #define AMPLE_CEN_HEADER_SIZE 160
 924 
 925 /* A good buffer size when we want to read CEN headers sequentially. */
 926 #define CENCACHE_PAGESIZE 8192
 927 
 928 static char *
 929 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
 930 {
 931     jint censize;
 932     ZFILE zfd = zip->zfd;
 933     char *cen;
 934     if (bufsize > zip->len - cenpos)
 935         bufsize = (jint)(zip->len - cenpos);
 936     if ((cen = malloc(bufsize)) == NULL)       goto Catch;
 937     if (readFullyAt(zfd, cen, bufsize, cenpos) == -1)     goto Catch;
 938     censize = CENSIZE(cen);
 939     if (censize <= bufsize) return cen;
 940     if ((cen = realloc(cen, censize)) == NULL)              goto Catch;
 941     if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch;
 942     return cen;
 943 
 944  Catch:
 945     free(cen);
 946     return NULL;
 947 }
 948 
 949 static char *
 950 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
 951 {
 952     cencache *cache = &zip->cencache;
 953     char *cen;
 954     if (cache->data != NULL
 955         && (cenpos >= cache->pos)
 956         && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
 957     {
 958         cen = cache->data + cenpos - cache->pos;
 959         if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
 960             /* A cache hit */
 961             return cen;
 962     }
 963 
 964     if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
 965         return NULL;
 966     free(cache->data);
 967     cache->data = cen;
 968     cache->pos  = cenpos;
 969     return cen;
 970 }
 971 
 972 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
 973 
 974 /*
 975  * Return a new initialized jzentry corresponding to a given hash cell.
 976  * In case of error, returns NULL.
 977  * We already sanity-checked all the CEN headers for ZIP format errors
 978  * in readCEN(), so we don't check them again here.
 979  * The ZIP lock should be held here.
 980  */
 981 static jzentry *
 982 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
 983 {
 984     jlong locoff;
 985     jint nlen, elen, clen;
 986     jzentry *ze;
 987     char *cen;
 988 
 989     if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
 990     ze->name    = NULL;
 991     ze->extra   = NULL;
 992     ze->comment = NULL;
 993 
 994 #ifdef USE_MMAP
 995     if (zip->usemmap) {
 996         cen = (char*) zip->maddr + zc->cenpos - zip->offset;
 997     } else
 998 #endif
 999     {
1000         if (accessHint == ACCESS_RANDOM)
1001             cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
1002         else
1003             cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
1004         if (cen == NULL) goto Catch;
1005     }
1006 
1007     nlen      = CENNAM(cen);
1008     elen      = CENEXT(cen);
1009     clen      = CENCOM(cen);
1010     ze->time  = CENTIM(cen);
1011     ze->size  = CENLEN(cen);
1012     ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
1013     ze->crc   = CENCRC(cen);
1014     locoff    = CENOFF(cen);
1015     ze->pos   = -(zip->locpos + locoff);
1016     ze->flag  = CENFLG(cen);
1017 
1018     if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
1019     memcpy(ze->name, cen + CENHDR, nlen);
1020     ze->name[nlen] = '\0';
1021     if (elen > 0) {
1022         char *extra = cen + CENHDR + nlen;
1023 
1024         /* This entry has "extra" data */
1025         if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1026         ze->extra[0] = (unsigned char) elen;
1027         ze->extra[1] = (unsigned char) (elen >> 8);
1028         memcpy(ze->extra+2, extra, elen);
1029         if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1030             locoff == ZIP64_MAGICVAL) {
1031             jint off = 0;
1032             while ((off + 4) < elen) {    // spec: HeaderID+DataSize+Data
1033                 jint sz = SH(extra, off + 2);
1034                 if (SH(extra, off) == ZIP64_EXTID) {
1035                     off += 4;
1036                     if (ze->size == ZIP64_MAGICVAL) {
1037                         // if invalid zip64 extra fields, just skip
1038                         if (sz < 8 || (off + 8) > elen)
1039                             break;
1040                         ze->size = LL(extra, off);
1041                         sz -= 8;
1042                         off += 8;
1043                     }
1044                     if (ze->csize == ZIP64_MAGICVAL) {
1045                         if (sz < 8 || (off + 8) > elen)
1046                             break;
1047                         ze->csize = LL(extra, off);
1048                         sz -= 8;
1049                         off += 8;
1050                     }
1051                     if (locoff == ZIP64_MAGICVAL) {
1052                         if (sz < 8 || (off + 8) > elen)
1053                             break;
1054                         ze->pos = -(zip->locpos +  LL(extra, off));
1055                         sz -= 8;
1056                         off += 8;
1057                     }
1058                     break;
1059                 }
1060                 off += (sz + 4);
1061             }
1062         }
1063     }
1064 
1065     if (clen > 0) {
1066         /* This entry has a comment */
1067         if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1068         memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1069         ze->comment[clen] = '\0';
1070     }
1071     goto Finally;
1072 
1073  Catch:
1074     free(ze->name);
1075     free(ze->extra);
1076     free(ze->comment);
1077     free(ze);
1078     ze = NULL;
1079 
1080  Finally:
1081 #ifdef USE_MMAP
1082     if (!zip->usemmap)
1083 #endif
1084         if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1085     return ze;
1086 }
1087 
1088 /*
1089  * Free the given jzentry.
1090  * In fact we maintain a one-entry cache of the most recently used
1091  * jzentry for each zip.  This optimizes a common access pattern.
1092  */
1093 
1094 void
1095 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1096 {
1097     jzentry *last;
1098     ZIP_Lock(jz);
1099     last = jz->cache;
1100     jz->cache = ze;
1101     ZIP_Unlock(jz);
1102     if (last != NULL) {
1103         /* Free the previously cached jzentry */
1104         free(last->name);
1105         if (last->extra)   free(last->extra);
1106         if (last->comment) free(last->comment);
1107         free(last);
1108     }
1109 }
1110 
1111 /*
1112  * Returns the zip entry corresponding to the specified name, or
1113  * NULL if not found.
1114  */
1115 jzentry *
1116 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1117 {
1118     unsigned int hsh = hash(name);
1119     jint idx;
1120     jzentry *ze = 0;
1121 
1122     ZIP_Lock(zip);
1123     if (zip->total == 0) {
1124         goto Finally;
1125     }
1126 
1127     idx = zip->table[hsh % zip->tablelen];
1128 
1129     /*
1130      * This while loop is an optimization where a double lookup
1131      * for name and name+/ is being performed. The name char
1132      * array has enough room at the end to try again with a
1133      * slash appended if the first table lookup does not succeed.
1134      */
1135     while(1) {
1136 
1137         /* Check the cached entry first */
1138         ze = zip->cache;
1139         if (ze && strcmp(ze->name,name) == 0) {
1140             /* Cache hit!  Remove and return the cached entry. */
1141             zip->cache = 0;
1142             ZIP_Unlock(zip);
1143             return ze;
1144         }
1145         ze = 0;
1146 
1147         /*
1148          * Search down the target hash chain for a cell whose
1149          * 32 bit hash matches the hashed name.
1150          */
1151         while (idx != ZIP_ENDCHAIN) {
1152             jzcell *zc = &zip->entries[idx];
1153 
1154             if (zc->hash == hsh) {
1155                 /*
1156                  * OK, we've found a ZIP entry whose 32 bit hashcode
1157                  * matches the name we're looking for.  Try to read
1158                  * its entry information from the CEN.  If the CEN
1159                  * name matches the name we're looking for, we're
1160                  * done.
1161                  * If the names don't match (which should be very rare)
1162                  * we keep searching.
1163                  */
1164                 ze = newEntry(zip, zc, ACCESS_RANDOM);
1165                 if (ze && strcmp(ze->name, name)==0) {
1166                     break;
1167                 }
1168                 if (ze != 0) {
1169                     /* We need to release the lock across the free call */
1170                     ZIP_Unlock(zip);
1171                     ZIP_FreeEntry(zip, ze);
1172                     ZIP_Lock(zip);
1173                 }
1174                 ze = 0;
1175             }
1176             idx = zc->next;
1177         }
1178 
1179         /* Entry found, return it */
1180         if (ze != 0) {
1181             break;
1182         }
1183 
1184         /* If no real length was passed in, we are done */
1185         if (ulen == 0) {
1186             break;
1187         }
1188 
1189         /* Slash is already there? */
1190         if (name[ulen-1] == '/') {
1191             break;
1192         }
1193 
1194         /* Add slash and try once more */
1195         name[ulen] = '/';
1196         name[ulen+1] = '\0';
1197         hsh = hash_append(hsh, '/');
1198         idx = zip->table[hsh % zip->tablelen];
1199         ulen = 0;
1200     }
1201 
1202 Finally:
1203     ZIP_Unlock(zip);
1204     return ze;
1205 }
1206 
1207 /*
1208  * Returns the n'th (starting at zero) zip file entry, or NULL if the
1209  * specified index was out of range.
1210  */
1211 jzentry * JNICALL
1212 ZIP_GetNextEntry(jzfile *zip, jint n)
1213 {
1214     jzentry *result;
1215     if (n < 0 || n >= zip->total) {
1216         return 0;
1217     }
1218     ZIP_Lock(zip);
1219     result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1220     ZIP_Unlock(zip);
1221     return result;
1222 }
1223 
1224 /*
1225  * Locks the specified zip file for reading.
1226  */
1227 void
1228 ZIP_Lock(jzfile *zip)
1229 {
1230     MLOCK(zip->lock);
1231 }
1232 
1233 /*
1234  * Unlocks the specified zip file.
1235  */
1236 void
1237 ZIP_Unlock(jzfile *zip)
1238 {
1239     MUNLOCK(zip->lock);
1240 }
1241 
1242 /*
1243  * Returns the offset of the entry data within the zip file.
1244  * Returns -1 if an error occurred, in which case zip->msg will
1245  * contain the error text.
1246  */
1247 jlong
1248 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1249 {
1250     /* The Zip file spec explicitly allows the LOC extra data size to
1251      * be different from the CEN extra data size, although the JDK
1252      * never creates such zip files.  Since we cannot trust the CEN
1253      * extra data size, we need to read the LOC to determine the entry
1254      * data offset.  We do this lazily to avoid touching the virtual
1255      * memory page containing the LOC when initializing jzentry
1256      * objects.  (This speeds up javac by a factor of 10 when the JDK
1257      * is installed on a very slow filesystem.)
1258      */
1259     if (entry->pos <= 0) {
1260         unsigned char loc[LOCHDR];
1261         if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1262             zip->msg = "error reading zip file";
1263             return -1;
1264         }
1265         if (GETSIG(loc) != LOCSIG) {
1266             zip->msg = "invalid LOC header (bad signature)";
1267             return -1;
1268         }
1269         entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1270     }
1271     return entry->pos;
1272 }
1273 
1274 /*
1275  * Reads bytes from the specified zip entry. Assumes that the zip
1276  * file had been previously locked with ZIP_Lock(). Returns the
1277  * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1278  * then a zip error occurred and zip->msg contains the error text.
1279  *
1280  * The current implementation does not support reading an entry that
1281  * has the size bigger than 2**32 bytes in ONE invocation.
1282  */
1283 jint
1284 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1285 {
1286     jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1287     jlong start;
1288 
1289     /* Clear previous zip error */
1290     zip->msg = NULL;
1291 
1292     /* Check specified position */
1293     if (pos < 0 || pos > entry_size - 1) {
1294         zip->msg = "ZIP_Read: specified offset out of range";
1295         return -1;
1296     }
1297 
1298     /* Check specified length */
1299     if (len <= 0)
1300         return 0;
1301     if (len > entry_size - pos)
1302         len = (jint)(entry_size - pos);
1303 
1304     /* Get file offset to start reading data */
1305     start = ZIP_GetEntryDataOffset(zip, entry);
1306     if (start < 0)
1307         return -1;
1308     start += pos;
1309 
1310     if (start + len > zip->len) {
1311         zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1312         return -1;
1313     }
1314 
1315     if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1316         zip->msg = "ZIP_Read: error reading zip file";
1317         return -1;
1318     }
1319     return len;
1320 }
1321 
1322 
1323 /* The maximum size of a stack-allocated buffer.
1324  */
1325 #define BUF_SIZE 4096
1326 
1327 /*
1328  * This function is used by the runtime system to load compressed entries
1329  * from ZIP/JAR files specified in the class path. It is defined here
1330  * so that it can be dynamically loaded by the runtime if the zip library
1331  * is found.
1332  *
1333  * The current implementation does not support reading an entry that
1334  * has the size bigger than 2**32 bytes in ONE invocation.
1335  */
1336 jboolean
1337 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1338 {
1339     z_stream strm;
1340     char tmp[BUF_SIZE];
1341     jlong pos = 0;
1342     jlong count = entry->csize;
1343 
1344     *msg = 0; /* Reset error message */
1345 
1346     if (count == 0) {
1347         *msg = "inflateFully: entry not compressed";
1348         return JNI_FALSE;
1349     }
1350 
1351     memset(&strm, 0, sizeof(z_stream));
1352     if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1353         *msg = strm.msg;
1354         return JNI_FALSE;
1355     }
1356 
1357     strm.next_out = buf;
1358     strm.avail_out = (uInt)entry->size;
1359 
1360     while (count > 0) {
1361         jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1362         ZIP_Lock(zip);
1363         n = ZIP_Read(zip, entry, pos, tmp, n);
1364         ZIP_Unlock(zip);
1365         if (n <= 0) {
1366             if (n == 0) {
1367                 *msg = "inflateFully: Unexpected end of file";
1368             }
1369             inflateEnd(&strm);
1370             return JNI_FALSE;
1371         }
1372         pos += n;
1373         count -= n;
1374         strm.next_in = (Bytef *)tmp;
1375         strm.avail_in = n;
1376         do {
1377             switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1378             case Z_OK:
1379                 break;
1380             case Z_STREAM_END:
1381                 if (count != 0 || strm.total_out != entry->size) {
1382                     *msg = "inflateFully: Unexpected end of stream";
1383                     inflateEnd(&strm);
1384                     return JNI_FALSE;
1385                 }
1386                 break;
1387             default:
1388                 break;
1389             }
1390         } while (strm.avail_in > 0);
1391     }
1392     inflateEnd(&strm);
1393     return JNI_TRUE;
1394 }
1395 
1396 /*
1397  * The current implementation does not support reading an entry that
1398  * has the size bigger than 2**32 bytes in ONE invocation.
1399  */
1400 jzentry * JNICALL
1401 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1402 {
1403     jzentry *entry = ZIP_GetEntry(zip, name, 0);
1404     if (entry) {
1405         *sizeP = (jint)entry->size;
1406         *nameLenP = strlen(entry->name);
1407     }
1408     return entry;
1409 }
1410 
1411 /*
1412  * Reads a zip file entry into the specified byte array
1413  * When the method completes, it releases the jzentry.
1414  * Note: this is called from the separately delivered VM (hotspot/classic)
1415  * so we have to be careful to maintain the expected behaviour.
1416  */
1417 jboolean JNICALL
1418 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1419 {
1420     char *msg;
1421 
1422     strcpy(entryname, entry->name);
1423     if (entry->csize == 0) {
1424         /* Entry is stored */
1425         jlong pos = 0;
1426         jlong size = entry->size;
1427         while (pos < size) {
1428             jint n;
1429             jlong limit = ((((jlong) 1) << 31) - 1);
1430             jint count = (size - pos < limit) ?
1431                 /* These casts suppress a VC++ Internal Compiler Error */
1432                 (jint) (size - pos) :
1433                 (jint) limit;
1434             ZIP_Lock(zip);
1435             n = ZIP_Read(zip, entry, pos, buf, count);
1436             msg = zip->msg;
1437             ZIP_Unlock(zip);
1438             if (n == -1) {
1439                 jio_fprintf(stderr, "%s: %s\n", zip->name,
1440                             msg != 0 ? msg : strerror(errno));
1441                 return JNI_FALSE;
1442             }
1443             buf += n;
1444             pos += n;
1445         }
1446     } else {
1447         /* Entry is compressed */
1448         int ok = InflateFully(zip, entry, buf, &msg);
1449         if (!ok) {
1450             if ((msg == NULL) || (*msg == 0)) {
1451                 msg = zip->msg;
1452             }
1453             jio_fprintf(stderr, "%s: %s\n", zip->name,
1454                         msg != 0 ? msg : strerror(errno));
1455             return JNI_FALSE;
1456         }
1457     }
1458 
1459     ZIP_FreeEntry(zip, entry);
1460 
1461     return JNI_TRUE;
1462 }