如何使用主文件表数据读取文件属性

时间:2015-08-11 10:00:06

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

在我的项目中,我希望列出特定文件路径下的所有文件。使用主文件表来访问所有文件,以解决某些用户权限问题。

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

这一个会列出文件名和父FRN,有没有办法列出文件属性呢????

我也想展示这些细节。

  1. 创建日期
  2. 修改数据
  3. 文件大小
  4. USN_RECORD包含这些细节。 enter image description here

2 个答案:

答案 0 :(得分:1)

你可能最好使用更高级别的东西来枚举路径的内容(如@HarryJohnston所建议的那样),但是如果你决定沿着这条路走下去,那么你可以选择这样做。然后选择了......

使用您从USN调用获得的FileReferenceNumber,您可以调用OpenFileByID(为dwDesiredAccess参数指定0 - 不读取,不写入),然后您可以随后调用GetFileInformationByHandle来获取你需要的细节。

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

答案 1 :(得分:0)

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();

        }