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