如何在C#中使用CreateFile打开目录以检查已删除的条目?

如何在C#中使用CreateFile打开目录以检查已删除文件的条目? 或者现在不可能? 我记得当能够使用CreateFile或可能的CreateFileEx打开NTFS分区上的目录时,但是在旧操作系统下使用C ++。

到目前为止,我已经有足够的Windows API调用(到kernel32.dll)读取现有文件,但它不会打开目录:

using System; using System.Collections.Generic; using System.Text; using System.IO; using Microsoft.Win32.SafeHandles; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Runtime.ConstrainedExecution; using System.Security; namespace Kernel_Test { class Program { static void Main(string[] args) { Kernel_Tools cKT = new Kernel_Tools(); cKT.DoTest("C:\\Temp"); cKT.DoTest("C:\\Temp\\test.txt"); } } [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)] [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] class Kernel_Tools { public void DoTest(string cTarget) { IntPtr cFile = NativeMethods.CreateFile( cTarget, NativeMethods.GENERIC_READ /* 0 or NativeMethods.GENERIC_READ */ , FileShare.Read, IntPtr.Zero /* failed try: NativeMethods.OPEN_ALWAYS */, (FileMode) NativeMethods.OPEN_EXISTING, NativeMethods.FILE_FLAG_BACKUP_SEMANTICS /* 0 */ , IntPtr.Zero); Console.WriteLine(cTarget); Console.WriteLine(cFile); if ((int)cFile != -1) { int length = 20; byte[] bytes = new byte[length]; int numRead = 0; int ErrorCheck = NativeMethods.ReadFile(cFile, bytes, length, out numRead, IntPtr.Zero); // This sample code will not work for all files. //int r = NativeMethods.ReadFile(_handle, bytes, length, out numRead, IntPtr.Zero); // Since we removed MyFileReader's finalizer, we no longer need to // call GC.KeepAlive here. Platform invoke will keep the SafeHandle // instance alive for the duration of the call. if (ErrorCheck == 0) { Console.WriteLine("Read failed."); NativeMethods.CloseHandle(cFile); return; //throw new Win32Exception(Marshal.GetLastWin32Error()); } if (numRead < length) { byte[] newBytes = new byte[numRead]; Array.Copy(bytes, newBytes, numRead); bytes = newBytes; } for (int i = 0; i < bytes.Length; i++) Console.Write((char)bytes[i]); Console.Write("\n\r"); // Console.WriteLine(); NativeMethods.CloseHandle(cFile); } } } [SuppressUnmanagedCodeSecurity()] internal static class NativeMethods { // Win32 constants for accessing files. internal const int GENERIC_READ = unchecked((int)0x80000000); internal const int FILE_FLAG_BACKUP_SEMANTICS = unchecked((int)0x02000000); internal const int OPEN_EXISTING = unchecked((int)3); // Allocate a file object in the kernel, then return a handle to it. [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)] internal extern static IntPtr CreateFile( String fileName, int dwDesiredAccess, System.IO.FileShare dwShareMode, IntPtr securityAttrs_MustBeZero, System.IO.FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile_MustBeZero); // Use the file handle. [DllImport("kernel32", SetLastError = true)] internal extern static int ReadFile( IntPtr handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero); // Free the kernel's file object (close the file). [DllImport("kernel32", SetLastError = true)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] internal extern static bool CloseHandle(IntPtr handle); } } 

编辑1:修改它以使用OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS和GENERIC_READ。

当作为Vista管理用户运行时,这将打开并显示指定文本文件的开头,与原始文件一样,但仍无法打开目录。 我猜我需要SE_BACKUP_NAME和SE_RESTORE_NAME权限,但我不确定如何指定除了将其作为本地计算机运行的服务(我只有最模糊的想法)。

AFAIK,这是一个相当复杂的过程。 您不能只使用CreateFile并枚举“已删除的文件”。 您必须加载驱动器的主文件表,并枚举标记为已删除的文件,然后尝试从MFT中列出的磁盘位置加载数据。 这将需要大量的Platform Invoked代码,并且可能需要对C#中的本机数据结构进行一些重新定义。

对你的问题的简短回答是这样的:

 CreateFile("\\\\.\\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL) 

您使用create file打开磁盘本身。

这是关于Code Project整个过程的一篇非常好的文章。 但是,这一切都在c ++中。 代码在那里,似乎你知道如何p \ invoke,所以移植它应该不是问题。

编辑:

驱动器是外置的这一事实不应该让它变得更难,你仍然可以像我展示的那样打开磁盘(也许在连接驱动器后使用WMI工具查找路径)。 然后,您可以使用Wiki32页面上的FAT32信息来定义您可以读取MFT和文件系统的其他部分的数据结构。 到达目的地后,您只需遍历目录表中的32字节文件定义,查看第一个字节:

 0xE5 Entry has been previously erased and is available. File undelete utilities must replace this character with a regular character as part of the undeletion process. 

我不确定你通过检查已删除的目录是什么意思,但是你应该能够通过将FILE_FLAG_BACKUP_SEMANTICS标志传递给CreateFile 确保为创建处置指定OPEN_EXISTING来获取目录句柄。 从关于CreateFile的MSDN文章 :

要使用CreateFile打开目录,请将FILE_FLAG_BACKUP_SEMANTICS标志指定为dwFlagsAndAttributes的一部分。 如果在没有SE_BACKUP_NAMESE_RESTORE_NAME权限的情况下使用此标记,则仍然适用相应的安全检查。

看起来你以前尝试了一些但是评论了它? 如果这对您不起作用,您可能希望确保您正在运行的用户有权访问相关目录。

只是向你抛出另一种方法,如果它是相关的,你总是可以用FileSystemWatcher观察目录并捕获Deleted事件。 当然,你需要在删除时观看它,但它可能是一个更容易的解决方案,然后尝试恢复它(如果它是一个选项)。