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 // BEGIN Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
779 /*
780 if (pmsg != 0) {
781 *pmsg = NULL;
782 }
783
784 zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
785
786 if (zip == NULL && *pmsg == NULL) {
787 ZFILE zfd = ZFILE_Open(name, mode);
788 zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
789 }
790 */
791 /*
792 * We want to know if ZIP_Get_From_Cache fails, which isn't possible to
793 * distinguish without passing a non-null message value. Hence, if the user
794 * didn't supply a `pmsg`, we make and manage our own.
795 */
796 char *localPmsg = NULL;
797 zip = ZIP_Get_From_Cache(name, &localPmsg, lastModified);
798
799 if (zip == NULL && localPmsg == NULL) {
800 ZFILE zfd = ZFILE_Open(name, mode);
801 zip = ZIP_Put_In_Cache(name, zfd, &localPmsg, lastModified);
802 }
803
804 if (pmsg == NULL) {
805 free(localPmsg);
806 } else {
807 *pmsg = localPmsg;
808 }
809 // END Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
810 return zip;
811 }
812
813 /*
814 * Returns the jzfile corresponding to the given file name from the cache of
815 * zip files, or NULL if the file is not in the cache. If the name is longer
816 * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
817 * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller
818 * is responsible to free the error message.
819 */
820 jzfile *
ZIP_Get_From_Cache(const char * name,char ** pmsg,jlong lastModified)821 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
822 {
823 char buf[PATH_MAX];
824 jzfile *zip;
825
826 if (InitializeZip()) {
827 return NULL;
828 }
829
830 /* Clear zip error message */
831 if (pmsg != 0) {
832 *pmsg = NULL;
833 }
834
835 if (strlen(name) >= PATH_MAX) {
836 if (pmsg) {
837 *pmsg = strdup("zip file name too long");
838 }
839 return NULL;
840 }
841 strcpy(buf, name);
842 JVM_NativePath(buf);
843 name = buf;
844
845 MLOCK(zfiles_lock);
846 for (zip = zfiles; zip != NULL; zip = zip->next) {
847 if (strcmp(name, zip->name) == 0
848 && (zip->lastModified == lastModified || zip->lastModified == 0)
849 && zip->refs < MAXREFS) {
850 zip->refs++;
851 break;
852 }
853 }
854 MUNLOCK(zfiles_lock);
855 return zip;
856 }
857
858 /*
859 * Reads data from the given file descriptor to create a jzfile, puts the
860 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error.
861 * If a zip error occurs, then *pmsg will be set to the error message text if
862 * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to
863 * free the error message.
864 */
865
866 jzfile *
ZIP_Put_In_Cache(const char * name,ZFILE zfd,char ** pmsg,jlong lastModified)867 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
868 {
869 return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
870 }
871
872 jzfile *
ZIP_Put_In_Cache0(const char * name,ZFILE zfd,char ** pmsg,jlong lastModified,jboolean usemmap)873 ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
874 jboolean usemmap)
875 {
876 char errbuf[256];
877 jlong len;
878 jzfile *zip;
879
880 if ((zip = allocZip(name)) == NULL) {
881 return NULL;
882 }
883
884 #ifdef USE_MMAP
885 zip->usemmap = usemmap;
886 #endif
887 zip->refs = 1;
888 zip->lastModified = lastModified;
889
890 if (zfd == -1) {
891 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
892 *pmsg = strdup(errbuf);
893 freeZip(zip);
894 return NULL;
895 }
896
897 // Trivially, reuse errbuf.
898 if (readFullyAt(zfd, errbuf, 4, 0 /* offset */) != -1) { // errors will be handled later
899 if (GETSIG(errbuf) == LOCSIG)
900 zip->locsig = JNI_TRUE;
901 else
902 zip->locsig = JNI_FALSE;
903 }
904
905 // This lseek is safe because it happens during construction of the ZipFile
906 // object. We must take care not to perform any operations that change the
907 // offset after (see b/30407219).
908 len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
909 if (len <= 0) {
910 if (len == 0) { /* zip file is empty */
911 if (pmsg) {
912 *pmsg = strdup("zip file is empty");
913 }
914 } else { /* error */
915 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
916 *pmsg = strdup(errbuf);
917 }
918 ZFILE_Close(zfd);
919 freeZip(zip);
920 return NULL;
921 }
922
923 zip->zfd = zfd;
924 if (readCEN(zip, -1) < 0) {
925 /* An error occurred while trying to read the zip file */
926 if (pmsg != 0) {
927 /* Set the zip error message */
928 if (zip->msg != NULL)
929 *pmsg = strdup(zip->msg);
930 }
931 freeZip(zip);
932 return NULL;
933 }
934 MLOCK(zfiles_lock);
935 zip->next = zfiles;
936 zfiles = zip;
937 MUNLOCK(zfiles_lock);
938
939 return zip;
940 }
941
942 /*
943 * Opens a zip file for reading. Returns the jzfile object or NULL
944 * if an error occurred. If a zip error occurred then *msg will be
945 * set to the error message text if msg != 0. Otherwise, *msg will be
946 * set to NULL. Caller doesn't need to free the error message.
947 */
948 jzfile * JNICALL
ZIP_Open(const char * name,char ** pmsg)949 ZIP_Open(const char *name, char **pmsg)
950 {
951 jzfile *file = ZIP_Open_Generic(name, pmsg, O_RDONLY, 0);
952 if (file == NULL && pmsg != NULL && *pmsg != NULL) {
953 free(*pmsg);
954 *pmsg = "Zip file open error";
955 }
956 return file;
957 }
958
959 /*
960 * Closes the specified zip file object.
961 */
962 void JNICALL
ZIP_Close(jzfile * zip)963 ZIP_Close(jzfile *zip)
964 {
965 MLOCK(zfiles_lock);
966 if (--zip->refs > 0) {
967 /* Still more references so just return */
968 MUNLOCK(zfiles_lock);
969 return;
970 }
971 /* No other references so close the file and remove from list */
972 if (zfiles == zip) {
973 zfiles = zfiles->next;
974 } else {
975 jzfile *zp;
976 for (zp = zfiles; zp->next != 0; zp = zp->next) {
977 if (zp->next == zip) {
978 zp->next = zip->next;
979 break;
980 }
981 }
982 }
983 MUNLOCK(zfiles_lock);
984 freeZip(zip);
985 return;
986 }
987
988 /* Empirically, most CEN headers are smaller than this. */
989 #define AMPLE_CEN_HEADER_SIZE 160
990
991 /* A good buffer size when we want to read CEN headers sequentially. */
992 #define CENCACHE_PAGESIZE 8192
993
994 static char *
readCENHeader(jzfile * zip,jlong cenpos,jint bufsize)995 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
996 {
997 jint censize;
998 ZFILE zfd = zip->zfd;
999 char *cen;
1000 if (bufsize > zip->len - cenpos)
1001 bufsize = (jint)(zip->len - cenpos);
1002 if ((cen = malloc(bufsize)) == NULL) goto Catch;
1003 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch;
1004 censize = CENSIZE(cen);
1005 if (censize <= bufsize) return cen;
1006 if ((cen = realloc(cen, censize)) == NULL) goto Catch;
1007 if (readFullyAt(zfd, cen+bufsize, censize-bufsize, cenpos + bufsize) == -1) goto Catch;
1008 return cen;
1009
1010 Catch:
1011 free(cen);
1012 return NULL;
1013 }
1014
1015 static char *
sequentialAccessReadCENHeader(jzfile * zip,jlong cenpos)1016 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
1017 {
1018 cencache *cache = &zip->cencache;
1019 char *cen;
1020 if (cache->data != NULL
1021 && (cenpos >= cache->pos)
1022 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
1023 {
1024 cen = cache->data + cenpos - cache->pos;
1025 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
1026 /* A cache hit */
1027 return cen;
1028 }
1029
1030 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
1031 return NULL;
1032 free(cache->data);
1033 cache->data = cen;
1034 cache->pos = cenpos;
1035 return cen;
1036 }
1037
1038 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
1039
1040 /*
1041 * Return a new initialized jzentry corresponding to a given hash cell.
1042 * In case of error, returns NULL.
1043 * We already sanity-checked all the CEN headers for ZIP format errors
1044 * in readCEN(), so we don't check them again here.
1045 * The ZIP lock should be held here.
1046 */
1047 static jzentry *
newEntry(jzfile * zip,jzcell * zc,AccessHint accessHint)1048 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
1049 {
1050 jlong locoff;
1051 jint nlen, elen, clen;
1052 jzentry *ze;
1053 char *cen;
1054
1055 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
1056 ze->name = NULL;
1057 ze->extra = NULL;
1058 ze->comment = NULL;
1059
1060 #ifdef USE_MMAP
1061 if (zip->usemmap) {
1062 cen = (char*) zip->maddr + zc->cenpos - zip->offset;
1063 } else
1064 #endif
1065 {
1066 if (accessHint == ACCESS_RANDOM)
1067 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
1068 else
1069 cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
1070 if (cen == NULL) goto Catch;
1071 }
1072
1073 nlen = CENNAM(cen);
1074 elen = CENEXT(cen);
1075 clen = CENCOM(cen);
1076 ze->time = CENTIM(cen);
1077 ze->size = CENLEN(cen);
1078 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
1079 ze->crc = CENCRC(cen);
1080 locoff = CENOFF(cen);
1081 ze->pos = -(zip->locpos + locoff);
1082 ze->flag = CENFLG(cen);
1083
1084 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
1085 memcpy(ze->name, cen + CENHDR, nlen);
1086 ze->name[nlen] = '\0';
1087 ze->nlen = nlen;
1088 if (elen > 0) {
1089 char *extra = cen + CENHDR + nlen;
1090
1091 /* This entry has "extra" data */
1092 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1093 ze->extra[0] = (unsigned char) elen;
1094 ze->extra[1] = (unsigned char) (elen >> 8);
1095 memcpy(ze->extra+2, extra, elen);
1096 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1097 locoff == ZIP64_MAGICVAL) {
1098 jint off = 0;
1099 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data
1100 jint sz = SH(extra, off + 2);
1101 if (SH(extra, off) == ZIP64_EXTID) {
1102 off += 4;
1103 if (ze->size == ZIP64_MAGICVAL) {
1104 // if invalid zip64 extra fields, just skip
1105 if (sz < 8 || (off + 8) > elen)
1106 break;
1107 ze->size = LL(extra, off);
1108 sz -= 8;
1109 off += 8;
1110 }
1111 if (ze->csize == ZIP64_MAGICVAL) {
1112 if (sz < 8 || (off + 8) > elen)
1113 break;
1114 ze->csize = LL(extra, off);
1115 sz -= 8;
1116 off += 8;
1117 }
1118 if (locoff == ZIP64_MAGICVAL) {
1119 if (sz < 8 || (off + 8) > elen)
1120 break;
1121 ze->pos = -(zip->locpos + LL(extra, off));
1122 sz -= 8;
1123 off += 8;
1124 }
1125 break;
1126 }
1127 off += (sz + 4);
1128 }
1129 }
1130 }
1131
1132 if (clen > 0) {
1133 /* This entry has a comment */
1134 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1135 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1136 ze->comment[clen] = '\0';
1137 }
1138 goto Finally;
1139
1140 Catch:
1141 free(ze->name);
1142 free(ze->extra);
1143 free(ze->comment);
1144 free(ze);
1145 ze = NULL;
1146
1147 Finally:
1148 #ifdef USE_MMAP
1149 if (!zip->usemmap)
1150 #endif
1151 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1152 return ze;
1153 }
1154
1155 /*
1156 * Free the given jzentry.
1157 * In fact we maintain a one-entry cache of the most recently used
1158 * jzentry for each zip. This optimizes a common access pattern.
1159 */
1160
1161 void
ZIP_FreeEntry(jzfile * jz,jzentry * ze)1162 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1163 {
1164 jzentry *last;
1165 ZIP_Lock(jz);
1166 last = jz->cache;
1167 jz->cache = ze;
1168 ZIP_Unlock(jz);
1169 if (last != NULL) {
1170 /* Free the previously cached jzentry */
1171 free(last->name);
1172 if (last->extra) free(last->extra);
1173 if (last->comment) free(last->comment);
1174 free(last);
1175 }
1176 }
1177
1178 /*
1179 * Returns the zip entry corresponding to the specified name, or
1180 * NULL if not found.
1181 */
1182 jzentry *
ZIP_GetEntry(jzfile * zip,char * name,jint ulen)1183 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1184 {
1185 if (ulen == 0) {
1186 return ZIP_GetEntry2(zip, name, strlen(name), JNI_FALSE);
1187 }
1188 return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);
1189 }
1190
equals(char * name1,int len1,char * name2,int len2)1191 jboolean equals(char* name1, int len1, char* name2, int len2) {
1192 if (len1 != len2) {
1193 return JNI_FALSE;
1194 }
1195 while (len1-- > 0) {
1196 if (*name1++ != *name2++) {
1197 return JNI_FALSE;
1198 }
1199 }
1200 return JNI_TRUE;
1201 }
1202
1203 /*
1204 * Returns the zip entry corresponding to the specified name, or
1205 * NULL if not found.
1206 * This method supports embedded null character in "name", use ulen
1207 * for the length of "name".
1208 */
1209 jzentry *
ZIP_GetEntry2(jzfile * zip,char * name,jint ulen,jboolean addSlash)1210 ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)
1211 {
1212 unsigned int hsh = hashN(name, ulen);
1213 jint idx;
1214 jzentry *ze = 0;
1215
1216 ZIP_Lock(zip);
1217 if (zip->total == 0) {
1218 goto Finally;
1219 }
1220
1221 idx = zip->table[hsh % zip->tablelen];
1222
1223 /*
1224 * This while loop is an optimization where a double lookup
1225 * for name and name+/ is being performed. The name char
1226 * array has enough room at the end to try again with a
1227 * slash appended if the first table lookup does not succeed.
1228 */
1229 while(1) {
1230
1231 /* Check the cached entry first */
1232 ze = zip->cache;
1233 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1234 /* Cache hit! Remove and return the cached entry. */
1235 zip->cache = 0;
1236 ZIP_Unlock(zip);
1237 return ze;
1238 }
1239 ze = 0;
1240
1241 /*
1242 * Search down the target hash chain for a cell whose
1243 * 32 bit hash matches the hashed name.
1244 */
1245 while (idx != ZIP_ENDCHAIN) {
1246 jzcell *zc = &zip->entries[idx];
1247
1248 if (zc->hash == hsh) {
1249 /*
1250 * OK, we've found a ZIP entry whose 32 bit hashcode
1251 * matches the name we're looking for. Try to read
1252 * its entry information from the CEN. If the CEN
1253 * name matches the name we're looking for, we're
1254 * done.
1255 * If the names don't match (which should be very rare)
1256 * we keep searching.
1257 */
1258 ze = newEntry(zip, zc, ACCESS_RANDOM);
1259 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1260 break;
1261 }
1262 if (ze != 0) {
1263 /* We need to release the lock across the free call */
1264 ZIP_Unlock(zip);
1265 ZIP_FreeEntry(zip, ze);
1266 ZIP_Lock(zip);
1267 }
1268 ze = 0;
1269 }
1270 idx = zc->next;
1271 }
1272
1273 /* Entry found, return it */
1274 if (ze != 0) {
1275 break;
1276 }
1277
1278 /* If no need to try appending slash, we are done */
1279 if (!addSlash) {
1280 break;
1281 }
1282
1283 /* Slash is already there? */
1284 if (name[ulen-1] == '/') {
1285 break;
1286 }
1287
1288 /* Add slash and try once more */
1289 name[ulen++] = '/';
1290 name[ulen] = '\0';
1291 hsh = hash_append(hsh, '/');
1292 idx = zip->table[hsh % zip->tablelen];
1293 addSlash = JNI_FALSE;
1294 }
1295
1296 Finally:
1297 ZIP_Unlock(zip);
1298 return ze;
1299 }
1300
1301 /*
1302 * Returns the n'th (starting at zero) zip file entry, or NULL if the
1303 * specified index was out of range.
1304 */
1305 jzentry * JNICALL
ZIP_GetNextEntry(jzfile * zip,jint n)1306 ZIP_GetNextEntry(jzfile *zip, jint n)
1307 {
1308 jzentry *result;
1309 if (n < 0 || n >= zip->total) {
1310 return 0;
1311 }
1312 ZIP_Lock(zip);
1313 result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1314 ZIP_Unlock(zip);
1315 return result;
1316 }
1317
1318 /*
1319 * Locks the specified zip file for reading.
1320 */
1321 void
ZIP_Lock(jzfile * zip)1322 ZIP_Lock(jzfile *zip)
1323 {
1324 MLOCK(zip->lock);
1325 }
1326
1327 /*
1328 * Unlocks the specified zip file.
1329 */
1330 void
ZIP_Unlock(jzfile * zip)1331 ZIP_Unlock(jzfile *zip)
1332 {
1333 MUNLOCK(zip->lock);
1334 }
1335
1336 /*
1337 * Returns the offset of the entry data within the zip file.
1338 * Returns -1 if an error occurred, in which case zip->msg will
1339 * contain the error text.
1340 */
1341 jlong
ZIP_GetEntryDataOffset(jzfile * zip,jzentry * entry)1342 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1343 {
1344 /* The Zip file spec explicitly allows the LOC extra data size to
1345 * be different from the CEN extra data size, although the JDK
1346 * never creates such zip files. Since we cannot trust the CEN
1347 * extra data size, we need to read the LOC to determine the entry
1348 * data offset. We do this lazily to avoid touching the virtual
1349 * memory page containing the LOC when initializing jzentry
1350 * objects. (This speeds up javac by a factor of 10 when the JDK
1351 * is installed on a very slow filesystem.)
1352 */
1353 if (entry->pos <= 0) {
1354 unsigned char loc[LOCHDR];
1355 if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1356 zip->msg = "error reading zip file";
1357 return -1;
1358 }
1359 if (GETSIG(loc) != LOCSIG) {
1360 zip->msg = "invalid LOC header (bad signature)";
1361 return -1;
1362 }
1363 entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1364 }
1365 return entry->pos;
1366 }
1367
1368 /*
1369 * Reads bytes from the specified zip entry. Assumes that the zip
1370 * file had been previously locked with ZIP_Lock(). Returns the
1371 * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1372 * then a zip error occurred and zip->msg contains the error text.
1373 *
1374 * The current implementation does not support reading an entry that
1375 * has the size bigger than 2**32 bytes in ONE invocation.
1376 */
1377 jint
ZIP_Read(jzfile * zip,jzentry * entry,jlong pos,void * buf,jint len)1378 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1379 {
1380 jlong entry_size;
1381 jlong start;
1382
1383 if (zip == 0) {
1384 return -1;
1385 }
1386
1387 /* Clear previous zip error */
1388 zip->msg = NULL;
1389
1390 if (entry == 0) {
1391 zip->msg = "ZIP_Read: jzentry is NULL";
1392 return -1;
1393 }
1394
1395 entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1396
1397 /* Check specified position */
1398 if (pos < 0 || pos > entry_size - 1) {
1399 zip->msg = "ZIP_Read: specified offset out of range";
1400 return -1;
1401 }
1402
1403 /* Check specified length */
1404 if (len <= 0)
1405 return 0;
1406 if (len > entry_size - pos)
1407 len = (jint)(entry_size - pos);
1408
1409 /* Get file offset to start reading data */
1410 start = ZIP_GetEntryDataOffset(zip, entry);
1411 if (start < 0)
1412 return -1;
1413 start += pos;
1414
1415 if (start + len > zip->len) {
1416 zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1417 return -1;
1418 }
1419
1420 if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1421 zip->msg = "ZIP_Read: error reading zip file";
1422 return -1;
1423 }
1424 return len;
1425 }
1426
1427
1428 /* The maximum size of a stack-allocated buffer.
1429 */
1430 #define BUF_SIZE 4096
1431
1432 /*
1433 * This function is used by the runtime system to load compressed entries
1434 * from ZIP/JAR files specified in the class path. It is defined here
1435 * so that it can be dynamically loaded by the runtime if the zip library
1436 * is found.
1437 *
1438 * The current implementation does not support reading an entry that
1439 * has the size bigger than 2**32 bytes in ONE invocation.
1440 */
1441 jboolean
InflateFully(jzfile * zip,jzentry * entry,void * buf,char ** msg)1442 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1443 {
1444 z_stream strm;
1445 char tmp[BUF_SIZE];
1446 jlong pos = 0;
1447 jlong count = entry->csize;
1448
1449 *msg = 0; /* Reset error message */
1450
1451 if (count == 0) {
1452 *msg = "inflateFully: entry not compressed";
1453 return JNI_FALSE;
1454 }
1455
1456 memset(&strm, 0, sizeof(z_stream));
1457 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1458 *msg = strm.msg;
1459 return JNI_FALSE;
1460 }
1461
1462 strm.next_out = buf;
1463 strm.avail_out = (uInt)entry->size;
1464
1465 while (count > 0) {
1466 jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1467 ZIP_Lock(zip);
1468 n = ZIP_Read(zip, entry, pos, tmp, n);
1469 ZIP_Unlock(zip);
1470 if (n <= 0) {
1471 if (n == 0) {
1472 *msg = "inflateFully: Unexpected end of file";
1473 }
1474 inflateEnd(&strm);
1475 return JNI_FALSE;
1476 }
1477 pos += n;
1478 count -= n;
1479 strm.next_in = (Bytef *)tmp;
1480 strm.avail_in = n;
1481 do {
1482 switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1483 case Z_OK:
1484 break;
1485 case Z_STREAM_END:
1486 if (count != 0 || entry->size < 0 || strm.total_out != (uint64_t)entry->size) {
1487 *msg = "inflateFully: Unexpected end of stream";
1488 inflateEnd(&strm);
1489 return JNI_FALSE;
1490 }
1491 break;
1492 default:
1493 break;
1494 }
1495 } while (strm.avail_in > 0);
1496 }
1497 inflateEnd(&strm);
1498 return JNI_TRUE;
1499 }
1500
1501 /*
1502 * The current implementation does not support reading an entry that
1503 * has the size bigger than 2**32 bytes in ONE invocation.
1504 */
1505 jzentry * JNICALL
ZIP_FindEntry(jzfile * zip,char * name,jint * sizeP,jint * nameLenP)1506 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1507 {
1508 jzentry *entry = ZIP_GetEntry(zip, name, 0);
1509 if (entry) {
1510 *sizeP = (jint)entry->size;
1511 *nameLenP = strlen(entry->name);
1512 }
1513 return entry;
1514 }
1515
1516 /*
1517 * Reads a zip file entry into the specified byte array
1518 * When the method completes, it releases the jzentry.
1519 * Note: this is called from the separately delivered VM (hotspot/classic)
1520 * so we have to be careful to maintain the expected behaviour.
1521 */
1522 jboolean JNICALL
ZIP_ReadEntry(jzfile * zip,jzentry * entry,unsigned char * buf,char * entryname)1523 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1524 {
1525 char *msg;
1526 char tmpbuf[1024];
1527
1528 if (entry == 0) {
1529 jio_fprintf(stderr, "jzentry was invalid");
1530 return JNI_FALSE;
1531 }
1532
1533 strcpy(entryname, entry->name);
1534 if (entry->csize == 0) {
1535 /* Entry is stored */
1536 jlong pos = 0;
1537 jlong size = entry->size;
1538 while (pos < size) {
1539 jint n;
1540 jlong limit = ((((jlong) 1) << 31) - 1);
1541 jint count = (size - pos < limit) ?
1542 /* These casts suppress a VC++ Internal Compiler Error */
1543 (jint) (size - pos) :
1544 (jint) limit;
1545 ZIP_Lock(zip);
1546 n = ZIP_Read(zip, entry, pos, buf, count);
1547 msg = zip->msg;
1548 ZIP_Unlock(zip);
1549 if (n == -1) {
1550 if (msg == 0) {
1551 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1552 msg = tmpbuf;
1553 }
1554 jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1555 return JNI_FALSE;
1556 }
1557 buf += n;
1558 pos += n;
1559 }
1560 } else {
1561 /* Entry is compressed */
1562 int ok = InflateFully(zip, entry, buf, &msg);
1563 if (!ok) {
1564 if ((msg == NULL) || (*msg == 0)) {
1565 msg = zip->msg;
1566 }
1567 if (msg == 0) {
1568 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1569 msg = tmpbuf;
1570 }
1571 jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1572 return JNI_FALSE;
1573 }
1574 }
1575
1576 ZIP_FreeEntry(zip, entry);
1577
1578 return JNI_TRUE;
1579 }
1580