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