Path: blob/master/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.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.*;30import java.io.IOException;31import java.util.*;32import java.util.regex.Pattern;33import sun.security.action.GetPropertyAction;3435/**36* Base implementation of FileSystem for Unix-like implementations.37*/3839abstract class UnixFileSystem40extends FileSystem41{42private final UnixFileSystemProvider provider;43private final byte[] defaultDirectory;44private final boolean needToResolveAgainstDefaultDirectory;45private final UnixPath rootDirectory;4647// package-private48UnixFileSystem(UnixFileSystemProvider provider, String dir) {49this.provider = provider;50this.defaultDirectory = Util.toBytes(UnixPath.normalizeAndCheck(dir));51if (this.defaultDirectory[0] != '/') {52throw new RuntimeException("default directory must be absolute");53}5455// if process-wide chdir is allowed or default directory is not the56// process working directory then paths must be resolved against the57// default directory.58String propValue = GetPropertyAction59.privilegedGetProperty("sun.nio.fs.chdirAllowed", "false");60boolean chdirAllowed = propValue.isEmpty() ? true : Boolean.parseBoolean(propValue);61if (chdirAllowed) {62this.needToResolveAgainstDefaultDirectory = true;63} else {64byte[] cwd = UnixNativeDispatcher.getcwd();65boolean defaultIsCwd = (cwd.length == defaultDirectory.length);66if (defaultIsCwd) {67for (int i=0; i<cwd.length; i++) {68if (cwd[i] != defaultDirectory[i]) {69defaultIsCwd = false;70break;71}72}73}74this.needToResolveAgainstDefaultDirectory = !defaultIsCwd;75}7677// the root directory78this.rootDirectory = new UnixPath(this, "/");79}8081// package-private82byte[] defaultDirectory() {83return defaultDirectory;84}8586boolean needToResolveAgainstDefaultDirectory() {87return needToResolveAgainstDefaultDirectory;88}8990UnixPath rootDirectory() {91return rootDirectory;92}9394static List<String> standardFileAttributeViews() {95return Arrays.asList("basic", "posix", "unix", "owner");96}9798@Override99public final FileSystemProvider provider() {100return provider;101}102103@Override104public final String getSeparator() {105return "/";106}107108@Override109public final boolean isOpen() {110return true;111}112113@Override114public final boolean isReadOnly() {115return false;116}117118@Override119public final void close() throws IOException {120throw new UnsupportedOperationException();121}122123/**124* Copies non-POSIX attributes from the source to target file.125*126* Copying a file preserving attributes, or moving a file, will preserve127* the file owner/group/permissions/timestamps but it does not preserve128* other non-POSIX attributes. This method is invoked by the129* copy or move operation to preserve these attributes. It should copy130* extended attributes, ACLs, or other attributes.131*132* @param sfd133* Open file descriptor to source file134* @param tfd135* Open file descriptor to target file136*/137void copyNonPosixAttributes(int sfd, int tfd) {138// no-op by default139}140141/**142* Unix systems only have a single root directory (/)143*/144@Override145public final Iterable<Path> getRootDirectories() {146final List<Path> allowedList =147Collections.unmodifiableList(Arrays.asList((Path)rootDirectory));148return new Iterable<>() {149public Iterator<Path> iterator() {150try {151@SuppressWarnings("removal")152SecurityManager sm = System.getSecurityManager();153if (sm != null)154sm.checkRead(rootDirectory.toString());155return allowedList.iterator();156} catch (SecurityException x) {157List<Path> disallowed = Collections.emptyList();158return disallowed.iterator();159}160}161};162}163164/**165* Returns object to iterate over entries in mounttab or equivalent166*/167abstract Iterable<UnixMountEntry> getMountEntries();168169/**170* Returns a FileStore to represent the file system for the given mount171* mount.172*/173abstract FileStore getFileStore(UnixMountEntry entry) throws IOException;174175/**176* Iterator returned by getFileStores method.177*/178private class FileStoreIterator implements Iterator<FileStore> {179private final Iterator<UnixMountEntry> entries;180private FileStore next;181182FileStoreIterator() {183this.entries = getMountEntries().iterator();184}185186private FileStore readNext() {187assert Thread.holdsLock(this);188for (;;) {189if (!entries.hasNext())190return null;191UnixMountEntry entry = entries.next();192193// skip entries with the "ignore" option194if (entry.isIgnored())195continue;196197// check permission to read mount point198@SuppressWarnings("removal")199SecurityManager sm = System.getSecurityManager();200if (sm != null) {201try {202sm.checkRead(Util.toString(entry.dir()));203} catch (SecurityException x) {204continue;205}206}207try {208return getFileStore(entry);209} catch (IOException ignore) {210// ignore as per spec211}212}213}214215@Override216public synchronized boolean hasNext() {217if (next != null)218return true;219next = readNext();220return next != null;221}222223@Override224public synchronized FileStore next() {225if (next == null)226next = readNext();227if (next == null) {228throw new NoSuchElementException();229} else {230FileStore result = next;231next = null;232return result;233}234}235236@Override237public void remove() {238throw new UnsupportedOperationException();239}240}241242@Override243public final Iterable<FileStore> getFileStores() {244@SuppressWarnings("removal")245SecurityManager sm = System.getSecurityManager();246if (sm != null) {247try {248sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));249} catch (SecurityException se) {250return Collections.emptyList();251}252}253return new Iterable<>() {254public Iterator<FileStore> iterator() {255return new FileStoreIterator();256}257};258}259260@Override261public final Path getPath(String first, String... more) {262Objects.requireNonNull(first);263String path;264if (more.length == 0) {265path = first;266} else {267StringBuilder sb = new StringBuilder();268sb.append(first);269for (String segment: more) {270if (!segment.isEmpty()) {271if (sb.length() > 0)272sb.append('/');273sb.append(segment);274}275}276path = sb.toString();277}278return new UnixPath(this, path);279}280281@Override282public PathMatcher getPathMatcher(String syntaxAndInput) {283int pos = syntaxAndInput.indexOf(':');284if (pos <= 0 || pos == syntaxAndInput.length())285throw new IllegalArgumentException();286String syntax = syntaxAndInput.substring(0, pos);287String input = syntaxAndInput.substring(pos+1);288289String expr;290if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) {291expr = Globs.toUnixRegexPattern(input);292} else {293if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) {294expr = input;295} else {296throw new UnsupportedOperationException("Syntax '" + syntax +297"' not recognized");298}299}300301// return matcher302final Pattern pattern = compilePathMatchPattern(expr);303304return new PathMatcher() {305@Override306public boolean matches(Path path) {307return pattern.matcher(path.toString()).matches();308}309};310}311312private static final String GLOB_SYNTAX = "glob";313private static final String REGEX_SYNTAX = "regex";314315@Override316public final UserPrincipalLookupService getUserPrincipalLookupService() {317return LookupService.instance;318}319320private static class LookupService {321static final UserPrincipalLookupService instance =322new UserPrincipalLookupService() {323@Override324public UserPrincipal lookupPrincipalByName(String name)325throws IOException326{327return UnixUserPrincipals.lookupUser(name);328}329330@Override331public GroupPrincipal lookupPrincipalByGroupName(String group)332throws IOException333{334return UnixUserPrincipals.lookupGroup(group);335}336};337}338339// Override if the platform has different path match requirement, such as340// case insensitive or Unicode canonical equal on MacOSX341Pattern compilePathMatchPattern(String expr) {342return Pattern.compile(expr);343}344345// Override if the platform uses different Unicode normalization form346// for native file path. For example on MacOSX, the native path is stored347// in Unicode NFD form.348String normalizeNativePath(String path) {349return path;350}351352// Override if the native file path use non-NFC form. For example on MacOSX,353// the native path is stored in Unicode NFD form, the path need to be354// normalized back to NFC before passed back to Java level.355String normalizeJavaPath(String path) {356return path;357}358}359360361