Мониторинг удалений и изменений на томе NTFS с помощью MFT_ENUM_DATA
Я использую этот код для заполнения базы данных всех файлов на диске:
TCHAR szVolumePath[_MAX_PATH] = L"\\\\.\\d:";
HANDLE hDrive = CreateFile(szVolumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
MFT_ENUM_DATA_V0 med = { 0 };
med.StartFileReferenceNumber = 0;
med.LowUsn = 0;
med.HighUsn = MAXLONGLONG;
DWORD cb;
PUSN_RECORD pRecord;
unsigned char pData[sizeof(DWORDLONG) + 0x10000] = { 0 };
while (DeviceIoControl(hDrive, FSCTL_ENUM_USN_DATA, &med, sizeof(med), pData, sizeof(pData), &cb, NULL) != FALSE)
{
pRecord = (PUSN_RECORD)&pData[sizeof(USN)];
while ((PBYTE)pRecord < (pData + cb))
{
wstring sz((LPCWSTR)(PBYTE)pRecord + pRecord->FileNameOffset, pRecord->FileNameLength / sizeof(WCHAR));
// file the database
pRecord = (PUSN_RECORD)((PBYTE)pRecord + pRecord->RecordLength);
}
med.StartFileReferenceNumber = *(DWORDLONG *)pData;
}
Как только цикл завершен, база данных успешно заполнена.
Но как продолжить (в качестве фоновой задачи) отслеживать в реальном времени изменения / удаления файлов? (пример: отобразить MessageBox()
"Файл readme.txt был переименован.")
Должен ли я перезапускать такой цикл каждую 1 секунду, с med.StartFileReferenceNumber
= самый высокий FileReferenceNumber, который вы видели раньше?
Примечание: я немного не хочу запускать этот код каждую 1 секунду (99% времени, даром). Делая это каждые 10 секунд, вы избежите использования такого большого количества ресурсов, но перед обнаружением изменений будет задержка, в то время как я знаю некоторые программы индексирования, которые не имеют такой задержки.
Примечание 2: я прочитал Как я могу обнаружить только удаленные, измененные и созданные файлы на томе? но цель основного ответа - запустить его один раз, а не постоянно в фоновом режиме.
Примечание 3: Я посмотрел на этот полезный пример кода от Microsoft, следящего за вашими дисками NTFS: объяснение журнала изменений Windows 2000.
Примечание 4: Должен ли я сохранить FSCTL_ENUM_USN_DATA для начальной загрузки базы данных, а затем использовать вместо него FSCTL_READ_USN_JOURNAL?
Note5: ReadDirectoryChangesW
или же FindNextChangeNotification
(первый дает полный путь изменений в уведомлениях, второй нет) не может быть использован, потому что он не даст FileReferenceNumber
удаленного файла (нужно открыть файл и использовать NtQueryInformationFile
получить это; но это невозможно для удаленных файлов); и FileReferenceNumber необходим для обновления файловой базы данных (файловая база данных использует карту / словарь с FileReferenceNumber s в качестве ключей).