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