jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java
changeset 2057 3acf8e5e2ca0
child 5506 202f599c92aa
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.nio.fs;
       
    27 
       
    28 import java.nio.file.*;
       
    29 import java.nio.channels.*;
       
    30 import java.io.FileDescriptor;
       
    31 import java.io.IOException;
       
    32 import java.util.*;
       
    33 
       
    34 import com.sun.nio.file.ExtendedOpenOption;
       
    35 
       
    36 import sun.nio.ch.FileChannelImpl;
       
    37 import sun.nio.ch.ThreadPool;
       
    38 import sun.nio.ch.WindowsAsynchronousFileChannelImpl;
       
    39 import sun.misc.SharedSecrets;
       
    40 import sun.misc.JavaIOFileDescriptorAccess;
       
    41 
       
    42 import static sun.nio.fs.WindowsNativeDispatcher.*;
       
    43 import static sun.nio.fs.WindowsConstants.*;
       
    44 
       
    45 /**
       
    46  * Factory to create FileChannels and AsynchronousFileChannels.
       
    47  */
       
    48 
       
    49 class WindowsChannelFactory {
       
    50     private static final JavaIOFileDescriptorAccess fdAccess =
       
    51         SharedSecrets.getJavaIOFileDescriptorAccess();
       
    52 
       
    53     private WindowsChannelFactory() { }
       
    54 
       
    55     /**
       
    56      * Do not follow reparse points when opening an existing file. Do not fail
       
    57      * if the file is a reparse point.
       
    58      */
       
    59     static final OpenOption OPEN_REPARSE_POINT = new OpenOption() { };
       
    60 
       
    61     /**
       
    62      * Represents the flags from a user-supplied set of open options.
       
    63      */
       
    64     private static class Flags {
       
    65         boolean read;
       
    66         boolean write;
       
    67         boolean append;
       
    68         boolean truncateExisting;
       
    69         boolean create;
       
    70         boolean createNew;
       
    71         boolean deleteOnClose;
       
    72         boolean sparse;
       
    73         boolean overlapped;
       
    74         boolean sync;
       
    75         boolean dsync;
       
    76 
       
    77         // non-standard
       
    78         boolean shareRead = true;
       
    79         boolean shareWrite = true;
       
    80         boolean shareDelete = true;
       
    81         boolean noFollowLinks;
       
    82         boolean openReparsePoint;
       
    83 
       
    84         static Flags toFlags(Set<? extends OpenOption> options) {
       
    85             Flags flags = new Flags();
       
    86             for (OpenOption option: options) {
       
    87                 if (option instanceof StandardOpenOption) {
       
    88                     switch ((StandardOpenOption)option) {
       
    89                         case READ : flags.read = true; break;
       
    90                         case WRITE : flags.write = true; break;
       
    91                         case APPEND : flags.append = true; break;
       
    92                         case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
       
    93                         case CREATE : flags.create = true; break;
       
    94                         case CREATE_NEW : flags.createNew = true; break;
       
    95                         case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
       
    96                         case SPARSE : flags.sparse = true; break;
       
    97                         case SYNC : flags.sync = true; break;
       
    98                         case DSYNC : flags.dsync = true; break;
       
    99                         default: throw new UnsupportedOperationException();
       
   100                     }
       
   101                     continue;
       
   102                 }
       
   103                 if (option instanceof ExtendedOpenOption) {
       
   104                     switch ((ExtendedOpenOption)option) {
       
   105                         case NOSHARE_READ : flags.shareRead = false; break;
       
   106                         case NOSHARE_WRITE : flags.shareWrite = false; break;
       
   107                         case NOSHARE_DELETE : flags.shareDelete = false; break;
       
   108                         default: throw new UnsupportedOperationException();
       
   109                     }
       
   110                     continue;
       
   111                 }
       
   112                 if (option == LinkOption.NOFOLLOW_LINKS) {
       
   113                     flags.noFollowLinks = true;
       
   114                     continue;
       
   115                 }
       
   116                 if (option == OPEN_REPARSE_POINT) {
       
   117                     flags.openReparsePoint = true;
       
   118                     continue;
       
   119                 }
       
   120                 if (option == null)
       
   121                     throw new NullPointerException();
       
   122                 throw new UnsupportedOperationException();
       
   123             }
       
   124             return flags;
       
   125         }
       
   126     }
       
   127 
       
   128     /**
       
   129      * Open/creates file, returning FileChannel to access the file
       
   130      *
       
   131      * @param   pathForWindows
       
   132      *          The path of the file to open/create
       
   133      * @param   pathToCheck
       
   134      *          The path used for permission checks (if security manager)
       
   135      */
       
   136     static FileChannel newFileChannel(String pathForWindows,
       
   137                                       String pathToCheck,
       
   138                                       Set<? extends OpenOption> options,
       
   139                                       long pSecurityDescriptor)
       
   140         throws WindowsException
       
   141     {
       
   142         Flags flags = Flags.toFlags(options);
       
   143 
       
   144         // default is reading; append => writing
       
   145         if (!flags.read && !flags.write) {
       
   146             if (flags.append) {
       
   147                 flags.write = true;
       
   148             } else {
       
   149                 flags.read = true;
       
   150             }
       
   151         }
       
   152 
       
   153         // validation
       
   154         if (flags.read && flags.append)
       
   155             throw new IllegalArgumentException("READ + APPEND not allowed");
       
   156         if (flags.append && flags.truncateExisting)
       
   157             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
       
   158 
       
   159         FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
       
   160         return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
       
   161     }
       
   162 
       
   163     /**
       
   164      * Open/creates file, returning AsynchronousFileChannel to access the file
       
   165      *
       
   166      * @param   pathForWindows
       
   167      *          The path of the file to open/create
       
   168      * @param   pathToCheck
       
   169      *          The path used for permission checks (if security manager)
       
   170      * @param   pool
       
   171      *          The thread pool that the channel is associated with
       
   172      */
       
   173     static AsynchronousFileChannel newAsynchronousFileChannel(String pathForWindows,
       
   174                                                               String pathToCheck,
       
   175                                                               Set<? extends OpenOption> options,
       
   176                                                               long pSecurityDescriptor,
       
   177                                                               ThreadPool pool)
       
   178         throws IOException
       
   179     {
       
   180         Flags flags = Flags.toFlags(options);
       
   181 
       
   182         // Overlapped I/O required
       
   183         flags.overlapped = true;
       
   184 
       
   185         // default is reading
       
   186         if (!flags.read && !flags.write) {
       
   187             flags.read = true;
       
   188         }
       
   189 
       
   190         // validation
       
   191         if (flags.append)
       
   192             throw new UnsupportedOperationException("APPEND not allowed");
       
   193 
       
   194         // open file for overlapped I/O
       
   195         FileDescriptor fdObj;
       
   196         try {
       
   197             fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
       
   198         } catch (WindowsException x) {
       
   199             x.rethrowAsIOException(pathForWindows);
       
   200             return null;
       
   201         }
       
   202 
       
   203         // create the AsynchronousFileChannel
       
   204         try {
       
   205             return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
       
   206         } catch (IOException x) {
       
   207             // IOException is thrown if the file handle cannot be associated
       
   208             // with the completion port. All we can do is close the file.
       
   209             long handle = fdAccess.getHandle(fdObj);
       
   210             CloseHandle(handle);
       
   211             throw x;
       
   212         }
       
   213     }
       
   214 
       
   215     /**
       
   216      * Opens file based on parameters and options, returning a FileDescriptor
       
   217      * encapsulating the handle to the open file.
       
   218      */
       
   219     private static FileDescriptor open(String pathForWindows,
       
   220                                        String pathToCheck,
       
   221                                        Flags flags,
       
   222                                        long pSecurityDescriptor)
       
   223         throws WindowsException
       
   224     {
       
   225         // set to true if file must be truncated after open
       
   226         boolean truncateAfterOpen = false;
       
   227 
       
   228         // map options
       
   229         int dwDesiredAccess = 0;
       
   230         if (flags.read)
       
   231             dwDesiredAccess |= GENERIC_READ;
       
   232         if (flags.write)
       
   233             dwDesiredAccess |= (flags.append) ? FILE_APPEND_DATA : GENERIC_WRITE;
       
   234 
       
   235         int dwShareMode = 0;
       
   236         if (flags.shareRead)
       
   237             dwShareMode |= FILE_SHARE_READ;
       
   238         if (flags.shareWrite)
       
   239             dwShareMode |= FILE_SHARE_WRITE;
       
   240         if (flags.shareDelete)
       
   241             dwShareMode |= FILE_SHARE_DELETE;
       
   242 
       
   243         int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
       
   244         int dwCreationDisposition = OPEN_EXISTING;
       
   245         if (flags.write) {
       
   246             if (flags.createNew) {
       
   247                 dwCreationDisposition = CREATE_NEW;
       
   248                 // force create to fail if file is orphaned reparse point
       
   249                 dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
       
   250             } else {
       
   251                 if (flags.create)
       
   252                     dwCreationDisposition = OPEN_ALWAYS;
       
   253                 if (flags.truncateExisting) {
       
   254                     // Windows doesn't have a creation disposition that exactly
       
   255                     // corresponds to CREATE + TRUNCATE_EXISTING so we use
       
   256                     // the OPEN_ALWAYS mode and then truncate the file.
       
   257                     if (dwCreationDisposition == OPEN_ALWAYS) {
       
   258                         truncateAfterOpen = true;
       
   259                     } else {
       
   260                         dwCreationDisposition = TRUNCATE_EXISTING;
       
   261                     }
       
   262                 }
       
   263             }
       
   264         }
       
   265 
       
   266         if (flags.dsync || flags.sync)
       
   267             dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
       
   268         if (flags.overlapped)
       
   269             dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
       
   270         if (flags.deleteOnClose)
       
   271             dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
       
   272 
       
   273         // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point
       
   274         boolean okayToFollowLinks = true;
       
   275         if (dwCreationDisposition != CREATE_NEW &&
       
   276             (flags.noFollowLinks ||
       
   277              flags.openReparsePoint ||
       
   278              flags.deleteOnClose))
       
   279         {
       
   280             if (flags.noFollowLinks || flags.deleteOnClose)
       
   281                 okayToFollowLinks = false;
       
   282             dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
       
   283         }
       
   284 
       
   285         // permission check
       
   286         if (pathToCheck != null) {
       
   287             SecurityManager sm = System.getSecurityManager();
       
   288             if (sm != null) {
       
   289                 if (flags.read)
       
   290                     sm.checkRead(pathToCheck);
       
   291                 if (flags.write)
       
   292                     sm.checkWrite(pathToCheck);
       
   293                 if (flags.deleteOnClose)
       
   294                     sm.checkDelete(pathToCheck);
       
   295             }
       
   296         }
       
   297 
       
   298         // open file
       
   299         long handle = CreateFile(pathForWindows,
       
   300                                  dwDesiredAccess,
       
   301                                  dwShareMode,
       
   302                                  pSecurityDescriptor,
       
   303                                  dwCreationDisposition,
       
   304                                  dwFlagsAndAttributes);
       
   305 
       
   306         // make sure this isn't a symbolic link.
       
   307         if (!okayToFollowLinks) {
       
   308             try {
       
   309                 if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink())
       
   310                     throw new WindowsException("File is symbolic link");
       
   311             } catch (WindowsException x) {
       
   312                 CloseHandle(handle);
       
   313                 throw x;
       
   314             }
       
   315         }
       
   316 
       
   317         // truncate file (for CREATE + TRUNCATE_EXISTING case)
       
   318         if (truncateAfterOpen) {
       
   319             try {
       
   320                 SetEndOfFile(handle);
       
   321             } catch (WindowsException x) {
       
   322                 CloseHandle(handle);
       
   323                 throw x;
       
   324             }
       
   325         }
       
   326 
       
   327         // make the file sparse if needed
       
   328         if (dwCreationDisposition == CREATE_NEW && flags.sparse) {
       
   329             try {
       
   330                 DeviceIoControlSetSparse(handle);
       
   331             } catch (WindowsException x) {
       
   332                 // ignore as sparse option is hint
       
   333             }
       
   334         }
       
   335 
       
   336         // create FileDescriptor and return
       
   337         FileDescriptor fdObj = new FileDescriptor();
       
   338         fdAccess.setHandle(fdObj, handle);
       
   339         return fdObj;
       
   340     }
       
   341 }