How do I get the full path for a USN journal request?

I am trying to go to the MSDN example ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa365736%28v=vs.85%29.aspx ) on how to query the USN log to track file changes to the NTFS drive. The sample code works well.

However, in this sample code, the USN_RECORD structure only returns me the file reference number and file name. It doesn't give me the full path to the file. Does anyone know how to query the USN journal to return the full path? Or is there a way to get the full path from the file reference number?

Thank.

+3


source to share


2 answers


The ParentFileReferenceNumber

structure element USN_RECORD

is the reference number for the directory containing the file.

You can use FSCTL_ENUM_USN_DATA

to search for a file (or directory!) By reference number. You will need to iterate over the tree to build the complete path. There is some code in this answer that might be helpful as an example.



This code looks for a reference number for the root directory, so you can find out when you're done:

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


source


I was trying to avoid recursively searching the parent directory to get the full path, as my initial test increased the total time it took to eliminate the path.

After spending a couple of hours with windbg and some help from OSR Online I finally got it.

post an answer to help someone else who gets into the same problem.

My current solution looks like this.

USN_RECORD-> FileReferenceNumber depends solely on the USN_RECORD version, once you retrieve the FILE_ID_DESCRIPTOR from the FileReferenceNumber you can call OpenFileById () and pass FILE_ID_DESCRIPTOR to get the parent folder handle.

Then you can call GetFinalPathNameByHandle () to get the path to the ParentDirectory.

Below is the code I ended up with to extract FILE_ID_DESCRIPTOR

If FileId is 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;
}

      

If you end up with UNS_RECORD_V3 the fileId is of type FILE_ID_128 and here is the code to extract the 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;
}

      

Once you retrieve the FileId, this is how you can get the parent path.

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

      

you can find reference implementation @ https://github.com/kirankumarcelestial/NTFSChangeJournalUserMode

However, I found that it GetFilePathNameByHandle()

is actually slow, and this API will eventually call GetFileInformationByHandleEx()

, and GetFileInformationByHandleEx()

- this is one call to KernelMode, and that would be an efficient way of getting parent information.

+1


source







All Articles