我想使用 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);
}