提交 5a873572 编写于 作者: S sherman

8015666: test/tools/pack200/TimeStamp.java failing

Summary: to keep the default behavior of ZOS unchanged, if ze extra time not explicitly set
Reviewed-by: alanb, ksrini
上级 c63c8533
...@@ -76,6 +76,13 @@ interface ZipConstants { ...@@ -76,6 +76,13 @@ interface ZipConstants {
static final int EXTID_UNIX = 0x000d; // UNIX static final int EXTID_UNIX = 0x000d; // UNIX
static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
/*
* EXTT timestamp flags
*/
static final int EXTT_FLAG_LMT = 0x1; // LastModifiedTime
static final int EXTT_FLAG_LAT = 0x2; // LastAccessTime
static final int EXTT_FLAT_CT = 0x4; // CreationTime
/* /*
* Central directory (CEN) header field offsets * Central directory (CEN) header field offsets
*/ */
......
/* /*
* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2013, 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
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
package java.util.zip; package java.util.zip;
import static java.util.zip.ZipUtils.*;
import java.nio.file.attribute.FileTime;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/** /**
* This class is used to represent a ZIP file entry. * This class is used to represent a ZIP file entry.
* *
...@@ -32,8 +37,12 @@ package java.util.zip; ...@@ -32,8 +37,12 @@ package java.util.zip;
*/ */
public public
class ZipEntry implements ZipConstants, Cloneable { class ZipEntry implements ZipConstants, Cloneable {
String name; // entry name String name; // entry name
long mtime = -1; // last modification time long time = -1; // last modification time
FileTime mtime; // last modification time, from extra field data
FileTime atime; // last access time, from extra field data
FileTime ctime; // creation time, from extra field data
long crc = -1; // crc-32 of entry data long crc = -1; // crc-32 of entry data
long size = -1; // uncompressed size of entry data long size = -1; // uncompressed size of entry data
long csize = -1; // compressed size of entry data long csize = -1; // compressed size of entry data
...@@ -55,15 +64,15 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -55,15 +64,15 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Creates a new zip entry with the specified name. * Creates a new zip entry with the specified name.
* *
* @param name the entry name * @param name
* @exception NullPointerException if the entry name is null * The entry name
* @exception IllegalArgumentException if the entry name is longer than *
* @throws NullPointerException if the entry name is null
* @throws IllegalArgumentException if the entry name is longer than
* 0xFFFF bytes * 0xFFFF bytes
*/ */
public ZipEntry(String name) { public ZipEntry(String name) {
if (name == null) { Objects.requireNonNull(name, "name");
throw new NullPointerException();
}
if (name.length() > 0xFFFF) { if (name.length() > 0xFFFF) {
throw new IllegalArgumentException("entry name too long"); throw new IllegalArgumentException("entry name too long");
} }
...@@ -73,11 +82,19 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -73,11 +82,19 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Creates a new zip entry with fields taken from the specified * Creates a new zip entry with fields taken from the specified
* zip entry. * zip entry.
* @param e a zip Entry object *
* @param e
* A zip Entry object
*
* @throws NullPointerException if the entry object is null
*/ */
public ZipEntry(ZipEntry e) { public ZipEntry(ZipEntry e) {
Objects.requireNonNull(e, "entry");
name = e.name; name = e.name;
time = e.time;
mtime = e.mtime; mtime = e.mtime;
atime = e.atime;
ctime = e.ctime;
crc = e.crc; crc = e.crc;
size = e.size; size = e.size;
csize = e.csize; csize = e.csize;
...@@ -103,30 +120,175 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -103,30 +120,175 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Sets the last modification time of the entry. * Sets the last modification time of the entry.
* *
* @param time the last modification time of the entry in milliseconds since the epoch * <p> If the entry is output to a ZIP file or ZIP file formatted
* output stream the last modification time set by this method will
* be stored into the {@code date and time fields} of the zip file
* entry and encoded in standard {@code MS-DOS date and time format}.
* The {@link java.util.TimeZone#getDefault() default TimeZone} is
* used to convert the epoch time to the MS-DOS data and time.
*
* @param time
* The last modification time of the entry in milliseconds
* since the epoch
*
* @see #getTime() * @see #getTime()
* @see #getLastModifiedTime()
*/ */
public void setTime(long time) { public void setTime(long time) {
this.mtime = time; this.time = time;
this.mtime = null;
} }
/** /**
* Returns the last modification time of the entry. * Returns the last modification time of the entry.
* <p> The last modificatin time may come from zip entry's extensible
* data field {@code NTFS} or {@code Info-ZIP Extended Timestamp}, if
* the entry is read from {@link ZipInputStream} or {@link ZipFile}.
* *
* @return the last modification time of the entry, or -1 if not specified * <p> If the entry is read from a ZIP file or ZIP file formatted
* input stream, this is the last modification time from the {@code
* date and time fields} of the zip file entry. The
* {@link java.util.TimeZone#getDefault() default TimeZone} is used
* to convert the standard MS-DOS formatted date and time to the
* epoch time.
*
* @return The last modification time of the entry in milliseconds
* since the epoch, or -1 if not specified
*
* @see #setTime(long) * @see #setTime(long)
* @see #setLastModifiedTime(FileTime)
*/ */
public long getTime() { public long getTime() {
return time;
}
/**
* Sets the last modification time of the entry.
*
* <p> When output to a ZIP file or ZIP file formatted output stream
* the last modification time set by this method will be stored into
* zip file entry's {@code date and time fields} in {@code standard
* MS-DOS date and time format}), and the extended timestamp fields
* in {@code optional extra data} in UTC time.
*
* @param time
* The last modification time of the entry
* @return This zip entry
*
* @throws NullPointerException if the {@code time} is null
*
* @see #getLastModifiedTime()
* @since 1.8
*/
public ZipEntry setLastModifiedTime(FileTime time) {
Objects.requireNonNull(name, "time");
this.mtime = time;
this.time = time.to(TimeUnit.MILLISECONDS);
return this;
}
/**
* Returns the last modification time of the entry.
*
* <p> If the entry is read from a ZIP file or ZIP file formatted
* input stream, this is the last modification time from the zip
* file entry's {@code optional extra data} if the extended timestamp
* fields are present. Otherwise the last modification time is read
* from the entry's {@code date and time fields}, the {@link
* java.util.TimeZone#getDefault() default TimeZone} is used to convert
* the standard MS-DOS formatted date and time to the epoch time.
*
* @return The last modification time of the entry, null if not specified
*
* @see #setLastModifiedTime(FileTime)
* @since 1.8
*/
public FileTime getLastModifiedTime() {
if (mtime != null)
return mtime; return mtime;
if (time == -1)
return null;
return FileTime.from(time, TimeUnit.MILLISECONDS);
}
/**
* Sets the last access time of the entry.
*
* <p> If set, the last access time will be stored into the extended
* timestamp fields of entry's {@code optional extra data}, when output
* to a ZIP file or ZIP file formatted stream.
*
* @param time
* The last access time of the entry
* @return This zip entry
*
* @throws NullPointerException if the {@code time} is null
*
* @see #getLastAccessTime()
* @since 1.8
*/
public ZipEntry setLastAccessTime(FileTime time) {
Objects.requireNonNull(name, "time");
this.atime = time;
return this;
}
/**
* Returns the last access time of the entry.
*
* <p> The last access time is from the extended timestamp fields
* of entry's {@code optional extra data} when read from a ZIP file
* or ZIP file formatted stream.
*
* @return The last access time of the entry, null if not specified
* @see #setLastAccessTime(long)
* @since 1.8
*/
public FileTime getLastAccessTime() {
return atime;
}
/**
* Sets the creation time of the entry.
*
* <p> If set, the creation time will be stored into the extended
* timestamp fields of entry's {@code optional extra data}, when
* output to a ZIP file or ZIP file formatted stream.
*
* @param time
* The creation time of the entry
* @return This zip entry
*
* @throws NullPointerException if the {@code time} is null
*
* @see #getCreationTime()
* @since 1.8
*/
public ZipEntry setCreationTime(FileTime time) {
Objects.requireNonNull(name, "time");
this.ctime = time;
return this;
}
/**
* Returns the creation time of the entry.
*
* <p> The creation time is from the extended timestamp fields of
* entry's {@code optional extra data} when read from a ZIP file
* or ZIP file formatted stream.
*
* @return the creation time of the entry, null if not specified
* @see #setCreationTime(FileTime)
* @since 1.8
*/
public FileTime getCreationTime() {
return ctime;
} }
/** /**
* Sets the uncompressed size of the entry data. * Sets the uncompressed size of the entry data.
*
* @param size the uncompressed size in bytes * @param size the uncompressed size in bytes
* @exception IllegalArgumentException if the specified size is less *
* @throws IllegalArgumentException if the specified size is less
* than 0, is greater than 0xFFFFFFFF when * than 0, is greater than 0xFFFFFFFF when
* <a href="package-summary.html#zip64">ZIP64 format</a> is not supported, * <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
* or is less than 0 when ZIP64 is supported * or is less than 0 when ZIP64 is supported
...@@ -140,7 +302,8 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -140,7 +302,8 @@ class ZipEntry implements ZipConstants, Cloneable {
} }
/** /**
* Returns the uncompressed size of the entry data, or -1 if not known. * Returns the uncompressed size of the entry data.
*
* @return the uncompressed size of the entry data, or -1 if not known * @return the uncompressed size of the entry data, or -1 if not known
* @see #setSize(long) * @see #setSize(long)
*/ */
...@@ -149,9 +312,11 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -149,9 +312,11 @@ class ZipEntry implements ZipConstants, Cloneable {
} }
/** /**
* Returns the size of the compressed entry data, or -1 if not known. * Returns the size of the compressed entry data.
* In the case of a stored entry, the compressed size will be the same *
* <p> In the case of a stored entry, the compressed size will be the same
* as the uncompressed size of the entry. * as the uncompressed size of the entry.
*
* @return the size of the compressed entry data, or -1 if not known * @return the size of the compressed entry data, or -1 if not known
* @see #setCompressedSize(long) * @see #setCompressedSize(long)
*/ */
...@@ -161,7 +326,9 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -161,7 +326,9 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Sets the size of the compressed entry data. * Sets the size of the compressed entry data.
*
* @param csize the compressed size to set to * @param csize the compressed size to set to
*
* @see #getCompressedSize() * @see #getCompressedSize()
*/ */
public void setCompressedSize(long csize) { public void setCompressedSize(long csize) {
...@@ -170,8 +337,10 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -170,8 +337,10 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Sets the CRC-32 checksum of the uncompressed entry data. * Sets the CRC-32 checksum of the uncompressed entry data.
*
* @param crc the CRC-32 value * @param crc the CRC-32 value
* @exception IllegalArgumentException if the specified CRC-32 value is *
* @throws IllegalArgumentException if the specified CRC-32 value is
* less than 0 or greater than 0xFFFFFFFF * less than 0 or greater than 0xFFFFFFFF
* @see #getCrc() * @see #getCrc()
*/ */
...@@ -183,10 +352,11 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -183,10 +352,11 @@ class ZipEntry implements ZipConstants, Cloneable {
} }
/** /**
* Returns the CRC-32 checksum of the uncompressed entry data, or -1 if * Returns the CRC-32 checksum of the uncompressed entry data.
* not known. *
* @return the CRC-32 checksum of the uncompressed entry data, or -1 if * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
* not known * not known
*
* @see #setCrc(long) * @see #setCrc(long)
*/ */
public long getCrc() { public long getCrc() {
...@@ -195,8 +365,10 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -195,8 +365,10 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Sets the compression method for the entry. * Sets the compression method for the entry.
*
* @param method the compression method, either STORED or DEFLATED * @param method the compression method, either STORED or DEFLATED
* @exception IllegalArgumentException if the specified compression *
* @throws IllegalArgumentException if the specified compression
* method is invalid * method is invalid
* @see #getMethod() * @see #getMethod()
*/ */
...@@ -208,7 +380,8 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -208,7 +380,8 @@ class ZipEntry implements ZipConstants, Cloneable {
} }
/** /**
* Returns the compression method of the entry, or -1 if not specified. * Returns the compression method of the entry.
*
* @return the compression method of the entry, or -1 if not specified * @return the compression method of the entry, or -1 if not specified
* @see #setMethod(int) * @see #setMethod(int)
*/ */
...@@ -218,21 +391,104 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -218,21 +391,104 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Sets the optional extra field data for the entry. * Sets the optional extra field data for the entry.
* @param extra the extra field data bytes *
* @exception IllegalArgumentException if the length of the specified * <p> Invoking this method may change this entry's last modification
* time, last access time and creation time, if the {@code extra} field
* data includes the extensible timestamp fields, such as {@code NTFS tag
* 0x0001} or {@code Info-ZIP Extended Timestamp}, as specified in
* <a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">Info-ZIP
* Application Note 970311</a>.
*
* @param extra
* The extra field data bytes
*
* @throws IllegalArgumentException if the length of the specified
* extra field data is greater than 0xFFFF bytes * extra field data is greater than 0xFFFF bytes
*
* @see #getExtra() * @see #getExtra()
*/ */
public void setExtra(byte[] extra) { public void setExtra(byte[] extra) {
if (extra != null && extra.length > 0xFFFF) { setExtra0(extra, false);
}
/**
* Sets the optional extra field data for the entry.
*
* @param extra
* the extra field data bytes
* @param doZIP64
* if true, set size and csize from ZIP64 fields if present
*/
void setExtra0(byte[] extra, boolean doZIP64) {
if (extra != null) {
if (extra.length > 0xFFFF) {
throw new IllegalArgumentException("invalid extra field length"); throw new IllegalArgumentException("invalid extra field length");
} }
// extra fields are in "HeaderID(2)DataSize(2)Data... format
int off = 0;
int len = extra.length;
while (off + 4 < len) {
int tag = get16(extra, off);
int sz = get16(extra, off + 2);
off += 4;
if (off + sz > len) // invalid data
break;
switch (tag) {
case EXTID_ZIP64:
if (doZIP64) {
// LOC extra zip64 entry MUST include BOTH original
// and compressed file size fields.
// If invalid zip64 extra fields, simply skip. Even
// it's rare, it's possible the entry size happens to
// be the magic value and it "accidently" has some
// bytes in extra match the id.
if (sz >= 16) {
size = get64(extra, off);
csize = get64(extra, off + 8);
}
}
break;
case EXTID_NTFS:
int pos = off + 4; // reserved 4 bytes
if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24)
break;
mtime = winTimeToFileTime(get64(extra, pos + 4));
atime = winTimeToFileTime(get64(extra, pos + 12));
ctime = winTimeToFileTime(get64(extra, pos + 20));
break;
case EXTID_EXTT:
int flag = Byte.toUnsignedInt(extra[off]);
int sz0 = 1;
// The CEN-header extra field contains the modification
// time only, or no timestamp at all. 'sz' is used to
// flag its presence or absence. But if mtime is present
// in LOC it must be present in CEN as well.
if ((flag & 0x1) != 0 && (sz0 + 4) <= sz) {
mtime = unixTimeToFileTime(get32(extra, off + sz0));
sz0 += 4;
}
if ((flag & 0x2) != 0 && (sz0 + 4) <= sz) {
atime = unixTimeToFileTime(get32(extra, off + sz0));
sz0 += 4;
}
if ((flag & 0x4) != 0 && (sz0 + 4) <= sz) {
ctime = unixTimeToFileTime(get32(extra, off + sz0));
sz0 += 4;
}
break;
default:
}
off += sz;
}
}
this.extra = extra; this.extra = extra;
} }
/** /**
* Returns the extra field data for the entry, or null if none. * Returns the extra field data for the entry.
*
* @return the extra field data for the entry, or null if none * @return the extra field data for the entry, or null if none
*
* @see #setExtra(byte[]) * @see #setExtra(byte[])
*/ */
public byte[] getExtra() { public byte[] getExtra() {
...@@ -255,8 +511,10 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -255,8 +511,10 @@ class ZipEntry implements ZipConstants, Cloneable {
} }
/** /**
* Returns the comment string for the entry, or null if none. * Returns the comment string for the entry.
*
* @return the comment string for the entry, or null if none * @return the comment string for the entry, or null if none
*
* @see #setComment(String) * @see #setComment(String)
*/ */
public String getComment() { public String getComment() {
......
/* /*
* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2013, 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
...@@ -567,44 +567,12 @@ class ZipFile implements ZipConstants, Closeable { ...@@ -567,44 +567,12 @@ class ZipFile implements ZipConstants, Closeable {
e.name = zc.toString(bname, bname.length); e.name = zc.toString(bname, bname.length);
} }
} }
e.time = dosToJavaTime(getEntryTime(jzentry));
e.crc = getEntryCrc(jzentry); e.crc = getEntryCrc(jzentry);
e.size = getEntrySize(jzentry); e.size = getEntrySize(jzentry);
e. csize = getEntryCSize(jzentry); e.csize = getEntryCSize(jzentry);
e.method = getEntryMethod(jzentry); e.method = getEntryMethod(jzentry);
e.extra = getEntryBytes(jzentry, JZENTRY_EXTRA); e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
if (e.extra != null) {
byte[] extra = e.extra;
int len = e.extra.length;
int off = 0;
while (off + 4 < len) {
int pos = off;
int tag = get16(extra, pos);
int sz = get16(extra, pos + 2);
pos += 4;
if (pos + sz > len) // invalid data
break;
switch (tag) {
case EXTID_NTFS:
pos += 4; // reserved 4 bytes
if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24)
break;
e.mtime = winToJavaTime(get64(extra, pos + 4));
break;
case EXTID_EXTT:
int flag = Byte.toUnsignedInt(extra[pos++]);
if ((flag & 0x1) != 0) {
e.mtime = unixToJavaTime(get32(extra, pos));
pos += 4;
}
break;
default: // unknown tag
}
off += (sz + 4);
}
}
if (e.mtime == -1) {
e.mtime = dosToJavaTime(getEntryTime(jzentry));
}
byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT); byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
if (bcomm == null) { if (bcomm == null) {
e.comment = null; e.comment = null;
......
/* /*
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1996, 2013, 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
...@@ -288,9 +288,9 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -288,9 +288,9 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
int len = get16(tmpbuf, LOCNAM); int len = get16(tmpbuf, LOCNAM);
int blen = b.length; int blen = b.length;
if (len > blen) { if (len > blen) {
do do {
blen = blen * 2; blen = blen * 2;
while (len > blen); } while (len > blen);
b = new byte[blen]; b = new byte[blen];
} }
readFully(b, 0, len); readFully(b, 0, len);
...@@ -303,7 +303,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -303,7 +303,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
throw new ZipException("encrypted ZIP entry not supported"); throw new ZipException("encrypted ZIP entry not supported");
} }
e.method = get16(tmpbuf, LOCHOW); e.method = get16(tmpbuf, LOCHOW);
e.mtime = dosToJavaTime(get32(tmpbuf, LOCTIM)); e.time = dosToJavaTime(get32(tmpbuf, LOCTIM));
if ((flag & 8) == 8) { if ((flag & 8) == 8) {
/* "Data Descriptor" present */ /* "Data Descriptor" present */
if (e.method != DEFLATED) { if (e.method != DEFLATED) {
...@@ -319,49 +319,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -319,49 +319,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
if (len > 0) { if (len > 0) {
byte[] extra = new byte[len]; byte[] extra = new byte[len];
readFully(extra, 0, len); readFully(extra, 0, len);
e.setExtra(extra); e.setExtra0(extra, true);
// extra fields are in "HeaderID(2)DataSize(2)Data... format
int off = 0;
while (off + 4 < len) {
int pos = off;
int tag = get16(extra, pos);
int sz = get16(extra, pos + 2);
pos += 4;
if (pos + sz > len) // invalid data
break;
switch (tag) {
case EXTID_ZIP64 :
// LOC extra zip64 entry MUST include BOTH original and
// compressed file size fields.
//
// If invalid zip64 extra fields, simply skip. Even it's
// rare, it's possible the entry size happens to be
// the magic value and it "accidently" has some bytes
// in extra match the id.
if (sz >= 16 && (pos + sz) <= len ) {
e.size = get64(extra, pos);
e.csize = get64(extra, pos + 8);
}
break;
case EXTID_NTFS:
pos += 4; // reserved 4 bytes
if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24)
break;
// override the loc field, NTFS time has 'microsecond' granularity
e.mtime = winToJavaTime(get64(extra, pos + 4));
break;
case EXTID_EXTT:
int flag = Byte.toUnsignedInt(extra[pos++]);
if ((flag & 0x1) != 0) {
e.mtime = unixToJavaTime(get32(extra, pos));
pos += 4;
}
break;
default: // unknown tag
}
off += (sz + 4);
}
} }
return e; return e;
} }
......
...@@ -59,8 +59,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -59,8 +59,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
"jdk.util.zip.inhibitZip64", "false"))); "jdk.util.zip.inhibitZip64", "false")));
private static class XEntry { private static class XEntry {
public final ZipEntry entry; final ZipEntry entry;
public final long offset; final long offset;
long dostime; // last modification time in msdos format
public XEntry(ZipEntry entry, long offset) { public XEntry(ZipEntry entry, long offset) {
this.entry = entry; this.entry = entry;
this.offset = offset; this.offset = offset;
...@@ -191,7 +192,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -191,7 +192,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (current != null) { if (current != null) {
closeEntry(); // close previous entry closeEntry(); // close previous entry
} }
if (e.mtime == -1) { if (e.time == -1) {
// by default, do NOT use extended timestamps in extra
// data, for now.
e.setTime(System.currentTimeMillis()); e.setTime(System.currentTimeMillis());
} }
if (e.method == -1) { if (e.method == -1) {
...@@ -384,25 +387,20 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -384,25 +387,20 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
ZipEntry e = xentry.entry; ZipEntry e = xentry.entry;
int flag = e.flag; int flag = e.flag;
boolean hasZip64 = false; boolean hasZip64 = false;
int elen = (e.extra != null) ? e.extra.length : 0; int elen = getExtraLen(e.extra);
int eoff = 0;
boolean foundEXTT = false; // if EXTT already present // keep a copy of dostime for writeCEN(), otherwise the tz
// do nothing. // sensitive local time entries in loc and cen might be
while (eoff + 4 < elen) { // different if the default tz get changed during writeLOC()
int tag = get16(e.extra, eoff); // and writeCEN()
int sz = get16(e.extra, eoff + 2); xentry.dostime = javaToDosTime(e.time);
if (tag == EXTID_EXTT) {
foundEXTT = true;
}
eoff += (4 + sz);
}
writeInt(LOCSIG); // LOC header signature writeInt(LOCSIG); // LOC header signature
if ((flag & 8) == 8) { if ((flag & 8) == 8) {
writeShort(version(e)); // version needed to extract writeShort(version(e)); // version needed to extract
writeShort(flag); // general purpose bit flag writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method writeShort(e.method); // compression method
writeInt(javaToDosTime(e.mtime)); // last modification time writeInt(xentry.dostime); // last modification time
// store size, uncompressed size, and crc-32 in data descriptor // store size, uncompressed size, and crc-32 in data descriptor
// immediately following compressed entry data // immediately following compressed entry data
writeInt(0); writeInt(0);
...@@ -417,7 +415,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -417,7 +415,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
} }
writeShort(flag); // general purpose bit flag writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method writeShort(e.method); // compression method
writeInt(javaToDosTime(e.mtime)); // last modification time writeInt(xentry.dostime); // last modification time
writeInt(e.crc); // crc-32 writeInt(e.crc); // crc-32
if (hasZip64) { if (hasZip64) {
writeInt(ZIP64_MAGICVAL); writeInt(ZIP64_MAGICVAL);
...@@ -430,8 +428,23 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -430,8 +428,23 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
} }
byte[] nameBytes = zc.getBytes(e.name); byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length); writeShort(nameBytes.length);
if (!foundEXTT)
elen += 9; // use Info-ZIP's ext time in extra int elenEXTT = 0; // info-zip extended timestamp
int flagEXTT = 0;
if (e.mtime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAG_LMT;
}
if (e.atime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAG_LAT;
}
if (e.ctime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAT_CT;
}
if (flagEXTT != 0)
elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
writeShort(elen); writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length); writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) { if (hasZip64) {
...@@ -440,15 +453,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -440,15 +453,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeLong(e.size); writeLong(e.size);
writeLong(e.csize); writeLong(e.csize);
} }
if (!foundEXTT) { if (flagEXTT != 0) {
writeShort(EXTID_EXTT); writeShort(EXTID_EXTT);
writeShort(5); // size for the folowing data block writeShort(elenEXTT + 1); // flag + data
writeByte(0x1); // flags byte, mtime only writeByte(flagEXTT);
writeInt(javaToUnixTime(e.mtime)); if (e.mtime != null)
} writeInt(fileTimeToUnixTime(e.mtime));
if (e.extra != null) { if (e.atime != null)
writeBytes(e.extra, 0, e.extra.length); writeInt(fileTimeToUnixTime(e.atime));
} if (e.ctime != null)
writeInt(fileTimeToUnixTime(e.ctime));
}
writeExtra(e.extra);
locoff = written; locoff = written;
} }
...@@ -506,31 +522,35 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -506,31 +522,35 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
} }
writeShort(flag); // general purpose bit flag writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method writeShort(e.method); // compression method
writeInt(javaToDosTime(e.mtime)); // last modification time // use the copy in xentry, which has been converted
// from e.time in writeLOC()
writeInt(xentry.dostime); // last modification time
writeInt(e.crc); // crc-32 writeInt(e.crc); // crc-32
writeInt(csize); // compressed size writeInt(csize); // compressed size
writeInt(size); // uncompressed size writeInt(size); // uncompressed size
byte[] nameBytes = zc.getBytes(e.name); byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length); writeShort(nameBytes.length);
int elen = (e.extra != null) ? e.extra.length : 0; int elen = getExtraLen(e.extra);
int eoff = 0; if (hasZip64) {
boolean foundEXTT = false; // if EXTT already present elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
// do nothing.
while (eoff + 4 < elen) {
int tag = get16(e.extra, eoff);
int sz = get16(e.extra, eoff + 2);
if (tag == EXTID_EXTT) {
foundEXTT = true;
} }
eoff += (4 + sz); // cen info-zip extended timestamp only outputs mtime
// but set the flag for a/ctime, if present in loc
int flagEXTT = 0;
if (e.mtime != null) {
elen += 4; // + mtime(4)
flagEXTT |= EXTT_FLAG_LMT;
} }
if (hasZip64) { if (e.atime != null) {
// + headid(2) + datasize(2) flagEXTT |= EXTT_FLAG_LAT;
elen += (elenZIP64 + 4); }
if (e.ctime != null) {
flagEXTT |= EXTT_FLAT_CT;
}
if (flagEXTT != 0) {
elen += 5; // headid + sz + flag
} }
if (!foundEXTT)
elen += 9; // Info-ZIP's Extended Timestamp
writeShort(elen); writeShort(elen);
byte[] commentBytes; byte[] commentBytes;
if (e.comment != null) { if (e.comment != null) {
...@@ -545,6 +565,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -545,6 +565,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(0); // external file attributes (unused) writeInt(0); // external file attributes (unused)
writeInt(offset); // relative offset of local header writeInt(offset); // relative offset of local header
writeBytes(nameBytes, 0, nameBytes.length); writeBytes(nameBytes, 0, nameBytes.length);
// take care of EXTID_ZIP64 and EXTID_EXTT
if (hasZip64) { if (hasZip64) {
writeShort(ZIP64_EXTID);// Zip64 extra writeShort(ZIP64_EXTID);// Zip64 extra
writeShort(elenZIP64); writeShort(elenZIP64);
...@@ -555,15 +577,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -555,15 +577,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (offset == ZIP64_MAGICVAL) if (offset == ZIP64_MAGICVAL)
writeLong(xentry.offset); writeLong(xentry.offset);
} }
if (!foundEXTT) { if (flagEXTT != 0) {
writeShort(EXTID_EXTT); writeShort(EXTID_EXTT);
writeShort(5); if (e.mtime != null) {
writeByte(0x1); // flags byte writeShort(5); // flag + mtime
writeInt(javaToUnixTime(e.mtime)); writeByte(flagEXTT);
writeInt(fileTimeToUnixTime(e.mtime));
} else {
writeShort(1); // flag only
writeByte(flagEXTT);
} }
if (e.extra != null) {
writeBytes(e.extra, 0, e.extra.length);
} }
writeExtra(e.extra);
if (commentBytes != null) { if (commentBytes != null) {
writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff)); writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
} }
...@@ -626,6 +651,47 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -626,6 +651,47 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
} }
} }
/*
* Returns the length of extra data without EXTT and ZIP64.
*/
private int getExtraLen(byte[] extra) {
if (extra == null)
return 0;
int skipped = 0;
int len = extra.length;
int off = 0;
while (off + 4 <= len) {
int tag = get16(extra, off);
int sz = get16(extra, off + 2);
if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
skipped += (sz + 4);
}
off += (sz + 4);
}
return len - skipped;
}
/*
* Writes extra data without EXTT and ZIP64.
*
* Extra timestamp and ZIP64 data is handled/output separately
* in writeLOC and writeCEN.
*/
private void writeExtra(byte[] extra) throws IOException {
if (extra != null) {
int len = extra.length;
int off = 0;
while (off + 4 <= len) {
int tag = get16(extra, off);
int sz = get16(extra, off + 2);
if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
writeBytes(extra, off, sz + 4);
}
off += (sz + 4);
}
}
}
/* /*
* Writes a 8-bit byte to the output stream. * Writes a 8-bit byte to the output stream.
*/ */
......
...@@ -25,42 +25,45 @@ ...@@ -25,42 +25,45 @@
package java.util.zip; package java.util.zip;
import java.nio.file.attribute.FileTime;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static java.util.zip.ZipConstants.*;
import static java.util.zip.ZipConstants64.*;
class ZipUtils { class ZipUtils {
// used to adjust values between Windows and java epoch // used to adjust values between Windows and java epoch
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L; private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
/** /**
* Converts Windows time (in microseconds, UTC/GMT) time to Java time. * Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
*/ */
public static final long winToJavaTime(long wtime) { public static final FileTime winTimeToFileTime(long wtime) {
return TimeUnit.MILLISECONDS.convert( return FileTime.from(wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS,
wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS); TimeUnit.MICROSECONDS);
} }
/** /**
* Converts Java time to Windows time. * Converts FileTime to Windows time.
*/ */
public static final long javaToWinTime(long time) { public static final long fileTimeToWinTime(FileTime ftime) {
return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS) return (ftime.to(TimeUnit.MICROSECONDS) - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
- WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
} }
/** /**
* Converts "standard Unix time"(in seconds, UTC/GMT) to Java time * Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
*/ */
public static final long unixToJavaTime(long utime) { public static final FileTime unixTimeToFileTime(long utime) {
return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS); return FileTime.from(utime, TimeUnit.SECONDS);
} }
/** /**
* Converts Java time to "standard Unix time". * Converts FileTime to "standard Unix time".
*/ */
public static final long javaToUnixTime(long time) { public static final long fileTimeToUnixTime(FileTime ftime) {
return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS); return ftime.to(TimeUnit.SECONDS);
} }
/** /**
...@@ -92,7 +95,6 @@ class ZipUtils { ...@@ -92,7 +95,6 @@ class ZipUtils {
d.getSeconds() >> 1; d.getSeconds() >> 1;
} }
/** /**
* Fetches unsigned 16-bit value from byte array at specified offset. * Fetches unsigned 16-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order. * The bytes are assumed to be in Intel (little-endian) byte order.
...@@ -116,5 +118,4 @@ class ZipUtils { ...@@ -116,5 +118,4 @@ class ZipUtils {
public static final long get64(byte b[], int off) { public static final long get64(byte b[], int off) {
return get32(b, off) | (get32(b, off+4) << 32); return get32(b, off) | (get32(b, off+4) << 32);
} }
} }
...@@ -335,8 +335,6 @@ sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all ...@@ -335,8 +335,6 @@ sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all
# Tests take too long, on sparcs see 7143279 # Tests take too long, on sparcs see 7143279
tools/pack200/CommandLineTests.java solaris-all, macosx-all tools/pack200/CommandLineTests.java solaris-all, macosx-all
tools/pack200/Pack200Test.java solaris-all, macosx-all tools/pack200/Pack200Test.java solaris-all, macosx-all
# 8015666
tools/pack200/TimeStamp.java generic-all
# 8007410 # 8007410
tools/launcher/FXLauncherTest.java linux-all tools/launcher/FXLauncherTest.java linux-all
......
...@@ -23,14 +23,19 @@ ...@@ -23,14 +23,19 @@
/** /**
* @test * @test
* @bug 4759491 6303183 7012868 * @bug 4759491 6303183 7012868 8015666
* @summary Test ZOS and ZIS timestamp in extra field correctly * @summary Test ZOS and ZIS timestamp in extra field correctly
*/ */
import java.io.*; import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
...@@ -41,14 +46,32 @@ public class TestExtraTime { ...@@ -41,14 +46,32 @@ public class TestExtraTime {
File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java"); File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
if (src.exists()) { if (src.exists()) {
long mtime = src.lastModified(); long time = src.lastModified();
test(mtime, null); FileTime mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
test(10, null); // ms-dos 1980 epoch problem FileTime atime = FileTime.from(time + 300000, TimeUnit.MILLISECONDS);
test(mtime, TimeZone.getTimeZone("Asia/Shanghai")); FileTime ctime = FileTime.from(time - 300000, TimeUnit.MILLISECONDS);
TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
test(mtime, null, null, null);
// ms-dos 1980 epoch problem
test(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null);
// non-default tz
test(mtime, null, null, tz);
test(mtime, atime, null, null);
test(mtime, null, ctime, null);
test(mtime, atime, ctime, null);
test(mtime, atime, null, tz);
test(mtime, null, ctime, tz);
test(mtime, atime, ctime, tz);
} }
} }
private static void test(long mtime, TimeZone tz) throws Throwable { static void test(FileTime mtime, FileTime atime, FileTime ctime,
TimeZone tz) throws Throwable {
System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n",
mtime, atime, ctime);
TimeZone tz0 = TimeZone.getDefault(); TimeZone tz0 = TimeZone.getDefault();
if (tz != null) { if (tz != null) {
TimeZone.setDefault(tz); TimeZone.setDefault(tz);
...@@ -57,23 +80,55 @@ public class TestExtraTime { ...@@ -57,23 +80,55 @@ public class TestExtraTime {
ZipOutputStream zos = new ZipOutputStream(baos); ZipOutputStream zos = new ZipOutputStream(baos);
ZipEntry ze = new ZipEntry("TestExtreTime.java"); ZipEntry ze = new ZipEntry("TestExtreTime.java");
ze.setTime(mtime); ze.setLastModifiedTime(mtime);
if (atime != null)
ze.setLastAccessTime(atime);
if (ctime != null)
ze.setCreationTime(ctime);
zos.putNextEntry(ze); zos.putNextEntry(ze);
zos.write(new byte[] { 1,2 ,3, 4}); zos.write(new byte[] { 1,2 ,3, 4});
zos.close(); zos.close();
if (tz != null) { if (tz != null) {
TimeZone.setDefault(tz0); TimeZone.setDefault(tz0);
} }
// ZipInputStream
ZipInputStream zis = new ZipInputStream( ZipInputStream zis = new ZipInputStream(
new ByteArrayInputStream(baos.toByteArray())); new ByteArrayInputStream(baos.toByteArray()));
ze = zis.getNextEntry(); ze = zis.getNextEntry();
zis.close(); zis.close();
check(mtime, atime, ctime, ze);
System.out.printf("%tc => %tc%n", mtime, ze.getTime()); // ZipFile
Path zpath = Paths.get(System.getProperty("test.dir", "."),
if (TimeUnit.MILLISECONDS.toSeconds(mtime) != "TestExtraTimp.zip");
TimeUnit.MILLISECONDS.toSeconds(ze.getTime())) Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
throw new RuntimeException("Timestamp storing failed!"); ZipFile zf = new ZipFile(zpath.toFile());
ze = zf.getEntry("TestExtreTime.java");
// ZipFile read entry from cen, which does not have a/ctime,
// for now.
check(mtime, null, null, ze);
zf.close();
Files.delete(zpath);
}
static void check(FileTime mtime, FileTime atime, FileTime ctime,
ZipEntry ze) {
/*
System.out.printf(" mtime [%tc]: [%tc]/[%tc]%n",
mtime.to(TimeUnit.MILLISECONDS),
ze.getTime(),
ze.getLastModifiedTime().to(TimeUnit.MILLISECONDS));
*/
if (mtime.to(TimeUnit.SECONDS) !=
ze.getLastModifiedTime().to(TimeUnit.SECONDS))
throw new RuntimeException("Timestamp: storing mtime failed!");
if (atime != null &&
atime.to(TimeUnit.SECONDS) !=
ze.getLastAccessTime().to(TimeUnit.SECONDS))
throw new RuntimeException("Timestamp: storing atime failed!");
if (ctime != null &&
ctime.to(TimeUnit.SECONDS) !=
ze.getCreationTime().to(TimeUnit.SECONDS))
throw new RuntimeException("Timestamp: storing ctime failed!");
} }
} }
...@@ -88,6 +88,7 @@ public class TimeStamp { ...@@ -88,6 +88,7 @@ public class TimeStamp {
unpackNative(packFile, pstFile); unpackNative(packFile, pstFile);
verifyJar(goldenFile, pstFile); verifyJar(goldenFile, pstFile);
pstFile.delete(); pstFile.delete();
Utils.cleanup();
} }
static void unpackNative(File packFile, File outFile) { static void unpackNative(File packFile, File outFile) {
...@@ -149,7 +150,6 @@ public class TimeStamp { ...@@ -149,7 +150,6 @@ public class TimeStamp {
Utils.close(jf1); Utils.close(jf1);
Utils.close(jf2); Utils.close(jf2);
} }
Utils.cleanup();
if (errors > 0) { if (errors > 0) {
throw new RuntimeException("FAIL:" + errors + " error(s) encounted"); throw new RuntimeException("FAIL:" + errors + " error(s) encounted");
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册