0

我想使用 Java JNA 库阅读 Windows USN(文件系统)日志。我可以打开驱动器的句柄并查询日志信息。但是当我尝试读取日志数据(FSCTL_READ_USN_JOURNAL)时,我收到错误 1784(提供的用户缓冲区对于请求的操作无效)。Windows 7/64,JNA 版本 4.5.1,java 8/32。我用 C++ 尝试了同样的方法,它工作得很好。

import java.io.IOException;
import java.util.List;

import com.sun.jna.Memory;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Kernel32Util;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.Winioctl;
import com.sun.jna.platform.win32.WinioctlUtil;
import com.sun.jna.ptr.IntByReference;

public class NtfsUsnJournal2
{
  public static void main(String[] args)
  {
    try
    {
      WinNT.HANDLE hDevice = openDisk('C');
      try
      {
    USN_JOURNAL_INFO_V0 journalInfo = queryJournal(hDevice);
    System.out.println(journalInfo);
    //
    Memory buffer = new Memory(4096);
    buffer.clear();
    IntByReference numBytesReturned = new IntByReference(0);
    READ_USN_JOURNAL_DATA_V0 journalData = new READ_USN_JOURNAL_DATA_V0();
    journalData.clear();
    journalData.ReasonMask = 0xFFFFFFFF;
    journalData.UsnJournalID = journalInfo.UsnJournalID;
    journalData.write();
    System.out.println(journalData);
    boolean ok = Kernel32.INSTANCE.DeviceIoControl(hDevice,
      FSCTL_READ_USN_JOURNAL, // = 590011
      journalData.getPointer(),journalData.size(),
      buffer.getPointer(0),(int)buffer.size(),
      numBytesReturned,null);
    if( !ok )
    {
      System.out.println("ERROR "+Kernel32.INSTANCE.GetLastError()+" "+Kernel32Util.getLastErrorMessage());
      return;
    }
    System.out.println(numBytesReturned.getValue());
    System.out.println(buffer.getInt(8));
      }
      finally
      {
    Kernel32.INSTANCE.CloseHandle(hDevice);
      }
    }
    catch( Exception e )
    {
      e.printStackTrace();
    }
  }

  static USN_JOURNAL_INFO_V0 queryJournal(WinNT.HANDLE hDevice) throws IOException
  {
    USN_JOURNAL_INFO_V0 journalInfo = new USN_JOURNAL_INFO_V0();
    journalInfo.clear();
    //
    IntByReference numBytesReturned = new IntByReference(0);
    boolean ok = Kernel32.INSTANCE.DeviceIoControl(hDevice,
      FSCTL_QUERY_USN_JOURNAL,null,0,
      journalInfo.getPointer(),journalInfo.size(),
      numBytesReturned,null);
    if( !ok )
    {
      throw new IOException(
    "ERROR "+Kernel32.INSTANCE.GetLastError()+": "+Kernel32Util.getLastErrorMessage());
    }
    journalInfo.read();
    return journalInfo;
  }

  static WinNT.HANDLE openDisk(char drive)
  {
    return Kernel32.INSTANCE.CreateFile("\\\\.\\"+drive+":",
      WinNT.GENERIC_READ|WinNT.GENERIC_WRITE,
      WinNT.FILE_SHARE_READ|WinNT.FILE_SHARE_WRITE,null,WinNT.OPEN_EXISTING,0,null);
  }

  static public class USN_JOURNAL_INFO_V0 extends Structure
  {
    public static final List<String> FIELDS = createFieldsOrder(
      "UsnJournalID","FirstUsn","NextUsn","LowestValidUsn","MaxUsn","MaximumSize","AllocationDelta");
    protected List<String> getFieldOrder() { return FIELDS; }
    //
    public long UsnJournalID;
    public long FirstUsn;
    public long NextUsn;
    public long LowestValidUsn;
    public long MaxUsn;
    public long MaximumSize;
    public long AllocationDelta;
  }

  static public class READ_USN_JOURNAL_DATA_V0 extends Structure
  {
    public static final List<String> FIELDS = createFieldsOrder(
      "StartUsn","ReasonMask","ReturnOnlyOnClose","Timeout","BytesToWaitFor","UsnJournalID");
    protected List<String> getFieldOrder() { return FIELDS; }
    //
    public long StartUsn;
    public int  ReasonMask;
    public int  ReturnOnlyOnClose;
    public long Timeout;
    public long BytesToWaitFor;
    public long UsnJournalID;
  }

  static final int FSCTL_QUERY_USN_JOURNAL =
    WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, 61,
    Winioctl.METHOD_BUFFERED,Winioctl.FILE_ANY_ACCESS);

  static final int FSCTL_READ_USN_JOURNAL =
    WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, 46,
    Winioctl.METHOD_NEITHER,Winioctl.FILE_ANY_ACCESS);
}
4

1 回答 1

0

内存扩展指针,不需要 getPointer

boolean ok = Kernel32.INSTANCE.DeviceIoControl(hDevice,
         FSCTL_READ_USN_JOURNAL, // = 590011
         journalData.getPointer(),journalData.size(),
         buffer,(int)buffer.size(),
         numBytesReturned,null);
于 2018-08-30T08:15:38.893 回答