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