Path: blob/master/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java
41137 views
/*1* Copyright (c) 2008, 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*/2425package sun.nio.fs;2627import java.nio.file.*;28import java.nio.file.attribute.*;29import java.nio.file.spi.FileTypeDetector;30import java.nio.channels.*;31import java.net.URI;32import java.util.concurrent.ExecutorService;33import java.io.IOException;34import java.io.FilePermission;35import java.util.*;3637import sun.nio.ch.ThreadPool;38import sun.security.util.SecurityConstants;39import static sun.nio.fs.UnixNativeDispatcher.*;40import static sun.nio.fs.UnixConstants.*;4142/**43* Base implementation of FileSystemProvider44*/4546public abstract class UnixFileSystemProvider47extends AbstractFileSystemProvider48{49private static final String USER_DIR = "user.dir";50private static final byte[] EMPTY_PATH = new byte[0];51private final UnixFileSystem theFileSystem;5253public UnixFileSystemProvider() {54String userDir = System.getProperty(USER_DIR);55theFileSystem = newFileSystem(userDir);56}5758UnixFileSystem theFileSystem() {59return theFileSystem;60}6162/**63* Constructs a new file system using the given default directory.64*/65abstract UnixFileSystem newFileSystem(String dir);6667@Override68public final String getScheme() {69return "file";70}7172private void checkUri(URI uri) {73if (!uri.getScheme().equalsIgnoreCase(getScheme()))74throw new IllegalArgumentException("URI does not match this provider");75if (uri.getRawAuthority() != null)76throw new IllegalArgumentException("Authority component present");77String path = uri.getPath();78if (path == null)79throw new IllegalArgumentException("Path component is undefined");80if (!path.equals("/"))81throw new IllegalArgumentException("Path component should be '/'");82if (uri.getRawQuery() != null)83throw new IllegalArgumentException("Query component present");84if (uri.getRawFragment() != null)85throw new IllegalArgumentException("Fragment component present");86}8788@Override89public final FileSystem newFileSystem(URI uri, Map<String,?> env) {90checkUri(uri);91throw new FileSystemAlreadyExistsException();92}9394@Override95public final FileSystem getFileSystem(URI uri) {96checkUri(uri);97return theFileSystem;98}99100@Override101public Path getPath(URI uri) {102return UnixUriUtils.fromUri(theFileSystem, uri);103}104105UnixPath checkPath(Path obj) {106if (obj == null)107throw new NullPointerException();108if (!(obj instanceof UnixPath))109throw new ProviderMismatchException();110return (UnixPath)obj;111}112113@Override114@SuppressWarnings("unchecked")115public <V extends FileAttributeView> V getFileAttributeView(Path obj,116Class<V> type,117LinkOption... options)118{119UnixPath file = UnixPath.toUnixPath(obj);120boolean followLinks = Util.followLinks(options);121if (type == BasicFileAttributeView.class)122return (V) UnixFileAttributeViews.createBasicView(file, followLinks);123if (type == PosixFileAttributeView.class)124return (V) UnixFileAttributeViews.createPosixView(file, followLinks);125if (type == FileOwnerAttributeView.class)126return (V) UnixFileAttributeViews.createOwnerView(file, followLinks);127if (type == null)128throw new NullPointerException();129return (V) null;130}131132@Override133@SuppressWarnings("unchecked")134public <A extends BasicFileAttributes> A readAttributes(Path file,135Class<A> type,136LinkOption... options)137throws IOException138{139Class<? extends BasicFileAttributeView> view;140if (type == BasicFileAttributes.class)141view = BasicFileAttributeView.class;142else if (type == PosixFileAttributes.class)143view = PosixFileAttributeView.class;144else if (type == null)145throw new NullPointerException();146else147throw new UnsupportedOperationException();148return (A) getFileAttributeView(file, view, options).readAttributes();149}150151@Override152protected DynamicFileAttributeView getFileAttributeView(Path obj,153String name,154LinkOption... options)155{156UnixPath file = UnixPath.toUnixPath(obj);157boolean followLinks = Util.followLinks(options);158if (name.equals("basic"))159return UnixFileAttributeViews.createBasicView(file, followLinks);160if (name.equals("posix"))161return UnixFileAttributeViews.createPosixView(file, followLinks);162if (name.equals("unix"))163return UnixFileAttributeViews.createUnixView(file, followLinks);164if (name.equals("owner"))165return UnixFileAttributeViews.createOwnerView(file, followLinks);166return null;167}168169@Override170public FileChannel newFileChannel(Path obj,171Set<? extends OpenOption> options,172FileAttribute<?>... attrs)173throws IOException174{175UnixPath file = checkPath(obj);176int mode = UnixFileModeAttribute177.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);178try {179return UnixChannelFactory.newFileChannel(file, options, mode);180} catch (UnixException x) {181x.rethrowAsIOException(file);182return null;183}184}185186@Override187public AsynchronousFileChannel newAsynchronousFileChannel(Path obj,188Set<? extends OpenOption> options,189ExecutorService executor,190FileAttribute<?>... attrs) throws IOException191{192UnixPath file = checkPath(obj);193int mode = UnixFileModeAttribute194.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);195ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);196try {197return UnixChannelFactory198.newAsynchronousFileChannel(file, options, mode, pool);199} catch (UnixException x) {200x.rethrowAsIOException(file);201return null;202}203}204205206@Override207public SeekableByteChannel newByteChannel(Path obj,208Set<? extends OpenOption> options,209FileAttribute<?>... attrs)210throws IOException211{212UnixPath file = UnixPath.toUnixPath(obj);213int mode = UnixFileModeAttribute214.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);215try {216return UnixChannelFactory.newFileChannel(file, options, mode);217} catch (UnixException x) {218x.rethrowAsIOException(file);219return null; // keep compiler happy220}221}222223@Override224boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {225UnixPath file = UnixPath.toUnixPath(obj);226file.checkDelete();227228// need file attributes to know if file is directory229UnixFileAttributes attrs = null;230try {231attrs = UnixFileAttributes.get(file, false);232if (attrs.isDirectory()) {233rmdir(file);234} else {235unlink(file);236}237return true;238} catch (UnixException x) {239// no-op if file does not exist240if (!failIfNotExists && x.errno() == ENOENT)241return false;242243// DirectoryNotEmptyException if not empty244if (attrs != null && attrs.isDirectory() &&245(x.errno() == EEXIST || x.errno() == ENOTEMPTY))246throw new DirectoryNotEmptyException(file.getPathForExceptionMessage());247248x.rethrowAsIOException(file);249return false;250}251}252253@Override254public void copy(Path source, Path target, CopyOption... options)255throws IOException256{257UnixCopyFile.copy(UnixPath.toUnixPath(source),258UnixPath.toUnixPath(target),259options);260}261262@Override263public void move(Path source, Path target, CopyOption... options)264throws IOException265{266UnixCopyFile.move(UnixPath.toUnixPath(source),267UnixPath.toUnixPath(target),268options);269}270271@Override272public void checkAccess(Path obj, AccessMode... modes) throws IOException {273UnixPath file = UnixPath.toUnixPath(obj);274boolean e = false;275boolean r = false;276boolean w = false;277boolean x = false;278279if (modes.length == 0) {280e = true;281} else {282for (AccessMode mode: modes) {283switch (mode) {284case READ : r = true; break;285case WRITE : w = true; break;286case EXECUTE : x = true; break;287default: throw new AssertionError("Should not get here");288}289}290}291292int mode = 0;293if (e || r) {294file.checkRead();295mode |= (r) ? R_OK : F_OK;296}297if (w) {298file.checkWrite();299mode |= W_OK;300}301if (x) {302@SuppressWarnings("removal")303SecurityManager sm = System.getSecurityManager();304if (sm != null) {305// not cached306sm.checkExec(file.getPathForPermissionCheck());307}308mode |= X_OK;309}310try {311access(file, mode);312} catch (UnixException exc) {313exc.rethrowAsIOException(file);314}315}316317@Override318public boolean isSameFile(Path obj1, Path obj2) throws IOException {319UnixPath file1 = UnixPath.toUnixPath(obj1);320if (file1.equals(obj2))321return true;322if (obj2 == null)323throw new NullPointerException();324if (!(obj2 instanceof UnixPath))325return false;326UnixPath file2 = (UnixPath)obj2;327328// check security manager access to both files329file1.checkRead();330file2.checkRead();331332UnixFileAttributes attrs1;333UnixFileAttributes attrs2;334try {335attrs1 = UnixFileAttributes.get(file1, true);336} catch (UnixException x) {337x.rethrowAsIOException(file1);338return false; // keep compiler happy339}340try {341attrs2 = UnixFileAttributes.get(file2, true);342} catch (UnixException x) {343x.rethrowAsIOException(file2);344return false; // keep compiler happy345}346return attrs1.isSameFile(attrs2);347}348349@Override350public boolean isHidden(Path obj) {351UnixPath file = UnixPath.toUnixPath(obj);352file.checkRead();353UnixPath name = file.getFileName();354if (name == null)355return false;356357byte[] path;358if (name.isEmpty()) { // corner case for empty paths359path = name.getFileSystem().defaultDirectory();360} else {361path = name.asByteArray();362}363return path[0] == '.';364}365366/**367* Returns a FileStore to represent the file system where the given file368* reside.369*/370abstract FileStore getFileStore(UnixPath path) throws IOException;371372@Override373public FileStore getFileStore(Path obj) throws IOException {374UnixPath file = UnixPath.toUnixPath(obj);375@SuppressWarnings("removal")376SecurityManager sm = System.getSecurityManager();377if (sm != null) {378sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));379file.checkRead();380}381return getFileStore(file);382}383384@Override385public void createDirectory(Path obj, FileAttribute<?>... attrs)386throws IOException387{388UnixPath dir = UnixPath.toUnixPath(obj);389dir.checkWrite();390391int mode = UnixFileModeAttribute.toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);392try {393mkdir(dir, mode);394} catch (UnixException x) {395if (x.errno() == EISDIR)396throw new FileAlreadyExistsException(dir.toString());397x.rethrowAsIOException(dir);398}399}400401402@Override403public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)404throws IOException405{406UnixPath dir = UnixPath.toUnixPath(obj);407dir.checkRead();408if (filter == null)409throw new NullPointerException();410411// can't return SecureDirectoryStream on kernels that don't support openat412// or O_NOFOLLOW413if (!openatSupported() || O_NOFOLLOW == 0) {414try {415long ptr = opendir(dir);416return new UnixDirectoryStream(dir, ptr, filter);417} catch (UnixException x) {418if (x.errno() == ENOTDIR)419throw new NotDirectoryException(dir.getPathForExceptionMessage());420x.rethrowAsIOException(dir);421}422}423424// open directory and dup file descriptor for use by425// opendir/readdir/closedir426int dfd1 = -1;427int dfd2 = -1;428long dp = 0L;429try {430dfd1 = open(dir, O_RDONLY, 0);431dfd2 = dup(dfd1);432dp = fdopendir(dfd1);433} catch (UnixException x) {434if (dfd1 != -1)435UnixNativeDispatcher.close(dfd1);436if (dfd2 != -1)437UnixNativeDispatcher.close(dfd2);438if (x.errno() == UnixConstants.ENOTDIR)439throw new NotDirectoryException(dir.getPathForExceptionMessage());440x.rethrowAsIOException(dir);441}442return new UnixSecureDirectoryStream(dir, dp, dfd2, filter);443}444445@Override446public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)447throws IOException448{449UnixPath link = UnixPath.toUnixPath(obj1);450UnixPath target = UnixPath.toUnixPath(obj2);451452// no attributes supported when creating links453if (attrs.length > 0) {454UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE455throw new UnsupportedOperationException("Initial file attributes" +456"not supported when creating symbolic link");457}458459// permission check460@SuppressWarnings("removal")461SecurityManager sm = System.getSecurityManager();462if (sm != null) {463sm.checkPermission(new LinkPermission("symbolic"));464link.checkWrite();465}466467// create link468try {469symlink(target.asByteArray(), link);470} catch (UnixException x) {471x.rethrowAsIOException(link);472}473}474475@Override476public void createLink(Path obj1, Path obj2) throws IOException {477UnixPath link = UnixPath.toUnixPath(obj1);478UnixPath existing = UnixPath.toUnixPath(obj2);479480// permission check481@SuppressWarnings("removal")482SecurityManager sm = System.getSecurityManager();483if (sm != null) {484sm.checkPermission(new LinkPermission("hard"));485link.checkWrite();486existing.checkWrite();487}488try {489link(existing, link);490} catch (UnixException x) {491x.rethrowAsIOException(link, existing);492}493}494495@Override496public Path readSymbolicLink(Path obj1) throws IOException {497UnixPath link = UnixPath.toUnixPath(obj1);498// permission check499@SuppressWarnings("removal")500SecurityManager sm = System.getSecurityManager();501if (sm != null) {502FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),503SecurityConstants.FILE_READLINK_ACTION);504sm.checkPermission(perm);505}506try {507byte[] target = readlink(link);508return new UnixPath(link.getFileSystem(), target);509} catch (UnixException x) {510if (x.errno() == UnixConstants.EINVAL)511throw new NotLinkException(link.getPathForExceptionMessage());512x.rethrowAsIOException(link);513return null; // keep compiler happy514}515}516517@Override518public final boolean isDirectory(Path obj) {519UnixPath file = UnixPath.toUnixPath(obj);520file.checkRead();521int mode = UnixNativeDispatcher.stat(file);522return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);523}524525@Override526public final boolean isRegularFile(Path obj) {527UnixPath file = UnixPath.toUnixPath(obj);528file.checkRead();529int mode = UnixNativeDispatcher.stat(file);530return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);531}532533@Override534public final boolean exists(Path obj) {535UnixPath file = UnixPath.toUnixPath(obj);536file.checkRead();537return UnixNativeDispatcher.exists(file);538}539540/**541* Returns a {@code FileTypeDetector} for this platform.542*/543FileTypeDetector getFileTypeDetector() {544return new AbstractFileTypeDetector() {545@Override546public String implProbeContentType(Path file) {547return null;548}549};550}551552/**553* Returns a {@code FileTypeDetector} that chains the given array of file554* type detectors. When the {@code implProbeContentType} method is invoked555* then each of the detectors is invoked in turn, the result from the556* first to detect the file type is returned.557*/558final FileTypeDetector chain(final AbstractFileTypeDetector... detectors) {559return new AbstractFileTypeDetector() {560@Override561protected String implProbeContentType(Path file) throws IOException {562for (AbstractFileTypeDetector detector : detectors) {563String result = detector.implProbeContentType(file);564if (result != null && !result.isEmpty()) {565return result;566}567}568return null;569}570};571}572573@Override574public byte[] getSunPathForSocketFile(Path obj) {575UnixPath file = UnixPath.toUnixPath(obj);576if (file.isEmpty()) {577return EMPTY_PATH;578}579return file.getByteArrayForSysCalls();580}581}582583584