逐步執行變更日誌記錄的緩衝區
傳回 USN) 變更日誌記錄 (更新序號的控制程式代碼, FSCTL_READ_USN_JOURNAL 和 FSCTL_ENUM_USN_DATA傳回輸出緩衝區中的類似資料。 兩者都會傳回 USN,後面接著零或多個變更日誌記錄,每個記錄都是 在USN_RECORD_V2 或 USN_RECORD_V3 結構中。
USN 作業的目標磁片區必須是 ReFS 或 NTFS 3.0 或更新版本。 若要取得磁片區的 NTFS 版本,請使用系統管理員存取權限開啟命令提示字元,然後執行下列命令:
FSUtil.exe FSInfo NTFSInfoX**:**
其中 X 是磁片區的磁碟機號。
下列清單會識別取得變更日誌記錄的方式:
- 使用 FSCTL_ENUM_USN_DATA 取得兩個 USN 之間所有變更日誌記錄的清單 (列舉) 。
- 使用 FSCTL_READ_USN_JOURNAL 更選擇性,例如在關閉檔案時選取變更或傳回的特定原因。
注意
這兩項作業只會傳回符合指定準則的變更日誌記錄子集。
當做輸出緩衝區中第一個專案傳回的 USN 是要擷取之下一筆記錄號碼的 USN。 使用此值繼續從結束界限向前讀取記錄。
USN_RECORD_V2或USN_RECORD_V3的FileName成員包含所要套用記錄的檔案名。 檔案名的長度會有所不同,因此 USN_RECORD_V2 和 USN_RECORD_V3 都是可變長度結構。 其第一個成員 RecordLength是結構長度, (包括檔案名) ,以位元組為單位。
當您使用USN_RECORD_V2和USN_RECORD_V3結構的FileName成員時,請勿假設檔案名包含尾端 '\0' 分隔符號。 若要判斷檔案名的長度,請使用 FileNameLength 成員。
下列範例會 呼叫 FSCTL_READ_USN_JOURNAL ,並逐步解說作業傳回之變更日誌記錄的緩衝區。
#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);
}
USN_RECORD_V2或USN_RECORD_V3結構所指定之任何記錄的大小上限 ((MaxComponentLength - 1) * Width) + Size
,其中MaxComponentLength是記錄檔名稱字元的最大長度。 寬度是寬字元的大小, 而 Size 是 結構的大小。
若要取得最大長度,請呼叫 GetVolumeInformation 函式 ,並檢查 lpMaximumComponentLength 參數所指向的值。 將其中一個從 MaxComponentLength 減去,以考慮 USN_RECORD 的定義和 USN_RECORD_V3 包含檔案名的一個字元。
在 C 程式設計語言中,最大的可能記錄大小如下:
(MaxComponentLength - 1) * sizeof(WCHAR) + sizeof(USN_RECORD)
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應