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