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