1 /*
   2  * Copyright (c) 1995, 2013, 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 legal 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     ze->nlen = nlen;
1025     if (elen > 0) {
1026         char *extra = cen + CENHDR + nlen;
1027 
1028         /* This entry has "extra" data */
1029         if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1030         ze->extra[0] = (unsigned char) elen;
1031         ze->extra[1] = (unsigned char) (elen >> 8);
1032         memcpy(ze->extra+2, extra, elen);
1033         if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1034             locoff == ZIP64_MAGICVAL) {
1035             jint off = 0;
1036             while ((off + 4) < elen) {    // spec: HeaderID+DataSize+Data
1037                 jint sz = SH(extra, off + 2);
1038                 if (SH(extra, off) == ZIP64_EXTID) {
1039                     off += 4;
1040                     if (ze->size == ZIP64_MAGICVAL) {
1041                         // if invalid zip64 extra fields, just skip
1042                         if (sz < 8 || (off + 8) > elen)
1043                             break;
1044                         ze->size = LL(extra, off);
1045                         sz -= 8;
1046                         off += 8;
1047                     }
1048                     if (ze->csize == ZIP64_MAGICVAL) {
1049                         if (sz < 8 || (off + 8) > elen)
1050                             break;
1051                         ze->csize = LL(extra, off);
1052                         sz -= 8;
1053                         off += 8;
1054                     }
1055                     if (locoff == ZIP64_MAGICVAL) {
1056                         if (sz < 8 || (off + 8) > elen)
1057                             break;
1058                         ze->pos = -(zip->locpos +  LL(extra, off));
1059                         sz -= 8;
1060                         off += 8;
1061                     }
1062                     break;
1063                 }
1064                 off += (sz + 4);
1065             }
1066         }
1067     }
1068 
1069     if (clen > 0) {
1070         /* This entry has a comment */
1071         if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1072         memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1073         ze->comment[clen] = '\0';
1074     }
1075     goto Finally;
1076 
1077  Catch:
1078     free(ze->name);
1079     free(ze->extra);
1080     free(ze->comment);
1081     free(ze);
1082     ze = NULL;
1083 
1084  Finally:
1085 #ifdef USE_MMAP
1086     if (!zip->usemmap)
1087 #endif
1088         if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1089     return ze;
1090 }
1091 
1092 /*
1093  * Free the given jzentry.
1094  * In fact we maintain a one-entry cache of the most recently used
1095  * jzentry for each zip.  This optimizes a common access pattern.
1096  */
1097 
1098 void
1099 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1100 {
1101     jzentry *last;
1102     ZIP_Lock(jz);
1103     last = jz->cache;
1104     jz->cache = ze;
1105     ZIP_Unlock(jz);
1106     if (last != NULL) {
1107         /* Free the previously cached jzentry */
1108         free(last->name);
1109         if (last->extra)   free(last->extra);
1110         if (last->comment) free(last->comment);
1111         free(last);
1112     }
1113 }
1114 
1115 /*
1116  * Returns the zip entry corresponding to the specified name, or
1117  * NULL if not found.
1118  */
1119 jzentry *
1120 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1121 {
1122     if (ulen == 0) {
1123         return ZIP_GetEntry2(zip, name, strlen(name), JNI_FALSE);
1124     }
1125     return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);
1126 }
1127 
1128 jboolean equals(char* name1, int len1, char* name2, int len2) {
1129     if (len1 != len2) {
1130         return JNI_FALSE;
1131     }
1132     while (len1-- > 0) {
1133         if (*name1++ != *name2++) {
1134             return JNI_FALSE;
1135         }
1136     }
1137     return JNI_TRUE;
1138 }
1139 
1140 /*
1141  * Returns the zip entry corresponding to the specified name, or
1142  * NULL if not found.
1143  * This method supports embedded null character in "name", use ulen
1144  * for the length of "name".
1145  */
1146 jzentry *
1147 ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)
1148 {
1149     unsigned int hsh = hashN(name, ulen);
1150     jint idx;
1151     jzentry *ze = 0;
1152 
1153     ZIP_Lock(zip);
1154     if (zip->total == 0) {
1155         goto Finally;
1156     }
1157 
1158     idx = zip->table[hsh % zip->tablelen];
1159 
1160     /*
1161      * This while loop is an optimization where a double lookup
1162      * for name and name+/ is being performed. The name char
1163      * array has enough room at the end to try again with a
1164      * slash appended if the first table lookup does not succeed.
1165      */
1166     while(1) {
1167 
1168         /* Check the cached entry first */
1169         ze = zip->cache;
1170         if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1171             /* Cache hit!  Remove and return the cached entry. */
1172             zip->cache = 0;
1173             ZIP_Unlock(zip);
1174             return ze;
1175         }
1176         ze = 0;
1177 
1178         /*
1179          * Search down the target hash chain for a cell whose
1180          * 32 bit hash matches the hashed name.
1181          */
1182         while (idx != ZIP_ENDCHAIN) {
1183             jzcell *zc = &zip->entries[idx];
1184 
1185             if (zc->hash == hsh) {
1186                 /*
1187                  * OK, we've found a ZIP entry whose 32 bit hashcode
1188                  * matches the name we're looking for.  Try to read
1189                  * its entry information from the CEN.  If the CEN
1190                  * name matches the name we're looking for, we're
1191                  * done.
1192                  * If the names don't match (which should be very rare)
1193                  * we keep searching.
1194                  */
1195                 ze = newEntry(zip, zc, ACCESS_RANDOM);
1196                 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1197                     break;
1198                 }
1199                 if (ze != 0) {
1200                     /* We need to release the lock across the free call */
1201                     ZIP_Unlock(zip);
1202                     ZIP_FreeEntry(zip, ze);
1203                     ZIP_Lock(zip);
1204                 }
1205                 ze = 0;
1206             }
1207             idx = zc->next;
1208         }
1209 
1210         /* Entry found, return it */
1211         if (ze != 0) {
1212             break;
1213         }
1214 
1215         /* If no need to try appending slash, we are done */
1216         if (!addSlash) {
1217             break;
1218         }
1219 
1220         /* Slash is already there? */
1221         if (name[ulen-1] == '/') {
1222             break;
1223         }
1224 
1225         /* Add slash and try once more */
1226         name[ulen++] = '/';
1227         name[ulen] = '\0';
1228         hsh = hash_append(hsh, '/');
1229         idx = zip->table[hsh % zip->tablelen];
1230         addSlash = JNI_FALSE;
1231     }
1232 
1233 Finally:
1234     ZIP_Unlock(zip);
1235     return ze;
1236 }
1237 
1238 /*
1239  * Returns the n'th (starting at zero) zip file entry, or NULL if the
1240  * specified index was out of range.
1241  */
1242 jzentry * JNICALL
1243 ZIP_GetNextEntry(jzfile *zip, jint n)
1244 {
1245     jzentry *result;
1246     if (n < 0 || n >= zip->total) {
1247         return 0;
1248     }
1249     ZIP_Lock(zip);
1250     result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1251     ZIP_Unlock(zip);
1252     return result;
1253 }
1254 
1255 /*
1256  * Locks the specified zip file for reading.
1257  */
1258 void
1259 ZIP_Lock(jzfile *zip)
1260 {
1261     MLOCK(zip->lock);
1262 }
1263 
1264 /*
1265  * Unlocks the specified zip file.
1266  */
1267 void
1268 ZIP_Unlock(jzfile *zip)
1269 {
1270     MUNLOCK(zip->lock);
1271 }
1272 
1273 /*
1274  * Returns the offset of the entry data within the zip file.
1275  * Returns -1 if an error occurred, in which case zip->msg will
1276  * contain the error text.
1277  */
1278 jlong
1279 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1280 {
1281     /* The Zip file spec explicitly allows the LOC extra data size to
1282      * be different from the CEN extra data size, although the JDK
1283      * never creates such zip files.  Since we cannot trust the CEN
1284      * extra data size, we need to read the LOC to determine the entry
1285      * data offset.  We do this lazily to avoid touching the virtual
1286      * memory page containing the LOC when initializing jzentry
1287      * objects.  (This speeds up javac by a factor of 10 when the JDK
1288      * is installed on a very slow filesystem.)
1289      */
1290     if (entry->pos <= 0) {
1291         unsigned char loc[LOCHDR];
1292         if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1293             zip->msg = "error reading zip file";
1294             return -1;
1295         }
1296         if (GETSIG(loc) != LOCSIG) {
1297             zip->msg = "invalid LOC header (bad signature)";
1298             return -1;
1299         }
1300         entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1301     }
1302     return entry->pos;
1303 }
1304 
1305 /*
1306  * Reads bytes from the specified zip entry. Assumes that the zip
1307  * file had been previously locked with ZIP_Lock(). Returns the
1308  * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1309  * then a zip error occurred and zip->msg contains the error text.
1310  *
1311  * The current implementation does not support reading an entry that
1312  * has the size bigger than 2**32 bytes in ONE invocation.
1313  */
1314 jint
1315 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1316 {
1317     jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1318     jlong start;
1319 
1320     /* Clear previous zip error */
1321     zip->msg = NULL;
1322 
1323     /* Check specified position */
1324     if (pos < 0 || pos > entry_size - 1) {
1325         zip->msg = "ZIP_Read: specified offset out of range";
1326         return -1;
1327     }
1328 
1329     /* Check specified length */
1330     if (len <= 0)
1331         return 0;
1332     if (len > entry_size - pos)
1333         len = (jint)(entry_size - pos);
1334 
1335     /* Get file offset to start reading data */
1336     start = ZIP_GetEntryDataOffset(zip, entry);
1337     if (start < 0)
1338         return -1;
1339     start += pos;
1340 
1341     if (start + len > zip->len) {
1342         zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1343         return -1;
1344     }
1345 
1346     if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1347         zip->msg = "ZIP_Read: error reading zip file";
1348         return -1;
1349     }
1350     return len;
1351 }
1352 
1353 
1354 /* The maximum size of a stack-allocated buffer.
1355  */
1356 #define BUF_SIZE 4096
1357 
1358 /*
1359  * This function is used by the runtime system to load compressed entries
1360  * from ZIP/JAR files specified in the class path. It is defined here
1361  * so that it can be dynamically loaded by the runtime if the zip library
1362  * is found.
1363  *
1364  * The current implementation does not support reading an entry that
1365  * has the size bigger than 2**32 bytes in ONE invocation.
1366  */
1367 jboolean
1368 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1369 {
1370     z_stream strm;
1371     char tmp[BUF_SIZE];
1372     jlong pos = 0;
1373     jlong count = entry->csize;
1374 
1375     *msg = 0; /* Reset error message */
1376 
1377     if (count == 0) {
1378         *msg = "inflateFully: entry not compressed";
1379         return JNI_FALSE;
1380     }
1381 
1382     memset(&strm, 0, sizeof(z_stream));
1383     if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1384         *msg = strm.msg;
1385         return JNI_FALSE;
1386     }
1387 
1388     strm.next_out = buf;
1389     strm.avail_out = (uInt)entry->size;
1390 
1391     while (count > 0) {
1392         jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1393         ZIP_Lock(zip);
1394         n = ZIP_Read(zip, entry, pos, tmp, n);
1395         ZIP_Unlock(zip);
1396         if (n <= 0) {
1397             if (n == 0) {
1398                 *msg = "inflateFully: Unexpected end of file";
1399             }
1400             inflateEnd(&strm);
1401             return JNI_FALSE;
1402         }
1403         pos += n;
1404         count -= n;
1405         strm.next_in = (Bytef *)tmp;
1406         strm.avail_in = n;
1407         do {
1408             switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1409             case Z_OK:
1410                 break;
1411             case Z_STREAM_END:
1412                 if (count != 0 || strm.total_out != entry->size) {
1413                     *msg = "inflateFully: Unexpected end of stream";
1414                     inflateEnd(&strm);
1415                     return JNI_FALSE;
1416                 }
1417                 break;
1418             default:
1419                 break;
1420             }
1421         } while (strm.avail_in > 0);
1422     }
1423     inflateEnd(&strm);
1424     return JNI_TRUE;
1425 }
1426 
1427 /*
1428  * The current implementation does not support reading an entry that
1429  * has the size bigger than 2**32 bytes in ONE invocation.
1430  */
1431 jzentry * JNICALL
1432 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1433 {
1434     jzentry *entry = ZIP_GetEntry(zip, name, 0);
1435     if (entry) {
1436         *sizeP = (jint)entry->size;
1437         *nameLenP = strlen(entry->name);
1438     }
1439     return entry;
1440 }
1441 
1442 /*
1443  * Reads a zip file entry into the specified byte array
1444  * When the method completes, it releases the jzentry.
1445  * Note: this is called from the separately delivered VM (hotspot/classic)
1446  * so we have to be careful to maintain the expected behaviour.
1447  */
1448 jboolean JNICALL
1449 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1450 {
1451     char *msg;
1452 
1453     strcpy(entryname, entry->name);
1454     if (entry->csize == 0) {
1455         /* Entry is stored */
1456         jlong pos = 0;
1457         jlong size = entry->size;
1458         while (pos < size) {
1459             jint n;
1460             jlong limit = ((((jlong) 1) << 31) - 1);
1461             jint count = (size - pos < limit) ?
1462                 /* These casts suppress a VC++ Internal Compiler Error */
1463                 (jint) (size - pos) :
1464                 (jint) limit;
1465             ZIP_Lock(zip);
1466             n = ZIP_Read(zip, entry, pos, buf, count);
1467             msg = zip->msg;
1468             ZIP_Unlock(zip);
1469             if (n == -1) {
1470                 jio_fprintf(stderr, "%s: %s\n", zip->name,
1471                             msg != 0 ? msg : strerror(errno));
1472                 return JNI_FALSE;
1473             }
1474             buf += n;
1475             pos += n;
1476         }
1477     } else {
1478         /* Entry is compressed */
1479         int ok = InflateFully(zip, entry, buf, &msg);
1480         if (!ok) {
1481             if ((msg == NULL) || (*msg == 0)) {
1482                 msg = zip->msg;
1483             }
1484             jio_fprintf(stderr, "%s: %s\n", zip->name,
1485                         msg != 0 ? msg : strerror(errno));
1486             return JNI_FALSE;
1487         }
1488     }
1489 
1490     ZIP_FreeEntry(zip, entry);
1491 
1492     return JNI_TRUE;
1493 }