How to read file attributes using Master File Tabl

2019-09-18 18:28发布

问题:

In my project i want list out all files under a specific file path.Do to some user permission issue am using master file table to access all files.

Using this thread I can able to read all files under a specific file location

This one will list the file name and parent FRN,is there any way to list the file attributes also????

I want to show these details also.

  1. Created Date
  2. Modified Data
  3. File Size

USN_RECORD contains these details.

回答1:

You'd probably be better off using something more high-level to enumerate the contents of a path (as suggested by @HarryJohnston), but if you're determined to go down the route you've chosen, then...

Using the FileReferenceNumber you got from your USN call, you can call OpenFileByID (specifying a 0 for the dwDesiredAccess parameter - no read, no write), and you can then subsequently call GetFileInformationByHandle to get the details you need.

You don't need read or write permissions on the file to call GetFileInformationByHandle. The file attributes you're getting from the USN call and/or the GetFileInformationByHandle call can be cast to a .Net System.IO.FileAttributes.



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

        }