How to get the full path for USN journal query?

后端 未结 3 861
青春惊慌失措
青春惊慌失措 2021-02-10 04:54

I am trying to go through the example on MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365736%28v=vs.85%29.aspx) on how to query USN journal in order to trace

相关标签:
3条回答
  • 2021-02-10 04:58

    I have been trying to avoid recursive parent directory search to get full path, as my initial test increased overall time it took to resolve the path.

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

    posting the answer to help anyone else who ends up with the same problem.

    My current solution is as follows.

    The USN_RECORD-> FileReferenceNumber is purely dependent on the version of USN_RECORD, once you extract FILE_ID_DESCRIPTOR from FileReferenceNumber, you can call OpenFileById() and pass the FILE_ID_DESCRIPTOR to get handle for the parent folder.

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

    Below is the code i ended up with for extracting FILE_ID_DESCRIPTOR

    If the FileId in USN_RECORD_V2, the 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 endup 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 extract the FileId, here 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 the reference implementation @ https://github.com/kirankumarcelestial/NTFSChangeJournalUserMode

    However I found that GetFilePathNameByHandle() is actually slow, and this API will eventually call GetFileInformationByHandleEx(), and GetFileInformationByHandleEx() is a single call to KernelMode, and this would be effective way to get get Parent Information.

    0 讨论(0)
  • 2021-02-10 05:04

    For the sake of being a Wiki, and to be helpful for the next person searching for this question, and the fact that i want them archived for posterity, here are: the pages on MSDN that explain the Update Sequence Number (USN) Journal, what it is, how it works, and how to query it.

    • Change Journals archive
      • Change Journal Records archive
      • Using the Change Journal Identifier archive
      • Creating, Modifying, and Deleting a Change Journal archive
      • Obtaining a Volume Handle for Change Journal Operations archive
      • Change Journal Operations archive
    0 讨论(0)
  • 2021-02-10 05:20

    The ParentFileReferenceNumber member of the USN_RECORD structure is the reference number for the directory containing the file.

    You can use FSCTL_ENUM_USN_DATA to look up a file (or directory!) by reference number. You will need to iterate up the tree to build the complete path. There is some code in this answer which may be helpful as an example.

    This code looks up the reference number for the root directory, so you can tell when you're finished:

    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;
    }
    
    0 讨论(0)
提交回复
热议问题