Path: blob/master/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.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.io.FileDescriptor;28import java.io.IOException;29import java.nio.channels.AsynchronousFileChannel;30import java.nio.channels.FileChannel;31import java.nio.file.LinkOption;32import java.nio.file.OpenOption;33import java.nio.file.StandardOpenOption;34import java.util.Set;3536import jdk.internal.access.JavaIOFileDescriptorAccess;37import jdk.internal.access.SharedSecrets;38import sun.nio.ch.FileChannelImpl;39import sun.nio.ch.ThreadPool;40import sun.nio.ch.WindowsAsynchronousFileChannelImpl;4142import static sun.nio.fs.WindowsNativeDispatcher.*;43import static sun.nio.fs.WindowsConstants.*;4445/**46* Factory to create FileChannels and AsynchronousFileChannels.47*/4849class WindowsChannelFactory {50private static final JavaIOFileDescriptorAccess fdAccess =51SharedSecrets.getJavaIOFileDescriptorAccess();5253private WindowsChannelFactory() { }5455/**56* Do not follow reparse points when opening an existing file. Do not fail57* if the file is a reparse point.58*/59static final OpenOption OPEN_REPARSE_POINT = new OpenOption() { };6061/**62* Represents the flags from a user-supplied set of open options.63*/64private static class Flags {65boolean read;66boolean write;67boolean append;68boolean truncateExisting;69boolean create;70boolean createNew;71boolean deleteOnClose;72boolean sparse;73boolean overlapped;74boolean sync;75boolean dsync;76boolean direct;7778// non-standard79boolean shareRead = true;80boolean shareWrite = true;81boolean shareDelete = true;82boolean noFollowLinks;83boolean openReparsePoint;8485static Flags toFlags(Set<? extends OpenOption> options) {86Flags flags = new Flags();87for (OpenOption option: options) {88if (option instanceof StandardOpenOption) {89switch ((StandardOpenOption)option) {90case READ : flags.read = true; break;91case WRITE : flags.write = true; break;92case APPEND : flags.append = true; break;93case TRUNCATE_EXISTING : flags.truncateExisting = true; break;94case CREATE : flags.create = true; break;95case CREATE_NEW : flags.createNew = true; break;96case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;97case SPARSE : flags.sparse = true; break;98case SYNC : flags.sync = true; break;99case DSYNC : flags.dsync = true; break;100default: throw new UnsupportedOperationException();101}102continue;103}104if (option == LinkOption.NOFOLLOW_LINKS) {105flags.noFollowLinks = true;106continue;107}108if (option == OPEN_REPARSE_POINT) {109flags.openReparsePoint = true;110continue;111}112if (ExtendedOptions.NOSHARE_READ.matches(option)) {113flags.shareRead = false;114continue;115}116if (ExtendedOptions.NOSHARE_WRITE.matches(option)) {117flags.shareWrite = false;118continue;119}120if (ExtendedOptions.NOSHARE_DELETE.matches(option)) {121flags.shareDelete = false;122continue;123}124if (ExtendedOptions.DIRECT.matches(option)) {125flags.direct = true;126continue;127}128if (option == null)129throw new NullPointerException();130throw new UnsupportedOperationException();131}132return flags;133}134}135136/**137* Open/creates file, returning FileChannel to access the file138*139* @param pathForWindows140* The path of the file to open/create141* @param pathToCheck142* The path used for permission checks (if security manager)143*/144static FileChannel newFileChannel(String pathForWindows,145String pathToCheck,146Set<? extends OpenOption> options,147long pSecurityDescriptor)148throws WindowsException149{150Flags flags = Flags.toFlags(options);151152// default is reading; append => writing153if (!flags.read && !flags.write) {154if (flags.append) {155flags.write = true;156} else {157flags.read = true;158}159}160161// validation162if (flags.read && flags.append)163throw new IllegalArgumentException("READ + APPEND not allowed");164if (flags.append && flags.truncateExisting)165throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");166167FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);168return FileChannelImpl.open(fdObj, pathForWindows, flags.read,169flags.write, flags.direct, null);170}171172/**173* Open/creates file, returning AsynchronousFileChannel to access the file174*175* @param pathForWindows176* The path of the file to open/create177* @param pathToCheck178* The path used for permission checks (if security manager)179* @param pool180* The thread pool that the channel is associated with181*/182static AsynchronousFileChannel newAsynchronousFileChannel(String pathForWindows,183String pathToCheck,184Set<? extends OpenOption> options,185long pSecurityDescriptor,186ThreadPool pool)187throws IOException188{189Flags flags = Flags.toFlags(options);190191// Overlapped I/O required192flags.overlapped = true;193194// default is reading195if (!flags.read && !flags.write) {196flags.read = true;197}198199// validation200if (flags.append)201throw new UnsupportedOperationException("APPEND not allowed");202203// open file for overlapped I/O204FileDescriptor fdObj;205try {206fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);207} catch (WindowsException x) {208x.rethrowAsIOException(pathForWindows);209return null;210}211212// create the AsynchronousFileChannel213try {214return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);215} catch (IOException x) {216// IOException is thrown if the file handle cannot be associated217// with the completion port. All we can do is close the file.218fdAccess.close(fdObj);219throw x;220}221}222223/**224* Opens file based on parameters and options, returning a FileDescriptor225* encapsulating the handle to the open file.226*/227private static FileDescriptor open(String pathForWindows,228String pathToCheck,229Flags flags,230long pSecurityDescriptor)231throws WindowsException232{233// set to true if file must be truncated after open234boolean truncateAfterOpen = false;235236// map options237int dwDesiredAccess = 0;238if (flags.read)239dwDesiredAccess |= GENERIC_READ;240if (flags.write)241dwDesiredAccess |= GENERIC_WRITE;242243int dwShareMode = 0;244if (flags.shareRead)245dwShareMode |= FILE_SHARE_READ;246if (flags.shareWrite)247dwShareMode |= FILE_SHARE_WRITE;248if (flags.shareDelete)249dwShareMode |= FILE_SHARE_DELETE;250251int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;252int dwCreationDisposition = OPEN_EXISTING;253if (flags.write) {254if (flags.createNew) {255dwCreationDisposition = CREATE_NEW;256// force create to fail if file is orphaned reparse point257dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;258} else {259if (flags.create)260dwCreationDisposition = OPEN_ALWAYS;261if (flags.truncateExisting) {262// Windows doesn't have a creation disposition that exactly263// corresponds to CREATE + TRUNCATE_EXISTING so we use264// the OPEN_ALWAYS mode and then truncate the file.265if (dwCreationDisposition == OPEN_ALWAYS) {266truncateAfterOpen = true;267} else {268dwCreationDisposition = TRUNCATE_EXISTING;269}270}271}272}273274if (flags.dsync || flags.sync)275dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;276if (flags.overlapped)277dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;278if (flags.deleteOnClose)279dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;280281// NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point282boolean okayToFollowLinks = true;283if (dwCreationDisposition != CREATE_NEW &&284(flags.noFollowLinks ||285flags.openReparsePoint ||286flags.deleteOnClose))287{288if (flags.noFollowLinks || flags.deleteOnClose)289okayToFollowLinks = false;290dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;291}292293// permission check294if (pathToCheck != null) {295@SuppressWarnings("removal")296SecurityManager sm = System.getSecurityManager();297if (sm != null) {298if (flags.read)299sm.checkRead(pathToCheck);300if (flags.write)301sm.checkWrite(pathToCheck);302if (flags.deleteOnClose)303sm.checkDelete(pathToCheck);304}305}306307// open file308long handle = CreateFile(pathForWindows,309dwDesiredAccess,310dwShareMode,311pSecurityDescriptor,312dwCreationDisposition,313dwFlagsAndAttributes);314315// make sure this isn't a symbolic link.316if (!okayToFollowLinks) {317try {318if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink())319throw new WindowsException("File is symbolic link");320} catch (WindowsException x) {321CloseHandle(handle);322throw x;323}324}325326// truncate file (for CREATE + TRUNCATE_EXISTING case)327if (truncateAfterOpen) {328try {329SetEndOfFile(handle);330} catch (WindowsException x) {331// ignore exception if file size is zero332if (GetFileSizeEx(handle) != 0) {333CloseHandle(handle);334throw x;335}336}337}338339// make the file sparse if needed340if (dwCreationDisposition == CREATE_NEW && flags.sparse) {341try {342DeviceIoControlSetSparse(handle);343} catch (WindowsException x) {344// ignore as sparse option is hint345}346}347348// create FileDescriptor and return349FileDescriptor fdObj = new FileDescriptor();350fdAccess.setHandle(fdObj, handle);351fdAccess.setAppend(fdObj, flags.append);352fdAccess.registerCleanup(fdObj);353return fdObj;354}355}356357358