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;