src/windows/classes/java/io/WinNTFileSystem.java

Print this page


   1 /*
   2  * Copyright (c) 2001, 2012, 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


  57         return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
  58     }
  59 
  60     private String slashify(String p) {
  61         if ((p.length() > 0) && (p.charAt(0) != slash)) return slash + p;
  62         else return p;
  63     }
  64 
  65     /* -- Normalization and construction -- */
  66 
  67     @Override
  68     public char getSeparator() {
  69         return slash;
  70     }
  71 
  72     @Override
  73     public char getPathSeparator() {
  74         return semicolon;
  75     }
  76 
  77     /* Check that the given pathname is normal.  If not, invoke the real
  78        normalizer on the part of the pathname that requires normalization.
  79        This way we iterate through the whole pathname string only once. */


  80     @Override
  81     public String normalize(String path) {
  82         int n = path.length();
  83         char slash = this.slash;
  84         char altSlash = this.altSlash;


  85         char prev = 0;
  86         for (int i = 0; i < n; i++) {


  87             char c = path.charAt(i);
  88             if (c == altSlash)
  89                 return normalize(path, n, (prev == slash) ? i - 1 : i);
  90             if ((c == slash) && (prev == slash) && (i > 1))
  91                 return normalize(path, n, i - 1);
  92             if ((c == ':') && (i > 1))
  93                 return normalize(path, n, 0);














  94             prev = c;

  95         }
  96         if (prev == slash) return normalize(path, n, n - 1);
  97         return path;



  98     }
  99 
 100     /* Normalize the given pathname, whose length is len, starting at the given
 101        offset; everything before this offset is already normal. */
 102     private String normalize(String path, int len, int off) {
 103         if (len == 0) return path;
 104         if (off < 3) off = 0;   /* Avoid fencepost cases with UNC pathnames */
 105         int src;
 106         char slash = this.slash;
 107         StringBuffer sb = new StringBuffer(len);



 108 
 109         if (off == 0) {
 110             /* Complete normalization, including prefix */
 111             src = normalizePrefix(path, len, sb);
 112         } else {
 113             /* Partial normalization */
 114             src = off;
 115             sb.append(path.substring(0, off));
 116         }
 117 
 118         /* Remove redundant slashes from the remainder of the path, forcing all

 119            slashes into the preferred slash */


 120         while (src < len) {
 121             char c = path.charAt(src++);

 122             if (isSlash(c)) {
 123                 while ((src < len) && isSlash(path.charAt(src))) src++;
 124                 if (src == len) {
 125                     /* Check for trailing separator */
 126                     int sn = sb.length();
 127                     if ((sn == 2) && (sb.charAt(1) == ':')) {
 128                         /* "z:\\" */
 129                         sb.append(slash);
 130                         break;
 131                     }
 132                     if (sn == 0) {
 133                         /* "\\" */
 134                         sb.append(slash);
 135                         break;
 136                     }
 137                     if ((sn == 1) && (isSlash(sb.charAt(0)))) {
 138                         /* "\\\\" is not collapsed to "\\" because "\\\\" marks
 139                            the beginning of a UNC pathname.  Even though it is
 140                            not, by itself, a valid UNC pathname, we leave it as
 141                            is in order to be consistent with the win32 APIs,
 142                            which treat this case as an invalid UNC pathname
 143                            rather than as an alias for the root directory of
 144                            the current drive. */
 145                         sb.append(slash);
 146                         break;
 147                     }
 148                     /* Path does not denote a root directory, so do not append
 149                        trailing slash */
 150                     break;
 151                 } else {
 152                     sb.append(slash);
 153                 }
 154             } else {
 155                 sb.append(c);

















 156             }
 157         }
 158 
 159         String rv = sb.toString();
 160         return rv;
 161     }
 162 
 163     /* A normal Win32 pathname contains no duplicate slashes, except possibly
 164        for a UNC prefix, and does not end with a slash.  It may be the empty
 165        string.  Normalized Win32 pathnames have the convenient property that
 166        the length of the prefix almost uniquely identifies the type of the path
 167        and whether it is absolute or relative:
 168 
 169            0  relative to both drive and directory
 170            1  drive-relative (begins with '\\')
 171            2  absolute UNC (if first char is '\\'),
 172                 else directory-relative (has form "z:foo")
 173            3  absolute local pathname (begins with "z:\\")
 174      */
 175     private int normalizePrefix(String path, int len, StringBuffer sb) {
 176         int src = 0;
 177         while ((src < len) && isSlash(path.charAt(src))) src++;












 178         char c;
 179         if ((len - src >= 2)
 180             && isLetter(c = path.charAt(src))
 181             && path.charAt(src + 1) == ':') {

 182             /* Remove leading slashes if followed by drive specifier.
 183                This hack is necessary to support file URLs containing drive
 184                specifiers (e.g., "file://c:/path").  As a side effect,
 185                "/c:/path" can be used as an alternative to "c:/path". */
 186             sb.append(c);
 187             sb.append(':');
 188             src += 2;
 189         } else {
 190             src = 0;
 191             if ((len >= 2)
 192                 && isSlash(path.charAt(0))
 193                 && isSlash(path.charAt(1))) {



 194                 /* UNC pathname: Retain first slash; leave src pointed at
 195                    second slash so that further slashes will be collapsed
 196                    into the second slash.  The result will be a pathname
 197                    beginning with "\\\\" followed (most likely) by a host
 198                    name. */
 199                 src = 1;
 200                 sb.append(slash);

 201             }
 202         }
 203         return src;
 204     }
 205 
 206     @Override
 207     public int prefixLength(String path) {
 208         char slash = this.slash;
 209         int n = path.length();
 210         if (n == 0) return 0;
 211         char c0 = path.charAt(0);
 212         char c1 = (n > 1) ? path.charAt(1) : 0;
 213         if (c0 == slash) {
 214             if (c1 == slash) return 2;  /* Absolute UNC pathname "\\\\foo" */
 215             return 1;                   /* Drive-relative "\\foo" */
 216         }
 217         if (isLetter(c0) && (c1 == ':')) {
 218             if ((n > 2) && (path.charAt(2) == slash))
 219                 return 3;               /* Absolute local pathname "z:\\foo" */
 220             return 2;                   /* Directory-relative "z:foo" */
 221         }
 222         return 0;                       /* Completely relative */
 223     }


   1 /*
   2  * Copyright (c) 2001, 2013, 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


  57         return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
  58     }
  59 
  60     private String slashify(String p) {
  61         if ((p.length() > 0) && (p.charAt(0) != slash)) return slash + p;
  62         else return p;
  63     }
  64 
  65     /* -- Normalization and construction -- */
  66 
  67     @Override
  68     public char getSeparator() {
  69         return slash;
  70     }
  71 
  72     @Override
  73     public char getPathSeparator() {
  74         return semicolon;
  75     }
  76 
  77     /*
  78      * Check whether the given path name is normal.  If not, invoke the real
  79      * normalizer on the part of the path name that requires normalization.
  80      * The following logic iterates the whole path name string only once.
  81      */
  82     @Override
  83     public String normalize(String path) {
  84         final int len = path.length();
  85         if (len == 0) return path;
  86 
  87         StringBuilder sb = new StringBuilder(len);
  88         int sbLen = 0;
  89         char prev = 0;
  90         int prevIdx = -1;
  91 
  92         for (int i = 0; i < len; i++) {
  93             char c = path.charAt(i);
  94             if (c == CHAR_NUL) continue;
  95 
  96             // Force to the preferred slash
  97             if (c == altSlash) c = slash;
  98 
  99             sbLen = sb.length();
 100             if ((c == slash) && (prev == slash) && (sbLen > 1)) {
 101                 sb.setLength(sbLen - 1);
 102                 return normalize(path, prevIdx, sb);
 103             }
 104 
 105             // If a path starts with a disk designator, like "c:", no
 106             // normalization is needed. But if a disk designator is not at
 107             // the beginning, normalization will be triggered to normalize
 108             // the prefix. StringBuilder, sb, will be cleared in the real
 109             // normalizer.
 110             if ((c == ':') && isLetter(prev) && (sbLen > 1))
 111                 return normalize(path, 0, sb);
 112 
 113             sb.append(c);
 114             prev = c;
 115             prevIdx = i;
 116         }
 117 
 118         sbLen = sb.length();
 119         if (prev == slash && sbLen > 1) {
 120             sb.setLength(sbLen - 1);
 121             return normalize(path, prevIdx, sb);
 122         }
 123 
 124         return sb.toString();
 125     }
 126 
 127     /*
 128      * Normalize a path name, starting at the given offset.
 129      * Everything before this offset is already normal.
 130      */
 131     private String normalize(String path, int off, StringBuilder sb) {
 132         final int len = path.length();
 133         /* Avoid fencepost cases with UNC pathnames */
 134         int src = sb.length() < 3 ? 0 : off;
 135 
 136         if (src == 0) {
 137             /* Complete normalization, including prefix */
 138             sb.setLength(0);
 139             src = normalizePrefix(path, sb);



 140         }
 141 
 142         /* Partial normalization
 143            Remove redundant slashes from the remainder of the path, and force all
 144            slashes into the preferred slash */
 145         char prev = 0;
 146         char c;
 147         while (src < len) {
 148             c = path.charAt(src++);
 149             if (c == CHAR_NUL) continue;
 150             if (isSlash(c)) {
 151                 if (prev == slash)
 152                     continue;
 153                 else if (c == altSlash)
 154                     c = slash;


























 155             }
 156 
 157             sb.append(c);
 158             prev = c;
 159         }
 160 
 161         /* Handle the trailing slash
 162          * Note, "\\\\" is not collapsed to "\\" because "\\\\" marks the
 163          * beginning of a UNC pathname.  Even though it is not, by itself, a
 164          * valid UNC pathname, we leave it as is in order to be consistent with
 165          * the win32 APIs, which treat this case as an invalid UNC pathname
 166          * rather than as an alias for the root directory of the current drive.
 167          */
 168         if (prev == slash) {
 169             int sbLen = sb.length();
 170             if (!(sbLen == 1 ||
 171                  (sbLen == 2 && sb.charAt(0) == slash) ||
 172                  (sbLen == 3 && isLetter(sb.charAt(0)) && sb.charAt(1) == ':')))
 173             {
 174                 sb.setLength(sbLen - 1);
 175             }
 176         }
 177 
 178         return sb.toString();

 179     }
 180 
 181     /* A normal Win32 pathname contains no duplicate slashes, except possibly
 182        for a UNC prefix, and does not end with a slash.  It may be the empty
 183        string.  Normalized Win32 path names have the convenient property that
 184        the length of the prefix almost uniquely identifies the type of the path
 185        and whether it is absolute or relative:
 186 
 187            0  relative to both drive and directory
 188            1  drive-relative (begins with '\\')
 189            2  absolute UNC (if first char is '\\'),
 190                 else directory-relative (has form "z:foo")
 191            3  absolute local pathname (begins with "z:\\")
 192      */
 193     private int normalizePrefix(String path, StringBuilder sb) {
 194         final int len = path.length();
 195         // Remove leading NUL chars
 196         int start = -1;
 197         while (++start < len && path.charAt(start) == CHAR_NUL);
 198 
 199         // Normalize disk designator preifx
 200         int src = start;
 201         // Remove slashes and NUL chars
 202         while (src < len &&
 203                 (isSlash(path.charAt(src)) || path.charAt(src) == CHAR_NUL))
 204         {
 205             src++;
 206         }
 207 
 208         char c;
 209         if ((len - src >= 2) && isLetter(c = path.charAt(src))) {
 210             // Find the next non-NUL char
 211             while (++src < len && path.charAt(src) == CHAR_NUL);
 212             if (src < len && path.charAt(src) == ':') {
 213                 /* Remove leading slashes if followed by drive specifier.
 214                    This hack is necessary to support file URLs containing drive
 215                    specifiers (e.g., "file://c:/path").  As a side effect,
 216                    "/c:/path" can be used as an alternative to "c:/path". */
 217                 sb.append(c);
 218                 sb.append(':');
 219                 return src + 1;
 220             }
 221         }
 222 
 223         // Normalize UNC prefix
 224         src = start;
 225         if ((len - src >= 2) && isSlash(path.charAt(src))) {
 226             while (++src < len && path.charAt(src) == CHAR_NUL);
 227             if (src < len && isSlash(path.charAt(src))) {
 228                 /* UNC pathname: Retain first slash; leave src pointed at
 229                    second slash so that further slashes will be collapsed
 230                    into the second slash.  The result will be a pathname
 231                    beginning with "\\\\" followed (most likely) by a host
 232                    name. */

 233                 sb.append(slash);
 234                 return src;
 235             }
 236         }
 237         return start;
 238     }
 239 
 240     @Override
 241     public int prefixLength(String path) {
 242         char slash = this.slash;
 243         int n = path.length();
 244         if (n == 0) return 0;
 245         char c0 = path.charAt(0);
 246         char c1 = (n > 1) ? path.charAt(1) : 0;
 247         if (c0 == slash) {
 248             if (c1 == slash) return 2;  /* Absolute UNC pathname "\\\\foo" */
 249             return 1;                   /* Drive-relative "\\foo" */
 250         }
 251         if (isLetter(c0) && (c1 == ':')) {
 252             if ((n > 2) && (path.charAt(2) == slash))
 253                 return 3;               /* Absolute local pathname "z:\\foo" */
 254             return 2;                   /* Directory-relative "z:foo" */
 255         }
 256         return 0;                       /* Completely relative */
 257     }