8069211: (zipfs) ZipFileSystem creates corrupted zip if entry output stream gets closed more than once
authorsherman
Thu, 22 Jan 2015 08:51:45 -0800
changeset 28561 bdb3c1d3a975
parent 28560 44e28eba3922
child 28562 a3e34b364d38
8069211: (zipfs) ZipFileSystem creates corrupted zip if entry output stream gets closed more than once Summary: to synchronize the write and close methods of the entry output stream Reviewed-by: alanb
jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java
jdk/test/jdk/nio/zipfs/ZipFSTester.java
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Thu Jan 22 12:33:05 2015 +0000
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Thu Jan 22 08:51:45 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 201, 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
@@ -1533,6 +1533,7 @@
         private CRC32 crc;
         private Entry e;
         private long written;
+        private boolean isClosed = false;
 
         EntryOutputStream(Entry e, OutputStream os)
             throws IOException
@@ -1545,9 +1546,14 @@
         }
 
         @Override
-        public void write(byte b[], int off, int len) throws IOException {
+        public synchronized void write(byte b[], int off, int len)
+            throws IOException
+        {
             if (e.type != Entry.FILECH)    // only from sync
                 ensureOpen();
+            if (isClosed) {
+                throw new IOException("Stream closed");
+            }
             if (off < 0 || len < 0 || off > b.length - len) {
                 throw new IndexOutOfBoundsException();
             } else if (len == 0) {
@@ -1568,7 +1574,11 @@
         }
 
         @Override
-        public void close() throws IOException {
+        public synchronized void close() throws IOException {
+            if (isClosed) {
+                return;
+            }
+            isClosed = true;
             // TBD ensureOpen();
             switch (e.method) {
             case METHOD_DEFLATED:
--- a/jdk/test/jdk/nio/zipfs/ZipFSTester.java	Thu Jan 22 12:33:05 2015 +0000
+++ b/jdk/test/jdk/nio/zipfs/ZipFSTester.java	Thu Jan 22 08:51:45 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, 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
@@ -45,6 +45,7 @@
 import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.spi.FileSystemProvider;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -67,7 +68,7 @@
  *
  * @test
  * @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596
- *      7157656 8002390 7012868 7012856 8015728 8038500 8040059
+ *      7157656 8002390 7012868 7012856 8015728 8038500 8040059 8069211
  * @summary Test Zip filesystem provider
  * @run main ZipFSTester
  * @run main/othervm/java.security.policy=test.policy ZipFSTester
@@ -89,6 +90,7 @@
             test2(fs);   // more tests
         }
         testTime(jarFile);
+        test8069211();
     }
 
     static void test0(FileSystem fs)
@@ -416,6 +418,29 @@
         Files.delete(fsPath);
     }
 
+    static void test8069211() throws Exception {
+        // create a new filesystem, copy this file into it
+        Map<String, Object> env = new HashMap<String, Object>();
+        env.put("create", "true");
+        Path fsPath = getTempPath();
+        try (FileSystem fs = newZipFileSystem(fsPath, env);) {
+            OutputStream out = Files.newOutputStream(fs.getPath("/foo"));
+            out.write("hello".getBytes());
+            out.close();
+            out.close();
+        }
+        try (FileSystem fs = newZipFileSystem(fsPath, new HashMap<String, Object>())) {
+            if (!Arrays.equals(Files.readAllBytes(fs.getPath("/foo")),
+                               "hello".getBytes())) {
+                throw new RuntimeException("entry close() failed");
+            }
+        } catch (Exception x) {
+            throw new RuntimeException("entry close() failed", x);
+        } finally {
+            Files.delete(fsPath);
+        }
+    }
+
     private static FileSystem newZipFileSystem(Path path, Map<String, ?> env)
         throws Exception
     {