From 97e10327edc4dc3610612823708d7c4e80beab4f Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 20 Aug 2009 08:42:38 +0100 Subject: [PATCH] 6870926: (file) Path.toRealPath performance can be improved (win) Reviewed-by: sherman --- .../sun/nio/fs/WindowsFileAttributes.java | 19 ++- .../sun/nio/fs/WindowsLinkSupport.java | 133 +++++++++--------- .../sun/nio/fs/WindowsNativeDispatcher.java | 2 + .../sun/nio/fs/WindowsNativeDispatcher.c | 5 +- 4 files changed, 86 insertions(+), 73 deletions(-) diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 9a1e0bd1a15..69105a96834 100644 --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -246,8 +246,8 @@ class WindowsFileAttributes 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 @@ class WindowsFileAttributes 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 @@ class WindowsFileAttributes // 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 @@ class WindowsFileAttributes } /** - * 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 @@ class WindowsFileAttributes (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 @@ class WindowsFileAttributes // package private boolean isReparsePoint() { - return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + return isReparsePoint(fileAttrs); } boolean isDirectoryLink() { diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java index 9ad84818927..bb0ccdb84f6 100644 --- a/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java @@ -62,6 +62,30 @@ class WindowsLinkSupport { } } + /** + * 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 @@ class WindowsLinkSupport { 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 @@ class WindowsLinkSupport { 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 @@ class WindowsLinkSupport { 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 @@ class WindowsLinkSupport { } // 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 @@ class WindowsLinkSupport { 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 @@ class WindowsLinkSupport { 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 @@ class WindowsLinkSupport { /** * 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 @@ class WindowsLinkSupport { } } - return path.toString(); + return path; } /** diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java index a116bf81190..0ad876755be 100644 --- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -180,10 +180,12 @@ class WindowsNativeDispatcher { 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; diff --git a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c index d5195c4f7b3..8e07bde64b6 100644 --- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c +++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c @@ -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 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) } 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 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0(JNIEnv* env, jclass this, 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 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this, if (handle == INVALID_HANDLE_VALUE) { throwWindowsException(env, GetLastError()); } - return ptr_to_jlong(handle); + return ptr_to_jlong(handle); } JNIEXPORT jstring JNICALL