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