2014-02-09 132 views
8

我需要在我的.net應用程序中使用C#訪問Windows MFT(主文件表)。
我已經搜索了這個,並沒有找到任何好的結果。我一直在搜索過去兩天的信息,但一直未能找到任何相關信息。我們如何通過C#訪問MFT

我不是在尋找確切的代碼來做同樣的事情,我只是尋找一些可以讓我開始的信息。

我一直能弄清楚的是我必須使用P/Invoke。
我想知道我將用於訪問MFT的功能。
如果你能夠提供一些代碼示例,那就太棒了。

+0

檢查http://www.codeproject.com/Articles/9293/Undelete-a-file-in-NTFS,只是捏住你需要的本地功能。 – devshorts

+0

@devshorts感謝您的鏈接,我已經檢查過它,但無法找到相關信息。 –

+0

選中此鏈接 - [MFT](http://code.msdn.microsoft.com/windowsdesktop/CCS-LABS-C-Accessing-the-d317805c/sourcecode?fileId=60931&pathId=14261056)。希望你有一些想法... –

回答

19

首先,您必須擁有並聲明訪問MFT的足夠權限 - 這本身就是一種痛苦。然後,您必須獲得捲上文件/文件夾的句柄 - 用於最後一步中的調用...即在循環中調用Windows API(稱爲DeviceIOControl)並從返回的API調用中讀取條目 - 這是它自己的特別頭痛。

概念 - 這看起來像:

static void Main(string[ ] args) 
{ 
    if (Privileges.HasBackupAndRestorePrivileges) 
    { 
    using (var volume = GetVolumeHandle("C:\\")) 
    { 
     ReadMft(volume); 
    } 
    } 
} 

如果你把每一種反過來,主張足夠的權限是最不起眼的部分。有一個Windows API來更改正在運行的令牌的權限 - 並使用它來添加必要的權限。以下是我用來聲明這些權限的類的摘錄。你可以聲稱更多的特權 - 但這應該足以閱讀MFT。

您的應用程序需要運行在實際可以獲得必要權限的帳戶下 - 管理員帳戶是好的。另外,備份操作員也可以工作。

public static class Privileges 
{ 
    private static int asserted = 0; 
    private static bool hasBackupPrivileges = false; 

    public static bool HasBackupAndRestorePrivileges 
    { 
    get { return AssertPriveleges(); } 
    } 

    /// <remarks> 
    /// First time this method is called, it attempts to set backup privileges for the current process. 
    /// Subsequently, it returns the results of that first call. 
    /// </remarks> 
    private static bool AssertPriveleges() 
    { 
    bool success = false; 
    var wasAsserted = Interlocked.CompareExchange(ref asserted, 1, 0); 
    if (wasAsserted == 0) // first time here? come on in! 
    { 
     success = 
     AssertPrivelege(NativeMethods.SE_BACKUP_NAME) 
     AssertPrivelege(NativeMethods.SE_RESTORE_NAME); 

     hasBackupPrivileges = success; 

    } 
    return hasBackupPrivileges; 
    } 


    private static bool AssertPrivelege(string privelege) 
    { 
    IntPtr token; 
    var tokenPrivileges = new NativeMethods.TOKEN_PRIVILEGES(); 
    tokenPrivileges.Privileges = new NativeMethods.LUID_AND_ATTRIBUTES[ 1 ]; 

    var success = 
     NativeMethods.OpenProcessToken(NativeMethods.GetCurrentProcess(), NativeMethods.TOKEN_ADJUST_PRIVILEGES, out token) 
     && 
     NativeMethods.LookupPrivilegeValue(null, privelege, out tokenPrivileges.Privileges[ 0 ].Luid); 

    try 
    { 
     if (success) 
     { 
     tokenPrivileges.PrivilegeCount = 1; 
     tokenPrivileges.Privileges[ 0 ].Attributes = NativeMethods.SE_PRIVILEGE_ENABLED; 
     success = 
      NativeMethods.AdjustTokenPrivileges(token, false, ref tokenPrivileges, Marshal.SizeOf(tokenPrivileges), IntPtr.Zero, IntPtr.Zero) 
      && 
      (Marshal.GetLastWin32Error() == 0); 
     } 

     if (!success) 
     { 
     Console.WriteLine("Could not assert privilege: " + privelege); 
     } 
    } 
    finally 
    { 
     NativeMethods.CloseHandle(token); 
    } 

    return success; 
    } 
} 

一旦你過了這一關,剩下的就是 - 嗯......還是一個默默無聞的節日。你必須得到一個文件或文件夾的句柄 - 用備份語義。您可能會在您之後的捲上的任何舊文件上打開FileStream,並且FileStream將有一個可用於後續調用的句柄。這不完全是我的應用程序 - 但我的應用程序必須做的事情,這個答案不必做。

internal static SafeFileHandle GetVolumeHandle(string pathToVolume, NativeMethods.EFileAccess access = NativeMethods.EFileAccess.AccessSystemSecurity | NativeMethods.EFileAccess.GenericRead | NativeMethods.EFileAccess.ReadControl) 
    { 
    var attributes = (uint) NativeMethods.EFileAttributes.BackupSemantics; 
    var handle = NativeMethods.CreateFile(pathToVolume, access, 7U, IntPtr.Zero, (uint) NativeMethods.ECreationDisposition.OpenExisting, attributes, IntPtr.Zero); 
    if (handle.IsInvalid) 
    { 
     throw new IOException("Bad path"); 
    } 

    return handle; 
    } 

對於ReadMft - 有一個相當複雜的Windows API函數 - DeviceIoControl的 - 即取緩衝器與史詩各種輸入,並返回含心態彎曲多種輸出緩衝器。這是一種用於查詢有關各種設備信息的全能API,而包含MFT的卷是一個設備。

要讀取MFT,可以使用設備IO控制代碼FSCTL_ENUM_USN_DATA調用DeviceIOControl - 它將爲MFT中的每個記錄返回一個USN記錄。每次調用都有很多記錄 - 每次調用後,都會使用前一次調用返回的第一個信息參數化循環中的下一個調用。

順便說一句 - 我改名爲我的代碼中的Windows API調用,使它們看起來更像.Net。我不確定我將來會這樣做。

特別說明這裏:每個文件都有一條記錄 - 無論有多少硬鏈接 - 您必須進行額外的調用來枚舉硬鏈接。

文件系統層次結構編碼在您從調用中返回的結構的FileReferenceNumber和ParentFileReferenceNumber中。你名義上將這些usn記錄保存到列表中,按照FileReferenceNumber排序併爲ParentFileReferenceNumber創建一個二級索引 - 或者類似的東西。爲了說明的目的,這段代碼只是轉儲MFT條目。

本示例使用不安全的代碼 - 並修復包含輸入和輸出的緩衝區的位置。有不同的方式來解決這個問題 - 但這是很好的和快樂的。如果你使用這個,你必須在你的項目設置中允許不安全的代碼。

public unsafe static bool ReadMft(SafeHandle volume) 
{ 
    var outputBufferSize = 1024 * 1024; 
    var input = new NativeMethods.MFTEnumDataV0(); 
    var usnRecord = new NativeMethods.UsnRecordV2(); 

    var outputBuffer = new byte[ outputBufferSize ]; 

    var okay = true; 
    var doneReading = false; 

    try 
    { 
    fixed (byte* pOutput = outputBuffer) 
    { 
     input.StartFileReferenceNumber = 0; 
     input.LowUsn = 0; 
     input.HighUsn = long.MaxValue; 

     using (var stream = new MemoryStream(outputBuffer, true)) 
     { 
     while (!doneReading) 
     { 
      var bytesRead = 0U; 
      okay = NativeMethods.DeviceIoControl 
      (
      volume.DangerousGetHandle(), 
      NativeMethods.DeviceIOControlCode.FsctlEnumUsnData, 
      (byte*) &input.StartFileReferenceNumber, 
      (uint) Marshal.SizeOf(input), 
      pOutput, 
      (uint) outputBufferSize, 
      out bytesRead, 
      IntPtr.Zero 
     ); 

      if (!okay) 
      { 
      var error = Marshal.GetLastWin32Error(); 
      okay = error == NativeMethods.ERROR_HANDLE_EOF; 
      if (!okay) 
      { 
       Console.WriteLine("Crap! Windows error " + error.ToString()); 
       break; 
      } 
      else 
      { 
       doneReading = true; 
      } 
      } 

      input.StartFileReferenceNumber = stream.ReadULong(); 
      while (stream.Position < bytesRead) 
      { 
      usnRecord.Read(stream); 

      //-->>>>>>>>>>>>>>>>> 
      //--> just an example of reading out the record... 
      Console.WriteLine("FRN:" + usnRecord.FileReferenceNumber.ToString()); 
      Console.WriteLine("Parent FRN:" + usnRecord.ParentFileReferenceNumber.ToString()); 
      Console.WriteLine("File name:" + usnRecord.FileName); 
      Console.WriteLine("Attributes: " + (NativeMethods.EFileAttributes) usnRecord.FileAttributes); 
      Console.WriteLine("Timestamp:" + usnRecord.TimeStamp); 
      //-->>>>>>>>>>>>>>>>>>> 
      } 
      stream.Seek(0, SeekOrigin.Begin); 
     } 
     } 
    } 
    } 
    catch (Exception ex) 
    { 
    Console.Write(ex); 
    okay = false; 
    } 
    return okay; 
} 

我做了什麼大概的那種俗氣給自己節省了大量的工作 - 我加僞序列化方法爲windows API的結構 - 使他們能夠讀出自己流的。例如,usnRecord用來讀取在上述代碼緩衝器是windows API結構 - 但實現了串行化接口:

[StructLayout(LayoutKind.Sequential)] 
internal struct UsnRecordV2: IBinarySerialize 
{ 
    public uint RecordLength; 
    public ushort MajorVersion; 
    public ushort MinorVersion; 
    public ulong FileReferenceNumber; 
    public ulong ParentFileReferenceNumber; 
    public long Usn; 
    public long TimeStamp; 
    public UsnReason Reason; 
    public uint SourceInfo; 
    public uint SecurityId; 
    public uint FileAttributes; 
    public ushort FileNameLength; 
    public ushort FileNameOffset; 
    public string FileName; 

    /// <remarks> 
    /// Note how the read advances to the FileNameOffset and reads only FileNameLength bytes. 
    /// </remarks> 
    public void Read(Stream stream) 
    { 
    var startOfRecord = stream.Position; 
    RecordLength = stream.ReadUInt(); 
    MajorVersion = stream.ReadUShort(); 
    MinorVersion = stream.ReadUShort(); 
    FileReferenceNumber = stream.ReadULong(); 
    ParentFileReferenceNumber = stream.ReadULong(); 
    Usn = stream.ReadLong(); 
    TimeStamp = stream.ReadLong(); 
    Reason = (UsnReason) stream.ReadUInt(); 
    SourceInfo = stream.ReadUInt(); 
    SecurityId = stream.ReadUInt(); 
    FileAttributes = stream.ReadUInt(); 
    FileNameLength = stream.ReadUShort(); 
    FileNameOffset = stream.ReadUShort(); 
    stream.Position = startOfRecord + FileNameOffset; 
    FileName = Encoding.Unicode.GetString(stream.ReadBytes(FileNameLength)); 
    stream.Position = startOfRecord + RecordLength; 

    } 

    /// <summary>We never write instances of this structure</summary> 
    void IBinarySerialize.Write(Stream stream) 
    { 
    throw new NotImplementedException(); 
    } 
} 

...其中IBinarySerialze是:

public interface IBinarySerialize 
{ 
    /// <summary>Reads an object's data from a <see cref="Stream"/></summary> 
    void Read(Stream stream); 

    /// <summary>Writes an objects serializable content to a <see cref="Stream"/></summary> 
    void Write(Stream stream); 

} 

有流結構中使用的擴展方法。基本上,他們從BinaryReader中解除。爲什麼?因爲在.Net 3.5中 - 我必須先寫這個--BBCL BinaryReader會關閉你把它包裹起來的流 - 而且我有很多地方只是無法忍受。

internal static class StreamingExtensions 
{ 
    public static ushort ReadUShort(this Stream stream) 
    { 
    return BitConverter.ToUInt16(ReadBytes(stream, 2), 0); 
    } 

    public static uint ReadUInt(this Stream stream) 
    { 
    return BitConverter.ToUInt32(ReadBytes(stream, 4), 0); 
    } 

    public static long ReadLong(this Stream stream) 
    { 
    return BitConverter.ToInt64(ReadBytes(stream, 8), 0); 
    } 

    public static ulong ReadULong(this Stream stream) 
    { 
    return BitConverter.ToUInt64(ReadBytes(stream, 8), 0); 
    } 
    public static byte[ ] ReadBytes(this Stream stream, int length, bool throwIfIncomplete = false) 
    { 
    var bytes = new byte[ length ]; 
    var bytesRead = 0; 
    var offset = 0; 
    if (length > 0) 
    { 
     while (offset < length) 
     { 
     bytesRead = stream.Read(bytes, offset, length - offset); 
     if (bytesRead == 0) 
     { 
      if (throwIfIncomplete) throw new InvalidOperationException("incomplete"); 
      break; 
     } 
     offset += bytesRead; 
     } 
    } 
    return bytes; 
    } 
} 

爲了完整起見,下面是本地方法,枚舉,常量和噪聲。大部分來自PInvoke.net,但是再次......許多這些東西的名稱都是.net-ified。對純粹主義者抱歉。

internal class NativeMethods 
{ 
    internal const int ERROR_HANDLE_EOF = 38; 

    //--> Privilege constants.... 
    internal const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002; 
    internal const string SE_BACKUP_NAME = "SeBackupPrivilege"; 
    internal const string SE_RESTORE_NAME = "SeRestorePrivilege"; 
    internal const string SE_SECURITY_NAME = "SeSecurityPrivilege"; 
    internal const string SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege"; 
    internal const string SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege"; 
    internal const string SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege"; 
    internal const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege"; 
    internal const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege"; 
    internal const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege"; 
    internal const string SE_TCB_NAME = "SeTcbPrivilege"; 
    internal const string SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege"; 
    internal const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege"; 

    //--> For starting a process in session 1 from session 0... 
    internal const int TOKEN_DUPLICATE = 0x0002; 
    internal const uint MAXIMUM_ALLOWED = 0x2000000; 
    internal const int CREATE_NEW_CONSOLE = 0x00000010; 
    internal const uint TOKEN_ADJUST_PRIVILEGES = 0x0020; 
    internal const int TOKEN_QUERY = 0x00000008; 


    [DllImport("advapi32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); 
    [DllImport("kernel32.dll")] 
    internal static extern IntPtr GetCurrentProcess(); 
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid); 
    [DllImport("advapi32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, Int32 BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static unsafe extern bool DeviceIoControl(IntPtr hDevice, DeviceIOControlCode controlCode, byte* lpInBuffer, uint nInBufferSize, byte* lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); 
    [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)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool CloseHandle(IntPtr hObject); 


    [Flags] 
    internal enum EMethod: uint 
    { 
    Buffered = 0, 
    InDirect = 1, 
    OutDirect = 2, 
    Neither = 3 
    } 

    [Flags] 
    internal enum EFileAccess: uint 
    { 
    GenericRead = 0x80000000, 
    GenericWrite = 0x40000000, 
    GenericExecute = 0x20000000, 
    GenericAll = 0x10000000, 

    Delete = 0x10000, 
    ReadControl = 0x20000, 
    WriteDAC = 0x40000, 
    WriteOwner = 0x80000, 
    Synchronize = 0x100000, 

    StandardRightsRequired = 0xF0000, 
    StandardRightsRead = ReadControl, 
    StandardRightsWrite = ReadControl, 
    StandardRightsExecute = ReadControl, 
    StandardRightsAll = 0x1F0000, 
    SpecificRightsAll = 0xFFFF, 

    AccessSystemSecurity = 0x1000000, 
    MaximumAllowed = 0x2000000 
    } 


    [Flags] 
    internal enum EFileDevice: uint 
    { 
    Beep = 0x00000001, 
    CDRom = 0x00000002, 
    CDRomFileSytem = 0x00000003, 
    Controller = 0x00000004, 
    Datalink = 0x00000005, 
    Dfs = 0x00000006, 
    Disk = 0x00000007, 
    DiskFileSystem = 0x00000008, 
    FileSystem = 0x00000009, 
    InPortPort = 0x0000000a, 
    Keyboard = 0x0000000b, 
    Mailslot = 0x0000000c, 
    MidiIn = 0x0000000d, 
    MidiOut = 0x0000000e, 
    Mouse = 0x0000000f, 
    MultiUncProvider = 0x00000010, 
    NamedPipe = 0x00000011, 
    Network = 0x00000012, 
    NetworkBrowser = 0x00000013, 
    NetworkFileSystem = 0x00000014, 
    Null = 0x00000015, 
    ParallelPort = 0x00000016, 
    PhysicalNetcard = 0x00000017, 
    Printer = 0x00000018, 
    Scanner = 0x00000019, 
    SerialMousePort = 0x0000001a, 
    SerialPort = 0x0000001b, 
    Screen = 0x0000001c, 
    Sound = 0x0000001d, 
    Streams = 0x0000001e, 
    Tape = 0x0000001f, 
    TapeFileSystem = 0x00000020, 
    Transport = 0x00000021, 
    Unknown = 0x00000022, 
    Video = 0x00000023, 
    VirtualDisk = 0x00000024, 
    WaveIn = 0x00000025, 
    WaveOut = 0x00000026, 
    Port8042 = 0x00000027, 
    NetworkRedirector = 0x00000028, 
    Battery = 0x00000029, 
    BusExtender = 0x0000002a, 
    Modem = 0x0000002b, 
    Vdm = 0x0000002c, 
    MassStorage = 0x0000002d, 
    Smb = 0x0000002e, 
    Ks = 0x0000002f, 
    Changer = 0x00000030, 
    Smartcard = 0x00000031, 
    Acpi = 0x00000032, 
    Dvd = 0x00000033, 
    FullscreenVideo = 0x00000034, 
    DfsFileSystem = 0x00000035, 
    DfsVolume = 0x00000036, 
    Serenum = 0x00000037, 
    Termsrv = 0x00000038, 
    Ksec = 0x00000039, 
    // From Windows Driver Kit 7 
    Fips = 0x0000003A, 
    Infiniband = 0x0000003B, 
    Vmbus = 0x0000003E, 
    CryptProvider = 0x0000003F, 
    Wpd = 0x00000040, 
    Bluetooth = 0x00000041, 
    MtComposite = 0x00000042, 
    MtTransport = 0x00000043, 
    Biometric = 0x00000044, 
    Pmi = 0x00000045 
    } 

    internal enum EFileIOCtlAccess: uint 
    { 
    Any = 0, 
    Special = Any, 
    Read = 1, 
    Write = 2 
    } 

    internal enum DeviceIOControlCode: uint 
    { 
    FsctlEnumUsnData = (EFileDevice.FileSystem << 16) | (44 << 2) | EMethod.Neither | (EFileIOCtlAccess.Any << 14), 
    FsctlReadUsnJournal = (EFileDevice.FileSystem << 16) | (46 << 2) | EMethod.Neither | (EFileIOCtlAccess.Any << 14), 
    FsctlReadFileUsnData = (EFileDevice.FileSystem << 16) | (58 << 2) | EMethod.Neither | (EFileIOCtlAccess.Any << 14), 
    FsctlQueryUsnJournal = (EFileDevice.FileSystem << 16) | (61 << 2) | EMethod.Buffered | (EFileIOCtlAccess.Any << 14), 
    FsctlCreateUsnJournal = (EFileDevice.FileSystem << 16) | (57 << 2) | EMethod.Neither | (EFileIOCtlAccess.Any << 14) 
    } 

    /// <summary>Control structure used to interrogate MFT data using DeviceIOControl from the user volume</summary> 
    [StructLayout(LayoutKind.Sequential)] 
    internal struct MFTEnumDataV0 
    { 
    public ulong StartFileReferenceNumber; 
    public long LowUsn; 
    public long HighUsn; 
    } 


    /// <summary>A structure resurned form USN queries</summary> 
    /// <remarks> 
    /// FileName is synthetic...composed during a read of the structure and is not technically 
    /// part of the Win32 API's definition...although the actual FileName is contained 
    /// "somewhere" in the structure's trailing bytes, according to FileNameLength and FileNameOffset. 
    /// 
    /// Alignment boundaries are enforced, and so, the RecordLength 
    /// may be somewhat larger than the accumulated lengths of the members plus the FileNameLength. 
    /// </remarks> 
    [StructLayout(LayoutKind.Sequential)] 
    internal struct UsnRecordV2: IBinarySerialize 
    { 
    public uint RecordLength; 
    public ushort MajorVersion; 
    public ushort MinorVersion; 
    public ulong FileReferenceNumber; 
    public ulong ParentFileReferenceNumber; 
    public long Usn; 
    public long TimeStamp; 
    public UsnReason Reason; 
    public uint SourceInfo; 
    public uint SecurityId; 
    public uint FileAttributes; 
    public ushort FileNameLength; 
    public ushort FileNameOffset; 
    public string FileName; 

    /// <remarks>Note how the read advances to the FileNameOffset and reads only FileNameLength bytes</remarks> 
    public void Read(Stream stream) 
    { 
     var startOfRecord = stream.Position; 
     RecordLength = stream.ReadUInt(); 
     MajorVersion = stream.ReadUShort(); 
     MinorVersion = stream.ReadUShort(); 
     FileReferenceNumber = stream.ReadULong(); 
     ParentFileReferenceNumber = stream.ReadULong(); 
     Usn = stream.ReadLong(); 
     TimeStamp = stream.ReadLong(); 
     Reason = (UsnReason) stream.ReadUInt(); 
     SourceInfo = stream.ReadUInt(); 
     SecurityId = stream.ReadUInt(); 
     FileAttributes = stream.ReadUInt(); 
     FileNameLength = stream.ReadUShort(); 
     FileNameOffset = stream.ReadUShort(); 
     stream.Position = startOfRecord + FileNameOffset; 
     FileName = Encoding.Unicode.GetString(stream.ReadBytes(FileNameLength)); 
     stream.Position = startOfRecord + RecordLength; 

    } 

    void IBinarySerialize.Write(Stream stream) 
    { 
     throw new NotImplementedException(); 
    } 
    } 

    /// <summary>Structure returned from USN query that describes the state of the journal</summary> 
    [StructLayout(LayoutKind.Sequential)] 
    internal struct UsnJournalDataV1: IBinarySerialize 
    { 
    public ulong UsnJournalId; 
    public long FirstUsn; 
    public long NextUsn; 
    public long LowestValidUsn; 
    public long MaxUsn; 
    public ulong MaximumSize; 
    public ulong AllocationDelta; 
    public ushort MinSupportedMajorVersion; 
    public ushort MaxSupportedMajorVersion; 

    public void Read(Stream stream) 
    { 
     UsnJournalId = stream.ReadULong(); 
     FirstUsn = stream.ReadLong(); 
     NextUsn = stream.ReadLong(); 
     LowestValidUsn = stream.ReadLong(); 
     MaxUsn = stream.ReadLong(); 
     MaximumSize = stream.ReadULong(); 
     AllocationDelta = stream.ReadULong(); 
     MinSupportedMajorVersion = stream.ReadUShort(); 
     MaxSupportedMajorVersion = stream.ReadUShort(); 
    } 

    void IBinarySerialize.Write(Stream stream) 
    { 
     throw new NotImplementedException(); 
    } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct LUID 
    { 
    public UInt32 LowPart; 
    public Int32 HighPart; 
    } 


    [StructLayout(LayoutKind.Sequential)] 
    internal struct LUID_AND_ATTRIBUTES 
    { 
    public LUID Luid; 
    public UInt32 Attributes; 
    } 


    internal struct TOKEN_PRIVILEGES 
    { 
    public UInt32 PrivilegeCount; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]  // !! think we only need one 
    public LUID_AND_ATTRIBUTES[ ] Privileges; 
    } 

    [Flags] 
    internal enum EFileAttributes: uint 
    { 
    /// <summary/> 
    None = 0, 

    //--> these are consistent w/ .Net FileAttributes... 
    Readonly = 0x00000001, 
    Hidden = 0x00000002, 
    System = 0x00000004, 
    Directory = 0x00000010, 
    Archive = 0x00000020, 
    Device = 0x00000040, 
    Normal = 0x00000080, 
    Temporary = 0x00000100, 
    SparseFile = 0x00000200, 
    ReparsePoint = 0x00000400, 
    Compressed = 0x00000800, 
    Offline = 0x00001000, 
    NotContentIndexed = 0x00002000, 
    Encrypted = 0x00004000, 

    //--> additional CreateFile call attributes... 
    Write_Through = 0x80000000, 
    Overlapped = 0x40000000, 
    NoBuffering = 0x20000000, 
    RandomAccess = 0x10000000, 
    SequentialScan = 0x08000000, 
    DeleteOnClose = 0x04000000, 
    BackupSemantics = 0x02000000, 
    PosixSemantics = 0x01000000, 
    OpenReparsePoint = 0x00200000, 
    OpenNoRecall = 0x00100000, 
    FirstPipeInstance = 0x00080000 
    } 

    /// <summary>Reasons the file changed (from USN journal)</summary> 
    [Flags] 
    public enum UsnReason: uint 
    { 
    BASIC_INFO_CHANGE = 0x00008000, 
    CLOSE = 0x80000000, 
    COMPRESSION_CHANGE = 0x00020000, 
    DATA_EXTEND = 0x00000002, 
    DATA_OVERWRITE = 0x00000001, 
    DATA_TRUNCATION = 0x00000004, 
    EA_CHANGE = 0x00000400, 
    ENCRYPTION_CHANGE = 0x00040000, 
    FILE_CREATE = 0x00000100, 
    FILE_DELETE = 0x00000200, 
    HARD_LINK_CHANGE = 0x00010000, 
    INDEXABLE_CHANGE = 0x00004000, 
    NAMED_DATA_EXTEND = 0x00000020, 
    NAMED_DATA_OVERWRITE = 0x00000010, 
    NAMED_DATA_TRUNCATION = 0x00000040, 
    OBJECT_ID_CHANGE = 0x00080000, 
    RENAME_NEW_NAME = 0x00002000, 
    RENAME_OLD_NAME = 0x00001000, 
    REPARSE_POINT_CHANGE = 0x00100000, 
    SECURITY_CHANGE = 0x00000800, 
    STREAM_CHANGE = 0x00200000, 

    None = 0x00000000 
    } 

    internal enum ECreationDisposition: uint 
    { 
    New = 1, 
    CreateAlways = 2, 
    OpenExisting = 3, 
    OpenAlways = 4, 
    TruncateExisting = 5 
    } 

} 
-2

Everything.exe(桌面搜索應用程序)也訪問相同,所以我希望你能找到everything.exe的Source-Code的一些信息。

當Everything.exe首次運行時,它會根據NTFS主文件表中的文件元數據創建捲上每個文件和文件夾的名稱的索引。默認情況下,所有掛載的NTFS卷都被編入索引。[4]一旦創建,該索引就會不斷由NTFS更改日誌中的應用程序更新。[5]一切都在這個索引中搜索匹配用戶搜索表達式的文件名,這可能是目標文件名或正則表達式的一個片段,[6]在輸入搜索詞時顯示中間結果。

+1

該URL不是Everythings源代碼,它只是它的SDK,不包含有關此主題的有價值的信息 – Suchiman

1

您可以使用Danny Couture用C#編寫的開放源代碼庫https://sourceforge.net/projects/ntfsreader/

我測試了它,它的性能很好。它可以在不到2秒的時間內解析出超過100000個條目(文件和文件夾)的NTFS驅動器。