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