jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java
changeset 2057 3acf8e5e2ca0
child 3065 452aaa2899fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,380 @@
+/*
+ * 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<cwd.length; i++) {
+                    if (cwd[i] != defaultDirectory[i]) {
+                        defaultIsCwd = false;
+                        break;
+                    }
+                }
+            }
+            this.needToResolveAgainstDefaultDirectory = !defaultIsCwd;
+        }
+
+        // the root directory
+        this.rootDirectory = new UnixPath(this, "/");
+    }
+
+    // package-private
+    byte[] defaultDirectory() {
+        return defaultDirectory;
+    }
+
+    boolean needToResolveAgainstDefaultDirectory() {
+        return needToResolveAgainstDefaultDirectory;
+    }
+
+    UnixPath rootDirectory() {
+        return rootDirectory;
+    }
+
+    boolean isSolaris() {
+        return false;
+    }
+
+    @Override
+    public final FileSystemProvider provider() {
+        return provider;
+    }
+
+    @Override
+    public final String getSeparator() {
+        return "/";
+    }
+
+    @Override
+    public final boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public final boolean isReadOnly() {
+        return false;
+    }
+
+    @Override
+    public final void close() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Copies non-POSIX attributes from the source to target file.
+     *
+     * Copying a file preserving attributes, or moving a file, will preserve
+     * the file owner/group/permissions/timestamps but it does not preserve
+     * other non-POSIX attributes. This method is invoked by the
+     * copy or move operation to preserve these attributes. It should copy
+     * extended attributes, ACLs, or other attributes.
+     *
+     * @param   sfd
+     *          Open file descriptor to source file
+     * @param   tfd
+     *          Open file descriptor to target file
+     */
+    abstract void copyNonPosixAttributes(int sfd, int tfd);
+
+    /**
+     * Tells if directory relative system calls (openat, etc.) are available
+     * on this operating system.
+     */
+    abstract boolean supportsSecureDirectoryStreams();
+
+    /**
+     * Unix systems only have a single root directory (/)
+     */
+    @Override
+    public final Iterable<Path> getRootDirectories() {
+        final List<Path> allowedList =
+           Collections.unmodifiableList(Arrays.asList((Path)rootDirectory));
+        return new Iterable<Path>() {
+            public Iterator<Path> iterator() {
+                try {
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null)
+                        sm.checkRead(rootDirectory.toString());
+                    return allowedList.iterator();
+                } catch (SecurityException x) {
+                    List<Path> disallowed = Collections.emptyList();
+                    return disallowed.iterator();
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns object to iterate over entries in mounttab or equivalent
+     */
+    abstract Iterable<UnixMountEntry> 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<FileStore> {
+        private final Iterator<UnixMountEntry> 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<FileStore> getFileStores() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
+            } catch (SecurityException se) {
+                return Collections.emptyList();
+            }
+        }
+        return new Iterable<FileStore>() {
+            public Iterator<FileStore> 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 extends FileAttributeView> V newFileAttributeView(Class<V> 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<String> 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);
+            }
+        };
+}