提交 acd702cf 编写于 作者: A alanb

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

Reviewed-by: sherman
上级 24fbe952
......@@ -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() {
......
......@@ -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;
}
/**
......
......@@ -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;
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册