8161942: java.util.zip.ZipEntry.java not covering UpperLimit range of DOS epoch

Reviewed-by: redestad
This commit is contained in:
Xueming Shen 2016-07-22 16:32:48 -07:00
parent 149b8bf45d
commit e944d9f280
5 changed files with 166 additions and 59 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2016, 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
@ -568,9 +568,18 @@ class ZipEntry implements ZipConstants, Cloneable {
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));
long wtime = get64(extra, pos + 4);
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
mtime = winTimeToFileTime(wtime);
}
wtime = get64(extra, pos + 12);
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
atime = winTimeToFileTime(wtime);
}
wtime = get64(extra, pos + 20);
if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
ctime = winTimeToFileTime(wtime);
}
break;
case EXTID_EXTT:
int flag = Byte.toUnsignedInt(extra[off]);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2016, 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
@ -421,22 +421,36 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
int elenEXTT = 0; // info-zip extended timestamp
int elenEXTT = 0; // info-zip extended timestamp
int flagEXTT = 0;
long umtime = -1;
long uatime = -1;
long uctime = -1;
if (e.mtime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAG_LMT;
umtime = fileTimeToUnixTime(e.mtime);
}
if (e.atime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAG_LAT;
uatime = fileTimeToUnixTime(e.atime);
}
if (e.ctime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAT_CT;
uctime = fileTimeToUnixTime(e.ctime);
}
if (flagEXTT != 0) {
// to use ntfs time if any m/a/ctime is beyond unixtime upper bound
if (umtime > UPPER_UNIXTIME_BOUND ||
uatime > UPPER_UNIXTIME_BOUND ||
uctime > UPPER_UNIXTIME_BOUND) {
elen += 36; // NTFS time, total 36 bytes
} else {
elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
}
}
if (flagEXTT != 0)
elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) {
@ -446,15 +460,31 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeLong(e.csize);
}
if (flagEXTT != 0) {
writeShort(EXTID_EXTT);
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));
if (umtime > UPPER_UNIXTIME_BOUND ||
uatime > UPPER_UNIXTIME_BOUND ||
uctime > UPPER_UNIXTIME_BOUND) {
writeShort(EXTID_NTFS); // id
writeShort(32); // data size
writeInt(0); // reserved
writeShort(0x0001); // NTFS attr tag
writeShort(24);
writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
: fileTimeToWinTime(e.mtime));
writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
: fileTimeToWinTime(e.atime));
writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
: fileTimeToWinTime(e.ctime));
} else {
writeShort(EXTID_EXTT);
writeShort(elenEXTT + 1); // flag + data
writeByte(flagEXTT);
if (e.mtime != null)
writeInt(umtime);
if (e.atime != null)
writeInt(uatime);
if (e.ctime != null)
writeInt(uctime);
}
}
writeExtra(e.extra);
locoff = written;
@ -528,18 +558,30 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
// cen info-zip extended timestamp only outputs mtime
// but set the flag for a/ctime, if present in loc
int flagEXTT = 0;
long umtime = -1;
long uatime = -1;
long uctime = -1;
if (e.mtime != null) {
elen += 4; // + mtime(4)
flagEXTT |= EXTT_FLAG_LMT;
umtime = fileTimeToUnixTime(e.mtime);
}
if (e.atime != null) {
flagEXTT |= EXTT_FLAG_LAT;
uatime = fileTimeToUnixTime(e.atime);
}
if (e.ctime != null) {
flagEXTT |= EXTT_FLAT_CT;
uctime = fileTimeToUnixTime(e.ctime);
}
if (flagEXTT != 0) {
elen += 5; // headid + sz + flag
// to use ntfs time if any m/a/ctime is beyond unixtime upper bound
if (umtime > UPPER_UNIXTIME_BOUND ||
uatime > UPPER_UNIXTIME_BOUND ||
uctime > UPPER_UNIXTIME_BOUND) {
elen += 36; // NTFS time total 36 bytes
} else {
elen += 9; // headid(2) + sz(2) + flag(1) + mtime (4)
}
}
writeShort(elen);
byte[] commentBytes;
@ -568,14 +610,30 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeLong(xentry.offset);
}
if (flagEXTT != 0) {
writeShort(EXTID_EXTT);
if (e.mtime != null) {
writeShort(5); // flag + mtime
writeByte(flagEXTT);
writeInt(fileTimeToUnixTime(e.mtime));
if (umtime > UPPER_UNIXTIME_BOUND ||
uatime > UPPER_UNIXTIME_BOUND ||
uctime > UPPER_UNIXTIME_BOUND) {
writeShort(EXTID_NTFS); // id
writeShort(32); // data size
writeInt(0); // reserved
writeShort(0x0001); // NTFS attr tag
writeShort(24);
writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
: fileTimeToWinTime(e.mtime));
writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
: fileTimeToWinTime(e.atime));
writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
: fileTimeToWinTime(e.ctime));
} else {
writeShort(1); // flag only
writeByte(flagEXTT);
writeShort(EXTID_EXTT);
if (e.mtime != null) {
writeShort(5); // flag + mtime
writeByte(flagEXTT);
writeInt(umtime);
} else {
writeShort(1); // flag only
writeByte(flagEXTT);
}
}
}
writeExtra(e.extra);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, 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
@ -38,6 +38,9 @@ class ZipUtils {
// used to adjust values between Windows and java epoch
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
// used to indicate the corresponding windows time is not available
public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
/**
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
*/
@ -53,6 +56,11 @@ class ZipUtils {
return (ftime.to(TimeUnit.MICROSECONDS) - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
}
/**
* The upper bound of the 32-bit unix time, the "year 2038 problem".
*/
public static final long UPPER_UNIXTIME_BOUND = 0x7fffffff;
/**
* Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, 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 8076641 8075526 8130914
* @bug 4759491 6303183 7012868 8015666 8023713 8068790 8076641 8075526 8130914 8161942
* @summary Test ZOS and ZIS timestamp in extra field correctly
*/
@ -32,6 +32,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@ -40,37 +41,52 @@ import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class TestExtraTime {
public static void main(String[] args) throws Throwable{
File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
if (src.exists()) {
if (!src.exists()) {
return;
}
TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) {
// ms-dos 1980 epoch problem
test0(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
// negative epoch time
test0(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
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(FileTime.from(time, TimeUnit.MILLISECONDS),
FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
tz, extra);
for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) {
test(mtime, null, null, null, extra);
// now
time = Instant.now().toEpochMilli();
test(FileTime.from(time, TimeUnit.MILLISECONDS),
FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
tz, extra);
// ms-dos 1980 epoch problem
test(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
// negative epoch time
test(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
// unix 2038
time = 0x80000000L;
test(FileTime.from(time, TimeUnit.SECONDS),
FileTime.from(time, TimeUnit.SECONDS),
FileTime.from(time, TimeUnit.SECONDS),
tz, extra);
// non-default tz
test(mtime, null, null, tz, extra);
test(mtime, atime, null, null, extra);
test(mtime, null, ctime, null, extra);
test(mtime, atime, ctime, null, extra);
test(mtime, atime, null, tz, extra);
test(mtime, null, ctime, tz, extra);
test(mtime, atime, ctime, tz, extra);
}
// mtime < unix 2038
time = 0x7fffffffL;
test(FileTime.from(time, TimeUnit.SECONDS),
FileTime.from(time + 30000, TimeUnit.SECONDS),
FileTime.from(time + 30000, TimeUnit.SECONDS),
tz, extra);
}
testNullHandling();
@ -80,6 +96,18 @@ public class TestExtraTime {
static void test(FileTime mtime, FileTime atime, FileTime ctime,
TimeZone tz, byte[] extra) throws Throwable {
test0(mtime, null, null, null, extra);
test0(mtime, null, null, tz, extra); // non-default tz
test0(mtime, atime, null, null, extra);
test0(mtime, null, ctime, null, extra);
test0(mtime, atime, ctime, null, extra);
test0(mtime, atime, null, tz, extra);
test0(mtime, null, ctime, tz, extra);
test0(mtime, atime, ctime, tz, extra);
}
static void test0(FileTime mtime, FileTime atime, FileTime ctime,
TimeZone tz, byte[] extra) throws Throwable {
System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n",
mtime, atime, ctime);
TimeZone tz0 = TimeZone.getDefault();
@ -120,13 +148,14 @@ public class TestExtraTime {
Path zpath = Paths.get(System.getProperty("test.dir", "."),
"TestExtraTime.zip");
Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
ZipFile zf = new ZipFile(zpath.toFile());
ze = zf.getEntry("TestExtraTime.java");
// ZipFile read entry from cen, which does not have a/ctime,
// for now.
check(mtime, null, null, ze, extra);
zf.close();
Files.delete(zpath);
try (ZipFile zf = new ZipFile(zpath.toFile())) {
ze = zf.getEntry("TestExtraTime.java");
// ZipFile read entry from cen, which does not have a/ctime,
// for now.
check(mtime, null, null, ze, extra);
} finally {
Files.delete(zpath);
}
}
static void check(FileTime mtime, FileTime atime, FileTime ctime,

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8075526 8135108 8155616
* @bug 8075526 8135108 8155616 8161942
* @summary Test timestamp via ZipEntry.get/setTimeLocal()
*/
@ -65,6 +65,9 @@ public class TestLocalTime {
test(LocalDateTime.of(1968, 04, 28, 2, 51, 25));
test(LocalDateTime.of(1970, 04, 26, 2, 31, 52));
// for #8161942
test(LocalDateTime.of(2200, 04, 26, 2, 31, 52)); // unix 2038
} finally {
TimeZone.setDefault(tz0);
}