mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-20 10:27:52 +00:00
6870926: (file) Path.toRealPath performance can be improved (win)
Reviewed-by: sherman
This commit is contained in:
parent
41a783f149
commit
97e10327ed
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user