4


我的目标是使用 USN 日志从选定的驱动器(通常是 C)读取写入操作。在我编写的下一个代码中,我创建了一个小类,通过使用 and 代码来处理DeviceIoControl
USNFSCTL_QUERY_USN_JOURNAL记录FSCTL_ENUM_USN_DATA

#include "stdafx.h"
#include <stdio.h> 
#include <assert.h>
#include <vector>
#include <system_error>
#include <Windows.h>

[[noreturn]] void throw_system_error(int error_code) {
    throw std::system_error(error_code, std::system_category());
}

class usn_journal {

private:
    HANDLE m_drive_handle;
    std::vector<uint8_t> m_buffer;
    USN_JOURNAL_DATA* m_usn_journal_data;
    USN m_next_usn_record_id;

public:
    usn_journal(const wchar_t* driver_name) {
        m_next_usn_record_id = 0;
        m_drive_handle = ::CreateFileW(
            driver_name,
            GENERIC_READ,
            FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
            nullptr,
            OPEN_ALWAYS,
            FILE_FLAG_NO_BUFFERING,
            nullptr);

        if (m_drive_handle == INVALID_HANDLE_VALUE) {
            throw_system_error(::GetLastError());
        }

        m_buffer.resize(1024 * 1024);
    }

    ~usn_journal() {
        ::CloseHandle(m_drive_handle);
    }

    void refresh_jounral() {
        assert(m_buffer.size() == 1024 * 1024);

        DWORD buffer_count = 0;
        if (!DeviceIoControl(
            m_drive_handle,
            FSCTL_QUERY_USN_JOURNAL,
            nullptr,
            0,
            m_buffer.data(),
            m_buffer.size(),
            &buffer_count,
            nullptr)) {
            throw_system_error(::GetLastError());
        }

        m_usn_journal_data =
            reinterpret_cast<decltype(m_usn_journal_data)>(m_buffer.data());
    }

    void process_entries() {
        DWORD bytes_read = 0;
        MFT_ENUM_DATA_V0 mft_enum_data = {};
        mft_enum_data.StartFileReferenceNumber = m_next_usn_record_id;
        mft_enum_data.LowUsn = 0;
        mft_enum_data.HighUsn = m_usn_journal_data->MaxUsn;

        assert(m_buffer.size() == 1024 * 1024);

        for (;;){       
            auto buffer = m_buffer.data();
            if (!DeviceIoControl(
                m_drive_handle,
                FSCTL_ENUM_USN_DATA,
                &mft_enum_data,
                sizeof(mft_enum_data),
                buffer,
                m_buffer.size(),
                &bytes_read,
                nullptr)){

                auto error_code = ::GetLastError();
                if (error_code == ERROR_HANDLE_EOF) {
                    return;
                }
                else {
                    throw_system_error(::GetLastError());
                }
            }

            m_next_usn_record_id = *reinterpret_cast<USN*>(buffer); 
            auto buffer_real_begin = buffer + sizeof(USN);
            auto usn_cursor = reinterpret_cast<USN_RECORD*>(buffer_real_begin);
            int64_t total_usn_buffer_number = bytes_read - sizeof(USN);

            while (total_usn_buffer_number >= 0){
                total_usn_buffer_number -= usn_cursor->RecordLength;
                buffer = reinterpret_cast<uint8_t*>(usn_cursor) + usn_cursor->RecordLength;
                usn_cursor = reinterpret_cast<USN_RECORD*>(usn_cursor);
                if (usn_cursor->Reason != 0) {
                    printf("%d\n", (int)usn_cursor->Reason);
                }
            }

            mft_enum_data.StartFileReferenceNumber = m_next_usn_record_id;
        }
    }
};

int main(int argc, char ** argv){
    usn_journal my_journal(L"\\\\?\\c:");
    while (true) {
        my_journal.refresh_jounral();
        my_journal.process_entries();
    }

    return 0;
}

这是我的问题,过了一会儿,记录用完了,调用失败了,我得到的错误代码是DeviceIoControl,即使我刷新日志,我也会得到同样的错误。 我希望能够流式传输任何新的 USN 记录并处理写入事件。我确信这是可能的,因为有 第三方工具可以不间断地显示 USN 记录。 怎样才能重现这种不间断流媒体的状态?FSCTL_ENUM_USN_DATA DeviceIoControlERROR_HANDLE_EOF


4

0 回答 0