static void Main(string[] args)
        {
            char driveLetter = 'C';

            if (args.Length == 1)
            {
                driveLetter = args[0][0];
            }

            using (RawDisk disk = new RawDisk(driveLetter))
            {
                MftDiskExtents res = new MftDiskExtents();

                byte[]     ntfsBoot = disk.ReadSectors(0, 1);
                BootSector boot     = BootSector.ParseData(ntfsBoot, ntfsBoot.Length, 0);
                Console.WriteLine("MFT is at LCN " + boot.MFTCluster);

                MftDetails mft = GetMftDetails(disk, boot);
                Console.WriteLine("MFT is in " + mft.MftExtents.Length + " extents");

                res.Extents.AddRange(mft.MftExtents);

                using (RawDiskStream diskStream = disk.CreateDiskStream())
                    using (NtfsDiskStream mftStream = new NtfsDiskStream(diskStream, false, mft.MftExtents, (uint)disk.ClusterSize, 0, (long)mft.MftSize))
                    {
                        uint   sectorsPrRecord = (uint)(boot.MFTRecordSizeBytes / disk.SectorSize);
                        ushort bytesPrSector   = (ushort)disk.SectorSize;

                        int records = (int)(mftStream.Length / boot.MFTRecordSizeBytes);

                        byte[] tmp = new byte[boot.MFTRecordSizeBytes];
                        while (true)
                        {
                            int read = mftStream.Read(tmp, 0, tmp.Length);
                            if (read < boot.MFTRecordSizeBytes)
                            {
                                Console.WriteLine("Stopped reading as we got " + read + " bytes instead of " + tmp.Length + " bytes");
                                break;
                            }

                            FileRecord rec = FileRecord.Parse(tmp, 0, bytesPrSector, sectorsPrRecord);

                            // Keep track of all external extents to the MFT
                            RecordExternalDiskExtents(rec, res);

                            //// Special case for LIST attributes, since they can further reference more extents outside the MFT
                            //ProcessNonResidentListAttributes(disk, rec);
                        }
                    }

                long clustersTotal = res.Extents.Sum(x => x.Clusters);

                Console.WriteLine("To copy: {0:N0} extents", res.Extents.Count);
                Console.WriteLine("{0:N0} clusters, {1:N0} bytes", clustersTotal, clustersTotal * disk.ClusterSize);
            }

            Console.ReadLine();
        }
        private static MftDetails GetMftDetails(RawDisk disk, BootSector boot)
        {
            byte[]     mftFirst = disk.ReadClusters((long)boot.MFTCluster, 1);
            FileRecord rec      = FileRecord.Parse(mftFirst, 0, (ushort)disk.SectorSize, (uint)(boot.MFTRecordSizeBytes / disk.SectorSize));

            // Get DATA attrib
            // TODO: Handle multiple DATA attributes
            AttributeGeneric dataAttrib = null;

            foreach (Attribute attribute in rec.Attributes)
            {
                if (attribute.Type == AttributeType.DATA && attribute.AttributeName.Length == 0)
                {
                    // Got it!
                    dataAttrib = attribute as AttributeGeneric;
                    break;
                }
            }

            Debug.Assert(dataAttrib != null);

            MftDetails res = new MftDetails();

            // Get attribute data
            // Parse out extents
            if (dataAttrib.NonResidentFlag == ResidentFlag.Resident)
            {
                byte[] dataAttribData = dataAttrib.Data;

                res.MftSize    = dataAttrib.ResidentHeader.ContentLength;
                res.MftExtents = DataFragment.ParseFragments(dataAttribData, dataAttribData.Length, 0, 0, 0);
            }
            else
            {
                res.MftSize    = dataAttrib.NonResidentHeader.ContentSize;
                res.MftExtents = dataAttrib.NonResidentHeader.Fragments;
            }

            Debug.Assert(res.MftExtents != null);

            return(res);
        }