From 5a4b7b70901ae208eeda56ef6be833c1ba7991f1 Mon Sep 17 00:00:00 2001 From: Hannes Wellmann Date: Sat, 7 Mar 2026 15:06:55 +0100 Subject: [PATCH] Migrate Win32Handler to Java's new Foreign Function & Memory API TODO: Add post processor similar like the javadoc basher, that - detects typedefs and replaces the original struct definition with the (often nicer) alias - removes unused code, like reinterpreters and tracing - suppresses warnings about unused imports or nls warnings (or just all?) --- .../org.eclipse.core.filesystem/.classpath | 3 +- .../.settings/org.eclipse.jdt.core.prefs | 10 +- .../META-INF/MANIFEST.MF | 4 +- .../generateWindowsH.bat | 34 + .../src-gen/com/microsoft/FILETIME.java | 29 + .../com/microsoft/WIN32_FIND_DATAW.java | 37 ++ .../src-gen/com/microsoft/Windows$shared.java | 64 ++ .../src-gen/com/microsoft/Windows.java | 498 ++++++++++++++ .../src-gen/com/microsoft/_FILETIME.java | 173 +++++ .../com/microsoft/_WIN32_FIND_DATAW.java | 607 ++++++++++++++++++ .../filesystem/local/Win32Handler.java | 213 +++--- 11 files changed, 1538 insertions(+), 134 deletions(-) create mode 100644 resources/bundles/org.eclipse.core.filesystem/generateWindowsH.bat create mode 100644 resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/FILETIME.java create mode 100644 resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/WIN32_FIND_DATAW.java create mode 100644 resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows$shared.java create mode 100644 resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows.java create mode 100644 resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_FILETIME.java create mode 100644 resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_WIN32_FIND_DATAW.java diff --git a/resources/bundles/org.eclipse.core.filesystem/.classpath b/resources/bundles/org.eclipse.core.filesystem/.classpath index 81fe078c20c..574d0f264e9 100644 --- a/resources/bundles/org.eclipse.core.filesystem/.classpath +++ b/resources/bundles/org.eclipse.core.filesystem/.classpath @@ -1,7 +1,8 @@ - + + diff --git a/resources/bundles/org.eclipse.core.filesystem/.settings/org.eclipse.jdt.core.prefs b/resources/bundles/org.eclipse.core.filesystem/.settings/org.eclipse.jdt.core.prefs index 3502cb6bd9f..d424094b9e5 100644 --- a/resources/bundles/org.eclipse.core.filesystem/.settings/org.eclipse.jdt.core.prefs +++ b/resources/bundles/org.eclipse.core.filesystem/.settings/org.eclipse.jdt.core.prefs @@ -17,9 +17,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=25 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.compliance=25 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -73,7 +73,7 @@ org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning -org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error org.eclipse.jdt.core.compiler.problem.nullReference=warning @@ -112,7 +112,7 @@ org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExcepti org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore -org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedImport=warning org.eclipse.jdt.core.compiler.problem.unusedLabel=warning org.eclipse.jdt.core.compiler.problem.unusedLocal=error org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore @@ -125,7 +125,7 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.source=25 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 diff --git a/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF index 5bea0c13567..c3663d48d11 100644 --- a/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF +++ b/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.core.filesystem; singleton:=true -Bundle-Version: 1.11.500.qualifier +Bundle-Version: 1.12.0.qualifier Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)" Export-Package: org.eclipse.core.filesystem;uses:="org.eclipse.core.runtime", @@ -11,7 +11,7 @@ Export-Package: org.eclipse.core.filesystem;uses:="org.eclipse.core.runtime", org.eclipse.core.internal.filesystem.local;x-internal:=true, org.eclipse.core.internal.filesystem.local.unix;x-internal:=true Bundle-Vendor: %providerName -Bundle-RequiredExecutionEnvironment: JavaSE-17 +Bundle-RequiredExecutionEnvironment: JavaSE-25 Bundle-ActivationPolicy: lazy Automatic-Module-Name: org.eclipse.core.filesystem Import-Package: com.sun.jna;version="[5.14.0,6.0.0)", diff --git a/resources/bundles/org.eclipse.core.filesystem/generateWindowsH.bat b/resources/bundles/org.eclipse.core.filesystem/generateWindowsH.bat new file mode 100644 index 00000000000..a807b7da04d --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/generateWindowsH.bat @@ -0,0 +1,34 @@ + +set "MSVC_HOME=C:\Program Files\Microsoft Visual Studio\2022\Community" +call "%MSVC_HOME%\VC\Auxiliary\Build\vcvarsall.bat" x64 + +@echo on + +jextract --output src-gen ^ + --include-function GetLastError ^ + --include-function GetShortPathNameW ^ + --include-function GetFileAttributesW ^ + --include-function SetFileAttributesW ^ + --include-function FindFirstFileW ^ + --include-function FindClose ^ + --include-typedef WIN32_FIND_DATAW ^ + --include-struct _WIN32_FIND_DATAW ^ + --include-typedef FILETIME ^ + --include-struct _FILETIME ^ + --include-constant MAXDWORD ^ + --include-constant FILE_ATTRIBUTE_NORMAL ^ + --include-constant FILE_ATTRIBUTE_ARCHIVE ^ + --include-constant FILE_ATTRIBUTE_READONLY ^ + --include-constant FILE_ATTRIBUTE_HIDDEN ^ + --include-constant FILE_ATTRIBUTE_DIRECTORY ^ + --include-constant FILE_ATTRIBUTE_REPARSE_POINT ^ + --include-constant IO_REPARSE_TAG_SYMLINK ^ + --include-constant INVALID_FILE_ATTRIBUTES ^ + --include-constant INVALID_HANDLE_VALUE ^ + --include-constant ERROR_FILE_NOT_FOUND ^ + --include-constant ERROR_PATH_NOT_FOUND ^ + --target-package com.microsoft ^ + --header-class-name Windows ^ + --library kernel32 ^ + --include-dir "%INCLUDE%" ^ + "Windows.h" diff --git a/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/FILETIME.java b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/FILETIME.java new file mode 100644 index 00000000000..1a82a08b7b1 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/FILETIME.java @@ -0,0 +1,29 @@ +// Generated by jextract + +package com.microsoft; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +/** + * {@snippet lang=c : + * typedef struct _FILETIME { + * DWORD dwLowDateTime; + * DWORD dwHighDateTime; + * } FILETIME + * } + */ +public class FILETIME extends _FILETIME { + + FILETIME() { + // Should not be called directly + } +} + diff --git a/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/WIN32_FIND_DATAW.java b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/WIN32_FIND_DATAW.java new file mode 100644 index 00000000000..ab6d61b5572 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/WIN32_FIND_DATAW.java @@ -0,0 +1,37 @@ +// Generated by jextract + +package com.microsoft; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +/** + * {@snippet lang=c : + * typedef struct _WIN32_FIND_DATAW { + * DWORD dwFileAttributes; + * FILETIME ftCreationTime; + * FILETIME ftLastAccessTime; + * FILETIME ftLastWriteTime; + * DWORD nFileSizeHigh; + * DWORD nFileSizeLow; + * DWORD dwReserved0; + * DWORD dwReserved1; + * WCHAR cFileName[260]; + * WCHAR cAlternateFileName[14]; + * } WIN32_FIND_DATAW + * } + */ +public class WIN32_FIND_DATAW extends _WIN32_FIND_DATAW { + + WIN32_FIND_DATAW() { + // Should not be called directly + } +} + diff --git a/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows$shared.java b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows$shared.java new file mode 100644 index 00000000000..4c2f7f63f4e --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows$shared.java @@ -0,0 +1,64 @@ +// Generated by jextract + +package com.microsoft; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class Windows$shared { + + Windows$shared() { + // Should not be called directly + } + + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + public static final ValueLayout.OfInt C_LONG = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("long"); + public static final ValueLayout.OfDouble C_LONG_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} + diff --git a/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows.java b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows.java new file mode 100644 index 00000000000..aeb9215b76b --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/Windows.java @@ -0,0 +1,498 @@ +// Generated by jextract + +package com.microsoft; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +public class Windows extends Windows$shared { + + Windows() { + // Should not be called directly + } + + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.libraryLookup(System.mapLibraryName("kernel32"), LIBRARY_ARENA) + .or(SymbolLookup.loaderLookup()) + .or(Linker.nativeLinker().defaultLookup()); + + private static final int FILE_ATTRIBUTE_READONLY = (int)1L; + /** + * {@snippet lang=c : + * #define FILE_ATTRIBUTE_READONLY 1 + * } + */ + public static int FILE_ATTRIBUTE_READONLY() { + return FILE_ATTRIBUTE_READONLY; + } + private static final int FILE_ATTRIBUTE_HIDDEN = (int)2L; + /** + * {@snippet lang=c : + * #define FILE_ATTRIBUTE_HIDDEN 2 + * } + */ + public static int FILE_ATTRIBUTE_HIDDEN() { + return FILE_ATTRIBUTE_HIDDEN; + } + private static final int FILE_ATTRIBUTE_DIRECTORY = (int)16L; + /** + * {@snippet lang=c : + * #define FILE_ATTRIBUTE_DIRECTORY 16 + * } + */ + public static int FILE_ATTRIBUTE_DIRECTORY() { + return FILE_ATTRIBUTE_DIRECTORY; + } + private static final int FILE_ATTRIBUTE_ARCHIVE = (int)32L; + /** + * {@snippet lang=c : + * #define FILE_ATTRIBUTE_ARCHIVE 32 + * } + */ + public static int FILE_ATTRIBUTE_ARCHIVE() { + return FILE_ATTRIBUTE_ARCHIVE; + } + private static final int FILE_ATTRIBUTE_NORMAL = (int)128L; + /** + * {@snippet lang=c : + * #define FILE_ATTRIBUTE_NORMAL 128 + * } + */ + public static int FILE_ATTRIBUTE_NORMAL() { + return FILE_ATTRIBUTE_NORMAL; + } + private static final int FILE_ATTRIBUTE_REPARSE_POINT = (int)1024L; + /** + * {@snippet lang=c : + * #define FILE_ATTRIBUTE_REPARSE_POINT 1024 + * } + */ + public static int FILE_ATTRIBUTE_REPARSE_POINT() { + return FILE_ATTRIBUTE_REPARSE_POINT; + } + + private static class FindClose { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Windows.C_INT, + Windows.C_POINTER + ); + + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("FindClose"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * BOOL FindClose(HANDLE hFindFile) + * } + */ + public static FunctionDescriptor FindClose$descriptor() { + return FindClose.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * BOOL FindClose(HANDLE hFindFile) + * } + */ + public static MethodHandle FindClose$handle() { + return FindClose.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * BOOL FindClose(HANDLE hFindFile) + * } + */ + public static MemorySegment FindClose$address() { + return FindClose.ADDR; + } + + /** + * {@snippet lang=c : + * BOOL FindClose(HANDLE hFindFile) + * } + */ + public static int FindClose(MemorySegment hFindFile) { + var mh$ = FindClose.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("FindClose", hFindFile); + } + return (int)mh$.invokeExact(hFindFile); + } catch (Error | RuntimeException ex) { + throw ex; + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class FindFirstFileW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Windows.C_POINTER, + Windows.C_POINTER, + Windows.C_POINTER + ); + + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("FindFirstFileW"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) + * } + */ + public static FunctionDescriptor FindFirstFileW$descriptor() { + return FindFirstFileW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) + * } + */ + public static MethodHandle FindFirstFileW$handle() { + return FindFirstFileW.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) + * } + */ + public static MemorySegment FindFirstFileW$address() { + return FindFirstFileW.ADDR; + } + + /** + * {@snippet lang=c : + * HANDLE FindFirstFileW(LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) + * } + */ + public static MemorySegment FindFirstFileW(MemorySegment lpFileName, MemorySegment lpFindFileData) { + var mh$ = FindFirstFileW.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("FindFirstFileW", lpFileName, lpFindFileData); + } + return (MemorySegment)mh$.invokeExact(lpFileName, lpFindFileData); + } catch (Error | RuntimeException ex) { + throw ex; + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class GetFileAttributesW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Windows.C_LONG, + Windows.C_POINTER + ); + + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("GetFileAttributesW"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * DWORD GetFileAttributesW(LPCWSTR lpFileName) + * } + */ + public static FunctionDescriptor GetFileAttributesW$descriptor() { + return GetFileAttributesW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * DWORD GetFileAttributesW(LPCWSTR lpFileName) + * } + */ + public static MethodHandle GetFileAttributesW$handle() { + return GetFileAttributesW.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * DWORD GetFileAttributesW(LPCWSTR lpFileName) + * } + */ + public static MemorySegment GetFileAttributesW$address() { + return GetFileAttributesW.ADDR; + } + + /** + * {@snippet lang=c : + * DWORD GetFileAttributesW(LPCWSTR lpFileName) + * } + */ + public static int GetFileAttributesW(MemorySegment lpFileName) { + var mh$ = GetFileAttributesW.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("GetFileAttributesW", lpFileName); + } + return (int)mh$.invokeExact(lpFileName); + } catch (Error | RuntimeException ex) { + throw ex; + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class GetShortPathNameW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Windows.C_LONG, + Windows.C_POINTER, + Windows.C_POINTER, + Windows.C_LONG + ); + + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("GetShortPathNameW"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * DWORD GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer) + * } + */ + public static FunctionDescriptor GetShortPathNameW$descriptor() { + return GetShortPathNameW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * DWORD GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer) + * } + */ + public static MethodHandle GetShortPathNameW$handle() { + return GetShortPathNameW.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * DWORD GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer) + * } + */ + public static MemorySegment GetShortPathNameW$address() { + return GetShortPathNameW.ADDR; + } + + /** + * {@snippet lang=c : + * DWORD GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer) + * } + */ + public static int GetShortPathNameW(MemorySegment lpszLongPath, MemorySegment lpszShortPath, int cchBuffer) { + var mh$ = GetShortPathNameW.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("GetShortPathNameW", lpszLongPath, lpszShortPath, cchBuffer); + } + return (int)mh$.invokeExact(lpszLongPath, lpszShortPath, cchBuffer); + } catch (Error | RuntimeException ex) { + throw ex; + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class SetFileAttributesW { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Windows.C_INT, + Windows.C_POINTER, + Windows.C_LONG + ); + + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("SetFileAttributesW"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) + * } + */ + public static FunctionDescriptor SetFileAttributesW$descriptor() { + return SetFileAttributesW.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) + * } + */ + public static MethodHandle SetFileAttributesW$handle() { + return SetFileAttributesW.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) + * } + */ + public static MemorySegment SetFileAttributesW$address() { + return SetFileAttributesW.ADDR; + } + + /** + * {@snippet lang=c : + * BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) + * } + */ + public static int SetFileAttributesW(MemorySegment lpFileName, int dwFileAttributes) { + var mh$ = SetFileAttributesW.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("SetFileAttributesW", lpFileName, dwFileAttributes); + } + return (int)mh$.invokeExact(lpFileName, dwFileAttributes); + } catch (Error | RuntimeException ex) { + throw ex; + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class GetLastError { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + Windows.C_LONG ); + + public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("GetLastError"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * DWORD GetLastError() + * } + */ + public static FunctionDescriptor GetLastError$descriptor() { + return GetLastError.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * DWORD GetLastError() + * } + */ + public static MethodHandle GetLastError$handle() { + return GetLastError.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * DWORD GetLastError() + * } + */ + public static MemorySegment GetLastError$address() { + return GetLastError.ADDR; + } + + /** + * {@snippet lang=c : + * DWORD GetLastError() + * } + */ + public static int GetLastError() { + var mh$ = GetLastError.HANDLE; + try { + if (TRACE_DOWNCALLS) { + traceDowncall("GetLastError"); + } + return (int)mh$.invokeExact(); + } catch (Error | RuntimeException ex) { + throw ex; + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + private static final int MAXDWORD = (int)4294967295L; + /** + * {@snippet lang=c : + * #define MAXDWORD 4294967295 + * } + */ + public static int MAXDWORD() { + return MAXDWORD; + } + private static final int IO_REPARSE_TAG_SYMLINK = (int)2684354572L; + /** + * {@snippet lang=c : + * #define IO_REPARSE_TAG_SYMLINK 2684354572 + * } + */ + public static int IO_REPARSE_TAG_SYMLINK() { + return IO_REPARSE_TAG_SYMLINK; + } + private static final int INVALID_FILE_ATTRIBUTES = (int)4294967295L; + /** + * {@snippet lang=c : + * #define INVALID_FILE_ATTRIBUTES 4294967295 + * } + */ + public static int INVALID_FILE_ATTRIBUTES() { + return INVALID_FILE_ATTRIBUTES; + } + private static final MemorySegment INVALID_HANDLE_VALUE = MemorySegment.ofAddress(-1L); + /** + * {@snippet lang=c : + * #define INVALID_HANDLE_VALUE (void*) -1 + * } + */ + public static MemorySegment INVALID_HANDLE_VALUE() { + return INVALID_HANDLE_VALUE; + } + private static final int ERROR_FILE_NOT_FOUND = (int)2L; + /** + * {@snippet lang=c : + * #define ERROR_FILE_NOT_FOUND 2 + * } + */ + public static int ERROR_FILE_NOT_FOUND() { + return ERROR_FILE_NOT_FOUND; + } + private static final int ERROR_PATH_NOT_FOUND = (int)3L; + /** + * {@snippet lang=c : + * #define ERROR_PATH_NOT_FOUND 3 + * } + */ + public static int ERROR_PATH_NOT_FOUND() { + return ERROR_PATH_NOT_FOUND; + } +} + diff --git a/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_FILETIME.java b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_FILETIME.java new file mode 100644 index 00000000000..4bb2990216c --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_FILETIME.java @@ -0,0 +1,173 @@ +// Generated by jextract + +package com.microsoft; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +/** + * {@snippet lang=c : + * struct _FILETIME { + * DWORD dwLowDateTime; + * DWORD dwHighDateTime; + * } + * } + */ +public class _FILETIME { + + _FILETIME() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + Windows.C_LONG.withName("dwLowDateTime"), + Windows.C_LONG.withName("dwHighDateTime") + ).withName("_FILETIME"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt dwLowDateTime$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dwLowDateTime")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dwLowDateTime + * } + */ + public static final OfInt dwLowDateTime$layout() { + return dwLowDateTime$LAYOUT; + } + + private static final long dwLowDateTime$OFFSET = $LAYOUT.byteOffset(groupElement("dwLowDateTime")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dwLowDateTime + * } + */ + public static final long dwLowDateTime$offset() { + return dwLowDateTime$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD dwLowDateTime + * } + */ + public static int dwLowDateTime(MemorySegment struct) { + return struct.get(dwLowDateTime$LAYOUT, dwLowDateTime$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD dwLowDateTime + * } + */ + public static void dwLowDateTime(MemorySegment struct, int fieldValue) { + struct.set(dwLowDateTime$LAYOUT, dwLowDateTime$OFFSET, fieldValue); + } + + private static final OfInt dwHighDateTime$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dwHighDateTime")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dwHighDateTime + * } + */ + public static final OfInt dwHighDateTime$layout() { + return dwHighDateTime$LAYOUT; + } + + private static final long dwHighDateTime$OFFSET = $LAYOUT.byteOffset(groupElement("dwHighDateTime")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dwHighDateTime + * } + */ + public static final long dwHighDateTime$offset() { + return dwHighDateTime$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD dwHighDateTime + * } + */ + public static int dwHighDateTime(MemorySegment struct) { + return struct.get(dwHighDateTime$LAYOUT, dwHighDateTime$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD dwHighDateTime + * } + */ + public static void dwHighDateTime(MemorySegment struct, int fieldValue) { + struct.set(dwHighDateTime$LAYOUT, dwHighDateTime$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_WIN32_FIND_DATAW.java b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_WIN32_FIND_DATAW.java new file mode 100644 index 00000000000..7c5a504e245 --- /dev/null +++ b/resources/bundles/org.eclipse.core.filesystem/src-gen/com/microsoft/_WIN32_FIND_DATAW.java @@ -0,0 +1,607 @@ +// Generated by jextract + +package com.microsoft; + +import java.lang.invoke.*; +import java.lang.foreign.*; +import java.nio.ByteOrder; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import static java.lang.foreign.ValueLayout.*; +import static java.lang.foreign.MemoryLayout.PathElement.*; + +/** + * {@snippet lang=c : + * struct _WIN32_FIND_DATAW { + * DWORD dwFileAttributes; + * FILETIME ftCreationTime; + * FILETIME ftLastAccessTime; + * FILETIME ftLastWriteTime; + * DWORD nFileSizeHigh; + * DWORD nFileSizeLow; + * DWORD dwReserved0; + * DWORD dwReserved1; + * WCHAR cFileName[260]; + * WCHAR cAlternateFileName[14]; + * } + * } + */ +public class _WIN32_FIND_DATAW { + + _WIN32_FIND_DATAW() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + Windows.C_LONG.withName("dwFileAttributes"), + _FILETIME.layout().withName("ftCreationTime"), + _FILETIME.layout().withName("ftLastAccessTime"), + _FILETIME.layout().withName("ftLastWriteTime"), + Windows.C_LONG.withName("nFileSizeHigh"), + Windows.C_LONG.withName("nFileSizeLow"), + Windows.C_LONG.withName("dwReserved0"), + Windows.C_LONG.withName("dwReserved1"), + MemoryLayout.sequenceLayout(260, Windows.C_SHORT).withName("cFileName"), + MemoryLayout.sequenceLayout(14, Windows.C_SHORT).withName("cAlternateFileName") + ).withName("_WIN32_FIND_DATAW"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfInt dwFileAttributes$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dwFileAttributes")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dwFileAttributes + * } + */ + public static final OfInt dwFileAttributes$layout() { + return dwFileAttributes$LAYOUT; + } + + private static final long dwFileAttributes$OFFSET = $LAYOUT.byteOffset(groupElement("dwFileAttributes")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dwFileAttributes + * } + */ + public static final long dwFileAttributes$offset() { + return dwFileAttributes$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD dwFileAttributes + * } + */ + public static int dwFileAttributes(MemorySegment struct) { + return struct.get(dwFileAttributes$LAYOUT, dwFileAttributes$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD dwFileAttributes + * } + */ + public static void dwFileAttributes(MemorySegment struct, int fieldValue) { + struct.set(dwFileAttributes$LAYOUT, dwFileAttributes$OFFSET, fieldValue); + } + + private static final GroupLayout ftCreationTime$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("ftCreationTime")); + + /** + * Layout for field: + * {@snippet lang=c : + * FILETIME ftCreationTime + * } + */ + public static final GroupLayout ftCreationTime$layout() { + return ftCreationTime$LAYOUT; + } + + private static final long ftCreationTime$OFFSET = $LAYOUT.byteOffset(groupElement("ftCreationTime")); + + /** + * Offset for field: + * {@snippet lang=c : + * FILETIME ftCreationTime + * } + */ + public static final long ftCreationTime$offset() { + return ftCreationTime$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * FILETIME ftCreationTime + * } + */ + public static MemorySegment ftCreationTime(MemorySegment struct) { + return struct.asSlice(ftCreationTime$OFFSET, ftCreationTime$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * FILETIME ftCreationTime + * } + */ + public static void ftCreationTime(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, ftCreationTime$OFFSET, ftCreationTime$LAYOUT.byteSize()); + } + + private static final GroupLayout ftLastAccessTime$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("ftLastAccessTime")); + + /** + * Layout for field: + * {@snippet lang=c : + * FILETIME ftLastAccessTime + * } + */ + public static final GroupLayout ftLastAccessTime$layout() { + return ftLastAccessTime$LAYOUT; + } + + private static final long ftLastAccessTime$OFFSET = $LAYOUT.byteOffset(groupElement("ftLastAccessTime")); + + /** + * Offset for field: + * {@snippet lang=c : + * FILETIME ftLastAccessTime + * } + */ + public static final long ftLastAccessTime$offset() { + return ftLastAccessTime$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * FILETIME ftLastAccessTime + * } + */ + public static MemorySegment ftLastAccessTime(MemorySegment struct) { + return struct.asSlice(ftLastAccessTime$OFFSET, ftLastAccessTime$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * FILETIME ftLastAccessTime + * } + */ + public static void ftLastAccessTime(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, ftLastAccessTime$OFFSET, ftLastAccessTime$LAYOUT.byteSize()); + } + + private static final GroupLayout ftLastWriteTime$LAYOUT = (GroupLayout)$LAYOUT.select(groupElement("ftLastWriteTime")); + + /** + * Layout for field: + * {@snippet lang=c : + * FILETIME ftLastWriteTime + * } + */ + public static final GroupLayout ftLastWriteTime$layout() { + return ftLastWriteTime$LAYOUT; + } + + private static final long ftLastWriteTime$OFFSET = $LAYOUT.byteOffset(groupElement("ftLastWriteTime")); + + /** + * Offset for field: + * {@snippet lang=c : + * FILETIME ftLastWriteTime + * } + */ + public static final long ftLastWriteTime$offset() { + return ftLastWriteTime$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * FILETIME ftLastWriteTime + * } + */ + public static MemorySegment ftLastWriteTime(MemorySegment struct) { + return struct.asSlice(ftLastWriteTime$OFFSET, ftLastWriteTime$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * FILETIME ftLastWriteTime + * } + */ + public static void ftLastWriteTime(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, ftLastWriteTime$OFFSET, ftLastWriteTime$LAYOUT.byteSize()); + } + + private static final OfInt nFileSizeHigh$LAYOUT = (OfInt)$LAYOUT.select(groupElement("nFileSizeHigh")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD nFileSizeHigh + * } + */ + public static final OfInt nFileSizeHigh$layout() { + return nFileSizeHigh$LAYOUT; + } + + private static final long nFileSizeHigh$OFFSET = $LAYOUT.byteOffset(groupElement("nFileSizeHigh")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD nFileSizeHigh + * } + */ + public static final long nFileSizeHigh$offset() { + return nFileSizeHigh$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD nFileSizeHigh + * } + */ + public static int nFileSizeHigh(MemorySegment struct) { + return struct.get(nFileSizeHigh$LAYOUT, nFileSizeHigh$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD nFileSizeHigh + * } + */ + public static void nFileSizeHigh(MemorySegment struct, int fieldValue) { + struct.set(nFileSizeHigh$LAYOUT, nFileSizeHigh$OFFSET, fieldValue); + } + + private static final OfInt nFileSizeLow$LAYOUT = (OfInt)$LAYOUT.select(groupElement("nFileSizeLow")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD nFileSizeLow + * } + */ + public static final OfInt nFileSizeLow$layout() { + return nFileSizeLow$LAYOUT; + } + + private static final long nFileSizeLow$OFFSET = $LAYOUT.byteOffset(groupElement("nFileSizeLow")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD nFileSizeLow + * } + */ + public static final long nFileSizeLow$offset() { + return nFileSizeLow$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD nFileSizeLow + * } + */ + public static int nFileSizeLow(MemorySegment struct) { + return struct.get(nFileSizeLow$LAYOUT, nFileSizeLow$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD nFileSizeLow + * } + */ + public static void nFileSizeLow(MemorySegment struct, int fieldValue) { + struct.set(nFileSizeLow$LAYOUT, nFileSizeLow$OFFSET, fieldValue); + } + + private static final OfInt dwReserved0$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dwReserved0")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dwReserved0 + * } + */ + public static final OfInt dwReserved0$layout() { + return dwReserved0$LAYOUT; + } + + private static final long dwReserved0$OFFSET = $LAYOUT.byteOffset(groupElement("dwReserved0")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dwReserved0 + * } + */ + public static final long dwReserved0$offset() { + return dwReserved0$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD dwReserved0 + * } + */ + public static int dwReserved0(MemorySegment struct) { + return struct.get(dwReserved0$LAYOUT, dwReserved0$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD dwReserved0 + * } + */ + public static void dwReserved0(MemorySegment struct, int fieldValue) { + struct.set(dwReserved0$LAYOUT, dwReserved0$OFFSET, fieldValue); + } + + private static final OfInt dwReserved1$LAYOUT = (OfInt)$LAYOUT.select(groupElement("dwReserved1")); + + /** + * Layout for field: + * {@snippet lang=c : + * DWORD dwReserved1 + * } + */ + public static final OfInt dwReserved1$layout() { + return dwReserved1$LAYOUT; + } + + private static final long dwReserved1$OFFSET = $LAYOUT.byteOffset(groupElement("dwReserved1")); + + /** + * Offset for field: + * {@snippet lang=c : + * DWORD dwReserved1 + * } + */ + public static final long dwReserved1$offset() { + return dwReserved1$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * DWORD dwReserved1 + * } + */ + public static int dwReserved1(MemorySegment struct) { + return struct.get(dwReserved1$LAYOUT, dwReserved1$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * DWORD dwReserved1 + * } + */ + public static void dwReserved1(MemorySegment struct, int fieldValue) { + struct.set(dwReserved1$LAYOUT, dwReserved1$OFFSET, fieldValue); + } + + private static final SequenceLayout cFileName$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("cFileName")); + + /** + * Layout for field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static final SequenceLayout cFileName$layout() { + return cFileName$LAYOUT; + } + + private static final long cFileName$OFFSET = $LAYOUT.byteOffset(groupElement("cFileName")); + + /** + * Offset for field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static final long cFileName$offset() { + return cFileName$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static MemorySegment cFileName(MemorySegment struct) { + return struct.asSlice(cFileName$OFFSET, cFileName$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static void cFileName(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, cFileName$OFFSET, cFileName$LAYOUT.byteSize()); + } + + private static long[] cFileName$DIMS = { 260 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static long[] cFileName$dimensions() { + return cFileName$DIMS; + } + private static final VarHandle cFileName$ELEM_HANDLE = cFileName$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static short cFileName(MemorySegment struct, long index0) { + return (short)cFileName$ELEM_HANDLE.get(struct, cFileName$OFFSET, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * WCHAR cFileName[260] + * } + */ + public static void cFileName(MemorySegment struct, long index0, short fieldValue) { + cFileName$ELEM_HANDLE.set(struct, cFileName$OFFSET, index0, fieldValue); + } + + private static final SequenceLayout cAlternateFileName$LAYOUT = (SequenceLayout)$LAYOUT.select(groupElement("cAlternateFileName")); + + /** + * Layout for field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static final SequenceLayout cAlternateFileName$layout() { + return cAlternateFileName$LAYOUT; + } + + private static final long cAlternateFileName$OFFSET = $LAYOUT.byteOffset(groupElement("cAlternateFileName")); + + /** + * Offset for field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static final long cAlternateFileName$offset() { + return cAlternateFileName$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static MemorySegment cAlternateFileName(MemorySegment struct) { + return struct.asSlice(cAlternateFileName$OFFSET, cAlternateFileName$LAYOUT.byteSize()); + } + + /** + * Setter for field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static void cAlternateFileName(MemorySegment struct, MemorySegment fieldValue) { + MemorySegment.copy(fieldValue, 0L, struct, cAlternateFileName$OFFSET, cAlternateFileName$LAYOUT.byteSize()); + } + + private static long[] cAlternateFileName$DIMS = { 14 }; + + /** + * Dimensions for array field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static long[] cAlternateFileName$dimensions() { + return cAlternateFileName$DIMS; + } + private static final VarHandle cAlternateFileName$ELEM_HANDLE = cAlternateFileName$LAYOUT.varHandle(sequenceElement()); + + /** + * Indexed getter for field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static short cAlternateFileName(MemorySegment struct, long index0) { + return (short)cAlternateFileName$ELEM_HANDLE.get(struct, cAlternateFileName$OFFSET, index0); + } + + /** + * Indexed setter for field: + * {@snippet lang=c : + * WCHAR cAlternateFileName[14] + * } + */ + public static void cAlternateFileName(MemorySegment struct, long index0, short fieldValue) { + cAlternateFileName$ELEM_HANDLE.set(struct, cAlternateFileName$OFFSET, index0, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} + diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/Win32Handler.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/Win32Handler.java index 30405005f3f..dc9f088f260 100644 --- a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/Win32Handler.java +++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/local/Win32Handler.java @@ -16,19 +16,20 @@ import static org.eclipse.core.internal.filesystem.local.Convert.WIN32_RAW_PATH_PREFIX; import static org.eclipse.core.internal.filesystem.local.Convert.WIN32_UNC_RAW_PATH_PREFIX; -import com.sun.jna.Memory; -import com.sun.jna.Native; -import com.sun.jna.NativeLibrary; -import com.sun.jna.Pointer; -import com.sun.jna.WString; -import com.sun.jna.platform.win32.WinBase; -import com.sun.jna.platform.win32.WinDef; -import com.sun.jna.platform.win32.WinError; -import com.sun.jna.platform.win32.WinNT; +import com.microsoft.Windows; +import com.microsoft._FILETIME; +import com.microsoft._WIN32_FIND_DATAW; import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Date; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.provider.FileInfo; @@ -46,6 +47,11 @@ public int getSupportedAttributes() { return ATTRIBUTES; } + public static void main(String[] args) { + FileInfo info = new Win32Handler().fetchFileInfo("C:\\Users\\Hannes\\Desktop\\java-21-25-news\\src\\main\\java\\news\\notExisting.txt"); //$NON-NLS-1$ + System.out.println(info); + } + @Override public FileInfo fetchFileInfo(String fileName) { FileInfo fileInfo = new FileInfo(); @@ -59,24 +65,23 @@ public FileInfo fetchFileInfo(String fileName) { fileInfo.setExists(Files.exists(Path.of(target.substring(WIN32_RAW_PATH_PREFIX.length())))); return fileInfo; } - - try (Memory mem = new Memory(WIN32_FIND_DATA_SIZE)) { - // Allocating (uninitialized) memory explicitly in advance is faster than using - // the slightly more convenient direct instantiation of a JNA WinBase.WIN32_FIND_DATA structure, - // probably because the latter perform also an initial autowrite and computes the size each time. - // For the same reason it is again faster to read the data-structure 'manually'. - long handle = FileAPIh.FindFirstFileW(new WString(target), mem); - if (handle == FileAPIh.INVALID_HANDLE_VALUE) { - int error = Native.getLastError(); - if (!(error == WinError.ERROR_FILE_NOT_FOUND // file not found in existing parent directory - || error == WinError.ERROR_PATH_NOT_FOUND)) { // Not even the parent directory exists + try (Arena arena = Arena.ofConfined()) { + MemorySegment lpFileName = arena.allocateFrom(target, StandardCharsets.UTF_16LE); + MemorySegment lpFindFileData = arena.allocate(_WIN32_FIND_DATAW.layout()); + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilew + MemorySegment handle = Windows.FindFirstFileW(lpFileName, lpFindFileData); + if (Windows.INVALID_HANDLE_VALUE().equals(handle)) { + int error = Windows.GetLastError(); + //TODO: does it at any time return something different than zero? + if (!(error == Windows.ERROR_FILE_NOT_FOUND() // file not found in existing parent directory + || error == Windows.ERROR_PATH_NOT_FOUND())) { // Not even the parent directory exists fileInfo.setError(IFileInfo.IO_ERROR); } return fileInfo; } - FileAPIh.FindClose(handle); + Windows.FindClose(handle); - convertFindDataWToFileInfo(mem, fileInfo, fileName); + convertFindDataWToFileInfo(lpFindFileData, fileInfo, fileName); } catch (IOException e) { // Leave alone and continue. The name is set before an IOException can be thrown fileInfo.setError(IFileInfo.IO_ERROR); @@ -86,41 +91,56 @@ public FileInfo fetchFileInfo(String fileName) { @Override public boolean putFileInfo(String fileName, IFileInfo info, int options) { - WString lpFileName = new WString(toLongWindowsPath(fileName)); - long dwFileAttributes = FileAPIh.GetFileAttributesW(lpFileName); - if (dwFileAttributes == FileAPIh.INVALID_FILE_ATTRIBUTES) { + int dwFileAttributes; + try (Arena arena = Arena.ofConfined()) { + MemorySegment lpFileName = arena.allocateFrom(toLongWindowsPath(fileName), StandardCharsets.UTF_16LE); + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesw + dwFileAttributes = Windows.GetFileAttributesW(lpFileName); + } + if (dwFileAttributes == Windows.INVALID_FILE_ATTRIBUTES()) { return false; } - if (dwFileAttributes == WinNT.FILE_ATTRIBUTE_NORMAL) { + if (dwFileAttributes == Windows.FILE_ATTRIBUTE_NORMAL()) { // Assume nothing is set, as the documentation of FILE_ATTRIBUTE_NORMAL states: // "A file that does not have other attributes set. This attribute is valid only when used alone." dwFileAttributes = 0; } - long fileAttributes = dwFileAttributes; + int fileAttributes = dwFileAttributes; boolean archive = info.getAttribute(EFS.ATTRIBUTE_ARCHIVE); boolean readOnly = info.getAttribute(EFS.ATTRIBUTE_READ_ONLY); boolean hidden = info.getAttribute(EFS.ATTRIBUTE_HIDDEN); - fileAttributes = set(fileAttributes, WinNT.FILE_ATTRIBUTE_ARCHIVE, archive); - fileAttributes = set(fileAttributes, WinNT.FILE_ATTRIBUTE_READONLY, readOnly); - fileAttributes = set(fileAttributes, WinNT.FILE_ATTRIBUTE_HIDDEN, hidden); + fileAttributes = set(fileAttributes, Windows.FILE_ATTRIBUTE_ARCHIVE(), archive); + fileAttributes = set(fileAttributes, Windows.FILE_ATTRIBUTE_READONLY(), readOnly); + fileAttributes = set(fileAttributes, Windows.FILE_ATTRIBUTE_HIDDEN(), hidden); if (dwFileAttributes == fileAttributes) { return true; // Everything is already up to date -> nothing to do } - return FileAPIh.SetFileAttributesW(lpFileName, fileAttributes); + //TODO: Combine arenas! + try (Arena arena = Arena.ofConfined()) { + MemorySegment lpFileName = arena.allocateFrom(toLongWindowsPath(fileName), StandardCharsets.UTF_16LE); + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesw + return Windows.SetFileAttributesW(lpFileName, fileAttributes) != 0; + } } public static String getShortPathName(String longPath) { longPath = toLongWindowsPath(longPath); - char[] buffer = new char[longPath.length()]; // https://learn.microsoft.com/de-de/windows/win32/api/fileapi/nf-fileapi-getshortpathnamew - int newLength = com.sun.jna.platform.win32.Kernel32.INSTANCE.GetShortPathName(longPath, buffer, buffer.length); - if (0 < newLength && newLength < buffer.length) { // zero means error - int offset = longPath.startsWith(WIN32_UNC_RAW_PATH_PREFIX) ? WIN32_UNC_RAW_PATH_PREFIX.length() : WIN32_RAW_PATH_PREFIX.length(); - return new String(buffer, offset, newLength - offset); + try (Arena arena = Arena.ofConfined()) { + MemorySegment lpszLongPath = arena.allocateFrom(longPath, StandardCharsets.UTF_16LE); + MemorySegment lpszShortPath = arena.allocate(lpszLongPath.byteSize()); + + int newLength = Windows.GetShortPathNameW(lpszLongPath, lpszShortPath, longPath.length()); + if (0 < newLength && newLength < longPath.length()) { // zero means error + int offset = longPath.startsWith(WIN32_UNC_RAW_PATH_PREFIX) ? WIN32_UNC_RAW_PATH_PREFIX.length() : WIN32_RAW_PATH_PREFIX.length(); + //TODO: Check this + return lpszShortPath.reinterpret(newLength * 2).getString(0, StandardCharsets.UTF_16LE).substring(offset); + } + return null; + } - return null; } private static String toLongWindowsPath(String fileName) { @@ -135,122 +155,63 @@ private static String toLongWindowsPath(String fileName) { return fileName; } - static class FileAPIh { - static { - Native.register(NativeLibrary.getInstance("Kernel32" /* , W32APIOptions.DEFAULT_OPTIONS */ )); //$NON-NLS-1$ - // Not using W32APIOptions.DEFAULT_OPTIONS requires the usage of a few special types (e.g. WString) but improves performance. - } - private static final long INVALID_HANDLE_VALUE = Pointer.nativeValue(WinBase.INVALID_HANDLE_VALUE.getPointer()); - - // winnt.h HANDLE can be expressed as java long - - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilew - static native long FindFirstFileW(WString lpFileName, Pointer lpFindFileData); - - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesw - static native long GetFileAttributesW(WString lpFileName); - - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesw - static native boolean SetFileAttributesW(WString lpFileName, long dwFileAttributes); - - static final long INVALID_FILE_ATTRIBUTES = new WinBase.DWORD(-1).longValue(); - - static native boolean FindClose(long handle); - } - - private static final int DWORD_SIZE = WinBase.DWORD.SIZE; - private static final int FILETIME_SIZE = 2 * DWORD_SIZE; - private static final int WCHAR_SIZE = 2; - - /** - * Read the of the native memory data-strcuture - * {@code WIN32_FIND_DATAW}. - *
-	 *	typedef struct _WIN32_FIND_DATAW {
-	 *		DWORD dwFileAttributes;
-	 *		FILETIME ftCreationTime;
-	 *		FILETIME ftLastAccessTime;
-	 *		FILETIME ftLastWriteTime;
-	 *		DWORD nFileSizeHigh;
-	 *		DWORD nFileSizeLow;
-	 *		DWORD dwReserved0;
-	 *		DWORD dwReserved1;
-	 *		_Field_z_ WCHAR  cFileName[ MAX_PATH ];
-	 *		_Field_z_ WCHAR  cAlternateFileName[ 14 ];
-	 *	} WIN32_FIND_DATAW
-	 * 
- */ - private static final int DW_FILE_ATTRIBUTES = 0; - private static final int FT_CREATION_TIME = DW_FILE_ATTRIBUTES + DWORD_SIZE; - private static final int FT_LAST_ACCESS_TIME = FT_CREATION_TIME + FILETIME_SIZE; - private static final int FT_LAST_WRITE_TIME = FT_LAST_ACCESS_TIME + FILETIME_SIZE; - private static final int N_FILE_SIZE_HIGH = FT_LAST_WRITE_TIME + FILETIME_SIZE; - private static final int N_FILE_SIZE_LOW = N_FILE_SIZE_HIGH + DWORD_SIZE; - private static final int DW_RESERVED_0 = N_FILE_SIZE_LOW + DWORD_SIZE; - private static final int DW_RESERVED_1 = DW_RESERVED_0 + DWORD_SIZE; - private static final int C_FILE_NAME = DW_RESERVED_1 + DWORD_SIZE; - private static final int C_ALTERNATE_FILE_NAME = C_FILE_NAME + WinDef.MAX_PATH * WCHAR_SIZE; - - private static final int WIN32_FIND_DATA_SIZE = C_ALTERNATE_FILE_NAME + 14 * WCHAR_SIZE; - static { - if (WIN32_FIND_DATA_SIZE != WinBase.WIN32_FIND_DATA.sizeOf()) { - throw new IllegalStateException("Struct 'WIN32_FIND_DATAW' has unexpected size"); //$NON-NLS-1$ - } - } private static final long MAXDWORD = 0xFFFFFFFFL; // unsigned long from winnt.h. On Windows a C long usually has only 32bit - private static void convertFindDataWToFileInfo(Memory mem, FileInfo info, String fileName) throws IOException { + private static void convertFindDataWToFileInfo(MemorySegment mem, FileInfo info, String fileName) throws IOException { /** * For possible values of dwFileAttributes and their descriptions, * see File Attribute Constants. */ - int dwFileAttributes = readDWORDAsSignedInt(mem, DW_FILE_ATTRIBUTES); - Date ftLastWriteTime = readFILETIME(mem, FT_LAST_WRITE_TIME); - long nFileSizeHigh = readDWORD(mem, N_FILE_SIZE_HIGH); - long nFileSizeLow = readDWORD(mem, N_FILE_SIZE_LOW); - int dwReserved0 = readDWORDAsSignedInt(mem, DW_RESERVED_0); - String cFileName = mem.getWideString(C_FILE_NAME); + + int dwFileAttributes = _WIN32_FIND_DATAW.dwFileAttributes(mem); + Instant ftLastWriteTime = readFILETIME(_WIN32_FIND_DATAW.ftLastWriteTime(mem)); + + int nFileSizeHigh = _WIN32_FIND_DATAW.nFileSizeHigh(mem); + int nFileSizeLow = _WIN32_FIND_DATAW.nFileSizeLow(mem); + int dwReserved0 = _WIN32_FIND_DATAW.dwReserved0(mem); + + String cFileName = _WIN32_FIND_DATAW.cFileName(mem).getString(0, StandardCharsets.UTF_16LE); long fileLength = (nFileSizeHigh * (MAXDWORD + 1)) + nFileSizeLow; + //TODO: check if equals! + fileLength = toLong(nFileSizeHigh, nFileSizeLow); info.setName(cFileName); info.setExists(true); - info.setLastModified(ftLastWriteTime.getTime()); + info.setLastModified(ftLastWriteTime.toEpochMilli()); info.setLength(fileLength); - info.setDirectory(isSet(dwFileAttributes, WinNT.FILE_ATTRIBUTE_DIRECTORY)); - info.setAttribute(EFS.ATTRIBUTE_ARCHIVE, isSet(dwFileAttributes, WinNT.FILE_ATTRIBUTE_ARCHIVE)); - info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, isSet(dwFileAttributes, WinNT.FILE_ATTRIBUTE_READONLY)); - info.setAttribute(EFS.ATTRIBUTE_HIDDEN, isSet(dwFileAttributes, WinNT.FILE_ATTRIBUTE_HIDDEN)); + info.setDirectory(isSet(dwFileAttributes, Windows.FILE_ATTRIBUTE_DIRECTORY())); + info.setAttribute(EFS.ATTRIBUTE_ARCHIVE, isSet(dwFileAttributes, Windows.FILE_ATTRIBUTE_ARCHIVE())); + info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, isSet(dwFileAttributes, Windows.FILE_ATTRIBUTE_READONLY())); + info.setAttribute(EFS.ATTRIBUTE_HIDDEN, isSet(dwFileAttributes, Windows.FILE_ATTRIBUTE_HIDDEN())); - boolean isReparsePoint = isSet(dwFileAttributes, WinNT.FILE_ATTRIBUTE_REPARSE_POINT); - if (isReparsePoint && dwReserved0 == WinNT.IO_REPARSE_TAG_SYMLINK) { + boolean isReparsePoint = isSet(dwFileAttributes, Windows.FILE_ATTRIBUTE_REPARSE_POINT()); + if (isReparsePoint && dwReserved0 == Windows.IO_REPARSE_TAG_SYMLINK()) { Path linkTarget = Files.readSymbolicLink(Path.of(fileName)); info.setAttribute(EFS.ATTRIBUTE_SYMLINK, true); info.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, linkTarget.toString()); } } - private static int readDWORDAsSignedInt(Memory memory, int offset) { - return memory.getInt(offset); // int is signed - } + private static final Instant WINDOWS_REFERENCE_DATE = LocalDateTime.of(1601, Month.JANUARY, 1, 0, 0).toInstant(ZoneOffset.UTC); - private static long readDWORD(Memory memory, int offset) { - // From https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types - // "DWORD - A 32-bit unsigned integer. The range is 0 through 4294967295 decimal. This type is declared in IntSafe.h as follows: typedef unsigned long DWORD;" - return readDWORDAsSignedInt(memory, offset) & MAXDWORD; + private static Instant readFILETIME(MemorySegment struct) { + int low = _FILETIME.dwLowDateTime(struct); + int high = _FILETIME.dwHighDateTime(struct); + final long filetime = toLong(high, low); + return WINDOWS_REFERENCE_DATE.plus(filetime / 10, ChronoUnit.MICROS); } + // See also https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types - private static Date readFILETIME(Memory memory, int offset) { - int low = readDWORDAsSignedInt(memory, offset); - int high = readDWORDAsSignedInt(memory, offset + DWORD_SIZE); - return WinBase.FILETIME.filetimeToDate(high, low); + private static long toLong(int high, int low) { + return (long) high << 32 | low & 0xffffffffL; } private static boolean isSet(long field, int bit) { return (field & bit) != 0; } - private long set(long field, int bit, boolean isSet) { + private int set(int field, int bit, boolean isSet) { return isSet ? (field | bit) : (field & ~bit); }