6870926: (file) Path.toRealPath performance can be improved (win)
Reviewed-by: sherman
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java Thu Aug 20 08:39:18 2009 +0100
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java Thu Aug 20 08:42:38 2009 +0100
@@ -246,8 +246,8 @@
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME);
long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);
- int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ?
- + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
+ int reparseTag = isReparsePoint(fileAttrs) ?
+ unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
return new WindowsFileAttributes(fileAttrs,
creationTime,
lastAccessTime,
@@ -275,7 +275,7 @@
int reparseTag = 0;
int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
- if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+ if (isReparsePoint(fileAttrs)) {
int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);
try {
@@ -311,7 +311,7 @@
// just return the attributes
int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
- if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ if (!isReparsePoint(fileAttrs))
return fromFileAttributeData(address, 0);
} catch (WindowsException x) {
if (x.lastError() != ERROR_SHARING_VIOLATION)
@@ -358,7 +358,7 @@
}
/**
- * Returns true if the attribtues are of the same file - both files must
+ * Returns true if the attributes are of the same file - both files must
* be open.
*/
static boolean isSameFile(WindowsFileAttributes attrs1,
@@ -370,6 +370,13 @@
(attrs1.fileIndexLow == attrs2.fileIndexLow);
}
+ /**
+ * Returns true if the attributes are of a file with a reparse point.
+ */
+ static boolean isReparsePoint(int attributes) {
+ return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+ }
+
// package-private
int attributes() {
return fileAttrs;
@@ -420,7 +427,7 @@
// package private
boolean isReparsePoint() {
- return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+ return isReparsePoint(fileAttrs);
}
boolean isDirectoryLink() {
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java Thu Aug 20 08:39:18 2009 +0100
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java Thu Aug 20 08:42:38 2009 +0100
@@ -63,6 +63,30 @@
}
/**
+ * Returns the final path (all symbolic links resolved) or null if this
+ * operation is not supported.
+ */
+ private static String getFinalPath(WindowsPath input) throws IOException {
+ long h = 0;
+ try {
+ h = input.openForReadAttributeAccess(true);
+ } catch (WindowsException x) {
+ x.rethrowAsIOException(input);
+ }
+ try {
+ return stripPrefix(GetFinalPathNameByHandle(h));
+ } catch (WindowsException x) {
+ // ERROR_INVALID_LEVEL is the error returned when not supported
+ // (a sym link to file on FAT32 or Samba server for example)
+ if (x.lastError() != ERROR_INVALID_LEVEL)
+ x.rethrowAsIOException(input);
+ } finally {
+ CloseHandle(h);
+ }
+ return null;
+ }
+
+ /**
* Returns the final path of a given path as a String. This should be used
* prior to calling Win32 system calls that do not follow links.
*/
@@ -70,7 +94,6 @@
throws IOException
{
WindowsFileSystem fs = input.getFileSystem();
-
try {
// if not following links then don't need final path
if (!followLinks || !fs.supportsLinks())
@@ -84,25 +107,10 @@
x.rethrowAsIOException(input);
}
- // The file is a symbolic link so we open it and try to get the
- // normalized path. This should succeed on NTFS but may fail if there
- // is a link to a non-NFTS file system.
- long h = 0;
- try {
- h = input.openForReadAttributeAccess(true);
- } catch (WindowsException x) {
- x.rethrowAsIOException(input);
- }
- try {
- return stripPrefix(GetFinalPathNameByHandle(h));
- } catch (WindowsException x) {
- // ERROR_INVALID_LEVEL is the error returned when not supported by
- // the file system
- if (x.lastError() != ERROR_INVALID_LEVEL)
- x.rethrowAsIOException(input);
- } finally {
- CloseHandle(h);
- }
+ // The file is a symbolic link so attempt to get the final path
+ String result = getFinalPath(input);
+ if (result != null)
+ return result;
// Fallback: read target of link, resolve against parent, and repeat
// until file is not a link.
@@ -149,31 +157,9 @@
throws IOException
{
WindowsFileSystem fs = input.getFileSystem();
- if (!fs.supportsLinks())
+ if (resolveLinks && !fs.supportsLinks())
resolveLinks = false;
- // On Vista use GetFinalPathNameByHandle. This should succeed on NTFS
- // but may fail if there is a link to a non-NFTS file system.
- if (resolveLinks) {
- long h = 0;
- try {
- h = input.openForReadAttributeAccess(true);
- } catch (WindowsException x) {
- x.rethrowAsIOException(input);
- }
- try {
- return stripPrefix(GetFinalPathNameByHandle(h));
- } catch (WindowsException x) {
- if (x.lastError() != ERROR_INVALID_LEVEL)
- x.rethrowAsIOException(input);
- } finally {
- CloseHandle(h);
- }
- }
-
- // Not resolving links or we are on Windows Vista (or newer) with a
- // link to non-NFTS file system.
-
// Start with absolute path
String path = null;
try {
@@ -183,15 +169,12 @@
}
// Collapse "." and ".."
- try {
- path = GetFullPathName(path);
- } catch (WindowsException x) {
- x.rethrowAsIOException(input);
- }
-
- // eliminate all symbolic links
- if (resolveLinks) {
- path = resolveAllLinks(WindowsPath.createFromNormalizedPath(fs, path));
+ if (path.indexOf('.') >= 0) {
+ try {
+ path = GetFullPathName(path);
+ } catch (WindowsException x) {
+ x.rethrowAsIOException(input);
+ }
}
// string builder to build up components of path
@@ -229,12 +212,15 @@
throw new AssertionError("path type not recognized");
}
- // check root directory exists
- try {
- FirstFile fileData = FindFirstFile(sb.toString() + "*");
- FindClose(fileData.handle());
- } catch (WindowsException x) {
- x.rethrowAsIOException(path);
+ // if the result is only a root component then we simply check it exists
+ if (start >= path.length()) {
+ String result = sb.toString();
+ try {
+ GetFileAttributes(result);
+ } catch (WindowsException x) {
+ x.rethrowAsIOException(path);
+ }
+ return result;
}
// iterate through each component to get its actual name in the
@@ -246,13 +232,28 @@
String search = sb.toString() + path.substring(curr, end);
try {
FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search));
- try {
- sb.append(fileData.name());
- if (next != -1) {
- sb.append('\\');
+ FindClose(fileData.handle());
+
+ // if a reparse point is encountered then we must return the
+ // final path.
+ if (resolveLinks &&
+ WindowsFileAttributes.isReparsePoint(fileData.attributes()))
+ {
+ String result = getFinalPath(input);
+ if (result == null) {
+ // Fallback to slow path, usually because there is a sym
+ // link to a file system that doesn't support sym links.
+ WindowsPath resolved = resolveAllLinks(
+ WindowsPath.createFromNormalizedPath(fs, path));
+ result = getRealPath(resolved, false);
}
- } finally {
- FindClose(fileData.handle());
+ return result;
+ }
+
+ // add the name to the result
+ sb.append(fileData.name());
+ if (next != -1) {
+ sb.append('\\');
}
} catch (WindowsException e) {
e.rethrowAsIOException(path);
@@ -342,7 +343,7 @@
/**
* Resolve all symbolic-links in a given absolute and normalized path
*/
- private static String resolveAllLinks(WindowsPath path)
+ private static WindowsPath resolveAllLinks(WindowsPath path)
throws IOException
{
assert path.isAbsolute();
@@ -401,7 +402,7 @@
}
}
- return path.toString();
+ return path;
}
/**
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Thu Aug 20 08:39:18 2009 +0100
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Thu Aug 20 08:42:38 2009 +0100
@@ -180,10 +180,12 @@
static class FirstFile {
private long handle;
private String name;
+ private int attributes;
private FirstFile() { }
public long handle() { return handle; }
public String name() { return name; }
+ public int attributes() { return attributes; }
}
private static native void FindFirstFile0(long lpFileName, FirstFile obj)
throws WindowsException;
--- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Thu Aug 20 08:39:18 2009 +0100
+++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Thu Aug 20 08:42:38 2009 +0100
@@ -48,6 +48,7 @@
*/
static jfieldID findFirst_handle;
static jfieldID findFirst_name;
+static jfieldID findFirst_attributes;
static jfieldID findStream_handle;
static jfieldID findStream_name;
@@ -134,6 +135,7 @@
}
findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
+ findFirst_attributes = (*env)->GetFieldID(env, clazz, "attributes", "I");
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream");
if (clazz == NULL) {
@@ -371,6 +373,7 @@
return;
(*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle));
(*env)->SetObjectField(env, obj, findFirst_name, name);
+ (*env)->SetIntField(env, obj, findFirst_attributes, data.dwFileAttributes);
} else {
throwWindowsException(env, GetLastError());
}
@@ -387,7 +390,7 @@
if (handle == INVALID_HANDLE_VALUE) {
throwWindowsException(env, GetLastError());
}
- return ptr_to_jlong(handle);
+ return ptr_to_jlong(handle);
}
JNIEXPORT jstring JNICALL