提交 acd702cf 编写于 作者: A alanb

6870926: (file) Path.toRealPath performance can be improved (win)

Reviewed-by: sherman
上级 24fbe952
...@@ -246,8 +246,8 @@ class WindowsFileAttributes ...@@ -246,8 +246,8 @@ class WindowsFileAttributes
long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME); long lastWriteTime = unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME);
long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32)
+ (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL);
int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? int reparseTag = isReparsePoint(fileAttrs) ?
+ unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0;
return new WindowsFileAttributes(fileAttrs, return new WindowsFileAttributes(fileAttrs,
creationTime, creationTime,
lastAccessTime, lastAccessTime,
...@@ -275,7 +275,7 @@ class WindowsFileAttributes ...@@ -275,7 +275,7 @@ class WindowsFileAttributes
int reparseTag = 0; int reparseTag = 0;
int fileAttrs = unsafe int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES); .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { if (isReparsePoint(fileAttrs)) {
int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size); NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);
try { try {
...@@ -311,7 +311,7 @@ class WindowsFileAttributes ...@@ -311,7 +311,7 @@ class WindowsFileAttributes
// just return the attributes // just return the attributes
int fileAttrs = unsafe int fileAttrs = unsafe
.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES); .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0) if (!isReparsePoint(fileAttrs))
return fromFileAttributeData(address, 0); return fromFileAttributeData(address, 0);
} catch (WindowsException x) { } catch (WindowsException x) {
if (x.lastError() != ERROR_SHARING_VIOLATION) if (x.lastError() != ERROR_SHARING_VIOLATION)
...@@ -358,7 +358,7 @@ class WindowsFileAttributes ...@@ -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. * be open.
*/ */
static boolean isSameFile(WindowsFileAttributes attrs1, static boolean isSameFile(WindowsFileAttributes attrs1,
...@@ -370,6 +370,13 @@ class WindowsFileAttributes ...@@ -370,6 +370,13 @@ class WindowsFileAttributes
(attrs1.fileIndexLow == attrs2.fileIndexLow); (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 // package-private
int attributes() { int attributes() {
return fileAttrs; return fileAttrs;
...@@ -420,7 +427,7 @@ class WindowsFileAttributes ...@@ -420,7 +427,7 @@ class WindowsFileAttributes
// package private // package private
boolean isReparsePoint() { boolean isReparsePoint() {
return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0; return isReparsePoint(fileAttrs);
} }
boolean isDirectoryLink() { boolean isDirectoryLink() {
......
...@@ -62,6 +62,30 @@ class WindowsLinkSupport { ...@@ -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 * 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. * prior to calling Win32 system calls that do not follow links.
...@@ -70,7 +94,6 @@ class WindowsLinkSupport { ...@@ -70,7 +94,6 @@ class WindowsLinkSupport {
throws IOException throws IOException
{ {
WindowsFileSystem fs = input.getFileSystem(); WindowsFileSystem fs = input.getFileSystem();
try { try {
// if not following links then don't need final path // if not following links then don't need final path
if (!followLinks || !fs.supportsLinks()) if (!followLinks || !fs.supportsLinks())
...@@ -84,25 +107,10 @@ class WindowsLinkSupport { ...@@ -84,25 +107,10 @@ class WindowsLinkSupport {
x.rethrowAsIOException(input); x.rethrowAsIOException(input);
} }
// The file is a symbolic link so we open it and try to get the // The file is a symbolic link so attempt to get the final path
// normalized path. This should succeed on NTFS but may fail if there String result = getFinalPath(input);
// is a link to a non-NFTS file system. if (result != null)
long h = 0; return result;
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);
}
// Fallback: read target of link, resolve against parent, and repeat // Fallback: read target of link, resolve against parent, and repeat
// until file is not a link. // until file is not a link.
...@@ -149,31 +157,9 @@ class WindowsLinkSupport { ...@@ -149,31 +157,9 @@ class WindowsLinkSupport {
throws IOException throws IOException
{ {
WindowsFileSystem fs = input.getFileSystem(); WindowsFileSystem fs = input.getFileSystem();
if (!fs.supportsLinks()) if (resolveLinks && !fs.supportsLinks())
resolveLinks = false; 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 // Start with absolute path
String path = null; String path = null;
try { try {
...@@ -183,15 +169,12 @@ class WindowsLinkSupport { ...@@ -183,15 +169,12 @@ class WindowsLinkSupport {
} }
// Collapse "." and ".." // Collapse "." and ".."
try { if (path.indexOf('.') >= 0) {
path = GetFullPathName(path); try {
} catch (WindowsException x) { path = GetFullPathName(path);
x.rethrowAsIOException(input); } catch (WindowsException x) {
} x.rethrowAsIOException(input);
}
// eliminate all symbolic links
if (resolveLinks) {
path = resolveAllLinks(WindowsPath.createFromNormalizedPath(fs, path));
} }
// string builder to build up components of path // string builder to build up components of path
...@@ -229,12 +212,15 @@ class WindowsLinkSupport { ...@@ -229,12 +212,15 @@ class WindowsLinkSupport {
throw new AssertionError("path type not recognized"); throw new AssertionError("path type not recognized");
} }
// check root directory exists // if the result is only a root component then we simply check it exists
try { if (start >= path.length()) {
FirstFile fileData = FindFirstFile(sb.toString() + "*"); String result = sb.toString();
FindClose(fileData.handle()); try {
} catch (WindowsException x) { GetFileAttributes(result);
x.rethrowAsIOException(path); } catch (WindowsException x) {
x.rethrowAsIOException(path);
}
return result;
} }
// iterate through each component to get its actual name in the // iterate through each component to get its actual name in the
...@@ -246,13 +232,28 @@ class WindowsLinkSupport { ...@@ -246,13 +232,28 @@ class WindowsLinkSupport {
String search = sb.toString() + path.substring(curr, end); String search = sb.toString() + path.substring(curr, end);
try { try {
FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search)); FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search));
try { FindClose(fileData.handle());
sb.append(fileData.name());
if (next != -1) { // if a reparse point is encountered then we must return the
sb.append('\\'); // 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 { return result;
FindClose(fileData.handle()); }
// add the name to the result
sb.append(fileData.name());
if (next != -1) {
sb.append('\\');
} }
} catch (WindowsException e) { } catch (WindowsException e) {
e.rethrowAsIOException(path); e.rethrowAsIOException(path);
...@@ -342,7 +343,7 @@ class WindowsLinkSupport { ...@@ -342,7 +343,7 @@ class WindowsLinkSupport {
/** /**
* Resolve all symbolic-links in a given absolute and normalized path * 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 throws IOException
{ {
assert path.isAbsolute(); assert path.isAbsolute();
...@@ -401,7 +402,7 @@ class WindowsLinkSupport { ...@@ -401,7 +402,7 @@ class WindowsLinkSupport {
} }
} }
return path.toString(); return path;
} }
/** /**
......
...@@ -180,10 +180,12 @@ class WindowsNativeDispatcher { ...@@ -180,10 +180,12 @@ class WindowsNativeDispatcher {
static class FirstFile { static class FirstFile {
private long handle; private long handle;
private String name; private String name;
private int attributes;
private FirstFile() { } private FirstFile() { }
public long handle() { return handle; } public long handle() { return handle; }
public String name() { return name; } public String name() { return name; }
public int attributes() { return attributes; }
} }
private static native void FindFirstFile0(long lpFileName, FirstFile obj) private static native void FindFirstFile0(long lpFileName, FirstFile obj)
throws WindowsException; throws WindowsException;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
*/ */
static jfieldID findFirst_handle; static jfieldID findFirst_handle;
static jfieldID findFirst_name; static jfieldID findFirst_name;
static jfieldID findFirst_attributes;
static jfieldID findStream_handle; static jfieldID findStream_handle;
static jfieldID findStream_name; static jfieldID findStream_name;
...@@ -134,6 +135,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) ...@@ -134,6 +135,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
} }
findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J"); findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;"); 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"); clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream");
if (clazz == NULL) { if (clazz == NULL) {
...@@ -371,6 +373,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0(JNIEnv* env, jclass this, ...@@ -371,6 +373,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0(JNIEnv* env, jclass this,
return; return;
(*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle)); (*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle));
(*env)->SetObjectField(env, obj, findFirst_name, name); (*env)->SetObjectField(env, obj, findFirst_name, name);
(*env)->SetIntField(env, obj, findFirst_attributes, data.dwFileAttributes);
} else { } else {
throwWindowsException(env, GetLastError()); throwWindowsException(env, GetLastError());
} }
...@@ -387,7 +390,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this, ...@@ -387,7 +390,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this,
if (handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE) {
throwWindowsException(env, GetLastError()); throwWindowsException(env, GetLastError());
} }
return ptr_to_jlong(handle); return ptr_to_jlong(handle);
} }
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册