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