1 /*
2 * Copyright (c) 1995, 2010, 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 #include "cutils/log.h"
51
52 #ifdef _ALLBSD_SOURCE
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 pread(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 const jlong minPos = minHDR - (sizeof(buf)-ENDHDR);
304 jint clen;
305
306 for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) {
307
308 int i;
309 jlong off = 0;
310 if (pos < 0) {
311 /* Pretend there are some NUL bytes before start of file */
312 off = -pos;
313 memset(buf, '\0', (size_t)off);
314 }
315
316 if (readFullyAt(zfd, buf + off, sizeof(buf) - off,
317 pos + off) == -1) {
318 return -1; /* System error */
319 }
320
321 /* Now scan the block backwards for END header signature */
322 for (i = sizeof(buf) - ENDHDR; i >= 0; i--) {
323 if (buf[i+0] == 'P' &&
324 buf[i+1] == 'K' &&
325 buf[i+2] == '\005' &&
326 buf[i+3] == '\006' &&
327 ((pos + i + ENDHDR + ENDCOM(buf + i) == len)
328 || verifyEND(zip, pos + i, buf + i))) {
329 /* Found END header */
330 memcpy(endbuf, buf + i, ENDHDR);
331
332 clen = ENDCOM(endbuf);
333 if (clen != 0) {
334 zip->comment = malloc(clen + 1);
335 if (zip->comment == NULL) {
336 return -1;
337 }
338 if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR)
339 == -1) {
340 free(zip->comment);
341 zip->comment = NULL;
342 return -1;
343 }
344 zip->comment[clen] = '\0';
345 zip->clen = clen;
346 }
347 return pos + i;
348 }
349 }
350 }
351
352 return -1; /* END header not found */
353 }
354
355 /*
356 * Searches for the ZIP64 end of central directory (END) header. The
357 * contents of the ZIP64 END header will be read and placed in end64buf.
358 * Returns the file position of the ZIP64 END header, otherwise returns
359 * -1 if the END header was not found or an error occurred.
360 *
361 * The ZIP format specifies the "position" of each related record as
362 * ...
363 * [central directory]
364 * [zip64 end of central directory record]
365 * [zip64 end of central directory locator]
366 * [end of central directory record]
367 *
368 * The offset of zip64 end locator can be calculated from endpos as
369 * "endpos - ZIP64_LOCHDR".
370 * The "offset" of zip64 end record is stored in zip64 end locator.
371 */
372 static jlong
findEND64(jzfile * zip,void * end64buf,jlong endpos)373 findEND64(jzfile *zip, void *end64buf, jlong endpos)
374 {
375 char loc64[ZIP64_LOCHDR];
376 jlong end64pos;
377 if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {
378 return -1; // end64 locator not found
379 }
380 end64pos = ZIP64_LOCOFF(loc64);
381 if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) {
382 return -1; // end64 record not found
383 }
384 return end64pos;
385 }
386
387 /*
388 * Returns a hash code value for a C-style NUL-terminated string.
389 */
390 static unsigned int
hash(const char * s)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 occured. 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 if (entries == NULL || table == NULL) goto Catch;
667 for (j = 0; j < tablelen; j++)
668 table[j] = ZIP_ENDCHAIN;
669
670 /* Iterate through the entries in the central directory */
671 for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {
672 /* Following are unsigned 16-bit */
673 jint method, nlen;
674 unsigned int hsh;
675
676 if (i >= total) {
677 /* This will only happen if the zip file has an incorrect
678 * ENDTOT field, which usually means it contains more than
679 * 65535 entries. */
680 cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend));
681 goto Finally;
682 }
683
684 method = CENHOW(cp);
685 nlen = CENNAM(cp);
686
687 if (GETSIG(cp) != CENSIG) {
688 ZIP_FORMAT_ERROR("invalid CEN header (bad signature)");
689 }
690 if (CENFLG(cp) & 1) {
691 ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)");
692 }
693 if (method != STORED && method != DEFLATED) {
694 ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)");
695 }
696 if (cp + CENHDR + nlen > cenend) {
697 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
698 }
699
700 const char* entryName = (const char *)cp + CENHDR;
701 if (!isValidEntryName(entryName, nlen)) {
702 ZIP_FORMAT_ERROR("invalid CEN header (invalid entry name)");
703 }
704
705 /* if the entry is metadata add it to our metadata names */
706 if (isMetaName(entryName, nlen)) {
707 if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0) {
708 goto Catch;
709 }
710 }
711
712 /* Record the CEN offset and the name hash in our hash cell. */
713 entries[i].cenpos = cenpos + (cp - cenbuf);
714 entries[i].hash = hashN(entryName, nlen);
715 entries[i].next = ZIP_ENDCHAIN;
716
717 /* Add the entry to the hash table */
718 hsh = entries[i].hash % tablelen;
719
720 /* First check that there are no other entries that have the same name. */
721 int chain = table[hsh];
722 while (chain != ZIP_ENDCHAIN) {
723 const jzcell* cell = &entries[chain];
724 if (cell->hash == entries[i].hash) {
725 const char* cenStart = (const char *) cenbuf + cell->cenpos - cenpos;
726 if (CENNAM(cenStart) == nlen) {
727 const char* chainName = cenStart + CENHDR;
728 if (strncmp(entryName, chainName, nlen) == 0) {
729 ZIP_FORMAT_ERROR("invalid CEN header (duplicate entry)");
730 }
731 }
732 }
733
734 chain = cell->next;
735 }
736
737
738 entries[i].next = table[hsh];
739 table[hsh] = i;
740 }
741 if (cp != cenend) {
742 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
743 }
744
745 zip->total = i;
746 goto Finally;
747
748 Catch:
749 freeCEN(zip);
750 cenpos = -1;
751
752 Finally:
753 #ifdef USE_MMAP
754 if (!zip->usemmap)
755 #endif
756 free(cenbuf);
757
758 return cenpos;
759 }
760
761 /*
762 * Opens a zip file with the specified mode. Returns the jzfile object
763 * or NULL if an error occurred. If a zip error occurred then *pmsg will
764 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be
765 * set to NULL. Caller is responsible to free the error message.
766 */
767 jzfile *
ZIP_Open_Generic(const char * name,char ** pmsg,int mode,jlong lastModified)768 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified)
769 {
770 jzfile *zip = NULL;
771
772 /* Clear zip error message */
773 if (pmsg != 0) {
774 *pmsg = NULL;
775 }
776
777 zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
778
779 if (zip == NULL && *pmsg == NULL) {
780 ZFILE zfd = ZFILE_Open(name, mode);
781 zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
782 }
783 return zip;
784 }
785
786 /*
787 * Returns the jzfile corresponding to the given file name from the cache of
788 * zip files, or NULL if the file is not in the cache. If the name is longer
789 * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
790 * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller
791 * is responsible to free the error message.
792 */
793 jzfile *
ZIP_Get_From_Cache(const char * name,char ** pmsg,jlong lastModified)794 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
795 {
796 char buf[PATH_MAX];
797 jzfile *zip;
798
799 if (InitializeZip()) {
800 return NULL;
801 }
802
803 /* Clear zip error message */
804 if (pmsg != 0) {
805 *pmsg = NULL;
806 }
807
808 if (strlen(name) >= PATH_MAX) {
809 if (pmsg) {
810 *pmsg = strdup("zip file name too long");
811 }
812 return NULL;
813 }
814 strcpy(buf, name);
815 JVM_NativePath(buf);
816 name = buf;
817
818 MLOCK(zfiles_lock);
819 for (zip = zfiles; zip != NULL; zip = zip->next) {
820 if (strcmp(name, zip->name) == 0
821 && (zip->lastModified == lastModified || zip->lastModified == 0)
822 && zip->refs < MAXREFS) {
823 zip->refs++;
824 break;
825 }
826 }
827 MUNLOCK(zfiles_lock);
828 return zip;
829 }
830
831 /*
832 * Reads data from the given file descriptor to create a jzfile, puts the
833 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error.
834 * If a zip error occurs, then *pmsg will be set to the error message text if
835 * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to
836 * free the error message.
837 */
838
839 jzfile *
ZIP_Put_In_Cache(const char * name,ZFILE zfd,char ** pmsg,jlong lastModified)840 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
841 {
842 return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
843 }
844
845 jzfile *
ZIP_Put_In_Cache0(const char * name,ZFILE zfd,char ** pmsg,jlong lastModified,jboolean usemmap)846 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
847 jboolean usemmap)
848 {
849 char errbuf[256];
850 jlong len;
851 jzfile *zip;
852
853 if ((zip = allocZip(name)) == NULL) {
854 return NULL;
855 }
856
857 #ifdef USE_MMAP
858 zip->usemmap = usemmap;
859 #endif
860 zip->refs = 1;
861 zip->lastModified = lastModified;
862
863 if (zfd == -1) {
864 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
865 *pmsg = strdup(errbuf);
866 freeZip(zip);
867 return NULL;
868 }
869
870 // Trivially, reuse errbuf.
871 if (readFullyAt(zfd, errbuf, 4, 0 /* offset */) != -1) { // errors will be handled later
872 if (GETSIG(errbuf) == LOCSIG)
873 zip->locsig = JNI_TRUE;
874 else
875 zip->locsig = JNI_FALSE;
876 }
877
878 // This lseek is safe because it happens during construction of the ZipFile
879 // object. We must take care not to perform any operations that change the
880 // offset after (see b/30407219).
881 len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
882 if (len <= 0) {
883 if (len == 0) { /* zip file is empty */
884 if (pmsg) {
885 *pmsg = strdup("zip file is empty");
886 }
887 } else { /* error */
888 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
889 *pmsg = strdup(errbuf);
890 }
891 ZFILE_Close(zfd);
892 freeZip(zip);
893 return NULL;
894 }
895
896 zip->zfd = zfd;
897 if (readCEN(zip, -1) < 0) {
898 /* An error occurred while trying to read the zip file */
899 if (pmsg != 0) {
900 /* Set the zip error message */
901 if (zip->msg != NULL)
902 *pmsg = strdup(zip->msg);
903 }
904 freeZip(zip);
905 return NULL;
906 }
907 MLOCK(zfiles_lock);
908 zip->next = zfiles;
909 zfiles = zip;
910 MUNLOCK(zfiles_lock);
911
912 return zip;
913 }
914
915 /*
916 * Opens a zip file for reading. Returns the jzfile object or NULL
917 * if an error occurred. If a zip error occurred then *msg will be
918 * set to the error message text if msg != 0. Otherwise, *msg will be
919 * set to NULL. Caller doesn't need to free the error message.
920 */
921 jzfile * JNICALL
ZIP_Open(const char * name,char ** pmsg)922 ZIP_Open(const char *name, char **pmsg)
923 {
924 jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);
925 if (file == NULL && pmsg != NULL && *pmsg != NULL) {
926 free(*pmsg);
927 *pmsg = "Zip file open error";
928 }
929 return file;
930 }
931
932 /*
933 * Closes the specified zip file object.
934 */
935 void JNICALL
ZIP_Close(jzfile * zip)936 ZIP_Close(jzfile *zip)
937 {
938 MLOCK(zfiles_lock);
939 if (--zip->refs > 0) {
940 /* Still more references so just return */
941 MUNLOCK(zfiles_lock);
942 return;
943 }
944 /* No other references so close the file and remove from list */
945 if (zfiles == zip) {
946 zfiles = zfiles->next;
947 } else {
948 jzfile *zp;
949 for (zp = zfiles; zp->next != 0; zp = zp->next) {
950 if (zp->next == zip) {
951 zp->next = zip->next;
952 break;
953 }
954 }
955 }
956 MUNLOCK(zfiles_lock);
957 freeZip(zip);
958 return;
959 }
960
961 /* Empirically, most CEN headers are smaller than this. */
962 #define AMPLE_CEN_HEADER_SIZE 160
963
964 /* A good buffer size when we want to read CEN headers sequentially. */
965 #define CENCACHE_PAGESIZE 8192
966
967 static char *
readCENHeader(jzfile * zip,jlong cenpos,jint bufsize)968 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
969 {
970 jint censize;
971 ZFILE zfd = zip->zfd;
972 char *cen;
973 if (bufsize > zip->len - cenpos)
974 bufsize = (jint)(zip->len - cenpos);
975 if ((cen = malloc(bufsize)) == NULL) goto Catch;
976 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch;
977 censize = CENSIZE(cen);
978 if (censize <= bufsize) return cen;
979 if ((cen = realloc(cen, censize)) == NULL) goto Catch;
980 if (readFullyAt(zfd, cen+bufsize, censize-bufsize, cenpos + bufsize) == -1) goto Catch;
981 return cen;
982
983 Catch:
984 free(cen);
985 return NULL;
986 }
987
988 static char *
sequentialAccessReadCENHeader(jzfile * zip,jlong cenpos)989 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
990 {
991 cencache *cache = &zip->cencache;
992 char *cen;
993 if (cache->data != NULL
994 && (cenpos >= cache->pos)
995 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
996 {
997 cen = cache->data + cenpos - cache->pos;
998 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
999 /* A cache hit */
1000 return cen;
1001 }
1002
1003 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
1004 return NULL;
1005 free(cache->data);
1006 cache->data = cen;
1007 cache->pos = cenpos;
1008 return cen;
1009 }
1010
1011 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
1012
1013 /*
1014 * Return a new initialized jzentry corresponding to a given hash cell.
1015 * In case of error, returns NULL.
1016 * We already sanity-checked all the CEN headers for ZIP format errors
1017 * in readCEN(), so we don't check them again here.
1018 * The ZIP lock should be held here.
1019 */
1020 static jzentry *
newEntry(jzfile * zip,jzcell * zc,AccessHint accessHint)1021 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
1022 {
1023 jlong locoff;
1024 jint nlen, elen, clen;
1025 jzentry *ze;
1026 char *cen;
1027
1028 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
1029 ze->name = NULL;
1030 ze->extra = NULL;
1031 ze->comment = NULL;
1032
1033 #ifdef USE_MMAP
1034 if (zip->usemmap) {
1035 cen = (char*) zip->maddr + zc->cenpos - zip->offset;
1036 } else
1037 #endif
1038 {
1039 if (accessHint == ACCESS_RANDOM)
1040 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
1041 else
1042 cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
1043 if (cen == NULL) goto Catch;
1044 }
1045
1046 nlen = CENNAM(cen);
1047 elen = CENEXT(cen);
1048 clen = CENCOM(cen);
1049 ze->time = CENTIM(cen);
1050 ze->size = CENLEN(cen);
1051 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
1052 ze->crc = CENCRC(cen);
1053 locoff = CENOFF(cen);
1054 ze->pos = -(zip->locpos + locoff);
1055 ze->flag = CENFLG(cen);
1056
1057 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
1058 memcpy(ze->name, cen + CENHDR, nlen);
1059 ze->name[nlen] = '\0';
1060 if (elen > 0) {
1061 char *extra = cen + CENHDR + nlen;
1062
1063 /* This entry has "extra" data */
1064 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1065 ze->extra[0] = (unsigned char) elen;
1066 ze->extra[1] = (unsigned char) (elen >> 8);
1067 memcpy(ze->extra+2, extra, elen);
1068 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1069 locoff == ZIP64_MAGICVAL) {
1070 jint off = 0;
1071 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data
1072 jint sz = SH(extra, off + 2);
1073 if (SH(extra, off) == ZIP64_EXTID) {
1074 off += 4;
1075 if (ze->size == ZIP64_MAGICVAL) {
1076 // if invalid zip64 extra fields, just skip
1077 if (sz < 8 || (off + 8) > elen)
1078 break;
1079 ze->size = LL(extra, off);
1080 sz -= 8;
1081 off += 8;
1082 }
1083 if (ze->csize == ZIP64_MAGICVAL) {
1084 if (sz < 8 || (off + 8) > elen)
1085 break;
1086 ze->csize = LL(extra, off);
1087 sz -= 8;
1088 off += 8;
1089 }
1090 if (locoff == ZIP64_MAGICVAL) {
1091 if (sz < 8 || (off + 8) > elen)
1092 break;
1093 ze->pos = -(zip->locpos + LL(extra, off));
1094 sz -= 8;
1095 off += 8;
1096 }
1097 break;
1098 }
1099 off += (sz + 4);
1100 }
1101 }
1102 }
1103
1104 if (clen > 0) {
1105 /* This entry has a comment */
1106 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1107 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1108 ze->comment[clen] = '\0';
1109 }
1110 goto Finally;
1111
1112 Catch:
1113 free(ze->name);
1114 free(ze->extra);
1115 free(ze->comment);
1116 free(ze);
1117 ze = NULL;
1118
1119 Finally:
1120 #ifdef USE_MMAP
1121 if (!zip->usemmap)
1122 #endif
1123 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1124 return ze;
1125 }
1126
1127 /*
1128 * Free the given jzentry.
1129 * In fact we maintain a one-entry cache of the most recently used
1130 * jzentry for each zip. This optimizes a common access pattern.
1131 */
1132
1133 void
ZIP_FreeEntry(jzfile * jz,jzentry * ze)1134 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1135 {
1136 jzentry *last;
1137 ZIP_Lock(jz);
1138 last = jz->cache;
1139 jz->cache = ze;
1140 ZIP_Unlock(jz);
1141 if (last != NULL) {
1142 /* Free the previously cached jzentry */
1143 free(last->name);
1144 if (last->extra) free(last->extra);
1145 if (last->comment) free(last->comment);
1146 free(last);
1147 }
1148 }
1149
1150 /*
1151 * Returns the zip entry corresponding to the specified name, or
1152 * NULL if not found.
1153 */
1154 jzentry *
ZIP_GetEntry(jzfile * zip,char * name,jint ulen)1155 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1156 {
1157 unsigned int hsh = hash(name);
1158 jint idx;
1159 jzentry *ze = 0;
1160
1161 ZIP_Lock(zip);
1162 if (zip->total == 0) {
1163 goto Finally;
1164 }
1165
1166 idx = zip->table[hsh % zip->tablelen];
1167
1168 /*
1169 * This while loop is an optimization where a double lookup
1170 * for name and name+/ is being performed. The name char
1171 * array has enough room at the end to try again with a
1172 * slash appended if the first table lookup does not succeed.
1173 */
1174 while(1) {
1175
1176 /* Check the cached entry first */
1177 ze = zip->cache;
1178 if (ze && strcmp(ze->name,name) == 0) {
1179 /* Cache hit! Remove and return the cached entry. */
1180 zip->cache = 0;
1181 ZIP_Unlock(zip);
1182 return ze;
1183 }
1184 ze = 0;
1185
1186 /*
1187 * Search down the target hash chain for a cell whose
1188 * 32 bit hash matches the hashed name.
1189 */
1190 while (idx != ZIP_ENDCHAIN) {
1191 jzcell *zc = &zip->entries[idx];
1192
1193 if (zc->hash == hsh) {
1194 /*
1195 * OK, we've found a ZIP entry whose 32 bit hashcode
1196 * matches the name we're looking for. Try to read
1197 * its entry information from the CEN. If the CEN
1198 * name matches the name we're looking for, we're
1199 * done.
1200 * If the names don't match (which should be very rare)
1201 * we keep searching.
1202 */
1203 ze = newEntry(zip, zc, ACCESS_RANDOM);
1204 if (ze && strcmp(ze->name, name)==0) {
1205 break;
1206 }
1207 if (ze != 0) {
1208 /* We need to release the lock across the free call */
1209 ZIP_Unlock(zip);
1210 ZIP_FreeEntry(zip, ze);
1211 ZIP_Lock(zip);
1212 }
1213 ze = 0;
1214 }
1215 idx = zc->next;
1216 }
1217
1218 /* Entry found, return it */
1219 if (ze != 0) {
1220 break;
1221 }
1222
1223 /* If no real length was passed in, we are done */
1224 if (ulen == 0) {
1225 break;
1226 }
1227
1228 /* Slash is already there? */
1229 if (name[ulen-1] == '/') {
1230 break;
1231 }
1232
1233 /* Add slash and try once more */
1234 name[ulen] = '/';
1235 name[ulen+1] = '\0';
1236 hsh = hash_append(hsh, '/');
1237 idx = zip->table[hsh % zip->tablelen];
1238 ulen = 0;
1239 }
1240
1241 Finally:
1242 ZIP_Unlock(zip);
1243 return ze;
1244 }
1245
1246 /*
1247 * Returns the n'th (starting at zero) zip file entry, or NULL if the
1248 * specified index was out of range.
1249 */
1250 jzentry * JNICALL
ZIP_GetNextEntry(jzfile * zip,jint n)1251 ZIP_GetNextEntry(jzfile *zip, jint n)
1252 {
1253 jzentry *result;
1254 if (n < 0 || n >= zip->total) {
1255 return 0;
1256 }
1257 ZIP_Lock(zip);
1258 result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1259 ZIP_Unlock(zip);
1260 return result;
1261 }
1262
1263 /*
1264 * Locks the specified zip file for reading.
1265 */
1266 void
ZIP_Lock(jzfile * zip)1267 ZIP_Lock(jzfile *zip)
1268 {
1269 MLOCK(zip->lock);
1270 }
1271
1272 /*
1273 * Unlocks the specified zip file.
1274 */
1275 void
ZIP_Unlock(jzfile * zip)1276 ZIP_Unlock(jzfile *zip)
1277 {
1278 MUNLOCK(zip->lock);
1279 }
1280
1281 // Temporary debugging information for b/30529561. If we encounter
1282 // a zip file with a bad LOC header, we log :
1283 //
1284 // - the file data at the offset.
1285 // - the offset itself.
1286 // - the first PATH_MAX bytes of the path associated with the fd.
1287 //
1288 // TODO(narayan): Remove this once b/30529561 is resolved.
ZIP_PrintDebugInfo(jzfile * zip,jzentry * entry,const unsigned char * loc)1289 void ZIP_PrintDebugInfo(jzfile *zip, jzentry *entry,
1290 const unsigned char *loc)
1291 {
1292 ALOGE("b/30529561: Unexpected LOC header: %x", *((unsigned int*) loc));
1293 ALOGE("b/30529561: Entry offset: %zd", (size_t) entry->pos);
1294
1295 char path[64];
1296 snprintf(path, sizeof(path), "/proc/self/fd/%d", zip->zfd);
1297
1298 char buf[PATH_MAX];
1299 ssize_t count = readlink(path, buf, PATH_MAX);
1300
1301 if (count == -1) {
1302 ALOGE("b/30529561: readlink failed for %s (%s)", path, strerror(errno));
1303 return;
1304 } else if (count == PATH_MAX) {
1305 // Truncate the name, we're just using this for debugging purposes
1306 // anyway.
1307 --count;
1308 }
1309
1310 buf[count] = '\0';
1311
1312 ALOGE("b/30529561: Reading zip file %s", buf);
1313 }
1314
1315 /*
1316 * Returns the offset of the entry data within the zip file.
1317 * Returns -1 if an error occurred, in which case zip->msg will
1318 * contain the error text.
1319 */
1320 jlong
ZIP_GetEntryDataOffset(jzfile * zip,jzentry * entry)1321 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1322 {
1323 /* The Zip file spec explicitly allows the LOC extra data size to
1324 * be different from the CEN extra data size, although the JDK
1325 * never creates such zip files. Since we cannot trust the CEN
1326 * extra data size, we need to read the LOC to determine the entry
1327 * data offset. We do this lazily to avoid touching the virtual
1328 * memory page containing the LOC when initializing jzentry
1329 * objects. (This speeds up javac by a factor of 10 when the JDK
1330 * is installed on a very slow filesystem.)
1331 */
1332 if (entry->pos <= 0) {
1333 unsigned char loc[LOCHDR];
1334 if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1335 zip->msg = "error reading zip file";
1336 return -1;
1337 }
1338 if (GETSIG(loc) != LOCSIG) {
1339 // TODO(narayan): Remove this debug message once b/30529561 is
1340 // sorted out satisfactorily.
1341 ZIP_PrintDebugInfo(zip, entry, loc);
1342
1343 zip->msg = "invalid LOC header (bad signature)";
1344 return -1;
1345 }
1346 entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1347 }
1348 return entry->pos;
1349 }
1350
1351 /*
1352 * Reads bytes from the specified zip entry. Assumes that the zip
1353 * file had been previously locked with ZIP_Lock(). Returns the
1354 * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1355 * then a zip error occurred and zip->msg contains the error text.
1356 *
1357 * The current implementation does not support reading an entry that
1358 * has the size bigger than 2**32 bytes in ONE invocation.
1359 */
1360 jint
ZIP_Read(jzfile * zip,jzentry * entry,jlong pos,void * buf,jint len)1361 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1362 {
1363 jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1364 jlong start;
1365
1366 /* Clear previous zip error */
1367 zip->msg = NULL;
1368
1369 /* Check specified position */
1370 if (pos < 0 || pos > entry_size - 1) {
1371 zip->msg = "ZIP_Read: specified offset out of range";
1372 return -1;
1373 }
1374
1375 /* Check specified length */
1376 if (len <= 0)
1377 return 0;
1378 if (len > entry_size - pos)
1379 len = (jint)(entry_size - pos);
1380
1381 /* Get file offset to start reading data */
1382 start = ZIP_GetEntryDataOffset(zip, entry);
1383 if (start < 0)
1384 return -1;
1385 start += pos;
1386
1387 if (start + len > zip->len) {
1388 zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1389 return -1;
1390 }
1391
1392 if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1393 zip->msg = "ZIP_Read: error reading zip file";
1394 return -1;
1395 }
1396 return len;
1397 }
1398
1399
1400 /* The maximum size of a stack-allocated buffer.
1401 */
1402 #define BUF_SIZE 4096
1403
1404 /*
1405 * This function is used by the runtime system to load compressed entries
1406 * from ZIP/JAR files specified in the class path. It is defined here
1407 * so that it can be dynamically loaded by the runtime if the zip library
1408 * is found.
1409 *
1410 * The current implementation does not support reading an entry that
1411 * has the size bigger than 2**32 bytes in ONE invocation.
1412 */
1413 jboolean
InflateFully(jzfile * zip,jzentry * entry,void * buf,char ** msg)1414 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1415 {
1416 z_stream strm;
1417 char tmp[BUF_SIZE];
1418 jlong pos = 0;
1419 jlong count = entry->csize;
1420
1421 *msg = 0; /* Reset error message */
1422
1423 if (count == 0) {
1424 *msg = "inflateFully: entry not compressed";
1425 return JNI_FALSE;
1426 }
1427
1428 memset(&strm, 0, sizeof(z_stream));
1429 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1430 *msg = strm.msg;
1431 return JNI_FALSE;
1432 }
1433
1434 strm.next_out = buf;
1435 strm.avail_out = (uInt)entry->size;
1436
1437 while (count > 0) {
1438 jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1439 ZIP_Lock(zip);
1440 n = ZIP_Read(zip, entry, pos, tmp, n);
1441 ZIP_Unlock(zip);
1442 if (n <= 0) {
1443 if (n == 0) {
1444 *msg = "inflateFully: Unexpected end of file";
1445 }
1446 inflateEnd(&strm);
1447 return JNI_FALSE;
1448 }
1449 pos += n;
1450 count -= n;
1451 strm.next_in = (Bytef *)tmp;
1452 strm.avail_in = n;
1453 do {
1454 switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1455 case Z_OK:
1456 break;
1457 case Z_STREAM_END:
1458 if (count != 0 || entry->size < 0 || strm.total_out != (uint64_t)entry->size) {
1459 *msg = "inflateFully: Unexpected end of stream";
1460 inflateEnd(&strm);
1461 return JNI_FALSE;
1462 }
1463 break;
1464 default:
1465 break;
1466 }
1467 } while (strm.avail_in > 0);
1468 }
1469 inflateEnd(&strm);
1470 return JNI_TRUE;
1471 }
1472
1473 /*
1474 * The current implementation does not support reading an entry that
1475 * has the size bigger than 2**32 bytes in ONE invocation.
1476 */
1477 jzentry * JNICALL
ZIP_FindEntry(jzfile * zip,char * name,jint * sizeP,jint * nameLenP)1478 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1479 {
1480 jzentry *entry = ZIP_GetEntry(zip, name, 0);
1481 if (entry) {
1482 *sizeP = (jint)entry->size;
1483 *nameLenP = strlen(entry->name);
1484 }
1485 return entry;
1486 }
1487
1488 /*
1489 * Reads a zip file entry into the specified byte array
1490 * When the method completes, it releases the jzentry.
1491 * Note: this is called from the separately delivered VM (hotspot/classic)
1492 * so we have to be careful to maintain the expected behaviour.
1493 */
1494 jboolean JNICALL
ZIP_ReadEntry(jzfile * zip,jzentry * entry,unsigned char * buf,char * entryname)1495 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1496 {
1497 char *msg;
1498
1499 strcpy(entryname, entry->name);
1500 if (entry->csize == 0) {
1501 /* Entry is stored */
1502 jlong pos = 0;
1503 jlong size = entry->size;
1504 while (pos < size) {
1505 jint n;
1506 jlong limit = ((((jlong) 1) << 31) - 1);
1507 jint count = (size - pos < limit) ?
1508 /* These casts suppress a VC++ Internal Compiler Error */
1509 (jint) (size - pos) :
1510 (jint) limit;
1511 ZIP_Lock(zip);
1512 n = ZIP_Read(zip, entry, pos, buf, count);
1513 msg = zip->msg;
1514 ZIP_Unlock(zip);
1515 if (n == -1) {
1516 jio_fprintf(stderr, "%s: %s\n", zip->name,
1517 msg != 0 ? msg : strerror(errno));
1518 return JNI_FALSE;
1519 }
1520 buf += n;
1521 pos += n;
1522 }
1523 } else {
1524 /* Entry is compressed */
1525 int ok = InflateFully(zip, entry, buf, &msg);
1526 if (!ok) {
1527 if ((msg == NULL) || (*msg == 0)) {
1528 msg = zip->msg;
1529 }
1530 jio_fprintf(stderr, "%s: %s\n", zip->name,
1531 msg != 0 ? msg : strerror(errno));
1532 return JNI_FALSE;
1533 }
1534 }
1535
1536 ZIP_FreeEntry(zip, entry);
1537
1538 return JNI_TRUE;
1539 }
1540