5

In my C# application, I already have a way to examine the file system but I would like to take advantage of reading from the Master File Table (MFT) because it is so much faster. I understand that 1) it is a proprietary specification and therefore subject to change without notice, and 2) it is only accessible when the application is running under administrative privileges.

I managed to read the Master File Table via this code. From the MFT query, I get a file name and a so-called file reference number. What I can't find is how to transition to a .NET FileInfo object, or even to a Windows API file handle, so that I can get more information about the files/folders in question, like: file size, full path, date stamps, etc.

Craig Silver
  • 587
  • 4
  • 25
  • Once you are able to transform to a file handle or a file info object, you may probably end up doing all what a framework or the file api does. As result there may not be a significant gain for the effort. MFT may not prove to be beneficial unless you keep it low level, that defeats the purpose of managed code. – pushpraj Jul 13 '14 at 16:28
  • I disagree but perhaps I was not clear before. The user will enter some search text that will be used as a filespec. Querying the MFT for partial matches throughout a drive volume will be way, way faster than doing it through a framework or the api. Once I have this shortlist, I will use slower means to flesh out details of the shortlisted items. Examples of this are already implemented in the freeware programs [Everything](http://www.voidtools.com/) and [UltraSearch](http://www.jam-software.com/ultrasearch/). – Craig Silver Jul 15 '14 at 06:23

1 Answers1

5

There's two straightforward approaches you can take to open the file when you're lurking around in the MFT - You can call OpenFileByID with that file reference number (Vista and higher), or you can build the fully qualified file name by traversing the list you built when reading the MFT and then calling the CreateFile with the assembled name.

You want to get the handle from CreateFile or OpenFileByID into a SafeFileHandle:

[DllImport( "kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode )]
internal static extern SafeFileHandle CreateFile( string lpFileName, EFileAccess dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile );

[DllImport( "kernel32.dll", SetLastError = true )]
internal static extern SafeFileHandle OpenFileById( IntPtr volumeHandle, ref FileIdDescriptor lpFileId, uint dwDesiredAccess, uint dwShareMode, uint lpSecurityAttributes, uint dwFlagsAndAttributes );

Once you have the SafeFileHandle (and you've checked that it's valid), you can pass it to a FileStream constructor and read/write the file like normal.

Every file is represented in the MFT, but there are caveats. For example, a single file can be in the file hierarchy in multiple places, yet there is a single MFT entry for all of 'em - these are the so-called hard links (they're not copies - there are multiple entry points to a file - headaches abound). There are thousands of these. There are APIs for interrogating the hard links, but it gets ugly.

Clay
  • 4,999
  • 1
  • 28
  • 45
  • I am trying `OpenFileById`. I have a value like 1407374883553285 but how do I contruct a Guid object? Here is the pInvoke that I found: `[DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr OpenFileById(IntPtr hFile, FILE_ID_DESCRIPTOR desc, uint dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwFlagas); [StructLayout(LayoutKind.Explicit)] public struct FILE_ID_DESCRIPTOR { [FieldOffset(0)] public uint dwSize; [FieldOffset(4)] public FILE_ID_TYPE type; [FieldOffset(8)] public Guid guid; }` – Craig Silver May 10 '15 at 23:38
  • In the Win API, the FILE_ID_DESCRIPTOR contains a union - that is, the field at offset 8 can be either a GUID or a LARGE_INTEGER - and its interpretation is driven by the FILE_ID_TYPE field. See https://msdn.microsoft.com/en-us/library/windows/desktop/aa364227(v=vs.85).aspx. For your purposes, you can change the `public Guid guid` to `public long FileReferenceNumber` - and set the type to 0. – Clay May 11 '15 at 11:34
  • That worked! I feel way closer. I was able to get the file size, for instance, by passing the handle returned from `OpenFileById()` to `GetFileSizeEx()`, but is there a way to use C#'s `FileInfo` class to get: full path, file name, attributes, size, dates, etc. all in one shot, or must I search for API functions to get all that data, now that all I have is a handle? I guess I could get the full path from the handle and then create the FileInfo object, just looking for the most efficient way. – Craig Silver May 11 '15 at 18:12
  • Cool - I'm glad. There are too many paths to try, aren't there? In my big c# MFT-reading thing, I abandon most of the framework types, and just populate a list of things-of-my-own making that come mostly from the MFT-reading API calls. I had to because I needed support for long (posix) names. However, that handle is good for some .Net APIs,...for example, there's a FileStream constructor that takes it. There are windows APIs that can get you groups of useful information - GetFileInformationByHandle or GetFileInormationByHandleEx...but it does seem that the APIs are a bit disorganized. – Clay May 11 '15 at 20:45
  • Indeed! I feel a bit better knowing that I'm not the only one who finds that. Thanks again for the nudge in the right direction. It moved the needle a lot. – Craig Silver May 12 '15 at 04:57
  • Have you found the solution for this requirement??? If it is solved, please help me to resolve the following thread http://stackoverflow.com/questions/31938722/how-to-read-file-attributes-using-master-file-table-data – thejustv Aug 11 '15 at 10:17
  • Darn! I'm sorry that I missed your question so long ago, thejustv. I read your question.. are you still struggling with this? – Craig Silver Sep 25 '16 at 03:45