我试图阅读NTFS Change Journal但是我注意到我在Windows 10上找到的所有示例代码都失败了,即使它适用于Windows 7。
例如,微软自己的示例Walking a Buffer of Change Journal Records适用于Windows 7,但是当我在Windows 10上运行相同的代码时,当我使用FSCTL_READ_USN_JOURNAL调用DeviceIoControl时,我收到错误87(参数不正确)(请注意,早期版本)使用FSCTL_QUERY_USN_JOURNAL调用DeviceIoControl成功完成并返回有效数据。)。
我甚至已经编译并在Windows 7上运行的EXE并将其复制到Windows 10机器上但它仍然失败,所以我相信Windows 10可能对参数验证更严格或类似的东西?< / p>
我正在以管理员身份运行代码,因此不是问题。
我无法找到对此问题的任何其他引用,但如果我使用其他人的示例代码并尝试在Windows 10上运行它,我会遇到同样的问题。
编辑:
代码本身:
#include <Windows.h>
#include <WinIoCtl.h>
#include <stdio.h>
#define BUF_LEN 4096
void main()
{
HANDLE hVol;
CHAR Buffer[BUF_LEN];
USN_JOURNAL_DATA JournalData;
READ_USN_JOURNAL_DATA ReadData = {0, 0xFFFFFFFF, FALSE, 0, 0};
PUSN_RECORD UsnRecord;
DWORD dwBytes;
DWORD dwRetBytes;
int I;
hVol = CreateFile( TEXT("\\\\.\\c:"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if( hVol == INVALID_HANDLE_VALUE )
{
printf("CreateFile failed (%d)\n", GetLastError());
return;
}
if( !DeviceIoControl( hVol,
FSCTL_QUERY_USN_JOURNAL,
NULL,
0,
&JournalData,
sizeof(JournalData),
&dwBytes,
NULL) )
{
printf( "Query journal failed (%d)\n", GetLastError());
return;
}
ReadData.UsnJournalID = JournalData.UsnJournalID;
printf( "Journal ID: %I64x\n", JournalData.UsnJournalID );
printf( "FirstUsn: %I64x\n\n", JournalData.FirstUsn );
for(I=0; I<=10; I++)
{
memset( Buffer, 0, BUF_LEN );
if( !DeviceIoControl( hVol,
FSCTL_READ_USN_JOURNAL,
&ReadData,
sizeof(ReadData),
&Buffer,
BUF_LEN,
&dwBytes,
NULL) )
{
printf( "Read journal failed (%d)\n", GetLastError());
return;
}
dwRetBytes = dwBytes - sizeof(USN);
// Find the first record
UsnRecord = (PUSN_RECORD)(((PUCHAR)Buffer) + sizeof(USN));
printf( "****************************************\n");
// This loop could go on for a long time, given the current buffer size.
while( dwRetBytes > 0 )
{
printf( "USN: %I64x\n", UsnRecord->Usn );
printf("File name: %.*S\n",
UsnRecord->FileNameLength/2,
UsnRecord->FileName );
printf( "Reason: %x\n", UsnRecord->Reason );
printf( "\n" );
dwRetBytes -= UsnRecord->RecordLength;
// Find the next record
UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord) +
UsnRecord->RecordLength);
}
// Update starting USN for next call
ReadData.StartUsn = *(USN *)&Buffer;
}
CloseHandle(hVol);
}
答案 0 :(得分:4)
我成功解决了问题所在。
示例Microsoft代码创建一个定义为READ_USN_JOURNAL_DATA的局部变量,定义为:
#if (NTDDI_VERSION >= NTDDI_WIN8)
typedef READ_USN_JOURNAL_DATA_V1 READ_USN_JOURNAL_DATA, *PREAD_USN_JOURNAL_DATA;
#else
typedef READ_USN_JOURNAL_DATA_V0 READ_USN_JOURNAL_DATA, *PREAD_USN_JOURNAL_DATA;
#endif
在我的系统上(Win10和Win7系统),这将评估为READ_USN_JOURNAL_DATA_V1。
看看READ_USN_JOURNAL_DATA_V0和READ_USN_JOURNAL_DATA_V1之间的区别,我们可以看到V0被定义为:
typedef struct {
USN StartUsn;
DWORD ReasonMask;
DWORD ReturnOnlyOnClose;
DWORDLONG Timeout;
DWORDLONG BytesToWaitFor;
DWORDLONG UsnJournalID;
} READ_USN_JOURNAL_DATA_V0, *PREAD_USN_JOURNAL_DATA_V0;
,V1版本定义为:
typedef struct {
USN StartUsn;
DWORD ReasonMask;
DWORD ReturnOnlyOnClose;
DWORDLONG Timeout;
DWORDLONG BytesToWaitFor;
DWORDLONG UsnJournalID;
WORD MinMajorVersion;
WORD MaxMajorVersion;
} READ_USN_JOURNAL_DATA_V1, *PREAD_USN_JOURNAL_DATA_V1;
请注意新的Min和Max Major版本成员。
因此,Microsoft代码定义了一个名为ReadData的局部变量,它实际上是一个V1结构,但它似乎填充了数据,假设它是一个V0结构。即它没有设置Min和Max元素。
看来Win7很好用,但Win10拒绝它并返回错误87(参数不正确)。
如果我明确地将ReadData变量定义为READ_USN_JOURNAL_DATA_V0,那么代码可以在Win7和Win10上运行,而如果我明确地将其定义为READ_USN_JOURNAL_DATA_V1,那么它将继续在Win7上工作,但不能在Win10上工作。
奇怪的是,READ_USN_JOURNAL_DATA_V1 structure的API文档声明它仅在Windows 8上受支持,因此奇怪的是它在Windows 7上完全可用。我想它只是将它解释为READ_USN_JOURNAL_DATA_V0结构,因为V1版本是V0结构的扩展。如果是这样,那么它必须忽略传递给DeviceIOControl的size参数。
无论如何,现在都在工作。我希望有人在将来发现这是一个有用的参考。
答案 1 :(得分:1)
我遇到了与OP完全相同的示例代码问题。在示例代码的开头,您将在声明时看到结构的部分初始化。在代码的稍后部分,在有问题的调用之前,有一行将UsnJournalID分配给读取的数据结构。
但是,对于Windows 10,V1结构的其他两个成员未初始化。我在UsnJournalID初始化之后立即初始化了它们:
#if (NTDDI_VERSION >= NTDDI_WIN8)
ReadData.MinMajorVersion = JournalData.MinSupportedMajorVersion;
ReadData.MaxMajorVersion = JournalData.MaxSupportedMajorVersion;
#endif
执行完此操作后,我的代码正常运行,没有错误代码。我记得在Volume Management API讨论中读过,需要设置Min和Max版本。我忘记了确切的位置,因为我已经阅读并测试了这两天。
无论如何,我希望能为所有追随我的人澄清这个问题。
答案 2 :(得分:0)
用READ_USN_JOURNAL_DATA_V0数据结构替换READ_USN_JOURNAL_DATA结构并对其进行初始化。
这对我有用
READ_USN_JOURNAL_DATA_V0 ReadData;
ZeroMemory(&ReadData, sizeof(ReadData));
ReadData.ReasonMask = 0xFFFFFFFF;