1 /* 2 * Copyright 1995-2009 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any 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 /* USE_MMAP means mmap the CEN & ENDHDR part of the zip file. */ 50 #ifdef USE_MMAP 51 #include <sys/mman.h> 52 #endif 53 54 #define MAXREFS 0xFFFF /* max number of open zip file references */ 55 56 #define MCREATE() JVM_RawMonitorCreate() 57 #define MLOCK(lock) JVM_RawMonitorEnter(lock) 58 #define MUNLOCK(lock) JVM_RawMonitorExit(lock) 59 #define MDESTROY(lock) JVM_RawMonitorDestroy(lock) 60 61 #define CENSIZE(cen) (CENHDR + CENNAM(cen) + CENEXT(cen) + CENCOM(cen)) 62 63 static jzfile *zfiles = 0; /* currently open zip files */ 64 static void *zfiles_lock = 0; 65 66 static void freeCEN(jzfile *); 67 68 #ifndef PATH_MAX 69 #define PATH_MAX 1024 70 #endif 71 72 static jint INITIAL_META_COUNT = 2; /* initial number of entries in meta name array */ 73 74 /* 75 * The ZFILE_* functions exist to provide some platform-independence with 76 * respect to file access needs. 77 */ 78 79 /* 80 * Opens the named file for reading, returning a ZFILE. 81 * 82 * Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c. 83 * This function does not take JNIEnv* and uses CreateFile (instead of 84 * CreateFileW). The expectation is that this function will be called only 85 * from ZIP_Open_Generic, which in turn is used by the JVM, where we do not 86 * need to concern ourselves with wide chars. 87 */ 88 static ZFILE 89 ZFILE_Open(const char *fname, int flags) { 90 #ifdef WIN32 91 const DWORD access = 92 (flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : 93 (flags & O_WRONLY) ? GENERIC_WRITE : 94 GENERIC_READ; 95 const DWORD sharing = 96 FILE_SHARE_READ | FILE_SHARE_WRITE; 97 const DWORD disposition = 98 /* Note: O_TRUNC overrides O_CREAT */ 99 (flags & O_TRUNC) ? CREATE_ALWAYS : 100 (flags & O_CREAT) ? OPEN_ALWAYS : 101 OPEN_EXISTING; 102 const DWORD maybeWriteThrough = 103 (flags & (O_SYNC | O_DSYNC)) ? 104 FILE_FLAG_WRITE_THROUGH : 105 FILE_ATTRIBUTE_NORMAL; 106 const DWORD maybeDeleteOnClose = 107 (flags & O_TEMPORARY) ? 108 FILE_FLAG_DELETE_ON_CLOSE : 109 FILE_ATTRIBUTE_NORMAL; 110 const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose; 111 112 return (jlong) CreateFile( 113 fname, /* Wide char path name */ 114 access, /* Read and/or write permission */ 115 sharing, /* File sharing flags */ 116 NULL, /* Security attributes */ 117 disposition, /* creation disposition */ 118 flagsAndAttributes, /* flags and attributes */ 119 NULL); 120 #else 121 return JVM_Open(fname, flags, 0); 122 #endif 123 } 124 125 /* 126 * The io_util_md.h files do not provide IO_CLOSE, hence we use platform 127 * specifics. 128 */ 129 static void 130 ZFILE_Close(ZFILE zfd) { 131 #ifdef WIN32 132 CloseHandle((HANDLE) zfd); 133 #else 134 JVM_Close(zfd); 135 #endif 136 } 137 138 static int 139 ZFILE_read(ZFILE zfd, char *buf, jint nbytes) { 140 #ifdef WIN32 141 return (int) IO_Read(zfd, buf, nbytes); 142 #else 143 /* 144 * Calling JVM_Read will return JVM_IO_INTR when Thread.interrupt is called 145 * only on Solaris. Continue reading jar file in this case is the best 146 * thing to do since zip file reading is relatively fast and it is very onerous 147 * for a interrupted thread to deal with this kind of hidden I/O. However, handling 148 * JVM_IO_INTR is tricky and could cause undesired side effect. So we decided 149 * to simply call "read" on Solaris/Linux. See details in bug 6304463. 150 */ 151 return read(zfd, buf, nbytes); 152 #endif 153 } 154 155 /* 156 * Initialize zip file support. Return 0 if successful otherwise -1 157 * if could not be initialized. 158 */ 159 static jint 160 InitializeZip() 161 { 162 static jboolean inited = JNI_FALSE; 163 164 // Initialize errno to 0. It may be set later (e.g. during memory 165 // allocation) but we can disregard previous values. 166 errno = 0; 167 168 if (inited) 169 return 0; 170 zfiles_lock = MCREATE(); 171 if (zfiles_lock == 0) { 172 return -1; 173 } 174 inited = JNI_TRUE; 175 176 return 0; 177 } 178 179 /* 180 * Reads len bytes of data into buf. 181 * Returns 0 if all bytes could be read, otherwise returns -1. 182 */ 183 static int 184 readFully(ZFILE zfd, void *buf, jlong len) { 185 char *bp = (char *) buf; 186 187 while (len > 0) { 188 jlong limit = ((((jlong) 1) << 31) - 1); 189 jint count = (len < limit) ? 190 (jint) len : 191 (jint) limit; 192 jint n = ZFILE_read(zfd, bp, count); 193 if (n > 0) { 194 bp += n; 195 len -= n; 196 } else if (n == JVM_IO_ERR && errno == EINTR) { 197 /* Retry after EINTR (interrupted by signal). 198 We depend on the fact that JVM_IO_ERR == -1. */ 199 continue; 200 } else { /* EOF or IO error */ 201 return -1; 202 } 203 } 204 return 0; 205 } 206 207 /* 208 * Reads len bytes of data from the specified offset into buf. 209 * Returns 0 if all bytes could be read, otherwise returns -1. 210 */ 211 static int 212 readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) 213 { 214 if (IO_Lseek(zfd, offset, SEEK_SET) == -1) { 215 return -1; /* lseek failure. */ 216 } 217 218 return readFully(zfd, buf, len); 219 } 220 221 /* 222 * Allocates a new zip file object for the specified file name. 223 * Returns the zip file object or NULL if not enough memory. 224 */ 225 static jzfile * 226 allocZip(const char *name) 227 { 228 jzfile *zip; 229 if (((zip = calloc(1, sizeof(jzfile))) != NULL) && 230 ((zip->name = strdup(name)) != NULL) && 231 ((zip->lock = MCREATE()) != NULL)) { 232 zip->zfd = -1; 233 return zip; 234 } 235 236 if (zip != NULL) { 237 free(zip->name); 238 free(zip); 239 } 240 return NULL; 241 } 242 243 /* 244 * Frees all native resources owned by the specified zip file object. 245 */ 246 static void 247 freeZip(jzfile *zip) 248 { 249 /* First free any cached jzentry */ 250 ZIP_FreeEntry(zip,0); 251 if (zip->lock != NULL) MDESTROY(zip->lock); 252 free(zip->name); 253 freeCEN(zip); 254 #ifdef USE_MMAP 255 if (zip->maddr != NULL) munmap((char *)zip->maddr, zip->mlen); 256 #else 257 free(zip->cencache.data); 258 #endif 259 if (zip->zfd != -1) ZFILE_Close(zip->zfd); 260 free(zip); 261 } 262 263 /* The END header is followed by a variable length comment of size < 64k. */ 264 static const jlong END_MAXLEN = 0xFFFF + ENDHDR; 265 266 #define READBLOCKSZ 128 267 268 /* 269 * Searches for end of central directory (END) header. The contents of 270 * the END header will be read and placed in endbuf. Returns the file 271 * position of the END header, otherwise returns -1 if the END header 272 * was not found or an error occurred. 273 */ 274 static jlong 275 findEND(jzfile *zip, void *endbuf) 276 { 277 char buf[READBLOCKSZ]; 278 jlong pos; 279 const jlong len = zip->len; 280 const ZFILE zfd = zip->zfd; 281 const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0; 282 const jlong minPos = minHDR - (sizeof(buf)-ENDHDR); 283 284 for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) { 285 286 int i; 287 jlong off = 0; 288 if (pos < 0) { 289 /* Pretend there are some NUL bytes before start of file */ 290 off = -pos; 291 memset(buf, '\0', off); 292 } 293 294 if (readFullyAt(zfd, buf + off, sizeof(buf) - off, 295 pos + off) == -1) { 296 return -1; /* System error */ 297 } 298 299 /* Now scan the block backwards for END header signature */ 300 for (i = sizeof(buf) - ENDHDR; i >= 0; i--) { 301 if (buf[i+0] == 'P' && 302 buf[i+1] == 'K' && 303 buf[i+2] == '\005' && 304 buf[i+3] == '\006' && 305 (pos + i + ENDHDR + ENDCOM(buf + i) == len)) { 306 /* Found END header */ 307 memcpy(endbuf, buf + i, ENDHDR); 308 return pos + i; 309 } 310 } 311 } 312 return -1; /* END header not found */ 313 } 314 315 /* 316 * Returns a hash code value for a C-style NUL-terminated string. 317 */ 318 static unsigned int 319 hash(const char *s) 320 { 321 int h = 0; 322 while (*s != '\0') 323 h = 31*h + *s++; 324 return h; 325 } 326 327 /* 328 * Returns a hash code value for a string of a specified length. 329 */ 330 static unsigned int 331 hashN(const char *s, int length) 332 { 333 int h = 0; 334 while (length-- > 0) 335 h = 31*h + *s++; 336 return h; 337 } 338 339 static unsigned int 340 hash_append(unsigned int hash, char c) 341 { 342 return ((int)hash)*31 + c; 343 } 344 345 /* 346 * Returns true if the specified entry's name begins with the string 347 * "META-INF/" irrespective of case. 348 */ 349 static int 350 isMetaName(const char *name, int length) 351 { 352 const char *s; 353 if (length < sizeof("META-INF/") - 1) 354 return 0; 355 for (s = "META-INF/"; *s != '\0'; s++) { 356 char c = *name++; 357 // Avoid toupper; it's locale-dependent 358 if (c >= 'a' && c <= 'z') c += 'A' - 'a'; 359 if (*s != c) 360 return 0; 361 } 362 return 1; 363 } 364 365 /* 366 * Increases the capacity of zip->metanames. 367 * Returns non-zero in case of allocation error. 368 */ 369 static int 370 growMetaNames(jzfile *zip) 371 { 372 jint i; 373 /* double the meta names array */ 374 const jint new_metacount = zip->metacount << 1; 375 zip->metanames = 376 realloc(zip->metanames, new_metacount * sizeof(zip->metanames[0])); 377 if (zip->metanames == NULL) return -1; 378 for (i = zip->metacount; i < new_metacount; i++) 379 zip->metanames[i] = NULL; 380 zip->metacurrent = zip->metacount; 381 zip->metacount = new_metacount; 382 return 0; 383 } 384 385 /* 386 * Adds name to zip->metanames. 387 * Returns non-zero in case of allocation error. 388 */ 389 static int 390 addMetaName(jzfile *zip, const char *name, int length) 391 { 392 jint i; 393 if (zip->metanames == NULL) { 394 zip->metacount = INITIAL_META_COUNT; 395 zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0])); 396 if (zip->metanames == NULL) return -1; 397 zip->metacurrent = 0; 398 } 399 400 i = zip->metacurrent; 401 402 /* current meta name array isn't full yet. */ 403 if (i < zip->metacount) { 404 zip->metanames[i] = (char *) malloc(length+1); 405 if (zip->metanames[i] == NULL) return -1; 406 memcpy(zip->metanames[i], name, length); 407 zip->metanames[i][length] = '\0'; 408 zip->metacurrent++; 409 return 0; 410 } 411 412 /* No free entries in zip->metanames? */ 413 if (growMetaNames(zip) != 0) return -1; 414 return addMetaName(zip, name, length); 415 } 416 417 static void 418 freeMetaNames(jzfile *zip) 419 { 420 if (zip->metanames) { 421 jint i; 422 for (i = 0; i < zip->metacount; i++) 423 free(zip->metanames[i]); 424 free(zip->metanames); 425 zip->metanames = NULL; 426 } 427 } 428 429 /* Free Zip data allocated by readCEN() */ 430 static void 431 freeCEN(jzfile *zip) 432 { 433 free(zip->entries); zip->entries = NULL; 434 free(zip->table); zip->table = NULL; 435 freeMetaNames(zip); 436 } 437 438 /* 439 * Counts the number of CEN headers in a central directory extending 440 * from BEG to END. Might return a bogus answer if the zip file is 441 * corrupt, but will not crash. 442 */ 443 static jint 444 countCENHeaders(unsigned char *beg, unsigned char *end) 445 { 446 jint count = 0; 447 ptrdiff_t i; 448 for (i = 0; i + CENHDR < end - beg; i += CENSIZE(beg + i)) 449 count++; 450 return count; 451 } 452 453 #define ZIP_FORMAT_ERROR(message) \ 454 if (1) { zip->msg = message; goto Catch; } else ((void)0) 455 456 /* 457 * Reads zip file central directory. Returns the file position of first 458 * CEN header, otherwise returns -1 if an error occured. If zip->msg != NULL 459 * then the error was a zip format error and zip->msg has the error text. 460 * Always pass in -1 for knownTotal; it's used for a recursive call. 461 */ 462 static jlong 463 readCEN(jzfile *zip, jint knownTotal) 464 { 465 /* Following are unsigned 32-bit */ 466 jlong endpos, cenpos, cenlen; 467 /* Following are unsigned 16-bit */ 468 jint total, tablelen, i, j; 469 unsigned char *cenbuf = NULL; 470 unsigned char *cenend; 471 unsigned char *cp; 472 #ifdef USE_MMAP 473 static jlong pagesize; 474 jlong offset; 475 #endif 476 unsigned char endbuf[ENDHDR]; 477 jzcell *entries; 478 jint *table; 479 480 /* Clear previous zip error */ 481 zip->msg = NULL; 482 483 /* Get position of END header */ 484 if ((endpos = findEND(zip, endbuf)) == -1) 485 return -1; /* no END header or system error */ 486 487 if (endpos == 0) return 0; /* only END header present */ 488 489 freeCEN(zip); 490 491 /* Get position and length of central directory */ 492 cenlen = ENDSIZ(endbuf); 493 if (cenlen > endpos) 494 ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); 495 cenpos = endpos - cenlen; 496 497 /* Get position of first local file (LOC) header, taking into 498 * account that there may be a stub prefixed to the zip file. */ 499 zip->locpos = cenpos - ENDOFF(endbuf); 500 if (zip->locpos < 0) 501 ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); 502 503 #ifdef USE_MMAP 504 /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to 505 * read the jar file contents. However, this greatly increased the perceived 506 * footprint numbers because the mmap'ed pages were adding into the totals shown 507 * by 'ps' and 'top'. We switched to mmaping only the central directory of jar 508 * file while calling 'read' to read the rest of jar file. Here are a list of 509 * reasons apart from above of why we are doing so: 510 * 1. Greatly reduces mmap overhead after startup complete; 511 * 2. Avoids dual path code maintainance; 512 * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. 513 */ 514 if (pagesize == 0) { 515 pagesize = (jlong)sysconf(_SC_PAGESIZE); 516 if (pagesize == 0) goto Catch; 517 } 518 if (cenpos > pagesize) { 519 offset = cenpos & ~(pagesize - 1); 520 } else { 521 offset = 0; 522 } 523 /* When we are not calling recursively, knownTotal is -1. */ 524 if (knownTotal == -1) { 525 void* mappedAddr; 526 /* Mmap the CEN and END part only. We have to figure 527 out the page size in order to make offset to be multiples of 528 page size. 529 */ 530 zip->mlen = cenpos - offset + cenlen + ENDHDR; 531 zip->offset = offset; 532 mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); 533 zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : 534 (unsigned char*)mappedAddr; 535 536 if (zip->maddr == NULL) { 537 jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); 538 goto Catch; 539 } 540 } 541 cenbuf = zip->maddr + cenpos - offset; 542 #else 543 if ((cenbuf = malloc((size_t) cenlen)) == NULL || 544 (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) 545 goto Catch; 546 #endif 547 cenend = cenbuf + cenlen; 548 549 /* Initialize zip file data structures based on the total number 550 * of central directory entries as stored in ENDTOT. Since this 551 * is a 2-byte field, but we (and other zip implementations) 552 * support approx. 2**31 entries, we do not trust ENDTOT, but 553 * treat it only as a strong hint. When we call ourselves 554 * recursively, knownTotal will have the "true" value. */ 555 total = (knownTotal != -1) ? knownTotal : ENDTOT(endbuf); 556 entries = zip->entries = calloc(total, sizeof(entries[0])); 557 tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions 558 table = zip->table = malloc(tablelen * sizeof(table[0])); 559 if (entries == NULL || table == NULL) goto Catch; 560 for (j = 0; j < tablelen; j++) 561 table[j] = ZIP_ENDCHAIN; 562 563 /* Iterate through the entries in the central directory */ 564 for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) { 565 /* Following are unsigned 16-bit */ 566 jint method, nlen; 567 unsigned int hsh; 568 569 if (i >= total) { 570 /* This will only happen if the zip file has an incorrect 571 * ENDTOT field, which usually means it contains more than 572 * 65535 entries. */ 573 cenpos = readCEN(zip, countCENHeaders(cenbuf, cenend)); 574 goto Finally; 575 } 576 577 method = CENHOW(cp); 578 nlen = CENNAM(cp); 579 580 if (GETSIG(cp) != CENSIG) 581 ZIP_FORMAT_ERROR("invalid CEN header (bad signature)"); 582 if (CENFLG(cp) & 1) 583 ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)"); 584 if (method != STORED && method != DEFLATED) 585 ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)"); 586 if (cp + CENHDR + nlen > cenend) 587 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 588 589 /* if the entry is metadata add it to our metadata names */ 590 if (isMetaName((char *)cp+CENHDR, nlen)) 591 if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0) 592 goto Catch; 593 594 /* Record the CEN offset and the name hash in our hash cell. */ 595 entries[i].cenpos = cenpos + (cp - cenbuf); 596 entries[i].hash = hashN((char *)cp+CENHDR, nlen); 597 598 /* Add the entry to the hash table */ 599 hsh = entries[i].hash % tablelen; 600 entries[i].next = table[hsh]; 601 table[hsh] = i; 602 } 603 if (cp != cenend) 604 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 605 606 zip->total = i; 607 608 goto Finally; 609 610 Catch: 611 freeCEN(zip); 612 cenpos = -1; 613 614 Finally: 615 #ifndef USE_MMAP 616 free(cenbuf); 617 #endif 618 return cenpos; 619 } 620 621 /* 622 * Opens a zip file with the specified mode. Returns the jzfile object 623 * or NULL if an error occurred. If a zip error occurred then *pmsg will 624 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be 625 * set to NULL. 626 */ 627 jzfile * 628 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) 629 { 630 jzfile *zip = NULL; 631 632 /* Clear zip error message */ 633 if (pmsg != 0) { 634 *pmsg = NULL; 635 } 636 637 zip = ZIP_Get_From_Cache(name, pmsg, lastModified); 638 639 if (zip == NULL && *pmsg == NULL) { 640 ZFILE zfd = ZFILE_Open(name, mode); 641 zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified); 642 } 643 return zip; 644 } 645 646 /* 647 * Returns the jzfile corresponding to the given file name from the cache of 648 * zip files, or NULL if the file is not in the cache. If the name is longer 649 * than PATH_MAX or a zip error occurred then *pmsg will be set to the error 650 * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. 651 */ 652 jzfile * 653 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified) 654 { 655 static char errbuf[256]; 656 char buf[PATH_MAX]; 657 jzfile *zip; 658 659 if (InitializeZip()) { 660 return NULL; 661 } 662 663 /* Clear zip error message */ 664 if (pmsg != 0) { 665 *pmsg = NULL; 666 } 667 668 if (strlen(name) >= PATH_MAX) { 669 if (pmsg) { 670 *pmsg = "zip file name too long"; 671 } 672 return NULL; 673 } 674 strcpy(buf, name); 675 JVM_NativePath(buf); 676 name = buf; 677 678 MLOCK(zfiles_lock); 679 for (zip = zfiles; zip != NULL; zip = zip->next) { 680 if (strcmp(name, zip->name) == 0 681 && (zip->lastModified == lastModified || zip->lastModified == 0) 682 && zip->refs < MAXREFS) { 683 zip->refs++; 684 break; 685 } 686 } 687 MUNLOCK(zfiles_lock); 688 return zip; 689 } 690 691 /* 692 * Reads data from the given file descriptor to create a jzfile, puts the 693 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error. 694 * If a zip error occurs, then *pmsg will be set to the error message text if 695 * pmsg != 0. Otherwise, *pmsg will be set to NULL. 696 */ 697 jzfile * 698 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) 699 { 700 static char errbuf[256]; 701 jlong len; 702 jzfile *zip; 703 704 if ((zip = allocZip(name)) == NULL) { 705 return NULL; 706 } 707 708 zip->refs = 1; 709 zip->lastModified = lastModified; 710 711 if (zfd == -1) { 712 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 713 *pmsg = errbuf; 714 freeZip(zip); 715 return NULL; 716 } 717 718 len = zip->len = IO_Lseek(zfd, 0, SEEK_END); 719 if (len <= 0) { 720 if (len == 0) { /* zip file is empty */ 721 if (pmsg) { 722 *pmsg = "zip file is empty"; 723 } 724 } else { /* error */ 725 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 726 *pmsg = errbuf; 727 } 728 ZFILE_Close(zfd); 729 freeZip(zip); 730 return NULL; 731 } 732 733 zip->zfd = zfd; 734 if (readCEN(zip, -1) < 0) { 735 /* An error occurred while trying to read the zip file */ 736 if (pmsg != 0) { 737 /* Set the zip error message */ 738 *pmsg = zip->msg; 739 } 740 freeZip(zip); 741 return NULL; 742 } 743 MLOCK(zfiles_lock); 744 zip->next = zfiles; 745 zfiles = zip; 746 MUNLOCK(zfiles_lock); 747 748 return zip; 749 } 750 751 /* 752 * Opens a zip file for reading. Returns the jzfile object or NULL 753 * if an error occurred. If a zip error occurred then *msg will be 754 * set to the error message text if msg != 0. Otherwise, *msg will be 755 * set to NULL. 756 */ 757 jzfile * JNICALL 758 ZIP_Open(const char *name, char **pmsg) 759 { 760 return ZIP_Open_Generic(name, pmsg, O_RDONLY, 0); 761 } 762 763 /* 764 * Closes the specified zip file object. 765 */ 766 void JNICALL 767 ZIP_Close(jzfile *zip) 768 { 769 MLOCK(zfiles_lock); 770 if (--zip->refs > 0) { 771 /* Still more references so just return */ 772 MUNLOCK(zfiles_lock); 773 return; 774 } 775 /* No other references so close the file and remove from list */ 776 if (zfiles == zip) { 777 zfiles = zfiles->next; 778 } else { 779 jzfile *zp; 780 for (zp = zfiles; zp->next != 0; zp = zp->next) { 781 if (zp->next == zip) { 782 zp->next = zip->next; 783 break; 784 } 785 } 786 } 787 MUNLOCK(zfiles_lock); 788 freeZip(zip); 789 return; 790 } 791 792 #ifndef USE_MMAP 793 794 /* Empirically, most CEN headers are smaller than this. */ 795 #define AMPLE_CEN_HEADER_SIZE 160 796 797 /* A good buffer size when we want to read CEN headers sequentially. */ 798 #define CENCACHE_PAGESIZE 8192 799 800 static char * 801 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) 802 { 803 jint censize; 804 ZFILE zfd = zip->zfd; 805 char *cen; 806 if (bufsize > zip->len - cenpos) 807 bufsize = zip->len - cenpos; 808 if ((cen = malloc(bufsize)) == NULL) goto Catch; 809 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch; 810 censize = CENSIZE(cen); 811 if (censize <= bufsize) return cen; 812 if ((cen = realloc(cen, censize)) == NULL) goto Catch; 813 if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch; 814 return cen; 815 816 Catch: 817 free(cen); 818 return NULL; 819 } 820 821 static char * 822 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos) 823 { 824 cencache *cache = &zip->cencache; 825 char *cen; 826 if (cache->data != NULL 827 && (cenpos >= cache->pos) 828 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE)) 829 { 830 cen = cache->data + cenpos - cache->pos; 831 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE) 832 /* A cache hit */ 833 return cen; 834 } 835 836 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL) 837 return NULL; 838 free(cache->data); 839 cache->data = cen; 840 cache->pos = cenpos; 841 return cen; 842 } 843 #endif /* not USE_MMAP */ 844 845 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; 846 847 /* 848 * Return a new initialized jzentry corresponding to a given hash cell. 849 * In case of error, returns NULL. 850 * We already sanity-checked all the CEN headers for ZIP format errors 851 * in readCEN(), so we don't check them again here. 852 * The ZIP lock should be held here. 853 */ 854 static jzentry * 855 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) 856 { 857 jint nlen, elen, clen; 858 jzentry *ze; 859 char *cen; 860 861 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL; 862 ze->name = NULL; 863 ze->extra = NULL; 864 ze->comment = NULL; 865 866 #ifdef USE_MMAP 867 cen = (char*) zip->maddr + zc->cenpos - zip->offset; 868 #else 869 if (accessHint == ACCESS_RANDOM) 870 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); 871 else 872 cen = sequentialAccessReadCENHeader(zip, zc->cenpos); 873 if (cen == NULL) goto Catch; 874 #endif 875 876 nlen = CENNAM(cen); 877 elen = CENEXT(cen); 878 clen = CENCOM(cen); 879 ze->time = CENTIM(cen); 880 ze->size = CENLEN(cen); 881 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); 882 ze->crc = CENCRC(cen); 883 ze->pos = -(zip->locpos + CENOFF(cen)); 884 885 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; 886 memcpy(ze->name, cen + CENHDR, nlen); 887 ze->name[nlen] = '\0'; 888 889 if (elen > 0) { 890 /* This entry has "extra" data */ 891 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; 892 ze->extra[0] = (unsigned char) elen; 893 ze->extra[1] = (unsigned char) (elen >> 8); 894 memcpy(ze->extra+2, cen + CENHDR + nlen, elen); 895 } 896 897 if (clen > 0) { 898 /* This entry has a comment */ 899 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; 900 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen); 901 ze->comment[clen] = '\0'; 902 } 903 goto Finally; 904 905 Catch: 906 free(ze->name); 907 free(ze->extra); 908 free(ze->comment); 909 free(ze); 910 ze = NULL; 911 912 Finally: 913 #ifndef USE_MMAP 914 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); 915 #endif 916 return ze; 917 } 918 919 /* 920 * Free the given jzentry. 921 * In fact we maintain a one-entry cache of the most recently used 922 * jzentry for each zip. This optimizes a common access pattern. 923 */ 924 925 void 926 ZIP_FreeEntry(jzfile *jz, jzentry *ze) 927 { 928 jzentry *last; 929 ZIP_Lock(jz); 930 last = jz->cache; 931 jz->cache = ze; 932 ZIP_Unlock(jz); 933 if (last != NULL) { 934 /* Free the previously cached jzentry */ 935 free(last->name); 936 if (last->extra) free(last->extra); 937 if (last->comment) free(last->comment); 938 free(last); 939 } 940 } 941 942 /* 943 * Returns the zip entry corresponding to the specified name, or 944 * NULL if not found. 945 */ 946 jzentry * 947 ZIP_GetEntry(jzfile *zip, char *name, jint ulen) 948 { 949 unsigned int hsh = hash(name); 950 jint idx; 951 jzentry *ze = 0; 952 953 ZIP_Lock(zip); 954 if (zip->total == 0) { 955 goto Finally; 956 } 957 958 idx = zip->table[hsh % zip->tablelen]; 959 960 /* 961 * This while loop is an optimization where a double lookup 962 * for name and name+/ is being performed. The name char 963 * array has enough room at the end to try again with a 964 * slash appended if the first table lookup does not succeed. 965 */ 966 while(1) { 967 968 /* Check the cached entry first */ 969 ze = zip->cache; 970 if (ze && strcmp(ze->name,name) == 0) { 971 /* Cache hit! Remove and return the cached entry. */ 972 zip->cache = 0; 973 ZIP_Unlock(zip); 974 return ze; 975 } 976 ze = 0; 977 978 /* 979 * Search down the target hash chain for a cell whose 980 * 32 bit hash matches the hashed name. 981 */ 982 while (idx != ZIP_ENDCHAIN) { 983 jzcell *zc = &zip->entries[idx]; 984 985 if (zc->hash == hsh) { 986 /* 987 * OK, we've found a ZIP entry whose 32 bit hashcode 988 * matches the name we're looking for. Try to read 989 * its entry information from the CEN. If the CEN 990 * name matches the name we're looking for, we're 991 * done. 992 * If the names don't match (which should be very rare) 993 * we keep searching. 994 */ 995 ze = newEntry(zip, zc, ACCESS_RANDOM); 996 if (ze && strcmp(ze->name, name)==0) { 997 break; 998 } 999 if (ze != 0) { 1000 /* We need to release the lock across the free call */ 1001 ZIP_Unlock(zip); 1002 ZIP_FreeEntry(zip, ze); 1003 ZIP_Lock(zip); 1004 } 1005 ze = 0; 1006 } 1007 idx = zc->next; 1008 } 1009 1010 /* Entry found, return it */ 1011 if (ze != 0) { 1012 break; 1013 } 1014 1015 /* If no real length was passed in, we are done */ 1016 if (ulen == 0) { 1017 break; 1018 } 1019 1020 /* Slash is already there? */ 1021 if (name[ulen-1] == '/') { 1022 break; 1023 } 1024 1025 /* Add slash and try once more */ 1026 name[ulen] = '/'; 1027 name[ulen+1] = '\0'; 1028 hsh = hash_append(hsh, '/'); 1029 idx = zip->table[hsh % zip->tablelen]; 1030 ulen = 0; 1031 } 1032 1033 Finally: 1034 ZIP_Unlock(zip); 1035 return ze; 1036 } 1037 1038 /* 1039 * Returns the n'th (starting at zero) zip file entry, or NULL if the 1040 * specified index was out of range. 1041 */ 1042 jzentry * JNICALL 1043 ZIP_GetNextEntry(jzfile *zip, jint n) 1044 { 1045 jzentry *result; 1046 if (n < 0 || n >= zip->total) { 1047 return 0; 1048 } 1049 ZIP_Lock(zip); 1050 result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL); 1051 ZIP_Unlock(zip); 1052 return result; 1053 } 1054 1055 /* 1056 * Locks the specified zip file for reading. 1057 */ 1058 void 1059 ZIP_Lock(jzfile *zip) 1060 { 1061 MLOCK(zip->lock); 1062 } 1063 1064 /* 1065 * Unlocks the specified zip file. 1066 */ 1067 void 1068 ZIP_Unlock(jzfile *zip) 1069 { 1070 MUNLOCK(zip->lock); 1071 } 1072 1073 /* 1074 * Returns the offset of the entry data within the zip file. 1075 * Returns -1 if an error occurred, in which case zip->msg will 1076 * contain the error text. 1077 */ 1078 jlong 1079 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry) 1080 { 1081 /* The Zip file spec explicitly allows the LOC extra data size to 1082 * be different from the CEN extra data size, although the JDK 1083 * never creates such zip files. Since we cannot trust the CEN 1084 * extra data size, we need to read the LOC to determine the entry 1085 * data offset. We do this lazily to avoid touching the virtual 1086 * memory page containing the LOC when initializing jzentry 1087 * objects. (This speeds up javac by a factor of 10 when the JDK 1088 * is installed on a very slow filesystem.) 1089 */ 1090 if (entry->pos <= 0) { 1091 unsigned char loc[LOCHDR]; 1092 if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) { 1093 zip->msg = "error reading zip file"; 1094 return -1; 1095 } 1096 if (GETSIG(loc) != LOCSIG) { 1097 zip->msg = "invalid LOC header (bad signature)"; 1098 return -1; 1099 } 1100 entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc); 1101 } 1102 return entry->pos; 1103 } 1104 1105 /* 1106 * Reads bytes from the specified zip entry. Assumes that the zip 1107 * file had been previously locked with ZIP_Lock(). Returns the 1108 * number of bytes read, or -1 if an error occurred. If zip->msg != 0 1109 * then a zip error occurred and zip->msg contains the error text. 1110 */ 1111 jint 1112 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len) 1113 { 1114 jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size; 1115 jlong start; 1116 1117 /* Clear previous zip error */ 1118 zip->msg = NULL; 1119 1120 /* Check specified position */ 1121 if (pos < 0 || pos > entry_size - 1) { 1122 zip->msg = "ZIP_Read: specified offset out of range"; 1123 return -1; 1124 } 1125 1126 /* Check specified length */ 1127 if (len <= 0) 1128 return 0; 1129 if (len > entry_size - pos) 1130 len = entry_size - pos; 1131 1132 /* Get file offset to start reading data */ 1133 start = ZIP_GetEntryDataOffset(zip, entry); 1134 if (start < 0) 1135 return -1; 1136 start += pos; 1137 1138 if (start + len > zip->len) { 1139 zip->msg = "ZIP_Read: corrupt zip file: invalid entry size"; 1140 return -1; 1141 } 1142 1143 if (readFullyAt(zip->zfd, buf, len, start) == -1) { 1144 zip->msg = "ZIP_Read: error reading zip file"; 1145 return -1; 1146 } 1147 return len; 1148 } 1149 1150 1151 /* The maximum size of a stack-allocated buffer. 1152 */ 1153 #define BUF_SIZE 4096 1154 1155 /* 1156 * This function is used by the runtime system to load compressed entries 1157 * from ZIP/JAR files specified in the class path. It is defined here 1158 * so that it can be dynamically loaded by the runtime if the zip library 1159 * is found. 1160 */ 1161 jboolean 1162 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) 1163 { 1164 z_stream strm; 1165 char tmp[BUF_SIZE]; 1166 jlong pos = 0; 1167 jlong count = entry->csize; 1168 jboolean status; 1169 1170 *msg = 0; /* Reset error message */ 1171 1172 if (count == 0) { 1173 *msg = "inflateFully: entry not compressed"; 1174 return JNI_FALSE; 1175 } 1176 1177 memset(&strm, 0, sizeof(z_stream)); 1178 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) { 1179 *msg = strm.msg; 1180 return JNI_FALSE; 1181 } 1182 1183 strm.next_out = buf; 1184 strm.avail_out = entry->size; 1185 1186 while (count > 0) { 1187 jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : count; 1188 ZIP_Lock(zip); 1189 n = ZIP_Read(zip, entry, pos, tmp, n); 1190 ZIP_Unlock(zip); 1191 if (n <= 0) { 1192 if (n == 0) { 1193 *msg = "inflateFully: Unexpected end of file"; 1194 } 1195 inflateEnd(&strm); 1196 return JNI_FALSE; 1197 } 1198 pos += n; 1199 count -= n; 1200 strm.next_in = (Bytef *)tmp; 1201 strm.avail_in = n; 1202 do { 1203 switch (inflate(&strm, Z_PARTIAL_FLUSH)) { 1204 case Z_OK: 1205 break; 1206 case Z_STREAM_END: 1207 if (count != 0 || strm.total_out != entry->size) { 1208 *msg = "inflateFully: Unexpected end of stream"; 1209 inflateEnd(&strm); 1210 return JNI_FALSE; 1211 } 1212 break; 1213 default: 1214 break; 1215 } 1216 } while (strm.avail_in > 0); 1217 } 1218 inflateEnd(&strm); 1219 return JNI_TRUE; 1220 } 1221 1222 jzentry * JNICALL 1223 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP) 1224 { 1225 jzentry *entry = ZIP_GetEntry(zip, name, 0); 1226 if (entry) { 1227 *sizeP = entry->size; 1228 *nameLenP = strlen(entry->name); 1229 } 1230 return entry; 1231 } 1232 1233 /* 1234 * Reads a zip file entry into the specified byte array 1235 * When the method completes, it releases the jzentry. 1236 * Note: this is called from the separately delivered VM (hotspot/classic) 1237 * so we have to be careful to maintain the expected behaviour. 1238 */ 1239 jboolean JNICALL 1240 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname) 1241 { 1242 char *msg; 1243 1244 strcpy(entryname, entry->name); 1245 if (entry->csize == 0) { 1246 /* Entry is stored */ 1247 jlong pos = 0; 1248 jlong size = entry->size; 1249 while (pos < size) { 1250 jint n; 1251 jlong limit = ((((jlong) 1) << 31) - 1); 1252 jint count = (size - pos < limit) ? 1253 /* These casts suppress a VC++ Internal Compiler Error */ 1254 (jint) (size - pos) : 1255 (jint) limit; 1256 ZIP_Lock(zip); 1257 n = ZIP_Read(zip, entry, pos, buf, count); 1258 msg = zip->msg; 1259 ZIP_Unlock(zip); 1260 if (n == -1) { 1261 jio_fprintf(stderr, "%s: %s\n", zip->name, 1262 msg != 0 ? msg : strerror(errno)); 1263 return JNI_FALSE; 1264 } 1265 buf += n; 1266 pos += n; 1267 } 1268 } else { 1269 /* Entry is compressed */ 1270 int ok = InflateFully(zip, entry, buf, &msg); 1271 if (!ok) { 1272 if ((msg == NULL) || (*msg == 0)) { 1273 msg = zip->msg; 1274 } 1275 jio_fprintf(stderr, "%s: %s\n", zip->name, 1276 msg != 0 ? msg : strerror(errno)); 1277 return JNI_FALSE; 1278 } 1279 } 1280 1281 ZIP_FreeEntry(zip, entry); 1282 1283 return JNI_TRUE; 1284 }