src/windows/classes/java/io/WinNTFileSystem.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2001, 2012, 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
--- 1,7 ----
/*
! * Copyright (c) 2001, 2013, 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
*** 72,208 ****
@Override
public char getPathSeparator() {
return semicolon;
}
! /* Check that the given pathname is normal. If not, invoke the real
! normalizer on the part of the pathname that requires normalization.
! This way we iterate through the whole pathname string only once. */
@Override
public String normalize(String path) {
! int n = path.length();
! char slash = this.slash;
! char altSlash = this.altSlash;
char prev = 0;
! for (int i = 0; i < n; i++) {
char c = path.charAt(i);
! if (c == altSlash)
! return normalize(path, n, (prev == slash) ? i - 1 : i);
! if ((c == slash) && (prev == slash) && (i > 1))
! return normalize(path, n, i - 1);
! if ((c == ':') && (i > 1))
! return normalize(path, n, 0);
prev = c;
}
! if (prev == slash) return normalize(path, n, n - 1);
! return path;
}
! /* Normalize the given pathname, whose length is len, starting at the given
! offset; everything before this offset is already normal. */
! private String normalize(String path, int len, int off) {
! if (len == 0) return path;
! if (off < 3) off = 0; /* Avoid fencepost cases with UNC pathnames */
! int src;
! char slash = this.slash;
! StringBuffer sb = new StringBuffer(len);
! if (off == 0) {
/* Complete normalization, including prefix */
! src = normalizePrefix(path, len, sb);
! } else {
! /* Partial normalization */
! src = off;
! sb.append(path.substring(0, off));
}
! /* Remove redundant slashes from the remainder of the path, forcing all
slashes into the preferred slash */
while (src < len) {
! char c = path.charAt(src++);
if (isSlash(c)) {
! while ((src < len) && isSlash(path.charAt(src))) src++;
! if (src == len) {
! /* Check for trailing separator */
! int sn = sb.length();
! if ((sn == 2) && (sb.charAt(1) == ':')) {
! /* "z:\\" */
! sb.append(slash);
! break;
}
! if (sn == 0) {
! /* "\\" */
! sb.append(slash);
! break;
! }
! if ((sn == 1) && (isSlash(sb.charAt(0)))) {
! /* "\\\\" is not collapsed to "\\" because "\\\\" marks
! the beginning of a UNC pathname. Even though it is
! not, by itself, a valid UNC pathname, we leave it as
! is in order to be consistent with the win32 APIs,
! which treat this case as an invalid UNC pathname
! rather than as an alias for the root directory of
! the current drive. */
! sb.append(slash);
! break;
! }
! /* Path does not denote a root directory, so do not append
! trailing slash */
! break;
! } else {
! sb.append(slash);
! }
! } else {
sb.append(c);
}
}
! String rv = sb.toString();
! return rv;
}
/* A normal Win32 pathname contains no duplicate slashes, except possibly
for a UNC prefix, and does not end with a slash. It may be the empty
! string. Normalized Win32 pathnames have the convenient property that
the length of the prefix almost uniquely identifies the type of the path
and whether it is absolute or relative:
0 relative to both drive and directory
1 drive-relative (begins with '\\')
2 absolute UNC (if first char is '\\'),
else directory-relative (has form "z:foo")
3 absolute local pathname (begins with "z:\\")
*/
! private int normalizePrefix(String path, int len, StringBuffer sb) {
! int src = 0;
! while ((src < len) && isSlash(path.charAt(src))) src++;
char c;
! if ((len - src >= 2)
! && isLetter(c = path.charAt(src))
! && path.charAt(src + 1) == ':') {
/* Remove leading slashes if followed by drive specifier.
This hack is necessary to support file URLs containing drive
specifiers (e.g., "file://c:/path"). As a side effect,
"/c:/path" can be used as an alternative to "c:/path". */
sb.append(c);
sb.append(':');
! src += 2;
! } else {
! src = 0;
! if ((len >= 2)
! && isSlash(path.charAt(0))
! && isSlash(path.charAt(1))) {
/* UNC pathname: Retain first slash; leave src pointed at
second slash so that further slashes will be collapsed
into the second slash. The result will be a pathname
beginning with "\\\\" followed (most likely) by a host
name. */
- src = 1;
sb.append(slash);
}
}
! return src;
}
@Override
public int prefixLength(String path) {
char slash = this.slash;
--- 72,242 ----
@Override
public char getPathSeparator() {
return semicolon;
}
! /*
! * Check whether the given path name is normal. If not, invoke the real
! * normalizer on the part of the path name that requires normalization.
! * The following logic iterates the whole path name string only once.
! */
@Override
public String normalize(String path) {
! final int len = path.length();
! if (len == 0) return path;
!
! StringBuilder sb = new StringBuilder(len);
! int sbLen = 0;
char prev = 0;
! int prevIdx = -1;
!
! for (int i = 0; i < len; i++) {
char c = path.charAt(i);
! if (c == CHAR_NUL) continue;
!
! // Force to the preferred slash
! if (c == altSlash) c = slash;
!
! sbLen = sb.length();
! if ((c == slash) && (prev == slash) && (sbLen > 1)) {
! sb.setLength(sbLen - 1);
! return normalize(path, prevIdx, sb);
! }
!
! // If a path starts with a disk designator, like "c:", no
! // normalization is needed. But if a disk designator is not at
! // the beginning, normalization will be triggered to normalize
! // the prefix. StringBuilder, sb, will be cleared in the real
! // normalizer.
! if ((c == ':') && isLetter(prev) && (sbLen > 1))
! return normalize(path, 0, sb);
!
! sb.append(c);
prev = c;
+ prevIdx = i;
}
!
! sbLen = sb.length();
! if (prev == slash && sbLen > 1) {
! sb.setLength(sbLen - 1);
! return normalize(path, prevIdx, sb);
}
! return sb.toString();
! }
! /*
! * Normalize a path name, starting at the given offset.
! * Everything before this offset is already normal.
! */
! private String normalize(String path, int off, StringBuilder sb) {
! final int len = path.length();
! /* Avoid fencepost cases with UNC pathnames */
! int src = sb.length() < 3 ? 0 : off;
!
! if (src == 0) {
/* Complete normalization, including prefix */
! sb.setLength(0);
! src = normalizePrefix(path, sb);
}
! /* Partial normalization
! Remove redundant slashes from the remainder of the path, and force all
slashes into the preferred slash */
+ char prev = 0;
+ char c;
while (src < len) {
! c = path.charAt(src++);
! if (c == CHAR_NUL) continue;
if (isSlash(c)) {
! if (prev == slash)
! continue;
! else if (c == altSlash)
! c = slash;
}
!
sb.append(c);
+ prev = c;
+ }
+
+ /* Handle the trailing slash
+ * Note, "\\\\" is not collapsed to "\\" because "\\\\" marks the
+ * beginning of a UNC pathname. Even though it is not, by itself, a
+ * valid UNC pathname, we leave it as is in order to be consistent with
+ * the win32 APIs, which treat this case as an invalid UNC pathname
+ * rather than as an alias for the root directory of the current drive.
+ */
+ if (prev == slash) {
+ int sbLen = sb.length();
+ if (!(sbLen == 1 ||
+ (sbLen == 2 && sb.charAt(0) == slash) ||
+ (sbLen == 3 && isLetter(sb.charAt(0)) && sb.charAt(1) == ':')))
+ {
+ sb.setLength(sbLen - 1);
}
}
! return sb.toString();
}
/* A normal Win32 pathname contains no duplicate slashes, except possibly
for a UNC prefix, and does not end with a slash. It may be the empty
! string. Normalized Win32 path names have the convenient property that
the length of the prefix almost uniquely identifies the type of the path
and whether it is absolute or relative:
0 relative to both drive and directory
1 drive-relative (begins with '\\')
2 absolute UNC (if first char is '\\'),
else directory-relative (has form "z:foo")
3 absolute local pathname (begins with "z:\\")
*/
! private int normalizePrefix(String path, StringBuilder sb) {
! final int len = path.length();
! // Remove leading NUL chars
! int start = -1;
! while (++start < len && path.charAt(start) == CHAR_NUL);
!
! // Normalize disk designator preifx
! int src = start;
! // Remove slashes and NUL chars
! while (src < len &&
! (isSlash(path.charAt(src)) || path.charAt(src) == CHAR_NUL))
! {
! src++;
! }
!
char c;
! if ((len - src >= 2) && isLetter(c = path.charAt(src))) {
! // Find the next non-NUL char
! while (++src < len && path.charAt(src) == CHAR_NUL);
! if (src < len && path.charAt(src) == ':') {
/* Remove leading slashes if followed by drive specifier.
This hack is necessary to support file URLs containing drive
specifiers (e.g., "file://c:/path"). As a side effect,
"/c:/path" can be used as an alternative to "c:/path". */
sb.append(c);
sb.append(':');
! return src + 1;
! }
! }
!
! // Normalize UNC prefix
! src = start;
! if ((len - src >= 2) && isSlash(path.charAt(src))) {
! while (++src < len && path.charAt(src) == CHAR_NUL);
! if (src < len && isSlash(path.charAt(src))) {
/* UNC pathname: Retain first slash; leave src pointed at
second slash so that further slashes will be collapsed
into the second slash. The result will be a pathname
beginning with "\\\\" followed (most likely) by a host
name. */
sb.append(slash);
+ return src;
}
}
! return start;
}
@Override
public int prefixLength(String path) {
char slash = this.slash;