--- old/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java 2015-06-23 14:28:59.000000000 +0200 +++ new/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java 2015-06-23 14:28:59.000000000 +0200 @@ -31,9 +31,9 @@ import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.charset.Charset; -import java.nio.file.AccessMode; import java.nio.file.ClosedFileSystemException; import java.nio.file.CopyOption; +import java.nio.file.LinkOption; import java.nio.file.FileStore; import java.nio.file.FileSystem; import java.nio.file.FileSystemException; @@ -45,16 +45,13 @@ import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.ReadOnlyFileSystemException; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.nio.file.WatchService; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileTime; import java.nio.file.attribute.UserPrincipalLookupService; import java.nio.file.spi.FileSystemProvider; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -63,8 +60,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.regex.Pattern; -import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; import jdk.internal.jimage.ImageReader; import jdk.internal.jimage.ImageReader.Node; import jdk.internal.jimage.UTF8String; @@ -74,6 +72,7 @@ */ class JrtFileSystem extends FileSystem { private static final Charset UTF_8 = Charset.forName("UTF-8"); + private final JrtFileSystemProvider provider; // System image readers private ImageReader bootImage; @@ -109,7 +108,8 @@ this.extImage = openImage(SystemImages.extImagePath); this.appImage = openImage(SystemImages.appImagePath); - rootPath = new JrtPath(this, new byte[]{'/'}); + byte[] root = new byte[] { '/' }; + rootPath = new JrtPath(this, root); isOpen = true; } @@ -149,12 +149,12 @@ synchronized(this) { isOpen = false; - // close all image readers and null out + // close all image reader and null out bootImage.close(); - extImage.close(); - appImage.close(); bootImage = null; + extImage.close(); extImage = null; + appImage.close(); appImage = null; } } @@ -289,21 +289,52 @@ } } - private NodeAndImage findNode(byte[] path) throws IOException { - ImageReader image = bootImage; + private NodeAndImage lookup(byte[] path) { Node node = bootImage.findNode(path); + ImageReader image = bootImage; if (node == null) { - image = extImage; node = extImage.findNode(path); + image = extImage; } if (node == null) { - image = appImage; node = appImage.findNode(path); + image = appImage; + } + return node != null? new NodeAndImage(node, image) : null; + } + + private NodeAndImage 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) { + break; + } + + if (ni.node.isLink()) { + Node link = ni.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); + } + } } - if (node == null || node.isHidden()) { - throw new NoSuchFileException(getString(path)); + + return null; + } + + private NodeAndImage findNode(byte[] path) throws IOException { + NodeAndImage ni = lookup(path); + if (ni == null) { + ni = lookupSymbolic(path); + if (ni == null) { + throw new NoSuchFileException(getString(path)); + } } - return new NodeAndImage(node, image); + return ni; } private NodeAndImage checkNode(byte[] path) throws IOException { @@ -321,10 +352,28 @@ return ni; } + static boolean followLinks(LinkOption... options) { + if (options != null) { + for (LinkOption lo : options) { + if (lo == LinkOption.NOFOLLOW_LINKS) { + return false; + } else if (lo == null) { + throw new NullPointerException(); + } else { + throw new AssertionError("should not reach here"); + } + } + } + return true; + } + // package private helpers - JrtFileAttributes getFileAttributes(byte[] path) + JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options) throws IOException { NodeAndImage ni = checkNode(path); + if (ni.node.isLink() && followLinks(options)) { + return new JrtFileAttributes(ni.node.resolveLink(true)); + } return new JrtFileAttributes(ni.node); } @@ -343,11 +392,13 @@ return true; } - boolean isDirectory(byte[] path) + boolean isDirectory(byte[] path, boolean resolveLinks) throws IOException { ensureOpen(); NodeAndImage ni = checkNode(path); - return ni.node.isDirectory(); + return resolveLinks && ni.node.isLink()? + ni.node.resolveLink(true).isDirectory() : + ni.node.isDirectory(); } JrtPath toJrtPath(String path) { @@ -358,6 +409,28 @@ return new JrtPath(this, path); } + boolean isSameFile(JrtPath p1, JrtPath p2) throws IOException { + NodeAndImage n1 = findNode(p1.getName()); + NodeAndImage n2 = findNode(p2.getName()); + return n1.node.equals(n2.node); + } + + boolean isLink(JrtPath jrtPath) throws IOException { + return findNode(jrtPath.getName()).node.isLink(); + } + + JrtPath resolveLink(JrtPath jrtPath) throws IOException { + NodeAndImage ni = findNode(jrtPath.getName()); + if (ni.node.isLink()) { + Node node = ni.node.resolveLink(); + return toJrtPath(node.getName().getBytesCopy()); + } + + return jrtPath; + } + + private Map> packagesTreeChildren = new ConcurrentHashMap<>(); + /** * returns the list of child paths of the given directory "path" * @@ -369,49 +442,73 @@ Iterator iteratorOf(byte[] path, String childPrefix) throws IOException { NodeAndImage ni = checkNode(path); - if (!ni.node.isDirectory()) { + Node node = ni.node.resolveLink(true); + + if (!node.isDirectory()) { throw new NotDirectoryException(getString(path)); } - if (ni.node.isRootDir()) { + if (node.isRootDir()) { return rootDirIterator(path, childPrefix); + } else if (node.isModulesDir()) { + return modulesDirIterator(path, childPrefix); + } else if (node.isPackagesDir()) { + return packagesDirIterator(path, childPrefix); + } else if (node.getNameString().startsWith("/packages/")) { + if (ni.image != appImage) { + UTF8String name = node.getName(); + List children = packagesTreeChildren.get(name); + if (children != null) { + return nodesToIterator(toJrtPath(path), childPrefix, children); + } + + children = new ArrayList<>(); + children.addAll(node.getChildren()); + Node tmpNode = null; + // found in boot + if (ni.image == bootImage) { + tmpNode = extImage.findNode(name); + if (tmpNode != null) { + children.addAll(tmpNode.getChildren()); + } + } + + // found in ext + tmpNode = appImage.findNode(name); + if (tmpNode != null) { + children.addAll(tmpNode.getChildren()); + } + + packagesTreeChildren.put(name, children); + return nodesToIterator(toJrtPath(path), childPrefix, children); + } } - return nodesToIterator(toJrtPath(path), childPrefix, ni.node.getChildren()); + return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren()); } private Iterator nodesToIterator(Path path, String childPrefix, List childNodes) { - List childPaths; - if (childPrefix == null) { - childPaths = childNodes.stream() - .filter(Node::isVisible) - .map(child -> toJrtPath(child.getNameString())) - .collect(Collectors.toCollection(ArrayList::new)); - } else { - childPaths = childNodes.stream() - .filter(Node::isVisible) - .map(child -> toJrtPath(childPrefix + child.getNameString().substring(1))) - .collect(Collectors.toCollection(ArrayList::new)); - } - return childPaths.iterator(); + Function f = childPrefix == null + ? child -> toJrtPath(child.getNameString()) + : child -> toJrtPath(childPrefix + child.getNameString().substring(1)); + return childNodes.stream().map(f).collect(toList()).iterator(); } - private List rootChildren; - private static void addRootDirContent(List dest, List src) { - for (Node n : src) { - // only module directories at the top level. Filter other stuff! - if (n.isModuleDir()) { - dest.add(n); + private void addRootDirContent(List children) { + for (Node child : children) { + if (!(child.isModulesDir() || child.isPackagesDir())) { + rootChildren.add(child); } } } + private List rootChildren; private synchronized void initRootChildren(byte[] path) { if (rootChildren == null) { rootChildren = new ArrayList<>(); - addRootDirContent(rootChildren, bootImage.findNode(path).getChildren()); - addRootDirContent(rootChildren, extImage.findNode(path).getChildren()); - addRootDirContent(rootChildren, appImage.findNode(path).getChildren()); + rootChildren.addAll(bootImage.findNode(path).getChildren()); + addRootDirContent(extImage.findNode(path).getChildren()); + addRootDirContent(appImage.findNode(path).getChildren()); } } @@ -420,6 +517,35 @@ return nodesToIterator(rootPath, childPrefix, rootChildren); } + private List modulesChildren; + private synchronized void initModulesChildren(byte[] path) { + if (modulesChildren == null) { + modulesChildren = new ArrayList<>(); + modulesChildren.addAll(bootImage.findNode(path).getChildren()); + modulesChildren.addAll(appImage.findNode(path).getChildren()); + modulesChildren.addAll(extImage.findNode(path).getChildren()); + } + } + + private Iterator modulesDirIterator(byte[] path, String childPrefix) throws IOException { + initModulesChildren(path); + return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren); + } + + private List packagesChildren; + private synchronized void initPackagesChildren(byte[] path) { + if (packagesChildren == null) { + packagesChildren = new ArrayList<>(); + packagesChildren.addAll(bootImage.findNode(path).getChildren()); + packagesChildren.addAll(extImage.findNode(path).getChildren()); + packagesChildren.addAll(appImage.findNode(path).getChildren()); + } + } + private Iterator packagesDirIterator(byte[] path, String childPrefix) throws IOException { + initPackagesChildren(path); + return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren); + } + void createDirectory(byte[] dir, FileAttribute... attrs) throws IOException { throw readOnly();