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

To keep the default behavior of ZOS unchanged, if ze extra time not explicitly set

Reviewed-by: alanb, ksrini
This commit is contained in:
Xueming Shen 2013-08-08 12:03:04 -07:00
parent dc14220ea6
commit dca36c08f3
9 changed files with 518 additions and 207 deletions

View File

@ -71,10 +71,17 @@ interface ZipConstants {
/*
* Extra field header ID
*/
static final int EXTID_ZIP64 = 0x0001; // Zip64
static final int EXTID_NTFS = 0x000a; // NTFS
static final int EXTID_UNIX = 0x000d; // UNIX
static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp
static final int EXTID_ZIP64 = 0x0001; // Zip64
static final int EXTID_NTFS = 0x000a; // NTFS
static final int EXTID_UNIX = 0x000d; // UNIX
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

View File

@ -1,5 +1,5 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,11 @@
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.
*
@ -32,8 +37,12 @@ package java.util.zip;
*/
public
class ZipEntry implements ZipConstants, Cloneable {
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 size = -1; // uncompressed size of entry data
long csize = -1; // compressed size of entry data
@ -55,15 +64,15 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* Creates a new zip entry with the specified name.
*
* @param name the entry name
* @exception NullPointerException if the entry name is null
* @exception IllegalArgumentException if the entry name is longer than
* 0xFFFF bytes
* @param name
* The entry name
*
* @throws NullPointerException if the entry name is null
* @throws IllegalArgumentException if the entry name is longer than
* 0xFFFF bytes
*/
public ZipEntry(String name) {
if (name == null) {
throw new NullPointerException();
}
Objects.requireNonNull(name, "name");
if (name.length() > 0xFFFF) {
throw new IllegalArgumentException("entry name too long");
}
@ -73,11 +82,19 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* Creates a new zip entry with fields taken from the specified
* 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) {
Objects.requireNonNull(e, "entry");
name = e.name;
time = e.time;
mtime = e.mtime;
atime = e.atime;
ctime = e.ctime;
crc = e.crc;
size = e.size;
csize = e.csize;
@ -103,33 +120,178 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* 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 #getLastModifiedTime()
*/
public void setTime(long time) {
this.mtime = time;
this.time = time;
this.mtime = null;
}
/**
* 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 #setLastModifiedTime(FileTime)
*/
public long getTime() {
return mtime;
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;
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.
*
* @param size the uncompressed size in bytes
* @exception IllegalArgumentException if the specified size is less
* than 0, is greater than 0xFFFFFFFF when
* <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
* or is less than 0 when ZIP64 is supported
*
* @throws IllegalArgumentException if the specified size is less
* than 0, is greater than 0xFFFFFFFF when
* <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
* or is less than 0 when ZIP64 is supported
* @see #getSize()
*/
public void setSize(long size) {
@ -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
* @see #setSize(long)
*/
@ -149,9 +312,11 @@ class ZipEntry implements ZipConstants, Cloneable {
}
/**
* Returns the size of the compressed entry data, or -1 if not known.
* In the case of a stored entry, the compressed size will be the same
* Returns the size of the compressed entry data.
*
* <p> In the case of a stored entry, the compressed size will be the same
* as the uncompressed size of the entry.
*
* @return the size of the compressed entry data, or -1 if not known
* @see #setCompressedSize(long)
*/
@ -161,7 +326,9 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the size of the compressed entry data.
*
* @param csize the compressed size to set to
*
* @see #getCompressedSize()
*/
public void setCompressedSize(long csize) {
@ -170,9 +337,11 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the CRC-32 checksum of the uncompressed entry data.
*
* @param crc the CRC-32 value
* @exception IllegalArgumentException if the specified CRC-32 value is
* less than 0 or greater than 0xFFFFFFFF
*
* @throws IllegalArgumentException if the specified CRC-32 value is
* less than 0 or greater than 0xFFFFFFFF
* @see #getCrc()
*/
public void setCrc(long crc) {
@ -183,10 +352,11 @@ class ZipEntry implements ZipConstants, Cloneable {
}
/**
* Returns the CRC-32 checksum of the uncompressed entry data, or -1 if
* not known.
* Returns the CRC-32 checksum of the uncompressed entry data.
*
* @return the CRC-32 checksum of the uncompressed entry data, or -1 if
* not known
*
* @see #setCrc(long)
*/
public long getCrc() {
@ -195,9 +365,11 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the compression method for the entry.
*
* @param method the compression method, either STORED or DEFLATED
* @exception IllegalArgumentException if the specified compression
* method is invalid
*
* @throws IllegalArgumentException if the specified compression
* method is invalid
* @see #getMethod()
*/
public void setMethod(int method) {
@ -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
* @see #setMethod(int)
*/
@ -218,21 +391,104 @@ class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the optional extra field data for the entry.
* @param extra the extra field data bytes
* @exception IllegalArgumentException if the length of the specified
* extra field data is greater than 0xFFFF bytes
*
* <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
*
* @see #getExtra()
*/
public void setExtra(byte[] extra) {
if (extra != null && extra.length > 0xFFFF) {
throw new IllegalArgumentException("invalid extra field length");
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");
}
// 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;
}
/**
* 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
*
* @see #setExtra(byte[])
*/
public byte[] getExtra() {
@ -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
*
* @see #setComment(String)
*/
public String getComment() {

View File

@ -1,5 +1,5 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
@ -567,44 +567,12 @@ class ZipFile implements ZipConstants, Closeable {
e.name = zc.toString(bname, bname.length);
}
}
e.time = dosToJavaTime(getEntryTime(jzentry));
e.crc = getEntryCrc(jzentry);
e.size = getEntrySize(jzentry);
e. csize = getEntryCSize(jzentry);
e.csize = getEntryCSize(jzentry);
e.method = getEntryMethod(jzentry);
e.extra = getEntryBytes(jzentry, JZENTRY_EXTRA);
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));
}
e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
if (bcomm == null) {
e.comment = null;

View File

@ -1,5 +1,5 @@
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
@ -288,9 +288,9 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
int len = get16(tmpbuf, LOCNAM);
int blen = b.length;
if (len > blen) {
do
do {
blen = blen * 2;
while (len > blen);
} while (len > blen);
b = new byte[blen];
}
readFully(b, 0, len);
@ -303,7 +303,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
throw new ZipException("encrypted ZIP entry not supported");
}
e.method = get16(tmpbuf, LOCHOW);
e.mtime = dosToJavaTime(get32(tmpbuf, LOCTIM));
e.time = dosToJavaTime(get32(tmpbuf, LOCTIM));
if ((flag & 8) == 8) {
/* "Data Descriptor" present */
if (e.method != DEFLATED) {
@ -319,49 +319,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
if (len > 0) {
byte[] extra = new byte[len];
readFully(extra, 0, len);
e.setExtra(extra);
// 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);
}
e.setExtra0(extra, true);
}
return e;
}

View File

@ -59,8 +59,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
"jdk.util.zip.inhibitZip64", "false")));
private static class XEntry {
public final ZipEntry entry;
public final long offset;
final ZipEntry entry;
final long offset;
long dostime; // last modification time in msdos format
public XEntry(ZipEntry entry, long offset) {
this.entry = entry;
this.offset = offset;
@ -191,7 +192,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (current != null) {
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());
}
if (e.method == -1) {
@ -384,25 +387,20 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
ZipEntry e = xentry.entry;
int flag = e.flag;
boolean hasZip64 = false;
int elen = (e.extra != null) ? e.extra.length : 0;
int eoff = 0;
boolean foundEXTT = false; // if EXTT already present
// 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);
}
int elen = getExtraLen(e.extra);
// keep a copy of dostime for writeCEN(), otherwise the tz
// sensitive local time entries in loc and cen might be
// different if the default tz get changed during writeLOC()
// and writeCEN()
xentry.dostime = javaToDosTime(e.time);
writeInt(LOCSIG); // LOC header signature
if ((flag & 8) == 8) {
writeShort(version(e)); // version needed to extract
writeShort(flag); // general purpose bit flag
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
// immediately following compressed entry data
writeInt(0);
@ -417,7 +415,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
}
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
writeInt(javaToDosTime(e.mtime)); // last modification time
writeInt(xentry.dostime); // last modification time
writeInt(e.crc); // crc-32
if (hasZip64) {
writeInt(ZIP64_MAGICVAL);
@ -430,8 +428,23 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
}
byte[] nameBytes = zc.getBytes(e.name);
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);
writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) {
@ -440,15 +453,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeLong(e.size);
writeLong(e.csize);
}
if (!foundEXTT) {
if (flagEXTT != 0) {
writeShort(EXTID_EXTT);
writeShort(5); // size for the folowing data block
writeByte(0x1); // flags byte, mtime only
writeInt(javaToUnixTime(e.mtime));
}
if (e.extra != null) {
writeBytes(e.extra, 0, e.extra.length);
writeShort(elenEXTT + 1); // flag + data
writeByte(flagEXTT);
if (e.mtime != null)
writeInt(fileTimeToUnixTime(e.mtime));
if (e.atime != null)
writeInt(fileTimeToUnixTime(e.atime));
if (e.ctime != null)
writeInt(fileTimeToUnixTime(e.ctime));
}
writeExtra(e.extra);
locoff = written;
}
@ -506,31 +522,35 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
}
writeShort(flag); // general purpose bit flag
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(csize); // compressed size
writeInt(size); // uncompressed size
byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
int elen = (e.extra != null) ? e.extra.length : 0;
int eoff = 0;
boolean foundEXTT = false; // if EXTT already present
// 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);
}
int elen = getExtraLen(e.extra);
if (hasZip64) {
// + headid(2) + datasize(2)
elen += (elenZIP64 + 4);
elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
}
// 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 (e.atime != null) {
flagEXTT |= EXTT_FLAG_LAT;
}
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);
byte[] commentBytes;
if (e.comment != null) {
@ -545,6 +565,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(0); // external file attributes (unused)
writeInt(offset); // relative offset of local header
writeBytes(nameBytes, 0, nameBytes.length);
// take care of EXTID_ZIP64 and EXTID_EXTT
if (hasZip64) {
writeShort(ZIP64_EXTID);// Zip64 extra
writeShort(elenZIP64);
@ -555,15 +577,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (offset == ZIP64_MAGICVAL)
writeLong(xentry.offset);
}
if (!foundEXTT) {
if (flagEXTT != 0) {
writeShort(EXTID_EXTT);
writeShort(5);
writeByte(0x1); // flags byte
writeInt(javaToUnixTime(e.mtime));
}
if (e.extra != null) {
writeBytes(e.extra, 0, e.extra.length);
if (e.mtime != null) {
writeShort(5); // flag + mtime
writeByte(flagEXTT);
writeInt(fileTimeToUnixTime(e.mtime));
} else {
writeShort(1); // flag only
writeByte(flagEXTT);
}
}
writeExtra(e.extra);
if (commentBytes != null) {
writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
}
@ -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.
*/

View File

@ -25,42 +25,45 @@
package java.util.zip;
import java.nio.file.attribute.FileTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import static java.util.zip.ZipConstants.*;
import static java.util.zip.ZipConstants64.*;
class ZipUtils {
// used to adjust values between Windows and java epoch
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) {
return TimeUnit.MILLISECONDS.convert(
wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS);
public static final FileTime winTimeToFileTime(long wtime) {
return FileTime.from(wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS,
TimeUnit.MICROSECONDS);
}
/**
* Converts Java time to Windows time.
* Converts FileTime to Windows time.
*/
public static final long javaToWinTime(long time) {
return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS)
- WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
public static final long fileTimeToWinTime(FileTime ftime) {
return (ftime.to(TimeUnit.MICROSECONDS) - 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) {
return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS);
public static final FileTime unixTimeToFileTime(long utime) {
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) {
return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS);
public static final long fileTimeToUnixTime(FileTime ftime) {
return ftime.to(TimeUnit.SECONDS);
}
/**
@ -92,7 +95,6 @@ class ZipUtils {
d.getSeconds() >> 1;
}
/**
* Fetches unsigned 16-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order.
@ -116,5 +118,4 @@ class ZipUtils {
public static final long get64(byte b[], int off) {
return get32(b, off) | (get32(b, off+4) << 32);
}
}

View File

@ -335,8 +335,6 @@ sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all
# Tests take too long, on sparcs see 7143279
tools/pack200/CommandLineTests.java solaris-all, macosx-all
tools/pack200/Pack200Test.java solaris-all, macosx-all
# 8015666
tools/pack200/TimeStamp.java generic-all
# 8007410
tools/launcher/FXLauncherTest.java linux-all

View File

@ -23,14 +23,19 @@
/**
* @test
* @bug 4759491 6303183 7012868
* @bug 4759491 6303183 7012868 8015666
* @summary Test ZOS and ZIS timestamp in extra field correctly
*/
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.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@ -41,14 +46,32 @@ public class TestExtraTime {
File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
if (src.exists()) {
long mtime = src.lastModified();
test(mtime, null);
test(10, null); // ms-dos 1980 epoch problem
test(mtime, TimeZone.getTimeZone("Asia/Shanghai"));
long time = src.lastModified();
FileTime mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
FileTime atime = FileTime.from(time + 300000, TimeUnit.MILLISECONDS);
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();
if (tz != null) {
TimeZone.setDefault(tz);
@ -57,23 +80,55 @@ public class TestExtraTime {
ZipOutputStream zos = new ZipOutputStream(baos);
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.write(new byte[] { 1,2 ,3, 4});
zos.close();
if (tz != null) {
TimeZone.setDefault(tz0);
}
// ZipInputStream
ZipInputStream zis = new ZipInputStream(
new ByteArrayInputStream(baos.toByteArray()));
ze = zis.getNextEntry();
zis.close();
check(mtime, atime, ctime, ze);
System.out.printf("%tc => %tc%n", mtime, ze.getTime());
if (TimeUnit.MILLISECONDS.toSeconds(mtime) !=
TimeUnit.MILLISECONDS.toSeconds(ze.getTime()))
throw new RuntimeException("Timestamp storing failed!");
// ZipFile
Path zpath = Paths.get(System.getProperty("test.dir", "."),
"TestExtraTimp.zip");
Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
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!");
}
}

View File

@ -88,6 +88,7 @@ public class TimeStamp {
unpackNative(packFile, pstFile);
verifyJar(goldenFile, pstFile);
pstFile.delete();
Utils.cleanup();
}
static void unpackNative(File packFile, File outFile) {
@ -149,7 +150,6 @@ public class TimeStamp {
Utils.close(jf1);
Utils.close(jf2);
}
Utils.cleanup();
if (errors > 0) {
throw new RuntimeException("FAIL:" + errors + " error(s) encounted");
}