2

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.

Community
  • 1
  • 1
rb_
  • 613
  • 9
  • 24
  • Reformat the drive. Throw it away if that fails (it should). – Hans Passant Aug 18 '11 at 11:56
  • CreateFile("\\.\PHYSICALDRIVE1", ... this shouldn't be working, C# should interpret \P as an escape sequence, unless you add an @ in front of the string ... – Hinek Aug 18 '11 at 12:01
  • @Hinek Sorry my bad, i'll edit the code listing to clarify that. – rb_ Aug 18 '11 at 12:09
  • @Hans Passant, Tried formatting the disk and it still failed, so I swapped the disk out for another (256MB in size) and it failed with the same error after 245MB. – rb_ Aug 18 '11 at 12:14
  • I'm going to have to guess that these are flash drives with a FAT32 file system on them. Which marks bad clusters by reserving them in the FAT with a special entry. Having bad clusters on a flash drive is not unusual. Your code is going to see them. And bomb on them. Your task got a *lot* more complicated. – Hans Passant Aug 18 '11 at 12:22
  • @Hans Passant They are indeed CF Cards with a FAT FS on them (not FAT32). I don't think there is bad areas on the card (is there a tool I can use to examine it for bad clusters?), but can't actually prove that. Also doing the same under linux using the dd command copies the entire drive with no issues (although i don't know how dd handles bad clusters on a physical device etc). – rb_ Aug 18 '11 at 12:30
  • I wouldn't use CopyTo; you should check the drive geometry and make sure you are using the correct block size - not doing that causes a myriad of problems. I have a wrapper for this functionality at home that I will put up (if I remember) - yes, it does grab the drive geometry and everything for you. – Jonathan Dickinson Aug 18 '11 at 16:02
  • @Jonathan Dickinson that would be great if you could do this, i've tried to grab some of the drive geometry using System.Management.ManagementClass but i'm not sure if wanted the Size Property from the Win32_Diskdrive or Win32_PhysicalMedia or other class - they both seem to give sizes that don't match what I was expecting. – rb_ Aug 18 '11 at 16:31
  • @rb_ - I can't remember either (I wrote it almost a year ago). I am not sure the copy of the class I have is 100% complete - but it will give a good starting point. Check back in say, 1hr. – Jonathan Dickinson Aug 18 '11 at 16:33
  • @rb_ sorry it took so long - https://gist.github.com/1157121 – Jonathan Dickinson Aug 19 '11 at 15:47

2 Answers2

1

The cyclic redundancy check, or "CRC" error indicates that the disk is corrupt or damaged in some way probably a bad spot on the disk. If you're seeing it when trying to copy a file it could be that the bad spot may be in the file itself.

Try copying the file to some other disk and see if that works.

Mamta D
  • 6,310
  • 3
  • 27
  • 41
  • It's the other way round, I'm copying a disk to a file. I have tried copying the disk and locating the destination/output file on another disk but it still threw the IOException after 121MB of the 128MB disk. – rb_ Aug 18 '11 at 12:08
  • That would probably mean that the original disk you are copying is corrupt in some way after the 121 MB. – Mamta D Aug 19 '11 at 09:28
  • The difference in sizes is due to certain apps counting a Kb/Mb as 1000 Bytes/Kb instead of 1024, so it was copying the whole 128MB then failing when it goes past the end. – rb_ Aug 19 '11 at 10:06
1

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.

rb_
  • 613
  • 9
  • 24