Here is a very small example of using the PathFromFrn() to enumerate the MFT with path information. What I did was use ParentFileReference and append the filename.
BTW: It will be slow if you output to the debug window and it's currently synchrounous example.
You can easily use it like this:
Dim myMFT AsNew EnumMFT
myMFT.FindAllFiles("E:")
Imports System.Runtime.InteropServices
Public Class EnumMFT
Private Const INVALID_HANDLE_VALUE = (-1)
Private Const GENERIC_READ = &H80000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_EXISTING = 3
Private Const FILE_READ_ATTRIBUTES = &H80
Private Const FileNameInformationClass = 9
Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Private Const FILE_OPEN_FOR_BACKUP_INTENT = &H4000
Private Const FILE_OPEN_BY_FILE_ID = &H2000
Private Const FILE_OPEN = &H1
Private Const OBJ_CASE_INSENSITIVE = &H40
Private Const FSCTL_ENUM_USN_DATA = &H900B3<StructLayout(LayoutKind.Sequential)> _
Private Structure MFT_ENUM_DATA
Dim StartFileReferenceNumber As Long
Dim LowUsn As Long
Dim HighUsn As Long
End Structure<StructLayout(LayoutKind.Sequential)> _
Private Structure USN_RECORD
Dim RecordLength As Integer
Dim MajorVersion As Short
Dim MinorVersion As Short
Dim FileReferenceNumber As Long
Dim ParentFileReferenceNumber As Long
Dim Usn As Long
Dim TimeStamp As Long
Dim Reason As Integer
Dim SourceInfo As Integer
Dim SecurityId As Integer
Dim FileAttributes As Integer
Dim FileNameLength As Short
Dim FileNameOffset As Short
End Structure<StructLayout(LayoutKind.Sequential)> _
Private Structure IO_STATUS_BLOCK
Dim Status As Integer
Dim Information As Integer
End Structure<StructLayout(LayoutKind.Sequential)> _
Private Structure UNICODE_STRING
Dim Length As Short
Dim MaximumLength As Short
Dim Buffer As IntPtr
End Structure<StructLayout(LayoutKind.Sequential)> _
Private Structure OBJECT_ATTRIBUTES
Dim Length As Integer
Dim RootDirectory As IntPtr
Dim ObjectName As IntPtr
Dim Attributes As Integer
Dim SecurityDescriptor As Integer
Dim SecurityQualityOfService As Integer
End Structure
'// MFT_ENUM_DATA
<DllImport("kernel32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function DeviceIoControl(ByVal hDevice As IntPtr, ByVal dwIoControlCode As Integer, ByRef lpInBuffer As MFT_ENUM_DATA, ByVal nInBufferSize As Integer, ByVal lpOutBuffer As IntPtr, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As IntPtr) As Boolean
End Function<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As IntPtr) As IntPtr
End Function<DllImport("kernel32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function CloseHandle(ByVal lpObject As IntPtr) As Int32
End Function<DllImport("ntdll.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function NtCreateFile(ByRef FileHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef ObjectAttributes As OBJECT_ATTRIBUTES, ByRef IoStatusBlock As IO_STATUS_BLOCK, ByVal AllocationSize As Integer, ByVal FileAttribs As Integer, ByVal SharedAccess As Integer, ByVal CreationDisposition As Integer, ByVal CreateOptions As Integer, ByVal EaBuffer As Integer, ByVal EaLength As Integer) As Integer
End Function<DllImport("ntdll.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function NtQueryInformationFile(ByVal FileHandle As IntPtr, ByRef IoStatusBlock As IO_STATUS_BLOCK, ByVal FileInformation As IntPtr, ByVal Length As Integer, ByVal FileInformationClass As Integer) As Integer
End Function
Private m_hCJ As IntPtr
Private m_Buffer As IntPtr
Private m_BufferSize As Integer
Private m_DriveLetter As String
Private Function OpenVolume(ByVal szDriveLetter As String) As IntPtr
Dim hCJ As IntPtr '// volume handle
m_DriveLetter = szDriveLetter
hCJ = CreateFile("\\.\" & szDriveLetter, GENERIC_READ, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, 0)
Return hCJ
End Function
Private Sub Cleanup()
If m_hCJ <> 0 Then
' Close the volume handle.
CloseHandle(m_hCJ)
m_hCJ = INVALID_HANDLE_VALUE
End If
If m_Buffer <> 0 Then
' Free the allocated memory
Marshal.FreeHGlobal(m_Buffer)
m_Buffer = IntPtr.Zero
End If
End Sub
Public Sub FindAllFiles(ByVal szDriveLetter As String)
Dim usnRecord As USN_RECORD
Dim mft As MFT_ENUM_DATA
Dim dwRetBytes As Integer
Dim cb As Integer
' This shouldn't be called more than once.
If m_Buffer.ToInt32 <> 0 Then
Console.WriteLine("invalid buffer")
Exit Sub
End If
' Assign buffer size
m_BufferSize = 65536 '64KB
' Allocate a buffer to use for reading records.
m_Buffer = Marshal.AllocHGlobal(m_BufferSize)
' Open the volume handle
m_hCJ = OpenVolume(szDriveLetter)
' Check if the volume handle is valid.
If m_hCJ = INVALID_HANDLE_VALUE Then
Console.WriteLine("Couldn't open handle to the volume.")
Cleanup()
Exit Sub
End If
mft.StartFileReferenceNumber = 0
mft.LowUsn = 0
mft.HighUsn = Long.MaxValue
Do
If DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, dwRetBytes, IntPtr.Zero) Then
cb = dwRetBytes
' Pointer to the first record
Dim pUsnRecord As New IntPtr(m_Buffer.ToInt32() + 8)
While (dwRetBytes > 8)
' Copy pointer to USN_RECORD structure.
usnRecord = Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType)
' The filename within the USN_RECORD.
Dim FileName As String = Marshal.PtrToStringUni(New IntPtr(pUsnRecord.ToInt32() + usnRecord.FileNameOffset), _
usnRecord.FileNameLength / 2)
If usnRecord.FileAttributes And vbDirectory Then
Dim dirPath As String = PathFromFrn(usnRecord.ParentFileReferenceNumber)
' directory
Console.WriteLine("Directory {0} ", szDriveLetter & dirPath)
Else
' files
Dim filePath As String = PathFromFrn(usnRecord.ParentFileReferenceNumber) & "\" & FileName
Console.WriteLine("File {0} ", szDriveLetter & filePath)
End If
' Pointer to the next record in the buffer.
pUsnRecord = New IntPtr(pUsnRecord.ToInt32() + usnRecord.RecordLength)
dwRetBytes -= usnRecord.RecordLength
End While
' The first 8 bytes is always the start of the next USN.
mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0)
Else
Exit Do
End If ' DeviceIoControl)
Loop Until cb <= 8
'// cleanup
Cleanup()
Console.WriteLine("Done")
End Sub
Private Function PathFromFrn(ByVal Id As Long) As String
Dim fOk As Integer
Dim FileName As String = String.Empty
Dim UnicodeString As UNICODE_STRING
Dim ObjAttributes As OBJECT_ATTRIBUTES
Dim IoStatusBlock As IO_STATUS_BLOCK
Dim hFile As IntPtr ' out handle
Dim Buffer As IntPtr = Marshal.AllocHGlobal(4096) ' Raw buffer
Dim Refptr As IntPtr = Marshal.AllocHGlobal(8) ' 8 byte FileID
Dim ObjAtt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ObjAttributes)) 'pointer to the unicode string struct
' pointer>>fileid
Marshal.WriteInt64(Refptr, 0, Id)
' 8 byte file id
UnicodeString.Length = 8
UnicodeString.MaximumLength = 8
UnicodeString.Buffer = Refptr
' copy unicode structure to pointer
Marshal.StructureToPtr(UnicodeString, ObjAtt, True)
' InitializeObjectAttributes Macro
ObjAttributes.Length = Marshal.SizeOf(ObjAttributes)
ObjAttributes.ObjectName = ObjAtt
ObjAttributes.RootDirectory = m_hCJ
ObjAttributes.Attributes = OBJ_CASE_INSENSITIVE
fOk = NtCreateFile(hFile, 0, ObjAttributes, IoStatusBlock, 0, 0, _
FILE_SHARE_READ Or FILE_SHARE_WRITE, _
FILE_OPEN, FILE_OPEN_BY_FILE_ID Or FILE_OPEN_FOR_BACKUP_INTENT, 0, 0)
If fOk <> INVALID_HANDLE_VALUE Then
fOk = NtQueryInformationFile(hFile, IoStatusBlock, Buffer, 4096, FileNameInformationClass)
If fOk = 0 Then
' The first 4 bytes is the length
Dim FileLength As Integer = Marshal.ReadInt32(Buffer, 0)
' The filename is just after the first 4 bytes.
FileName = Marshal.PtrToStringUni(New IntPtr(Buffer.ToInt32() + 4), FileLength / 2)
End If
End If
' free allocated memory and handles
CloseHandle(hFile)
Marshal.FreeHGlobal(Buffer)
Marshal.FreeHGlobal(ObjAtt)
Marshal.FreeHGlobal(Refptr)
Return FileName
End Function
End Class