pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


DemoQueryAllocatedRanges.java
Posted by Anonymous on Thu 20th Feb 2025 11:48
raw | new post

  1.  
  2. /*
  3.  * run with
  4.  * $ java --enable-native-access DemoQueryAllocatedRanges -classpath . DemoQueryAllocatedRanges
  5.  * compile with:
  6.  * javac --enable-preview --add-modules java.base --release 23 DemoQueryAllocatedRanges.java
  7.  *
  8.  * Currently fails like this:
  9.  * ---- snip ----
  10.  * $ java --enable-native-access DemoQueryAllocatedRanges -classpath . DemoQueryAllocatedRanges
  11.  * WARNING: Unknown module: DemoQueryAllocatedRanges specified to --enable-native-access
  12.  * Running QueryAllocatedRanges for file: foo.bin
  13.  * Error running QueryAllocatedRanges:
  14.  * java.lang.ExceptionInInitializerError
  15.  *         at DemoQueryAllocatedRanges.main(DemoQueryAllocatedRanges.java:299)
  16.  * Caused by: java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: Function CreateFileW not found in library kernel32
  17.  *         at WindowsLinker.downcallHandle(DemoQueryAllocatedRanges.java:270)
  18.  *         at QueryAllocatedRanges.<clinit>(DemoQueryAllocatedRanges.java:77)
  19.  *         ... 1 more
  20.  * Caused by: java.lang.UnsatisfiedLinkError: Function CreateFileW not found in library kernel32
  21.  *         at WindowsLinker.lambda$downcallHandle$0(DemoQueryAllocatedRanges.java:263)
  22.  *         at java.base/java.util.Optional.orElseThrow(Optional.java:403)
  23.  *         at WindowsLinker.downcallHandle(DemoQueryAllocatedRanges.java:262)
  24.  *         ... 2 more
  25.  * Demo finished.
  26.  * ---- snip ----
  27.  */
  28.  
  29. import java.io.IOException;
  30. import java.lang.foreign.Arena;
  31. import java.lang.foreign.MemoryLayout;
  32. import java.lang.foreign.MemorySegment;
  33. import java.lang.foreign.ValueLayout;
  34. import java.nio.ByteBuffer;
  35. import java.nio.ByteOrder;
  36. import java.nio.CharBuffer;
  37. import java.nio.channels.FileChannel;
  38. import java.nio.file.Path;
  39. import java.nio.file.StandardOpenOption;
  40. import java.nio.charset.Charset;
  41. import java.nio.charset.StandardCharsets;
  42. import java.util.ArrayList;
  43. import java.util.List;
  44.  
  45. import static java.lang.foreign.ValueLayout.ADDRESS;
  46. import static java.lang.foreign.ValueLayout.JAVA_LONG;
  47. import static java.lang.foreign.ValueLayout.JAVA_INT;
  48. import static java.lang.foreign.ValueLayout.JAVA_BYTE;
  49. import static java.lang.foreign.MemoryLayout.PathElement; // Import PathElement
  50.  
  51. /* needed for demo code */
  52. import java.io.IOException;
  53. import java.nio.file.Files;
  54. import java.nio.file.Path;
  55. import java.nio.file.Paths;
  56.  
  57. /* public */ class QueryAllocatedRanges {
  58.  
  59.     // Define FSCTL_QUERY_ALLOCATED_RANGES control code
  60.     private static final int FILE_DEVICE_FILE_SYSTEM = 0x00000009;
  61.     private static final int METHOD_BUFFERED = 0;
  62.     private static final int FILE_ANY_ACCESS = 0;
  63.     private static final int FSCTL_QUERY_ALLOCATED_RANGES = (FILE_DEVICE_FILE_SYSTEM << 16) | (FILE_ANY_ACCESS << 14) | (51 << 2) | METHOD_BUFFERED;
  64.  
  65.     // Define FILE_ATTRIBUTE_NORMAL for CreateFile
  66.     private static final int FILE_ATTRIBUTE_NORMAL = 0x00000080;
  67.     // Define GENERIC_READ for CreateFile
  68.     private static final int GENERIC_READ = 0x80000000;
  69.     // Define GENERIC_WRITE for CreateFile - not needed for this FSCTL but might be needed for others
  70.     private static final int GENERIC_WRITE = 0x40000000;
  71.     // Define OPEN_EXISTING for CreateFile
  72.     private static final int OPEN_EXISTING = 3;
  73.     // Define INVALID_HANDLE_VALUE
  74.     private static final long INVALID_HANDLE_VALUE = -1;
  75.  
  76.     // Define constants for Windows API functions and structs using Foreign Function and Memory API
  77.  
  78.     // HANDLE CreateFileW(
  79.     //   LPCWSTR               lpFileName,
  80.     //   DWORD                 dwDesiredAccess,
  81.     //   DWORD                 dwShareMode,
  82.     //   LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  83.     //   DWORD                 dwCreationDisposition,
  84.     //   DWORD                 dwFlagsAndAttributes,
  85.     //   HANDLE                hTemplateFile
  86.     // );
  87.     private static final java.lang.foreign.FunctionDescriptor CreateFileWDescriptor = java.lang.foreign.FunctionDescriptor.of(
  88.             ADDRESS, // HANDLE
  89.             ADDRESS, // LPCWSTR lpFileName
  90.             JAVA_INT, // DWORD dwDesiredAccess
  91.             JAVA_INT, // DWORD dwShareMode
  92.             ADDRESS, // LPSECURITY_ATTRIBUTES lpSecurityAttributes
  93.             JAVA_INT, // DWORD dwCreationDisposition
  94.             JAVA_INT, // DWORD dwFlagsAndAttributes
  95.             ADDRESS  // HANDLE hTemplateFile
  96.     );
  97.     private static final java.lang.invoke.MethodHandle CreateFileW = WindowsLinker.downcallHandle(
  98.             "kernel32", "CreateFileW", CreateFileWDescriptor
  99.     );
  100.  
  101.     // BOOL DeviceIoControl(
  102.     //   HANDLE                 hDevice,
  103.     //   DWORD                  dwIoControlCode,
  104.     //   LPVOID                 lpInBuffer,
  105.     //   DWORD                  nInBufferSize,
  106.     //   LPVOID                 lpOutBuffer,
  107.     //   DWORD                  nOutBufferSize,
  108.     //   LPDWORD                lpBytesReturned,
  109.     //   LPOVERLAPPED             lpOverlapped
  110.     // );
  111.     private static final java.lang.foreign.FunctionDescriptor DeviceIoControlDescriptor = java.lang.foreign.FunctionDescriptor.of(
  112.             JAVA_INT, // BOOL
  113.             ADDRESS, // HANDLE hDevice
  114.             JAVA_INT, // DWORD dwIoControlCode
  115.             ADDRESS, // LPVOID lpInBuffer
  116.             JAVA_INT, // DWORD nInBufferSize
  117.             ADDRESS, // LPVOID lpOutBuffer
  118.             JAVA_INT, // DWORD nOutBufferSize
  119.             ADDRESS, // LPDWORD lpBytesReturned
  120.             ADDRESS  // LPOVERLAPPED lpOverlapped
  121.     );
  122.     private static final java.lang.invoke.MethodHandle DeviceIoControl = WindowsLinker.downcallHandle(
  123.             "kernel32.dll", "DeviceIoControl", DeviceIoControlDescriptor
  124.     );
  125.  
  126.     // BOOL CloseHandle(
  127.     //   HANDLE hObject
  128.     // );
  129.     private static final java.lang.foreign.FunctionDescriptor CloseHandleDescriptor = java.lang.foreign.FunctionDescriptor.of(
  130.             JAVA_INT, // BOOL
  131.             ADDRESS  // HANDLE hObject
  132.     );
  133.     private static final java.lang.invoke.MethodHandle CloseHandle = WindowsLinker.downcallHandle(
  134.             "kernel32.dll", "CloseHandle", CloseHandleDescriptor
  135.     );
  136.  
  137.  
  138.     // typedef struct _QUERY_ALLOCATED_RANGES_BUFFER {
  139.     //   DWORD         FileOffset;
  140.     //   DWORD         Length;
  141.     // } QUERY_ALLOCATED_RANGES_BUFFER, *PQUERY_ALLOCATED_RANGES_BUFFER;
  142.     private static final MemoryLayout QUERY_ALLOCATED_RANGES_BUFFER_LAYOUT = MemoryLayout.structLayout(
  143.             JAVA_LONG.withName("FileOffset"),
  144.             JAVA_LONG.withName("Length")
  145.     );
  146.  
  147.     // typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
  148.     //   LARGE_INTEGER FileOffset;
  149.     //   LARGE_INTEGER Length;
  150.     // } FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
  151.     private static final MemoryLayout FILE_ALLOCATED_RANGE_BUFFER_LAYOUT = MemoryLayout.structLayout(
  152.             JAVA_LONG.withName("FileOffset"),
  153.             JAVA_LONG.withName("Length")
  154.     );
  155.  
  156.  
  157.     public static void main(String[] args) throws Throwable {
  158.         if (args.length != 1) {
  159.             System.out.println("Usage: java QueryAllocatedRanges <file_path>");
  160.             return;
  161.         }
  162.         String filePath = args[0];
  163.  
  164.         try (Arena arena = Arena.ofConfined()) {
  165.             byte[] filePathBytes = filePath.getBytes(StandardCharsets.UTF_16LE); // Encode in UTF-16LE
  166.             MemorySegment lpFileName = arena.allocate(filePathBytes.length + 2); // +2 for null terminator
  167.             lpFileName.copyFrom(MemorySegment.ofArray(filePathBytes)); // Use copyFrom instead of writeByteArray
  168.             lpFileName.set(ValueLayout.JAVA_SHORT, filePathBytes.length, (short) 0); // Null-terminate (UTF-16 null is 2 bytes)
  169.  
  170.             MemorySegment handle = (MemorySegment) CreateFileW.invokeExact(
  171.                     lpFileName.address(), // Pass the address of the MemorySegment
  172.                     GENERIC_READ,
  173.                     0, // dwShareMode = 0 for exclusive access
  174.                     MemorySegment.NULL, // lpSecurityAttributes
  175.                     OPEN_EXISTING,
  176.                     FILE_ATTRIBUTE_NORMAL,
  177.                     MemorySegment.NULL // hTemplateFile
  178.             );
  179.  
  180.             if (handle.address() == INVALID_HANDLE_VALUE) {
  181.                 System.err.println("Error opening file: " + filePath);
  182.                 return; // Or throw an exception
  183.             }
  184.  
  185.             MemorySegment inputBuffer = arena.allocate(QUERY_ALLOCATED_RANGES_BUFFER_LAYOUT);
  186.             inputBuffer.set(JAVA_LONG, QUERY_ALLOCATED_RANGES_BUFFER_LAYOUT.byteOffset(PathElement.groupElement("FileOffset")), 0L); // FileOffset = 0 // Use PathElement
  187.             inputBuffer.set(JAVA_LONG, QUERY_ALLOCATED_RANGES_BUFFER_LAYOUT.byteOffset(PathElement.groupElement("Length")), -1L); // Length = -1 (ALL remaining ranges) // Use PathElement
  188.  
  189.  
  190.             int inputBufferSize = (int) QUERY_ALLOCATED_RANGES_BUFFER_LAYOUT.byteSize();
  191.  
  192.             int initialOutputBufferSize = 4096;
  193.             MemorySegment outputBuffer = arena.allocate(initialOutputBufferSize);
  194.             MemorySegment bytesReturnedSegment = arena.allocate(JAVA_INT);
  195.             int outputBufferSize = initialOutputBufferSize;
  196.  
  197.  
  198.             boolean success = (boolean) DeviceIoControl.invokeExact(
  199.                     handle,
  200.                     FSCTL_QUERY_ALLOCATED_RANGES,
  201.                     inputBuffer,
  202.                     inputBufferSize,
  203.                     outputBuffer,
  204.                     outputBufferSize,
  205.                     bytesReturnedSegment,
  206.                     MemorySegment.NULL // lpOverlapped
  207.             );
  208.  
  209.             if (!success) {
  210.                 int lastError = WindowsLastError.GetLastError();
  211.                 if (lastError == 234) { // ERROR_MORE_DATA (234) - output buffer was too small
  212.                     int bytesReturned = bytesReturnedSegment.get(JAVA_INT, 0);
  213.                     outputBufferSize = bytesReturned;
  214.                     outputBuffer = arena.allocate(outputBufferSize);
  215.  
  216.                     success = (boolean) DeviceIoControl.invokeExact(
  217.                             handle,
  218.                             FSCTL_QUERY_ALLOCATED_RANGES,
  219.                             inputBuffer,
  220.                             inputBufferSize,
  221.                             outputBuffer,
  222.                             outputBufferSize,
  223.                             bytesReturnedSegment,
  224.                             MemorySegment.NULL // lpOverlapped
  225.                     );
  226.                     if (!success) {
  227.                         System.err.println("DeviceIoControl failed after buffer reallocation with error code: " + WindowsLastError.GetLastError());
  228.                         CloseHandle.invokeExact(handle);
  229.                         return;
  230.                     }
  231.  
  232.                 } else {
  233.                     System.err.println("DeviceIoControl failed with error code: " + lastError);
  234.                     CloseHandle.invokeExact(handle);
  235.                     return;
  236.                 }
  237.             }
  238.  
  239.             int bytesReturned = bytesReturnedSegment.get(JAVA_INT, 0);
  240.             if (bytesReturned > 0) {
  241.                 System.out.println("Allocated Ranges:");
  242.                 long offset = 0;
  243.                 while (offset < bytesReturned) {
  244.                     MemorySegment rangeSegment = outputBuffer.asSlice(offset, FILE_ALLOCATED_RANGE_BUFFER_LAYOUT.byteSize());
  245.                     long fileOffset = rangeSegment.get(JAVA_LONG, FILE_ALLOCATED_RANGE_BUFFER_LAYOUT.byteOffset(PathElement.groupElement("FileOffset"))); // Use PathElement
  246.                     long length = rangeSegment.get(JAVA_LONG, FILE_ALLOCATED_RANGE_BUFFER_LAYOUT.byteOffset(PathElement.groupElement("Length"))); // Use PathElement
  247.                     System.out.println("  Offset: " + fileOffset + ", Length: " + length);
  248.                     offset += FILE_ALLOCATED_RANGE_BUFFER_LAYOUT.byteSize();
  249.                 }
  250.             } else {
  251.                 System.out.println("No allocated ranges found.");
  252.             }
  253.  
  254.             CloseHandle.invokeExact(handle);
  255.         } catch (IOException | InterruptedException |  java.lang.invoke.WrongMethodTypeException e) {
  256.             e.printStackTrace();
  257.         }
  258.     }
  259. }
  260.  
  261. class WindowsLastError {
  262.     private static final java.lang.foreign.FunctionDescriptor GetLastErrorDescriptor = java.lang.foreign.FunctionDescriptor.of(
  263.             JAVA_INT // DWORD
  264.     );
  265.     private static final java.lang.invoke.MethodHandle GetLastError = WindowsLinker.downcallHandle(
  266.             "kernel32.dll", "GetLastError", GetLastErrorDescriptor
  267.     );
  268.  
  269.     public static int GetLastError() throws Throwable {
  270.         return (int) GetLastError.invokeExact();
  271.     }
  272. }
  273.  
  274. class WindowsLinker {
  275.     private static final java.lang.foreign.Linker LINKER = java.lang.foreign.Linker.nativeLinker(); // Or Linker.defaultLinker()
  276.  
  277.     public static java.lang.invoke.MethodHandle downcallHandle(String libraryName, String functionName, java.lang.foreign.FunctionDescriptor descriptor) {
  278.         try {
  279.             // Use findSymbol and handle Optional<MemorySegment> correctly
  280.             java.lang.foreign.SymbolLookup symbolLookup = LINKER.defaultLookup();
  281.             java.lang.foreign.MemorySegment functionAddress = symbolLookup.find(functionName)
  282.                     .orElseThrow(() -> // orElseThrow on Optional<MemorySegment>
  283.                             new UnsatisfiedLinkError("Function " + functionName + " not found in library " + libraryName));
  284.  
  285.             return LINKER.downcallHandle(
  286.                     functionAddress, // Pass the MemorySegment (function address)
  287.                     descriptor
  288.             );
  289.         } catch (Throwable e) {
  290.             throw new RuntimeException(e);
  291.         }
  292.     }
  293. }
  294.  
  295.  
  296.  
  297. public class DemoQueryAllocatedRanges {
  298.  
  299.     public static void main(String[] args) {
  300.         String filePath = "foo.bin";
  301.         Path file = Paths.get(filePath);
  302.  
  303.         // Create foo.bin if it doesn't exist
  304.         if (!Files.exists(file)) {
  305.             try {
  306.                 Files.createFile(file);
  307.                 System.out.println("Created file: " + filePath);
  308.             } catch (IOException e) {
  309.                 System.err.println("Error creating file: " + filePath);
  310.                 e.printStackTrace();
  311.                 return; // Exit if file creation fails
  312.             }
  313.         }
  314.  
  315.         System.out.println("Running QueryAllocatedRanges for file: " + filePath);
  316.  
  317.         try {
  318.             // Call QueryAllocatedRanges.main() with filePath as argument
  319.             QueryAllocatedRanges.main(new String[]{filePath});
  320.         } catch (Throwable e) {
  321.             System.err.println("Error running QueryAllocatedRanges:");
  322.             e.printStackTrace();
  323.         }
  324.  
  325.         System.out.println("Demo finished.");
  326.     }
  327. }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at