変更ジャーナル レコードのバッファーを調べる
更新シーケンス番号 (USN) の変更ジャーナル レコードを返す制御コードは、FSCTL_READ_USN_JOURNAL および FSCTL_ENUM_USN_DATA、出力バッファーに同様のデータを返します。 どちらも USN の後に 0 個以上の変更履歴レコードが返され、それぞれ USN_RECORD_V2 または USN_RECORD_V3 構造になります。
USN 操作のターゲット ボリュームは、ReFS または NTFS 3.0 以降である必要があります。 ボリュームの NTFS バージョンを取得するには、管理者アクセス権でコマンド プロンプトを開き、次のコマンドを実行します。
FSUtil.exe FSInfo NTFSInfo X**:**
ここで、X はボリュームのドライブ文字です。
次の一覧は、変更ジャーナル レコードを取得する方法を示しています。
- FSCTL_ENUM_USN_DATA を使用して、2 つの USN 間のすべての変更ジャーナル レコードの一覧 (列挙) を取得します。
- FSCTL_READ_USN_JOURNAL を使用して、変更の特定の理由を選択したり、ファイルが閉じられたときに戻るなど、より選択的になります。
Note
これらの操作は両方とも、指定された条件を満たす変更ジャーナル レコードのサブセットのみを返します。
出力バッファーの最初の項目として返される 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 から 1 つ減算して、USN_RECORD と USN_RECORD_V3 の定義にファイル名の 1 文字が含まれていることを考慮します。
C プログラミング言語では、可能な最大レコード サイズは次のとおりです。
(MaxComponentLength - 1) * sizeof(WCHAR) + sizeof(USN_RECORD)