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);