提交 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. * 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
...@@ -41,7 +41,9 @@ public ...@@ -41,7 +41,9 @@ public
class ZipEntry implements ZipConstants, Cloneable { class ZipEntry implements ZipConstants, Cloneable {
String name; // entry name 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 mtime; // last modification time, from extra field data
FileTime atime; // last access time, from extra field data FileTime atime; // last access time, from extra field data
FileTime ctime; // creation time, from extra field data FileTime ctime; // creation time, from extra field data
...@@ -63,6 +65,28 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -63,6 +65,28 @@ class ZipEntry implements ZipConstants, Cloneable {
*/ */
public static final int DEFLATED = 8; 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. * Creates a new zip entry with the specified name.
* *
...@@ -93,7 +117,7 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -93,7 +117,7 @@ class ZipEntry implements ZipConstants, Cloneable {
public ZipEntry(ZipEntry e) { public ZipEntry(ZipEntry e) {
Objects.requireNonNull(e, "entry"); Objects.requireNonNull(e, "entry");
name = e.name; name = e.name;
time = e.time; xdostime = e.xdostime;
mtime = e.mtime; mtime = e.mtime;
atime = e.atime; atime = e.atime;
ctime = e.ctime; ctime = e.ctime;
...@@ -137,8 +161,14 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -137,8 +161,14 @@ class ZipEntry implements ZipConstants, Cloneable {
* @see #getLastModifiedTime() * @see #getLastModifiedTime()
*/ */
public void setTime(long time) { public void setTime(long time) {
this.time = time; this.xdostime = javaToExtendedDosTime(time);
this.mtime = null; // 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 { ...@@ -158,7 +188,10 @@ class ZipEntry implements ZipConstants, Cloneable {
* @see #setLastModifiedTime(FileTime) * @see #setLastModifiedTime(FileTime)
*/ */
public long getTime() { 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 { ...@@ -181,7 +214,7 @@ class ZipEntry implements ZipConstants, Cloneable {
*/ */
public ZipEntry setLastModifiedTime(FileTime time) { public ZipEntry setLastModifiedTime(FileTime time) {
this.mtime = Objects.requireNonNull(time, "lastModifiedTime"); this.mtime = Objects.requireNonNull(time, "lastModifiedTime");
this.time = time.to(TimeUnit.MILLISECONDS); this.xdostime = javaToExtendedDosTime(time.to(TimeUnit.MILLISECONDS));
return this; return this;
} }
...@@ -204,9 +237,9 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -204,9 +237,9 @@ class ZipEntry implements ZipConstants, Cloneable {
public FileTime getLastModifiedTime() { public FileTime getLastModifiedTime() {
if (mtime != null) if (mtime != null)
return mtime; return mtime;
if (time == -1) if (xdostime == -1)
return null; 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. * 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
...@@ -46,7 +46,6 @@ import java.util.stream.Stream; ...@@ -46,7 +46,6 @@ import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import static java.util.zip.ZipConstants64.*; import static java.util.zip.ZipConstants64.*;
import static java.util.zip.ZipUtils.*;
/** /**
* This class is used to read entries from a zip file. * This class is used to read entries from a zip file.
...@@ -567,7 +566,7 @@ class ZipFile implements ZipConstants, Closeable { ...@@ -567,7 +566,7 @@ 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.xdostime = 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);
......
/* /*
* 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. * 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
...@@ -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.time = dosToJavaTime(get32(tmpbuf, LOCTIM)); e.xdostime = 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) {
......
/* /*
* 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. * 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
...@@ -61,7 +61,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -61,7 +61,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private static class XEntry { private static class XEntry {
final ZipEntry entry; final ZipEntry entry;
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;
...@@ -192,7 +191,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -192,7 +191,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (current != null) { if (current != null) {
closeEntry(); // close previous entry closeEntry(); // close previous entry
} }
if (e.time == -1) { if (e.xdostime == -1) {
// by default, do NOT use extended timestamps in extra // by default, do NOT use extended timestamps in extra
// data, for now. // data, for now.
e.setTime(System.currentTimeMillis()); e.setTime(System.currentTimeMillis());
...@@ -389,18 +388,12 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -389,18 +388,12 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
boolean hasZip64 = false; boolean hasZip64 = false;
int elen = getExtraLen(e.extra); 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 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(xentry.dostime); // last modification time writeInt(e.xdostime); // 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);
...@@ -415,7 +408,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -415,7 +408,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(xentry.dostime); // last modification time writeInt(e.xdostime); // last modification time
writeInt(e.crc); // crc-32 writeInt(e.crc); // crc-32
if (hasZip64) { if (hasZip64) {
writeInt(ZIP64_MAGICVAL); writeInt(ZIP64_MAGICVAL);
...@@ -522,9 +515,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -522,9 +515,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
// use the copy in xentry, which has been converted writeInt(e.xdostime); // last modification time
// 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
......
/* /*
* 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. * 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
...@@ -29,9 +29,6 @@ import java.nio.file.attribute.FileTime; ...@@ -29,9 +29,6 @@ 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
...@@ -69,7 +66,7 @@ class ZipUtils { ...@@ -69,7 +66,7 @@ class ZipUtils {
/** /**
* Converts DOS time to Java time (number of milliseconds since epoch). * 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. @SuppressWarnings("deprecation") // Use of date constructor.
Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80), Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
(int)(((dtime >> 21) & 0x0f) - 1), (int)(((dtime >> 21) & 0x0f) - 1),
...@@ -80,21 +77,50 @@ class ZipUtils { ...@@ -80,21 +77,50 @@ class ZipUtils {
return d.getTime(); 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. * Converts Java time to DOS time.
*/ */
@SuppressWarnings("deprecation") // Use of date methods @SuppressWarnings("deprecation") // Use of date methods
public static long javaToDosTime(long time) { private static long javaToDosTime(long time) {
Date d = new Date(time); Date d = new Date(time);
int year = d.getYear() + 1900; int year = d.getYear() + 1900;
if (year < 1980) { if (year < 1980) {
return (1 << 21) | (1 << 16); return ZipEntry.DOSTIME_BEFORE_1980;
} }
return (year - 1980) << 25 | (d.getMonth() + 1) << 21 | return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 | d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
d.getSeconds() >> 1; 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. * 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.
......
/* /*
* 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. * 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
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/** /**
* @test * @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 * @summary Test ZOS and ZIS timestamp in extra field correctly
*/ */
...@@ -71,6 +71,7 @@ public class TestExtraTime { ...@@ -71,6 +71,7 @@ public class TestExtraTime {
} }
testNullHandling(); testNullHandling();
testTimeConversions();
} }
static void test(FileTime mtime, FileTime atime, FileTime ctime, static void test(FileTime mtime, FileTime atime, FileTime ctime,
...@@ -178,4 +179,33 @@ public class TestExtraTime { ...@@ -178,4 +179,33 @@ public class TestExtraTime {
// pass // 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.
先完成此消息的编辑!
想要评论请 注册