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->comment != NULL) 260 free(zip->comment); 261 if (zip->zfd != -1) ZFILE_Close(zip->zfd); 262 free(zip); 263 } 264 265 /* The END header is followed by a variable length comment of size < 64k. */ 266 static const jlong END_MAXLEN = 0xFFFF + ENDHDR; 267 268 #define READBLOCKSZ 128 269 270 static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) { 271 /* ENDSIG matched, however the size of file comment in it does not 272 match the real size. One "common" cause for this problem is some 273 "extra" bytes are padded at the end of the zipfile. 274 Let's do some extra verification, we don't care about the performance 275 in this situation. 276 */ 277 jlong cenpos = endpos - ENDSIZ(endbuf); 278 jlong locpos = cenpos - ENDOFF(endbuf); 568 if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { 569 cenlen = ZIP64_ENDSIZ(end64buf); 570 cenoff = ZIP64_ENDOFF(end64buf); 571 total = (jint)ZIP64_ENDTOT(end64buf); 572 endpos = end64pos; 573 endhdrlen = ZIP64_ENDHDR; 574 } 575 } 576 577 if (cenlen > endpos) 578 ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); 579 cenpos = endpos - cenlen; 580 581 /* Get position of first local file (LOC) header, taking into 582 * account that there may be a stub prefixed to the zip file. */ 583 zip->locpos = cenpos - cenoff; 584 if (zip->locpos < 0) 585 ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); 586 587 #ifdef USE_MMAP 588 /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to 589 * read the jar file contents. However, this greatly increased the perceived 590 * footprint numbers because the mmap'ed pages were adding into the totals shown 591 * by 'ps' and 'top'. We switched to mmaping only the central directory of jar 592 * file while calling 'read' to read the rest of jar file. Here are a list of 593 * reasons apart from above of why we are doing so: 594 * 1. Greatly reduces mmap overhead after startup complete; 595 * 2. Avoids dual path code maintainance; 596 * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. 597 */ 598 if (pagesize == 0) { 599 pagesize = (jlong)sysconf(_SC_PAGESIZE); 600 if (pagesize == 0) goto Catch; 601 } 602 if (cenpos > pagesize) { 603 offset = cenpos & ~(pagesize - 1); 604 } else { 605 offset = 0; 606 } 607 /* When we are not calling recursively, knownTotal is -1. */ 608 if (knownTotal == -1) { 609 void* mappedAddr; 610 /* Mmap the CEN and END part only. We have to figure 611 out the page size in order to make offset to be multiples of 612 page size. 613 */ 614 zip->mlen = cenpos - offset + cenlen + endhdrlen; 615 zip->offset = offset; 616 mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); 617 zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : 618 (unsigned char*)mappedAddr; 619 620 if (zip->maddr == NULL) { 621 jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); 622 goto Catch; 623 } 624 } 625 cenbuf = zip->maddr + cenpos - offset; 626 #else 627 if ((cenbuf = malloc((size_t) cenlen)) == NULL || 628 (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) 629 goto Catch; 630 #endif 631 cenend = cenbuf + cenlen; 632 633 /* Initialize zip file data structures based on the total number 634 * of central directory entries as stored in ENDTOT. Since this 635 * is a 2-byte field, but we (and other zip implementations) 636 * support approx. 2**31 entries, we do not trust ENDTOT, but 637 * treat it only as a strong hint. When we call ourselves 638 * recursively, knownTotal will have the "true" value. 639 * 640 * Keep this path alive even with the Zip64 END support added, just 641 * for zip files that have more than 0xffff entries but don't have 642 * the Zip64 enabled. 643 */ 644 total = (knownTotal != -1) ? knownTotal : total; 645 entries = zip->entries = calloc(total, sizeof(entries[0])); 646 tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions 647 table = zip->table = malloc(tablelen * sizeof(table[0])); 648 if (entries == NULL || table == NULL) goto Catch; 649 for (j = 0; j < tablelen; j++) 650 table[j] = ZIP_ENDCHAIN; 683 /* Record the CEN offset and the name hash in our hash cell. */ 684 entries[i].cenpos = cenpos + (cp - cenbuf); 685 entries[i].hash = hashN((char *)cp+CENHDR, nlen); 686 687 /* Add the entry to the hash table */ 688 hsh = entries[i].hash % tablelen; 689 entries[i].next = table[hsh]; 690 table[hsh] = i; 691 } 692 if (cp != cenend) 693 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 694 695 zip->total = i; 696 goto Finally; 697 698 Catch: 699 freeCEN(zip); 700 cenpos = -1; 701 702 Finally: 703 #ifndef USE_MMAP 704 free(cenbuf); 705 #endif 706 return cenpos; 707 } 708 709 /* 710 * Opens a zip file with the specified mode. Returns the jzfile object 711 * or NULL if an error occurred. If a zip error occurred then *pmsg will 712 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be 713 * set to NULL. 714 */ 715 jzfile * 716 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) 717 { 718 jzfile *zip = NULL; 719 720 /* Clear zip error message */ 721 if (pmsg != 0) { 722 *pmsg = NULL; 723 } 724 725 zip = ZIP_Get_From_Cache(name, pmsg, lastModified); 765 766 MLOCK(zfiles_lock); 767 for (zip = zfiles; zip != NULL; zip = zip->next) { 768 if (strcmp(name, zip->name) == 0 769 && (zip->lastModified == lastModified || zip->lastModified == 0) 770 && zip->refs < MAXREFS) { 771 zip->refs++; 772 break; 773 } 774 } 775 MUNLOCK(zfiles_lock); 776 return zip; 777 } 778 779 /* 780 * Reads data from the given file descriptor to create a jzfile, puts the 781 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error. 782 * If a zip error occurs, then *pmsg will be set to the error message text if 783 * pmsg != 0. Otherwise, *pmsg will be set to NULL. 784 */ 785 jzfile * 786 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) 787 { 788 static char errbuf[256]; 789 jlong len; 790 jzfile *zip; 791 792 if ((zip = allocZip(name)) == NULL) { 793 return NULL; 794 } 795 796 zip->refs = 1; 797 zip->lastModified = lastModified; 798 799 if (zfd == -1) { 800 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 801 *pmsg = errbuf; 802 freeZip(zip); 803 return NULL; 804 } 805 806 len = zip->len = IO_Lseek(zfd, 0, SEEK_END); 807 if (len <= 0) { 808 if (len == 0) { /* zip file is empty */ 809 if (pmsg) { 810 *pmsg = "zip file is empty"; 811 } 812 } else { /* error */ 813 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 814 *pmsg = errbuf; 815 } 860 MUNLOCK(zfiles_lock); 861 return; 862 } 863 /* No other references so close the file and remove from list */ 864 if (zfiles == zip) { 865 zfiles = zfiles->next; 866 } else { 867 jzfile *zp; 868 for (zp = zfiles; zp->next != 0; zp = zp->next) { 869 if (zp->next == zip) { 870 zp->next = zip->next; 871 break; 872 } 873 } 874 } 875 MUNLOCK(zfiles_lock); 876 freeZip(zip); 877 return; 878 } 879 880 #ifndef USE_MMAP 881 882 /* Empirically, most CEN headers are smaller than this. */ 883 #define AMPLE_CEN_HEADER_SIZE 160 884 885 /* A good buffer size when we want to read CEN headers sequentially. */ 886 #define CENCACHE_PAGESIZE 8192 887 888 static char * 889 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) 890 { 891 jint censize; 892 ZFILE zfd = zip->zfd; 893 char *cen; 894 if (bufsize > zip->len - cenpos) 895 bufsize = zip->len - cenpos; 896 if ((cen = malloc(bufsize)) == NULL) goto Catch; 897 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch; 898 censize = CENSIZE(cen); 899 if (censize <= bufsize) return cen; 900 if ((cen = realloc(cen, censize)) == NULL) goto Catch; 901 if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch; 911 { 912 cencache *cache = &zip->cencache; 913 char *cen; 914 if (cache->data != NULL 915 && (cenpos >= cache->pos) 916 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE)) 917 { 918 cen = cache->data + cenpos - cache->pos; 919 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE) 920 /* A cache hit */ 921 return cen; 922 } 923 924 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL) 925 return NULL; 926 free(cache->data); 927 cache->data = cen; 928 cache->pos = cenpos; 929 return cen; 930 } 931 #endif /* not USE_MMAP */ 932 933 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; 934 935 /* 936 * Return a new initialized jzentry corresponding to a given hash cell. 937 * In case of error, returns NULL. 938 * We already sanity-checked all the CEN headers for ZIP format errors 939 * in readCEN(), so we don't check them again here. 940 * The ZIP lock should be held here. 941 */ 942 static jzentry * 943 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) 944 { 945 jlong locoff; 946 jint nlen, elen, clen; 947 jzentry *ze; 948 char *cen; 949 950 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL; 951 ze->name = NULL; 952 ze->extra = NULL; 953 ze->comment = NULL; 954 955 #ifdef USE_MMAP 956 cen = (char*) zip->maddr + zc->cenpos - zip->offset; 957 #else 958 if (accessHint == ACCESS_RANDOM) 959 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); 960 else 961 cen = sequentialAccessReadCENHeader(zip, zc->cenpos); 962 if (cen == NULL) goto Catch; 963 #endif 964 965 nlen = CENNAM(cen); 966 elen = CENEXT(cen); 967 clen = CENCOM(cen); 968 ze->time = CENTIM(cen); 969 ze->size = CENLEN(cen); 970 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); 971 ze->crc = CENCRC(cen); 972 locoff = CENOFF(cen); 973 ze->pos = -(zip->locpos + locoff); 974 ze->flag = CENFLG(cen); 975 976 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; 977 memcpy(ze->name, cen + CENHDR, nlen); 978 ze->name[nlen] = '\0'; 979 980 if (elen > 0) { 981 char *extra = cen + CENHDR + nlen; 982 983 /* This entry has "extra" data */ 984 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; 985 ze->extra[0] = (unsigned char) elen; 986 ze->extra[1] = (unsigned char) (elen >> 8); 987 memcpy(ze->extra+2, extra, elen); 988 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || 989 locoff == ZIP64_MAGICVAL) { 990 jint off = 0; 991 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data 992 jint sz = SH(extra, off + 2); 993 if (SH(extra, off) == ZIP64_EXTID) { 994 off += 4; 995 if (ze->size == ZIP64_MAGICVAL) { 996 // if invalid zip64 extra fields, just skip 997 if (sz < 8 || (off + 8) > elen) 998 break; 999 ze->size = LL(extra, off); 1020 } 1021 } 1022 } 1023 1024 if (clen > 0) { 1025 /* This entry has a comment */ 1026 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; 1027 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen); 1028 ze->comment[clen] = '\0'; 1029 } 1030 goto Finally; 1031 1032 Catch: 1033 free(ze->name); 1034 free(ze->extra); 1035 free(ze->comment); 1036 free(ze); 1037 ze = NULL; 1038 1039 Finally: 1040 #ifndef USE_MMAP 1041 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); 1042 #endif 1043 return ze; 1044 } 1045 1046 /* 1047 * Free the given jzentry. 1048 * In fact we maintain a one-entry cache of the most recently used 1049 * jzentry for each zip. This optimizes a common access pattern. 1050 */ 1051 1052 void 1053 ZIP_FreeEntry(jzfile *jz, jzentry *ze) 1054 { 1055 jzentry *last; 1056 ZIP_Lock(jz); 1057 last = jz->cache; 1058 jz->cache = ze; 1059 ZIP_Unlock(jz); 1060 if (last != NULL) { 1061 /* Free the previously cached jzentry */ 1062 free(last->name); | 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 255 #ifdef USE_MMAP 256 if (zip->usemmap) { 257 if (zip->maddr != NULL) 258 munmap((char *)zip->maddr, zip->mlen); 259 } else 260 #endif 261 { 262 free(zip->cencache.data); 263 } 264 if (zip->comment != NULL) 265 free(zip->comment); 266 if (zip->zfd != -1) ZFILE_Close(zip->zfd); 267 free(zip); 268 } 269 270 /* The END header is followed by a variable length comment of size < 64k. */ 271 static const jlong END_MAXLEN = 0xFFFF + ENDHDR; 272 273 #define READBLOCKSZ 128 274 275 static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) { 276 /* ENDSIG matched, however the size of file comment in it does not 277 match the real size. One "common" cause for this problem is some 278 "extra" bytes are padded at the end of the zipfile. 279 Let's do some extra verification, we don't care about the performance 280 in this situation. 281 */ 282 jlong cenpos = endpos - ENDSIZ(endbuf); 283 jlong locpos = cenpos - ENDOFF(endbuf); 573 if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { 574 cenlen = ZIP64_ENDSIZ(end64buf); 575 cenoff = ZIP64_ENDOFF(end64buf); 576 total = (jint)ZIP64_ENDTOT(end64buf); 577 endpos = end64pos; 578 endhdrlen = ZIP64_ENDHDR; 579 } 580 } 581 582 if (cenlen > endpos) 583 ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); 584 cenpos = endpos - cenlen; 585 586 /* Get position of first local file (LOC) header, taking into 587 * account that there may be a stub prefixed to the zip file. */ 588 zip->locpos = cenpos - cenoff; 589 if (zip->locpos < 0) 590 ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); 591 592 #ifdef USE_MMAP 593 if (zip->usemmap) { 594 /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to 595 * read the jar file contents. However, this greatly increased the perceived 596 * footprint numbers because the mmap'ed pages were adding into the totals shown 597 * by 'ps' and 'top'. We switched to mmaping only the central directory of jar 598 * file while calling 'read' to read the rest of jar file. Here are a list of 599 * reasons apart from above of why we are doing so: 600 * 1. Greatly reduces mmap overhead after startup complete; 601 * 2. Avoids dual path code maintainance; 602 * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. 603 */ 604 if (pagesize == 0) { 605 pagesize = (jlong)sysconf(_SC_PAGESIZE); 606 if (pagesize == 0) goto Catch; 607 } 608 if (cenpos > pagesize) { 609 offset = cenpos & ~(pagesize - 1); 610 } else { 611 offset = 0; 612 } 613 /* When we are not calling recursively, knownTotal is -1. */ 614 if (knownTotal == -1) { 615 void* mappedAddr; 616 /* Mmap the CEN and END part only. We have to figure 617 out the page size in order to make offset to be multiples of 618 page size. 619 */ 620 zip->mlen = cenpos - offset + cenlen + endhdrlen; 621 zip->offset = offset; 622 mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); 623 zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : 624 (unsigned char*)mappedAddr; 625 626 if (zip->maddr == NULL) { 627 jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); 628 goto Catch; 629 } 630 } 631 cenbuf = zip->maddr + cenpos - offset; 632 } else 633 #endif 634 { 635 if ((cenbuf = malloc((size_t) cenlen)) == NULL || 636 (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) 637 goto Catch; 638 } 639 640 cenend = cenbuf + cenlen; 641 642 /* Initialize zip file data structures based on the total number 643 * of central directory entries as stored in ENDTOT. Since this 644 * is a 2-byte field, but we (and other zip implementations) 645 * support approx. 2**31 entries, we do not trust ENDTOT, but 646 * treat it only as a strong hint. When we call ourselves 647 * recursively, knownTotal will have the "true" value. 648 * 649 * Keep this path alive even with the Zip64 END support added, just 650 * for zip files that have more than 0xffff entries but don't have 651 * the Zip64 enabled. 652 */ 653 total = (knownTotal != -1) ? knownTotal : total; 654 entries = zip->entries = calloc(total, sizeof(entries[0])); 655 tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions 656 table = zip->table = malloc(tablelen * sizeof(table[0])); 657 if (entries == NULL || table == NULL) goto Catch; 658 for (j = 0; j < tablelen; j++) 659 table[j] = ZIP_ENDCHAIN; 692 /* Record the CEN offset and the name hash in our hash cell. */ 693 entries[i].cenpos = cenpos + (cp - cenbuf); 694 entries[i].hash = hashN((char *)cp+CENHDR, nlen); 695 696 /* Add the entry to the hash table */ 697 hsh = entries[i].hash % tablelen; 698 entries[i].next = table[hsh]; 699 table[hsh] = i; 700 } 701 if (cp != cenend) 702 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)"); 703 704 zip->total = i; 705 goto Finally; 706 707 Catch: 708 freeCEN(zip); 709 cenpos = -1; 710 711 Finally: 712 #ifdef USE_MMAP 713 if (!zip->usemmap) 714 #endif 715 free(cenbuf); 716 717 return cenpos; 718 } 719 720 /* 721 * Opens a zip file with the specified mode. Returns the jzfile object 722 * or NULL if an error occurred. If a zip error occurred then *pmsg will 723 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be 724 * set to NULL. 725 */ 726 jzfile * 727 ZIP_Open_Generic(const char *name, char **pmsg, int mode, jlong lastModified) 728 { 729 jzfile *zip = NULL; 730 731 /* Clear zip error message */ 732 if (pmsg != 0) { 733 *pmsg = NULL; 734 } 735 736 zip = ZIP_Get_From_Cache(name, pmsg, lastModified); 776 777 MLOCK(zfiles_lock); 778 for (zip = zfiles; zip != NULL; zip = zip->next) { 779 if (strcmp(name, zip->name) == 0 780 && (zip->lastModified == lastModified || zip->lastModified == 0) 781 && zip->refs < MAXREFS) { 782 zip->refs++; 783 break; 784 } 785 } 786 MUNLOCK(zfiles_lock); 787 return zip; 788 } 789 790 /* 791 * Reads data from the given file descriptor to create a jzfile, puts the 792 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error. 793 * If a zip error occurs, then *pmsg will be set to the error message text if 794 * pmsg != 0. Otherwise, *pmsg will be set to NULL. 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 static 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 && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 823 *pmsg = errbuf; 824 freeZip(zip); 825 return NULL; 826 } 827 828 len = zip->len = IO_Lseek(zfd, 0, SEEK_END); 829 if (len <= 0) { 830 if (len == 0) { /* zip file is empty */ 831 if (pmsg) { 832 *pmsg = "zip file is empty"; 833 } 834 } else { /* error */ 835 if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) 836 *pmsg = errbuf; 837 } 882 MUNLOCK(zfiles_lock); 883 return; 884 } 885 /* No other references so close the file and remove from list */ 886 if (zfiles == zip) { 887 zfiles = zfiles->next; 888 } else { 889 jzfile *zp; 890 for (zp = zfiles; zp->next != 0; zp = zp->next) { 891 if (zp->next == zip) { 892 zp->next = zip->next; 893 break; 894 } 895 } 896 } 897 MUNLOCK(zfiles_lock); 898 freeZip(zip); 899 return; 900 } 901 902 /* Empirically, most CEN headers are smaller than this. */ 903 #define AMPLE_CEN_HEADER_SIZE 160 904 905 /* A good buffer size when we want to read CEN headers sequentially. */ 906 #define CENCACHE_PAGESIZE 8192 907 908 static char * 909 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) 910 { 911 jint censize; 912 ZFILE zfd = zip->zfd; 913 char *cen; 914 if (bufsize > zip->len - cenpos) 915 bufsize = zip->len - cenpos; 916 if ((cen = malloc(bufsize)) == NULL) goto Catch; 917 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch; 918 censize = CENSIZE(cen); 919 if (censize <= bufsize) return cen; 920 if ((cen = realloc(cen, censize)) == NULL) goto Catch; 921 if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch; 931 { 932 cencache *cache = &zip->cencache; 933 char *cen; 934 if (cache->data != NULL 935 && (cenpos >= cache->pos) 936 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE)) 937 { 938 cen = cache->data + cenpos - cache->pos; 939 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE) 940 /* A cache hit */ 941 return cen; 942 } 943 944 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL) 945 return NULL; 946 free(cache->data); 947 cache->data = cen; 948 cache->pos = cenpos; 949 return cen; 950 } 951 952 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; 953 954 /* 955 * Return a new initialized jzentry corresponding to a given hash cell. 956 * In case of error, returns NULL. 957 * We already sanity-checked all the CEN headers for ZIP format errors 958 * in readCEN(), so we don't check them again here. 959 * The ZIP lock should be held here. 960 */ 961 static jzentry * 962 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) 963 { 964 jlong locoff; 965 jint nlen, elen, clen; 966 jzentry *ze; 967 char *cen; 968 969 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL; 970 ze->name = NULL; 971 ze->extra = NULL; 972 ze->comment = NULL; 973 974 #ifdef USE_MMAP 975 if (zip->usemmap) { 976 cen = (char*) zip->maddr + zc->cenpos - zip->offset; 977 } else 978 #endif 979 { 980 if (accessHint == ACCESS_RANDOM) 981 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); 982 else 983 cen = sequentialAccessReadCENHeader(zip, zc->cenpos); 984 if (cen == NULL) goto Catch; 985 } 986 987 nlen = CENNAM(cen); 988 elen = CENEXT(cen); 989 clen = CENCOM(cen); 990 ze->time = CENTIM(cen); 991 ze->size = CENLEN(cen); 992 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); 993 ze->crc = CENCRC(cen); 994 locoff = CENOFF(cen); 995 ze->pos = -(zip->locpos + locoff); 996 ze->flag = CENFLG(cen); 997 998 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; 999 memcpy(ze->name, cen + CENHDR, nlen); 1000 ze->name[nlen] = '\0'; 1001 if (elen > 0) { 1002 char *extra = cen + CENHDR + nlen; 1003 1004 /* This entry has "extra" data */ 1005 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; 1006 ze->extra[0] = (unsigned char) elen; 1007 ze->extra[1] = (unsigned char) (elen >> 8); 1008 memcpy(ze->extra+2, extra, elen); 1009 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || 1010 locoff == ZIP64_MAGICVAL) { 1011 jint off = 0; 1012 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data 1013 jint sz = SH(extra, off + 2); 1014 if (SH(extra, off) == ZIP64_EXTID) { 1015 off += 4; 1016 if (ze->size == ZIP64_MAGICVAL) { 1017 // if invalid zip64 extra fields, just skip 1018 if (sz < 8 || (off + 8) > elen) 1019 break; 1020 ze->size = LL(extra, off); 1041 } 1042 } 1043 } 1044 1045 if (clen > 0) { 1046 /* This entry has a comment */ 1047 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; 1048 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen); 1049 ze->comment[clen] = '\0'; 1050 } 1051 goto Finally; 1052 1053 Catch: 1054 free(ze->name); 1055 free(ze->extra); 1056 free(ze->comment); 1057 free(ze); 1058 ze = NULL; 1059 1060 Finally: 1061 #ifdef USE_MMAP 1062 if (!zip->usemmap) 1063 #endif 1064 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); 1065 return ze; 1066 } 1067 1068 /* 1069 * Free the given jzentry. 1070 * In fact we maintain a one-entry cache of the most recently used 1071 * jzentry for each zip. This optimizes a common access pattern. 1072 */ 1073 1074 void 1075 ZIP_FreeEntry(jzfile *jz, jzentry *ze) 1076 { 1077 jzentry *last; 1078 ZIP_Lock(jz); 1079 last = jz->cache; 1080 jz->cache = ze; 1081 ZIP_Unlock(jz); 1082 if (last != NULL) { 1083 /* Free the previously cached jzentry */ 1084 free(last->name); |