Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public class ZipFileSystem extends FileSystem {
private final boolean createNew; // create a new zip if not exists
private static final boolean isWindows =
System.getProperty("os.name").startsWith("Windows");
private final boolean forceEnd64;

// a threshold, in bytes, to decide whether to create a temp file
// for outputstream of a zip entry
Expand All @@ -112,12 +113,13 @@ public class ZipFileSystem extends FileSystem {
if (this.defaultDir.charAt(0) != '/')
throw new IllegalArgumentException("default dir should be absolute");

this.forceEnd64 = "true".equals(env.get("forceZIP64End"));
this.provider = provider;
this.zfpath = zfpath;
if (Files.notExists(zfpath)) {
if (createNew) {
try (OutputStream os = Files.newOutputStream(zfpath, CREATE_NEW, WRITE)) {
new END().write(os, 0);
new END().write(os, 0, forceEnd64);
}
} else {
throw new FileSystemNotFoundException(zfpath.toString());
Expand Down Expand Up @@ -1014,28 +1016,36 @@ private END findEND() throws IOException
end.cenoff = ENDOFF(buf);
end.comlen = ENDCOM(buf);
end.endpos = pos + i;
if (end.cenlen == ZIP64_MINVAL ||
end.cenoff == ZIP64_MINVAL ||
end.centot == ZIP64_MINVAL32)
{
// need to find the zip64 end;
byte[] loc64 = new byte[ZIP64_LOCHDR];
if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
!= loc64.length) {
return end;
}
long end64pos = ZIP64_LOCOFF(loc64);
byte[] end64buf = new byte[ZIP64_ENDHDR];
if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
!= end64buf.length) {
return end;
}
// end64 found, re-calcualte everything.
end.cenlen = ZIP64_ENDSIZ(end64buf);
end.cenoff = ZIP64_ENDOFF(end64buf);
end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g
end.endpos = end64pos;
// try if there is zip64 end;
byte[] loc64 = new byte[ZIP64_LOCHDR];
if (end.endpos < ZIP64_LOCHDR ||
readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
!= loc64.length ||
!locator64SigAt(loc64, 0)) {
return end;
}
long end64pos = ZIP64_LOCOFF(loc64);
byte[] end64buf = new byte[ZIP64_ENDHDR];
if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
!= end64buf.length ||
!end64SigAt(end64buf, 0)) {
return end;
}
// end64 found,
long cenlen64 = ZIP64_ENDSIZ(end64buf);
long cenoff64 = ZIP64_ENDOFF(end64buf);
long centot64 = ZIP64_ENDTOT(end64buf);
// double-check
if (cenlen64 != end.cenlen && end.cenlen != ZIP64_MINVAL ||
cenoff64 != end.cenoff && end.cenoff != ZIP64_MINVAL ||
centot64 != end.centot && end.centot != ZIP64_MINVAL32) {
return end;
}
// to use the end64 values
end.cenlen = cenlen64;
end.cenoff = cenoff64;
end.centot = (int)centot64; // assume total < 2g
end.endpos = end64pos;
return end;
}
}
Expand Down Expand Up @@ -1201,7 +1211,7 @@ private long copyLOCEntry(Entry e, boolean updateHeader,

// sync the zip file system, if there is any udpate
private void sync() throws IOException {
//System.out.printf("->sync(%s) starting....!%n", toString());
// System.out.printf("->sync(%s) starting....!%n", toString());
// check ex-closer
if (!exChClosers.isEmpty()) {
for (ExChannelCloser ecc : exChClosers) {
Expand Down Expand Up @@ -1292,7 +1302,7 @@ private void sync() throws IOException {
}
end.centot = elist.size();
end.cenlen = written - end.cenoff;
end.write(os, written);
end.write(os, written, forceEnd64);
}
if (!streams.isEmpty()) {
//
Expand Down Expand Up @@ -1849,8 +1859,8 @@ static class END {
long endpos;
int disktot;

void write(OutputStream os, long offset) throws IOException {
boolean hasZip64 = false;
void write(OutputStream os, long offset, boolean forceEnd64) throws IOException {
boolean hasZip64 = forceEnd64; // false;
long xlen = cenlen;
long xoff = cenoff;
if (xlen >= ZIP64_MINVAL) {
Expand All @@ -1875,8 +1885,8 @@ void write(OutputStream os, long offset) throws IOException {
writeShort(os, 45); // version needed to extract
writeInt(os, 0); // number of this disk
writeInt(os, 0); // central directory start disk
writeLong(os, centot); // number of directory entires on disk
writeLong(os, centot); // number of directory entires
writeLong(os, centot); // number of directory entries on disk
writeLong(os, centot); // number of directory entries
writeLong(os, cenlen); // length of central directory
writeLong(os, cenoff); // offset of central directory

Expand Down
25 changes: 18 additions & 7 deletions jdk/src/share/native/java/util/zip/zip_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ findEND64(jzfile *zip, void *end64buf, jlong endpos)
{
char loc64[ZIP64_LOCHDR];
jlong end64pos;
if (endpos < ZIP64_LOCHDR) {
return -1;
}
if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {
return -1; // end64 locator not found
}
Expand Down Expand Up @@ -567,6 +570,7 @@ readCEN(jzfile *zip, jint knownTotal)
{
/* Following are unsigned 32-bit */
jlong endpos, end64pos, cenpos, cenlen, cenoff, total64;
jlong cenlen64, cenoff64, centot64;
/* Following are unsigned 16-bit */
jint total, tablelen, i, j;
unsigned char *cenbuf = NULL;
Expand Down Expand Up @@ -594,13 +598,20 @@ readCEN(jzfile *zip, jint knownTotal)
cenlen = ENDSIZ(endbuf);
cenoff = ENDOFF(endbuf);
total = ENDTOT(endbuf);
if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL ||
total == ZIP64_MAGICCOUNT) {
unsigned char end64buf[ZIP64_ENDHDR];
if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {
cenlen = ZIP64_ENDSIZ(end64buf);
cenoff = ZIP64_ENDOFF(end64buf);
total64 = ZIP64_ENDTOT(end64buf);
unsigned char end64buf[ZIP64_ENDHDR];
if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {
// end64 candidate found,
cenlen64 = ZIP64_ENDSIZ(end64buf);
cenoff64 = ZIP64_ENDOFF(end64buf);
centot64 = ZIP64_ENDTOT(end64buf);
// double-check
if ((cenlen64 == cenlen || cenlen == ZIP64_MAGICVAL) &&
(cenoff64 == cenoff || cenoff == ZIP64_MAGICVAL) &&
(centot64 == total || total == ZIP64_MAGICCOUNT)) {
// to use the end64 values
cenlen = cenlen64;
cenoff = cenoff64;
total64 = centot64;
/* ZIP64 size, offset and total-count fields are unsigned 64-bit
* values. Sizes and offsets that do not fit in signed jlong
* (i.e., >= 2^63), or total values that do not fit in jint, are
Expand Down
65 changes: 62 additions & 3 deletions jdk/test/java/util/zip/ZipFile/ReadZip.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*/

/* @test
* @bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8184993
* @bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8184993 8186464
* @summary Make sure we can read a zip file.
@key randomness
* @run main/othervm ReadZip
Expand All @@ -31,12 +31,24 @@
*/

import java.io.*;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.*;

import sun.misc.IOUtils;

import static java.nio.charset.StandardCharsets.US_ASCII;

public class ReadZip {
private static void unreached (Object o)
throws Exception
Expand Down Expand Up @@ -144,14 +156,61 @@
newZip.delete();
}



// Throw a FNF exception when read a non-existing zip file
try { unreached (new ZipFile(
new File(System.getProperty("test.src", "."),
"input"
+ String.valueOf(new java.util.Random().nextInt())
+ ".zip")));
} catch (FileNotFoundException fnfe) {}

// read a zip file with ZIP64 end
Path path = Paths.get(System.getProperty("test.dir", ""), "end64.zip");
try {
URI uri = URI.create("jar:" + path.toUri());
Map<String, Object> env = new HashMap<>();
env.put("create", "true");

Check failure on line 172 in jdk/test/java/util/zip/ZipFile/ReadZip.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk8u-dev-835

Whitespace error

Column 0: tab
env.put("forceZIP64End", "true");

Check failure on line 173 in jdk/test/java/util/zip/ZipFile/ReadZip.java

View check run for this annotation

openjdk / jcheck-openjdk/jdk8u-dev-835

Whitespace error

Column 0: tab
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Files.write(fs.getPath("hello"), "hello".getBytes());
}
try (ZipFile zf = new ZipFile(path.toFile())) {
if (!"hello".equals(new String(IOUtils.readAllBytes(zf.getInputStream(new ZipEntry("hello"))),
US_ASCII)))
throw new RuntimeException("zipfile: read entry failed");
} catch (IOException x) {
throw new RuntimeException("zipfile: zip64 end failed");
}
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
if (!"hello".equals(new String(Files.readAllBytes(fs.getPath("hello")))))
throw new RuntimeException("zipfs: read entry failed");
} catch (IOException x) {
throw new RuntimeException("zipfile: zip64 end failed");
}
} finally {
Files.deleteIfExists(path);
}

// read a zip file created via "echo hello | zip dst.zip -", which uses
// ZIP64 end record
if (Files.notExists(Paths.get("/usr/bin/zip")))
return;
try {
Process zip = new ProcessBuilder("zip", path.toString().toString(), "-").start();
OutputStream os = zip.getOutputStream();
os.write("hello".getBytes(US_ASCII));
os.close();
zip.waitFor();
if (zip.exitValue() == 0 && Files.exists(path)) {
try (ZipFile zf = new ZipFile(path.toFile())) {
if (!"hello".equals(new String(IOUtils.readAllBytes(zf.getInputStream(new ZipEntry("-"))))))
throw new RuntimeException("zipfile: read entry failed");
} catch (IOException x) {
throw new RuntimeException("zipfile: zip64 end failed");
}
}
} finally {
Files.deleteIfExists(path);
}
}
}