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 fdAccess.close(fdObj); 220 throw x; 221 } 222 } 223 224 /** 225 * Opens file based on parameters and options, returning a FileDescriptor 226 * encapsulating the handle to the open file. 227 */ 228 private static FileDescriptor open(String pathForWindows, 229 String pathToCheck, 230 Flags flags, 231 long pSecurityDescriptor) 232 throws WindowsException 233 { 234 // set to true if file must be truncated after open 235 boolean truncateAfterOpen = false; 236 237 // map options 238 int dwDesiredAccess = 0; 239 if (flags.read) 240 dwDesiredAccess |= GENERIC_READ; 241 if (flags.write) 242 dwDesiredAccess |= GENERIC_WRITE; 243 244 int dwShareMode = 0; 245 if (flags.shareRead) 246 dwShareMode |= FILE_SHARE_READ; 247 if (flags.shareWrite) 248 dwShareMode |= FILE_SHARE_WRITE; 249 if (flags.shareDelete) 250 dwShareMode |= FILE_SHARE_DELETE; 251 252 int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 253 int dwCreationDisposition = OPEN_EXISTING; 254 if (flags.write) { 255 if (flags.createNew) { 256 dwCreationDisposition = CREATE_NEW; 257 // force create to fail if file is orphaned reparse point 258 dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT; 259 } else { 260 if (flags.create) 261 dwCreationDisposition = OPEN_ALWAYS; 262 if (flags.truncateExisting) { 263 // Windows doesn't have a creation disposition that exactly 264 // corresponds to CREATE + TRUNCATE_EXISTING so we use 265 // the OPEN_ALWAYS mode and then truncate the file. 266 if (dwCreationDisposition == OPEN_ALWAYS) { 267 truncateAfterOpen = true; 268 } else { 269 dwCreationDisposition = TRUNCATE_EXISTING; 270 } 271 } 272 } 273 } 274 275 if (flags.dsync || flags.sync) 276 dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH; 277 if (flags.overlapped) 278 dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED; 279 if (flags.deleteOnClose) 280 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE; 281 282 // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point 283 boolean okayToFollowLinks = true; 284 if (dwCreationDisposition != CREATE_NEW && 285 (flags.noFollowLinks || 286 flags.openReparsePoint || 287 flags.deleteOnClose)) 288 { 289 if (flags.noFollowLinks || flags.deleteOnClose) 290 okayToFollowLinks = false; 291 dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT; 292 } 293 294 // permission check 295 if (pathToCheck != null) { 296 SecurityManager sm = System.getSecurityManager(); 297 if (sm != null) { 298 if (flags.read) 299 sm.checkRead(pathToCheck); 300 if (flags.write) 301 sm.checkWrite(pathToCheck); 302 if (flags.deleteOnClose) 303 sm.checkDelete(pathToCheck); 304 } 305 } 306 307 // open file 308 long handle = CreateFile(pathForWindows, 309 dwDesiredAccess, 310 dwShareMode, 311 pSecurityDescriptor, 312 dwCreationDisposition, 313 dwFlagsAndAttributes); 314 315 // make sure this isn't a symbolic link. 316 if (!okayToFollowLinks) { 317 try { 318 if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink()) 319 throw new WindowsException("File is symbolic link"); 320 } catch (WindowsException x) { 321 CloseHandle(handle); 322 throw x; 323 } 324 } 325 326 // truncate file (for CREATE + TRUNCATE_EXISTING case) 327 if (truncateAfterOpen) { 328 try { 329 SetEndOfFile(handle); 330 } catch (WindowsException x) { 331 CloseHandle(handle); 332 throw x; 333 } 334 } 335 336 // make the file sparse if needed 337 if (dwCreationDisposition == CREATE_NEW && flags.sparse) { 338 try { 339 DeviceIoControlSetSparse(handle); 340 } catch (WindowsException x) { 341 // ignore as sparse option is hint 342 } 343 } 344 345 // create FileDescriptor and return 346 FileDescriptor fdObj = new FileDescriptor(); 347 fdAccess.setHandle(fdObj, handle); 348 fdAccess.setAppend(fdObj, flags.append); 349 fdAccess.registerCleanup(fdObj); 350 return fdObj; 351 } 352 }