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