| /* |
| * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.nio.fs; |
| |
| import java.nio.file.*; |
| import java.nio.file.attribute.*; |
| import java.io.*; |
| import java.net.URI; |
| import java.util.*; |
| import java.lang.ref.WeakReference; |
| |
| import static sun.nio.fs.WindowsNativeDispatcher.*; |
| import static sun.nio.fs.WindowsConstants.*; |
| |
| /** |
| * Windows implementation of Path |
| */ |
| |
| class WindowsPath implements Path { |
| |
| // The maximum path that does not require long path prefix. On Windows |
| // the maximum path is 260 minus 1 (NUL) but for directories it is 260 |
| // minus 12 minus 1 (to allow for the creation of a 8.3 file in the |
| // directory). |
| private static final int MAX_PATH = 247; |
| |
| // Maximum extended-length path |
| private static final int MAX_LONG_PATH = 32000; |
| |
| // FIXME - eliminate this reference to reduce space |
| private final WindowsFileSystem fs; |
| |
| // path type |
| private final WindowsPathType type; |
| // root component (may be empty) |
| private final String root; |
| // normalized path |
| private final String path; |
| |
| // the path to use in Win32 calls. This differs from path for relative |
| // paths and has a long path prefix for all paths longer than MAX_PATH. |
| private volatile WeakReference<String> pathForWin32Calls; |
| |
| // offsets into name components (computed lazily) |
| private volatile Integer[] offsets; |
| |
| // computed hash code (computed lazily, no need to be volatile) |
| private int hash; |
| |
| |
| /** |
| * Initializes a new instance of this class. |
| */ |
| private WindowsPath(WindowsFileSystem fs, |
| WindowsPathType type, |
| String root, |
| String path) |
| { |
| this.fs = fs; |
| this.type = type; |
| this.root = root; |
| this.path = path; |
| } |
| |
| /** |
| * Creates a Path by parsing the given path. |
| */ |
| static WindowsPath parse(WindowsFileSystem fs, String path) { |
| WindowsPathParser.Result result = WindowsPathParser.parse(path); |
| return new WindowsPath(fs, result.type(), result.root(), result.path()); |
| } |
| |
| /** |
| * Creates a Path from a given path that is known to be normalized. |
| */ |
| static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, |
| String path, |
| BasicFileAttributes attrs) |
| { |
| try { |
| WindowsPathParser.Result result = |
| WindowsPathParser.parseNormalizedPath(path); |
| if (attrs == null) { |
| return new WindowsPath(fs, |
| result.type(), |
| result.root(), |
| result.path()); |
| } else { |
| return new WindowsPathWithAttributes(fs, |
| result.type(), |
| result.root(), |
| result.path(), |
| attrs); |
| } |
| } catch (InvalidPathException x) { |
| throw new AssertionError(x.getMessage()); |
| } |
| } |
| |
| /** |
| * Creates a WindowsPath from a given path that is known to be normalized. |
| */ |
| static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, |
| String path) |
| { |
| return createFromNormalizedPath(fs, path, null); |
| } |
| |
| /** |
| * Special implementation with attached/cached attributes (used to quicken |
| * file tree traversal) |
| */ |
| private static class WindowsPathWithAttributes |
| extends WindowsPath implements BasicFileAttributesHolder |
| { |
| final WeakReference<BasicFileAttributes> ref; |
| |
| WindowsPathWithAttributes(WindowsFileSystem fs, |
| WindowsPathType type, |
| String root, |
| String path, |
| BasicFileAttributes attrs) |
| { |
| super(fs, type, root, path); |
| ref = new WeakReference<BasicFileAttributes>(attrs); |
| } |
| |
| @Override |
| public BasicFileAttributes get() { |
| return ref.get(); |
| } |
| |
| @Override |
| public void invalidate() { |
| ref.clear(); |
| } |
| |
| // no need to override equals/hashCode. |
| } |
| |
| // use this message when throwing exceptions |
| String getPathForExceptionMessage() { |
| return path; |
| } |
| |
| // use this path for permission checks |
| String getPathForPermissionCheck() { |
| return path; |
| } |
| |
| // use this path for Win32 calls |
| // This method will prefix long paths with \\?\ or \\?\UNC as required. |
| String getPathForWin32Calls() throws WindowsException { |
| // short absolute paths can be used directly |
| if (isAbsolute() && path.length() <= MAX_PATH) |
| return path; |
| |
| // return cached values if available |
| WeakReference<String> ref = pathForWin32Calls; |
| String resolved = (ref != null) ? ref.get() : null; |
| if (resolved != null) { |
| // Win32 path already available |
| return resolved; |
| } |
| |
| // resolve against default directory |
| resolved = getAbsolutePath(); |
| |
| // Long paths need to have "." and ".." removed and be prefixed with |
| // "\\?\". Note that it is okay to remove ".." even when it follows |
| // a link - for example, it is okay for foo/link/../bar to be changed |
| // to foo/bar. The reason is that Win32 APIs to access foo/link/../bar |
| // will access foo/bar anyway (which differs to Unix systems) |
| if (resolved.length() > MAX_PATH) { |
| if (resolved.length() > MAX_LONG_PATH) { |
| throw new WindowsException("Cannot access file with path exceeding " |
| + MAX_LONG_PATH + " characters"); |
| } |
| resolved = addPrefixIfNeeded(GetFullPathName(resolved)); |
| } |
| |
| // cache the resolved path (except drive relative paths as the working |
| // directory on removal media devices can change during the lifetime |
| // of the VM) |
| if (type != WindowsPathType.DRIVE_RELATIVE) { |
| synchronized (path) { |
| pathForWin32Calls = new WeakReference<String>(resolved); |
| } |
| } |
| return resolved; |
| } |
| |
| // return this path resolved against the file system's default directory |
| private String getAbsolutePath() throws WindowsException { |
| if (isAbsolute()) |
| return path; |
| |
| // Relative path ("foo" for example) |
| if (type == WindowsPathType.RELATIVE) { |
| String defaultDirectory = getFileSystem().defaultDirectory(); |
| if (isEmpty()) |
| return defaultDirectory; |
| if (defaultDirectory.endsWith("\\")) { |
| return defaultDirectory + path; |
| } else { |
| StringBuilder sb = |
| new StringBuilder(defaultDirectory.length() + path.length() + 1); |
| return sb.append(defaultDirectory).append('\\').append(path).toString(); |
| } |
| } |
| |
| // Directory relative path ("\foo" for example) |
| if (type == WindowsPathType.DIRECTORY_RELATIVE) { |
| String defaultRoot = getFileSystem().defaultRoot(); |
| return defaultRoot + path.substring(1); |
| } |
| |
| // Drive relative path ("C:foo" for example). |
| if (isSameDrive(root, getFileSystem().defaultRoot())) { |
| // relative to default directory |
| String remaining = path.substring(root.length()); |
| String defaultDirectory = getFileSystem().defaultDirectory(); |
| if (remaining.length() == 0) { |
| return defaultDirectory; |
| } else if (defaultDirectory.endsWith("\\")) { |
| return defaultDirectory + remaining; |
| } else { |
| return defaultDirectory + "\\" + remaining; |
| } |
| } else { |
| // relative to some other drive |
| String wd; |
| try { |
| int dt = GetDriveType(root + "\\"); |
| if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR) |
| throw new WindowsException(""); |
| wd = GetFullPathName(root + "."); |
| } catch (WindowsException x) { |
| throw new WindowsException("Unable to get working directory of drive '" + |
| Character.toUpperCase(root.charAt(0)) + "'"); |
| } |
| String result = wd; |
| if (wd.endsWith("\\")) { |
| result += path.substring(root.length()); |
| } else { |
| if (path.length() > root.length()) |
| result += "\\" + path.substring(root.length()); |
| } |
| return result; |
| } |
| } |
| |
| // returns true if same drive letter |
| private static boolean isSameDrive(String root1, String root2) { |
| return Character.toUpperCase(root1.charAt(0)) == |
| Character.toUpperCase(root2.charAt(0)); |
| } |
| |
| // Add long path prefix to path if required |
| static String addPrefixIfNeeded(String path) { |
| if (path.length() > MAX_PATH) { |
| if (path.startsWith("\\\\")) { |
| path = "\\\\?\\UNC" + path.substring(1, path.length()); |
| } else { |
| path = "\\\\?\\" + path; |
| } |
| } |
| return path; |
| } |
| |
| @Override |
| public WindowsFileSystem getFileSystem() { |
| return fs; |
| } |
| |
| // -- Path operations -- |
| |
| private boolean isEmpty() { |
| return path.length() == 0; |
| } |
| |
| private WindowsPath emptyPath() { |
| return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", ""); |
| } |
| |
| @Override |
| public Path getFileName() { |
| int len = path.length(); |
| // represents empty path |
| if (len == 0) |
| return this; |
| // represents root component only |
| if (root.length() == len) |
| return null; |
| int off = path.lastIndexOf('\\'); |
| if (off < root.length()) |
| off = root.length(); |
| else |
| off++; |
| return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", path.substring(off)); |
| } |
| |
| @Override |
| public WindowsPath getParent() { |
| // represents root component only |
| if (root.length() == path.length()) |
| return null; |
| int off = path.lastIndexOf('\\'); |
| if (off < root.length()) |
| return getRoot(); |
| else |
| return new WindowsPath(getFileSystem(), |
| type, |
| root, |
| path.substring(0, off)); |
| } |
| |
| @Override |
| public WindowsPath getRoot() { |
| if (root.length() == 0) |
| return null; |
| return new WindowsPath(getFileSystem(), type, root, root); |
| } |
| |
| // package-private |
| WindowsPathType type() { |
| return type; |
| } |
| |
| // package-private |
| boolean isUnc() { |
| return type == WindowsPathType.UNC; |
| } |
| |
| boolean needsSlashWhenResolving() { |
| if (path.endsWith("\\")) |
| return false; |
| return path.length() > root.length(); |
| } |
| |
| @Override |
| public boolean isAbsolute() { |
| return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC; |
| } |
| |
| static WindowsPath toWindowsPath(Path path) { |
| if (path == null) |
| throw new NullPointerException(); |
| if (!(path instanceof WindowsPath)) { |
| throw new ProviderMismatchException(); |
| } |
| return (WindowsPath)path; |
| } |
| |
| // return true if this path has "." or ".." |
| private boolean hasDotOrDotDot() { |
| int n = getNameCount(); |
| for (int i=0; i<n; i++) { |
| String name = elementAsString(i); |
| if (name.length() == 1 && name.charAt(0) == '.') |
| return true; |
| if (name.length() == 2 |
| && name.charAt(0) == '.' && name.charAt(1) == '.') |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public WindowsPath relativize(Path obj) { |
| WindowsPath child = toWindowsPath(obj); |
| if (this.equals(child)) |
| return emptyPath(); |
| |
| // can only relativize paths of the same type |
| if (this.type != child.type) |
| throw new IllegalArgumentException("'other' is different type of Path"); |
| |
| // can only relativize paths if root component matches |
| if (!this.root.equalsIgnoreCase(child.root)) |
| throw new IllegalArgumentException("'other' has different root"); |
| |
| // this path is the empty path |
| if (this.isEmpty()) |
| return child; |
| |
| |
| WindowsPath base = this; |
| if (base.hasDotOrDotDot() || child.hasDotOrDotDot()) { |
| base = base.normalize(); |
| child = child.normalize(); |
| } |
| |
| int baseCount = base.getNameCount(); |
| int childCount = child.getNameCount(); |
| |
| // skip matching names |
| int n = Math.min(baseCount, childCount); |
| int i = 0; |
| while (i < n) { |
| if (!base.getName(i).equals(child.getName(i))) |
| break; |
| i++; |
| } |
| |
| // remaining elements in child |
| WindowsPath childRemaining; |
| boolean isChildEmpty; |
| if (i == childCount) { |
| childRemaining = emptyPath(); |
| isChildEmpty = true; |
| } else { |
| childRemaining = child.subpath(i, childCount); |
| isChildEmpty = childRemaining.isEmpty(); |
| } |
| |
| // matched all of base |
| if (i == baseCount) { |
| return childRemaining; |
| } |
| |
| // the remainder of base cannot contain ".." |
| WindowsPath baseRemaining = base.subpath(i, baseCount); |
| if (baseRemaining.hasDotOrDotDot()) { |
| throw new IllegalArgumentException("Unable to compute relative " |
| + " path from " + this + " to " + obj); |
| } |
| if (baseRemaining.isEmpty()) |
| return childRemaining; |
| |
| // number of ".." needed |
| int dotdots = baseRemaining.getNameCount(); |
| if (dotdots == 0) { |
| return childRemaining; |
| } |
| |
| StringBuilder result = new StringBuilder(); |
| for (int j=0; j<dotdots; j++) { |
| result.append("..\\"); |
| } |
| |
| // append remaining names in child |
| if (!isChildEmpty) { |
| for (int j=0; j<childRemaining.getNameCount(); j++) { |
| result.append(childRemaining.getName(j).toString()); |
| result.append("\\"); |
| } |
| } |
| |
| // drop trailing slash |
| result.setLength(result.length()-1); |
| return createFromNormalizedPath(getFileSystem(), result.toString()); |
| } |
| |
| @Override |
| public WindowsPath normalize() { |
| final int count = getNameCount(); |
| if (count == 0 || isEmpty()) |
| return this; |
| |
| boolean[] ignore = new boolean[count]; // true => ignore name |
| int remaining = count; // number of names remaining |
| |
| // multiple passes to eliminate all occurrences of "." and "name/.." |
| int prevRemaining; |
| do { |
| prevRemaining = remaining; |
| int prevName = -1; |
| for (int i=0; i<count; i++) { |
| if (ignore[i]) |
| continue; |
| |
| String name = elementAsString(i); |
| |
| // not "." or ".." |
| if (name.length() > 2) { |
| prevName = i; |
| continue; |
| } |
| |
| // "." or something else |
| if (name.length() == 1) { |
| // ignore "." |
| if (name.charAt(0) == '.') { |
| ignore[i] = true; |
| remaining--; |
| } else { |
| prevName = i; |
| } |
| continue; |
| } |
| |
| // not ".." |
| if (name.charAt(0) != '.' || name.charAt(1) != '.') { |
| prevName = i; |
| continue; |
| } |
| |
| // ".." found |
| if (prevName >= 0) { |
| // name/<ignored>/.. found so mark name and ".." to be |
| // ignored |
| ignore[prevName] = true; |
| ignore[i] = true; |
| remaining = remaining - 2; |
| prevName = -1; |
| } else { |
| // Cases: |
| // C:\<ignored>\.. |
| // \\server\\share\<ignored>\.. |
| // \<ignored>.. |
| if (isAbsolute() || type == WindowsPathType.DIRECTORY_RELATIVE) { |
| boolean hasPrevious = false; |
| for (int j=0; j<i; j++) { |
| if (!ignore[j]) { |
| hasPrevious = true; |
| break; |
| } |
| } |
| if (!hasPrevious) { |
| // all proceeding names are ignored |
| ignore[i] = true; |
| remaining--; |
| } |
| } |
| } |
| } |
| } while (prevRemaining > remaining); |
| |
| // no redundant names |
| if (remaining == count) |
| return this; |
| |
| // corner case - all names removed |
| if (remaining == 0) { |
| return (root.length() == 0) ? emptyPath() : getRoot(); |
| } |
| |
| // re-constitute the path from the remaining names. |
| StringBuilder result = new StringBuilder(); |
| if (root != null) |
| result.append(root); |
| for (int i=0; i<count; i++) { |
| if (!ignore[i]) { |
| result.append(getName(i)); |
| result.append("\\"); |
| } |
| } |
| |
| // drop trailing slash in result |
| result.setLength(result.length()-1); |
| return createFromNormalizedPath(getFileSystem(), result.toString()); |
| } |
| |
| @Override |
| public WindowsPath resolve(Path obj) { |
| WindowsPath other = toWindowsPath(obj); |
| if (other.isEmpty()) |
| return this; |
| if (other.isAbsolute()) |
| return other; |
| |
| switch (other.type) { |
| case RELATIVE: { |
| String result; |
| if (path.endsWith("\\") || (root.length() == path.length())) { |
| result = path + other.path; |
| } else { |
| result = path + "\\" + other.path; |
| } |
| return new WindowsPath(getFileSystem(), type, root, result); |
| } |
| |
| case DIRECTORY_RELATIVE: { |
| String result; |
| if (root.endsWith("\\")) { |
| result = root + other.path.substring(1); |
| } else { |
| result = root + other.path; |
| } |
| return createFromNormalizedPath(getFileSystem(), result); |
| } |
| |
| case DRIVE_RELATIVE: { |
| if (!root.endsWith("\\")) |
| return other; |
| // if different roots then return other |
| String thisRoot = root.substring(0, root.length()-1); |
| if (!thisRoot.equalsIgnoreCase(other.root)) |
| return other; |
| // same roots |
| String remaining = other.path.substring(other.root.length()); |
| String result; |
| if (path.endsWith("\\")) { |
| result = path + remaining; |
| } else { |
| result = path + "\\" + remaining; |
| } |
| return createFromNormalizedPath(getFileSystem(), result); |
| } |
| |
| default: |
| throw new AssertionError(); |
| } |
| } |
| |
| // generate offset array |
| private void initOffsets() { |
| if (offsets == null) { |
| ArrayList<Integer> list = new ArrayList<>(); |
| if (isEmpty()) { |
| // empty path considered to have one name element |
| list.add(0); |
| } else { |
| int start = root.length(); |
| int off = root.length(); |
| while (off < path.length()) { |
| if (path.charAt(off) != '\\') { |
| off++; |
| } else { |
| list.add(start); |
| start = ++off; |
| } |
| } |
| if (start != off) |
| list.add(start); |
| } |
| synchronized (this) { |
| if (offsets == null) |
| offsets = list.toArray(new Integer[list.size()]); |
| } |
| } |
| } |
| |
| @Override |
| public int getNameCount() { |
| initOffsets(); |
| return offsets.length; |
| } |
| |
| private String elementAsString(int i) { |
| initOffsets(); |
| if (i == (offsets.length-1)) |
| return path.substring(offsets[i]); |
| return path.substring(offsets[i], offsets[i+1]-1); |
| } |
| |
| @Override |
| public WindowsPath getName(int index) { |
| initOffsets(); |
| if (index < 0 || index >= offsets.length) |
| throw new IllegalArgumentException(); |
| return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", elementAsString(index)); |
| } |
| |
| @Override |
| public WindowsPath subpath(int beginIndex, int endIndex) { |
| initOffsets(); |
| if (beginIndex < 0) |
| throw new IllegalArgumentException(); |
| if (beginIndex >= offsets.length) |
| throw new IllegalArgumentException(); |
| if (endIndex > offsets.length) |
| throw new IllegalArgumentException(); |
| if (beginIndex >= endIndex) |
| throw new IllegalArgumentException(); |
| |
| StringBuilder sb = new StringBuilder(); |
| Integer[] nelems = new Integer[endIndex - beginIndex]; |
| for (int i = beginIndex; i < endIndex; i++) { |
| nelems[i-beginIndex] = sb.length(); |
| sb.append(elementAsString(i)); |
| if (i != (endIndex-1)) |
| sb.append("\\"); |
| } |
| return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", sb.toString()); |
| } |
| |
| @Override |
| public boolean startsWith(Path obj) { |
| if (!(Objects.requireNonNull(obj) instanceof WindowsPath)) |
| return false; |
| WindowsPath other = (WindowsPath)obj; |
| |
| // if this path has a root component the given path's root must match |
| if (!this.root.equalsIgnoreCase(other.root)) { |
| return false; |
| } |
| |
| // empty path starts with itself |
| if (other.isEmpty()) |
| return this.isEmpty(); |
| |
| // roots match so compare elements |
| int thisCount = getNameCount(); |
| int otherCount = other.getNameCount(); |
| if (otherCount <= thisCount) { |
| while (--otherCount >= 0) { |
| String thisElement = this.elementAsString(otherCount); |
| String otherElement = other.elementAsString(otherCount); |
| // FIXME: should compare in uppercase |
| if (!thisElement.equalsIgnoreCase(otherElement)) |
| return false; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean endsWith(Path obj) { |
| if (!(Objects.requireNonNull(obj) instanceof WindowsPath)) |
| return false; |
| WindowsPath other = (WindowsPath)obj; |
| |
| // other path is longer |
| if (other.path.length() > this.path.length()) { |
| return false; |
| } |
| |
| // empty path ends in itself |
| if (other.isEmpty()) { |
| return this.isEmpty(); |
| } |
| |
| int thisCount = this.getNameCount(); |
| int otherCount = other.getNameCount(); |
| |
| // given path has more elements that this path |
| if (otherCount > thisCount) { |
| return false; |
| } |
| |
| // compare roots |
| if (other.root.length() > 0) { |
| if (otherCount < thisCount) |
| return false; |
| // FIXME: should compare in uppercase |
| if (!this.root.equalsIgnoreCase(other.root)) |
| return false; |
| } |
| |
| // match last 'otherCount' elements |
| int off = thisCount - otherCount; |
| while (--otherCount >= 0) { |
| String thisElement = this.elementAsString(off + otherCount); |
| String otherElement = other.elementAsString(otherCount); |
| // FIXME: should compare in uppercase |
| if (!thisElement.equalsIgnoreCase(otherElement)) |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public int compareTo(Path obj) { |
| if (obj == null) |
| throw new NullPointerException(); |
| String s1 = path; |
| String s2 = ((WindowsPath)obj).path; |
| int n1 = s1.length(); |
| int n2 = s2.length(); |
| int min = Math.min(n1, n2); |
| for (int i = 0; i < min; i++) { |
| char c1 = s1.charAt(i); |
| char c2 = s2.charAt(i); |
| if (c1 != c2) { |
| c1 = Character.toUpperCase(c1); |
| c2 = Character.toUpperCase(c2); |
| if (c1 != c2) { |
| return c1 - c2; |
| } |
| } |
| } |
| return n1 - n2; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if ((obj != null) && (obj instanceof WindowsPath)) { |
| return compareTo((Path)obj) == 0; |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| // OK if two or more threads compute hash |
| int h = hash; |
| if (h == 0) { |
| for (int i = 0; i< path.length(); i++) { |
| h = 31*h + Character.toUpperCase(path.charAt(i)); |
| } |
| hash = h; |
| } |
| return h; |
| } |
| |
| @Override |
| public String toString() { |
| return path; |
| } |
| |
| // -- file operations -- |
| |
| // package-private |
| long openForReadAttributeAccess(boolean followLinks) |
| throws WindowsException |
| { |
| int flags = FILE_FLAG_BACKUP_SEMANTICS; |
| if (!followLinks) |
| flags |= FILE_FLAG_OPEN_REPARSE_POINT; |
| return CreateFile(getPathForWin32Calls(), |
| FILE_READ_ATTRIBUTES, |
| (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), |
| 0L, |
| OPEN_EXISTING, |
| flags); |
| } |
| |
| void checkRead() { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkRead(getPathForPermissionCheck()); |
| } |
| } |
| |
| void checkWrite() { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkWrite(getPathForPermissionCheck()); |
| } |
| } |
| |
| void checkDelete() { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkDelete(getPathForPermissionCheck()); |
| } |
| } |
| |
| @Override |
| public URI toUri() { |
| return WindowsUriSupport.toUri(this); |
| } |
| |
| @Override |
| public WindowsPath toAbsolutePath() { |
| if (isAbsolute()) |
| return this; |
| |
| // permission check as per spec |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkPropertyAccess("user.dir"); |
| } |
| |
| try { |
| return createFromNormalizedPath(getFileSystem(), getAbsolutePath()); |
| } catch (WindowsException x) { |
| throw new IOError(new IOException(x.getMessage())); |
| } |
| } |
| |
| @Override |
| public WindowsPath toRealPath(LinkOption... options) throws IOException { |
| checkRead(); |
| String rp = WindowsLinkSupport.getRealPath(this, Util.followLinks(options)); |
| return createFromNormalizedPath(getFileSystem(), rp); |
| } |
| |
| @Override |
| public WatchKey register(WatchService watcher, |
| WatchEvent.Kind<?>[] events, |
| WatchEvent.Modifier... modifiers) |
| throws IOException |
| { |
| if (watcher == null) |
| throw new NullPointerException(); |
| if (!(watcher instanceof WindowsWatchService)) |
| throw new ProviderMismatchException(); |
| |
| // When a security manager is set then we need to make a defensive |
| // copy of the modifiers and check for the Windows specific FILE_TREE |
| // modifier. When the modifier is present then check that permission |
| // has been granted recursively. |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| boolean watchSubtree = false; |
| final int ml = modifiers.length; |
| if (ml > 0) { |
| modifiers = Arrays.copyOf(modifiers, ml); |
| int i=0; |
| while (i < ml) { |
| if (ExtendedOptions.FILE_TREE.matches(modifiers[i++])) { |
| watchSubtree = true; |
| break; |
| } |
| } |
| } |
| String s = getPathForPermissionCheck(); |
| sm.checkRead(s); |
| if (watchSubtree) |
| sm.checkRead(s + "\\-"); |
| } |
| |
| return ((WindowsWatchService)watcher).register(this, events, modifiers); |
| } |
| } |