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 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, flags.write, flags.direct, null); 170 } 171 172 /** 173 * Open/creates file, returning AsynchronousFileChannel to access the file 174 * 175 * @param pathForWindows 176 * The path of the file to open/create 177 * @param pathToCheck 178 * The path used for permission checks (if security manager) 179 * @param pool 180 * The thread pool that the channel is associated with 181 */ 182 static AsynchronousFileChannel newAsynchronousFileChannel(String pathForWindows, 183 String pathToCheck, 184 Set<? extends OpenOption> options, 185 long pSecurityDescriptor, 186 ThreadPool pool) 187 throws IOException 188 { 189 Flags flags = Flags.toFlags(options); 190 191 // Overlapped I/O required 192 flags.overlapped = true; 193 194 // default is reading 195 if (!flags.read && !flags.write) { 196 flags.read = true; 197 } 198 199 // validation 200 if (flags.append) 201 throw new UnsupportedOperationException("APPEND not allowed"); 202 203 // open file for overlapped I/O 204 FileDescriptor fdObj; 205 try { 206 fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor); 207 } catch (WindowsException x) { 208 x.rethrowAsIOException(pathForWindows); 209 return null; 210 } 211 212 // create the AsynchronousFileChannel 213 try { 214 return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool); 215 } catch (IOException x) { 216 // IOException is thrown if the file handle cannot be associated 217 // with the completion port. All we can do is close the file. 218 long handle = fdAccess.getHandle(fdObj); 219 CloseHandle(handle); 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 if (flags.direct) 282 dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING; 283 284 // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point 285 boolean okayToFollowLinks = true; 286 if (dwCreationDisposition != CREATE_NEW && 287 (flags.noFollowLinks || 288 flags.openReparsePoint || 289 flags.deleteOnClose)) 290 { 291 if (flags.noFollowLinks || flags.deleteOnClose) 292 okayToFollowLinks = false; 293 dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT; 294 } 295 296 // permission check 297 if (pathToCheck != null) { 298 SecurityManager sm = System.getSecurityManager(); 299 if (sm != null) { 300 if (flags.read) 301 sm.checkRead(pathToCheck); 302 if (flags.write) 303 sm.checkWrite(pathToCheck); 304 if (flags.deleteOnClose) 305 sm.checkDelete(pathToCheck); 306 } 307 } 308 309 // open file 310 long handle = CreateFile(pathForWindows, 311 dwDesiredAccess, 312 dwShareMode, 313 pSecurityDescriptor, 314 dwCreationDisposition, 315 dwFlagsAndAttributes); 316 317 // make sure this isn't a symbolic link. 318 if (!okayToFollowLinks) { 319 try { 320 if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink()) 321 throw new WindowsException("File is symbolic link"); 322 } catch (WindowsException x) { 323 CloseHandle(handle); 324 throw x; 325 } 326 } 327 328 // truncate file (for CREATE + TRUNCATE_EXISTING case) 329 if (truncateAfterOpen) { 330 try { 331 SetEndOfFile(handle); 332 } catch (WindowsException x) { 333 CloseHandle(handle); 334 throw x; 335 } 336 } 337 338 // make the file sparse if needed 339 if (dwCreationDisposition == CREATE_NEW && flags.sparse) { 340 try { 341 DeviceIoControlSetSparse(handle); 342 } catch (WindowsException x) { 343 // ignore as sparse option is hint 344 } 345 } 346 347 // create FileDescriptor and return 348 FileDescriptor fdObj = new FileDescriptor(); 349 fdAccess.setHandle(fdObj, handle); 350 fdAccess.setAppend(fdObj, flags.append); 351 return fdObj; 352 } 353 }