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.nio.file.*; 29 import java.nio.file.attribute.*; 30 import java.io.*; 31 import java.net.URI; 32 import java.util.*; 33 import java.lang.ref.WeakReference; 34 35 import static sun.nio.fs.WindowsNativeDispatcher.*; 36 import static sun.nio.fs.WindowsConstants.*; 37 38 /** 39 * Windows implementation of Path 40 */ 41 42 class WindowsPath implements Path { 43 44 // The maximum path that does not require long path prefix. On Windows 45 // the maximum path is 260 minus 1 (NUL) but for directories it is 260 46 // minus 12 minus 1 (to allow for the creation of a 8.3 file in the 47 // directory). 48 private static final int MAX_PATH = 247; 49 50 // Maximum extended-length path 51 private static final int MAX_LONG_PATH = 32000; 52 53 // FIXME - eliminate this reference to reduce space 54 private final WindowsFileSystem fs; 55 56 // path type 57 private final WindowsPathType type; 58 // root component (may be empty) 59 private final String root; 60 // normalized path 61 private final String path; 62 63 // the path to use in Win32 calls. This differs from path for relative 64 // paths and has a long path prefix for all paths longer than MAX_PATH. 65 private volatile WeakReference<String> pathForWin32Calls; 66 67 // offsets into name components (computed lazily) 68 private volatile Integer[] offsets; 69 70 // computed hash code (computed lazily, no need to be volatile) 71 private int hash; 72 73 74 /** 75 * Initializes a new instance of this class. 76 */ 77 private WindowsPath(WindowsFileSystem fs, 78 WindowsPathType type, 79 String root, 80 String path) 81 { 82 this.fs = fs; 83 this.type = type; 84 this.root = root; 85 this.path = path; 86 } 87 88 /** 89 * Creates a Path by parsing the given path. 90 */ 91 static WindowsPath parse(WindowsFileSystem fs, String path) { 92 WindowsPathParser.Result result = WindowsPathParser.parse(path); 93 return new WindowsPath(fs, result.type(), result.root(), result.path()); 94 } 95 96 /** 97 * Creates a Path from a given path that is known to be normalized. 98 */ 99 static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, 100 String path, 101 BasicFileAttributes attrs) 102 { 103 try { 104 WindowsPathParser.Result result = 105 WindowsPathParser.parseNormalizedPath(path); 106 if (attrs == null) { 107 return new WindowsPath(fs, 108 result.type(), 109 result.root(), 110 result.path()); 111 } else { 112 return new WindowsPathWithAttributes(fs, 113 result.type(), 114 result.root(), 115 result.path(), 116 attrs); 117 } 118 } catch (InvalidPathException x) { 119 throw new AssertionError(x.getMessage()); 120 } 121 } 122 123 /** 124 * Creates a WindowsPath from a given path that is known to be normalized. 125 */ 126 static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, 127 String path) 128 { 129 return createFromNormalizedPath(fs, path, null); 130 } 131 132 /** 133 * Special implementation with attached/cached attributes (used to quicken 134 * file tree traversal) 135 */ 136 private static class WindowsPathWithAttributes 137 extends WindowsPath implements BasicFileAttributesHolder 138 { 139 final WeakReference<BasicFileAttributes> ref; 140 141 WindowsPathWithAttributes(WindowsFileSystem fs, 142 WindowsPathType type, 143 String root, 144 String path, 145 BasicFileAttributes attrs) 146 { 147 super(fs, type, root, path); 148 ref = new WeakReference<BasicFileAttributes>(attrs); 149 } 150 151 @Override 152 public BasicFileAttributes get() { 153 return ref.get(); 154 } 155 156 @Override 157 public void invalidate() { 158 ref.clear(); 159 } 160 161 // no need to override equals/hashCode. 162 } 163 164 // use this message when throwing exceptions 165 String getPathForExceptionMessage() { 166 return path; 167 } 168 169 // use this path for permission checks 170 String getPathForPermissionCheck() { 171 return path; 172 } 173 174 // use this path for Win32 calls 175 // This method will prefix long paths with \\?\ or \\?\UNC as required. 176 String getPathForWin32Calls() throws WindowsException { 177 // short absolute paths can be used directly 178 if (isAbsolute() && path.length() <= MAX_PATH) 179 return path; 180 181 // return cached values if available 182 WeakReference<String> ref = pathForWin32Calls; 183 String resolved = (ref != null) ? ref.get() : null; 184 if (resolved != null) { 185 // Win32 path already available 186 return resolved; 187 } 188 189 // resolve against default directory 190 resolved = getAbsolutePath(); 191 192 // Long paths need to have "." and ".." removed and be prefixed with 193 // "\\?\". Note that it is okay to remove ".." even when it follows 194 // a link - for example, it is okay for foo/link/../bar to be changed 195 // to foo/bar. The reason is that Win32 APIs to access foo/link/../bar 196 // will access foo/bar anyway (which differs to Unix systems) 197 if (resolved.length() > MAX_PATH) { 198 if (resolved.length() > MAX_LONG_PATH) { 199 throw new WindowsException("Cannot access file with path exceeding " 200 + MAX_LONG_PATH + " characters"); 201 } 202 resolved = addPrefixIfNeeded(GetFullPathName(resolved)); 203 } 204 205 // cache the resolved path (except drive relative paths as the working 206 // directory on removal media devices can change during the lifetime 207 // of the VM) 208 if (type != WindowsPathType.DRIVE_RELATIVE) { 209 synchronized (path) { 210 pathForWin32Calls = new WeakReference<String>(resolved); 211 } 212 } 213 return resolved; 214 } 215 216 // return this path resolved against the file system's default directory 217 private String getAbsolutePath() throws WindowsException { 218 if (isAbsolute()) 219 return path; 220 221 // Relative path ("foo" for example) 222 if (type == WindowsPathType.RELATIVE) { 223 String defaultDirectory = getFileSystem().defaultDirectory(); 224 if (isEmpty()) 225 return defaultDirectory; 226 if (defaultDirectory.endsWith("\\")) { 227 return defaultDirectory + path; 228 } else { 229 StringBuilder sb = 230 new StringBuilder(defaultDirectory.length() + path.length() + 1); 231 return sb.append(defaultDirectory).append('\\').append(path).toString(); 232 } 233 } 234 235 // Directory relative path ("\foo" for example) 236 if (type == WindowsPathType.DIRECTORY_RELATIVE) { 237 String defaultRoot = getFileSystem().defaultRoot(); 238 return defaultRoot + path.substring(1); 239 } 240 241 // Drive relative path ("C:foo" for example). 242 if (isSameDrive(root, getFileSystem().defaultRoot())) { 243 // relative to default directory 244 String remaining = path.substring(root.length()); 245 String defaultDirectory = getFileSystem().defaultDirectory(); 246 if (remaining.length() == 0) { 247 return defaultDirectory; 248 } else if (defaultDirectory.endsWith("\\")) { 249 return defaultDirectory + remaining; 250 } else { 251 return defaultDirectory + "\\" + remaining; 252 } 253 } else { 254 // relative to some other drive 255 String wd; 256 try { 257 int dt = GetDriveType(root + "\\"); 258 if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) 259 throw new WindowsException(""); 260 wd = GetFullPathName(root + "."); 261 } catch (WindowsException x) { 262 throw new WindowsException("Unable to get working directory of drive '" + 263 Character.toUpperCase(root.charAt(0)) + "'"); 264 } 265 String result = wd; 266 if (wd.endsWith("\\")) { 267 result += path.substring(root.length()); 268 } else { 269 if (path.length() > root.length()) 270 result += "\\" + path.substring(root.length()); 271 } 272 return result; 273 } 274 } 275 276 // returns true if same drive letter 277 private static boolean isSameDrive(String root1, String root2) { 278 return Character.toUpperCase(root1.charAt(0)) == 279 Character.toUpperCase(root2.charAt(0)); 280 } 281 282 // Add long path prefix to path if required 283 static String addPrefixIfNeeded(String path) { 284 if (path.length() > MAX_PATH) { 285 if (path.startsWith("\\\\")) { 286 path = "\\\\?\\UNC" + path.substring(1, path.length()); 287 } else { 288 path = "\\\\?\\" + path; 289 } 290 } 291 return path; 292 } 293 294 @Override 295 public WindowsFileSystem getFileSystem() { 296 return fs; 297 } 298 299 // -- Path operations -- 300 301 private boolean isEmpty() { 302 return path.length() == 0; 303 } 304 305 private WindowsPath emptyPath() { 306 return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", ""); 307 } 308 309 @Override 310 public Path getFileName() { 311 int len = path.length(); 312 // represents empty path 313 if (len == 0) 314 return this; 315 // represents root component only 316 if (root.length() == len) 317 return null; 318 int off = path.lastIndexOf('\\'); 319 if (off < root.length()) 320 off = root.length(); 321 else 322 off++; 323 return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", path.substring(off)); 324 } 325 326 @Override 327 public WindowsPath getParent() { 328 // represents root component only 329 if (root.length() == path.length()) 330 return null; 331 int off = path.lastIndexOf('\\'); 332 if (off < root.length()) 333 return getRoot(); 334 else 335 return new WindowsPath(getFileSystem(), 336 type, 337 root, 338 path.substring(0, off)); 339 } 340 341 @Override 342 public WindowsPath getRoot() { 343 if (root.length() == 0) 344 return null; 345 return new WindowsPath(getFileSystem(), type, root, root); 346 } 347 348 // package-private 349 WindowsPathType type() { 350 return type; 351 } 352 353 // package-private 354 boolean isUnc() { 355 return type == WindowsPathType.UNC; 356 } 357 358 boolean needsSlashWhenResolving() { 359 if (path.endsWith("\\")) 360 return false; 361 return path.length() > root.length(); 362 } 363 364 @Override 365 public boolean isAbsolute() { 366 return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC; 367 } 368 369 static WindowsPath toWindowsPath(Path path) { 370 if (path == null) 371 throw new NullPointerException(); 372 if (!(path instanceof WindowsPath)) { 373 throw new ProviderMismatchException(); 374 } 375 return (WindowsPath)path; 376 } 377 378 // return true if this path has "." or ".." 379 private boolean hasDotOrDotDot() { 380 int n = getNameCount(); 381 for (int i=0; i<n; i++) { 382 String name = elementAsString(i); 383 if (name.length() == 1 && name.charAt(0) == '.') 384 return true; 385 if (name.length() == 2 386 && name.charAt(0) == '.' && name.charAt(1) == '.') 387 return true; 388 } 389 return false; 390 } 391 392 @Override 393 public WindowsPath relativize(Path obj) { 394 WindowsPath child = toWindowsPath(obj); 395 if (this.equals(child)) 396 return emptyPath(); 397 398 // can only relativize paths of the same type 399 if (this.type != child.type) 400 throw new IllegalArgumentException("'other' is different type of Path"); 401 402 // can only relativize paths if root component matches 403 if (!this.root.equalsIgnoreCase(child.root)) 404 throw new IllegalArgumentException("'other' has different root"); 405 406 // this path is the empty path 407 if (this.isEmpty()) 408 return child; 409 410 411 WindowsPath base = this; 412 if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) { 413 base = base.normalize(); 414 child = child.normalize(); 415 } 416 417 int baseCount = base.getNameCount(); 418 int childCount = child.getNameCount(); 419 420 // skip matching names 421 int n = Math.min(baseCount, childCount); 422 int i = 0; 423 while (i < n) { 424 if (!base.getName(i).equals(child.getName(i))) 425 break; 426 i++; 427 } 428 429 // remaining elements in child 430 WindowsPath childRemaining; 431 boolean isChildEmpty; 432 if (i == childCount) { 433 childRemaining = emptyPath(); 434 isChildEmpty = true; 435 } else { 436 childRemaining = child.subpath(i, childCount); 437 isChildEmpty = childRemaining.isEmpty(); 438 } 439 440 // matched all of base 441 if (i == baseCount) { 442 return childRemaining; 443 } 444 445 // the remainder of base cannot contain ".." 446 WindowsPath baseRemaining = base.subpath(i, baseCount); 447 if (baseRemaining.hasDotOrDotDot()) { 448 throw new IllegalArgumentException("Unable to compute relative " 449 + " path from " + this + " to " + obj); 450 } 451 if (baseRemaining.isEmpty()) 452 return childRemaining; 453 454 // number of ".." needed 455 int dotdots = baseRemaining.getNameCount(); 456 if (dotdots == 0) { 457 return childRemaining; 458 } 459 460 StringBuilder result = new StringBuilder(); 461 for (int j=0; j<dotdots; j++) { 462 result.append("..\\"); 463 } 464 465 // append remaining names in child 466 if (!isChildEmpty) { 467 for (int j=0; j<childRemaining.getNameCount(); j++) { 468 result.append(childRemaining.getName(j).toString()); 469 result.append("\\"); 470 } 471 } 472 473 // drop trailing slash 474 result.setLength(result.length()-1); 475 return createFromNormalizedPath(getFileSystem(), result.toString()); 476 } 477 478 @Override 479 public WindowsPath normalize() { 480 final int count = getNameCount(); 481 if (count == 0 || isEmpty()) 482 return this; 483 484 boolean[] ignore = new boolean[count]; // true => ignore name 485 int remaining = count; // number of names remaining 486 487 // multiple passes to eliminate all occurrences of "." and "name/.." 488 int prevRemaining; 489 do { 490 prevRemaining = remaining; 491 int prevName = -1; 492 for (int i=0; i<count; i++) { 493 if (ignore[i]) 494 continue; 495 496 String name = elementAsString(i); 497 498 // not "." or ".." 499 if (name.length() > 2) { 500 prevName = i; 501 continue; 502 } 503 504 // "." or something else 505 if (name.length() == 1) { 506 // ignore "." 507 if (name.charAt(0) == '.') { 508 ignore[i] = true; 509 remaining--; 510 } else { 511 prevName = i; 512 } 513 continue; 514 } 515 516 // not ".." 517 if (name.charAt(0) != '.' || name.charAt(1) != '.') { 518 prevName = i; 519 continue; 520 } 521 522 // ".." found 523 if (prevName >= 0) { 524 // name/<ignored>/.. found so mark name and ".." to be 525 // ignored 526 ignore[prevName] = true; 527 ignore[i] = true; 528 remaining = remaining - 2; 529 prevName = -1; 530 } else { 531 // Cases: 532 // C:\<ignored>\.. 533 // \\server\\share\<ignored>\.. 534 // \<ignored>.. 535 if (isAbsolute() || type == WindowsPathType.DIRECTORY_RELATIVE) { 536 boolean hasPrevious = false; 537 for (int j=0; j<i; j++) { 538 if (!ignore[j]) { 539 hasPrevious = true; 540 break; 541 } 542 } 543 if (!hasPrevious) { 544 // all proceeding names are ignored 545 ignore[i] = true; 546 remaining--; 547 } 548 } 549 } 550 } 551 } while (prevRemaining > remaining); 552 553 // no redundant names 554 if (remaining == count) 555 return this; 556 557 // corner case - all names removed 558 if (remaining == 0) { 559 return (root.length() == 0) ? emptyPath() : getRoot(); 560 } 561 562 // re-constitute the path from the remaining names. 563 StringBuilder result = new StringBuilder(); 564 if (root != null) 565 result.append(root); 566 for (int i=0; i<count; i++) { 567 if (!ignore[i]) { 568 result.append(getName(i)); 569 result.append("\\"); 570 } 571 } 572 573 // drop trailing slash in result 574 result.setLength(result.length()-1); 575 return createFromNormalizedPath(getFileSystem(), result.toString()); 576 } 577 578 @Override 579 public WindowsPath resolve(Path obj) { 580 WindowsPath other = toWindowsPath(obj); 581 if (other.isEmpty()) 582 return this; 583 if (other.isAbsolute()) 584 return other; 585 586 switch (other.type) { 587 case RELATIVE: { 588 String result; 589 if (path.endsWith("\\") || (root.length() == path.length())) { 590 result = path + other.path; 591 } else { 592 result = path + "\\" + other.path; 593 } 594 return new WindowsPath(getFileSystem(), type, root, result); 595 } 596 597 case DIRECTORY_RELATIVE: { 598 String result; 599 if (root.endsWith("\\")) { 600 result = root + other.path.substring(1); 601 } else { 602 result = root + other.path; 603 } 604 return createFromNormalizedPath(getFileSystem(), result); 605 } 606 607 case DRIVE_RELATIVE: { 608 if (!root.endsWith("\\")) 609 return other; 610 // if different roots then return other 611 String thisRoot = root.substring(0, root.length()-1); 612 if (!thisRoot.equalsIgnoreCase(other.root)) 613 return other; 614 // same roots 615 String remaining = other.path.substring(other.root.length()); 616 String result; 617 if (path.endsWith("\\")) { 618 result = path + remaining; 619 } else { 620 result = path + "\\" + remaining; 621 } 622 return createFromNormalizedPath(getFileSystem(), result); 623 } 624 625 default: 626 throw new AssertionError(); 627 } 628 } 629 630 // generate offset array 631 private void initOffsets() { 632 if (offsets == null) { 633 ArrayList<Integer> list = new ArrayList<>(); 634 if (isEmpty()) { 635 // empty path considered to have one name element 636 list.add(0); 637 } else { 638 int start = root.length(); 639 int off = root.length(); 640 while (off < path.length()) { 641 if (path.charAt(off) != '\\') { 642 off++; 643 } else { 644 list.add(start); 645 start = ++off; 646 } 647 } 648 if (start != off) 649 list.add(start); 650 } 651 synchronized (this) { 652 if (offsets == null) 653 offsets = list.toArray(new Integer[list.size()]); 654 } 655 } 656 } 657 658 @Override 659 public int getNameCount() { 660 initOffsets(); 661 return offsets.length; 662 } 663 664 private String elementAsString(int i) { 665 initOffsets(); 666 if (i == (offsets.length-1)) 667 return path.substring(offsets[i]); 668 return path.substring(offsets[i], offsets[i+1]-1); 669 } 670 671 @Override 672 public WindowsPath getName(int index) { 673 initOffsets(); 674 if (index < 0 || index >= offsets.length) 675 throw new IllegalArgumentException(); 676 return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", elementAsString(index)); 677 } 678 679 @Override 680 public WindowsPath subpath(int beginIndex, int endIndex) { 681 initOffsets(); 682 if (beginIndex < 0) 683 throw new IllegalArgumentException(); 684 if (beginIndex >= offsets.length) 685 throw new IllegalArgumentException(); 686 if (endIndex > offsets.length) 687 throw new IllegalArgumentException(); 688 if (beginIndex >= endIndex) 689 throw new IllegalArgumentException(); 690 691 StringBuilder sb = new StringBuilder(); 692 Integer[] nelems = new Integer[endIndex - beginIndex]; 693 for (int i = beginIndex; i < endIndex; i++) { 694 nelems[i-beginIndex] = sb.length(); 695 sb.append(elementAsString(i)); 696 if (i != (endIndex-1)) 697 sb.append("\\"); 698 } 699 return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", sb.toString()); 700 } 701 702 @Override 703 public boolean startsWith(Path obj) { 704 if (!(Objects.requireNonNull(obj) instanceof WindowsPath)) 705 return false; 706 WindowsPath other = (WindowsPath)obj; 707 708 // if this path has a root component the given path's root must match 709 if (!this.root.equalsIgnoreCase(other.root)) { 710 return false; 711 } 712 713 // empty path starts with itself 714 if (other.isEmpty()) 715 return this.isEmpty(); 716 717 // roots match so compare elements 718 int thisCount = getNameCount(); 719 int otherCount = other.getNameCount(); 720 if (otherCount <= thisCount) { 721 while (--otherCount >= 0) { 722 String thisElement = this.elementAsString(otherCount); 723 String otherElement = other.elementAsString(otherCount); 724 // FIXME: should compare in uppercase 725 if (!thisElement.equalsIgnoreCase(otherElement)) 726 return false; 727 } 728 return true; 729 } 730 return false; 731 } 732 733 @Override 734 public boolean endsWith(Path obj) { 735 if (!(Objects.requireNonNull(obj) instanceof WindowsPath)) 736 return false; 737 WindowsPath other = (WindowsPath)obj; 738 739 // other path is longer 740 if (other.path.length() > this.path.length()) { 741 return false; 742 } 743 744 // empty path ends in itself 745 if (other.isEmpty()) { 746 return this.isEmpty(); 747 } 748 749 int thisCount = this.getNameCount(); 750 int otherCount = other.getNameCount(); 751 752 // given path has more elements that this path 753 if (otherCount > thisCount) { 754 return false; 755 } 756 757 // compare roots 758 if (other.root.length() > 0) { 759 if (otherCount < thisCount) 760 return false; 761 // FIXME: should compare in uppercase 762 if (!this.root.equalsIgnoreCase(other.root)) 763 return false; 764 } 765 766 // match last 'otherCount' elements 767 int off = thisCount - otherCount; 768 while (--otherCount >= 0) { 769 String thisElement = this.elementAsString(off + otherCount); 770 String otherElement = other.elementAsString(otherCount); 771 // FIXME: should compare in uppercase 772 if (!thisElement.equalsIgnoreCase(otherElement)) 773 return false; 774 } 775 return true; 776 } 777 778 @Override 779 public int compareTo(Path obj) { 780 if (obj == null) 781 throw new NullPointerException(); 782 String s1 = path; 783 String s2 = ((WindowsPath)obj).path; 784 int n1 = s1.length(); 785 int n2 = s2.length(); 786 int min = Math.min(n1, n2); 787 for (int i = 0; i < min; i++) { 788 char c1 = s1.charAt(i); 789 char c2 = s2.charAt(i); 790 if (c1 != c2) { 791 c1 = Character.toUpperCase(c1); 792 c2 = Character.toUpperCase(c2); 793 if (c1 != c2) { 794 return c1 - c2; 795 } 796 } 797 } 798 return n1 - n2; 799 } 800 801 @Override 802 public boolean equals(Object obj) { 803 if ((obj != null) && (obj instanceof WindowsPath)) { 804 return compareTo((Path)obj) == 0; 805 } 806 return false; 807 } 808 809 @Override 810 public int hashCode() { 811 // OK if two or more threads compute hash 812 int h = hash; 813 if (h == 0) { 814 for (int i = 0; i< path.length(); i++) { 815 h = 31*h + Character.toUpperCase(path.charAt(i)); 816 } 817 hash = h; 818 } 819 return h; 820 } 821 822 @Override 823 public String toString() { 824 return path; 825 } 826 827 // -- file operations -- 828 829 // package-private 830 long openForReadAttributeAccess(boolean followLinks) 831 throws WindowsException 832 { 833 int flags = FILE_FLAG_BACKUP_SEMANTICS; 834 if (!followLinks) 835 flags |= FILE_FLAG_OPEN_REPARSE_POINT; 836 return CreateFile(getPathForWin32Calls(), 837 FILE_READ_ATTRIBUTES, 838 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), 839 0L, 840 OPEN_EXISTING, 841 flags); 842 } 843 844 void checkRead() { 845 SecurityManager sm = System.getSecurityManager(); 846 if (sm != null) { 847 sm.checkRead(getPathForPermissionCheck()); 848 } 849 } 850 851 void checkWrite() { 852 SecurityManager sm = System.getSecurityManager(); 853 if (sm != null) { 854 sm.checkWrite(getPathForPermissionCheck()); 855 } 856 } 857 858 void checkDelete() { 859 SecurityManager sm = System.getSecurityManager(); 860 if (sm != null) { 861 sm.checkDelete(getPathForPermissionCheck()); 862 } 863 } 864 865 @Override 866 public URI toUri() { 867 return WindowsUriSupport.toUri(this); 868 } 869 870 @Override 871 public WindowsPath toAbsolutePath() { 872 if (isAbsolute()) 873 return this; 874 875 // permission check as per spec 876 SecurityManager sm = System.getSecurityManager(); 877 if (sm != null) { 878 sm.checkPropertyAccess("user.dir"); 879 } 880 881 try { 882 return createFromNormalizedPath(getFileSystem(), getAbsolutePath()); 883 } catch (WindowsException x) { 884 throw new IOError(new IOException(x.getMessage())); 885 } 886 } 887 888 @Override 889 public WindowsPath toRealPath(LinkOption... options) throws IOException { 890 checkRead(); 891 String rp = WindowsLinkSupport.getRealPath(this, Util.followLinks(options)); 892 return createFromNormalizedPath(getFileSystem(), rp); 893 } 894 895 @Override 896 public WatchKey register(WatchService watcher, 897 WatchEvent.Kind<?>[] events, 898 WatchEvent.Modifier... modifiers) 899 throws IOException 900 { 901 if (watcher == null) 902 throw new NullPointerException(); 903 if (!(watcher instanceof WindowsWatchService)) 904 throw new ProviderMismatchException(); 905 906 // When a security manager is set then we need to make a defensive 907 // copy of the modifiers and check for the Windows specific FILE_TREE 908 // modifier. When the modifier is present then check that permission 909 // has been granted recursively. 910 SecurityManager sm = System.getSecurityManager(); 911 if (sm != null) { 912 boolean watchSubtree = false; 913 final int ml = modifiers.length; 914 if (ml > 0) { 915 modifiers = Arrays.copyOf(modifiers, ml); 916 int i=0; 917 while (i < ml) { 918 if (ExtendedOptions.FILE_TREE.matches(modifiers[i++])) { 919 watchSubtree = true; 920 break; 921 } 922 } 923 } 924 String s = getPathForPermissionCheck(); 925 sm.checkRead(s); 926 if (watchSubtree) 927 sm.checkRead(s + "\\-"); 928 } 929 930 return ((WindowsWatchService)watcher).register(this, events, modifiers); 931 } 932 }