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; |