Path: blob/master/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java
41159 views
/*1* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package jdk.internal.jrtfs;2526import java.io.*;27import java.net.MalformedURLException;28import java.net.URL;29import java.net.URLClassLoader;30import java.nio.channels.*;31import java.nio.file.*;32import java.nio.file.DirectoryStream.Filter;33import java.nio.file.attribute.*;34import java.nio.file.spi.FileSystemProvider;35import java.net.URI;36import java.security.AccessController;37import java.security.PrivilegedAction;38import java.util.HashMap;39import java.util.Map;40import java.util.Objects;41import java.util.Set;42import java.util.concurrent.ExecutorService;4344/**45* File system provider for jrt file systems. Conditionally creates jrt fs on46* .jimage file or exploded modules directory of underlying JDK.47*48* @implNote This class needs to maintain JDK 8 source compatibility.49*50* It is used internally in the JDK to implement jimage/jrtfs access,51* but also compiled and delivered as part of the jrtfs.jar to support access52* to the jimage file provided by the shipped JDK by tools running on JDK 8.53*/54public final class JrtFileSystemProvider extends FileSystemProvider {5556private volatile FileSystem theFileSystem;5758public JrtFileSystemProvider() {59}6061@Override62public String getScheme() {63return "jrt";64}6566/**67* Need RuntimePermission "accessSystemModules" to create or get jrt:/68*/69private void checkPermission() {70@SuppressWarnings("removal")71SecurityManager sm = System.getSecurityManager();72if (sm != null) {73RuntimePermission perm = new RuntimePermission("accessSystemModules");74sm.checkPermission(perm);75}76}7778private void checkUri(URI uri) {79if (!uri.getScheme().equalsIgnoreCase(getScheme())) {80throw new IllegalArgumentException("URI does not match this provider");81}82if (uri.getAuthority() != null) {83throw new IllegalArgumentException("Authority component present");84}85if (uri.getPath() == null) {86throw new IllegalArgumentException("Path component is undefined");87}88if (!uri.getPath().equals("/")) {89throw new IllegalArgumentException("Path component should be '/'");90}91if (uri.getQuery() != null) {92throw new IllegalArgumentException("Query component present");93}94if (uri.getFragment() != null) {95throw new IllegalArgumentException("Fragment component present");96}97}9899@Override100public FileSystem newFileSystem(URI uri, Map<String, ?> env)101throws IOException {102Objects.requireNonNull(env);103checkPermission();104checkUri(uri);105if (env.containsKey("java.home")) {106return newFileSystem((String)env.get("java.home"), uri, env);107} else {108return new JrtFileSystem(this, env);109}110}111112private static final String JRT_FS_JAR = "jrt-fs.jar";113private FileSystem newFileSystem(String targetHome, URI uri, Map<String, ?> env)114throws IOException {115Objects.requireNonNull(targetHome);116Path jrtfs = FileSystems.getDefault().getPath(targetHome, "lib", JRT_FS_JAR);117if (Files.notExists(jrtfs)) {118throw new IOException(jrtfs.toString() + " not exist");119}120Map<String,?> newEnv = new HashMap<>(env);121newEnv.remove("java.home");122ClassLoader cl = newJrtFsLoader(jrtfs);123try {124Class<?> c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl);125@SuppressWarnings("deprecation")126Object tmp = c.newInstance();127return ((FileSystemProvider)tmp).newFileSystem(uri, newEnv);128} catch (ClassNotFoundException |129IllegalAccessException |130InstantiationException e) {131throw new IOException(e);132}133}134135private static class JrtFsLoader extends URLClassLoader {136JrtFsLoader(URL[] urls) {137super(urls);138}139@Override140protected Class<?> loadClass(String cn, boolean resolve)141throws ClassNotFoundException142{143Class<?> c = findLoadedClass(cn);144if (c == null) {145URL u = findResource(cn.replace('.', '/') + ".class");146if (u != null) {147c = findClass(cn);148} else {149return super.loadClass(cn, resolve);150}151}152if (resolve)153resolveClass(c);154return c;155}156}157158@SuppressWarnings("removal")159private static URLClassLoader newJrtFsLoader(Path jrtfs) {160final URL url;161try {162url = jrtfs.toUri().toURL();163} catch (MalformedURLException mue) {164throw new IllegalArgumentException(mue);165}166167final URL[] urls = new URL[] { url };168return AccessController.doPrivileged(169new PrivilegedAction<URLClassLoader>() {170@Override171public URLClassLoader run() {172return new JrtFsLoader(urls);173}174}175);176}177178@Override179public Path getPath(URI uri) {180checkPermission();181if (!uri.getScheme().equalsIgnoreCase(getScheme())) {182throw new IllegalArgumentException("URI does not match this provider");183}184if (uri.getAuthority() != null) {185throw new IllegalArgumentException("Authority component present");186}187if (uri.getQuery() != null) {188throw new IllegalArgumentException("Query component present");189}190if (uri.getFragment() != null) {191throw new IllegalArgumentException("Fragment component present");192}193String path = uri.getPath();194if (path == null || path.charAt(0) != '/' || path.contains("..")) {195throw new IllegalArgumentException("Invalid path component");196}197198return getTheFileSystem().getPath("/modules" + path);199}200201private FileSystem getTheFileSystem() {202checkPermission();203FileSystem fs = this.theFileSystem;204if (fs == null) {205synchronized (this) {206fs = this.theFileSystem;207if (fs == null) {208try {209this.theFileSystem = fs = new JrtFileSystem(this, null);210} catch (IOException ioe) {211throw new InternalError(ioe);212}213}214}215}216return fs;217}218219@Override220public FileSystem getFileSystem(URI uri) {221checkPermission();222checkUri(uri);223return getTheFileSystem();224}225226// Checks that the given file is a JrtPath227static final JrtPath toJrtPath(Path path) {228Objects.requireNonNull(path, "path");229if (!(path instanceof JrtPath)) {230throw new ProviderMismatchException();231}232return (JrtPath) path;233}234235@Override236public void checkAccess(Path path, AccessMode... modes) throws IOException {237toJrtPath(path).checkAccess(modes);238}239240@Override241public Path readSymbolicLink(Path link) throws IOException {242return toJrtPath(link).readSymbolicLink();243}244245@Override246public void copy(Path src, Path target, CopyOption... options)247throws IOException {248toJrtPath(src).copy(toJrtPath(target), options);249}250251@Override252public void createDirectory(Path path, FileAttribute<?>... attrs)253throws IOException {254toJrtPath(path).createDirectory(attrs);255}256257@Override258public final void delete(Path path) throws IOException {259toJrtPath(path).delete();260}261262@Override263@SuppressWarnings("unchecked")264public <V extends FileAttributeView> V265getFileAttributeView(Path path, Class<V> type, LinkOption... options) {266return JrtFileAttributeView.get(toJrtPath(path), type, options);267}268269@Override270public FileStore getFileStore(Path path) throws IOException {271return toJrtPath(path).getFileStore();272}273274@Override275public boolean isHidden(Path path) {276return toJrtPath(path).isHidden();277}278279@Override280public boolean isSameFile(Path path, Path other) throws IOException {281return toJrtPath(path).isSameFile(other);282}283284@Override285public void move(Path src, Path target, CopyOption... options)286throws IOException {287toJrtPath(src).move(toJrtPath(target), options);288}289290@Override291public AsynchronousFileChannel newAsynchronousFileChannel(Path path,292Set<? extends OpenOption> options,293ExecutorService exec,294FileAttribute<?>... attrs)295throws IOException {296throw new UnsupportedOperationException();297}298299@Override300public SeekableByteChannel newByteChannel(Path path,301Set<? extends OpenOption> options,302FileAttribute<?>... attrs)303throws IOException {304return toJrtPath(path).newByteChannel(options, attrs);305}306307@Override308public DirectoryStream<Path> newDirectoryStream(309Path path, Filter<? super Path> filter) throws IOException {310return toJrtPath(path).newDirectoryStream(filter);311}312313@Override314public FileChannel newFileChannel(Path path,315Set<? extends OpenOption> options,316FileAttribute<?>... attrs)317throws IOException {318return toJrtPath(path).newFileChannel(options, attrs);319}320321@Override322public InputStream newInputStream(Path path, OpenOption... options)323throws IOException {324return toJrtPath(path).newInputStream(options);325}326327@Override328public OutputStream newOutputStream(Path path, OpenOption... options)329throws IOException {330return toJrtPath(path).newOutputStream(options);331}332333@Override334@SuppressWarnings("unchecked") // Cast to A335public <A extends BasicFileAttributes> A336readAttributes(Path path, Class<A> type, LinkOption... options)337throws IOException {338if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) {339return (A) toJrtPath(path).getAttributes(options);340}341return null;342}343344@Override345public Map<String, Object>346readAttributes(Path path, String attribute, LinkOption... options)347throws IOException {348return toJrtPath(path).readAttributes(attribute, options);349}350351@Override352public void setAttribute(Path path, String attribute,353Object value, LinkOption... options)354throws IOException {355toJrtPath(path).setAttribute(attribute, value, options);356}357}358359360