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