8188869: jdk9/10 reject zip/jar files where seconds value of timestamp is out of supported range 0 - 59
Reviewed-by: sherman, alanb
This commit is contained in:
parent
874060c138
commit
81b7f75837
@ -28,9 +28,11 @@ package java.util.zip;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.util.zip.ZipConstants.ENDHDR;
|
||||
@ -78,31 +80,39 @@ class ZipUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Converts DOS time to Java time (number of milliseconds since epoch).
|
||||
*/
|
||||
public static long dosToJavaTime(long dtime) {
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int year = (int) (((dtime >> 25) & 0x7f) + 1980);
|
||||
int month = (int) ((dtime >> 21) & 0x0f);
|
||||
int day = (int) ((dtime >> 16) & 0x1f);
|
||||
int hour = (int) ((dtime >> 11) & 0x1f);
|
||||
int minute = (int) ((dtime >> 5) & 0x3f);
|
||||
int second = (int) ((dtime << 1) & 0x3e);
|
||||
if ((dtime >> 16) == 0) {
|
||||
// Interpret the 0 DOS date as 1979-11-30 for compatibility with
|
||||
// other implementations.
|
||||
year = 1979;
|
||||
month = 11;
|
||||
day = 30;
|
||||
} else {
|
||||
year = (int) (((dtime >> 25) & 0x7f) + 1980);
|
||||
month = (int) ((dtime >> 21) & 0x0f);
|
||||
day = (int) ((dtime >> 16) & 0x1f);
|
||||
|
||||
if (month > 0 && month < 13 && day > 0 && hour < 24 && minute < 60 && second < 60) {
|
||||
try {
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
|
||||
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
|
||||
} catch (DateTimeException dte) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
|
||||
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
|
||||
return overflowDosToJavaTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with corner cases where an arguably mal-formed DOS time is used
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Use of Date constructor
|
||||
private static long overflowDosToJavaTime(int year, int month, int day,
|
||||
int hour, int minute, int second) {
|
||||
return new Date(year - 1900, month - 1, day, hour, minute, second).getTime();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts extended DOS time to Java time, where up to 1999 milliseconds
|
||||
* might be encoded into the upper half of the returned long.
|
||||
|
@ -27,10 +27,12 @@ package jdk.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -106,26 +108,32 @@ class ZipUtils {
|
||||
* Converts DOS time to Java time (number of milliseconds since epoch).
|
||||
*/
|
||||
public static long dosToJavaTime(long dtime) {
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int year = (int) (((dtime >> 25) & 0x7f) + 1980);
|
||||
int month = (int) ((dtime >> 21) & 0x0f);
|
||||
int day = (int) ((dtime >> 16) & 0x1f);
|
||||
int hour = (int) ((dtime >> 11) & 0x1f);
|
||||
int minute = (int) ((dtime >> 5) & 0x3f);
|
||||
int second = (int) ((dtime << 1) & 0x3e);
|
||||
if ((dtime >> 16) == 0) {
|
||||
// Interpret the 0 DOS date as 1979-11-30 for compatibility with
|
||||
// other implementations.
|
||||
year = 1979;
|
||||
month = 11;
|
||||
day = 30;
|
||||
} else {
|
||||
year = (int) (((dtime >> 25) & 0x7f) + 1980);
|
||||
month = (int) ((dtime >> 21) & 0x0f);
|
||||
day = (int) ((dtime >> 16) & 0x1f);
|
||||
|
||||
if (month > 0 && month < 13 && day > 0 && hour < 24 && minute < 60 && second < 60) {
|
||||
try {
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
|
||||
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
|
||||
} catch (DateTimeException dte) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, minute, second);
|
||||
return TimeUnit.MILLISECONDS.convert(ldt.toEpochSecond(
|
||||
ZoneId.systemDefault().getRules().getOffset(ldt)), TimeUnit.SECONDS);
|
||||
return overflowDosToJavaTime(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with corner cases where an arguably mal-formed DOS time is used
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Use of Date constructor
|
||||
private static long overflowDosToJavaTime(int year, int month, int day,
|
||||
int hour, int minute, int second) {
|
||||
return new Date(year - 1900, month - 1, day, hour, minute, second).getTime();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -34,14 +34,16 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/* @test
|
||||
* @bug 8184940
|
||||
* @bug 8184940 8188869
|
||||
* @summary JDK 9 rejects zip files where the modified day or month is 0
|
||||
* or otherwise represent an invalid date, such as 1980-02-30 24:60:60
|
||||
* @author Liam Miller-Cushon
|
||||
*/
|
||||
public class ZeroDate {
|
||||
@ -63,12 +65,19 @@ public class ZeroDate {
|
||||
Files.delete(path);
|
||||
|
||||
// year, month, day are zero
|
||||
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30));
|
||||
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30).atStartOfDay());
|
||||
// only year is zero
|
||||
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5));
|
||||
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5).atStartOfDay());
|
||||
// month is greater than 12
|
||||
testDate(data.clone(), 0 << 25 | 13 << 21 | 1 << 16, LocalDate.of(1981, 1, 1).atStartOfDay());
|
||||
// 30th of February
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16, LocalDate.of(1980, 3, 1).atStartOfDay());
|
||||
// 30th of February, 24:60:60
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16 | 24 << 11 | 60 << 5 | 60 >> 1,
|
||||
LocalDateTime.of(1980, 3, 2, 1, 1, 0));
|
||||
}
|
||||
|
||||
private static void testDate(byte[] data, int date, LocalDate expected) throws IOException {
|
||||
private static void testDate(byte[] data, int date, LocalDateTime expected) throws IOException {
|
||||
// set the datetime
|
||||
int endpos = data.length - ENDHDR;
|
||||
int cenpos = u16(data, endpos + ENDOFF);
|
||||
@ -84,8 +93,7 @@ public class ZeroDate {
|
||||
try (ZipFile zf = new ZipFile(path.toFile())) {
|
||||
ZipEntry ze = zf.entries().nextElement();
|
||||
Instant actualInstant = ze.getLastModifiedTime().toInstant();
|
||||
Instant expectedInstant =
|
||||
expected.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
|
||||
Instant expectedInstant = expected.atZone(ZoneId.systemDefault()).toInstant();
|
||||
if (!actualInstant.equals(expectedInstant)) {
|
||||
throw new AssertionError(
|
||||
String.format("actual: %s, expected: %s", actualInstant, expectedInstant));
|
||||
|
@ -38,14 +38,16 @@ import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collections;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/* @test
|
||||
* @bug 8184940 8186227
|
||||
* @bug 8184940 8186227 8188869
|
||||
* @summary JDK 9 rejects zip files where the modified day or month is 0
|
||||
* or otherwise represent an invalid date, such as 1980-02-30 24:60:60
|
||||
* @author Liam Miller-Cushon
|
||||
*/
|
||||
public class ZeroDate {
|
||||
@ -67,12 +69,19 @@ public class ZeroDate {
|
||||
Files.delete(path);
|
||||
|
||||
// year, month, day are zero
|
||||
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30));
|
||||
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30).atStartOfDay());
|
||||
// only year is zero
|
||||
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5));
|
||||
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5).atStartOfDay());
|
||||
// month is greater than 12
|
||||
testDate(data.clone(), 0 << 25 | 13 << 21 | 1 << 16, LocalDate.of(1981, 1, 1).atStartOfDay());
|
||||
// 30th of February
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16, LocalDate.of(1980, 3, 1).atStartOfDay());
|
||||
// 30th of February, 24:60:60
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16 | 24 << 11 | 60 << 5 | 60 >> 1,
|
||||
LocalDateTime.of(1980, 3, 2, 1, 1, 0));
|
||||
}
|
||||
|
||||
private static void testDate(byte[] data, int date, LocalDate expected) throws IOException {
|
||||
private static void testDate(byte[] data, int date, LocalDateTime expected) throws IOException {
|
||||
// set the datetime
|
||||
int endpos = data.length - ENDHDR;
|
||||
int cenpos = u16(data, endpos + ENDOFF);
|
||||
@ -93,7 +102,7 @@ public class ZeroDate {
|
||||
.lastModifiedTime()
|
||||
.toInstant();
|
||||
Instant expectedInstant =
|
||||
expected.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
|
||||
expected.atZone(ZoneId.systemDefault()).toInstant();
|
||||
if (!actualInstant.equals(expectedInstant)) {
|
||||
throw new AssertionError(
|
||||
String.format("actual: %s, expected: %s", actualInstant, expectedInstant));
|
||||
|
Loading…
Reference in New Issue
Block a user