Как получить полный путь для запроса журнала USN?

Я пытаюсь пройти пример на MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365736%28v=vs.85%29.aspx) о том, как запросить журнал USN для отслеживания изменений файлов на диске NTFS. Пример кода работает хорошо.

Однако в этом примере кода структура USN_RECORD возвращает мне только номер ссылки на файл и имя файла. Это не возвращает мне полный путь к файлу. Кто-нибудь есть идеи, как запросить журнал USN, чтобы вернуть полный путь? Или есть способ получить полный путь от номера файла?

Благодарю.

3

Решение

ParentFileReferenceNumber член USN_RECORD структура является ссылочным номером для каталога, содержащего файл.

Ты можешь использовать FSCTL_ENUM_USN_DATA искать файл (или каталог!) по номеру ссылки. Вам нужно будет пройтись по дереву, чтобы построить полный путь. Есть некоторый код в этот ответ что может быть полезным в качестве примера.

Этот код ищет ссылочный номер для корневого каталога, чтобы вы могли сказать, когда вы закончите:

HANDLE rootdir_handle;
USN_RECORD * rootdir_usn;

printf("Opening root directory.\n");

rootdir_handle = CreateFile(L"\\\\?\\C:\\", GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_FLAG_BACKUP_SEMANTICS, NULL);

if (rootdir_handle == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
return 0;
}

if (!DeviceIoControl(rootdir_handle, FSCTL_READ_FILE_USN_DATA, NULL, 0,
buffer, BUFFER_SIZE, &bytecount, NULL))
{
printf("FSCTL_READ_FILE_USN_DATA: %u\n", GetLastError());
}
else
{
rootdir_usn = (USN_RECORD *)buffer;
show_record(rootdir_usn, FALSE);
rootdir = rootdir_usn->FileReferenceNumber;
}
2

Другие решения

Я пытался избежать рекурсивного поиска в родительском каталоге, чтобы получить полный путь, так как мой первоначальный тест увеличил общее время, необходимое для определения пути.

Потратив пару часов с windbg и небольшой помощью от OSR Online fourm, я наконец-то получил его.

опубликовать ответ, чтобы помочь кому-то еще, кто сталкивается с той же проблемой.

Мое текущее решение заключается в следующем.

USN_RECORD-> FileReferenceNumber полностью зависит от версии USN_RECORD. После извлечения FILE_ID_DESCRIPTOR из FileReferenceNumber вы можете вызвать OpenFileById () и передать FILE_ID_DESCRIPTOR, чтобы получить дескриптор для родительской папки.

Затем вы можете вызвать GetFinalPathNameByHandle (), чтобы получить путь ParentDirectory.

Ниже приведен код для извлечения FILE_ID_DESCRIPTOR

Если FileId в USN_RECORD_V2, FileReferenceNu DWORDLONG.

FILE_ID_DESCRIPTOR getFileIdDescriptor(const DWORDLONG fileId)
{
FILE_ID_DESCRIPTOR fileDescriptor;
fileDescriptor.Type = FileIdType;
fileDescriptor.FileId.QuadPart = fileId;
fileDescriptor.dwSize = sizeof(fileDescriptor);

return fileDescriptor;
}

Если вы в конечном итоге UNS_RECORD_V3, fileId имеет тип FILE_ID_128, и вот код для извлечения FileId.

FILE_ID_DESCRIPTOR getFileIdDescriptor(const FILE_ID_128& fileId)
{
FILE_ID_DESCRIPTOR fileDescriptor;
fileDescriptor.Type = ExtendedFileIdType;
fileDescriptor.ExtendedFileId = fileId;
fileDescriptor.dwSize = sizeof(fileDescriptor);
return fileDescriptor;
}

После того, как вы извлечете FileId, вот как вы можете получить родительский путь.

TCHAR filePath[MAX_PATH];
HANDLE hh= OpenFileById(volume_, &(getFileIdDescriptor(UsnRecord->FileReferenceNumber)), 0, 0, 0, 0);
GetFinalPathNameByHandle(hh,filePath, MAX_PATH, 0);

Вы можете найти справочную реализацию @ https://github.com/kirankumarcelestial/NTFSChangeJournalUserMode

Однако я обнаружил, что GetFilePathNameByHandle() на самом деле медленно, и этот API в конечном итоге вызовет GetFileInformationByHandleEx(), а также GetFileInformationByHandleEx() это один вызов KernelMode, и это будет эффективным способом получения родительской информации.

1

По вопросам рекламы [email protected]