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