src/share/native/java/util/zip/zip_util.c

Print this page

        

*** 311,320 **** --- 311,352 ---- } return -1; /* END header not found */ } /* + * Searches for the ZIP64 end of central directory (END) header. The + * contents of the ZIP64 END header will be read and placed in end64buf. + * Returns the file position of the ZIP64 END header, otherwise returns + * -1 if the END header was not found or an error occurred. + * + * The ZIP format specifies the "position" of each related record as + * ... + * [central directory] + * [zip64 end of central directory record] + * [zip64 end of central directory locator] + * [end of central directory record] + * + * The offset of zip64 end locator can be calculated from endpos as + * "endpos - ZIP64_LOCHDR". + * The "offset" of zip64 end record is stored in zip64 end locator. + */ + static jlong + findEND64(jzfile *zip, void *end64buf, jlong endpos) + { + char loc64[ZIP64_LOCHDR]; + jlong end64pos; + if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) { + return -1; // end64 locator not found + } + end64pos = ZIP64_LOCOFF(loc64); + if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) { + return -1; // end64 record not found + } + return end64pos; + } + + /* * Returns a hash code value for a C-style NUL-terminated string. */ static unsigned int hash(const char *s) {
*** 461,471 **** */ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ ! jlong endpos, cenpos, cenlen; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; unsigned char *cenend; unsigned char *cp; --- 493,503 ---- */ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ ! jlong endpos, end64pos, cenpos, cenlen, cenoff; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; unsigned char *cenend; unsigned char *cp;
*** 472,481 **** --- 504,514 ---- #ifdef USE_MMAP static jlong pagesize; jlong offset; #endif unsigned char endbuf[ENDHDR]; + jint endhdrlen = ENDHDR; jzcell *entries; jint *table; /* Clear previous zip error */ zip->msg = NULL;
*** 488,504 **** freeCEN(zip); /* Get position and length of central directory */ cenlen = ENDSIZ(endbuf); if (cenlen > endpos) ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); cenpos = endpos - cenlen; /* Get position of first local file (LOC) header, taking into * account that there may be a stub prefixed to the zip file. */ ! zip->locpos = cenpos - ENDOFF(endbuf); if (zip->locpos < 0) ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); #ifdef USE_MMAP /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to --- 521,551 ---- freeCEN(zip); /* Get position and length of central directory */ cenlen = ENDSIZ(endbuf); + cenoff = ENDOFF(endbuf); + total = ENDTOT(endbuf); + if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL || + total == ZIP64_MAGICCOUNT) { + unsigned char end64buf[ZIP64_ENDHDR]; + if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { + cenlen = ZIP64_ENDSIZ(end64buf); + cenoff = ZIP64_ENDOFF(end64buf); + total = (jint)ZIP64_ENDTOT(end64buf); + endpos = end64pos; + endhdrlen = ZIP64_ENDHDR; + } + } + if (cenlen > endpos) ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); cenpos = endpos - cenlen; /* Get position of first local file (LOC) header, taking into * account that there may be a stub prefixed to the zip file. */ ! zip->locpos = cenpos - cenoff; if (zip->locpos < 0) ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); #ifdef USE_MMAP /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
*** 525,535 **** void* mappedAddr; /* Mmap the CEN and END part only. We have to figure out the page size in order to make offset to be multiples of page size. */ ! zip->mlen = cenpos - offset + cenlen + ENDHDR; zip->offset = offset; mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : (unsigned char*)mappedAddr; --- 572,582 ---- void* mappedAddr; /* Mmap the CEN and END part only. We have to figure out the page size in order to make offset to be multiples of page size. */ ! zip->mlen = cenpos - offset + cenlen + endhdrlen; zip->offset = offset; mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : (unsigned char*)mappedAddr;
*** 549,560 **** /* Initialize zip file data structures based on the total number * of central directory entries as stored in ENDTOT. Since this * is a 2-byte field, but we (and other zip implementations) * support approx. 2**31 entries, we do not trust ENDTOT, but * treat it only as a strong hint. When we call ourselves ! * recursively, knownTotal will have the "true" value. */ ! total = (knownTotal != -1) ? knownTotal : ENDTOT(endbuf); entries = zip->entries = calloc(total, sizeof(entries[0])); tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions table = zip->table = malloc(tablelen * sizeof(table[0])); if (entries == NULL || table == NULL) goto Catch; for (j = 0; j < tablelen; j++) --- 596,612 ---- /* Initialize zip file data structures based on the total number * of central directory entries as stored in ENDTOT. Since this * is a 2-byte field, but we (and other zip implementations) * support approx. 2**31 entries, we do not trust ENDTOT, but * treat it only as a strong hint. When we call ourselves ! * recursively, knownTotal will have the "true" value. ! * ! * Keep this path alive even with the Zip64 END support added, just ! * for zip files that have more than 0xffff entries but don't have ! * the Zip64 enabled. ! */ ! total = (knownTotal != -1) ? knownTotal : total; entries = zip->entries = calloc(total, sizeof(entries[0])); tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions table = zip->table = malloc(tablelen * sizeof(table[0])); if (entries == NULL || table == NULL) goto Catch; for (j = 0; j < tablelen; j++)
*** 852,861 **** --- 904,914 ---- * The ZIP lock should be held here. */ static jzentry * newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) { + jlong locoff; jint nlen, elen, clen; jzentry *ze; char *cen; if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
*** 878,900 **** clen = CENCOM(cen); ze->time = CENTIM(cen); ze->size = CENLEN(cen); ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); ze->crc = CENCRC(cen); ! ze->pos = -(zip->locpos + CENOFF(cen)); if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; memcpy(ze->name, cen + CENHDR, nlen); ze->name[nlen] = '\0'; if (elen > 0) { /* This entry has "extra" data */ if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; ze->extra[0] = (unsigned char) elen; ze->extra[1] = (unsigned char) (elen >> 8); ! memcpy(ze->extra+2, cen + CENHDR + nlen, elen); } if (clen > 0) { /* This entry has a comment */ if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; memcpy(ze->comment, cen + CENHDR + nlen + elen, clen); --- 931,990 ---- clen = CENCOM(cen); ze->time = CENTIM(cen); ze->size = CENLEN(cen); ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); ze->crc = CENCRC(cen); ! locoff = CENOFF(cen); ! ze->pos = -(zip->locpos + locoff); if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; memcpy(ze->name, cen + CENHDR, nlen); ze->name[nlen] = '\0'; if (elen > 0) { + char *extra = cen + CENHDR + nlen; + /* This entry has "extra" data */ if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; ze->extra[0] = (unsigned char) elen; ze->extra[1] = (unsigned char) (elen >> 8); ! memcpy(ze->extra+2, extra, elen); ! if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL || ! locoff == ZIP64_MAGICVAL) { ! jint off = 0; ! while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data ! jint sz = SH(extra, off + 2); ! if (SH(extra, off) == ZIP64_EXTID) { ! off += 4; ! if (ze->size == ZIP64_MAGICVAL) { ! // if invalid zip64 extra fields, just skip ! if (sz < 8 || (off + 8) > elen) ! break; ! ze->size = LL(extra, off); ! sz -= 8; ! off += 8; } + if (ze->csize == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > elen) + break; + ze->csize = LL(extra, off); + sz -= 8; + off += 8; + } + if (locoff == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > elen) + break; + ze->pos = -(zip->locpos + LL(extra, off)); + sz -= 8; + off += 8; + } + break; + } + off += (sz + 4); + } + } + } if (clen > 0) { /* This entry has a comment */ if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch; memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);