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