mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-06 10:42:45 +00:00
8383623: (fs) Update Windows file system provider to use GetFileInformationByName where possible
Reviewed-by: alanb
This commit is contained in:
parent
86637704fd
commit
36eb8edadf
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -115,6 +115,12 @@ class WindowsConstants {
|
||||
public static final int ERROR_NOT_A_REPARSE_POINT = 4390;
|
||||
public static final int ERROR_INVALID_REPARSE_DATA = 4392;
|
||||
|
||||
// FILE_INFO_BY_NAME_CLASS enum values for GetFileInformationByName()
|
||||
public static final int FileStatByNameInfo = 0;
|
||||
public static final int FileStatLxByNameInfo = 1;
|
||||
public static final int FileCaseSensitiveByNameInfo = 2;
|
||||
public static final int FileStatBasicByNameInfo = 3;
|
||||
|
||||
// notify filters
|
||||
public static final int FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001;
|
||||
public static final int FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -107,6 +107,35 @@ class WindowsFileAttributes
|
||||
private static final short OFFSETOF_FIND_DATA_SIZELOW = 32;
|
||||
private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36;
|
||||
|
||||
/*
|
||||
* typedef struct _FILE_STAT_BASIC_INFORMATION {
|
||||
* LARGE_INTEGER FileId; // offset = 0
|
||||
* LARGE_INTEGER CreationTime; // offset = 8
|
||||
* LARGE_INTEGER LastAccessTime; // offset = 16
|
||||
* LARGE_INTEGER LastWriteTime; // offset = 24
|
||||
* LARGE_INTEGER ChangeTime; // offset = 32
|
||||
* LARGE_INTEGER AllocationSize; // offset = 40
|
||||
* LARGE_INTEGER EndOfFile; // offset = 48
|
||||
* ULONG FileAttributes; // offset = 56
|
||||
* ULONG ReparseTag; // offset = 60
|
||||
* ULONG NumberOfLinks; // offset = 64
|
||||
* ULONG DeviceType; // offset = 68
|
||||
* ULONG DeviceCharacteristics; // offset = 72
|
||||
* ULONG Reserved; // offset = 76
|
||||
* LARGE_INTEGER VolumeSerialNumber; // offset = 80
|
||||
* FILE_ID_128 FileId128; // offset = 88
|
||||
* } FILE_STAT_BASIC_INFORMATION;
|
||||
*/
|
||||
private static final short SIZEOF_STAT_BASIC_INFO = 104;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_FILEID = 0;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_CREATETIME = 8;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_LASTACCESSTIME = 16;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_LASTWRITETIME = 24;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_ENDOFFILE = 48;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_ATTRIBUTES = 56;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_REPARSETAG = 60;
|
||||
private static final short OFFSETOF_STAT_BASIC_INFO_VOLSERIAL = 80;
|
||||
|
||||
// used to adjust values between Windows and java epochs
|
||||
private static final long WINDOWS_EPOCH_IN_MICROS = -11644473600000000L;
|
||||
private static final long WINDOWS_EPOCH_IN_100NS = -116444736000000000L;
|
||||
@ -226,6 +255,32 @@ class WindowsFileAttributes
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a WindowsFileAttributes from a FILE_STAT_BASIC_INFORMATION structure
|
||||
*/
|
||||
static WindowsFileAttributes fromStatBasicInfo(long address) {
|
||||
int fileAttrs = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_ATTRIBUTES);
|
||||
long creationTime = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_CREATETIME);
|
||||
long lastAccessTime = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_LASTACCESSTIME);
|
||||
long lastWriteTime = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_LASTWRITETIME);
|
||||
long size = unsafe.getLong(address + OFFSETOF_STAT_BASIC_INFO_ENDOFFILE);
|
||||
int reparseTag = isReparsePoint(fileAttrs) ?
|
||||
unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_REPARSETAG) : 0;
|
||||
int volSerialNumber = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_VOLSERIAL);
|
||||
int fileIndexLow = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_FILEID);
|
||||
int fileIndexHigh = unsafe.getInt(address + OFFSETOF_STAT_BASIC_INFO_FILEID + 4);
|
||||
|
||||
return new WindowsFileAttributes(fileAttrs,
|
||||
creationTime,
|
||||
lastAccessTime,
|
||||
lastWriteTime,
|
||||
size,
|
||||
reparseTag,
|
||||
volSerialNumber,
|
||||
fileIndexHigh,
|
||||
fileIndexLow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a native buffer for a WIN32_FIND_DATA structure
|
||||
*/
|
||||
@ -332,6 +387,23 @@ class WindowsFileAttributes
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsGetFileInformationByName()) {
|
||||
try (NativeBuffer buffer = NativeBuffers.getNativeBuffer(SIZEOF_STAT_BASIC_INFO)) {
|
||||
long addr = buffer.address();
|
||||
GetFileInformationByName(path.getPathForWin32Calls(),
|
||||
FileStatBasicByNameInfo, addr,
|
||||
SIZEOF_STAT_BASIC_INFO);
|
||||
|
||||
// GetFileInformationByName() doesn't follow reparse points so if
|
||||
// we discover that this is a reparse point and if we're being asked
|
||||
// to follow links, then drop to the slow path.
|
||||
int fileAttrs = unsafe.getInt(addr + OFFSETOF_STAT_BASIC_INFO_ATTRIBUTES);
|
||||
if (!isReparsePoint(fileAttrs) || !followLinks) {
|
||||
return fromStatBasicInfo(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// file is reparse point so need to open file to get attributes
|
||||
long handle = path.openForReadAttributeAccess(followLinks);
|
||||
try {
|
||||
|
||||
@ -367,6 +367,24 @@ class WindowsNativeDispatcher {
|
||||
private static native void GetFileAttributesEx0(long lpFileName, long address)
|
||||
throws WindowsException;
|
||||
|
||||
/**
|
||||
* GetFileInformationByName(
|
||||
* PCWSTR FileName,
|
||||
* FILE_INFO_BY_NAME_CLASS FileInformationClass,
|
||||
* PVOID FileInfoBuffer,
|
||||
* ULONG FileInfoBufferSize
|
||||
* )
|
||||
*/
|
||||
static void GetFileInformationByName(String path, int infoClass, long address, int size)
|
||||
throws WindowsException
|
||||
{
|
||||
try (NativeBuffer buffer = asNativeBuffer(path)) {
|
||||
GetFileInformationByName0(buffer.address(), infoClass, address, size);
|
||||
}
|
||||
}
|
||||
private static native void GetFileInformationByName0(long pathAddress,
|
||||
int infoClass, long infoAddress, int infoSize) throws WindowsException;
|
||||
|
||||
/**
|
||||
* SetFileTime(
|
||||
* HANDLE hFile,
|
||||
@ -1090,15 +1108,23 @@ class WindowsNativeDispatcher {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// -- capabilities --
|
||||
private static final int SUPPORTS_GETFILEINFORMATIONBYNAME = 1 << 1;
|
||||
private static final int capabilities;
|
||||
|
||||
static boolean supportsGetFileInformationByName() {
|
||||
return (capabilities & SUPPORTS_GETFILEINFORMATIONBYNAME) != 0;
|
||||
}
|
||||
|
||||
// -- native library initialization --
|
||||
|
||||
private static native void initIDs();
|
||||
private static native int init();
|
||||
|
||||
static {
|
||||
// nio.dll has dependency on net.dll
|
||||
jdk.internal.loader.BootLoader.loadLibrary("net");
|
||||
jdk.internal.loader.BootLoader.loadLibrary("nio");
|
||||
initIDs();
|
||||
capabilities = init();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -79,75 +79,122 @@ static void throwWindowsException(JNIEnv* env, DWORD lastError) {
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI)
|
||||
|
||||
typedef struct _FILE_STAT_BASIC_INFORMATION {
|
||||
LARGE_INTEGER FileId;
|
||||
LARGE_INTEGER CreationTime;
|
||||
LARGE_INTEGER LastAccessTime;
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
LARGE_INTEGER ChangeTime;
|
||||
LARGE_INTEGER AllocationSize;
|
||||
LARGE_INTEGER EndOfFile;
|
||||
ULONG FileAttributes;
|
||||
ULONG ReparseTag;
|
||||
ULONG NumberOfLinks;
|
||||
ULONG DeviceType;
|
||||
ULONG DeviceCharacteristics;
|
||||
ULONG Reserved;
|
||||
LARGE_INTEGER VolumeSerialNumber;
|
||||
FILE_ID_128 FileId128;
|
||||
} FILE_STAT_BASIC_INFORMATION;
|
||||
|
||||
typedef enum _FILE_INFO_BY_NAME_CLASS {
|
||||
FileStatByNameInfo,
|
||||
FileStatLxByNameInfo,
|
||||
FileCaseSensitiveByNameInfo,
|
||||
FileStatBasicByNameInfo,
|
||||
MaximumFileInfoByNameClass
|
||||
} FILE_INFO_BY_NAME_CLASS;
|
||||
|
||||
#endif /* !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI) */
|
||||
|
||||
typedef BOOL (WINAPI *PGetFileInformationByName)(
|
||||
PCWSTR, FILE_INFO_BY_NAME_CLASS, PVOID, ULONG);
|
||||
|
||||
static PGetFileInformationByName pGetFileInformationByName = NULL;
|
||||
|
||||
/**
|
||||
* Initializes jfieldIDs and get address of Win32 calls that are located
|
||||
* at runtime.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_init(JNIEnv* env, jclass this)
|
||||
{
|
||||
jclass clazz;
|
||||
jint capabilities = 0;
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
|
||||
CHECK_NULL(findFirst_handle);
|
||||
CHECK_NULL_RETURN(findFirst_handle, 0);
|
||||
findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
|
||||
CHECK_NULL(findFirst_name);
|
||||
CHECK_NULL_RETURN(findFirst_name, 0);
|
||||
findFirst_attributes = (*env)->GetFieldID(env, clazz, "attributes", "I");
|
||||
CHECK_NULL(findFirst_attributes);
|
||||
CHECK_NULL_RETURN(findFirst_attributes, 0);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
findStream_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
|
||||
CHECK_NULL(findStream_handle);
|
||||
CHECK_NULL_RETURN(findStream_handle, 0);
|
||||
findStream_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
|
||||
CHECK_NULL(findStream_name);
|
||||
CHECK_NULL_RETURN(findStream_name, 0);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$VolumeInformation");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
volumeInfo_fsName = (*env)->GetFieldID(env, clazz, "fileSystemName", "Ljava/lang/String;");
|
||||
CHECK_NULL(volumeInfo_fsName);
|
||||
CHECK_NULL_RETURN(volumeInfo_fsName, 0);
|
||||
volumeInfo_volName = (*env)->GetFieldID(env, clazz, "volumeName", "Ljava/lang/String;");
|
||||
CHECK_NULL(volumeInfo_volName);
|
||||
CHECK_NULL_RETURN(volumeInfo_volName, 0);
|
||||
volumeInfo_volSN = (*env)->GetFieldID(env, clazz, "volumeSerialNumber", "I");
|
||||
CHECK_NULL(volumeInfo_volSN);
|
||||
CHECK_NULL_RETURN(volumeInfo_volSN, 0);
|
||||
volumeInfo_flags = (*env)->GetFieldID(env, clazz, "flags", "I");
|
||||
CHECK_NULL(volumeInfo_flags);
|
||||
CHECK_NULL_RETURN(volumeInfo_flags, 0);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$DiskFreeSpace");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
diskSpace_bytesAvailable = (*env)->GetFieldID(env, clazz, "freeBytesAvailable", "J");
|
||||
CHECK_NULL(diskSpace_bytesAvailable);
|
||||
CHECK_NULL_RETURN(diskSpace_bytesAvailable, 0);
|
||||
diskSpace_totalBytes = (*env)->GetFieldID(env, clazz, "totalNumberOfBytes", "J");
|
||||
CHECK_NULL(diskSpace_totalBytes);
|
||||
CHECK_NULL_RETURN(diskSpace_totalBytes, 0);
|
||||
diskSpace_totalFree = (*env)->GetFieldID(env, clazz, "totalNumberOfFreeBytes", "J");
|
||||
CHECK_NULL(diskSpace_totalFree);
|
||||
CHECK_NULL_RETURN(diskSpace_totalFree, 0);
|
||||
diskSpace_bytesPerSector = (*env)->GetFieldID(env, clazz, "bytesPerSector", "J");
|
||||
CHECK_NULL(diskSpace_bytesPerSector);
|
||||
CHECK_NULL_RETURN(diskSpace_bytesPerSector, 0);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$Account");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
account_domain = (*env)->GetFieldID(env, clazz, "domain", "Ljava/lang/String;");
|
||||
CHECK_NULL(account_domain);
|
||||
CHECK_NULL_RETURN(account_domain, 0);
|
||||
account_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
|
||||
CHECK_NULL(account_name);
|
||||
CHECK_NULL_RETURN(account_name, 0);
|
||||
account_use = (*env)->GetFieldID(env, clazz, "use", "I");
|
||||
CHECK_NULL(account_use);
|
||||
CHECK_NULL_RETURN(account_use, 0);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$AclInformation");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
aclInfo_aceCount = (*env)->GetFieldID(env, clazz, "aceCount", "I");
|
||||
CHECK_NULL(aclInfo_aceCount);
|
||||
CHECK_NULL_RETURN(aclInfo_aceCount, 0);
|
||||
|
||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$CompletionStatus");
|
||||
CHECK_NULL(clazz);
|
||||
CHECK_NULL_RETURN(clazz, 0);
|
||||
completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
|
||||
CHECK_NULL(completionStatus_error);
|
||||
CHECK_NULL_RETURN(completionStatus_error, 0);
|
||||
completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
|
||||
CHECK_NULL(completionStatus_bytesTransferred);
|
||||
CHECK_NULL_RETURN(completionStatus_bytesTransferred, 0);
|
||||
completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J");
|
||||
CHECK_NULL(completionStatus_completionKey);
|
||||
CHECK_NULL_RETURN(completionStatus_completionKey, 0);
|
||||
|
||||
HMODULE hMod = GetModuleHandleW(L"kernel32.dll");
|
||||
if (hMod != NULL) {
|
||||
pGetFileInformationByName =
|
||||
(PGetFileInformationByName)GetProcAddress(hMod, "GetFileInformationByName");
|
||||
if (pGetFileInformationByName != NULL) {
|
||||
capabilities |= sun_nio_fs_WindowsNativeDispatcher_SUPPORTS_GETFILEINFORMATIONBYNAME;
|
||||
}
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
@ -510,6 +557,23 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFileAttributesEx0(JNIEnv* env, jclass
|
||||
throwWindowsException(env, GetLastError());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_GetFileInformationByName0(JNIEnv* env,
|
||||
jclass this, jlong pathAddress, jint infoClass, jlong infoAddress, jint infoSize)
|
||||
{
|
||||
LPCWSTR lpFileName = jlong_to_ptr(pathAddress);
|
||||
PVOID pInfo = jlong_to_ptr(infoAddress);
|
||||
|
||||
if (pGetFileInformationByName == NULL) {
|
||||
JNU_ThrowInternalError(env, "should not reach here");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pGetFileInformationByName(lpFileName, (FILE_INFO_BY_NAME_CLASS)infoClass,
|
||||
pInfo, (ULONG)infoSize)) {
|
||||
throwWindowsException(env, GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_WindowsNativeDispatcher_SetFileTime0(JNIEnv* env, jclass this,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user