public static void PresentResult(RawDisk disk)
        {
            byte[] data = disk.ReadClusters(0, (int)Math.Min(disk.ClusterCount, ClustersToRead));

            string fatType = Encoding.ASCII.GetString(data, 82, 8);     // Extended FAT parameters have a display name here.
            bool isFat = fatType.StartsWith("FAT");
            bool isNTFS = Encoding.ASCII.GetString(data, 3, 4) == "NTFS";

            // Optimization, if it's a known FS, we know it's not all zeroes.
            bool allZero = (!isNTFS || !isFat) && data.All(s => s == 0);

            Console.WriteLine("Size in bytes : {0:N0}", disk.SizeBytes);
            Console.WriteLine("Sectors       : {0:N0}", disk.ClusterCount);
            Console.WriteLine("SectorSize    : {0:N0}", disk.SectorSize);
            Console.WriteLine("ClusterCount  : {0:N0}", disk.ClusterCount);
            Console.WriteLine("ClusterSize   : {0:N0}", disk.ClusterSize);

            if (!isFat && !isNTFS)
                Console.ForegroundColor = ConsoleColor.Red;

            if (isNTFS)
                Console.ForegroundColor = ConsoleColor.Green;

            Console.WriteLine("Is NTFS       : {0}", isNTFS);
            Console.ForegroundColor = DefaultColor;

            if (!isFat && !isNTFS)
                Console.ForegroundColor = ConsoleColor.Red;

            if (isFat)
                Console.ForegroundColor = ConsoleColor.Green;

            Console.WriteLine("Is FAT        : {0}", isFat ? fatType : "False");
            Console.ForegroundColor = DefaultColor;

            if (!allZero)
                Console.ForegroundColor = ConsoleColor.Green;
            else
                Console.ForegroundColor = ConsoleColor.Red;

            Console.WriteLine("All bytes zero: {0}", allZero);
            Console.ForegroundColor = DefaultColor;
        }
        public static void CopyFile(string sourceFile, string dstFile)
        {
            // FileAttributes 0x20000000L = FILE_FLAG_NO_BUFFERING
            SafeFileHandle fileHandle = Win32Helper.CreateFile(sourceFile, (FileAccess)Program.FILE_READ_ATTRIBUTES, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal | (FileAttributes)0x20000000L, IntPtr.Zero);

            if (fileHandle.IsInvalid)
                throw new ArgumentException("Invalid file: " + sourceFile);

            //var driveWrapper = new DeviceIOControlWrapper(driveHandle);
            FilesystemDeviceWrapper fileWrapper = new FilesystemDeviceWrapper(fileHandle);

            FileExtentInfo[] extents = fileWrapper.FileSystemGetRetrievalPointers();
            decimal totalSize = extents.Sum(s => (decimal)s.Size);
            decimal copiedBytes = 0;

            using (RawDisk disk = new RawDisk(char.ToUpper(sourceFile[0])))
            {
                // Write to the source file
                using (FileStream fs = new FileStream(dstFile, FileMode.Create))
                {
                    // Copy all extents
                    foreach (FileExtentInfo fileExtentInfo in extents)
                    {
                        // Copy chunks of data
                        for (ulong offset = 0; offset < fileExtentInfo.Size; offset += 10000)
                        {
                            int currentSizeBytes = (int)Math.Min(10000, fileExtentInfo.Size - offset);
                            byte[] data = disk.ReadClusters((long)(fileExtentInfo.Lcn + offset), currentSizeBytes);
                            fs.Write(data, 0, data.Length);

                            copiedBytes += currentSizeBytes;
                        }
                    }
                }
            }

            Debug.Assert(copiedBytes == totalSize);
        }
        public override void Execute()
        {
            IEnumerable<char> volumeDrives = Utils.GetAllAvailableVolumes();
            IEnumerable<int> harddiskVolumes = Utils.GetAllAvailableDrives(DiskNumberType.Volume);

            Console.WriteLine("You need to enter a volume on which to write and read. Note that this volume will be useless afterwards - do not chose anything by test volumes!");
            Console.WriteLine("Select volume:");
            List<int> options = new List<int>();

            foreach (int harddiskVolume in harddiskVolumes)
            {
                try
                {
                    using (RawDisk disk = new RawDisk(DiskNumberType.Volume, harddiskVolume))
                    {
                        char[] driveLetters = DiskHelper.GetDriveLetters(disk.DosDeviceName.Remove(0, @"\\.\GLOBALROOT".Length)).Where(volumeDrives.Contains).ToArray();

                        Console.WriteLine("  {0:N0}: {1:N0} Bytes, Drive Letters: {2}", harddiskVolume, disk.SizeBytes, string.Join(", ", driveLetters));
                        options.Add(harddiskVolume);
                    }
                }
                catch (Exception)
                {
                    // Don't write it
                }
            }

            string vol;
            int selectedVol;
            do
            {
                Console.WriteLine("Enter #:");
                vol = Console.ReadLine();
            } while (!(int.TryParse(vol, out selectedVol) && options.Contains(selectedVol)));

            Console.WriteLine("Selected " + selectedVol + ".");

            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Are you sure? Type YES.");
            Console.ForegroundColor = ExampleUtilities.DefaultColor;

            bool allSuccess = false;

            string confirm = Console.ReadLine();
            if (confirm == "YES")
            {
                Console.WriteLine("Confirmed - starting");

                using (RawDisk disk = new RawDisk(DiskNumberType.Volume, selectedVol, FileAccess.ReadWrite))
                {
                    long chunks = disk.ClusterCount / ExampleUtilities.ClustersToRead;

                    Console.WriteLine("Disk {0} is {1:N0} Bytes large.", disk.DosDeviceName, disk.SizeBytes);
                    Console.WriteLine("Beginning random write in {0:N0} cluster chunks of {1:N0} Bytes each", ExampleUtilities.ClustersToRead, disk.ClusterSize);
                    Console.WriteLine(" # of chunks: {0:N0}", chunks);

                    byte[] chunkData = new byte[disk.ClusterSize * ExampleUtilities.ClustersToRead];
                    byte[] readData = new byte[disk.ClusterSize * ExampleUtilities.ClustersToRead];
                    Random rand = new Random();

                    StringBuilder blankLineBuilder = new StringBuilder(Console.BufferWidth);
                    for (int i = 0; i < Console.BufferWidth; i++)
                        blankLineBuilder.Append(' ');
                    string blankLine = blankLineBuilder.ToString();

                    allSuccess = true;

                    for (int chunk = 0; chunk < chunks; chunk++)
                    {
                        rand.NextBytes(chunkData);

                        Console.Write("Chunk #{0}: ", chunk);

                        try
                        {
                            // Write
                            Console.Write("Writing ... ");

                            disk.WriteClusters(chunkData, chunk * ExampleUtilities.ClustersToRead);

                            // Read
                            Console.Write("Reading ... ");

                            disk.ReadClusters(readData, 0, chunk * ExampleUtilities.ClustersToRead, (int)ExampleUtilities.ClustersToRead);

                            // Check
                            if (chunkData.SequenceEqual(readData))
                            {
                                Console.ForegroundColor = ConsoleColor.Green;
                                Console.WriteLine("Confirmed!");
                                Console.ForegroundColor = ExampleUtilities.DefaultColor;
                            }
                            else
                            {
                                allSuccess = false;

                                Console.ForegroundColor = ConsoleColor.Red;
                                Console.WriteLine("Failed!");
                                Console.ForegroundColor = ExampleUtilities.DefaultColor;

                                Console.WriteLine("Presse enter to proceed.");
                                Console.ReadLine();
                            }
                        }
                        catch (Exception ex)
                        {
                            allSuccess = false;

                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("Error: " + ex.Message);
                            Console.ForegroundColor = ExampleUtilities.DefaultColor;

                            Console.WriteLine("Presse enter to proceed.");
                            Console.ReadLine();

                            Console.CursorTop--;
                        }

                        Console.CursorTop--;
                        Console.CursorLeft = 0;
                        Console.Write(blankLine);
                        Console.CursorTop--;
                        Console.CursorLeft = 0;
                    }
                }
            }
            else
            {
                Console.WriteLine("Aborted");
            }

            if (allSuccess)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("All chunks were able to write and read successfully.");
                Console.ForegroundColor = ExampleUtilities.DefaultColor;
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Some chunks were unable to be read correctly.");
                Console.ForegroundColor = ExampleUtilities.DefaultColor;
            }
        }