8145260: To bring j.u.z.ZipFile's native implementation to Java to remove the expensive jni cost and mmap crash risk [2]
Reviewed-by: coffeys
This commit is contained in:
parent
38302301fd
commit
2b91819eec
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
SUNWprivate_1.1 {
|
SUNWprivate_1.1 {
|
||||||
global:
|
global:
|
||||||
Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
|
||||||
Java_java_util_zip_Adler32_update;
|
Java_java_util_zip_Adler32_update;
|
||||||
Java_java_util_zip_Adler32_updateBytes;
|
Java_java_util_zip_Adler32_updateBytes;
|
||||||
Java_java_util_zip_Adler32_updateByteBuffer;
|
Java_java_util_zip_Adler32_updateByteBuffer;
|
||||||
@ -48,25 +47,6 @@ SUNWprivate_1.1 {
|
|||||||
Java_java_util_zip_Inflater_initIDs;
|
Java_java_util_zip_Inflater_initIDs;
|
||||||
Java_java_util_zip_Inflater_reset;
|
Java_java_util_zip_Inflater_reset;
|
||||||
Java_java_util_zip_Inflater_setDictionary;
|
Java_java_util_zip_Inflater_setDictionary;
|
||||||
Java_java_util_zip_ZipFile_close;
|
|
||||||
Java_java_util_zip_ZipFile_getCommentBytes;
|
|
||||||
Java_java_util_zip_ZipFile_freeEntry;
|
|
||||||
Java_java_util_zip_ZipFile_getEntry;
|
|
||||||
Java_java_util_zip_ZipFile_getEntryBytes;
|
|
||||||
Java_java_util_zip_ZipFile_getEntryCrc;
|
|
||||||
Java_java_util_zip_ZipFile_getEntryCSize;
|
|
||||||
Java_java_util_zip_ZipFile_getEntryFlag;
|
|
||||||
Java_java_util_zip_ZipFile_getEntryMethod;
|
|
||||||
Java_java_util_zip_ZipFile_getEntrySize;
|
|
||||||
Java_java_util_zip_ZipFile_getEntryTime;
|
|
||||||
Java_java_util_zip_ZipFile_getNextEntry;
|
|
||||||
Java_java_util_zip_ZipFile_getZipMessage;
|
|
||||||
Java_java_util_zip_ZipFile_getTotal;
|
|
||||||
Java_java_util_zip_ZipFile_initIDs;
|
|
||||||
Java_java_util_zip_ZipFile_open;
|
|
||||||
Java_java_util_zip_ZipFile_read;
|
|
||||||
Java_java_util_zip_ZipFile_startsWithLOC;
|
|
||||||
|
|
||||||
ZIP_Close;
|
ZIP_Close;
|
||||||
ZIP_CRC32;
|
ZIP_CRC32;
|
||||||
ZIP_FindEntry;
|
ZIP_FindEntry;
|
||||||
|
@ -16,30 +16,14 @@ text: .text%ZIP_InflateFully;
|
|||||||
text: .text%ZIP_Lock;
|
text: .text%ZIP_Lock;
|
||||||
text: .text%ZIP_Unlock;
|
text: .text%ZIP_Unlock;
|
||||||
text: .text%ZIP_FreeEntry;
|
text: .text%ZIP_FreeEntry;
|
||||||
text: .text%Java_java_util_zip_ZipFile_initIDs;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_open;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getTotal;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntry;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_freeEntry;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryTime;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntrySize;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
|
|
||||||
text: .text%Java_java_util_zip_Inflater_initIDs;
|
text: .text%Java_java_util_zip_Inflater_initIDs;
|
||||||
text: .text%Java_java_util_zip_Inflater_init;
|
text: .text%Java_java_util_zip_Inflater_init;
|
||||||
text: .text%inflateInit2_;
|
text: .text%inflateInit2_;
|
||||||
text: .text%zcalloc;
|
text: .text%zcalloc;
|
||||||
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
||||||
text: .text%Java_java_util_zip_ZipFile_read;
|
|
||||||
text: .text%ZIP_Read;
|
text: .text%ZIP_Read;
|
||||||
text: .text%zcfree;
|
text: .text%zcfree;
|
||||||
text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
|
||||||
text: .text%Java_java_util_zip_Inflater_reset;
|
text: .text%Java_java_util_zip_Inflater_reset;
|
||||||
text: .text%Java_java_util_zip_Inflater_end;
|
text: .text%Java_java_util_zip_Inflater_end;
|
||||||
text: .text%inflateEnd;
|
text: .text%inflateEnd;
|
||||||
text: .text%Java_java_util_zip_ZipFile_close;
|
|
||||||
text: .text%ZIP_Close;
|
text: .text%ZIP_Close;
|
||||||
|
@ -15,19 +15,6 @@ text: .text%ZIP_InflateFully;
|
|||||||
text: .text%ZIP_Lock;
|
text: .text%ZIP_Lock;
|
||||||
text: .text%ZIP_Unlock;
|
text: .text%ZIP_Unlock;
|
||||||
text: .text%ZIP_FreeEntry;
|
text: .text%ZIP_FreeEntry;
|
||||||
text: .text%Java_java_util_zip_ZipFile_initIDs;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_open;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getTotal;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntry;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_freeEntry;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryTime;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntrySize;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
|
|
||||||
text: .text%Java_java_util_zip_Inflater_initIDs;
|
text: .text%Java_java_util_zip_Inflater_initIDs;
|
||||||
text: .text%Java_java_util_zip_Inflater_init;
|
text: .text%Java_java_util_zip_Inflater_init;
|
||||||
text: .text%inflateInit2_;
|
text: .text%inflateInit2_;
|
||||||
@ -35,7 +22,6 @@ text: .text%zcalloc;
|
|||||||
text: .text%inflateReset;
|
text: .text%inflateReset;
|
||||||
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
||||||
text: .text%inflate;
|
text: .text%inflate;
|
||||||
text: .text%Java_java_util_zip_ZipFile_read;
|
|
||||||
text: .text%ZIP_Read;
|
text: .text%ZIP_Read;
|
||||||
text: .text%zcfree;
|
text: .text%zcfree;
|
||||||
text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
||||||
@ -43,6 +29,5 @@ text: .text%ZIP_ReadEntry;
|
|||||||
text: .text%InflateFully;
|
text: .text%InflateFully;
|
||||||
text: .text%inflateEnd;
|
text: .text%inflateEnd;
|
||||||
text: .text%Java_java_util_zip_Inflater_reset;
|
text: .text%Java_java_util_zip_Inflater_reset;
|
||||||
text: .text%Java_java_util_zip_ZipFile_close;
|
|
||||||
text: .text%ZIP_Close;
|
text: .text%ZIP_Close;
|
||||||
text: .text%Java_java_util_zip_Inflater_end;
|
text: .text%Java_java_util_zip_Inflater_end;
|
||||||
|
@ -16,34 +16,16 @@ text: .text%ZIP_InflateFully;
|
|||||||
text: .text%ZIP_Lock;
|
text: .text%ZIP_Lock;
|
||||||
text: .text%ZIP_Unlock;
|
text: .text%ZIP_Unlock;
|
||||||
text: .text%ZIP_FreeEntry;
|
text: .text%ZIP_FreeEntry;
|
||||||
text: .text%Java_java_util_zip_ZipFile_initIDs;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_open;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getTotal;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntry;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_freeEntry;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryTime;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntrySize;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
|
|
||||||
text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
|
|
||||||
text: .text%Java_java_util_zip_Inflater_initIDs;
|
|
||||||
text: .text%Java_java_util_zip_Inflater_init;
|
|
||||||
text: .text%inflateInit2_;
|
text: .text%inflateInit2_;
|
||||||
text: .text%zcalloc;
|
text: .text%zcalloc;
|
||||||
text: .text%inflateReset;
|
text: .text%inflateReset;
|
||||||
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
||||||
text: .text%inflate;
|
text: .text%inflate;
|
||||||
text: .text%Java_java_util_zip_ZipFile_read;
|
|
||||||
text: .text%ZIP_Read;
|
text: .text%ZIP_Read;
|
||||||
text: .text%zcfree;
|
text: .text%zcfree;
|
||||||
text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
|
||||||
text: .text%ZIP_ReadEntry;
|
text: .text%ZIP_ReadEntry;
|
||||||
text: .text%InflateFully;
|
text: .text%InflateFully;
|
||||||
text: .text%inflateEnd;
|
text: .text%inflateEnd;
|
||||||
text: .text%Java_java_util_zip_Inflater_reset;
|
text: .text%Java_java_util_zip_Inflater_reset;
|
||||||
text: .text%Java_java_util_zip_ZipFile_close;
|
|
||||||
text: .text%ZIP_Close;
|
text: .text%ZIP_Close;
|
||||||
text: .text%Java_java_util_zip_Inflater_end;
|
text: .text%Java_java_util_zip_Inflater_end;
|
||||||
|
@ -203,7 +203,10 @@ class JarFile extends ZipFile {
|
|||||||
return man;
|
return man;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native String[] getMetaInfEntryNames();
|
private String[] getMetaInfEntryNames() {
|
||||||
|
return jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess()
|
||||||
|
.getMetaInfEntryNames((ZipFile)this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code JarEntry} for the given entry name or
|
* Returns the {@code JarEntry} for the given entry name or
|
||||||
|
@ -43,7 +43,7 @@ import sun.nio.cs.ArrayEncoder;
|
|||||||
|
|
||||||
final class ZipCoder {
|
final class ZipCoder {
|
||||||
|
|
||||||
String toString(byte[] ba, int length) {
|
String toString(byte[] ba, int off, int length) {
|
||||||
CharsetDecoder cd = decoder().reset();
|
CharsetDecoder cd = decoder().reset();
|
||||||
int len = (int)(length * cd.maxCharsPerByte());
|
int len = (int)(length * cd.maxCharsPerByte());
|
||||||
char[] ca = new char[len];
|
char[] ca = new char[len];
|
||||||
@ -53,12 +53,12 @@ final class ZipCoder {
|
|||||||
// CodingErrorAction.REPLACE mode. ZipCoder uses
|
// CodingErrorAction.REPLACE mode. ZipCoder uses
|
||||||
// REPORT mode.
|
// REPORT mode.
|
||||||
if (isUTF8 && cd instanceof ArrayDecoder) {
|
if (isUTF8 && cd instanceof ArrayDecoder) {
|
||||||
int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);
|
int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca);
|
||||||
if (clen == -1) // malformed
|
if (clen == -1) // malformed
|
||||||
throw new IllegalArgumentException("MALFORMED");
|
throw new IllegalArgumentException("MALFORMED");
|
||||||
return new String(ca, 0, clen);
|
return new String(ca, 0, clen);
|
||||||
}
|
}
|
||||||
ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
|
ByteBuffer bb = ByteBuffer.wrap(ba, off, length);
|
||||||
CharBuffer cb = CharBuffer.wrap(ca);
|
CharBuffer cb = CharBuffer.wrap(ca);
|
||||||
CoderResult cr = cd.decode(bb, cb, true);
|
CoderResult cr = cd.decode(bb, cb, true);
|
||||||
if (!cr.isUnderflow())
|
if (!cr.isUnderflow())
|
||||||
@ -69,8 +69,12 @@ final class ZipCoder {
|
|||||||
return new String(ca, 0, cb.position());
|
return new String(ca, 0, cb.position());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toString(byte[] ba, int length) {
|
||||||
|
return toString(ba, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
String toString(byte[] ba) {
|
String toString(byte[] ba) {
|
||||||
return toString(ba, ba.length);
|
return toString(ba, 0, ba.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] getBytes(String s) {
|
byte[] getBytes(String s) {
|
||||||
@ -111,13 +115,16 @@ final class ZipCoder {
|
|||||||
return utf8.getBytes(s);
|
return utf8.getBytes(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String toStringUTF8(byte[] ba, int len) {
|
String toStringUTF8(byte[] ba, int len) {
|
||||||
|
return toStringUTF8(ba, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toStringUTF8(byte[] ba, int off, int len) {
|
||||||
if (isUTF8)
|
if (isUTF8)
|
||||||
return toString(ba, len);
|
return toString(ba, off, len);
|
||||||
if (utf8 == null)
|
if (utf8 == null)
|
||||||
utf8 = new ZipCoder(StandardCharsets.UTF_8);
|
utf8 = new ZipCoder(StandardCharsets.UTF_8);
|
||||||
return utf8.toString(ba, len);
|
return utf8.toString(ba, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isUTF8() {
|
boolean isUTF8() {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,8 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static java.util.zip.ZipConstants.ENDHDR;
|
||||||
|
|
||||||
class ZipUtils {
|
class ZipUtils {
|
||||||
|
|
||||||
// used to adjust values between Windows and java epoch
|
// used to adjust values between Windows and java epoch
|
||||||
@ -133,7 +135,7 @@ class ZipUtils {
|
|||||||
* The bytes are assumed to be in Intel (little-endian) byte order.
|
* The bytes are assumed to be in Intel (little-endian) byte order.
|
||||||
*/
|
*/
|
||||||
public static final int get16(byte b[], int off) {
|
public static final int get16(byte b[], int off) {
|
||||||
return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
|
return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -160,4 +162,79 @@ class ZipUtils {
|
|||||||
public static final int get32S(byte b[], int off) {
|
public static final int get32S(byte b[], int off) {
|
||||||
return (get16(b, off) | (get16(b, off+2) << 16));
|
return (get16(b, off) | (get16(b, off+2) << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fields access methods
|
||||||
|
static final int CH(byte[] b, int n) {
|
||||||
|
return b[n] & 0xff ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final int SH(byte[] b, int n) {
|
||||||
|
return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final long LG(byte[] b, int n) {
|
||||||
|
return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final long LL(byte[] b, int n) {
|
||||||
|
return (LG(b, n)) | (LG(b, n + 4) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final long GETSIG(byte[] b) {
|
||||||
|
return LG(b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// local file (LOC) header fields
|
||||||
|
static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
|
||||||
|
static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
|
||||||
|
static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
|
||||||
|
static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
|
||||||
|
static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
|
||||||
|
static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
|
||||||
|
static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
|
||||||
|
static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
|
||||||
|
static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
|
||||||
|
static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
|
||||||
|
|
||||||
|
// extra local (EXT) header fields
|
||||||
|
static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
|
||||||
|
static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
|
||||||
|
static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
|
||||||
|
|
||||||
|
// end of central directory header (END) fields
|
||||||
|
static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
|
||||||
|
static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
|
||||||
|
static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
|
||||||
|
static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
|
||||||
|
static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
|
||||||
|
static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
|
||||||
|
|
||||||
|
// zip64 end of central directory recoder fields
|
||||||
|
static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
|
||||||
|
static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
|
||||||
|
static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
|
||||||
|
static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
|
||||||
|
static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
|
||||||
|
|
||||||
|
// central directory header (CEN) fields
|
||||||
|
static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
|
||||||
|
static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
|
||||||
|
static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
|
||||||
|
static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
|
||||||
|
static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
|
||||||
|
static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
|
||||||
|
static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
|
||||||
|
static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
|
||||||
|
static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
|
||||||
|
static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
|
||||||
|
static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
|
||||||
|
static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
|
||||||
|
static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
|
||||||
|
static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
|
||||||
|
static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
|
||||||
|
static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
|
||||||
|
|
||||||
|
// The END header is followed by a variable length comment of size < 64k.
|
||||||
|
static final long END_MAXLEN = 0xFFFF + ENDHDR;
|
||||||
|
static final int READBLOCKSZ = 128;
|
||||||
}
|
}
|
||||||
|
@ -29,5 +29,6 @@ import java.util.zip.ZipFile;
|
|||||||
|
|
||||||
public interface JavaUtilZipFileAccess {
|
public interface JavaUtilZipFileAccess {
|
||||||
public boolean startsWithLocHeader(ZipFile zip);
|
public boolean startsWithLocHeader(ZipFile zip);
|
||||||
|
public String[] getMetaInfEntryNames(ZipFile zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,9 +274,6 @@ public class VM {
|
|||||||
// used by java.lang.Integer.IntegerCache
|
// used by java.lang.Integer.IntegerCache
|
||||||
props.remove("java.lang.Integer.IntegerCache.high");
|
props.remove("java.lang.Integer.IntegerCache.high");
|
||||||
|
|
||||||
// used by java.util.zip.ZipFile
|
|
||||||
props.remove("sun.zip.disableMemoryMapping");
|
|
||||||
|
|
||||||
// used by sun.launcher.LauncherHelper
|
// used by sun.launcher.LauncherHelper
|
||||||
props.remove("sun.java.launcher.diag");
|
props.remove("sun.java.launcher.diag");
|
||||||
}
|
}
|
||||||
|
@ -1,406 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Native method support for java.util.zip.ZipFile
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "jlong.h"
|
|
||||||
#include "jvm.h"
|
|
||||||
#include "jni.h"
|
|
||||||
#include "jni_util.h"
|
|
||||||
#include "zip_util.h"
|
|
||||||
#ifdef WIN32
|
|
||||||
#include "io_util_md.h"
|
|
||||||
#else
|
|
||||||
#include "io_util.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "java_util_zip_ZipFile.h"
|
|
||||||
#include "java_util_jar_JarFile.h"
|
|
||||||
|
|
||||||
#define DEFLATED 8
|
|
||||||
#define STORED 0
|
|
||||||
|
|
||||||
static jfieldID jzfileID;
|
|
||||||
|
|
||||||
static int OPEN_READ = java_util_zip_ZipFile_OPEN_READ;
|
|
||||||
static int OPEN_DELETE = java_util_zip_ZipFile_OPEN_DELETE;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Declare library specific JNI_Onload entry if static build
|
|
||||||
*/
|
|
||||||
DEF_STATIC_JNI_OnLoad
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_initIDs(JNIEnv *env, jclass cls)
|
|
||||||
{
|
|
||||||
jzfileID = (*env)->GetFieldID(env, cls, "jzfile", "J");
|
|
||||||
assert(jzfileID != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ThrowZipException(JNIEnv *env, const char *msg)
|
|
||||||
{
|
|
||||||
jstring s = NULL;
|
|
||||||
jobject x;
|
|
||||||
|
|
||||||
if (msg != NULL) {
|
|
||||||
s = JNU_NewStringPlatform(env, msg);
|
|
||||||
}
|
|
||||||
if (s != NULL) {
|
|
||||||
x = JNU_NewObjectByName(env,
|
|
||||||
"java/util/zip/ZipException",
|
|
||||||
"(Ljava/lang/String;)V", s);
|
|
||||||
if (x != NULL) {
|
|
||||||
(*env)->Throw(env, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
|
|
||||||
jint mode, jlong lastModified,
|
|
||||||
jboolean usemmap)
|
|
||||||
{
|
|
||||||
const char *path = JNU_GetStringPlatformChars(env, name, 0);
|
|
||||||
char *msg = 0;
|
|
||||||
jlong result = 0;
|
|
||||||
int flag = 0;
|
|
||||||
jzfile *zip = 0;
|
|
||||||
|
|
||||||
if (mode & OPEN_READ) flag |= O_RDONLY;
|
|
||||||
|
|
||||||
if (path != 0) {
|
|
||||||
zip = ZIP_Get_From_Cache(path, &msg, lastModified);
|
|
||||||
if (zip == 0 && msg == 0) {
|
|
||||||
ZFILE zfd = 0;
|
|
||||||
#ifdef WIN32
|
|
||||||
if (mode & OPEN_DELETE) flag |= O_TEMPORARY;
|
|
||||||
zfd = winFileHandleOpen(env, name, flag);
|
|
||||||
if (zfd == -1) {
|
|
||||||
/* Exception already pending. */
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
zfd = open(path, flag, 0);
|
|
||||||
if (zfd < 0) {
|
|
||||||
throwFileNotFoundException(env, name);
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
if (mode & OPEN_DELETE) {
|
|
||||||
unlink(path);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zip != 0) {
|
|
||||||
result = ptr_to_jlong(zip);
|
|
||||||
} else if (msg != 0) {
|
|
||||||
ThrowZipException(env, msg);
|
|
||||||
free(msg);
|
|
||||||
} else if (errno == ENOMEM) {
|
|
||||||
JNU_ThrowOutOfMemoryError(env, 0);
|
|
||||||
} else {
|
|
||||||
ThrowZipException(env, "error in opening zip file");
|
|
||||||
}
|
|
||||||
finally:
|
|
||||||
JNU_ReleaseStringPlatformChars(env, name, path);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getTotal(JNIEnv *env, jclass cls, jlong zfile)
|
|
||||||
{
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
|
|
||||||
return zip->total;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_startsWithLOC(JNIEnv *env, jclass cls, jlong zfile)
|
|
||||||
{
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
|
|
||||||
return zip->locsig;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_close(JNIEnv *env, jclass cls, jlong zfile)
|
|
||||||
{
|
|
||||||
ZIP_Close(jlong_to_ptr(zfile));
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,
|
|
||||||
jbyteArray name, jboolean addSlash)
|
|
||||||
{
|
|
||||||
#define MAXNAME 1024
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
jsize ulen = (*env)->GetArrayLength(env, name);
|
|
||||||
char buf[MAXNAME+2], *path;
|
|
||||||
jzentry *ze;
|
|
||||||
|
|
||||||
if (ulen > MAXNAME) {
|
|
||||||
path = malloc(ulen + 2);
|
|
||||||
if (path == 0) {
|
|
||||||
JNU_ThrowOutOfMemoryError(env, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
path = buf;
|
|
||||||
}
|
|
||||||
(*env)->GetByteArrayRegion(env, name, 0, ulen, (jbyte *)path);
|
|
||||||
path[ulen] = '\0';
|
|
||||||
ze = ZIP_GetEntry2(zip, path, (jint)ulen, addSlash);
|
|
||||||
if (path != buf) {
|
|
||||||
free(path);
|
|
||||||
}
|
|
||||||
return ptr_to_jlong(ze);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_freeEntry(JNIEnv *env, jclass cls, jlong zfile,
|
|
||||||
jlong zentry)
|
|
||||||
{
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
ZIP_FreeEntry(zip, ze);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env, jclass cls, jlong zfile,
|
|
||||||
jint n)
|
|
||||||
{
|
|
||||||
jzentry *ze = ZIP_GetNextEntry(jlong_to_ptr(zfile), n);
|
|
||||||
return ptr_to_jlong(ze);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntryMethod(JNIEnv *env, jclass cls, jlong zentry)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
return ze->csize != 0 ? DEFLATED : STORED;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntryFlag(JNIEnv *env, jclass cls, jlong zentry)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
return ze->flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntryCSize(JNIEnv *env, jclass cls, jlong zentry)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
return ze->csize != 0 ? ze->csize : ze->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntrySize(JNIEnv *env, jclass cls, jlong zentry)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
return ze->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntryTime(JNIEnv *env, jclass cls, jlong zentry)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
return (jlong)ze->time & 0xffffffffUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntryCrc(JNIEnv *env, jclass cls, jlong zentry)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
return (jlong)ze->crc & 0xffffffffUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jbyteArray JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getCommentBytes(JNIEnv *env,
|
|
||||||
jclass cls,
|
|
||||||
jlong zfile)
|
|
||||||
{
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
jbyteArray jba = NULL;
|
|
||||||
|
|
||||||
if (zip->comment != NULL) {
|
|
||||||
if ((jba = (*env)->NewByteArray(env, zip->clen)) == NULL)
|
|
||||||
return NULL;
|
|
||||||
(*env)->SetByteArrayRegion(env, jba, 0, zip->clen, (jbyte*)zip->comment);
|
|
||||||
}
|
|
||||||
return jba;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jbyteArray JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getEntryBytes(JNIEnv *env,
|
|
||||||
jclass cls,
|
|
||||||
jlong zentry, jint type)
|
|
||||||
{
|
|
||||||
jzentry *ze = jlong_to_ptr(zentry);
|
|
||||||
int len = 0;
|
|
||||||
jbyteArray jba = NULL;
|
|
||||||
switch (type) {
|
|
||||||
case java_util_zip_ZipFile_JZENTRY_NAME:
|
|
||||||
if (ze->name != 0) {
|
|
||||||
len = (int)ze->nlen;
|
|
||||||
// Unlike for extra and comment, we never return null for
|
|
||||||
// an (extremely rarely seen) empty name
|
|
||||||
if ((jba = (*env)->NewByteArray(env, len)) == NULL)
|
|
||||||
break;
|
|
||||||
(*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte *)ze->name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case java_util_zip_ZipFile_JZENTRY_EXTRA:
|
|
||||||
if (ze->extra != 0) {
|
|
||||||
unsigned char *bp = (unsigned char *)&ze->extra[0];
|
|
||||||
len = (bp[0] | (bp[1] << 8));
|
|
||||||
if (len <= 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
|
|
||||||
break;
|
|
||||||
(*env)->SetByteArrayRegion(env, jba, 0, len, &ze->extra[2]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case java_util_zip_ZipFile_JZENTRY_COMMENT:
|
|
||||||
if (ze->comment != 0) {
|
|
||||||
len = (int)strlen(ze->comment);
|
|
||||||
if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
|
|
||||||
break;
|
|
||||||
(*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte*)ze->comment);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return jba;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile,
|
|
||||||
jlong zentry, jlong pos, jbyteArray bytes,
|
|
||||||
jint off, jint len)
|
|
||||||
{
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
char *msg;
|
|
||||||
|
|
||||||
#define BUFSIZE 8192
|
|
||||||
/* copy via tmp stack buffer: */
|
|
||||||
jbyte buf[BUFSIZE];
|
|
||||||
|
|
||||||
if (len > BUFSIZE) {
|
|
||||||
len = BUFSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZIP_Lock(zip);
|
|
||||||
len = ZIP_Read(zip, jlong_to_ptr(zentry), pos, buf, len);
|
|
||||||
msg = zip->msg;
|
|
||||||
ZIP_Unlock(zip);
|
|
||||||
if (len != -1) {
|
|
||||||
(*env)->SetByteArrayRegion(env, bytes, off, len, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == -1) {
|
|
||||||
if (msg != 0) {
|
|
||||||
ThrowZipException(env, msg);
|
|
||||||
} else {
|
|
||||||
char errmsg[128];
|
|
||||||
sprintf(errmsg, "errno: %d, error: %s\n",
|
|
||||||
errno, "Error reading ZIP file");
|
|
||||||
JNU_ThrowIOExceptionWithLastError(env, errmsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns an array of strings representing the names of all entries
|
|
||||||
* that begin with "META-INF/" (case ignored). This native method is
|
|
||||||
* used in JarFile as an optimization when looking up manifest and
|
|
||||||
* signature file entries. Returns null if no entries were found.
|
|
||||||
*/
|
|
||||||
JNIEXPORT jobjectArray JNICALL
|
|
||||||
Java_java_util_jar_JarFile_getMetaInfEntryNames(JNIEnv *env, jobject obj)
|
|
||||||
{
|
|
||||||
jlong zfile = (*env)->GetLongField(env, obj, jzfileID);
|
|
||||||
jzfile *zip;
|
|
||||||
int i, count;
|
|
||||||
jobjectArray result = 0;
|
|
||||||
|
|
||||||
if (zfile == 0) {
|
|
||||||
JNU_ThrowByName(env,
|
|
||||||
"java/lang/IllegalStateException", "zip file closed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
zip = jlong_to_ptr(zfile);
|
|
||||||
|
|
||||||
/* count the number of valid ZIP metanames */
|
|
||||||
count = 0;
|
|
||||||
if (zip->metanames != 0) {
|
|
||||||
for (i = 0; i < zip->metacount; i++) {
|
|
||||||
if (zip->metanames[i] != 0) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If some names were found then build array of java strings */
|
|
||||||
if (count > 0) {
|
|
||||||
jclass cls = JNU_ClassString(env);
|
|
||||||
CHECK_NULL_RETURN(cls, NULL);
|
|
||||||
result = (*env)->NewObjectArray(env, count, cls, 0);
|
|
||||||
CHECK_NULL_RETURN(result, NULL);
|
|
||||||
if (result != 0) {
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
jstring str = (*env)->NewStringUTF(env, zip->metanames[i]);
|
|
||||||
if (str == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(*env)->SetObjectArrayElement(env, result, i, str);
|
|
||||||
(*env)->DeleteLocalRef(env, str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_java_util_zip_ZipFile_getZipMessage(JNIEnv *env, jclass cls, jlong zfile)
|
|
||||||
{
|
|
||||||
jzfile *zip = jlong_to_ptr(zfile);
|
|
||||||
char *msg = zip->msg;
|
|
||||||
if (msg == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return JNU_NewStringPlatform(env, msg);
|
|
||||||
}
|
|
@ -84,9 +84,10 @@ public class TestZipError {
|
|||||||
try {
|
try {
|
||||||
while (entries.hasMoreElements()) {
|
while (entries.hasMoreElements()) {
|
||||||
ze = entries.nextElement();
|
ze = entries.nextElement();
|
||||||
|
zf.getInputStream(ze).readAllBytes();
|
||||||
}
|
}
|
||||||
fail("Did not get expected exception");
|
fail("Did not get expected exception");
|
||||||
} catch (ZipError e) {
|
} catch (ZipException e) {
|
||||||
pass();
|
pass();
|
||||||
} catch (InternalError e) {
|
} catch (InternalError e) {
|
||||||
fail("Caught InternalError instead of expected ZipError");
|
fail("Caught InternalError instead of expected ZipError");
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
@ -110,6 +111,6 @@ public class ReadZip {
|
|||||||
"input"
|
"input"
|
||||||
+ String.valueOf(new java.util.Random().nextInt())
|
+ String.valueOf(new java.util.Random().nextInt())
|
||||||
+ ".zip")));
|
+ ".zip")));
|
||||||
} catch (FileNotFoundException fnfe) {}
|
} catch (NoSuchFileException nsfe) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
361
jdk/test/java/util/zip/ZipFile/TestZipFile.java
Normal file
361
jdk/test/java/util/zip/ZipFile/TestZipFile.java
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8142508
|
||||||
|
* @summary Tests various ZipFile apis
|
||||||
|
* @run main/manual TestZipFile
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.*;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.attribute.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.zip.*;
|
||||||
|
|
||||||
|
public class TestZipFile {
|
||||||
|
|
||||||
|
private static Random r = new Random();
|
||||||
|
private static int N = 50;
|
||||||
|
private static int NN = 10;
|
||||||
|
private static int ENUM = 10000;
|
||||||
|
private static int ESZ = 10000;
|
||||||
|
private static ExecutorService executor = Executors.newFixedThreadPool(20);
|
||||||
|
private static Set<Path> paths = new HashSet<>();
|
||||||
|
|
||||||
|
static void realMain (String[] args) throws Throwable {
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||||
|
test(r.nextInt(ENUM), r.nextInt(ESZ), true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < NN; i++) {
|
||||||
|
test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), false, true);
|
||||||
|
test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), true, true);
|
||||||
|
testCachedDelete();
|
||||||
|
testCachedOverwrite();
|
||||||
|
//test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
test(70000, 1000, false, true); // > 65536 entry number;
|
||||||
|
testDelete(); // OPEN_DELETE
|
||||||
|
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(10, TimeUnit.MINUTES);
|
||||||
|
} finally {
|
||||||
|
for (Path path : paths) {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test(int numEntry, int szMax, boolean addPrefix, boolean cleanOld) {
|
||||||
|
String name = "zftest" + r.nextInt() + ".zip";
|
||||||
|
Zip zip = new Zip(name, numEntry, szMax, addPrefix, cleanOld);
|
||||||
|
for (int i = 0; i < NN; i++) {
|
||||||
|
executor.submit(() -> doTest(zip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test scenario:
|
||||||
|
// (1) open the ZipFile(zip) with OPEN_READ | OPEN_DELETE
|
||||||
|
// (2) test the ZipFile works correctly
|
||||||
|
// (3) check the zip is deleted after ZipFile gets closed
|
||||||
|
static void testDelete() throws Throwable {
|
||||||
|
String name = "zftest" + r.nextInt() + ".zip";
|
||||||
|
Zip zip = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||||
|
try (ZipFile zf = new ZipFile(new File(zip.name),
|
||||||
|
ZipFile.OPEN_READ | ZipFile.OPEN_DELETE ))
|
||||||
|
{
|
||||||
|
doTest0(zip, zf);
|
||||||
|
}
|
||||||
|
Path p = Paths.get(name);
|
||||||
|
if (Files.exists(p)) {
|
||||||
|
fail("Failed to delete " + name + " with OPEN_DELETE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test scenario:
|
||||||
|
// (1) keep a ZipFile(zip1) alive (in ZipFile's cache), dont close it
|
||||||
|
// (2) delete zip1 and create zip2 with the same name the zip1 with zip2
|
||||||
|
// (3) zip1 tests should fail, but no crash
|
||||||
|
// (4) zip2 tasks should all get zip2, then pass normal testing.
|
||||||
|
static void testCachedDelete() throws Throwable {
|
||||||
|
String name = "zftest" + r.nextInt() + ".zip";
|
||||||
|
Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||||
|
|
||||||
|
try (ZipFile zf = new ZipFile(zip1.name)) {
|
||||||
|
for (int i = 0; i < NN; i++) {
|
||||||
|
executor.submit(() -> verifyNoCrash(zip1));
|
||||||
|
}
|
||||||
|
// delete the "zip1" and create a new one to test
|
||||||
|
Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||||
|
/*
|
||||||
|
System.out.println("========================================");
|
||||||
|
System.out.printf(" zip1=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
|
||||||
|
zip1.name, zip1.lastModified, zip1.entries.size(),
|
||||||
|
zip1.attrs.fileKey(), zip1.attrs.size(), zip1.attrs.lastModifiedTime().toMillis());
|
||||||
|
System.out.printf(" zip2=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
|
||||||
|
zip2.name, zip2.lastModified, zip2.entries.size(),
|
||||||
|
zip2.attrs.fileKey(), zip2.attrs.size(), zip2.attrs.lastModifiedTime().toMillis());
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < NN; i++) {
|
||||||
|
executor.submit(() -> doTest(zip2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite the "zip1" and create a new one to test. So the two zip files
|
||||||
|
// have the same fileKey, but probably different lastModified()
|
||||||
|
static void testCachedOverwrite() throws Throwable {
|
||||||
|
String name = "zftest" + r.nextInt() + ".zip";
|
||||||
|
Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||||
|
try (ZipFile zf = new ZipFile(zip1.name)) {
|
||||||
|
for (int i = 0; i < NN; i++) {
|
||||||
|
executor.submit(() -> verifyNoCrash(zip1));
|
||||||
|
}
|
||||||
|
// overwrite the "zip1" with new contents
|
||||||
|
Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, false);
|
||||||
|
for (int i = 0; i < NN; i++) {
|
||||||
|
executor.submit(() -> doTest(zip2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just check the entries and contents. since the file has been either overwritten
|
||||||
|
// or deleted/rewritten, we only care if it crahes or not.
|
||||||
|
static void verifyNoCrash(Zip zip) throws RuntimeException {
|
||||||
|
try (ZipFile zf = new ZipFile(zip.name)) {
|
||||||
|
List<ZipEntry> zlist = new ArrayList(zip.entries.keySet());
|
||||||
|
String[] elist = zf.stream().map( e -> e.getName()).toArray(String[]::new);
|
||||||
|
if (!Arrays.equals(elist,
|
||||||
|
zlist.stream().map( e -> e.getName()).toArray(String[]::new)))
|
||||||
|
{
|
||||||
|
//System.out.printf("++++++ LIST NG [%s] entries.len=%d, expected=%d+++++++%n",
|
||||||
|
// zf.getName(), elist.length, zlist.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (ZipEntry ze : zlist) {
|
||||||
|
byte[] zdata = zip.entries.get(ze);
|
||||||
|
ZipEntry e = zf.getEntry(ze.getName());
|
||||||
|
if (e != null) {
|
||||||
|
checkEqual(e, ze);
|
||||||
|
if (!e.isDirectory()) {
|
||||||
|
// check with readAllBytes
|
||||||
|
try (InputStream is = zf.getInputStream(e)) {
|
||||||
|
if (!Arrays.equals(zdata, is.readAllBytes())) {
|
||||||
|
//System.out.printf("++++++ BYTES NG [%s]/[%s] ++++++++%n",
|
||||||
|
// zf.getName(), ze.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// t.printStackTrace();
|
||||||
|
// fail(t.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkEqual(ZipEntry x, ZipEntry y) {
|
||||||
|
if (x.getName().equals(y.getName()) &&
|
||||||
|
x.isDirectory() == y.isDirectory() &&
|
||||||
|
x.getMethod() == y.getMethod() &&
|
||||||
|
(x.getTime() / 2000) == y.getTime() / 2000 &&
|
||||||
|
x.getSize() == y.getSize() &&
|
||||||
|
x.getCompressedSize() == y.getCompressedSize() &&
|
||||||
|
x.getCrc() == y.getCrc() &&
|
||||||
|
x.getComment().equals(y.getComment())
|
||||||
|
) {
|
||||||
|
pass();
|
||||||
|
} else {
|
||||||
|
fail(x + " not equal to " + y);
|
||||||
|
System.out.printf(" %s %s%n", x.getName(), y.getName());
|
||||||
|
System.out.printf(" %d %d%n", x.getMethod(), y.getMethod());
|
||||||
|
System.out.printf(" %d %d%n", x.getTime(), y.getTime());
|
||||||
|
System.out.printf(" %d %d%n", x.getSize(), y.getSize());
|
||||||
|
System.out.printf(" %d %d%n", x.getCompressedSize(), y.getCompressedSize());
|
||||||
|
System.out.printf(" %d %d%n", x.getCrc(), y.getCrc());
|
||||||
|
System.out.println("-----------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doTest(Zip zip) throws RuntimeException {
|
||||||
|
//Thread me = Thread.currentThread();
|
||||||
|
try (ZipFile zf = new ZipFile(zip.name)) {
|
||||||
|
doTest0(zip, zf);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doTest0(Zip zip, ZipFile zf) throws Throwable {
|
||||||
|
List<ZipEntry> list = new ArrayList(zip.entries.keySet());
|
||||||
|
// (1) check entry list, in expected order
|
||||||
|
if (!check(Arrays.equals(
|
||||||
|
list.stream().map( e -> e.getName()).toArray(String[]::new),
|
||||||
|
zf.stream().map( e -> e.getName()).toArray(String[]::new)))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// (2) shuffle, and check each entry and its bytes
|
||||||
|
Collections.shuffle(list);
|
||||||
|
for (ZipEntry ze : list) {
|
||||||
|
byte[] data = zip.entries.get(ze);
|
||||||
|
ZipEntry e = zf.getEntry(ze.getName());
|
||||||
|
checkEqual(e, ze);
|
||||||
|
if (!e.isDirectory()) {
|
||||||
|
// check with readAllBytes
|
||||||
|
try (InputStream is = zf.getInputStream(e)) {
|
||||||
|
check(Arrays.equals(data, is.readAllBytes()));
|
||||||
|
}
|
||||||
|
// check with smaller sized buf
|
||||||
|
try (InputStream is = zf.getInputStream(e)) {
|
||||||
|
byte[] buf = new byte[(int)e.getSize()];
|
||||||
|
int sz = r.nextInt((int)e.getSize()/4 + 1) + 1;
|
||||||
|
int off = 0;
|
||||||
|
int n;
|
||||||
|
while ((n = is.read(buf, off, buf.length - off)) > 0) {
|
||||||
|
off += n;
|
||||||
|
}
|
||||||
|
check(is.read() == -1);
|
||||||
|
check(Arrays.equals(data, buf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// (3) check getMetaInfEntryNames
|
||||||
|
String[] metas = list.stream()
|
||||||
|
.map( e -> e.getName())
|
||||||
|
.filter( s -> s.startsWith("META-INF/"))
|
||||||
|
.sorted()
|
||||||
|
.toArray(String[]::new);
|
||||||
|
if (metas.length > 0) {
|
||||||
|
// meta-inf entries
|
||||||
|
Method getMetas = ZipFile.class.getDeclaredMethod("getMetaInfEntryNames");
|
||||||
|
getMetas.setAccessible(true);
|
||||||
|
String[] names = (String[])getMetas.invoke(zf);
|
||||||
|
if (names == null) {
|
||||||
|
fail("Failed to get metanames from " + zf);
|
||||||
|
} else {
|
||||||
|
Arrays.sort(names);
|
||||||
|
check(Arrays.equals(names, metas));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Zip {
|
||||||
|
String name;
|
||||||
|
Map<ZipEntry, byte[]> entries;
|
||||||
|
BasicFileAttributes attrs;
|
||||||
|
long lastModified;
|
||||||
|
|
||||||
|
Zip(String name, int num, int szMax, boolean prefix, boolean clean) {
|
||||||
|
this.name = name;
|
||||||
|
entries = new LinkedHashMap<>(num);
|
||||||
|
try {
|
||||||
|
Path p = Paths.get(name);
|
||||||
|
if (clean) {
|
||||||
|
Files.deleteIfExists(p);
|
||||||
|
}
|
||||||
|
paths.add(p);
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw (RuntimeException)x;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(name);
|
||||||
|
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||||
|
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||||
|
{
|
||||||
|
if (prefix) {
|
||||||
|
byte[] bytes = new byte[r.nextInt(1000)];
|
||||||
|
r.nextBytes(bytes);
|
||||||
|
bos.write(bytes);
|
||||||
|
}
|
||||||
|
CRC32 crc = new CRC32();
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
String ename = "entry-" + i + "-name-" + r.nextLong();
|
||||||
|
ZipEntry ze = new ZipEntry(ename);
|
||||||
|
int method = r.nextBoolean() ? ZipEntry.STORED : ZipEntry.DEFLATED;
|
||||||
|
writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
||||||
|
}
|
||||||
|
// add some manifest entries
|
||||||
|
for (int i = 0; i < r.nextInt(20); i++) {
|
||||||
|
String meta = "META-INF/" + "entry-" + i + "-metainf-" + r.nextLong();
|
||||||
|
ZipEntry ze = new ZipEntry(meta);
|
||||||
|
writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
||||||
|
}
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw (RuntimeException)x;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
|
||||||
|
this.lastModified = new File(name).lastModified();
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw (RuntimeException)x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeEntry(ZipOutputStream zos, CRC32 crc,
|
||||||
|
ZipEntry ze, int method, int szMax)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
ze.setMethod(method);
|
||||||
|
byte[] data = new byte[r.nextInt(szMax + 1)];
|
||||||
|
r.nextBytes(data);
|
||||||
|
if (method == ZipEntry.STORED) { // must set size/csize/crc
|
||||||
|
ze.setSize(data.length);
|
||||||
|
ze.setCompressedSize(data.length);
|
||||||
|
crc.reset();
|
||||||
|
crc.update(data);
|
||||||
|
ze.setCrc(crc.getValue());
|
||||||
|
}
|
||||||
|
ze.setTime(System.currentTimeMillis());
|
||||||
|
ze.setComment(ze.getName());
|
||||||
|
zos.putNextEntry(ze);
|
||||||
|
zos.write(data);
|
||||||
|
zos.closeEntry();
|
||||||
|
entries.put(ze, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------- Infrastructure ---------------------------
|
||||||
|
static volatile int passed = 0, failed = 0;
|
||||||
|
static void pass() {passed++;}
|
||||||
|
static void pass(String msg) {System.out.println(msg); passed++;}
|
||||||
|
static void fail() {failed++; Thread.dumpStack();}
|
||||||
|
static void fail(String msg) {System.out.println(msg); fail();}
|
||||||
|
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||||
|
static void unexpected(Throwable t, String msg) {
|
||||||
|
System.out.println(msg); failed++; t.printStackTrace();}
|
||||||
|
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||||
|
System.out.println("\nPassed = " + passed + " failed = " + failed);
|
||||||
|
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user