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