/* * Copyright 2008-2009 Sun Microsystems, Inc. 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. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.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.file.spi.*; import java.io.IOException; import java.util.*; import java.util.regex.Pattern; import java.security.AccessController; import sun.security.action.GetPropertyAction; /** * Base implementation of FileSystem for Unix-like implementations. */ abstract class UnixFileSystem extends FileSystem { private final UnixFileSystemProvider provider; private final byte[] defaultDirectory; private final boolean needToResolveAgainstDefaultDirectory; private final UnixPath rootDirectory; // package-private UnixFileSystem(UnixFileSystemProvider provider, String dir) { this.provider = provider; this.defaultDirectory = UnixPath.normalizeAndCheck(dir).getBytes(); if (this.defaultDirectory[0] != '/') { throw new RuntimeException("default directory must be absolute"); } // if process-wide chdir is allowed or default directory is not the // process working directory then paths must be resolved against the // default directory. String propValue = AccessController.doPrivileged( new GetPropertyAction("sun.nio.fs.chdirAllowed", "false")); boolean chdirAllowed = (propValue.length() == 0) ? true : Boolean.valueOf(propValue); if (chdirAllowed) { this.needToResolveAgainstDefaultDirectory = true; } else { byte[] cwd = UnixNativeDispatcher.getcwd(); boolean defaultIsCwd = (cwd.length == defaultDirectory.length); if (defaultIsCwd) { for (int i=0; i getRootDirectories() { final List allowedList = Collections.unmodifiableList(Arrays.asList((Path)rootDirectory)); return new Iterable() { public Iterator iterator() { try { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkRead(rootDirectory.toString()); return allowedList.iterator(); } catch (SecurityException x) { List disallowed = Collections.emptyList(); return disallowed.iterator(); } } }; } /** * Returns object to iterate over entries in mounttab or equivalent */ abstract Iterable getMountEntries(); /** * Returns a FileStore to represent the file system where the given file * reside. */ abstract FileStore getFileStore(UnixPath path) throws IOException; /** * Returns a FileStore to represent the file system for the given mount * mount. */ abstract FileStore getFileStore(UnixMountEntry entry) throws IOException; /** * Iterator returned by getFileStores method. */ private class FileStoreIterator implements Iterator { private final Iterator entries; private FileStore next; FileStoreIterator() { this.entries = getMountEntries().iterator(); } private FileStore readNext() { assert Thread.holdsLock(this); for (;;) { if (!entries.hasNext()) return null; UnixMountEntry entry = entries.next(); // skip entries with the "ignore" option if (entry.isIgnored()) continue; // check permission to read mount point SecurityManager sm = System.getSecurityManager(); if (sm != null) { try { sm.checkRead(new String(entry.dir())); } catch (SecurityException x) { continue; } } try { return getFileStore(entry); } catch (IOException ignore) { // ignore as per spec } } } @Override public synchronized boolean hasNext() { if (next != null) return true; next = readNext(); return next != null; } @Override public synchronized FileStore next() { if (next == null) next = readNext(); if (next == null) { throw new NoSuchElementException(); } else { FileStore result = next; next = null; return result; } } @Override public void remove() { throw new UnsupportedOperationException(); } } @Override public final Iterable getFileStores() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { try { sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); } catch (SecurityException se) { return Collections.emptyList(); } } return new Iterable() { public Iterator iterator() { return new FileStoreIterator(); } }; } @Override public final UnixPath getPath(String path) { return new UnixPath(this, path); } @Override public PathMatcher getPathMatcher(String syntaxAndInput) { int pos = syntaxAndInput.indexOf(':'); if (pos <= 0 || pos == syntaxAndInput.length()) throw new IllegalArgumentException(); String syntax = syntaxAndInput.substring(0, pos); String input = syntaxAndInput.substring(pos+1); String expr; if (syntax.equals(GLOB_SYNTAX)) { expr = Globs.toUnixRegexPattern(input); } else { if (syntax.equals(REGEX_SYNTAX)) { expr = input; } else { throw new UnsupportedOperationException("Syntax '" + syntax + "' not recognized"); } } // return matcher final Pattern pattern = Pattern.compile(expr); return new PathMatcher() { @Override public boolean matches(Path path) { return pattern.matcher(path.toString()).matches(); } }; } private static final String GLOB_SYNTAX = "glob"; private static final String REGEX_SYNTAX = "regex"; protected 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; } @SuppressWarnings("unchecked") protected V newFileAttributeView(Class view, UnixPath file, LinkOption... options) { if (view == null) throw new NullPointerException(); boolean followLinks = followLinks(options); Class c = view; if (c == BasicFileAttributeView.class) return (V) UnixFileAttributeViews.createBasicView(file, followLinks); if (c == PosixFileAttributeView.class) return (V) UnixFileAttributeViews.createPosixView(file, followLinks); if (c == FileOwnerAttributeView.class) return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); return (V) null; } static List standardFileAttributeViews() { return Arrays.asList("basic", "posix", "unix", "owner"); } protected FileAttributeView newFileAttributeView(String name, UnixPath file, LinkOption... options) { 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 final UserPrincipalLookupService getUserPrincipalLookupService() { return theLookupService; } private static final UserPrincipalLookupService theLookupService = new UserPrincipalLookupService() { @Override public UserPrincipal lookupPrincipalByName(String name) throws IOException { return UnixUserPrincipals.lookupUser(name); } @Override public GroupPrincipal lookupPrincipalByGroupName(String group) throws IOException { return UnixUserPrincipals.lookupGroup(group); } }; }