1

ドライブ上のファイルの変更を監視するために NTFS 変更ジャーナルを読んでいますが、返された USN_RECORD には関連ファイルのファイル名のみが含まれ、完全なパスは含まれていません。

完全なパスを取得するには、OpenFileById API で FileReferenceNumber (USN_RECORD にもあります) を使用して、関連付けられたファイルへのハンドルを取得し、続いて GetFinalPathNameByHandleA を使用して完全なパスを取得します。

これは、そのファイルがまだ存在する限りうまく機能しますが、ファイルが削除されている場合 (たとえば、ファイルの削除のために USN_RECORD を処理している場合)、明らかに OpenFileById が失敗するため、完全なパスを取得できません。

USN_RECORD には、親ディレクトリの名前を取得できるようにする ParentFileReferenceNumber メンバー (おそらく OpenFileById を使用して開くことができる) が含まれていますが、同じ問題が存在します。つまり、親ディレクトリが削除された場合はどうなりますか?

また、親ディレクトリが削除されていない場合でも、ボリューム ルートに到達するまで、次のディレクトリ (つまり、親の親) に移動するにはどうすればよいですか?

これが私のコード例です:

#include "stdafx.h"
#include <Windows.h>
#include <WinIoCtl.h>
#include <stdio.h>
#include <string>

using std::string;
#define BUF_LEN 4096

std::string GetFullPath(HANDLE hVol, DWORDLONG fileRefNum)
{
    FILE_ID_DESCRIPTOR fid;
    ZeroMemory(&fid, sizeof(fid));
    fid.dwSize = sizeof(fid);
    fid.Type = FileIdType;
    fid.FileId.QuadPart = fileRefNum;   

    HANDLE handle = OpenFileById(hVol, &fid, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, FILE_FLAG_BACKUP_SEMANTICS);
    if (handle == INVALID_HANDLE_VALUE)
        return "Error: " + std::to_string(GetLastError());

    char buffer[1024];
    GetFinalPathNameByHandleA(handle, &buffer[0], 1024, 0);

    return string(&buffer[0]);
}

void main()
{
    // Open the volume
    DWORD dwBytes;
    DWORD dwRetBytes;
    HANDLE 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;
    }

    // Query the Journal
    USN_JOURNAL_DATA_V0 JournalData;
    if (!DeviceIoControl(hVol, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &JournalData, sizeof(JournalData), &dwBytes, NULL))
    {
        printf("Query journal failed (%d)\n", GetLastError());
        return;
    }


    printf("Journal ID: %I64x\n", JournalData.UsnJournalID);
    printf("FirstUsn: %I64x\n\n", JournalData.FirstUsn);

    READ_USN_JOURNAL_DATA_V0 ReadData;
    ZeroMemory(&ReadData, sizeof(ReadData));
    ReadData.ReasonMask = 0xFFFFFFFF;
    ReadData.UsnJournalID = JournalData.UsnJournalID;
    PUSN_RECORD UsnRecord;
    CHAR Buffer[BUF_LEN];
    for (int loop = 0; loop <= 100; loop++)
    {
        // Read the journal
        ZeroMemory(Buffer, 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("Filename:       %.*S\n", UsnRecord->FileNameLength / 2, UsnRecord->FileName);
            printf("Full filename:  %s\n", GetFullPath(hVol, UsnRecord->FileReferenceNumber).c_str());
            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:            8ebc423a8
Filename:       999000000167237.xml
Full filename:  Error: 87
Reason:         80000200

USN:            8ebc42410
Filename:       999000000167238.xml
Full filename:  Error: 87
Reason:         80000200

USN:            8ebc42478
Filename:       MobilityDB.db
Full filename:  \\?\C:\ProgramData\NGC\Open Mobile\Profiles\12316\MobilityDB.db
Reason:         1
4

0 に答える 0