Search code examples
c#filestream

IOException "Cyclic Rendundancy Check" FileStream.CopyTo using C#.Net


I have some C# code that uses FileStreams to open a PhysicalDrive and take an image of the whole disk, but s consistently throwing an IOException with the message "Data error (cyclic redundancy check)." After copying about 121MB of a 128MB disk.

    using Microsoft.Win32.SafeHandles;
    using System.IO;
    using System;

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    protected static extern SafeFileHandle CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        uint dwShareMode,
        IntPtr SecurityAttributes,
        uint dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile
    );

public void MakeImage() 
{

    SafeFileHandle TheDevice = null;
    try
    {
    TheDevice = CreateFile(@"\\.\PHYSICALDRIVE1", (uint)FileAccess.Read, (uint)0, IntPtr.Zero, (uint)FileMode.Open, (uint)FILE_ATTRIBUTE_SYSTEM, IntPtr.Zero);
        if (TheDevice.IsInvalid) { throw new IOException("Unable to access drive. Win32 Error Code " + Marshal.GetLastWin32Error()); }
        using (FileStream Dest = System.IO.File.Open("output.bin", FileMode.Create))
        {
            using (FileStream Src = new FileStream(TheDevice, FileAccess.Read))
            {
                Src.CopyTo(Dest);
                Src.Close();
            }
            Dest.Close();
        }
    }
    catch(Exception Ex)
    {
        //Here is where i am getting the IOException
        //Handle error..
    }
    finally
    {
        if (TheDevice != null)
        {
            if (!TheDevice.IsClosed)
                TheDevice.Close();
            TheDevice.Dispose();
        }
    }
}

I have run Scan Disk on the Drive in question and there doesn't appear to be anything wrong with it. If I change the first Param of CreateFile to just read a partition (not what I want to do), then the image is created fine.

This is a follow up to Windows C# implementation of linux dd command that I've been trying to do.

UPDATE:

Further investigations show that the error has something do with not being able to get or know the Src.Length property. I changed my code to copy byte by byte and keep a count, it errors after 126959616 bytes, which is 1 byte more than the total size of the image produced by dd.


Solution

  • The cause of the IOException was reading past the end of the Stream. For some reason when opening a Physical Disk as a FileSteam I am unable to get the Length of the stream or otherwise find out its size. The solution is to use the System.Management namespace objects to find out the length of the Device file in bytes and then use Read to copy the correct amount of data from the Stream.

    I think the reason this would happen after 121MB is due to something along the way not using 1024B to a KB and instead using 1000B to a KB, so that was a bit of a red herring on my part.

    I still don't understand why it would throw a CRC error and not a "Sector Not Found" or "Read Past the End of the Stream" type message.