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