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