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
  76  */
  77 DEF_STATIC_JNI_OnLoad
  78 
  79 /*
  80  * The ZFILE_* functions exist to provide some platform-independence with
  81  * respect to file access needs.
  82  */
  83 
  84 /*
  85  * Opens the named file for reading, returning a ZFILE.
  86  *
  87  * Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c.
  88  * This function does not take JNIEnv* and uses CreateFile (instead of
  89  * CreateFileW).  The expectation is that this function will be called only
  90  * from ZIP_Open_Generic, which in turn is used by the JVM, where we do not
  91  * need to concern ourselves with wide chars.
  92  */
  93 static ZFILE
  94 ZFILE_Open(const char *fname, int flags) {
  95 #ifdef WIN32
  96     WCHAR *wfname, *wprefixed_fname;
  97     size_t fname_length;
  98     jlong fhandle;
  99     const DWORD access =
 100         (flags & O_RDWR)   ? (GENERIC_WRITE | GENERIC_READ) :
 101         (flags & O_WRONLY) ?  GENERIC_WRITE :
 102         GENERIC_READ;
 103     const DWORD sharing =
 104         FILE_SHARE_READ | FILE_SHARE_WRITE;
 105     const DWORD disposition =
 106         /* Note: O_TRUNC overrides O_CREAT */
 107         (flags & O_TRUNC) ? CREATE_ALWAYS :
 108         (flags & O_CREAT) ? OPEN_ALWAYS   :
 109         OPEN_EXISTING;
 110     const DWORD  maybeWriteThrough =
 111         (flags & (O_SYNC | O_DSYNC)) ?
 112         FILE_FLAG_WRITE_THROUGH :
 113         FILE_ATTRIBUTE_NORMAL;
 114     const DWORD maybeDeleteOnClose =
 115         (flags & O_TEMPORARY) ?
 116         FILE_FLAG_DELETE_ON_CLOSE :
 117         FILE_ATTRIBUTE_NORMAL;
 118     const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
 119 
 120     fname_length = strlen(fname);
 121     if (fname_length < MAX_PATH) {
 122         return (jlong)CreateFile(
 123             fname,              /* path name in multibyte char */
 124             access,             /* Read and/or write permission */
 125             sharing,            /* File sharing flags */
 126             NULL,               /* Security attributes */
 127             disposition,        /* creation disposition */
 128             flagsAndAttributes, /* flags and attributes */
 129             NULL);
 130     } else {
 131         /* Get required buffer size to convert to Unicode */
 132         int wfname_len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
 133                                              fname, -1, NULL, 0);
 134         if (wfname_len == 0) {
 135             return (jlong)INVALID_HANDLE_VALUE;
 136         }
 137         if ((wfname = (WCHAR*)malloc(wfname_len * sizeof(WCHAR))) == NULL) {
 138             return (jlong)INVALID_HANDLE_VALUE;
 139         }
 140         if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
 141                                 fname, -1, wfname, wfname_len) == 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     unsigned 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 != NULL) {
 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 maintenance;
 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 = mmap(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off_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 doesn't need to free the error message.
 761  * The error message, if set, points to a static thread-safe buffer.
 762  */
 763 jzfile *
 764 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified)
 765 {
 766     jzfile *zip = NULL;
 767 
 768     /* Clear zip error message */
 769     if (pmsg != NULL) {
 770         *pmsg = NULL;
 771     }
 772 
 773     zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
 774 
 775     if (zip == NULL && pmsg != NULL && *pmsg == NULL) {
 776         ZFILE zfd = ZFILE_Open(name, mode);
 777         zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
 778     }
 779     return zip;
 780 }
 781 
 782 /*
 783  * Returns the jzfile corresponding to the given file name from the cache of
 784  * zip files, or NULL if the file is not in the cache.  If the name is longer
 785  * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
 786  * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller
 787  * doesn't need to free the error message.
 788  */
 789 jzfile *
 790 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
 791 {
 792     char buf[PATH_MAX];
 793     jzfile *zip;
 794 
 795     if (InitializeZip()) {
 796         return NULL;
 797     }
 798 
 799     /* Clear zip error message */
 800     if (pmsg != NULL) {
 801         *pmsg = NULL;
 802     }
 803 
 804     if (strlen(name) >= PATH_MAX) {
 805         if (pmsg != NULL) {
 806             *pmsg = "zip file name too long";
 807         }
 808         return NULL;
 809     }
 810     strcpy(buf, name);
 811     JVM_NativePath(buf);
 812     name = buf;
 813 
 814     MLOCK(zfiles_lock);
 815     for (zip = zfiles; zip != NULL; zip = zip->next) {
 816         if (strcmp(name, zip->name) == 0
 817             && (zip->lastModified == lastModified || zip->lastModified == 0)
 818             && zip->refs < MAXREFS) {
 819             zip->refs++;
 820             break;
 821         }
 822     }
 823     MUNLOCK(zfiles_lock);
 824     return zip;
 825 }
 826 
 827 /*
 828  * Reads data from the given file descriptor to create a jzfile, puts the
 829  * jzfile in a cache, and returns that jzfile.  Returns NULL in case of error.
 830  * If a zip error occurs, then *pmsg will be set to the error message text if
 831  * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller doesn't need to
 832  * free the error message.
 833  */
 834 
 835 jzfile *
 836 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
 837 {
 838     return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
 839 }
 840 
 841 jzfile *
 842 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
 843                  jboolean usemmap)
 844 {
 845     char errbuf[256];
 846     jlong len;
 847     jzfile *zip;
 848 
 849     if ((zip = allocZip(name)) == NULL) {
 850         return NULL;
 851     }
 852 
 853 #ifdef USE_MMAP
 854     zip->usemmap = usemmap;
 855 #endif
 856     zip->refs = 1;
 857     zip->lastModified = lastModified;
 858 
 859     if (zfd == -1) {
 860         if (pmsg != NULL)
 861             *pmsg = "ZFILE_Open failed";
 862         freeZip(zip);
 863         return NULL;
 864     }
 865 
 866     // Assumption, zfd refers to start of file. Trivially, reuse errbuf.
 867     if (readFully(zfd, errbuf, 4) != -1) {  // errors will be handled later
 868         zip->locsig = LOCSIG_AT(errbuf) ? JNI_TRUE : JNI_FALSE;
 869     }
 870 
 871     len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
 872     if (len <= 0) {
 873         if (len == 0) { /* zip file is empty */
 874             if (pmsg != NULL) {
 875                 *pmsg = "zip file is empty";
 876             }
 877         } else { /* error */
 878             if (pmsg != NULL)
 879                 *pmsg = "IO_Lseek failed";
 880         }
 881         ZFILE_Close(zfd);
 882         freeZip(zip);
 883         return NULL;
 884     }
 885 
 886     zip->zfd = zfd;
 887     if (readCEN(zip, -1) < 0) {
 888         /* An error occurred while trying to read the zip file */
 889         if (pmsg != NULL) {
 890             /* Set the zip error message */
 891             *pmsg = 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     return file;
 915 }
 916 
 917 /*
 918  * Closes the specified zip file object.
 919  */
 920 JNIEXPORT void
 921 ZIP_Close(jzfile *zip)
 922 {
 923     MLOCK(zfiles_lock);
 924     if (--zip->refs > 0) {
 925         /* Still more references so just return */
 926         MUNLOCK(zfiles_lock);
 927         return;
 928     }
 929     /* No other references so close the file and remove from list */
 930     if (zfiles == zip) {
 931         zfiles = zfiles->next;
 932     } else {
 933         jzfile *zp;
 934         for (zp = zfiles; zp->next != 0; zp = zp->next) {
 935             if (zp->next == zip) {
 936                 zp->next = zip->next;
 937                 break;
 938             }
 939         }
 940     }
 941     MUNLOCK(zfiles_lock);
 942     freeZip(zip);
 943     return;
 944 }
 945 
 946 /* Empirically, most CEN headers are smaller than this. */
 947 #define AMPLE_CEN_HEADER_SIZE 160
 948 
 949 /* A good buffer size when we want to read CEN headers sequentially. */
 950 #define CENCACHE_PAGESIZE 8192
 951 
 952 static char *
 953 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
 954 {
 955     jint censize;
 956     ZFILE zfd = zip->zfd;
 957     char *cen;
 958     if (bufsize > zip->len - cenpos)
 959         bufsize = (jint)(zip->len - cenpos);
 960     if ((cen = malloc(bufsize)) == NULL)       goto Catch;
 961     if (readFullyAt(zfd, cen, bufsize, cenpos) == -1)     goto Catch;
 962     censize = CENSIZE(cen);
 963     if (censize <= bufsize) return cen;
 964     if ((cen = realloc(cen, censize)) == NULL)              goto Catch;
 965     if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch;
 966     return cen;
 967 
 968  Catch:
 969     free(cen);
 970     return NULL;
 971 }
 972 
 973 static char *
 974 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
 975 {
 976     cencache *cache = &zip->cencache;
 977     char *cen;
 978     if (cache->data != NULL
 979         && (cenpos >= cache->pos)
 980         && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
 981     {
 982         cen = cache->data + cenpos - cache->pos;
 983         if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
 984             /* A cache hit */
 985             return cen;
 986     }
 987 
 988     if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
 989         return NULL;
 990     free(cache->data);
 991     cache->data = cen;
 992     cache->pos  = cenpos;
 993     return cen;
 994 }
 995 
 996 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
 997 
 998 /*
 999  * Return a new initialized jzentry corresponding to a given hash cell.
1000  * In case of error, returns NULL.
1001  * We already sanity-checked all the CEN headers for ZIP format errors
1002  * in readCEN(), so we don't check them again here.
1003  * The ZIP lock should be held here.
1004  */
1005 static jzentry *
1006 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
1007 {
1008     jlong locoff;
1009     jint nlen, elen, clen;
1010     jzentry *ze;
1011     char *cen;
1012 
1013     if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
1014     ze->name    = NULL;
1015     ze->extra   = NULL;
1016     ze->comment = NULL;
1017 
1018 #ifdef USE_MMAP
1019     if (zip->usemmap) {
1020         cen = (char*) zip->maddr + zc->cenpos - zip->offset;
1021     } else
1022 #endif
1023     {
1024         if (accessHint == ACCESS_RANDOM)
1025             cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
1026         else
1027             cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
1028         if (cen == NULL) goto Catch;
1029     }
1030 
1031     nlen      = CENNAM(cen);
1032     elen      = CENEXT(cen);
1033     clen      = CENCOM(cen);
1034     ze->time  = CENTIM(cen);
1035     ze->size  = CENLEN(cen);
1036     ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
1037     ze->crc   = CENCRC(cen);
1038     locoff    = CENOFF(cen);
1039     ze->pos   = -(zip->locpos + locoff);
1040     ze->flag  = CENFLG(cen);
1041 
1042     if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
1043     memcpy(ze->name, cen + CENHDR, nlen);
1044     ze->name[nlen] = '\0';
1045     ze->nlen = nlen;
1046     if (elen > 0) {
1047         char *extra = cen + CENHDR + nlen;
1048 
1049         /* This entry has "extra" data */
1050         if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1051         ze->extra[0] = (unsigned char) elen;
1052         ze->extra[1] = (unsigned char) (elen >> 8);
1053         memcpy(ze->extra+2, extra, elen);
1054         if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1055             locoff == ZIP64_MAGICVAL) {
1056             jint off = 0;
1057             while ((off + 4) < elen) {    // spec: HeaderID+DataSize+Data
1058                 jint sz = SH(extra, off + 2);
1059                 if (SH(extra, off) == ZIP64_EXTID) {
1060                     off += 4;
1061                     if (ze->size == ZIP64_MAGICVAL) {
1062                         // if invalid zip64 extra fields, just skip
1063                         if (sz < 8 || (off + 8) > elen)
1064                             break;
1065                         ze->size = LL(extra, off);
1066                         sz -= 8;
1067                         off += 8;
1068                     }
1069                     if (ze->csize == ZIP64_MAGICVAL) {
1070                         if (sz < 8 || (off + 8) > elen)
1071                             break;
1072                         ze->csize = LL(extra, off);
1073                         sz -= 8;
1074                         off += 8;
1075                     }
1076                     if (locoff == ZIP64_MAGICVAL) {
1077                         if (sz < 8 || (off + 8) > elen)
1078                             break;
1079                         ze->pos = -(zip->locpos +  LL(extra, off));
1080                         sz -= 8;
1081                         off += 8;
1082                     }
1083                     break;
1084                 }
1085                 off += (sz + 4);
1086             }
1087         }
1088     }
1089 
1090     if (clen > 0) {
1091         /* This entry has a comment */
1092         if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1093         memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1094         ze->comment[clen] = '\0';
1095     }
1096     goto Finally;
1097 
1098  Catch:
1099     free(ze->name);
1100     free(ze->extra);
1101     free(ze->comment);
1102     free(ze);
1103     ze = NULL;
1104 
1105  Finally:
1106 #ifdef USE_MMAP
1107     if (!zip->usemmap)
1108 #endif
1109         if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1110     return ze;
1111 }
1112 
1113 /*
1114  * Free the given jzentry.
1115  * In fact we maintain a one-entry cache of the most recently used
1116  * jzentry for each zip.  This optimizes a common access pattern.
1117  */
1118 
1119 void
1120 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1121 {
1122     jzentry *last;
1123     ZIP_Lock(jz);
1124     last = jz->cache;
1125     jz->cache = ze;
1126     ZIP_Unlock(jz);
1127     if (last != NULL) {
1128         /* Free the previously cached jzentry */
1129         free(last->name);
1130         free(last->extra);
1131         free(last->comment);
1132         free(last);
1133     }
1134 }
1135 
1136 /*
1137  * Returns the zip entry corresponding to the specified name, or
1138  * NULL if not found.
1139  */
1140 jzentry *
1141 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1142 {
1143     if (ulen == 0) {
1144         return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE);
1145     }
1146     return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);
1147 }
1148 
1149 jboolean equals(char* name1, int len1, char* name2, int len2) {
1150     if (len1 != len2) {
1151         return JNI_FALSE;
1152     }
1153     while (len1-- > 0) {
1154         if (*name1++ != *name2++) {
1155             return JNI_FALSE;
1156         }
1157     }
1158     return JNI_TRUE;
1159 }
1160 
1161 /*
1162  * Returns the zip entry corresponding to the specified name, or
1163  * NULL if not found.
1164  * This method supports embedded null character in "name", use ulen
1165  * for the length of "name".
1166  */
1167 jzentry *
1168 ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)
1169 {
1170     unsigned int hsh = hashN(name, ulen);
1171     jint idx;
1172     jzentry *ze = 0;
1173 
1174     ZIP_Lock(zip);
1175     if (zip->total == 0) {
1176         goto Finally;
1177     }
1178 
1179     idx = zip->table[hsh % zip->tablelen];
1180 
1181     /*
1182      * This while loop is an optimization where a double lookup
1183      * for name and name+/ is being performed. The name char
1184      * array has enough room at the end to try again with a
1185      * slash appended if the first table lookup does not succeed.
1186      */
1187     while(1) {
1188 
1189         /* Check the cached entry first */
1190         ze = zip->cache;
1191         if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1192             /* Cache hit!  Remove and return the cached entry. */
1193             zip->cache = 0;
1194             ZIP_Unlock(zip);
1195             return ze;
1196         }
1197         ze = 0;
1198 
1199         /*
1200          * Search down the target hash chain for a cell whose
1201          * 32 bit hash matches the hashed name.
1202          */
1203         while (idx != ZIP_ENDCHAIN) {
1204             jzcell *zc = &zip->entries[idx];
1205 
1206             if (zc->hash == hsh) {
1207                 /*
1208                  * OK, we've found a ZIP entry whose 32 bit hashcode
1209                  * matches the name we're looking for.  Try to read
1210                  * its entry information from the CEN.  If the CEN
1211                  * name matches the name we're looking for, we're
1212                  * done.
1213                  * If the names don't match (which should be very rare)
1214                  * we keep searching.
1215                  */
1216                 ze = newEntry(zip, zc, ACCESS_RANDOM);
1217                 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1218                     break;
1219                 }
1220                 if (ze != 0) {
1221                     /* We need to release the lock across the free call */
1222                     ZIP_Unlock(zip);
1223                     ZIP_FreeEntry(zip, ze);
1224                     ZIP_Lock(zip);
1225                 }
1226                 ze = 0;
1227             }
1228             idx = zc->next;
1229         }
1230 
1231         /* Entry found, return it */
1232         if (ze != 0) {
1233             break;
1234         }
1235 
1236         /* If no need to try appending slash, we are done */
1237         if (!addSlash) {
1238             break;
1239         }
1240 
1241         /* Slash is already there? */
1242         if (ulen > 0 && name[ulen - 1] == '/') {
1243             break;
1244         }
1245 
1246         /* Add slash and try once more */
1247         name[ulen++] = '/';
1248         name[ulen] = '\0';
1249         hsh = hash_append(hsh, '/');
1250         idx = zip->table[hsh % zip->tablelen];
1251         addSlash = JNI_FALSE;
1252     }
1253 
1254 Finally:
1255     ZIP_Unlock(zip);
1256     return ze;
1257 }
1258 
1259 /*
1260  * Returns the n'th (starting at zero) zip file entry, or NULL if the
1261  * specified index was out of range.
1262  */
1263 JNIEXPORT jzentry *
1264 ZIP_GetNextEntry(jzfile *zip, jint n)
1265 {
1266     jzentry *result;
1267     if (n < 0 || n >= zip->total) {
1268         return 0;
1269     }
1270     ZIP_Lock(zip);
1271     result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1272     ZIP_Unlock(zip);
1273     return result;
1274 }
1275 
1276 /*
1277  * Locks the specified zip file for reading.
1278  */
1279 void
1280 ZIP_Lock(jzfile *zip)
1281 {
1282     MLOCK(zip->lock);
1283 }
1284 
1285 /*
1286  * Unlocks the specified zip file.
1287  */
1288 void
1289 ZIP_Unlock(jzfile *zip)
1290 {
1291     MUNLOCK(zip->lock);
1292 }
1293 
1294 /*
1295  * Returns the offset of the entry data within the zip file.
1296  * Returns -1 if an error occurred, in which case zip->msg will
1297  * contain the error text.
1298  */
1299 jlong
1300 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1301 {
1302     /* The Zip file spec explicitly allows the LOC extra data size to
1303      * be different from the CEN extra data size, although the JDK
1304      * never creates such zip files.  Since we cannot trust the CEN
1305      * extra data size, we need to read the LOC to determine the entry
1306      * data offset.  We do this lazily to avoid touching the virtual
1307      * memory page containing the LOC when initializing jzentry
1308      * objects.  (This speeds up javac by a factor of 10 when the JDK
1309      * is installed on a very slow filesystem.)
1310      */
1311     if (entry->pos <= 0) {
1312         unsigned char loc[LOCHDR];
1313         if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1314             zip->msg = "error reading zip file";
1315             return -1;
1316         }
1317         if (!LOCSIG_AT(loc)) {
1318             zip->msg = "invalid LOC header (bad signature)";
1319             return -1;
1320         }
1321         entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1322     }
1323     return entry->pos;
1324 }
1325 
1326 /*
1327  * Reads bytes from the specified zip entry. Assumes that the zip
1328  * file had been previously locked with ZIP_Lock(). Returns the
1329  * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1330  * then a zip error occurred and zip->msg contains the error text.
1331  *
1332  * The current implementation does not support reading an entry that
1333  * has the size bigger than 2**32 bytes in ONE invocation.
1334  */
1335 jint
1336 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1337 {
1338     jlong entry_size;
1339     jlong start;
1340 
1341     if (zip == 0) {
1342         return -1;
1343     }
1344 
1345     /* Clear previous zip error */
1346     zip->msg = NULL;
1347 
1348     if (entry == 0) {
1349         zip->msg = "ZIP_Read: jzentry is NULL";
1350         return -1;
1351     }
1352 
1353     entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1354 
1355     /* Check specified position */
1356     if (pos < 0 || pos > entry_size - 1) {
1357         zip->msg = "ZIP_Read: specified offset out of range";
1358         return -1;
1359     }
1360 
1361     /* Check specified length */
1362     if (len <= 0)
1363         return 0;
1364     if (len > entry_size - pos)
1365         len = (jint)(entry_size - pos);
1366 
1367     /* Get file offset to start reading data */
1368     start = ZIP_GetEntryDataOffset(zip, entry);
1369     if (start < 0)
1370         return -1;
1371     start += pos;
1372 
1373     if (start + len > zip->len) {
1374         zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1375         return -1;
1376     }
1377 
1378     if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1379         zip->msg = "ZIP_Read: error reading zip file";
1380         return -1;
1381     }
1382     return len;
1383 }
1384 
1385 
1386 /* The maximum size of a stack-allocated buffer.
1387  */
1388 #define BUF_SIZE 4096
1389 
1390 /*
1391  * This function is used by the runtime system to load compressed entries
1392  * from ZIP/JAR files specified in the class path. It is defined here
1393  * so that it can be dynamically loaded by the runtime if the zip library
1394  * is found.
1395  *
1396  * The current implementation does not support reading an entry that
1397  * has the size bigger than 2**32 bytes in ONE invocation.
1398  */
1399 jboolean
1400 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1401 {
1402     z_stream strm;
1403     char tmp[BUF_SIZE];
1404     jlong pos = 0;
1405     jlong count = entry->csize;
1406 
1407     *msg = 0; /* Reset error message */
1408 
1409     if (count == 0) {
1410         *msg = "inflateFully: entry not compressed";
1411         return JNI_FALSE;
1412     }
1413 
1414     memset(&strm, 0, sizeof(z_stream));
1415     if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1416         *msg = strm.msg;
1417         return JNI_FALSE;
1418     }
1419 
1420     strm.next_out = buf;
1421     strm.avail_out = (uInt)entry->size;
1422 
1423     while (count > 0) {
1424         jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1425         ZIP_Lock(zip);
1426         n = ZIP_Read(zip, entry, pos, tmp, n);
1427         ZIP_Unlock(zip);
1428         if (n <= 0) {
1429             if (n == 0) {
1430                 *msg = "inflateFully: Unexpected end of file";
1431             }
1432             inflateEnd(&strm);
1433             return JNI_FALSE;
1434         }
1435         pos += n;
1436         count -= n;
1437         strm.next_in = (Bytef *)tmp;
1438         strm.avail_in = n;
1439         do {
1440             switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1441             case Z_OK:
1442                 break;
1443             case Z_STREAM_END:
1444                 if (count != 0 || strm.total_out != (uInt)entry->size) {
1445                     *msg = "inflateFully: Unexpected end of stream";
1446                     inflateEnd(&strm);
1447                     return JNI_FALSE;
1448                 }
1449                 break;
1450             default:
1451                 break;
1452             }
1453         } while (strm.avail_in > 0);
1454     }
1455 
1456     inflateEnd(&strm);
1457     return JNI_TRUE;
1458 }
1459 
1460 /*
1461  * The current implementation does not support reading an entry that
1462  * has the size bigger than 2**32 bytes in ONE invocation.
1463  */
1464 JNIEXPORT jzentry *
1465 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1466 {
1467     jzentry *entry = ZIP_GetEntry(zip, name, 0);
1468     if (entry) {
1469         *sizeP = (jint)entry->size;
1470         *nameLenP = (jint)strlen(entry->name);
1471     }
1472     return entry;
1473 }
1474 
1475 /*
1476  * Reads a zip file entry into the specified byte array
1477  * When the method completes, it releases the jzentry.
1478  * Note: this is called from the separately delivered VM (hotspot/classic)
1479  * so we have to be careful to maintain the expected behaviour.
1480  */
1481 JNIEXPORT jboolean
1482 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1483 {
1484     char *msg;
1485     char tmpbuf[1024];
1486 
1487     if (entry == 0) {
1488         jio_fprintf(stderr, "jzentry was invalid");
1489         return JNI_FALSE;
1490     }
1491 
1492     strcpy(entryname, entry->name);
1493     if (entry->csize == 0) {
1494         /* Entry is stored */
1495         jlong pos = 0;
1496         jlong size = entry->size;
1497         while (pos < size) {
1498             jint n;
1499             jlong limit = ((((jlong) 1) << 31) - 1);
1500             jint count = (size - pos < limit) ?
1501                 /* These casts suppress a VC++ Internal Compiler Error */
1502                 (jint) (size - pos) :
1503                 (jint) limit;
1504             ZIP_Lock(zip);
1505             n = ZIP_Read(zip, entry, pos, buf, count);
1506             msg = zip->msg;
1507             ZIP_Unlock(zip);
1508             if (n == -1) {
1509                 if (msg == NULL) {
1510                     getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1511                     msg = tmpbuf;
1512                 }
1513                 jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1514                 return JNI_FALSE;
1515             }
1516             buf += n;
1517             pos += n;
1518         }
1519     } else {
1520         /* Entry is compressed */
1521         int ok = InflateFully(zip, entry, buf, &msg);
1522         if (!ok) {
1523             if ((msg == NULL) || (*msg == 0)) {
1524                 msg = zip->msg;
1525             }
1526             if (msg == NULL) {
1527                 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1528                 msg = tmpbuf;
1529             }
1530             jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1531             return JNI_FALSE;
1532         }
1533     }
1534 
1535     ZIP_FreeEntry(zip, entry);
1536 
1537     return JNI_TRUE;
1538 }
1539 
1540 JNIEXPORT jboolean
1541 ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg)
1542 {
1543     z_stream strm;
1544     memset(&strm, 0, sizeof(z_stream));
1545 
1546     *pmsg = NULL; /* Reset error message */
1547 
1548     if (inflateInit2(&strm, MAX_WBITS) != Z_OK) {
1549         *pmsg = strm.msg;
1550         return JNI_FALSE;
1551     }
1552 
1553     strm.next_out = (Bytef *) outBuf;
1554     strm.avail_out = (uInt)outLen;
1555     strm.next_in = (Bytef *) inBuf;
1556     strm.avail_in = (uInt)inLen;
1557 
1558     do {
1559         switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1560             case Z_OK:
1561                 break;
1562             case Z_STREAM_END:
1563                 if (strm.total_out != (uInt)outLen) {
1564                     *pmsg = "INFLATER_inflateFully: Unexpected end of stream";
1565                     inflateEnd(&strm);
1566                     return JNI_FALSE;
1567                 }
1568                 break;
1569             case Z_DATA_ERROR:
1570                 *pmsg = "INFLATER_inflateFully: Compressed data corrupted";
1571                 inflateEnd(&strm);
1572                 return JNI_FALSE;
1573             case Z_MEM_ERROR:
1574                 *pmsg = "INFLATER_inflateFully: out of memory";
1575                 inflateEnd(&strm);
1576                 return JNI_FALSE;
1577             default:
1578                 *pmsg = "INFLATER_inflateFully: internal error";
1579                 inflateEnd(&strm);
1580                 return JNI_FALSE;
1581         }
1582     } while (strm.avail_in > 0);
1583 
1584     inflateEnd(&strm);
1585     return JNI_TRUE;
1586 }
1587 
1588 static voidpf tracking_zlib_alloc(voidpf opaque, uInt items, uInt size) {
1589   size_t* needed = (size_t*) opaque;
1590   *needed += (size_t) items * (size_t) size;
1591   return (voidpf) calloc((size_t) items, (size_t) size);
1592 }
1593 
1594 static void tracking_zlib_free(voidpf opaque, voidpf address) {
1595   free((void*) address);
1596 }
1597 
1598 static voidpf zlib_block_alloc(voidpf opaque, uInt items, uInt size) {
1599   char** range = (char**) opaque;
1600   voidpf result = NULL;
1601   size_t needed = (size_t) items * (size_t) size;
1602 
1603   if (range[1] - range[0] >= (ptrdiff_t) needed) {
1604     result = (voidpf) range[0];
1605     range[0] += needed;
1606   }
1607 
1608   return result;
1609 }
1610 
1611 static void zlib_block_free(voidpf opaque, voidpf address) {
1612   /* Nothing to do. */
1613 }
1614 
1615 static char const* deflateInit2Wrapper(z_stream* strm, int level) {
1616   int err = deflateInit2(strm, level >= 0 && level <= 9 ? level : Z_DEFAULT_COMPRESSION,
1617                          Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
1618   if (err == Z_MEM_ERROR) {
1619     return "Out of memory in deflateInit2";
1620   }
1621 
1622   if (err != Z_OK) {
1623     return "Internal error in deflateInit2";
1624   }
1625 
1626   return NULL;
1627 }
1628 
1629 JNIEXPORT char const*
1630 ZIP_GZip_InitParams(size_t inLen, size_t* outLen, size_t* tmpLen, int level) {
1631   z_stream strm;
1632   *tmpLen = 0;
1633   char const* errorMsg;
1634 
1635   memset(&strm, 0, sizeof(z_stream));
1636   strm.zalloc = tracking_zlib_alloc;
1637   strm.zfree = tracking_zlib_free;
1638   strm.opaque = (voidpf) tmpLen;
1639 
1640   errorMsg = deflateInit2Wrapper(&strm, level);
1641 
1642   if (errorMsg == NULL) {
1643     *outLen = (size_t) deflateBound(&strm, (uLong) inLen);
1644     deflateEnd(&strm);
1645   }
1646 
1647   return errorMsg;
1648 }
1649 
1650 JNIEXPORT size_t
1651 ZIP_GZip_Fully(char* inBuf, size_t inLen, char* outBuf, size_t outLen, char* tmp, size_t tmpLen,
1652                int level, char* comment, char const** pmsg) {
1653   z_stream strm;
1654   gz_header hdr;
1655   int err;
1656   char* block[] = {tmp, tmpLen + tmp};
1657   size_t result = 0;
1658 
1659   memset(&strm, 0, sizeof(z_stream));
1660   strm.zalloc = zlib_block_alloc;
1661   strm.zfree = zlib_block_free;
1662   strm.opaque = (voidpf) block;
1663 
1664   *pmsg = deflateInit2Wrapper(&strm, level);
1665 
1666   if (*pmsg == NULL) {
1667     strm.next_out = (Bytef *) outBuf;
1668     strm.avail_out = (uInt) outLen;
1669     strm.next_in = (Bytef *) inBuf;
1670     strm.avail_in = (uInt) inLen;
1671 
1672     if (comment != NULL) {
1673       memset(&hdr, 0, sizeof(hdr));
1674       hdr.comment = (Bytef*) comment;
1675       deflateSetHeader(&strm, &hdr);
1676     }
1677 
1678     err = deflate(&strm, Z_FINISH);
1679 
1680     if (err == Z_OK || err == Z_BUF_ERROR) {
1681       *pmsg = "Buffer too small";
1682     } else if (err != Z_STREAM_END) {
1683       *pmsg = "Intern deflate error";
1684     } else {
1685       result = (size_t) strm.total_out;
1686     }
1687 
1688     deflateEnd(&strm);
1689   }
1690 
1691   return result;
1692 }