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