Path: blob/master/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java
67770 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 jdk.internal.util.StaticProperty;38import sun.nio.ch.ThreadPool;39import sun.security.util.SecurityConstants;40import static sun.nio.fs.UnixNativeDispatcher.*;41import static sun.nio.fs.UnixConstants.*;4243/**44* Base implementation of FileSystemProvider45*/4647public abstract class UnixFileSystemProvider48extends AbstractFileSystemProvider49{50private static final byte[] EMPTY_PATH = new byte[0];51private final UnixFileSystem theFileSystem;5253public UnixFileSystemProvider() {54theFileSystem = newFileSystem(StaticProperty.userDir());55}5657UnixFileSystem theFileSystem() {58return theFileSystem;59}6061/**62* Constructs a new file system using the given default directory.63*/64abstract UnixFileSystem newFileSystem(String dir);6566@Override67public final String getScheme() {68return "file";69}7071private void checkUri(URI uri) {72if (!uri.getScheme().equalsIgnoreCase(getScheme()))73throw new IllegalArgumentException("URI does not match this provider");74if (uri.getRawAuthority() != null)75throw new IllegalArgumentException("Authority component present");76String path = uri.getPath();77if (path == null)78throw new IllegalArgumentException("Path component is undefined");79if (!path.equals("/"))80throw new IllegalArgumentException("Path component should be '/'");81if (uri.getRawQuery() != null)82throw new IllegalArgumentException("Query component present");83if (uri.getRawFragment() != null)84throw new IllegalArgumentException("Fragment component present");85}8687@Override88public final FileSystem newFileSystem(URI uri, Map<String,?> env) {89checkUri(uri);90throw new FileSystemAlreadyExistsException();91}9293@Override94public final FileSystem getFileSystem(URI uri) {95checkUri(uri);96return theFileSystem;97}9899@Override100public Path getPath(URI uri) {101return UnixUriUtils.fromUri(theFileSystem, uri);102}103104UnixPath checkPath(Path obj) {105if (obj == null)106throw new NullPointerException();107if (!(obj instanceof UnixPath))108throw new ProviderMismatchException();109return (UnixPath)obj;110}111112@Override113@SuppressWarnings("unchecked")114public <V extends FileAttributeView> V getFileAttributeView(Path obj,115Class<V> type,116LinkOption... options)117{118UnixPath file = UnixPath.toUnixPath(obj);119boolean followLinks = Util.followLinks(options);120if (type == BasicFileAttributeView.class)121return (V) UnixFileAttributeViews.createBasicView(file, followLinks);122if (type == PosixFileAttributeView.class)123return (V) UnixFileAttributeViews.createPosixView(file, followLinks);124if (type == FileOwnerAttributeView.class)125return (V) UnixFileAttributeViews.createOwnerView(file, followLinks);126if (type == null)127throw new NullPointerException();128return (V) null;129}130131@Override132@SuppressWarnings("unchecked")133public <A extends BasicFileAttributes> A readAttributes(Path file,134Class<A> type,135LinkOption... options)136throws IOException137{138Class<? extends BasicFileAttributeView> view;139if (type == BasicFileAttributes.class)140view = BasicFileAttributeView.class;141else if (type == PosixFileAttributes.class)142view = PosixFileAttributeView.class;143else if (type == null)144throw new NullPointerException();145else146throw new UnsupportedOperationException();147return (A) getFileAttributeView(file, view, options).readAttributes();148}149150@Override151protected DynamicFileAttributeView getFileAttributeView(Path obj,152String name,153LinkOption... options)154{155UnixPath file = UnixPath.toUnixPath(obj);156boolean followLinks = Util.followLinks(options);157if (name.equals("basic"))158return UnixFileAttributeViews.createBasicView(file, followLinks);159if (name.equals("posix"))160return UnixFileAttributeViews.createPosixView(file, followLinks);161if (name.equals("unix"))162return UnixFileAttributeViews.createUnixView(file, followLinks);163if (name.equals("owner"))164return UnixFileAttributeViews.createOwnerView(file, followLinks);165return null;166}167168@Override169public FileChannel newFileChannel(Path obj,170Set<? extends OpenOption> options,171FileAttribute<?>... attrs)172throws IOException173{174UnixPath file = checkPath(obj);175int mode = UnixFileModeAttribute176.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);177try {178return UnixChannelFactory.newFileChannel(file, options, mode);179} catch (UnixException x) {180x.rethrowAsIOException(file);181return null;182}183}184185@Override186public AsynchronousFileChannel newAsynchronousFileChannel(Path obj,187Set<? extends OpenOption> options,188ExecutorService executor,189FileAttribute<?>... attrs) throws IOException190{191UnixPath file = checkPath(obj);192int mode = UnixFileModeAttribute193.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);194ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);195try {196return UnixChannelFactory197.newAsynchronousFileChannel(file, options, mode, pool);198} catch (UnixException x) {199x.rethrowAsIOException(file);200return null;201}202}203204205@Override206public SeekableByteChannel newByteChannel(Path obj,207Set<? extends OpenOption> options,208FileAttribute<?>... attrs)209throws IOException210{211UnixPath file = UnixPath.toUnixPath(obj);212int mode = UnixFileModeAttribute213.toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);214try {215return UnixChannelFactory.newFileChannel(file, options, mode);216} catch (UnixException x) {217x.rethrowAsIOException(file);218return null; // keep compiler happy219}220}221222@Override223boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {224UnixPath file = UnixPath.toUnixPath(obj);225file.checkDelete();226227// need file attributes to know if file is directory228UnixFileAttributes attrs = null;229try {230attrs = UnixFileAttributes.get(file, false);231if (attrs.isDirectory()) {232rmdir(file);233} else {234unlink(file);235}236return true;237} catch (UnixException x) {238// no-op if file does not exist239if (!failIfNotExists && x.errno() == ENOENT)240return false;241242// DirectoryNotEmptyException if not empty243if (attrs != null && attrs.isDirectory() &&244(x.errno() == EEXIST || x.errno() == ENOTEMPTY))245throw new DirectoryNotEmptyException(file.getPathForExceptionMessage());246247x.rethrowAsIOException(file);248return false;249}250}251252@Override253public void copy(Path source, Path target, CopyOption... options)254throws IOException255{256UnixCopyFile.copy(UnixPath.toUnixPath(source),257UnixPath.toUnixPath(target),258options);259}260261@Override262public void move(Path source, Path target, CopyOption... options)263throws IOException264{265UnixCopyFile.move(UnixPath.toUnixPath(source),266UnixPath.toUnixPath(target),267options);268}269270@Override271public void checkAccess(Path obj, AccessMode... modes) throws IOException {272UnixPath file = UnixPath.toUnixPath(obj);273boolean e = false;274boolean r = false;275boolean w = false;276boolean x = false;277278if (modes.length == 0) {279e = true;280} else {281for (AccessMode mode: modes) {282switch (mode) {283case READ : r = true; break;284case WRITE : w = true; break;285case EXECUTE : x = true; break;286default: throw new AssertionError("Should not get here");287}288}289}290291int mode = 0;292if (e || r) {293file.checkRead();294mode |= (r) ? R_OK : F_OK;295}296if (w) {297file.checkWrite();298mode |= W_OK;299}300if (x) {301@SuppressWarnings("removal")302SecurityManager sm = System.getSecurityManager();303if (sm != null) {304// not cached305sm.checkExec(file.getPathForPermissionCheck());306}307mode |= X_OK;308}309try {310access(file, mode);311} catch (UnixException exc) {312exc.rethrowAsIOException(file);313}314}315316@Override317public boolean isSameFile(Path obj1, Path obj2) throws IOException {318UnixPath file1 = UnixPath.toUnixPath(obj1);319if (file1.equals(obj2))320return true;321if (obj2 == null)322throw new NullPointerException();323if (!(obj2 instanceof UnixPath))324return false;325UnixPath file2 = (UnixPath)obj2;326327// check security manager access to both files328file1.checkRead();329file2.checkRead();330331UnixFileAttributes attrs1;332UnixFileAttributes attrs2;333try {334attrs1 = UnixFileAttributes.get(file1, true);335} catch (UnixException x) {336x.rethrowAsIOException(file1);337return false; // keep compiler happy338}339try {340attrs2 = UnixFileAttributes.get(file2, true);341} catch (UnixException x) {342x.rethrowAsIOException(file2);343return false; // keep compiler happy344}345return attrs1.isSameFile(attrs2);346}347348@Override349public boolean isHidden(Path obj) {350UnixPath file = UnixPath.toUnixPath(obj);351file.checkRead();352UnixPath name = file.getFileName();353if (name == null)354return false;355356byte[] path;357if (name.isEmpty()) { // corner case for empty paths358path = name.getFileSystem().defaultDirectory();359} else {360path = name.asByteArray();361}362return path[0] == '.';363}364365/**366* Returns a FileStore to represent the file system where the given file367* reside.368*/369abstract FileStore getFileStore(UnixPath path) throws IOException;370371@Override372public FileStore getFileStore(Path obj) throws IOException {373UnixPath file = UnixPath.toUnixPath(obj);374@SuppressWarnings("removal")375SecurityManager sm = System.getSecurityManager();376if (sm != null) {377sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));378file.checkRead();379}380return getFileStore(file);381}382383@Override384public void createDirectory(Path obj, FileAttribute<?>... attrs)385throws IOException386{387UnixPath dir = UnixPath.toUnixPath(obj);388dir.checkWrite();389390int mode = UnixFileModeAttribute.toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);391try {392mkdir(dir, mode);393} catch (UnixException x) {394if (x.errno() == EISDIR)395throw new FileAlreadyExistsException(dir.toString());396x.rethrowAsIOException(dir);397}398}399400401@Override402public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)403throws IOException404{405UnixPath dir = UnixPath.toUnixPath(obj);406dir.checkRead();407if (filter == null)408throw new NullPointerException();409410// can't return SecureDirectoryStream on kernels that don't support openat411// or O_NOFOLLOW412if (!openatSupported() || O_NOFOLLOW == 0) {413try {414long ptr = opendir(dir);415return new UnixDirectoryStream(dir, ptr, filter);416} catch (UnixException x) {417if (x.errno() == ENOTDIR)418throw new NotDirectoryException(dir.getPathForExceptionMessage());419x.rethrowAsIOException(dir);420}421}422423// open directory and dup file descriptor for use by424// opendir/readdir/closedir425int dfd1 = -1;426int dfd2 = -1;427long dp = 0L;428try {429dfd1 = open(dir, O_RDONLY, 0);430dfd2 = dup(dfd1);431dp = fdopendir(dfd1);432} catch (UnixException x) {433if (dfd1 != -1)434UnixNativeDispatcher.close(dfd1);435if (dfd2 != -1)436UnixNativeDispatcher.close(dfd2);437if (x.errno() == UnixConstants.ENOTDIR)438throw new NotDirectoryException(dir.getPathForExceptionMessage());439x.rethrowAsIOException(dir);440}441return new UnixSecureDirectoryStream(dir, dp, dfd2, filter);442}443444@Override445public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)446throws IOException447{448UnixPath link = UnixPath.toUnixPath(obj1);449UnixPath target = UnixPath.toUnixPath(obj2);450451// no attributes supported when creating links452if (attrs.length > 0) {453UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE454throw new UnsupportedOperationException("Initial file attributes" +455"not supported when creating symbolic link");456}457458// permission check459@SuppressWarnings("removal")460SecurityManager sm = System.getSecurityManager();461if (sm != null) {462sm.checkPermission(new LinkPermission("symbolic"));463link.checkWrite();464}465466// create link467try {468symlink(target.asByteArray(), link);469} catch (UnixException x) {470x.rethrowAsIOException(link);471}472}473474@Override475public void createLink(Path obj1, Path obj2) throws IOException {476UnixPath link = UnixPath.toUnixPath(obj1);477UnixPath existing = UnixPath.toUnixPath(obj2);478479// permission check480@SuppressWarnings("removal")481SecurityManager sm = System.getSecurityManager();482if (sm != null) {483sm.checkPermission(new LinkPermission("hard"));484link.checkWrite();485existing.checkWrite();486}487try {488link(existing, link);489} catch (UnixException x) {490x.rethrowAsIOException(link, existing);491}492}493494@Override495public Path readSymbolicLink(Path obj1) throws IOException {496UnixPath link = UnixPath.toUnixPath(obj1);497// permission check498@SuppressWarnings("removal")499SecurityManager sm = System.getSecurityManager();500if (sm != null) {501FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),502SecurityConstants.FILE_READLINK_ACTION);503sm.checkPermission(perm);504}505try {506byte[] target = readlink(link);507return new UnixPath(link.getFileSystem(), target);508} catch (UnixException x) {509if (x.errno() == UnixConstants.EINVAL)510throw new NotLinkException(link.getPathForExceptionMessage());511x.rethrowAsIOException(link);512return null; // keep compiler happy513}514}515516@Override517public final boolean isDirectory(Path obj) {518UnixPath file = UnixPath.toUnixPath(obj);519file.checkRead();520int mode = UnixNativeDispatcher.stat(file);521return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);522}523524@Override525public final boolean isRegularFile(Path obj) {526UnixPath file = UnixPath.toUnixPath(obj);527file.checkRead();528int mode = UnixNativeDispatcher.stat(file);529return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);530}531532@Override533public final boolean exists(Path obj) {534UnixPath file = UnixPath.toUnixPath(obj);535file.checkRead();536return UnixNativeDispatcher.exists(file);537}538539/**540* Returns a {@code FileTypeDetector} for this platform.541*/542FileTypeDetector getFileTypeDetector() {543return new AbstractFileTypeDetector() {544@Override545public String implProbeContentType(Path file) {546return null;547}548};549}550551/**552* Returns a {@code FileTypeDetector} that chains the given array of file553* type detectors. When the {@code implProbeContentType} method is invoked554* then each of the detectors is invoked in turn, the result from the555* first to detect the file type is returned.556*/557final FileTypeDetector chain(final AbstractFileTypeDetector... detectors) {558return new AbstractFileTypeDetector() {559@Override560protected String implProbeContentType(Path file) throws IOException {561for (AbstractFileTypeDetector detector : detectors) {562String result = detector.implProbeContentType(file);563if (result != null && !result.isEmpty()) {564return result;565}566}567return null;568}569};570}571572@Override573public byte[] getSunPathForSocketFile(Path obj) {574UnixPath file = UnixPath.toUnixPath(obj);575if (file.isEmpty()) {576return EMPTY_PATH;577}578return file.getByteArrayForSysCalls();579}580}581582583