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