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