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