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