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