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