287 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| # HG changeset patch
 | |
| # User sherman
 | |
| # Date 1505950914 25200
 | |
| #      Wed Sep 20 16:41:54 2017 -0700
 | |
| # Node ID 723486922bfe4c17e3f5c067ce5e97229842fbcd
 | |
| # Parent  c8ac05bbe47771b3dafa2e7fc9a95d86d68d7c07
 | |
| 8186464: ZipFile cannot read some InfoZip ZIP64 zip files
 | |
| Reviewed-by: martin
 | |
| 
 | |
| diff --git openjdk.orig/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java openjdk/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java
 | |
| index 26e2a5bf9e9..2630c118817 100644
 | |
| --- openjdk.orig/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java
 | |
| +++ openjdk/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java
 | |
| @@ -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
 | |
| @@ -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());
 | |
| @@ -1014,28 +1016,36 @@ public 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;
 | |
|                  }
 | |
|              }
 | |
| @@ -1201,7 +1211,7 @@ public 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) {
 | |
| @@ -1292,7 +1302,7 @@ public 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()) {
 | |
|              //
 | |
| @@ -1849,8 +1859,8 @@ public 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) {
 | |
| @@ -1875,8 +1885,8 @@ public 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
 | |
|  
 | |
| diff --git openjdk.orig/jdk/src/share/native/java/util/zip/zip_util.c openjdk/jdk/src/share/native/java/util/zip/zip_util.c
 | |
| index 5fd6fea049d..858e5814e92 100644
 | |
| --- openjdk.orig/jdk/src/share/native/java/util/zip/zip_util.c
 | |
| +++ openjdk/jdk/src/share/native/java/util/zip/zip_util.c
 | |
| @@ -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
 | |
|      }
 | |
| @@ -567,6 +570,7 @@ readCEN(jzfile *zip, jint knownTotal)
 | |
|  {
 | |
|      /* Following are unsigned 32-bit */
 | |
|      jlong endpos, end64pos, cenpos, cenlen, cenoff;
 | |
| +    jlong cenlen64, cenoff64, centot64;
 | |
|      /* Following are unsigned 16-bit */
 | |
|      jint total, tablelen, i, j;
 | |
|      unsigned char *cenbuf = NULL;
 | |
| @@ -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);
 | |
| -            total = (jint)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;
 | |
| +            total = (jint)centot64;
 | |
|              endpos = end64pos;
 | |
|              endhdrlen = ZIP64_ENDHDR;
 | |
|          }
 | |
| diff --git openjdk.orig/jdk/test/java/util/zip/ZipFile/ReadZip.java openjdk/jdk/test/java/util/zip/ZipFile/ReadZip.java
 | |
| index ffe8a8ed712..9b380003893 100644
 | |
| --- openjdk.orig/jdk/test/java/util/zip/ZipFile/ReadZip.java
 | |
| +++ openjdk/jdk/test/java/util/zip/ZipFile/ReadZip.java
 | |
| @@ -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
 | |
| @@ -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
 | |
| @@ -144,8 +156,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", "."),
 | |
| @@ -153,5 +163,54 @@ public class ReadZip {
 | |
|                                        + 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");
 | |
| +	    env.put("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(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);
 | |
| +        }
 | |
|      }
 | |
|  }
 |