Path: blob/master/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
41139 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.channels.*;30import java.nio.charset.StandardCharsets;31import java.net.URI;32import java.util.concurrent.ExecutorService;33import java.io.*;34import java.util.*;35import java.security.AccessController;36import jdk.internal.misc.Unsafe;37import jdk.internal.util.StaticProperty;38import sun.nio.ch.ThreadPool;39import sun.security.util.SecurityConstants;4041import static sun.nio.fs.WindowsNativeDispatcher.*;42import static sun.nio.fs.WindowsSecurity.*;43import static sun.nio.fs.WindowsConstants.*;4445class WindowsFileSystemProvider46extends AbstractFileSystemProvider47{48private static final byte[] EMPTY_PATH = new byte[0];4950private final WindowsFileSystem theFileSystem;5152public WindowsFileSystemProvider() {53theFileSystem = new WindowsFileSystem(this, StaticProperty.userDir());54}5556WindowsFileSystem theFileSystem() {57return theFileSystem;58}5960@Override61public String getScheme() {62return "file";63}6465private void checkUri(URI uri) {66if (!uri.getScheme().equalsIgnoreCase(getScheme()))67throw new IllegalArgumentException("URI does not match this provider");68if (uri.getRawAuthority() != null)69throw new IllegalArgumentException("Authority component present");70String path = uri.getPath();71if (path == null)72throw new IllegalArgumentException("Path component is undefined");73if (!path.equals("/"))74throw new IllegalArgumentException("Path component should be '/'");75if (uri.getRawQuery() != null)76throw new IllegalArgumentException("Query component present");77if (uri.getRawFragment() != null)78throw new IllegalArgumentException("Fragment component present");79}8081@Override82public FileSystem newFileSystem(URI uri, Map<String,?> env)83throws IOException84{85checkUri(uri);86throw new FileSystemAlreadyExistsException();87}8889@Override90public final FileSystem getFileSystem(URI uri) {91checkUri(uri);92return theFileSystem;93}9495@Override96public Path getPath(URI uri) {97return WindowsUriSupport.fromUri(theFileSystem, uri);98}99100@Override101public FileChannel newFileChannel(Path path,102Set<? extends OpenOption> options,103FileAttribute<?>... attrs)104throws IOException105{106if (path == null)107throw new NullPointerException();108if (!(path instanceof WindowsPath))109throw new ProviderMismatchException();110WindowsPath file = (WindowsPath)path;111112WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);113try {114return WindowsChannelFactory115.newFileChannel(file.getPathForWin32Calls(),116file.getPathForPermissionCheck(),117options,118sd.address());119} catch (WindowsException x) {120x.rethrowAsIOException(file);121return null;122} finally {123if (sd != null)124sd.release();125}126}127128@Override129public AsynchronousFileChannel newAsynchronousFileChannel(Path path,130Set<? extends OpenOption> options,131ExecutorService executor,132FileAttribute<?>... attrs)133throws IOException134{135if (path == null)136throw new NullPointerException();137if (!(path instanceof WindowsPath))138throw new ProviderMismatchException();139WindowsPath file = (WindowsPath)path;140ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);141WindowsSecurityDescriptor sd =142WindowsSecurityDescriptor.fromAttribute(attrs);143try {144return WindowsChannelFactory145.newAsynchronousFileChannel(file.getPathForWin32Calls(),146file.getPathForPermissionCheck(),147options,148sd.address(),149pool);150} catch (WindowsException x) {151x.rethrowAsIOException(file);152return null;153} finally {154if (sd != null)155sd.release();156}157}158159@Override160@SuppressWarnings("unchecked")161public <V extends FileAttributeView> V162getFileAttributeView(Path obj, Class<V> view, LinkOption... options)163{164WindowsPath file = WindowsPath.toWindowsPath(obj);165if (view == null)166throw new NullPointerException();167boolean followLinks = Util.followLinks(options);168if (view == BasicFileAttributeView.class)169return (V) WindowsFileAttributeViews.createBasicView(file, followLinks);170if (view == DosFileAttributeView.class)171return (V) WindowsFileAttributeViews.createDosView(file, followLinks);172if (view == AclFileAttributeView.class)173return (V) new WindowsAclFileAttributeView(file, followLinks);174if (view == FileOwnerAttributeView.class)175return (V) new FileOwnerAttributeViewImpl(176new WindowsAclFileAttributeView(file, followLinks));177if (view == UserDefinedFileAttributeView.class)178return (V) new WindowsUserDefinedFileAttributeView(file, followLinks);179return (V) null;180}181182@Override183@SuppressWarnings("unchecked")184public <A extends BasicFileAttributes> A readAttributes(Path file,185Class<A> type,186LinkOption... options)187throws IOException188{189Class<? extends BasicFileAttributeView> view;190if (type == BasicFileAttributes.class)191view = BasicFileAttributeView.class;192else if (type == DosFileAttributes.class)193view = DosFileAttributeView.class;194else if (type == null)195throw new NullPointerException();196else197throw new UnsupportedOperationException();198return (A) getFileAttributeView(file, view, options).readAttributes();199}200201@Override202public DynamicFileAttributeView getFileAttributeView(Path obj, String name, LinkOption... options) {203WindowsPath file = WindowsPath.toWindowsPath(obj);204boolean followLinks = Util.followLinks(options);205if (name.equals("basic"))206return WindowsFileAttributeViews.createBasicView(file, followLinks);207if (name.equals("dos"))208return WindowsFileAttributeViews.createDosView(file, followLinks);209if (name.equals("acl"))210return new WindowsAclFileAttributeView(file, followLinks);211if (name.equals("owner"))212return new FileOwnerAttributeViewImpl(213new WindowsAclFileAttributeView(file, followLinks));214if (name.equals("user"))215return new WindowsUserDefinedFileAttributeView(file, followLinks);216return null;217}218219@Override220public SeekableByteChannel newByteChannel(Path obj,221Set<? extends OpenOption> options,222FileAttribute<?>... attrs)223throws IOException224{225WindowsPath file = WindowsPath.toWindowsPath(obj);226WindowsSecurityDescriptor sd =227WindowsSecurityDescriptor.fromAttribute(attrs);228try {229return WindowsChannelFactory230.newFileChannel(file.getPathForWin32Calls(),231file.getPathForPermissionCheck(),232options,233sd.address());234} catch (WindowsException x) {235x.rethrowAsIOException(file);236return null; // keep compiler happy237} finally {238sd.release();239}240}241242@Override243boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {244WindowsPath file = WindowsPath.toWindowsPath(obj);245file.checkDelete();246247WindowsFileAttributes attrs = null;248try {249// need to know if file is a directory or junction250attrs = WindowsFileAttributes.get(file, false);251if (attrs.isDirectory() || attrs.isDirectoryLink()) {252RemoveDirectory(file.getPathForWin32Calls());253} else {254DeleteFile(file.getPathForWin32Calls());255}256return true;257} catch (WindowsException x) {258259// no-op if file does not exist260if (!failIfNotExists &&261(x.lastError() == ERROR_FILE_NOT_FOUND ||262x.lastError() == ERROR_PATH_NOT_FOUND)) return false;263264if (attrs != null && attrs.isDirectory()) {265// ERROR_ALREADY_EXISTS is returned when attempting to delete266// non-empty directory on SAMBA servers.267if (x.lastError() == ERROR_DIR_NOT_EMPTY ||268x.lastError() == ERROR_ALREADY_EXISTS)269{270throw new DirectoryNotEmptyException(271file.getPathForExceptionMessage());272}273}274x.rethrowAsIOException(file);275return false;276}277}278279@Override280public void copy(Path source, Path target, CopyOption... options)281throws IOException282{283WindowsFileCopy.copy(WindowsPath.toWindowsPath(source),284WindowsPath.toWindowsPath(target),285options);286}287288@Override289public void move(Path source, Path target, CopyOption... options)290throws IOException291{292WindowsFileCopy.move(WindowsPath.toWindowsPath(source),293WindowsPath.toWindowsPath(target),294options);295}296297/**298* Checks the file security against desired access.299*/300private static boolean hasDesiredAccess(WindowsPath file, int rights) throws IOException {301// read security descriptor containing ACL (symlinks are followed)302boolean hasRights = false;303String target = WindowsLinkSupport.getFinalPath(file, true);304NativeBuffer aclBuffer = WindowsAclFileAttributeView305.getFileSecurity(target,306DACL_SECURITY_INFORMATION307| OWNER_SECURITY_INFORMATION308| GROUP_SECURITY_INFORMATION);309try {310hasRights = checkAccessMask(aclBuffer.address(), rights,311FILE_GENERIC_READ,312FILE_GENERIC_WRITE,313FILE_GENERIC_EXECUTE,314FILE_ALL_ACCESS);315} catch (WindowsException exc) {316exc.rethrowAsIOException(file);317} finally {318aclBuffer.release();319}320return hasRights;321}322323/**324* Checks if the given file(or directory) exists and is readable.325*/326private void checkReadAccess(WindowsPath file) throws IOException {327try {328Set<OpenOption> opts = Collections.emptySet();329FileChannel fc = WindowsChannelFactory330.newFileChannel(file.getPathForWin32Calls(),331file.getPathForPermissionCheck(),332opts,3330L);334fc.close();335} catch (WindowsException exc) {336try {337if (exc.lastError() == ERROR_CANT_ACCESS_FILE && isUnixDomainSocket(file)) {338// socket file is accessible339return;340}341} catch (WindowsException ignore) {}342343// Windows errors are very inconsistent when the file is a directory344// (ERROR_PATH_NOT_FOUND returned for root directories for example)345// so we retry by attempting to open it as a directory.346try {347new WindowsDirectoryStream(file, null).close();348} catch (IOException ioe) {349// translate and throw original exception350exc.rethrowAsIOException(file);351}352}353}354355private static boolean isUnixDomainSocket(WindowsPath path) throws WindowsException {356WindowsFileAttributes attrs = WindowsFileAttributes.get(path, false);357return attrs.isUnixDomainSocket();358}359360@Override361public void checkAccess(Path obj, AccessMode... modes) throws IOException {362WindowsPath file = WindowsPath.toWindowsPath(obj);363364boolean r = false;365boolean w = false;366boolean x = false;367for (AccessMode mode: modes) {368switch (mode) {369case READ : r = true; break;370case WRITE : w = true; break;371case EXECUTE : x = true; break;372default: throw new AssertionError("Should not get here");373}374}375376// special-case read access to avoid needing to determine effective377// access to file; default if modes not specified378if (!w && !x) {379checkReadAccess(file);380return;381}382383int mask = 0;384if (r) {385file.checkRead();386mask |= FILE_READ_DATA;387}388if (w) {389file.checkWrite();390mask |= FILE_WRITE_DATA;391}392if (x) {393@SuppressWarnings("removal")394SecurityManager sm = System.getSecurityManager();395if (sm != null)396sm.checkExec(file.getPathForPermissionCheck());397mask |= FILE_EXECUTE;398}399400if (!hasDesiredAccess(file, mask))401throw new AccessDeniedException(402file.getPathForExceptionMessage(), null,403"Permissions does not allow requested access");404405// for write access we need to check if the DOS readonly attribute406// and if the volume is read-only407if (w) {408try {409WindowsFileAttributes attrs = WindowsFileAttributes.get(file, true);410if (!attrs.isDirectory() && attrs.isReadOnly())411throw new AccessDeniedException(412file.getPathForExceptionMessage(), null,413"DOS readonly attribute is set");414} catch (WindowsException exc) {415exc.rethrowAsIOException(file);416}417418if (WindowsFileStore.create(file).isReadOnly()) {419throw new AccessDeniedException(420file.getPathForExceptionMessage(), null, "Read-only file system");421}422}423}424425@Override426public boolean isSameFile(Path obj1, Path obj2) throws IOException {427WindowsPath file1 = WindowsPath.toWindowsPath(obj1);428if (file1.equals(obj2))429return true;430if (obj2 == null)431throw new NullPointerException();432if (!(obj2 instanceof WindowsPath))433return false;434WindowsPath file2 = (WindowsPath)obj2;435436// check security manager access to both files437file1.checkRead();438file2.checkRead();439440// open both files and see if they are the same441long h1 = 0L;442try {443h1 = file1.openForReadAttributeAccess(true);444} catch (WindowsException x) {445x.rethrowAsIOException(file1);446}447try {448WindowsFileAttributes attrs1 = null;449try {450attrs1 = WindowsFileAttributes.readAttributes(h1);451} catch (WindowsException x) {452x.rethrowAsIOException(file1);453}454long h2 = 0L;455try {456h2 = file2.openForReadAttributeAccess(true);457} catch (WindowsException x) {458x.rethrowAsIOException(file2);459}460try {461WindowsFileAttributes attrs2 = null;462try {463attrs2 = WindowsFileAttributes.readAttributes(h2);464} catch (WindowsException x) {465x.rethrowAsIOException(file2);466}467return WindowsFileAttributes.isSameFile(attrs1, attrs2);468} finally {469CloseHandle(h2);470}471} finally {472CloseHandle(h1);473}474}475476@Override477public boolean isHidden(Path obj) throws IOException {478WindowsPath file = WindowsPath.toWindowsPath(obj);479file.checkRead();480WindowsFileAttributes attrs = null;481try {482attrs = WindowsFileAttributes.get(file, true);483} catch (WindowsException x) {484x.rethrowAsIOException(file);485}486return attrs.isHidden();487}488489@Override490public FileStore getFileStore(Path obj) throws IOException {491WindowsPath file = WindowsPath.toWindowsPath(obj);492@SuppressWarnings("removal")493SecurityManager sm = System.getSecurityManager();494if (sm != null) {495sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));496file.checkRead();497}498return WindowsFileStore.create(file);499}500501502@Override503public void createDirectory(Path obj, FileAttribute<?>... attrs)504throws IOException505{506WindowsPath dir = WindowsPath.toWindowsPath(obj);507dir.checkWrite();508WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);509try {510CreateDirectory(dir.getPathForWin32Calls(), sd.address());511} catch (WindowsException x) {512// convert ERROR_ACCESS_DENIED to FileAlreadyExistsException if we can513// verify that the directory exists514if (x.lastError() == ERROR_ACCESS_DENIED) {515try {516if (WindowsFileAttributes.get(dir, false).isDirectory())517throw new FileAlreadyExistsException(dir.toString());518} catch (WindowsException ignore) { }519}520x.rethrowAsIOException(dir);521} finally {522sd.release();523}524}525526@Override527public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)528throws IOException529{530WindowsPath dir = WindowsPath.toWindowsPath(obj);531dir.checkRead();532if (filter == null)533throw new NullPointerException();534return new WindowsDirectoryStream(dir, filter);535}536537@Override538public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)539throws IOException540{541WindowsPath link = WindowsPath.toWindowsPath(obj1);542WindowsPath target = WindowsPath.toWindowsPath(obj2);543544// no attributes allowed545if (attrs.length > 0) {546WindowsSecurityDescriptor.fromAttribute(attrs); // may throw NPE or UOE547throw new UnsupportedOperationException("Initial file attributes" +548"not supported when creating symbolic link");549}550551// permission check552@SuppressWarnings("removal")553SecurityManager sm = System.getSecurityManager();554if (sm != null) {555sm.checkPermission(new LinkPermission("symbolic"));556link.checkWrite();557}558559/**560* Throw I/O exception for the drive-relative case because Windows561* creates a link with the resolved target for this case.562*/563if (target.type() == WindowsPathType.DRIVE_RELATIVE) {564throw new IOException("Cannot create symbolic link to working directory relative target");565}566567/*568* Windows treats symbolic links to directories differently than it569* does to other file types. For that reason we need to check if the570* target is a directory (or a directory junction).571*/572WindowsPath resolvedTarget;573if (target.type() == WindowsPathType.RELATIVE) {574WindowsPath parent = link.getParent();575resolvedTarget = (parent == null) ? target : parent.resolve(target);576} else {577resolvedTarget = link.resolve(target);578}579int flags = 0;580try {581WindowsFileAttributes wattrs = WindowsFileAttributes.get(resolvedTarget, false);582if (wattrs.isDirectory() || wattrs.isDirectoryLink())583flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;584} catch (WindowsException x) {585// unable to access target so assume target is not a directory586}587588// create the link589try {590CreateSymbolicLink(link.getPathForWin32Calls(),591WindowsPath.addPrefixIfNeeded(target.toString()),592flags);593} catch (WindowsException x) {594if (x.lastError() == ERROR_INVALID_REPARSE_DATA) {595x.rethrowAsIOException(link, target);596} else {597x.rethrowAsIOException(link);598}599}600}601602@Override603public void createLink(Path obj1, Path obj2) throws IOException {604WindowsPath link = WindowsPath.toWindowsPath(obj1);605WindowsPath existing = WindowsPath.toWindowsPath(obj2);606607// permission check608@SuppressWarnings("removal")609SecurityManager sm = System.getSecurityManager();610if (sm != null) {611sm.checkPermission(new LinkPermission("hard"));612link.checkWrite();613existing.checkWrite();614}615616// create hard link617try {618CreateHardLink(link.getPathForWin32Calls(),619existing.getPathForWin32Calls());620} catch (WindowsException x) {621x.rethrowAsIOException(link, existing);622}623}624625@Override626public Path readSymbolicLink(Path obj1) throws IOException {627WindowsPath link = WindowsPath.toWindowsPath(obj1);628WindowsFileSystem fs = link.getFileSystem();629630// permission check631@SuppressWarnings("removal")632SecurityManager sm = System.getSecurityManager();633if (sm != null) {634FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),635SecurityConstants.FILE_READLINK_ACTION);636sm.checkPermission(perm);637}638639String target = WindowsLinkSupport.readLink(link);640return WindowsPath.createFromNormalizedPath(fs, target);641}642643@Override644public byte[] getSunPathForSocketFile(Path obj) {645WindowsPath file = WindowsPath.toWindowsPath(obj);646String s = file.toString();647return s.isEmpty() ? EMPTY_PATH : s.getBytes(StandardCharsets.UTF_8);648}649650}651652653