/* * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.nio.fs; import java.nio.file.*; import java.nio.file.attribute.*; import java.nio.channels.*; import java.net.URI; import java.util.concurrent.ExecutorService; import java.io.IOException; import java.io.FilePermission; import java.util.*; import java.security.AccessController; import sun.nio.ch.ThreadPool; import sun.security.util.SecurityConstants; import static sun.nio.fs.UnixNativeDispatcher.*; import static sun.nio.fs.UnixConstants.*; /** * Base implementation of FileSystemProvider */ public abstract class UnixFileSystemProvider extends AbstractFileSystemProvider { private static final String USER_DIR = "user.dir"; private final UnixFileSystem theFileSystem; public UnixFileSystemProvider() { String userDir = System.getProperty(USER_DIR); theFileSystem = newFileSystem(userDir); } /** * Constructs a new file system using the given default directory. */ abstract UnixFileSystem newFileSystem(String dir); @Override public final String getScheme() { return "file"; } private void checkUri(URI uri) { if (!uri.getScheme().equalsIgnoreCase(getScheme())) throw new IllegalArgumentException("URI does not match this provider"); if (uri.getAuthority() != null) throw new IllegalArgumentException("Authority component present"); if (uri.getPath() == null) throw new IllegalArgumentException("Path component is undefined"); if (!uri.getPath().equals("/")) throw new IllegalArgumentException("Path component should be '/'"); if (uri.getQuery() != null) throw new IllegalArgumentException("Query component present"); if (uri.getFragment() != null) throw new IllegalArgumentException("Fragment component present"); } @Override public final FileSystem newFileSystem(URI uri, Map env) { checkUri(uri); throw new FileSystemAlreadyExistsException(); } @Override public final FileSystem getFileSystem(URI uri) { checkUri(uri); return theFileSystem; } @Override public Path getPath(URI uri) { return UnixUriUtils.fromUri(theFileSystem, uri); } UnixPath checkPath(Path obj) { if (obj == null) throw new NullPointerException(); if (!(obj instanceof UnixPath)) throw new ProviderMismatchException(); return (UnixPath)obj; } boolean followLinks(LinkOption... options) { boolean followLinks = true; for (LinkOption option: options) { if (option == LinkOption.NOFOLLOW_LINKS) { followLinks = false; continue; } if (option == null) throw new NullPointerException(); throw new AssertionError("Should not get here"); } return followLinks; } @Override @SuppressWarnings("unchecked") public V getFileAttributeView(Path obj, Class type, LinkOption... options) { UnixPath file = UnixPath.toUnixPath(obj); boolean followLinks = followLinks(options); if (type == BasicFileAttributeView.class) return (V) UnixFileAttributeViews.createBasicView(file, followLinks); if (type == PosixFileAttributeView.class) return (V) UnixFileAttributeViews.createPosixView(file, followLinks); if (type == FileOwnerAttributeView.class) return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); if (type == null) throw new NullPointerException(); return (V) null; } @Override @SuppressWarnings("unchecked") public A readAttributes(Path file, Class type, LinkOption... options) throws IOException { Class view; if (type == BasicFileAttributes.class) view = BasicFileAttributeView.class; else if (type == PosixFileAttributes.class) view = PosixFileAttributeView.class; else if (type == null) throw new NullPointerException(); else throw new UnsupportedOperationException(); return (A) getFileAttributeView(file, view, options).readAttributes(); } @Override protected DynamicFileAttributeView getFileAttributeView(Path obj, String name, LinkOption... options) { UnixPath file = UnixPath.toUnixPath(obj); boolean followLinks = followLinks(options); if (name.equals("basic")) return UnixFileAttributeViews.createBasicView(file, followLinks); if (name.equals("posix")) return UnixFileAttributeViews.createPosixView(file, followLinks); if (name.equals("unix")) return UnixFileAttributeViews.createUnixView(file, followLinks); if (name.equals("owner")) return UnixFileAttributeViews.createOwnerView(file, followLinks); return null; } @Override public FileChannel newFileChannel(Path obj, Set options, FileAttribute... attrs) throws IOException { UnixPath file = checkPath(obj); int mode = UnixFileModeAttribute .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); try { return UnixChannelFactory.newFileChannel(file, options, mode); } catch (UnixException x) { x.rethrowAsIOException(file); return null; } } @Override public AsynchronousFileChannel newAsynchronousFileChannel(Path obj, Set options, ExecutorService executor, FileAttribute... attrs) throws IOException { UnixPath file = checkPath(obj); int mode = UnixFileModeAttribute .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0); try { return UnixChannelFactory .newAsynchronousFileChannel(file, options, mode, pool); } catch (UnixException x) { x.rethrowAsIOException(file); return null; } } @Override public SeekableByteChannel newByteChannel(Path obj, Set options, FileAttribute... attrs) throws IOException { UnixPath file = UnixPath.toUnixPath(obj); int mode = UnixFileModeAttribute .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); try { return UnixChannelFactory.newFileChannel(file, options, mode); } catch (UnixException x) { x.rethrowAsIOException(file); return null; // keep compiler happy } } @Override boolean implDelete(Path obj, boolean failIfNotExists) throws IOException { UnixPath file = UnixPath.toUnixPath(obj); file.checkDelete(); // need file attributes to know if file is directory UnixFileAttributes attrs = null; try { attrs = UnixFileAttributes.get(file, false); if (attrs.isDirectory()) { rmdir(file); } else { unlink(file); } return true; } catch (UnixException x) { // no-op if file does not exist if (!failIfNotExists && x.errno() == ENOENT) return false; // DirectoryNotEmptyException if not empty if (attrs != null && attrs.isDirectory() && (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) throw new DirectoryNotEmptyException(file.getPathForExecptionMessage()); x.rethrowAsIOException(file); return false; } } @Override public void copy(Path source, Path target, CopyOption... options) throws IOException { UnixCopyFile.copy(UnixPath.toUnixPath(source), UnixPath.toUnixPath(target), options); } @Override public void move(Path source, Path target, CopyOption... options) throws IOException { UnixCopyFile.move(UnixPath.toUnixPath(source), UnixPath.toUnixPath(target), options); } @Override public void checkAccess(Path obj, AccessMode... modes) throws IOException { UnixPath file = UnixPath.toUnixPath(obj); boolean e = false; boolean r = false; boolean w = false; boolean x = false; if (modes.length == 0) { e = true; } else { for (AccessMode mode: modes) { switch (mode) { case READ : r = true; break; case WRITE : w = true; break; case EXECUTE : x = true; break; default: throw new AssertionError("Should not get here"); } } } int mode = 0; if (e || r) { file.checkRead(); mode |= (r) ? R_OK : F_OK; } if (w) { file.checkWrite(); mode |= W_OK; } if (x) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { // not cached sm.checkExec(file.getPathForPermissionCheck()); } mode |= X_OK; } try { access(file, mode); } catch (UnixException exc) { exc.rethrowAsIOException(file); } } @Override public boolean isSameFile(Path obj1, Path obj2) throws IOException { UnixPath file1 = UnixPath.toUnixPath(obj1); if (file1.equals(obj2)) return true; if (obj2 == null) throw new NullPointerException(); if (!(obj2 instanceof UnixPath)) return false; UnixPath file2 = (UnixPath)obj2; // check security manager access to both files file1.checkRead(); file2.checkRead(); UnixFileAttributes attrs1; UnixFileAttributes attrs2; try { attrs1 = UnixFileAttributes.get(file1, true); } catch (UnixException x) { x.rethrowAsIOException(file1); return false; // keep compiler happy } try { attrs2 = UnixFileAttributes.get(file2, true); } catch (UnixException x) { x.rethrowAsIOException(file2); return false; // keep compiler happy } return attrs1.isSameFile(attrs2); } @Override public boolean isHidden(Path obj) { UnixPath file = UnixPath.toUnixPath(obj); file.checkRead(); UnixPath name = file.getFileName(); if (name == null) return false; return (name.asByteArray()[0] == '.'); } /** * Returns a FileStore to represent the file system where the given file * reside. */ abstract FileStore getFileStore(UnixPath path) throws IOException; @Override public FileStore getFileStore(Path obj) throws IOException { UnixPath file = UnixPath.toUnixPath(obj); SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); file.checkRead(); } return getFileStore(file); } @Override public void createDirectory(Path obj, FileAttribute... attrs) throws IOException { UnixPath dir = UnixPath.toUnixPath(obj); dir.checkWrite(); int mode = UnixFileModeAttribute .toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs); try { mkdir(dir, mode); } catch (UnixException x) { x.rethrowAsIOException(dir); } } @Override public DirectoryStream newDirectoryStream(Path obj, DirectoryStream.Filter filter) throws IOException { UnixPath dir = UnixPath.toUnixPath(obj); dir.checkRead(); if (filter == null) throw new NullPointerException(); // can't return SecureDirectoryStream on kernels that don't support // openat, etc. if (!supportsAtSysCalls()) { try { long ptr = opendir(dir); return new UnixDirectoryStream(dir, ptr, filter); } catch (UnixException x) { if (x.errno() == ENOTDIR) throw new NotDirectoryException(dir.getPathForExecptionMessage()); x.rethrowAsIOException(dir); } } // open directory and dup file descriptor for use by // opendir/readdir/closedir int dfd1 = -1; int dfd2 = -1; long dp = 0L; try { dfd1 = open(dir, O_RDONLY, 0); dfd2 = dup(dfd1); dp = fdopendir(dfd1); } catch (UnixException x) { if (dfd1 != -1) UnixNativeDispatcher.close(dfd1); if (dfd2 != -1) UnixNativeDispatcher.close(dfd2); if (x.errno() == UnixConstants.ENOTDIR) throw new NotDirectoryException(dir.getPathForExecptionMessage()); x.rethrowAsIOException(dir); } return new UnixSecureDirectoryStream(dir, dp, dfd2, filter); } @Override public void createSymbolicLink(Path obj1, Path obj2, FileAttribute... attrs) throws IOException { UnixPath link = UnixPath.toUnixPath(obj1); UnixPath target = UnixPath.toUnixPath(obj2); // no attributes supported when creating links if (attrs.length > 0) { UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE throw new UnsupportedOperationException("Initial file attributes" + "not supported when creating symbolic link"); } // permission check SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new LinkPermission("symbolic")); link.checkWrite(); } // create link try { symlink(target.asByteArray(), link); } catch (UnixException x) { x.rethrowAsIOException(link); } } @Override public void createLink(Path obj1, Path obj2) throws IOException { UnixPath link = UnixPath.toUnixPath(obj1); UnixPath existing = UnixPath.toUnixPath(obj2); // permission check SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new LinkPermission("hard")); link.checkWrite(); existing.checkWrite(); } try { link(existing, link); } catch (UnixException x) { x.rethrowAsIOException(link, existing); } } @Override public Path readSymbolicLink(Path obj1) throws IOException { UnixPath link = UnixPath.toUnixPath(obj1); // permission check SecurityManager sm = System.getSecurityManager(); if (sm != null) { FilePermission perm = new FilePermission(link.getPathForPermissionCheck(), SecurityConstants.FILE_READLINK_ACTION); AccessController.checkPermission(perm); } try { byte[] target = readlink(link); return new UnixPath(link.getFileSystem(), target); } catch (UnixException x) { if (x.errno() == UnixConstants.EINVAL) throw new NotLinkException(link.getPathForExecptionMessage()); x.rethrowAsIOException(link); return null; // keep compiler happy } } }