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

8074694: Lazy conversion of ZipEntry time

Summary: to backport the same fix to 8u
Reviewed-by: sherman
Contributed-by: claes.redestad@oracle.com
上级 f1c753ea
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 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
......@@ -41,7 +41,9 @@ public
class ZipEntry implements ZipConstants, Cloneable {
String name; // entry name
long time = -1; // last modification time
long xdostime = -1; // last modification time (in extended DOS time,
// where milliseconds lost in conversion might
// be encoded into the upper half)
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
......@@ -63,6 +65,28 @@ class ZipEntry implements ZipConstants, Cloneable {
*/
public static final int DEFLATED = 8;
/**
* DOS time constant for representing timestamps before 1980.
*/
static final long DOSTIME_BEFORE_1980 = (1 << 21) | (1 << 16);
/**
* Approximately 128 years, in milliseconds (ignoring leap years etc).
*
* This establish an approximate high-bound value for DOS times in
* milliseconds since epoch, used to enable an efficient but
* sufficient bounds check to avoid generating extended last modified
* time entries.
*
* Calculating the exact number is locale dependent, would require loading
* TimeZone data eagerly, and would make little practical sense. Since DOS
* times theoretically go to 2107 - with compatibility not guaranteed
* after 2099 - setting this to a time that is before but near 2099
* should be sufficient.
*/
private static final long UPPER_DOSTIME_BOUND =
128L * 365 * 24 * 60 * 60 * 1000;
/**
* Creates a new zip entry with the specified name.
*
......@@ -93,7 +117,7 @@ class ZipEntry implements ZipConstants, Cloneable {
public ZipEntry(ZipEntry e) {
Objects.requireNonNull(e, "entry");
name = e.name;
time = e.time;
xdostime = e.xdostime;
mtime = e.mtime;
atime = e.atime;
ctime = e.ctime;
......@@ -137,8 +161,14 @@ class ZipEntry implements ZipConstants, Cloneable {
* @see #getLastModifiedTime()
*/
public void setTime(long time) {
this.time = time;
this.mtime = null;
this.xdostime = javaToExtendedDosTime(time);
// Avoid setting the mtime field if time is in the valid
// range for a DOS time
if (xdostime != DOSTIME_BEFORE_1980 && time <= UPPER_DOSTIME_BOUND) {
this.mtime = null;
} else {
this.mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
}
}
/**
......@@ -158,7 +188,10 @@ class ZipEntry implements ZipConstants, Cloneable {
* @see #setLastModifiedTime(FileTime)
*/
public long getTime() {
return time;
if (mtime != null) {
return mtime.toMillis();
}
return (xdostime != -1) ? extendedDosToJavaTime(xdostime) : -1;
}
/**
......@@ -181,7 +214,7 @@ class ZipEntry implements ZipConstants, Cloneable {
*/
public ZipEntry setLastModifiedTime(FileTime time) {
this.mtime = Objects.requireNonNull(time, "lastModifiedTime");
this.time = time.to(TimeUnit.MILLISECONDS);
this.xdostime = javaToExtendedDosTime(time.to(TimeUnit.MILLISECONDS));
return this;
}
......@@ -204,9 +237,9 @@ class ZipEntry implements ZipConstants, Cloneable {
public FileTime getLastModifiedTime() {
if (mtime != null)
return mtime;
if (time == -1)
if (xdostime == -1)
return null;
return FileTime.from(time, TimeUnit.MILLISECONDS);
return FileTime.from(getTime(), TimeUnit.MILLISECONDS);
}
/**
......
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 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
......@@ -46,7 +46,6 @@ import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.zip.ZipConstants64.*;
import static java.util.zip.ZipUtils.*;
/**
* This class is used to read entries from a zip file.
......@@ -567,7 +566,7 @@ class ZipFile implements ZipConstants, Closeable {
e.name = zc.toString(bname, bname.length);
}
}
e.time = dosToJavaTime(getEntryTime(jzentry));
e.xdostime = getEntryTime(jzentry);
e.crc = getEntryCrc(jzentry);
e.size = getEntrySize(jzentry);
e.csize = getEntryCSize(jzentry);
......
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
......@@ -303,7 +303,7 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
throw new ZipException("encrypted ZIP entry not supported");
}
e.method = get16(tmpbuf, LOCHOW);
e.time = dosToJavaTime(get32(tmpbuf, LOCTIM));
e.xdostime = get32(tmpbuf, LOCTIM);
if ((flag & 8) == 8) {
/* "Data Descriptor" present */
if (e.method != DEFLATED) {
......
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
......@@ -61,7 +61,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private static class XEntry {
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;
......@@ -192,7 +191,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (current != null) {
closeEntry(); // close previous entry
}
if (e.time == -1) {
if (e.xdostime == -1) {
// by default, do NOT use extended timestamps in extra
// data, for now.
e.setTime(System.currentTimeMillis());
......@@ -389,18 +388,12 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
boolean hasZip64 = false;
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(xentry.dostime); // last modification time
writeInt(e.xdostime); // last modification time
// store size, uncompressed size, and crc-32 in data descriptor
// immediately following compressed entry data
writeInt(0);
......@@ -415,7 +408,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
}
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
writeInt(xentry.dostime); // last modification time
writeInt(e.xdostime); // last modification time
writeInt(e.crc); // crc-32
if (hasZip64) {
writeInt(ZIP64_MAGICVAL);
......@@ -522,9 +515,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
}
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
// use the copy in xentry, which has been converted
// from e.time in writeLOC()
writeInt(xentry.dostime); // last modification time
writeInt(e.xdostime); // last modification time
writeInt(e.crc); // crc-32
writeInt(csize); // compressed size
writeInt(size); // uncompressed size
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
......@@ -29,9 +29,6 @@ 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
......@@ -69,7 +66,7 @@ class ZipUtils {
/**
* Converts DOS time to Java time (number of milliseconds since epoch).
*/
public static long dosToJavaTime(long dtime) {
private static long dosToJavaTime(long dtime) {
@SuppressWarnings("deprecation") // Use of date constructor.
Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
(int)(((dtime >> 21) & 0x0f) - 1),
......@@ -80,21 +77,50 @@ class ZipUtils {
return d.getTime();
}
/**
* Converts extended DOS time to Java time, where up to 1999 milliseconds
* might be encoded into the upper half of the returned long.
*
* @param xdostime the extended DOS time value
* @return milliseconds since epoch
*/
public static long extendedDosToJavaTime(long xdostime) {
long time = dosToJavaTime(xdostime);
return time + (xdostime >> 32);
}
/**
* Converts Java time to DOS time.
*/
@SuppressWarnings("deprecation") // Use of date methods
public static long javaToDosTime(long time) {
private static long javaToDosTime(long time) {
Date d = new Date(time);
int year = d.getYear() + 1900;
if (year < 1980) {
return (1 << 21) | (1 << 16);
return ZipEntry.DOSTIME_BEFORE_1980;
}
return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
d.getSeconds() >> 1;
}
/**
* Converts Java time to DOS time, encoding any milliseconds lost
* in the conversion into the upper half of the returned long.
*
* @param time milliseconds since epoch
* @return DOS time with 2s remainder encoded into upper half
*/
public static long javaToExtendedDosTime(long time) {
if (time < 0) {
return ZipEntry.DOSTIME_BEFORE_1980;
}
long dostime = javaToDosTime(time);
return (dostime != ZipEntry.DOSTIME_BEFORE_1980)
? dostime + ((time % 2000) << 32)
: ZipEntry.DOSTIME_BEFORE_1980;
}
/**
* Fetches unsigned 16-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order.
......
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
......@@ -23,7 +23,7 @@
/**
* @test
* @bug 4759491 6303183 7012868 8015666 8023713 8068790
* @bug 4759491 6303183 7012868 8015666 8023713 8068790 8074694
* @summary Test ZOS and ZIS timestamp in extra field correctly
*/
......@@ -71,6 +71,7 @@ public class TestExtraTime {
}
testNullHandling();
testTimeConversions();
}
static void test(FileTime mtime, FileTime atime, FileTime ctime,
......@@ -178,4 +179,33 @@ public class TestExtraTime {
// pass
}
}
// verify that setting and getting any time is possible as per the intent
// of 4759491
static void testTimeConversions() {
// Sample across the entire range
long step = Long.MAX_VALUE / 100L;
testTimeConversions(Long.MIN_VALUE, Long.MAX_VALUE - step, step);
// Samples through the near future
long currentTime = System.currentTimeMillis();
testTimeConversions(currentTime, currentTime + 1_000_000, 10_000);
}
static void testTimeConversions(long from, long to, long step) {
ZipEntry ze = new ZipEntry("TestExtraTime.java");
for (long time = from; time <= to; time += step) {
ze.setTime(time);
FileTime lastModifiedTime = ze.getLastModifiedTime();
if (lastModifiedTime.toMillis() != time) {
throw new RuntimeException("setTime should make getLastModifiedTime " +
"return the specified instant: " + time +
" got: " + lastModifiedTime.toMillis());
}
if (ze.getTime() != time) {
throw new RuntimeException("getTime after setTime, expected: " +
time + " got: " + ze.getTime());
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册