/* * 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; }
/* * Computes and positions at the start of the CEN header, ie. the central * directory, this will also return the offset if there is a zip file comment * at the end of the archive, for most cases this would be 0. */ static jlong compute_cen(int fd, Byte *bp) { int bytes; Byte *p; jlong base_offset; jlong offset; char buffer[MINREAD]; p = buffer; /* * Read the END Header, which is the starting point for ZIP files. * (Clearly designed to make writing a zip file easier than reading * one. Now isn't that precious...) */ if ((base_offset = find_end(fd, bp)) == -1) { return (-1); } p = bp; /* * There is a historical, but undocumented, ability to allow for * additional "stuff" to be prepended to the zip/jar file. It seems * that this has been used to prepend an actual java launcher * executable to the jar on Windows. Although this is just another * form of statically linking a small piece of the JVM to the * application, we choose to continue to support it. Note that no * guarantees have been made (or should be made) to the customer that * this will continue to work. * * Therefore, calculate the base offset of the zip file (within the * expanded file) by assuming that the central directory is followed * immediately by the end record. */ if (zip64_present) { if ((offset = ZIP64_LOCOFF(p)) < (jlong)0) { return -1; } if (JLI_Lseek(fd, offset, SEEK_SET) < (jlong) 0) { return (-1); } if ((bytes = read(fd, buffer, MINREAD)) < 0) { return (-1); } if (GETSIG(buffer) != ZIP64_ENDSIG) { return -1; } if ((offset = ZIP64_ENDOFF(buffer)) < (jlong)0) { return -1; } if (JLI_Lseek(fd, offset, SEEK_SET) < (jlong)0) { return (-1); } p = buffer; base_offset = base_offset - ZIP64_ENDSIZ(p) - ZIP64_ENDOFF(p) - ZIP64_ENDHDR; } else { base_offset = base_offset - ENDSIZ(p) - ENDOFF(p); /* * The END Header indicates the start of the Central Directory * Headers. Remember that the desired Central Directory Header (CEN) * will almost always be the second one and the first one is a small * directory entry ("META-INF/"). Keep the code optimized for * that case. * * Seek to the beginning of the Central Directory. */ if (JLI_Lseek(fd, base_offset + ENDOFF(p), SEEK_SET) < (jlong) 0) { return (-1); } } return base_offset; }