changeset 14490:67c711a267db

8141521: jrt file system's DirectoryStream reports child paths with wrong paths for directories under /packages Reviewed-by: alanb
author sundar
date Tue, 17 Nov 2015 12:56:35 +0100
parents 5b75092f3ecc
children e1579b30cbec
files src/java.base/share/classes/jdk/internal/jimage/UTF8String.java src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java test/jdk/internal/jrtfs/Basic.java
diffstat 7 files changed, 194 insertions(+), 166 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java	Tue Nov 17 12:56:35 2015 +0100
@@ -258,10 +258,10 @@
 
     @Override
     public String toString() {
-        ByteBuffer buffer = ByteBuffer.allocate(bytes.length+2);
+        ByteBuffer buffer = ByteBuffer.allocate(count+2);
         buffer.order(ByteOrder.BIG_ENDIAN);
-        buffer.putShort((short)bytes.length);
-        buffer.put(bytes);
+        buffer.putShort((short)count);
+        buffer.put(bytes, offset, count);
         ByteArrayInputStream stream = new ByteArrayInputStream(buffer.array());
         DataInputStream in = new DataInputStream(stream);
         try {
--- a/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java	Tue Nov 17 12:56:35 2015 +0100
@@ -232,48 +232,48 @@
     }
 
     // These methods throw read only file system exception
-    final void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime)
+    final void setTimes(AbstractJrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime)
             throws IOException {
         throw readOnly();
     }
 
-    final void createDirectory(byte[] path, FileAttribute<?>... attrs) throws IOException {
+    final void createDirectory(AbstractJrtPath jrtPath, FileAttribute<?>... attrs) throws IOException {
         throw readOnly();
     }
 
-    final void deleteFile(byte[] path, boolean failIfNotExists)
+    final void deleteFile(AbstractJrtPath jrtPath, boolean failIfNotExists)
             throws IOException {
         throw readOnly();
     }
 
-    final OutputStream newOutputStream(byte[] path, OpenOption... options)
+    final OutputStream newOutputStream(AbstractJrtPath jrtPath, OpenOption... options)
             throws IOException {
         throw readOnly();
     }
 
-    final void copyFile(boolean deletesrc, byte[] src, byte[] dst, CopyOption... options)
+    final void copyFile(boolean deletesrc, AbstractJrtPath srcPath, AbstractJrtPath dstPath, CopyOption... options)
             throws IOException {
         throw readOnly();
     }
 
-    final FileChannel newFileChannel(byte[] path,
+    final FileChannel newFileChannel(AbstractJrtPath jrtPath,
             Set<? extends OpenOption> options,
             FileAttribute<?>... attrs)
             throws IOException {
         throw new UnsupportedOperationException("newFileChannel");
     }
 
-    final InputStream newInputStream(byte[] path) throws IOException {
-        return new ByteArrayInputStream(getFileContent(path));
+    final InputStream newInputStream(AbstractJrtPath jrtPath) throws IOException {
+        return new ByteArrayInputStream(getFileContent(jrtPath));
     }
 
-    final SeekableByteChannel newByteChannel(byte[] path,
+    final SeekableByteChannel newByteChannel(AbstractJrtPath jrtPath,
             Set<? extends OpenOption> options,
             FileAttribute<?>... attrs)
             throws IOException {
         checkOptions(options);
 
-        byte[] buf = getFileContent(path);
+        byte[] buf = getFileContent(jrtPath);
         final ReadableByteChannel rbc
                 = Channels.newChannel(new ByteArrayInputStream(buf));
         final long size = buf.length;
@@ -328,8 +328,8 @@
         };
     }
 
-    final JrtFileStore getFileStore(AbstractJrtPath path) {
-        return new JrtFileStore(path);
+    final JrtFileStore getFileStore(AbstractJrtPath jrtPath) {
+        return new JrtFileStore(jrtPath);
     }
 
     final void ensureOpen() throws IOException {
@@ -341,29 +341,26 @@
     // abstract methods to be implemented by a particular jrt file system
     abstract AbstractJrtPath getRootPath();
 
-    abstract boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException;
+    abstract boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException;
 
     abstract boolean isLink(AbstractJrtPath jrtPath) throws IOException;
 
     abstract AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException;
 
-    abstract AbstractJrtFileAttributes getFileAttributes(byte[] path, LinkOption... options) throws IOException;
+    abstract AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException;
 
-    abstract boolean exists(byte[] path) throws IOException;
+    abstract boolean exists(AbstractJrtPath jrtPath) throws IOException;
 
-    abstract boolean isDirectory(byte[] path, boolean resolveLinks) throws IOException;
+    abstract boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException;
 
     /**
      * returns the list of child paths of the given directory "path"
      *
      * @param path name of the directory whose content is listed
-     * @param childPrefix prefix added to returned children names - may be null
-     * in which case absolute child paths are returned
      * @return iterator for child paths of the given directory path
      */
-    abstract Iterator<Path> iteratorOf(byte[] path, String childPrefix)
-            throws IOException;
+    abstract Iterator<Path> iteratorOf(AbstractJrtPath jrtPath) throws IOException;
 
     // returns the content of the file resource specified by the path
-    abstract byte[] getFileContent(byte[] path) throws IOException;
+    abstract byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException;
 }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java	Tue Nov 17 12:56:35 2015 +0100
@@ -685,7 +685,7 @@
 
     final void createDirectory(FileAttribute<?>... attrs)
             throws IOException {
-        jrtfs.createDirectory(getResolvedPath(), attrs);
+        jrtfs.createDirectory(this, attrs);
     }
 
     final InputStream newInputStream(OpenOption... options) throws IOException {
@@ -696,7 +696,7 @@
                 }
             }
         }
-        return jrtfs.newInputStream(getResolvedPath());
+        return jrtfs.newInputStream(this);
     }
 
     final DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter)
@@ -705,15 +705,15 @@
     }
 
     final void delete() throws IOException {
-        jrtfs.deleteFile(getResolvedPath(), true);
+        jrtfs.deleteFile(this, true);
     }
 
     final void deleteIfExists() throws IOException {
-        jrtfs.deleteFile(getResolvedPath(), false);
+        jrtfs.deleteFile(this, false);
     }
 
     final AbstractJrtFileAttributes getAttributes(LinkOption... options) throws IOException {
-        AbstractJrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath(), options);
+        AbstractJrtFileAttributes zfas = jrtfs.getFileAttributes(this, options);
         if (zfas == null) {
             throw new NoSuchFileException(toString());
         }
@@ -741,7 +741,7 @@
 
     final void setTimes(FileTime mtime, FileTime atime, FileTime ctime)
             throws IOException {
-        jrtfs.setTimes(getResolvedPath(), mtime, atime, ctime);
+        jrtfs.setTimes(this, mtime, atime, ctime);
     }
 
     final Map<String, Object> readAttributes(String attributes, LinkOption... options)
@@ -789,13 +789,13 @@
     final SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
             FileAttribute<?>... attrs)
             throws IOException {
-        return jrtfs.newByteChannel(getResolvedPath(), options, attrs);
+        return jrtfs.newByteChannel(this, options, attrs);
     }
 
     final FileChannel newFileChannel(Set<? extends OpenOption> options,
             FileAttribute<?>... attrs)
             throws IOException {
-        return jrtfs.newFileChannel(getResolvedPath(), options, attrs);
+        return jrtfs.newFileChannel(this, options, attrs);
     }
 
     final void checkAccess(AccessMode... modes) throws IOException {
@@ -816,7 +816,7 @@
             }
         }
 
-        BasicFileAttributes attrs = jrtfs.getFileAttributes(getResolvedPath());
+        BasicFileAttributes attrs = jrtfs.getFileAttributes(this);
         if (attrs == null && (path.length != 1 || path[0] != '/')) {
             throw new NoSuchFileException(toString());
         }
@@ -831,7 +831,7 @@
 
     final boolean exists() {
         try {
-            return jrtfs.exists(getResolvedPath());
+            return jrtfs.exists(this);
         } catch (IOException x) {
         }
         return false;
@@ -839,17 +839,17 @@
 
     final OutputStream newOutputStream(OpenOption... options) throws IOException {
         if (options.length == 0) {
-            return jrtfs.newOutputStream(getResolvedPath(),
+            return jrtfs.newOutputStream(this,
                     CREATE_NEW, WRITE);
         }
-        return jrtfs.newOutputStream(getResolvedPath(), options);
+        return jrtfs.newOutputStream(this, options);
     }
 
     final void move(AbstractJrtPath target, CopyOption... options)
             throws IOException {
         if (this.jrtfs == target.jrtfs) {
             jrtfs.copyFile(true,
-                    getResolvedPath(), target.getResolvedPath(),
+                    this, target,
                     options);
         } else {
             copyToTarget(target, options);
@@ -861,7 +861,7 @@
             throws IOException {
         if (this.jrtfs == target.jrtfs) {
             jrtfs.copyFile(false,
-                    getResolvedPath(), target.getResolvedPath(),
+                    this, target,
                     options);
         } else {
             copyToTarget(target, options);
@@ -901,7 +901,7 @@
             // create directory or file
             target.createDirectory();
         } else {
-            try (InputStream is = jrtfs.newInputStream(getResolvedPath()); OutputStream os = target.newOutputStream()) {
+            try (InputStream is = jrtfs.newInputStream(this); OutputStream os = target.newOutputStream()) {
                 byte[] buf = new byte[8192];
                 int n;
                 while ((n = is.read(buf)) != -1) {
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java	Tue Nov 17 12:56:35 2015 +0100
@@ -39,10 +39,7 @@
 final class JrtDirectoryStream implements DirectoryStream<Path> {
 
     private final AbstractJrtFileSystem jrtfs;
-    private final byte[] path;
-    // prefix to be used for children of this directory
-    // so that child path are reported relatively (if needed)
-    private final String childPrefix;
+    private final AbstractJrtPath dir;
     private final DirectoryStream.Filter<? super Path> filter;
     private volatile boolean isClosed;
     private volatile Iterator<Path> itr;
@@ -51,22 +48,12 @@
             DirectoryStream.Filter<? super java.nio.file.Path> filter)
             throws IOException {
         this.jrtfs = jrtPath.getFileSystem();
-        this.path = jrtPath.getResolvedPath();
+        this.dir = jrtPath;
         // sanity check
-        if (!jrtfs.isDirectory(path, true)) {
+        if (!jrtfs.isDirectory(dir, true)) {
             throw new NotDirectoryException(jrtPath.toString());
         }
 
-        // absolute path and does not have funky chars in front like /./java.base
-        if (jrtPath.isAbsolute() && (path.length == jrtPath.getPathLength())) {
-            childPrefix = null;
-        } else {
-            // cases where directory content needs to modified with prefix
-            // like ./java.base, /./java.base, java.base and so on.
-            String dirName = jrtPath.toString();
-            int idx = dirName.indexOf(JrtFileSystem.getString(path).substring(1));
-            childPrefix = dirName.substring(0, idx);
-        }
         this.filter = filter;
     }
 
@@ -80,7 +67,7 @@
         }
 
         try {
-            itr = jrtfs.iteratorOf(path, childPrefix);
+            itr = jrtfs.iteratorOf(dir);
         } catch (IOException e) {
             throw new IllegalStateException(e);
         }
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java	Tue Nov 17 12:56:35 2015 +0100
@@ -293,26 +293,26 @@
     }
 
     @Override
-    boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException {
-        Node n1 = checkNode(p1.getName());
-        Node n2 = checkNode(p2.getName());
+    boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException {
+        Node n1 = checkNode(jrtPath1);
+        Node n2 = checkNode(jrtPath2);
         return n1 == n2;
     }
 
     @Override
     boolean isLink(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath.getName()).isLink();
+        return checkNode(jrtPath).isLink();
     }
 
     @Override
     AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
-        String name = checkNode(jrtPath.getName()).resolveLink().getName();
+        String name = checkNode(jrtPath).resolveLink().getName();
         return toJrtExplodedPath(name);
     }
 
     @Override
-    AbstractJrtFileAttributes getFileAttributes(byte[] path, LinkOption... options) throws IOException {
-        Node node = checkNode(path);
+    AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException {
+        Node node = checkNode(jrtPath);
         if (node.isLink() && followLinks(options)) {
             node = node.resolveLink(true);
         }
@@ -320,9 +320,9 @@
     }
 
     @Override
-    boolean exists(byte[] path) throws IOException {
+    boolean exists(AbstractJrtPath jrtPath) throws IOException {
         try {
-            checkNode(path);
+            checkNode(jrtPath);
             return true;
         } catch (NoSuchFileException nsfe) {
             return false;
@@ -330,29 +330,37 @@
     }
 
     @Override
-    boolean isDirectory(byte[] path, boolean resolveLinks) throws IOException {
-        Node node = checkNode(path);
+    boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException {
+        Node node = checkNode(jrtPath);
         return resolveLinks && node.isLink()
                 ? node.resolveLink(true).isDirectory()
                 : node.isDirectory();
     }
 
     @Override
-    Iterator<Path> iteratorOf(byte[] path, String childPrefix) throws IOException {
-        Node node = checkNode(path).resolveLink(true);
+    Iterator<Path> iteratorOf(AbstractJrtPath dir) throws IOException {
+        Node node = checkNode(dir).resolveLink(true);
         if (!node.isDirectory()) {
-            throw new NotDirectoryException(getString(path));
+            throw new NotDirectoryException(getString(dir.getName()));
         }
 
-        Function<Node, Path> f = childPrefix == null
-                ? child -> toJrtExplodedPath(child.getName())
-                : child -> toJrtExplodedPath(childPrefix + child.getName().substring(1));
-        return node.getChildren().stream().map(f).collect(toList()).iterator();
+        Function<Node, Path> nodeToPath =
+            child -> dir.resolve(
+                toJrtExplodedPath(child.getName()).
+                getFileName());
+
+        return node.getChildren().stream().
+                   map(nodeToPath).collect(toList()).
+                   iterator();
     }
 
     @Override
-    byte[] getFileContent(byte[] path) throws IOException {
-        return checkNode(path).getContent();
+    byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath).getContent();
+    }
+
+    private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath.getResolvedPath());
     }
 
     private Node checkNode(byte[] path) throws IOException {
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java	Tue Nov 17 12:56:35 2015 +0100
@@ -36,6 +36,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 import static java.util.stream.Collectors.toList;
 import jdk.internal.jimage.ImageReader;
@@ -103,21 +104,21 @@
     @Override
     boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException {
         ensureOpen();
-        NodeAndImage n1 = findNode(p1.getName());
-        NodeAndImage n2 = findNode(p2.getName());
-        return n1.node.equals(n2.node);
+        Node node1 = findNode(p1);
+        Node node2 = findNode(p2);
+        return node1.equals(node2);
     }
 
     @Override
     boolean isLink(AbstractJrtPath jrtPath) throws IOException {
-        return checkNode(jrtPath.getName()).node.isLink();
+        return checkNode(jrtPath).isLink();
     }
 
     @Override
     AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException {
-        NodeAndImage ni = checkNode(jrtPath.getName());
-        if (ni.node.isLink()) {
-            Node node = ni.node.resolveLink();
+        Node node = checkNode(jrtPath);
+        if (node.isLink()) {
+            node = node.resolveLink();
             return toJrtPath(node.getName().getBytesCopy());
         }
 
@@ -125,19 +126,19 @@
     }
 
     @Override
-    JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options)
+    JrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options)
             throws IOException {
-        NodeAndImage ni = checkNode(path);
-        if (ni.node.isLink() && followLinks(options)) {
-            return new JrtFileAttributes(ni.node.resolveLink(true));
+        Node node = checkNode(jrtPath);
+        if (node.isLink() && followLinks(options)) {
+            return new JrtFileAttributes(node.resolveLink(true));
         }
-        return new JrtFileAttributes(ni.node);
+        return new JrtFileAttributes(node);
     }
 
     @Override
-    boolean exists(byte[] path) throws IOException {
+    boolean exists(AbstractJrtPath jrtPath) throws IOException {
         try {
-            checkNode(path);
+            checkNode(jrtPath);
         } catch (NoSuchFileException exp) {
             return false;
         }
@@ -145,39 +146,36 @@
     }
 
     @Override
-    boolean isDirectory(byte[] path, boolean resolveLinks)
+    boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks)
             throws IOException {
-        NodeAndImage ni = checkNode(path);
-        return resolveLinks && ni.node.isLink()
-                ? ni.node.resolveLink(true).isDirectory()
-                : ni.node.isDirectory();
+        Node node = checkNode(jrtPath);
+        return resolveLinks && node.isLink()
+                ? node.resolveLink(true).isDirectory()
+                : node.isDirectory();
     }
 
     @Override
-    Iterator<Path> iteratorOf(byte[] path, String childPrefix)
-            throws IOException {
-        NodeAndImage ni = checkNode(path);
-        Node node = ni.node.resolveLink(true);
-
+    Iterator<Path> iteratorOf(AbstractJrtPath jrtPath) throws IOException {
+        Node node = checkNode(jrtPath).resolveLink(true);
         if (!node.isDirectory()) {
-            throw new NotDirectoryException(getString(path));
+            throw new NotDirectoryException(getString(jrtPath.getName()));
         }
 
         if (node.isRootDir()) {
-            return rootDirIterator(path, childPrefix);
+            return rootDirIterator(jrtPath);
         } else if (node.isModulesDir()) {
-            return modulesDirIterator(path, childPrefix);
+            return modulesDirIterator(jrtPath);
         } else if (node.isPackagesDir()) {
-            return packagesDirIterator(path, childPrefix);
+            return packagesDirIterator(jrtPath);
         }
 
-        return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren());
+        return nodesToIterator(jrtPath, node.getChildren());
     }
 
     @Override
-    byte[] getFileContent(byte[] path) throws IOException {
-        final NodeAndImage ni = checkResource(path);
-        return ni.getResource();
+    byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException {
+        final Node node = checkResource(jrtPath);
+        return bootImage.getResource(node);
     }
 
     // Implementation details below this point
@@ -196,48 +194,32 @@
         }
     }
 
-    private static class NodeAndImage {
-
-        final Node node;
-        final ImageReader image;
-
-        NodeAndImage(Node node, ImageReader image) {
-            this.node = node;
-            this.image = image;
-        }
-
-        byte[] getResource() throws IOException {
-            return image.getResource(node);
-        }
-    }
-
-    private NodeAndImage lookup(byte[] path) {
-        ImageReader image = bootImage;
-        Node node;
+    private Node lookup(byte[] path) {
+        Node node = null;
         try {
             node = bootImage.findNode(path);
         } catch (RuntimeException re) {
             throw new InvalidPathException(getString(path), re.toString());
         }
-        return node != null ? new NodeAndImage(node, image) : null;
+        return node;
     }
 
-    private NodeAndImage lookupSymbolic(byte[] path) {
+    private Node lookupSymbolic(byte[] path) {
         for (int i = 1; i < path.length; i++) {
             if (path[i] == (byte) '/') {
                 byte[] prefix = Arrays.copyOfRange(path, 0, i);
-                NodeAndImage ni = lookup(prefix);
-                if (ni == null) {
+                Node node = lookup(prefix);
+                if (node == null) {
                     break;
                 }
 
-                if (ni.node.isLink()) {
-                    Node link = ni.node.resolveLink(true);
+                if (node.isLink()) {
+                    Node link = node.resolveLink(true);
                     // resolved symbolic path concatenated to the rest of the path
                     UTF8String resPath = link.getName().concat(new UTF8String(path, i));
                     byte[] resPathBytes = resPath.getBytesCopy();
-                    ni = lookup(resPathBytes);
-                    return ni != null ? ni : lookupSymbolic(resPathBytes);
+                    node = lookup(resPathBytes);
+                    return node != null ? node : lookupSymbolic(resPathBytes);
                 }
             }
         }
@@ -245,30 +227,42 @@
         return null;
     }
 
-    private NodeAndImage findNode(byte[] path) throws IOException {
-        NodeAndImage ni = lookup(path);
-        if (ni == null) {
-            ni = lookupSymbolic(path);
-            if (ni == null) {
+    private Node findNode(AbstractJrtPath jrtPath) throws IOException {
+        return findNode(jrtPath.getResolvedPath());
+    }
+
+    private Node findNode(byte[] path) throws IOException {
+        Node node = lookup(path);
+        if (node == null) {
+            node = lookupSymbolic(path);
+            if (node == null) {
                 throw new NoSuchFileException(getString(path));
             }
         }
-        return ni;
+        return node;
     }
 
-    private NodeAndImage checkNode(byte[] path) throws IOException {
+    private Node checkNode(AbstractJrtPath jrtPath) throws IOException {
+        return checkNode(jrtPath.getResolvedPath());
+    }
+
+    private Node checkNode(byte[] path) throws IOException {
         ensureOpen();
         return findNode(path);
     }
 
-    private NodeAndImage checkResource(byte[] path) throws IOException {
-        NodeAndImage ni = checkNode(path);
-        if (ni.node.isDirectory()) {
+    private Node checkResource(AbstractJrtPath jrtPath) throws IOException {
+        return checkResource(jrtPath.getResolvedPath());
+    }
+
+    private Node checkResource(byte[] path) throws IOException {
+        Node node = checkNode(path);
+        if (node.isDirectory()) {
             throw new FileSystemException(getString(path) + " is a directory");
         }
 
-        assert ni.node.isResource() : "resource node expected here";
-        return ni;
+        assert node.isResource() : "resource node expected here";
+        return node;
     }
 
     private JrtPath toJrtPath(String path) {
@@ -279,52 +273,54 @@
         return new JrtPath(this, path);
     }
 
-    private Iterator<Path> nodesToIterator(Path path, String childPrefix, List<Node> childNodes) {
-        Function<Node, Path> f = childPrefix == null
-                ? child -> toJrtPath(child.getNameString())
-                : child -> toJrtPath(childPrefix + child.getNameString().substring(1));
-        return childNodes.stream().map(f).collect(toList()).iterator();
+    private Iterator<Path> nodesToIterator(AbstractJrtPath dir, List<Node> childNodes) {
+        Function<Node, Path> nodeToPath =
+            child -> dir.resolve(
+                toJrtPath(child.getNameString()).getFileName());
+        return childNodes.stream().
+                map(nodeToPath).collect(toList()).
+                iterator();
     }
 
     private List<Node> rootChildren;
 
-    private synchronized void initRootChildren(byte[] path) {
+    private synchronized void initRootChildren(AbstractJrtPath jrtPath) throws IOException {
         if (rootChildren == null) {
             rootChildren = new ArrayList<>();
-            rootChildren.addAll(bootImage.findNode(path).getChildren());
+            rootChildren.addAll(findNode(jrtPath).getChildren());
         }
     }
 
-    private Iterator<Path> rootDirIterator(byte[] path, String childPrefix) throws IOException {
-        initRootChildren(path);
-        return nodesToIterator(rootPath, childPrefix, rootChildren);
+    private Iterator<Path> rootDirIterator(AbstractJrtPath jrtPath) throws IOException {
+        initRootChildren(jrtPath);
+        return nodesToIterator(jrtPath, rootChildren);
     }
 
     private List<Node> modulesChildren;
 
-    private synchronized void initModulesChildren(byte[] path) {
+    private synchronized void initModulesChildren(AbstractJrtPath jrtPath) throws IOException {
         if (modulesChildren == null) {
             modulesChildren = new ArrayList<>();
-            modulesChildren.addAll(bootImage.findNode(path).getChildren());
+            modulesChildren.addAll(findNode(jrtPath).getChildren());
         }
     }
 
-    private Iterator<Path> modulesDirIterator(byte[] path, String childPrefix) throws IOException {
-        initModulesChildren(path);
-        return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren);
+    private Iterator<Path> modulesDirIterator(AbstractJrtPath jrtPath) throws IOException {
+        initModulesChildren(jrtPath);
+        return nodesToIterator(jrtPath, modulesChildren);
     }
 
     private List<Node> packagesChildren;
 
-    private synchronized void initPackagesChildren(byte[] path) {
+    private synchronized void initPackagesChildren(AbstractJrtPath jrtPath) throws IOException {
         if (packagesChildren == null) {
             packagesChildren = new ArrayList<>();
-            packagesChildren.addAll(bootImage.findNode(path).getChildren());
+            packagesChildren.addAll(findNode(jrtPath).getChildren());
         }
     }
 
-    private Iterator<Path> packagesDirIterator(byte[] path, String childPrefix) throws IOException {
-        initPackagesChildren(path);
-        return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren);
+    private Iterator<Path> packagesDirIterator(AbstractJrtPath jrtPath) throws IOException {
+        initPackagesChildren(jrtPath);
+        return nodesToIterator(jrtPath, packagesChildren);
     }
 }
--- a/test/jdk/internal/jrtfs/Basic.java	Mon Nov 16 16:02:09 2015 -0800
+++ b/test/jdk/internal/jrtfs/Basic.java	Tue Nov 17 12:56:35 2015 +0100
@@ -28,6 +28,7 @@
  */
 
 import java.io.InputStream;
+import java.io.IOException;
 import java.io.DataInputStream;
 import java.nio.file.DirectoryStream;
 import java.nio.file.InvalidPathException;
@@ -583,4 +584,43 @@
         }
         assertTrue(ipe != null);
     }
+
+    @DataProvider(name="packagesLinkedDirs")
+    private Object[][] packagesLinkedDirs() {
+        return new Object[][] {
+            { "/packages/java.lang/java.base/java/lang/ref"             },
+            { "/./packages/java.lang/java.base/java/lang/ref"           },
+            { "packages/java.lang/java.base/java/lang/ref"              },
+            { "/packages/../packages/java.lang/java.base/java/lang/ref" },
+            { "/packages/java.lang/java.base/java/util/zip"             },
+            { "/./packages/java.lang/java.base/java/util/zip"           },
+            { "packages/java.lang/java.base/java/util/zip"              },
+            { "/packages/../packages/java.lang/java.base/java/util/zip" },
+            { "/packages/com.oracle/java.xml.ws/com"                    },
+            { "/./packages/com.oracle/java.xml.ws/com"                  },
+            { "packages/com.oracle/java.xml.ws/com"                     },
+            { "/packages/../packages/com.oracle/java.xml.ws/com"        }
+        };
+    }
+
+    // @bug 8141521: jrt file system's DirectoryStream reports child paths
+    // with wrong paths for directories under /packages
+    @Test(dataProvider = "packagesLinkedDirs")
+    public void dirStreamPackagesDirTest(String dirName) throws IOException {
+        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        Path path = fs.getPath(dirName);
+
+        int childCount = 0, dirPrefixOkayCount = 0;
+        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(path)) {
+            for (Path child : dirStream) {
+                childCount++;
+                if (child.toString().startsWith(dirName)) {
+                    dirPrefixOkayCount++;
+                }
+            }
+        }
+
+        assertTrue(childCount != 0);
+        assertEquals(dirPrefixOkayCount, childCount);
+    }
 }