【问题标题】:How to read file attributes using Master File Table data如何使用主文件表数据读取文件属性
【发布时间】:2015-08-11 10:00:06
【问题描述】:

在我的项目中,我想列出特定文件路径下的所有文件。对于某些用户权限问题,我正在使用主文件表访问所有文件。

使用这个thread我可以读取特定文件位置下的所有文件

这个会列出文件名和父FRN,有什么办法也列出文件属性????

我也想展示这些细节。

  1. 创建日期
  2. 修改后的数据
  3. 文件大小

USN_RECORD 包含这些详细信息。

【问题讨论】:

  • USN_RECORD 结构包含文件的属性,但不包含您想要的其他信息。但无论如何,这都不是解决问题的有效方法。您拥有管理员权限(否则您无法访问 MFT),因此只需启用备份和恢复权限(绕过权限检查),您就可以通过正常方式获取所需信息。
  • 附上USN_RECORD详细信息截图

标签: c# windows file-attributes ntfs-mft


【解决方案1】:

您可能最好使用更高级的东西来枚举路径的内容(正如@HarryJohnston 所建议的那样),但如果您决心沿着您选择的路线前进,那么...... .

使用您从 USN 调用中获得的 FileReferenceNumber,您可以调用 OpenFileByID(为 dwDesiredAccess 参数指定 0 - 不读取,不写入),然后您可以随后调用 GetFileInformationByHandle 以获取所需的详细信息.

调用 GetFileInformationByHandle 不需要文件的读取或写入权限。您从 USN 调用和/或 GetFileInformationByHandle 调用获得的文件属性可以转换为 .Net System.IO.FileAttributes。

【讨论】:

  • 认为您仍然需要启用备份和恢复权限,除非您对文件或其父目录具有适当的访问权限。如果任何人都可以获取文件 ID 并在没有正确权限的情况下查找有关该文件的信息,那将是一个安全漏洞。
  • @HarryJohnston - 可能是对的 - 不确定我曾经做过 MFT 阅读的唯一上下文是备份、恢复和映像(这只不过是不加选择的备份)。在这种情况下,如果使用 dwDesiredAcces=0,OpenFileByID 应该会快得多,因为不会构造或返回任何流——但同样,我有限的经验并没有证明或反驳这个断言。它看起来非常快 - 但我没有什么可以与之比较的。
【解决方案2】:
public IEnumerable<FileDetails> EnumerateFiles(string szDriveLetter)
        {

            List<FileDetails> fdList = new List<FileDetails>();
            try
            {
                var usnRecord = default(USN_RECORD);
                var mft = default(MFT_ENUM_DATA);
                var dwRetBytes = 0;
                int cb;
                var dicFrnLookup = new Dictionary<long, FSNode>();
                bool bIsFile;

                // This shouldn't be called more than once.
                if (m_Buffer.ToInt32() != 0)
                {
                    throw new Exception("invalid buffer");
                }

                // Assign buffer size
                m_BufferSize = 65536;
                //64KB

                // Allocate a buffer to use for reading records.
                m_Buffer = Marshal.AllocHGlobal(m_BufferSize);

                // correct path
                szDriveLetter = szDriveLetter.TrimEnd('\\');

                // Open the volume handle 
                m_hCJ = OpenVolume(szDriveLetter);
                uint iny = NativeMethods.GetLastError();
                // Check if the volume handle is valid.
                if (m_hCJ == INVALID_HANDLE_VALUE)
                {
                    throw new Exception("Couldn't open handle to the volume.");
                }

                mft.StartFileReferenceNumber = 0;
                mft.LowUsn = 0;
                mft.HighUsn = long.MaxValue;

                do
                {
                    if (DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, ref mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, ref dwRetBytes, IntPtr.Zero))
                    {
                        cb = dwRetBytes;
                        // Pointer to the first record
                        IntPtr pUsnRecord = new IntPtr(m_Buffer.ToInt32() + 8);

                        while ((dwRetBytes > 8))
                        {
                            // Copy pointer to USN_RECORD structure.
                            usnRecord = (USN_RECORD)Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType());

                            // The filename within the USN_RECORD.
                            string fileName = Marshal.PtrToStringUni(new IntPtr(pUsnRecord.ToInt32() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2);

                            bIsFile = !usnRecord.FileAttribute.HasFlag(FileAttributes.Directory);
                            dicFrnLookup.Add(usnRecord.FileReferenceNumber, new FSNode(usnRecord.ParentFileReferenceNumber, fileName, bIsFile));

                            // Pointer to the next record in the buffer.
                            pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usnRecord.RecordLength);

                            dwRetBytes -= usnRecord.RecordLength;
                        }

                        // The first 8 bytes is always the start of the next USN.
                        mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0);


                    }
                    else
                    {
                        break; // TODO: might not be correct. Was : Exit Do

                    }

                } while (!(cb <= 8));

                // Resolve all paths for Files
                foreach (FSNode oFSNode in dicFrnLookup.Values.Where(o => o.IsFile))
                {
                    FileDetails fd = new FileDetails();
                    string sFullPath = oFSNode.FileName;
                    FSNode oParentFSNode = oFSNode;

                    while (dicFrnLookup.TryGetValue(oParentFSNode.ParentFRN, out oParentFSNode))
                    {
                        sFullPath = string.Concat(oParentFSNode.FileName, "\\", sFullPath);
                    }
                    sFullPath = string.Concat(szDriveLetter, "\\", sFullPath);

                    //File Attribute details
                    WIN32_FILE_ATTRIBUTE_DATA data;                

                    if (NativeMethods.GetFileAttributesEx(@sFullPath, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out data))
                    {

                        fd.FileSize = Convert.ToDouble(data.fileSizeLow);
                    }

                    long highBits = data.creationTime.dwHighDateTime;
                    highBits = highBits << 32;

                    DateTime createdDate = DateTime.FromFileTimeUtc(highBits + (uint)data.creationTime.dwLowDateTime);
                    fd.CreatedDate = createdDate.ToString(CultureInfo.CurrentCulture);
                    fd.CreatedYear = createdDate.Year;
                    fd.FileType = data.filetype;

                    long highBitsModified = data.lastWriteTime.dwHighDateTime;
                    highBitsModified = highBitsModified << 32;
                    DateTime modifiedDate = DateTime.FromFileTimeUtc(highBitsModified + (uint)data.creationTime.dwLowDateTime);
                    fd.ModifiedYear = modifiedDate.Year;
                    fd.ModifiedDate = modifiedDate.ToString(CultureInfo.CurrentCulture);
                    fd.FilePath = sFullPath;
                    fd.MachineName = SystemInformation.ComputerName;

                    List<string> names = sFullPath.Split('.').ToList();
                    fd.FileType = "." + names.LastOrDefault();                    

                    List<string> folders = sFullPath.Split('\\').ToList();
                    //fd.FileName = folders.LastOrDefault();
                    fd.FileName = oFSNode.FileName;
                    fdList.Add(fd);

                    yield return fd;
                }
            }
            finally
            {
                //// cleanup
                Cleanup();
            }
        }

public class NativeMethods
        {
            [DllImport("KERNEL32.dll", CharSet = CharSet.None)]
            public static extern bool GetFileAttributesEx(string path, GET_FILEEX_INFO_LEVELS level, out WIN32_FILE_ATTRIBUTE_DATA data);

            [DllImport("kernel32.dll")]
            public static extern uint GetLastError();

        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 2016-09-21
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    相关资源
    最近更新 更多