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