jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java
changeset 3628 2768d95a0e7d
parent 3065 452aaa2899fc
child 5506 202f599c92aa
equal deleted inserted replaced
3627:d0ad40d5adab 3628:2768d95a0e7d
    61             CloseHandle(handle);
    61             CloseHandle(handle);
    62         }
    62         }
    63     }
    63     }
    64 
    64 
    65     /**
    65     /**
       
    66      * Returns the final path (all symbolic links resolved) or null if this
       
    67      * operation is not supported.
       
    68      */
       
    69     private static String getFinalPath(WindowsPath input) throws IOException {
       
    70         long h = 0;
       
    71         try {
       
    72             h = input.openForReadAttributeAccess(true);
       
    73         } catch (WindowsException x) {
       
    74             x.rethrowAsIOException(input);
       
    75         }
       
    76         try {
       
    77             return stripPrefix(GetFinalPathNameByHandle(h));
       
    78         } catch (WindowsException x) {
       
    79             // ERROR_INVALID_LEVEL is the error returned when not supported
       
    80             // (a sym link to file on FAT32 or Samba server for example)
       
    81             if (x.lastError() != ERROR_INVALID_LEVEL)
       
    82                 x.rethrowAsIOException(input);
       
    83         } finally {
       
    84             CloseHandle(h);
       
    85         }
       
    86         return null;
       
    87     }
       
    88 
       
    89     /**
    66      * Returns the final path of a given path as a String. This should be used
    90      * Returns the final path of a given path as a String. This should be used
    67      * prior to calling Win32 system calls that do not follow links.
    91      * prior to calling Win32 system calls that do not follow links.
    68      */
    92      */
    69     static String getFinalPath(WindowsPath input, boolean followLinks)
    93     static String getFinalPath(WindowsPath input, boolean followLinks)
    70         throws IOException
    94         throws IOException
    71     {
    95     {
    72         WindowsFileSystem fs = input.getFileSystem();
    96         WindowsFileSystem fs = input.getFileSystem();
    73 
       
    74         try {
    97         try {
    75             // if not following links then don't need final path
    98             // if not following links then don't need final path
    76             if (!followLinks || !fs.supportsLinks())
    99             if (!followLinks || !fs.supportsLinks())
    77                 return input.getPathForWin32Calls();
   100                 return input.getPathForWin32Calls();
    78 
   101 
    82             }
   105             }
    83         } catch (WindowsException x) {
   106         } catch (WindowsException x) {
    84             x.rethrowAsIOException(input);
   107             x.rethrowAsIOException(input);
    85         }
   108         }
    86 
   109 
    87         // The file is a symbolic link so we open it and try to get the
   110         // The file is a symbolic link so attempt to get the final path
    88         // normalized path. This should succeed on NTFS but may fail if there
   111         String result = getFinalPath(input);
    89         // is a link to a non-NFTS file system.
   112         if (result != null)
    90         long h = 0;
   113             return result;
    91         try {
       
    92             h = input.openForReadAttributeAccess(true);
       
    93         } catch (WindowsException x) {
       
    94             x.rethrowAsIOException(input);
       
    95         }
       
    96         try {
       
    97             return stripPrefix(GetFinalPathNameByHandle(h));
       
    98         } catch (WindowsException x) {
       
    99             // ERROR_INVALID_LEVEL is the error returned when not supported by
       
   100             // the file system
       
   101             if (x.lastError() != ERROR_INVALID_LEVEL)
       
   102                 x.rethrowAsIOException(input);
       
   103         } finally {
       
   104             CloseHandle(h);
       
   105         }
       
   106 
   114 
   107         // Fallback: read target of link, resolve against parent, and repeat
   115         // Fallback: read target of link, resolve against parent, and repeat
   108         // until file is not a link.
   116         // until file is not a link.
   109         WindowsPath target = input;
   117         WindowsPath target = input;
   110         int linkCount = 0;
   118         int linkCount = 0;
   147      */
   155      */
   148     static String getRealPath(WindowsPath input, boolean resolveLinks)
   156     static String getRealPath(WindowsPath input, boolean resolveLinks)
   149         throws IOException
   157         throws IOException
   150     {
   158     {
   151         WindowsFileSystem fs = input.getFileSystem();
   159         WindowsFileSystem fs = input.getFileSystem();
   152         if (!fs.supportsLinks())
   160         if (resolveLinks && !fs.supportsLinks())
   153             resolveLinks = false;
   161             resolveLinks = false;
   154 
       
   155         // On Vista use GetFinalPathNameByHandle. This should succeed on NTFS
       
   156         // but may fail if there is a link to a non-NFTS file system.
       
   157         if (resolveLinks) {
       
   158             long h = 0;
       
   159             try {
       
   160                 h = input.openForReadAttributeAccess(true);
       
   161             } catch (WindowsException x) {
       
   162                 x.rethrowAsIOException(input);
       
   163             }
       
   164             try {
       
   165                 return stripPrefix(GetFinalPathNameByHandle(h));
       
   166             } catch (WindowsException x) {
       
   167                 if (x.lastError() != ERROR_INVALID_LEVEL)
       
   168                     x.rethrowAsIOException(input);
       
   169             } finally {
       
   170                 CloseHandle(h);
       
   171             }
       
   172         }
       
   173 
       
   174         // Not resolving links or we are on Windows Vista (or newer) with a
       
   175         // link to non-NFTS file system.
       
   176 
   162 
   177         // Start with absolute path
   163         // Start with absolute path
   178         String path = null;
   164         String path = null;
   179         try {
   165         try {
   180             path = input.toAbsolutePath().toString();
   166             path = input.toAbsolutePath().toString();
   181         } catch (IOError x) {
   167         } catch (IOError x) {
   182             throw (IOException)(x.getCause());
   168             throw (IOException)(x.getCause());
   183         }
   169         }
   184 
   170 
   185         // Collapse "." and ".."
   171         // Collapse "." and ".."
   186         try {
   172         if (path.indexOf('.') >= 0) {
   187             path = GetFullPathName(path);
   173             try {
   188         } catch (WindowsException x) {
   174                 path = GetFullPathName(path);
   189             x.rethrowAsIOException(input);
   175             } catch (WindowsException x) {
   190         }
   176                 x.rethrowAsIOException(input);
   191 
   177             }
   192         // eliminate all symbolic links
       
   193         if (resolveLinks) {
       
   194             path = resolveAllLinks(WindowsPath.createFromNormalizedPath(fs, path));
       
   195         }
   178         }
   196 
   179 
   197         // string builder to build up components of path
   180         // string builder to build up components of path
   198         StringBuilder sb = new StringBuilder(path.length());
   181         StringBuilder sb = new StringBuilder(path.length());
   199 
   182 
   227             start = pos + 1;
   210             start = pos + 1;
   228         } else {
   211         } else {
   229             throw new AssertionError("path type not recognized");
   212             throw new AssertionError("path type not recognized");
   230         }
   213         }
   231 
   214 
   232         // check root directory exists
   215         // if the result is only a root component then we simply check it exists
   233         try {
   216         if (start >= path.length()) {
   234             FirstFile fileData = FindFirstFile(sb.toString() + "*");
   217             String result = sb.toString();
   235             FindClose(fileData.handle());
   218             try {
   236         } catch (WindowsException x) {
   219                 GetFileAttributes(result);
   237             x.rethrowAsIOException(path);
   220             } catch (WindowsException x) {
       
   221                 x.rethrowAsIOException(path);
       
   222             }
       
   223             return result;
   238         }
   224         }
   239 
   225 
   240         // iterate through each component to get its actual name in the
   226         // iterate through each component to get its actual name in the
   241         // directory
   227         // directory
   242         int curr = start;
   228         int curr = start;
   244             int next = path.indexOf('\\', curr);
   230             int next = path.indexOf('\\', curr);
   245             int end = (next == -1) ? path.length() : next;
   231             int end = (next == -1) ? path.length() : next;
   246             String search = sb.toString() + path.substring(curr, end);
   232             String search = sb.toString() + path.substring(curr, end);
   247             try {
   233             try {
   248                 FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search));
   234                 FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search));
   249                 try {
   235                 FindClose(fileData.handle());
   250                     sb.append(fileData.name());
   236 
   251                     if (next != -1) {
   237                 // if a reparse point is encountered then we must return the
   252                         sb.append('\\');
   238                 // final path.
       
   239                 if (resolveLinks &&
       
   240                     WindowsFileAttributes.isReparsePoint(fileData.attributes()))
       
   241                 {
       
   242                     String result = getFinalPath(input);
       
   243                     if (result == null) {
       
   244                         // Fallback to slow path, usually because there is a sym
       
   245                         // link to a file system that doesn't support sym links.
       
   246                         WindowsPath resolved = resolveAllLinks(
       
   247                             WindowsPath.createFromNormalizedPath(fs, path));
       
   248                         result = getRealPath(resolved, false);
   253                     }
   249                     }
   254                 } finally {
   250                     return result;
   255                     FindClose(fileData.handle());
   251                 }
       
   252 
       
   253                 // add the name to the result
       
   254                 sb.append(fileData.name());
       
   255                 if (next != -1) {
       
   256                     sb.append('\\');
   256                 }
   257                 }
   257             } catch (WindowsException e) {
   258             } catch (WindowsException e) {
   258                 e.rethrowAsIOException(path);
   259                 e.rethrowAsIOException(path);
   259             }
   260             }
   260             curr = end + 1;
   261             curr = end + 1;
   340     }
   341     }
   341 
   342 
   342     /**
   343     /**
   343      * Resolve all symbolic-links in a given absolute and normalized path
   344      * Resolve all symbolic-links in a given absolute and normalized path
   344      */
   345      */
   345     private static String resolveAllLinks(WindowsPath path)
   346     private static WindowsPath resolveAllLinks(WindowsPath path)
   346         throws IOException
   347         throws IOException
   347     {
   348     {
   348         assert path.isAbsolute();
   349         assert path.isAbsolute();
   349         WindowsFileSystem fs = path.getFileSystem();
   350         WindowsFileSystem fs = path.getFileSystem();
   350 
   351 
   399                 // not a link
   400                 // not a link
   400                 elem++;
   401                 elem++;
   401             }
   402             }
   402         }
   403         }
   403 
   404 
   404         return path.toString();
   405         return path;
   405     }
   406     }
   406 
   407 
   407     /**
   408     /**
   408      * Add long path prefix to path if required.
   409      * Add long path prefix to path if required.
   409      */
   410      */