OpenJDK / jdk / hs
changeset 3628:2768d95a0e7d
6870926: (file) Path.toRealPath performance can be improved (win)
Reviewed-by: sherman
author | alanb |
---|---|
date | Thu, 20 Aug 2009 08:42:38 +0100 |
parents | d0ad40d5adab |
children | 6035eed86b12 |
files | jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c |
diffstat | 4 files changed, 86 insertions(+), 73 deletions(-) [+] |
line wrap: on
line diff
--- 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