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.file.spi.*; 30 import java.nio.file.attribute.*; 31 import java.nio.channels.*; 32 import java.net.URI; 33 import java.util.concurrent.ExecutorService; 34 import java.io.IOException; 35 import java.util.*; 36 37 import sun.nio.ch.ThreadPool; 38 39 public class WindowsFileSystemProvider 40 extends FileSystemProvider 41 { 42 private static final String USER_DIR = "user.dir"; 43 private final WindowsFileSystem theFileSystem; 44 45 public WindowsFileSystemProvider() { 46 theFileSystem = new WindowsFileSystem(this, System.getProperty(USER_DIR)); 47 } 48 49 @Override 50 public String getScheme() { 51 return "file"; 52 } 53 54 private void checkUri(URI uri) { 55 if (!uri.getScheme().equalsIgnoreCase(getScheme())) 56 throw new IllegalArgumentException("URI does not match this provider"); 57 if (uri.getAuthority() != null) 58 throw new IllegalArgumentException("Authority component present"); 59 if (uri.getPath() == null) 60 throw new IllegalArgumentException("Path component is undefined"); 61 if (!uri.getPath().equals("/")) 126 throw new ProviderMismatchException(); 127 WindowsPath file = (WindowsPath)path; 128 ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0); 129 WindowsSecurityDescriptor sd = 130 WindowsSecurityDescriptor.fromAttribute(attrs); 131 try { 132 return WindowsChannelFactory 133 .newAsynchronousFileChannel(file.getPathForWin32Calls(), 134 file.getPathForPermissionCheck(), 135 options, 136 sd.address(), 137 pool); 138 } catch (WindowsException x) { 139 x.rethrowAsIOException(file); 140 return null; 141 } finally { 142 if (sd != null) 143 sd.release(); 144 } 145 } 146 } | 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.file.attribute.*; 30 import java.nio.channels.*; 31 import java.net.URI; 32 import java.util.concurrent.ExecutorService; 33 import java.io.*; 34 import java.util.*; 35 import java.security.AccessController; 36 import sun.misc.Unsafe; 37 import sun.nio.ch.ThreadPool; 38 import sun.security.util.SecurityConstants; 39 40 import static sun.nio.fs.WindowsNativeDispatcher.*; 41 import static sun.nio.fs.WindowsConstants.*; 42 43 public class WindowsFileSystemProvider 44 extends AbstractFileSystemProvider 45 { 46 private static final Unsafe unsafe = Unsafe.getUnsafe(); 47 48 private static final String USER_DIR = "user.dir"; 49 private final WindowsFileSystem theFileSystem; 50 51 public WindowsFileSystemProvider() { 52 theFileSystem = new WindowsFileSystem(this, System.getProperty(USER_DIR)); 53 } 54 55 @Override 56 public String getScheme() { 57 return "file"; 58 } 59 60 private void checkUri(URI uri) { 61 if (!uri.getScheme().equalsIgnoreCase(getScheme())) 62 throw new IllegalArgumentException("URI does not match this provider"); 63 if (uri.getAuthority() != null) 64 throw new IllegalArgumentException("Authority component present"); 65 if (uri.getPath() == null) 66 throw new IllegalArgumentException("Path component is undefined"); 67 if (!uri.getPath().equals("/")) 132 throw new ProviderMismatchException(); 133 WindowsPath file = (WindowsPath)path; 134 ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0); 135 WindowsSecurityDescriptor sd = 136 WindowsSecurityDescriptor.fromAttribute(attrs); 137 try { 138 return WindowsChannelFactory 139 .newAsynchronousFileChannel(file.getPathForWin32Calls(), 140 file.getPathForPermissionCheck(), 141 options, 142 sd.address(), 143 pool); 144 } catch (WindowsException x) { 145 x.rethrowAsIOException(file); 146 return null; 147 } finally { 148 if (sd != null) 149 sd.release(); 150 } 151 } 152 153 private boolean followLinks(LinkOption... options) { 154 boolean followLinks = true; 155 for (LinkOption option: options) { 156 if (option == LinkOption.NOFOLLOW_LINKS) { 157 followLinks = false; 158 continue; 159 } 160 if (option == null) 161 throw new NullPointerException(); 162 throw new AssertionError("Should not get here"); 163 } 164 return followLinks; 165 } 166 167 @Override 168 @SuppressWarnings("unchecked") 169 public <V extends FileAttributeView> V 170 getFileAttributeView(Path obj, Class<V> view, LinkOption... options) 171 { 172 WindowsPath file = WindowsPath.toWindowsPath(obj); 173 if (view == null) 174 throw new NullPointerException(); 175 boolean followLinks = followLinks(options); 176 if (view == BasicFileAttributeView.class) 177 return (V) WindowsFileAttributeViews.createBasicView(file, followLinks); 178 if (view == DosFileAttributeView.class) 179 return (V) WindowsFileAttributeViews.createDosView(file, followLinks); 180 if (view == AclFileAttributeView.class) 181 return (V) new WindowsAclFileAttributeView(file, followLinks); 182 if (view == FileOwnerAttributeView.class) 183 return (V) new FileOwnerAttributeViewImpl( 184 new WindowsAclFileAttributeView(file, followLinks)); 185 if (view == UserDefinedFileAttributeView.class) 186 return (V) new WindowsUserDefinedFileAttributeView(file, followLinks); 187 return (V) null; 188 } 189 190 @Override 191 @SuppressWarnings("unchecked") 192 public <A extends BasicFileAttributes> A readAttributes(Path file, 193 Class<A> type, 194 LinkOption... options) 195 throws IOException 196 { 197 Class<? extends BasicFileAttributeView> view; 198 if (type == BasicFileAttributes.class) 199 view = BasicFileAttributeView.class; 200 else if (type == DosFileAttributes.class) 201 view = DosFileAttributeView.class; 202 else if (type == null) 203 throw new NullPointerException(); 204 else 205 throw new UnsupportedOperationException(); 206 return (A) getFileAttributeView(file, view, options).readAttributes(); 207 } 208 209 @Override 210 public DynamicFileAttributeView getFileAttributeView(Path obj, String name, LinkOption... options) { 211 WindowsPath file = WindowsPath.toWindowsPath(obj); 212 boolean followLinks = followLinks(options); 213 if (name.equals("basic")) 214 return WindowsFileAttributeViews.createBasicView(file, followLinks); 215 if (name.equals("dos")) 216 return WindowsFileAttributeViews.createDosView(file, followLinks); 217 if (name.equals("acl")) 218 return new WindowsAclFileAttributeView(file, followLinks); 219 if (name.equals("owner")) 220 return new FileOwnerAttributeViewImpl( 221 new WindowsAclFileAttributeView(file, followLinks)); 222 if (name.equals("user")) 223 return new WindowsUserDefinedFileAttributeView(file, followLinks); 224 return null; 225 } 226 227 @Override 228 public SeekableByteChannel newByteChannel(Path obj, 229 Set<? extends OpenOption> options, 230 FileAttribute<?>... attrs) 231 throws IOException 232 { 233 WindowsPath file = WindowsPath.toWindowsPath(obj); 234 WindowsSecurityDescriptor sd = 235 WindowsSecurityDescriptor.fromAttribute(attrs); 236 try { 237 return WindowsChannelFactory 238 .newFileChannel(file.getPathForWin32Calls(), 239 file.getPathForPermissionCheck(), 240 options, 241 sd.address()); 242 } catch (WindowsException x) { 243 x.rethrowAsIOException(file); 244 return null; // keep compiler happy 245 } finally { 246 sd.release(); 247 } 248 } 249 250 @Override 251 boolean implDelete(Path obj, boolean failIfNotExists) throws IOException { 252 WindowsPath file = WindowsPath.toWindowsPath(obj); 253 file.checkDelete(); 254 255 WindowsFileAttributes attrs = null; 256 try { 257 // need to know if file is a directory or junction 258 attrs = WindowsFileAttributes.get(file, false); 259 if (attrs.isDirectory() || attrs.isDirectoryLink()) { 260 RemoveDirectory(file.getPathForWin32Calls()); 261 } else { 262 DeleteFile(file.getPathForWin32Calls()); 263 } 264 return true; 265 } catch (WindowsException x) { 266 267 // no-op if file does not exist 268 if (!failIfNotExists && 269 (x.lastError() == ERROR_FILE_NOT_FOUND || 270 x.lastError() == ERROR_PATH_NOT_FOUND)) return false; 271 272 if (attrs != null && attrs.isDirectory()) { 273 // ERROR_ALREADY_EXISTS is returned when attempting to delete 274 // non-empty directory on SAMBA servers. 275 if (x.lastError() == ERROR_DIR_NOT_EMPTY || 276 x.lastError() == ERROR_ALREADY_EXISTS) 277 { 278 throw new DirectoryNotEmptyException( 279 file.getPathForExceptionMessage()); 280 } 281 } 282 x.rethrowAsIOException(file); 283 return false; 284 } 285 } 286 287 @Override 288 public void copy(Path source, Path target, CopyOption... options) 289 throws IOException 290 { 291 WindowsFileCopy.copy(WindowsPath.toWindowsPath(source), 292 WindowsPath.toWindowsPath(target), 293 options); 294 } 295 296 @Override 297 public void move(Path source, Path target, CopyOption... options) 298 throws IOException 299 { 300 WindowsFileCopy.move(WindowsPath.toWindowsPath(source), 301 WindowsPath.toWindowsPath(target), 302 options); 303 } 304 305 /** 306 * Returns buffer with SID_AND_ATTRIBUTES structure representing the user 307 * associated with the current thread access token. 308 * FIXME - this should be cached. 309 */ 310 private static NativeBuffer getUserInfo(WindowsPath file) throws IOException { 311 try { 312 long hToken = WindowsSecurity.processTokenWithQueryAccess; 313 int size = GetTokenInformation(hToken, TokenUser, 0L, 0); 314 assert size > 0; 315 316 NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); 317 try { 318 int newsize = GetTokenInformation(hToken, TokenUser, 319 buffer.address(), size); 320 if (newsize != size) 321 throw new AssertionError(); 322 return buffer; 323 } catch (WindowsException x) { 324 buffer.release(); 325 throw x; 326 } 327 } catch (WindowsException x) { 328 throw new IOException(x.getMessage()); 329 } 330 } 331 332 /** 333 * Reads the file ACL and return the effective access as ACCESS_MASK 334 */ 335 private static int getEffectiveAccess(WindowsPath file) throws IOException { 336 // read security descriptor continaing ACL (symlinks are followed) 337 String target = WindowsLinkSupport.getFinalPath(file, true); 338 NativeBuffer aclBuffer = WindowsAclFileAttributeView 339 .getFileSecurity(target, DACL_SECURITY_INFORMATION); 340 341 // retrieves DACL from security descriptor 342 long pAcl = GetSecurityDescriptorDacl(aclBuffer.address()); 343 344 // Use GetEffectiveRightsFromAcl to get effective access to file 345 try { 346 NativeBuffer userBuffer = getUserInfo(file); 347 try { 348 try { 349 // SID_AND_ATTRIBUTES->pSid 350 long pSid = unsafe.getAddress(userBuffer.address()); 351 long pTrustee = BuildTrusteeWithSid(pSid); 352 try { 353 return GetEffectiveRightsFromAcl(pAcl, pTrustee); 354 } finally { 355 LocalFree(pTrustee); 356 } 357 } catch (WindowsException x) { 358 throw new IOException("Unable to get effective rights from ACL: " + 359 x.getMessage()); 360 } 361 } finally { 362 userBuffer.release(); 363 } 364 } finally { 365 aclBuffer.release(); 366 } 367 } 368 369 @Override 370 public void checkAccess(Path obj, AccessMode... modes) throws IOException { 371 WindowsPath file = WindowsPath.toWindowsPath(obj); 372 // if no access modes then simply file attributes 373 if (modes.length == 0) { 374 file.checkRead(); 375 try { 376 WindowsFileAttributes.get(file, true); 377 } catch (WindowsException exc) { 378 exc.rethrowAsIOException(file); 379 } 380 return; 381 } 382 383 boolean r = false; 384 boolean w = false; 385 boolean x = false; 386 for (AccessMode mode: modes) { 387 switch (mode) { 388 case READ : r = true; break; 389 case WRITE : w = true; break; 390 case EXECUTE : x = true; break; 391 default: throw new AssertionError("Should not get here"); 392 } 393 } 394 395 int mask = 0; 396 if (r) { 397 file.checkRead(); 398 mask |= FILE_READ_DATA; 399 } 400 if (w) { 401 file.checkWrite(); 402 mask |= FILE_WRITE_DATA; 403 } 404 if (x) { 405 SecurityManager sm = System.getSecurityManager(); 406 if (sm != null) 407 sm.checkExec(file.getPathForPermissionCheck()); 408 mask |= FILE_EXECUTE; 409 } 410 411 if ((getEffectiveAccess(file) & mask) == 0) 412 throw new AccessDeniedException( 413 file.getPathForExceptionMessage(), null, 414 "Effective permissions does not allow requested access"); 415 416 // for write access we neeed to check if the DOS readonly attribute 417 // and if the volume is read-only 418 if (w) { 419 try { 420 WindowsFileAttributes attrs = WindowsFileAttributes.get(file, true); 421 if (!attrs.isDirectory() && attrs.isReadOnly()) 422 throw new AccessDeniedException( 423 file.getPathForExceptionMessage(), null, 424 "DOS readonly attribute is set"); 425 } catch (WindowsException exc) { 426 exc.rethrowAsIOException(file); 427 } 428 429 if (WindowsFileStore.create(file).isReadOnly()) { 430 throw new AccessDeniedException( 431 file.getPathForExceptionMessage(), null, "Read-only file system"); 432 } 433 return; 434 } 435 } 436 437 @Override 438 public boolean isSameFile(Path obj1, Path obj2) throws IOException { 439 WindowsPath file1 = WindowsPath.toWindowsPath(obj1); 440 if (file1.equals(obj2)) 441 return true; 442 if (obj2 == null) 443 throw new NullPointerException(); 444 if (!(obj2 instanceof WindowsPath)) 445 return false; 446 WindowsPath file2 = (WindowsPath)obj2; 447 448 // check security manager access to both files 449 file1.checkRead(); 450 file2.checkRead(); 451 452 // open both files and see if they are the same 453 long h1 = 0L; 454 try { 455 h1 = file1.openForReadAttributeAccess(true); 456 } catch (WindowsException x) { 457 x.rethrowAsIOException(file1); 458 } 459 try { 460 WindowsFileAttributes attrs1 = null; 461 try { 462 attrs1 = WindowsFileAttributes.readAttributes(h1); 463 } catch (WindowsException x) { 464 x.rethrowAsIOException(file1); 465 } 466 long h2 = 0L; 467 try { 468 h2 = file2.openForReadAttributeAccess(true); 469 } catch (WindowsException x) { 470 x.rethrowAsIOException(file2); 471 } 472 try { 473 WindowsFileAttributes attrs2 = null; 474 try { 475 attrs2 = WindowsFileAttributes.readAttributes(h2); 476 } catch (WindowsException x) { 477 x.rethrowAsIOException(file2); 478 } 479 return WindowsFileAttributes.isSameFile(attrs1, attrs2); 480 } finally { 481 CloseHandle(h2); 482 } 483 } finally { 484 CloseHandle(h1); 485 } 486 } 487 488 @Override 489 public boolean isHidden(Path obj) throws IOException { 490 WindowsPath file = WindowsPath.toWindowsPath(obj); 491 file.checkRead(); 492 WindowsFileAttributes attrs = null; 493 try { 494 attrs = WindowsFileAttributes.get(file, true); 495 } catch (WindowsException x) { 496 x.rethrowAsIOException(file); 497 } 498 // DOS hidden attribute not meaningful when set on directories 499 if (attrs.isDirectory()) 500 return false; 501 return attrs.isHidden(); 502 } 503 504 @Override 505 public FileStore getFileStore(Path obj) throws IOException { 506 WindowsPath file = WindowsPath.toWindowsPath(obj); 507 SecurityManager sm = System.getSecurityManager(); 508 if (sm != null) { 509 sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); 510 file.checkRead(); 511 } 512 return WindowsFileStore.create(file); 513 } 514 515 516 @Override 517 public void createDirectory(Path obj, FileAttribute<?>... attrs) 518 throws IOException 519 { 520 WindowsPath dir = WindowsPath.toWindowsPath(obj); 521 dir.checkWrite(); 522 WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs); 523 try { 524 CreateDirectory(dir.getPathForWin32Calls(), sd.address()); 525 } catch (WindowsException x) { 526 x.rethrowAsIOException(dir); 527 } finally { 528 sd.release(); 529 } 530 } 531 532 @Override 533 public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter) 534 throws IOException 535 { 536 WindowsPath dir = WindowsPath.toWindowsPath(obj); 537 dir.checkRead(); 538 if (filter == null) 539 throw new NullPointerException(); 540 return new WindowsDirectoryStream(dir, filter); 541 } 542 543 @Override 544 public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs) 545 throws IOException 546 { 547 WindowsPath link = WindowsPath.toWindowsPath(obj1); 548 WindowsPath target = WindowsPath.toWindowsPath(obj2); 549 550 if (!link.getFileSystem().supportsLinks()) { 551 throw new UnsupportedOperationException("Symbolic links not supported " 552 + "on this operating system"); 553 } 554 555 // no attributes allowed 556 if (attrs.length > 0) { 557 WindowsSecurityDescriptor.fromAttribute(attrs); // may throw NPE or UOE 558 throw new UnsupportedOperationException("Initial file attributes" + 559 "not supported when creating symbolic link"); 560 } 561 562 // permission check 563 SecurityManager sm = System.getSecurityManager(); 564 if (sm != null) { 565 sm.checkPermission(new LinkPermission("symbolic")); 566 link.checkWrite(); 567 } 568 569 /** 570 * Throw I/O exception for the drive-relative case because Windows 571 * creates a link with the resolved target for this case. 572 */ 573 if (target.type() == WindowsPathType.DRIVE_RELATIVE) { 574 throw new IOException("Cannot create symbolic link to working directory relative target"); 575 } 576 577 /* 578 * Windows treates symbolic links to directories differently than it 579 * does to other file types. For that reason we need to check if the 580 * target is a directory (or a directory junction). 581 */ 582 WindowsPath resolvedTarget; 583 if (target.type() == WindowsPathType.RELATIVE) { 584 WindowsPath parent = link.getParent(); 585 resolvedTarget = (parent == null) ? target : parent.resolve(target); 586 } else { 587 resolvedTarget = link.resolve(target); 588 } 589 int flags = 0; 590 try { 591 WindowsFileAttributes wattrs = WindowsFileAttributes.get(resolvedTarget, false); 592 if (wattrs.isDirectory() || wattrs.isDirectoryLink()) 593 flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; 594 } catch (WindowsException x) { 595 // unable to access target so assume target is not a directory 596 } 597 598 // create the link 599 try { 600 CreateSymbolicLink(link.getPathForWin32Calls(), 601 WindowsPath.addPrefixIfNeeded(target.toString()), 602 flags); 603 } catch (WindowsException x) { 604 if (x.lastError() == ERROR_INVALID_REPARSE_DATA) { 605 x.rethrowAsIOException(link, target); 606 } else { 607 x.rethrowAsIOException(link); 608 } 609 } 610 } 611 612 @Override 613 public void createLink(Path obj1, Path obj2) throws IOException { 614 WindowsPath link = WindowsPath.toWindowsPath(obj1); 615 WindowsPath existing = WindowsPath.toWindowsPath(obj2); 616 617 // permission check 618 SecurityManager sm = System.getSecurityManager(); 619 if (sm != null) { 620 sm.checkPermission(new LinkPermission("hard")); 621 link.checkWrite(); 622 existing.checkWrite(); 623 } 624 625 // create hard link 626 try { 627 CreateHardLink(link.getPathForWin32Calls(), 628 existing.getPathForWin32Calls()); 629 } catch (WindowsException x) { 630 x.rethrowAsIOException(link, existing); 631 } 632 } 633 634 @Override 635 public Path readSymbolicLink(Path obj1) throws IOException { 636 WindowsPath link = WindowsPath.toWindowsPath(obj1); 637 WindowsFileSystem fs = link.getFileSystem(); 638 if (!fs.supportsLinks()) { 639 throw new UnsupportedOperationException("symbolic links not supported"); 640 } 641 642 // permission check 643 SecurityManager sm = System.getSecurityManager(); 644 if (sm != null) { 645 FilePermission perm = new FilePermission(link.getPathForPermissionCheck(), 646 SecurityConstants.FILE_READLINK_ACTION); 647 AccessController.checkPermission(perm); 648 } 649 650 String target = WindowsLinkSupport.readLink(link); 651 return WindowsPath.createFromNormalizedPath(fs, target); 652 } 653 } |