diff --git a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java index 52063e45a78..3cb7ca49d39 100644 --- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java +++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java @@ -65,8 +65,9 @@ public class ZipFileSystemProvider extends FileSystemProvider { // only support legacy JAR URL syntax jar:{uri}!/{entry} for now String spec = uri.getRawSchemeSpecificPart(); int sep = spec.indexOf("!/"); - if (sep != -1) + if (sep != -1) { spec = spec.substring(0, sep); + } return Paths.get(new URI(spec)).toAbsolutePath(); } catch (URISyntaxException e) { throw new IllegalArgumentException(e.getMessage(), e); @@ -107,6 +108,9 @@ public class ZipFileSystemProvider extends FileSystemProvider { // assume NOT a zip/jar file throw new UnsupportedOperationException(); } + if (realPath == null) { // newly created + realPath = path.toRealPath(); + } filesystems.put(realPath, zipfs); return zipfs; } @@ -132,7 +136,6 @@ public class ZipFileSystemProvider extends FileSystemProvider { @Override public Path getPath(URI uri) { - String spec = uri.getSchemeSpecificPart(); int sep = spec.indexOf("!/"); if (sep == -1) diff --git a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java index 6e40ab574e0..edc6d3c2f00 100644 --- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java +++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java @@ -32,10 +32,10 @@ import java.nio.file.*; import java.nio.file.DirectoryStream.Filter; import java.nio.file.attribute.*; import java.util.*; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.StandardOpenOption.*; import static java.nio.file.StandardCopyOption.*; - /** * * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal @@ -180,7 +180,7 @@ class ZipPath implements Path { public URI toUri() { try { return new URI("jar", - zfs.getZipFile().toUri() + + decodeUri(zfs.getZipFile().toUri().toString()) + "!" + zfs.getString(toAbsolutePath().path), null); @@ -866,4 +866,57 @@ class ZipPath implements Path { } } } + + private static int decode(char c) { + if ((c >= '0') && (c <= '9')) + return c - '0'; + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + assert false; + return -1; + } + + // to avoid double escape + static String decodeUri(String s) { + if (s == null) + return s; + int n = s.length(); + if (n == 0) + return s; + if (s.indexOf('%') < 0) + return s; + + StringBuilder sb = new StringBuilder(n); + byte[] bb = new byte[n]; + boolean betweenBrackets = false; + + for (int i = 0; i < n;) { + char c = s.charAt(i); + if (c == '[') { + betweenBrackets = true; + } else if (betweenBrackets && c == ']') { + betweenBrackets = false; + } + if (c != '%' || betweenBrackets ) { + sb.append(c); + i++; + continue; + } + int nb = 0; + while (c == '%') { + assert (n - i >= 2); + bb[nb++] = (byte)(((decode(s.charAt(++i)) & 0xf) << 4) | + (decode(s.charAt(++i)) & 0xf)); + if (++i >= n) { + break; + } + c = s.charAt(i); + } + sb.append(new String(bb, 0, nb, UTF_8)); + } + return sb.toString(); + } + } diff --git a/jdk/test/jdk/nio/zipfs/ZipFSTester.java b/jdk/test/jdk/nio/zipfs/ZipFSTester.java index 69777e3728f..58389250e43 100644 --- a/jdk/test/jdk/nio/zipfs/ZipFSTester.java +++ b/jdk/test/jdk/nio/zipfs/ZipFSTester.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.net.URLDecoder; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; @@ -69,6 +70,7 @@ import static java.nio.file.StandardCopyOption.*; * @test * @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596 * 7157656 8002390 7012868 7012856 8015728 8038500 8040059 8069211 + * 8131067 * @summary Test Zip filesystem provider * @run main ZipFSTester * @run main/othervm/java.security.policy=test.policy ZipFSTester @@ -91,6 +93,7 @@ public class ZipFSTester { } testTime(jarFile); test8069211(); + test8131067(); } static void test0(FileSystem fs) @@ -441,11 +444,34 @@ public class ZipFSTester { } } + static void test8131067() throws Exception { + Map env = new HashMap(); + env.put("create", "true"); + + // file name with space character for URI to quote it + File tmp = File.createTempFile("test zipfs", "zip"); + tmp.delete(); // we need a clean path, no file + Path fsPath = tmp.toPath(); + try (FileSystem fs = newZipFileSystem(fsPath, env);) { + Files.write(fs.getPath("/foo"), "hello".getBytes()); + URI fooUri = fs.getPath("/foo").toUri(); + if (!Arrays.equals(Files.readAllBytes(Paths.get(fooUri)), + "hello".getBytes())) { + throw new RuntimeException("entry close() failed"); + } + } finally { + Files.delete(fsPath); + } + } + private static FileSystem newZipFileSystem(Path path, Map env) throws Exception { + // Use URLDecoder (for test only) to remove the double escaped space + // character return FileSystems.newFileSystem( - new URI("jar", path.toUri().toString(), null), env, null); + new URI("jar", URLDecoder.decode(path.toUri().toString(), "utf8"), + null), env, null); } private static Path getTempPath() throws IOException