private static void RecordExternalDiskExtents(FileRecord rec, MftDiskExtents res)
        {
            foreach (Attribute attribute in rec.Attributes)
            {
                // Skip RESIDENT attributes
                if (attribute.NonResidentFlag == ResidentFlag.Resident)
                {
                    continue;
                }

                // Skip DATA attributes, if the MFT id is larger than 26 (first special reserved ID's)  Source: https://en.wikipedia.org/wiki/NTFS#Master_File_Table
                // Skip ID#8 DATA attribs, as they represent either the entire disk or unreadable clusters
                if (rec.FileReference.FileId == 8 || (rec.FileReference.FileId > 26 && attribute.Type == AttributeType.DATA))
                {
                    continue;
                }

                // Record external extents
                res.Extents.AddRange(attribute.NonResidentHeader.Fragments);

                //if (attribute.Type == AttributeType.INDEX_ALLOCATION)
                //    continue;

                //Console.WriteLine(" " + rec.FileReference + " : " + attribute.Type + "_" + attribute.AttributeName + " " + string.Join(",", attribute.NonResidentHeader.Fragments.Select(x => x.LCN + "->" + x.Clusters)));
            }
        }
        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();
        }