• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     // BEGIN Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
779     /*
780     if (pmsg != 0) {
781         *pmsg = NULL;
782     }
783 
784     zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
785 
786     if (zip == NULL && *pmsg == NULL) {
787         ZFILE zfd = ZFILE_Open(name, mode);
788         zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
789     }
790     */
791     /*
792      * We want to know if ZIP_Get_From_Cache fails, which isn't possible to
793      * distinguish without passing a non-null message value. Hence, if the user
794      * didn't supply a `pmsg`, we make and manage our own.
795      */
796     char *localPmsg = NULL;
797     zip = ZIP_Get_From_Cache(name, &localPmsg, lastModified);
798 
799     if (zip == NULL && localPmsg == NULL) {
800         ZFILE zfd = ZFILE_Open(name, mode);
801         zip = ZIP_Put_In_Cache(name, zfd, &localPmsg, lastModified);
802     }
803 
804     if (pmsg == NULL) {
805       free(localPmsg);
806     } else {
807       *pmsg = localPmsg;
808     }
809     // END Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
810     return zip;
811 }
812 
813 /*
814  * Returns the jzfile corresponding to the given file name from the cache of
815  * zip files, or NULL if the file is not in the cache.  If the name is longer
816  * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
817  * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller
818  * is responsible to free the error message.
819  */
820 jzfile *
ZIP_Get_From_Cache(const char * name,char ** pmsg,jlong lastModified)821 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
822 {
823     char buf[PATH_MAX];
824     jzfile *zip;
825 
826     if (InitializeZip()) {
827         return NULL;
828     }
829 
830     /* Clear zip error message */
831     if (pmsg != 0) {
832         *pmsg = NULL;
833     }
834 
835     if (strlen(name) >= PATH_MAX) {
836         if (pmsg) {
837             *pmsg = strdup("zip file name too long");
838         }
839         return NULL;
840     }
841     strcpy(buf, name);
842     JVM_NativePath(buf);
843     name = buf;
844 
845     MLOCK(zfiles_lock);
846     for (zip = zfiles; zip != NULL; zip = zip->next) {
847         if (strcmp(name, zip->name) == 0
848             && (zip->lastModified == lastModified || zip->lastModified == 0)
849             && zip->refs < MAXREFS) {
850             zip->refs++;
851             break;
852         }
853     }
854     MUNLOCK(zfiles_lock);
855     return zip;
856 }
857 
858 /*
859  * Reads data from the given file descriptor to create a jzfile, puts the
860  * jzfile in a cache, and returns that jzfile.  Returns NULL in case of error.
861  * If a zip error occurs, then *pmsg will be set to the error message text if
862  * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to
863  * free the error message.
864  */
865 
866 jzfile *
ZIP_Put_In_Cache(const char * name,ZFILE zfd,char ** pmsg,jlong lastModified)867 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
868 {
869     return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
870 }
871 
872 jzfile *
ZIP_Put_In_Cache0(const char * name,ZFILE zfd,char ** pmsg,jlong lastModified,jboolean usemmap)873 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
874                  jboolean usemmap)
875 {
876     char errbuf[256];
877     jlong len;
878     jzfile *zip;
879 
880     if ((zip = allocZip(name)) == NULL) {
881         return NULL;
882     }
883 
884 #ifdef USE_MMAP
885     zip->usemmap = usemmap;
886 #endif
887     zip->refs = 1;
888     zip->lastModified = lastModified;
889 
890     if (zfd == -1) {
891         if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
892             *pmsg = strdup(errbuf);
893         freeZip(zip);
894         return NULL;
895     }
896 
897     // Trivially, reuse errbuf.
898     if (readFullyAt(zfd, errbuf, 4, 0 /* offset */) != -1) {  // errors will be handled later
899         if (GETSIG(errbuf) == LOCSIG)
900             zip->locsig = JNI_TRUE;
901         else
902             zip->locsig = JNI_FALSE;
903     }
904 
905     // This lseek is safe because it happens during construction of the ZipFile
906     // object. We must take care not to perform any operations that change the
907     // offset after (see b/30407219).
908     len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
909     if (len <= 0) {
910         if (len == 0) { /* zip file is empty */
911             if (pmsg) {
912                 *pmsg = strdup("zip file is empty");
913             }
914         } else { /* error */
915             if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
916                 *pmsg = strdup(errbuf);
917         }
918         ZFILE_Close(zfd);
919         freeZip(zip);
920         return NULL;
921     }
922 
923     zip->zfd = zfd;
924     if (readCEN(zip, -1) < 0) {
925         /* An error occurred while trying to read the zip file */
926         if (pmsg != 0) {
927             /* Set the zip error message */
928             if (zip->msg != NULL)
929                 *pmsg = strdup(zip->msg);
930         }
931         freeZip(zip);
932         return NULL;
933     }
934     MLOCK(zfiles_lock);
935     zip->next = zfiles;
936     zfiles = zip;
937     MUNLOCK(zfiles_lock);
938 
939     return zip;
940 }
941 
942 /*
943  * Opens a zip file for reading. Returns the jzfile object or NULL
944  * if an error occurred. If a zip error occurred then *msg will be
945  * set to the error message text if msg != 0. Otherwise, *msg will be
946  * set to NULL. Caller doesn't need to free the error message.
947  */
948 jzfile * JNICALL
ZIP_Open(const char * name,char ** pmsg)949 ZIP_Open(const char *name, char **pmsg)
950 {
951     jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);
952     if (file == NULL && pmsg != NULL && *pmsg != NULL) {
953         free(*pmsg);
954         *pmsg = "Zip file open error";
955     }
956     return file;
957 }
958 
959 /*
960  * Closes the specified zip file object.
961  */
962 void JNICALL
ZIP_Close(jzfile * zip)963 ZIP_Close(jzfile *zip)
964 {
965     MLOCK(zfiles_lock);
966     if (--zip->refs > 0) {
967         /* Still more references so just return */
968         MUNLOCK(zfiles_lock);
969         return;
970     }
971     /* No other references so close the file and remove from list */
972     if (zfiles == zip) {
973         zfiles = zfiles->next;
974     } else {
975         jzfile *zp;
976         for (zp = zfiles; zp->next != 0; zp = zp->next) {
977             if (zp->next == zip) {
978                 zp->next = zip->next;
979                 break;
980             }
981         }
982     }
983     MUNLOCK(zfiles_lock);
984     freeZip(zip);
985     return;
986 }
987 
988 /* Empirically, most CEN headers are smaller than this. */
989 #define AMPLE_CEN_HEADER_SIZE 160
990 
991 /* A good buffer size when we want to read CEN headers sequentially. */
992 #define CENCACHE_PAGESIZE 8192
993 
994 static char *
readCENHeader(jzfile * zip,jlong cenpos,jint bufsize)995 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
996 {
997     jint censize;
998     ZFILE zfd = zip->zfd;
999     char *cen;
1000     if (bufsize > zip->len - cenpos)
1001         bufsize = (jint)(zip->len - cenpos);
1002     if ((cen = malloc(bufsize)) == NULL)       goto Catch;
1003     if (readFullyAt(zfd, cen, bufsize, cenpos) == -1)     goto Catch;
1004     censize = CENSIZE(cen);
1005     if (censize <= bufsize) return cen;
1006     if ((cen = realloc(cen, censize)) == NULL)              goto Catch;
1007     if (readFullyAt(zfd, cen+bufsize, censize-bufsize, cenpos + bufsize) == -1) goto Catch;
1008     return cen;
1009 
1010  Catch:
1011     free(cen);
1012     return NULL;
1013 }
1014 
1015 static char *
sequentialAccessReadCENHeader(jzfile * zip,jlong cenpos)1016 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
1017 {
1018     cencache *cache = &zip->cencache;
1019     char *cen;
1020     if (cache->data != NULL
1021         && (cenpos >= cache->pos)
1022         && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
1023     {
1024         cen = cache->data + cenpos - cache->pos;
1025         if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
1026             /* A cache hit */
1027             return cen;
1028     }
1029 
1030     if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
1031         return NULL;
1032     free(cache->data);
1033     cache->data = cen;
1034     cache->pos  = cenpos;
1035     return cen;
1036 }
1037 
1038 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
1039 
1040 /*
1041  * Return a new initialized jzentry corresponding to a given hash cell.
1042  * In case of error, returns NULL.
1043  * We already sanity-checked all the CEN headers for ZIP format errors
1044  * in readCEN(), so we don't check them again here.
1045  * The ZIP lock should be held here.
1046  */
1047 static jzentry *
newEntry(jzfile * zip,jzcell * zc,AccessHint accessHint)1048 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
1049 {
1050     jlong locoff;
1051     jint nlen, elen, clen;
1052     jzentry *ze;
1053     char *cen;
1054 
1055     if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
1056     ze->name    = NULL;
1057     ze->extra   = NULL;
1058     ze->comment = NULL;
1059 
1060 #ifdef USE_MMAP
1061     if (zip->usemmap) {
1062         cen = (char*) zip->maddr + zc->cenpos - zip->offset;
1063     } else
1064 #endif
1065     {
1066         if (accessHint == ACCESS_RANDOM)
1067             cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
1068         else
1069             cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
1070         if (cen == NULL) goto Catch;
1071     }
1072 
1073     nlen      = CENNAM(cen);
1074     elen      = CENEXT(cen);
1075     clen      = CENCOM(cen);
1076     ze->time  = CENTIM(cen);
1077     ze->size  = CENLEN(cen);
1078     ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
1079     ze->crc   = CENCRC(cen);
1080     locoff    = CENOFF(cen);
1081     ze->pos   = -(zip->locpos + locoff);
1082     ze->flag  = CENFLG(cen);
1083 
1084     if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
1085     memcpy(ze->name, cen + CENHDR, nlen);
1086     ze->name[nlen] = '\0';
1087     ze->nlen = nlen;
1088     if (elen > 0) {
1089         char *extra = cen + CENHDR + nlen;
1090 
1091         /* This entry has "extra" data */
1092         if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1093         ze->extra[0] = (unsigned char) elen;
1094         ze->extra[1] = (unsigned char) (elen >> 8);
1095         memcpy(ze->extra+2, extra, elen);
1096         if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1097             locoff == ZIP64_MAGICVAL) {
1098             jint off = 0;
1099             while ((off + 4) < elen) {    // spec: HeaderID+DataSize+Data
1100                 jint sz = SH(extra, off + 2);
1101                 if (SH(extra, off) == ZIP64_EXTID) {
1102                     off += 4;
1103                     if (ze->size == ZIP64_MAGICVAL) {
1104                         // if invalid zip64 extra fields, just skip
1105                         if (sz < 8 || (off + 8) > elen)
1106                             break;
1107                         ze->size = LL(extra, off);
1108                         sz -= 8;
1109                         off += 8;
1110                     }
1111                     if (ze->csize == ZIP64_MAGICVAL) {
1112                         if (sz < 8 || (off + 8) > elen)
1113                             break;
1114                         ze->csize = LL(extra, off);
1115                         sz -= 8;
1116                         off += 8;
1117                     }
1118                     if (locoff == ZIP64_MAGICVAL) {
1119                         if (sz < 8 || (off + 8) > elen)
1120                             break;
1121                         ze->pos = -(zip->locpos +  LL(extra, off));
1122                         sz -= 8;
1123                         off += 8;
1124                     }
1125                     break;
1126                 }
1127                 off += (sz + 4);
1128             }
1129         }
1130     }
1131 
1132     if (clen > 0) {
1133         /* This entry has a comment */
1134         if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1135         memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1136         ze->comment[clen] = '\0';
1137     }
1138     goto Finally;
1139 
1140  Catch:
1141     free(ze->name);
1142     free(ze->extra);
1143     free(ze->comment);
1144     free(ze);
1145     ze = NULL;
1146 
1147  Finally:
1148 #ifdef USE_MMAP
1149     if (!zip->usemmap)
1150 #endif
1151         if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1152     return ze;
1153 }
1154 
1155 /*
1156  * Free the given jzentry.
1157  * In fact we maintain a one-entry cache of the most recently used
1158  * jzentry for each zip.  This optimizes a common access pattern.
1159  */
1160 
1161 void
ZIP_FreeEntry(jzfile * jz,jzentry * ze)1162 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1163 {
1164     jzentry *last;
1165     ZIP_Lock(jz);
1166     last = jz->cache;
1167     jz->cache = ze;
1168     ZIP_Unlock(jz);
1169     if (last != NULL) {
1170         /* Free the previously cached jzentry */
1171         free(last->name);
1172         if (last->extra)   free(last->extra);
1173         if (last->comment) free(last->comment);
1174         free(last);
1175     }
1176 }
1177 
1178 /*
1179  * Returns the zip entry corresponding to the specified name, or
1180  * NULL if not found.
1181  */
1182 jzentry *
ZIP_GetEntry(jzfile * zip,char * name,jint ulen)1183 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1184 {
1185     if (ulen == 0) {
1186         return ZIP_GetEntry2(zip, name, strlen(name), JNI_FALSE);
1187     }
1188     return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);
1189 }
1190 
equals(char * name1,int len1,char * name2,int len2)1191 jboolean equals(char* name1, int len1, char* name2, int len2) {
1192     if (len1 != len2) {
1193         return JNI_FALSE;
1194     }
1195     while (len1-- > 0) {
1196         if (*name1++ != *name2++) {
1197             return JNI_FALSE;
1198         }
1199     }
1200     return JNI_TRUE;
1201 }
1202 
1203 /*
1204  * Returns the zip entry corresponding to the specified name, or
1205  * NULL if not found.
1206  * This method supports embedded null character in "name", use ulen
1207  * for the length of "name".
1208  */
1209 jzentry *
ZIP_GetEntry2(jzfile * zip,char * name,jint ulen,jboolean addSlash)1210 ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)
1211 {
1212     unsigned int hsh = hashN(name, ulen);
1213     jint idx;
1214     jzentry *ze = 0;
1215 
1216     ZIP_Lock(zip);
1217     if (zip->total == 0) {
1218         goto Finally;
1219     }
1220 
1221     idx = zip->table[hsh % zip->tablelen];
1222 
1223     /*
1224      * This while loop is an optimization where a double lookup
1225      * for name and name+/ is being performed. The name char
1226      * array has enough room at the end to try again with a
1227      * slash appended if the first table lookup does not succeed.
1228      */
1229     while(1) {
1230 
1231         /* Check the cached entry first */
1232         ze = zip->cache;
1233         if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1234             /* Cache hit!  Remove and return the cached entry. */
1235             zip->cache = 0;
1236             ZIP_Unlock(zip);
1237             return ze;
1238         }
1239         ze = 0;
1240 
1241         /*
1242          * Search down the target hash chain for a cell whose
1243          * 32 bit hash matches the hashed name.
1244          */
1245         while (idx != ZIP_ENDCHAIN) {
1246             jzcell *zc = &zip->entries[idx];
1247 
1248             if (zc->hash == hsh) {
1249                 /*
1250                  * OK, we've found a ZIP entry whose 32 bit hashcode
1251                  * matches the name we're looking for.  Try to read
1252                  * its entry information from the CEN.  If the CEN
1253                  * name matches the name we're looking for, we're
1254                  * done.
1255                  * If the names don't match (which should be very rare)
1256                  * we keep searching.
1257                  */
1258                 ze = newEntry(zip, zc, ACCESS_RANDOM);
1259                 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1260                     break;
1261                 }
1262                 if (ze != 0) {
1263                     /* We need to release the lock across the free call */
1264                     ZIP_Unlock(zip);
1265                     ZIP_FreeEntry(zip, ze);
1266                     ZIP_Lock(zip);
1267                 }
1268                 ze = 0;
1269             }
1270             idx = zc->next;
1271         }
1272 
1273         /* Entry found, return it */
1274         if (ze != 0) {
1275             break;
1276         }
1277 
1278         /* If no need to try appending slash, we are done */
1279         if (!addSlash) {
1280             break;
1281         }
1282 
1283         /* Slash is already there? */
1284         if (name[ulen-1] == '/') {
1285             break;
1286         }
1287 
1288         /* Add slash and try once more */
1289         name[ulen++] = '/';
1290         name[ulen] = '\0';
1291         hsh = hash_append(hsh, '/');
1292         idx = zip->table[hsh % zip->tablelen];
1293         addSlash = JNI_FALSE;
1294     }
1295 
1296 Finally:
1297     ZIP_Unlock(zip);
1298     return ze;
1299 }
1300 
1301 /*
1302  * Returns the n'th (starting at zero) zip file entry, or NULL if the
1303  * specified index was out of range.
1304  */
1305 jzentry * JNICALL
ZIP_GetNextEntry(jzfile * zip,jint n)1306 ZIP_GetNextEntry(jzfile *zip, jint n)
1307 {
1308     jzentry *result;
1309     if (n < 0 || n >= zip->total) {
1310         return 0;
1311     }
1312     ZIP_Lock(zip);
1313     result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1314     ZIP_Unlock(zip);
1315     return result;
1316 }
1317 
1318 /*
1319  * Locks the specified zip file for reading.
1320  */
1321 void
ZIP_Lock(jzfile * zip)1322 ZIP_Lock(jzfile *zip)
1323 {
1324     MLOCK(zip->lock);
1325 }
1326 
1327 /*
1328  * Unlocks the specified zip file.
1329  */
1330 void
ZIP_Unlock(jzfile * zip)1331 ZIP_Unlock(jzfile *zip)
1332 {
1333     MUNLOCK(zip->lock);
1334 }
1335 
1336 /*
1337  * Returns the offset of the entry data within the zip file.
1338  * Returns -1 if an error occurred, in which case zip->msg will
1339  * contain the error text.
1340  */
1341 jlong
ZIP_GetEntryDataOffset(jzfile * zip,jzentry * entry)1342 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1343 {
1344     /* The Zip file spec explicitly allows the LOC extra data size to
1345      * be different from the CEN extra data size, although the JDK
1346      * never creates such zip files.  Since we cannot trust the CEN
1347      * extra data size, we need to read the LOC to determine the entry
1348      * data offset.  We do this lazily to avoid touching the virtual
1349      * memory page containing the LOC when initializing jzentry
1350      * objects.  (This speeds up javac by a factor of 10 when the JDK
1351      * is installed on a very slow filesystem.)
1352      */
1353     if (entry->pos <= 0) {
1354         unsigned char loc[LOCHDR];
1355         if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1356             zip->msg = "error reading zip file";
1357             return -1;
1358         }
1359         if (GETSIG(loc) != LOCSIG) {
1360             zip->msg = "invalid LOC header (bad signature)";
1361             return -1;
1362         }
1363         entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1364     }
1365     return entry->pos;
1366 }
1367 
1368 /*
1369  * Reads bytes from the specified zip entry. Assumes that the zip
1370  * file had been previously locked with ZIP_Lock(). Returns the
1371  * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1372  * then a zip error occurred and zip->msg contains the error text.
1373  *
1374  * The current implementation does not support reading an entry that
1375  * has the size bigger than 2**32 bytes in ONE invocation.
1376  */
1377 jint
ZIP_Read(jzfile * zip,jzentry * entry,jlong pos,void * buf,jint len)1378 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1379 {
1380     jlong entry_size;
1381     jlong start;
1382 
1383     if (zip == 0) {
1384         return -1;
1385     }
1386 
1387     /* Clear previous zip error */
1388     zip->msg = NULL;
1389 
1390     if (entry == 0) {
1391         zip->msg = "ZIP_Read: jzentry is NULL";
1392         return -1;
1393     }
1394 
1395     entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1396 
1397     /* Check specified position */
1398     if (pos < 0 || pos > entry_size - 1) {
1399         zip->msg = "ZIP_Read: specified offset out of range";
1400         return -1;
1401     }
1402 
1403     /* Check specified length */
1404     if (len <= 0)
1405         return 0;
1406     if (len > entry_size - pos)
1407         len = (jint)(entry_size - pos);
1408 
1409     /* Get file offset to start reading data */
1410     start = ZIP_GetEntryDataOffset(zip, entry);
1411     if (start < 0)
1412         return -1;
1413     start += pos;
1414 
1415     if (start + len > zip->len) {
1416         zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1417         return -1;
1418     }
1419 
1420     if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1421         zip->msg = "ZIP_Read: error reading zip file";
1422         return -1;
1423     }
1424     return len;
1425 }
1426 
1427 
1428 /* The maximum size of a stack-allocated buffer.
1429  */
1430 #define BUF_SIZE 4096
1431 
1432 /*
1433  * This function is used by the runtime system to load compressed entries
1434  * from ZIP/JAR files specified in the class path. It is defined here
1435  * so that it can be dynamically loaded by the runtime if the zip library
1436  * is found.
1437  *
1438  * The current implementation does not support reading an entry that
1439  * has the size bigger than 2**32 bytes in ONE invocation.
1440  */
1441 jboolean
InflateFully(jzfile * zip,jzentry * entry,void * buf,char ** msg)1442 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1443 {
1444     z_stream strm;
1445     char tmp[BUF_SIZE];
1446     jlong pos = 0;
1447     jlong count = entry->csize;
1448 
1449     *msg = 0; /* Reset error message */
1450 
1451     if (count == 0) {
1452         *msg = "inflateFully: entry not compressed";
1453         return JNI_FALSE;
1454     }
1455 
1456     memset(&strm, 0, sizeof(z_stream));
1457     if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1458         *msg = strm.msg;
1459         return JNI_FALSE;
1460     }
1461 
1462     strm.next_out = buf;
1463     strm.avail_out = (uInt)entry->size;
1464 
1465     while (count > 0) {
1466         jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1467         ZIP_Lock(zip);
1468         n = ZIP_Read(zip, entry, pos, tmp, n);
1469         ZIP_Unlock(zip);
1470         if (n <= 0) {
1471             if (n == 0) {
1472                 *msg = "inflateFully: Unexpected end of file";
1473             }
1474             inflateEnd(&strm);
1475             return JNI_FALSE;
1476         }
1477         pos += n;
1478         count -= n;
1479         strm.next_in = (Bytef *)tmp;
1480         strm.avail_in = n;
1481         do {
1482             switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1483             case Z_OK:
1484                 break;
1485             case Z_STREAM_END:
1486                 if (count != 0 || entry->size < 0 || strm.total_out != (uint64_t)entry->size) {
1487                     *msg = "inflateFully: Unexpected end of stream";
1488                     inflateEnd(&strm);
1489                     return JNI_FALSE;
1490                 }
1491                 break;
1492             default:
1493                 break;
1494             }
1495         } while (strm.avail_in > 0);
1496     }
1497     inflateEnd(&strm);
1498     return JNI_TRUE;
1499 }
1500 
1501 /*
1502  * The current implementation does not support reading an entry that
1503  * has the size bigger than 2**32 bytes in ONE invocation.
1504  */
1505 jzentry * JNICALL
ZIP_FindEntry(jzfile * zip,char * name,jint * sizeP,jint * nameLenP)1506 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1507 {
1508     jzentry *entry = ZIP_GetEntry(zip, name, 0);
1509     if (entry) {
1510         *sizeP = (jint)entry->size;
1511         *nameLenP = strlen(entry->name);
1512     }
1513     return entry;
1514 }
1515 
1516 /*
1517  * Reads a zip file entry into the specified byte array
1518  * When the method completes, it releases the jzentry.
1519  * Note: this is called from the separately delivered VM (hotspot/classic)
1520  * so we have to be careful to maintain the expected behaviour.
1521  */
1522 jboolean JNICALL
ZIP_ReadEntry(jzfile * zip,jzentry * entry,unsigned char * buf,char * entryname)1523 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1524 {
1525     char *msg;
1526     char tmpbuf[1024];
1527 
1528     if (entry == 0) {
1529         jio_fprintf(stderr, "jzentry was invalid");
1530         return JNI_FALSE;
1531     }
1532 
1533     strcpy(entryname, entry->name);
1534     if (entry->csize == 0) {
1535         /* Entry is stored */
1536         jlong pos = 0;
1537         jlong size = entry->size;
1538         while (pos < size) {
1539             jint n;
1540             jlong limit = ((((jlong) 1) << 31) - 1);
1541             jint count = (size - pos < limit) ?
1542                 /* These casts suppress a VC++ Internal Compiler Error */
1543                 (jint) (size - pos) :
1544                 (jint) limit;
1545             ZIP_Lock(zip);
1546             n = ZIP_Read(zip, entry, pos, buf, count);
1547             msg = zip->msg;
1548             ZIP_Unlock(zip);
1549             if (n == -1) {
1550                 if (msg == 0) {
1551                     getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1552                     msg = tmpbuf;
1553                 }
1554                 jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1555                 return JNI_FALSE;
1556             }
1557             buf += n;
1558             pos += n;
1559         }
1560     } else {
1561         /* Entry is compressed */
1562         int ok = InflateFully(zip, entry, buf, &msg);
1563         if (!ok) {
1564             if ((msg == NULL) || (*msg == 0)) {
1565                 msg = zip->msg;
1566             }
1567             if (msg == 0) {
1568                 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1569                 msg = tmpbuf;
1570             }
1571             jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1572             return JNI_FALSE;
1573         }
1574     }
1575 
1576     ZIP_FreeEntry(zip, entry);
1577 
1578     return JNI_TRUE;
1579 }
1580