Моя цель — прочитать операции записи с выбранного диска (обычно C), используя журнал USN.
В следующем коде, который я написал, я создал небольшой класс, который обрабатывает записи USN с помощью DeviceIoControl
с FSCTL_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
а также FSCTL_ENUM_USN_DATA
DeviceIoControl
не удается, и код ошибки, который я получаю, ERROR_HANDLE_EOF
, даже если я обновляю журнал, я получаю ту же ошибку.
Я хочу иметь возможность передавать любую новую запись USN и обрабатывать события записи. Я точно знаю, что это возможно, так как есть
сторонние инструменты, которые представляют записи USN нон-стоп.
как можно воспроизвести это состояние безостановочной потоковой передачи?
Задача ещё не решена.
Других решений пока нет …