/// <summary><see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/dd405526(v=vs.85).aspx"/></summary>
        /// <remarks>
        ///     Does not correcly handle all cases of this method!. Especially regarding compressed/encrypted and/or sparse files in NTFS.
        ///     Consider yourself warned.
        /// </remarks>
        public FileExtentInfo[] FileSystemGetRetrievalPointers()
        {
            STARTING_VCN_INPUT_BUFFER input = new STARTING_VCN_INPUT_BUFFER();

            input.StartingVcn = 0;

            List <FileExtentInfo> extents = new List <FileExtentInfo>();

            uint chunkSize        = 1024;
            uint singleExtentSize = MarshalHelper.SizeOf <RETRIEVAL_POINTERS_EXTENT>();

            int lastError;

            do
            {
                byte[] data = DeviceIoControlHelper.InvokeIoControl(Handle, IOControlCode.FsctlGetRetrievalPointers, chunkSize, input, out lastError);

                RETRIEVAL_POINTERS_BUFFER output = new RETRIEVAL_POINTERS_BUFFER();
                output.ExtentCount = BitConverter.ToUInt32(data, 0);
                output.StartingVcn = BitConverter.ToUInt64(data, sizeof(ulong));

                output.Extents = new RETRIEVAL_POINTERS_EXTENT[output.ExtentCount];

                // Parse extents
                int extentsSize = (int)(output.ExtentCount * singleExtentSize);
                using (var dataPtr = new UnmanagedMemory(extentsSize))
                {
                    Marshal.Copy(data, sizeof(ulong) + sizeof(ulong), dataPtr, extentsSize);

                    for (ulong i = 0; i < output.ExtentCount; i++)
                    {
                        IntPtr currentPtr = new IntPtr(dataPtr.Handle.ToInt64() + (int)(singleExtentSize * i));
                        output.Extents[i] = currentPtr.ToStructure <RETRIEVAL_POINTERS_EXTENT>();
                    }
                }

                // Make extents more readable
                for (ulong i = 0; i < output.ExtentCount; i++)
                {
                    ulong startVcn = i == 0
                        ? output.StartingVcn
                        : output.Extents[i - 1].NextVcn;

                    ulong size = output.Extents[i].NextVcn - startVcn;

                    FileExtentInfo extent = new FileExtentInfo();
                    extent.Size = size;
                    extent.Vcn  = startVcn;
                    extent.Lcn  = output.Extents[i].Lcn;

                    extents.Add(extent);
                }

                if (lastError == 38)
                {
                    // End of file reached
                    break;
                }

                // Prep the start point for the next call
                input.StartingVcn = output.Extents[output.ExtentCount - 1].NextVcn;
            } while (lastError == 234);

            return(extents.ToArray());
        }
Esempio n. 2
0
        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
            totalClusters = 0;
            int extentNumber = 1;

            label4.Text = "File fragmentation factor = ";


            if (path.Length == 0 || !File.Exists(path))
            {
                MessageBox.Show("Select a file!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            textBox1.Text += "Analysis...";

            using (var file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                var vcnIn         = new STARTING_VCN_INPUT_BUFFER();
                var rpb           = new RETRIEVAL_POINTERS_BUFFER();
                int bytesReturned = 0;
                int err           = 0;
                vcnIn.StartingVcn = 0L;
                do
                {
                    DeviceIoControl(
                        file.SafeFileHandle, FSCTL_GET_RETRIEVAL_POINTERS,
                        &vcnIn, STARTING_VCN_INPUT_BUFFER.Size,
                        &rpb, RETRIEVAL_POINTERS_BUFFER.Size,
                        &bytesReturned, null
                        );

                    err = Marshal.GetLastWin32Error();

                    switch (err)
                    {
                    case 38:     // ERROR_HANDLE_EOF

                        if (extentNumber == 1)
                        {
                            textBox1.Text += "MFT Table...";
                        }
                        else
                        {
                            textBox1.Text += $"\r\nTotal clusters: {totalClusters} \r\nFragments: {(extentNumber - 1)}";
                        }
                        break;

                    case 0:     // NO_ERROR
                        textBox1.Text += $"\r\nFragment #{extentNumber}";
                        textBox1.Text += $"\r\n\tStart cluster: {rpb.Lcn}\r\n\tLength: {rpb.NextVcn - rpb.StartingVcn} clusters";
                        totalClusters += rpb.NextVcn - rpb.StartingVcn;
                        textBox1.Text += $"\r\nTotal clusters: {totalClusters}\r\nFragments:{extentNumber}";
                        break;

                    case 234:     // ERROR_MORE_DATA
                        textBox1.Text    += $"\r\nFragment #{extentNumber++}";
                        textBox1.Text    += $"\r\n\tStart cluster: {rpb.Lcn}\r\n\tLength: {rpb.NextVcn - rpb.StartingVcn} clusters";
                        totalClusters    += rpb.NextVcn - rpb.StartingVcn;
                        vcnIn.StartingVcn = rpb.NextVcn;
                        break;
                    }
                } while (err == 234);
            }
            if (extentNumber - 1 == 0)
            {
                textBox1.Text += $"\r\nFile fragmentation factor = 0%";
                label4.Text   += $"0%";
            }
            else
            {
                double coeffragment = (double)(extentNumber - 1) / totalClusters * 100;
                textBox1.Text += $"\r\nFile fragmentation factor = {coeffragment:0.####} %";
                label4.Text   += $"{coeffragment:0.######}%";
            }
        }