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