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