C++ Can';不停地阅读USN日志

C++ Can';不停地阅读USN日志,c++,windows,winapi,filesystems,usn,C++,Windows,Winapi,Filesystems,Usn,我的目标是使用USN日志从选定的驱动器(通常是C)读写操作。 在我编写的下一段代码中,我创建了一个小类,它使用DeviceIoControl处理USN记录 使用FSCTL_QUERY_USN_JOURNAL和FSCTL_ENUM_USN_DATAcode #include "stdafx.h" #include <stdio.h> #include <assert.h> #include <vector> #include <system_error&


我的目标是使用USN日志从选定的驱动器(通常是C)读写操作。 在我编写的下一段代码中,我创建了一个小类,它使用
DeviceIoControl

处理USN记录 使用
FSCTL_QUERY_USN_JOURNAL
FSCTL_ENUM_USN_DATA
code

#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;
}
#包括“stdafx.h”
#包括
#包括
#包括
#包括
#包括
[[noreturn]]无效抛出系统错误(整数错误代码){
抛出std::system_error(错误代码,std::system_category());
}
美国海军大学学报{
私人:
手柄、驱动手柄;
std::向量m_缓冲区;
USN_日志数据*m_USN_日志数据;
USN m_next_USN_record_id;
公众:
usn_日志(const wchar_t*驱动程序名称){
m_next_usn_record_id=0;
m_drive_handle=::CreateFileW(
司机姓名,
泛读,
文件共享删除文件共享读取文件共享写入,
nullptr,
永远敞开心扉,
文件\u标志\u无缓冲,
nullptr);
如果(m_驱动器\u句柄==无效的\u句柄\u值){
抛出系统错误(::GetLastError());
}
m_缓冲区大小调整(1024*1024);
}
~usn_杂志(){
::闭合手柄(m_驱动手柄);
}
void refresh_jounral(){
断言(m_buffer.size()=1024*1024);
DWORD缓冲区计数=0;
如果(!DeviceIoControl(
m_-drive_-handle,
FSCTL_查询_USN_日志,
nullptr,
0,
m_buffer.data(),
m_buffer.size(),
&缓冲区计数,
空值(PTR){
抛出系统错误(::GetLastError());
}
m_usn_日志_数据=
重新解释强制转换(m_buffer.data());
}
作废流程_条目(){
DWORD字节_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;
断言(m_buffer.size()=1024*1024);
对于(;){
自动缓冲区=m_buffer.data();
如果(!DeviceIoControl(
m_-drive_-handle,
FSCTL_ENUM_USN_数据,
&mft_枚举数据,
sizeof(mft_枚举数据),
缓冲器
m_buffer.size(),
&读取的字节数,
空值(PTR){
自动错误代码=::GetLastError();
如果(错误代码==错误句柄){
返回;
}
否则{
抛出系统错误(::GetLastError());
}
}
m_next_usn_record_id=*重新解释\u cast(缓冲区);
自动缓冲区\u real\u begin=buffer+sizeof(USN);
自动usn\u游标=重新解释\u转换(缓冲区\u实际\u开始);
int64_t total_usn_buffer_number=bytes_read-sizeof(usn);
而(总usn缓冲区数量>=0){
总usn\U缓冲区\U编号-=usn\U光标->记录长度;
缓冲区=重新解释\u转换(usn\u游标)+usn\u游标->记录长度;
usn\U cursor=重新解释强制转换(usn\U cursor);
如果(usn_光标->原因!=0){
printf(“%d\n”,(int)usn\u游标->原因);
}
}
mft_enum_data.StartFileReferenceNumber=m_next_usn_record_id;
}
}
};
int main(int argc,字符**argv){
usn\U日志我的日志(L“\\?\\c:”);
while(true){
我的日志。刷新日志();
我的日志。处理日志();
}
返回0;
}
这是我的问题,过了一段时间,记录耗尽,调用
DeviceIoControl
FSCTL\u ENUM\u USN\u DATA
DeviceIoControl
失败,我得到的错误代码是
error\u HANDLE\u EOF
,即使我刷新日志,我也会得到相同的错误。
我希望能够流式传输任何新的USN记录,并处理写入事件。我确信这是可能的,因为有
提供USN记录的第三方工具不间断。

如何再现这种不间断流的状态?

但您没有重置为0
m\u next\u usn\u record\u id
。结果和
错误\u处理\u EOF
。在
process_entries()
function
mft_enum_data.StartFileReferenceNumber=0必须在循环之前。请重新阅读代码。构造函数将此变量设置为零。这是
process\u entries
使用的第一个值,在第一次调用
process\u entries()
时它将为零,但如果第二次调用
process\u entries()
则在开始时它已经不是0。不清楚为什么这个变量是类的成员而不是函数的局部变量?目前它只用作局部变量。仅当
process\u entries()
可以中断枚举时,才在类exist sense中移动此变量,然后从
m\u next\u usn\u record\u id
重新启动它,而不是从0开始。这是我一开始所做的。它没有帮助。我不理解
refresh\u journral()
-
FSCTL\u QUERY\u USN\u JOURNAL
-输出缓冲区必须是
USN\u JOURNAL\u DATA
-固定大小的结构,但您在这里做什么?