8186464: ZipFile cannot read some InfoZip ZIP64 zip files
Reviewed-by: martin
This commit is contained in:
parent
dae210f6d6
commit
02b9452ed3
@ -1122,30 +1122,36 @@ class ZipFile implements ZipConstants, Closeable {
|
||||
zerror("zip comment read failed");
|
||||
}
|
||||
}
|
||||
if (end.cenlen == ZIP64_MAGICVAL ||
|
||||
end.cenoff == ZIP64_MAGICVAL ||
|
||||
end.centot == ZIP64_MAGICCOUNT)
|
||||
{
|
||||
// need to find the zip64 end;
|
||||
try {
|
||||
byte[] loc64 = new byte[ZIP64_LOCHDR];
|
||||
if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
|
||||
!= loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
|
||||
return end;
|
||||
}
|
||||
long end64pos = ZIP64_LOCOFF(loc64);
|
||||
byte[] end64buf = new byte[ZIP64_ENDHDR];
|
||||
if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
|
||||
!= end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
|
||||
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;
|
||||
} catch (IOException x) {} // no zip64 loc/end
|
||||
}
|
||||
// must check for a zip64 end record; it is always permitted to be present
|
||||
try {
|
||||
byte[] loc64 = new byte[ZIP64_LOCHDR];
|
||||
if (end.endpos < ZIP64_LOCHDR ||
|
||||
readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
|
||||
!= loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
|
||||
return end;
|
||||
}
|
||||
long end64pos = ZIP64_LOCOFF(loc64);
|
||||
byte[] end64buf = new byte[ZIP64_ENDHDR];
|
||||
if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
|
||||
!= end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
|
||||
return end;
|
||||
}
|
||||
// end64 candidate 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_MAGICVAL ||
|
||||
cenoff64 != end.cenoff && end.cenoff != ZIP64_MAGICVAL ||
|
||||
centot64 != end.centot && end.centot != ZIP64_MAGICCOUNT) {
|
||||
return end;
|
||||
}
|
||||
// to use the end64 values
|
||||
end.cenlen = cenlen64;
|
||||
end.cenoff = cenoff64;
|
||||
end.centot = (int)centot64; // assume total < 2g
|
||||
end.endpos = end64pos;
|
||||
} catch (IOException x) {} // no zip64 loc/end
|
||||
return end;
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ class ZipFileSystem extends FileSystem {
|
||||
private static final boolean isWindows = AccessController.doPrivileged(
|
||||
(PrivilegedAction<Boolean>) () -> System.getProperty("os.name")
|
||||
.startsWith("Windows"));
|
||||
private final boolean forceEnd64;
|
||||
|
||||
ZipFileSystem(ZipFileSystemProvider provider,
|
||||
Path zfpath,
|
||||
@ -91,12 +92,13 @@ class ZipFileSystem extends FileSystem {
|
||||
(String)env.get("encoding") : "UTF-8";
|
||||
this.noExtt = "false".equals(env.get("zipinfo-time"));
|
||||
this.useTempFile = TRUE.equals(env.get("useTempFile"));
|
||||
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());
|
||||
@ -1000,28 +1002,36 @@ class ZipFileSystem extends FileSystem {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1192,7 +1202,7 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
// 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) {
|
||||
@ -1282,7 +1292,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
end.centot = elist.size();
|
||||
end.cenlen = written - end.cenoff;
|
||||
end.write(os, written);
|
||||
end.write(os, written, forceEnd64);
|
||||
}
|
||||
if (!streams.isEmpty()) {
|
||||
//
|
||||
@ -1712,8 +1722,8 @@ class ZipFileSystem extends FileSystem {
|
||||
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) {
|
||||
@ -1738,8 +1748,8 @@ class ZipFileSystem extends FileSystem {
|
||||
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
|
||||
|
||||
|
@ -22,19 +22,27 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977
|
||||
@bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8186464
|
||||
@summary Make sure we can read a zip file.
|
||||
@key randomness
|
||||
*/
|
||||
|
||||
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.NoSuchFileException;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
public class ReadZip {
|
||||
private static void unreached (Object o)
|
||||
throws Exception
|
||||
@ -137,8 +145,6 @@ public class ReadZip {
|
||||
newZip.delete();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Throw a FNF exception when read a non-existing zip file
|
||||
try { unreached (new ZipFile(
|
||||
new File(System.getProperty("test.src", "."),
|
||||
@ -146,5 +152,54 @@ public class ReadZip {
|
||||
+ String.valueOf(new java.util.Random().nextInt())
|
||||
+ ".zip")));
|
||||
} catch (NoSuchFileException nsfe) {}
|
||||
|
||||
// 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 = Map.of("create", "true", "forceZIP64End", "true");
|
||||
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(zf.getInputStream(new ZipEntry("hello"))
|
||||
.readAllBytes(),
|
||||
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, Map.of())) {
|
||||
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(zf.getInputStream(new ZipEntry("-"))
|
||||
.readAllBytes())))
|
||||
throw new RuntimeException("zipfile: read entry failed");
|
||||
} catch (IOException x) {
|
||||
throw new RuntimeException("zipfile: zip64 end failed");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user