Question

I need to open read disk in raw mode, so I'm using CreateFile API function for that purposes.

private static FileStream OpenDisk(string drive)
{
    // Try to open hard disk drive in raw mode for reading
    SafeFileHandle safeHandle = Native.CreateFile(
        string.Format(@"\\.\{0}", drive),
        FileAccess.Read,
        FileShare.Read,
        IntPtr.Zero,
        FileMode.Open,
        FileAttributes.ReadOnly | FileAttributes.Device,
        IntPtr.Zero);

    // Check if the drive was successfully opened
    if (safeHandle.IsInvalid)
    {
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
    }

    // Create file stream on the file for reading
    return new FileStream(safeHandle, FileAccess.Read);
}

But when I try to read from the stream I get the following error

Handle does not support synchronous operations. The parameters to the FileStream constructor may need to be changed to indicate that the handle was opened asynchronously (that is, it was opened explicitly for overlapped I/O).

Here is the sample code that reproduces this issue

using (FileStream stream = OpenDisk("X:"))
{
    byte[] buffer = new byte[1000];
    while (stream.Read(buffer, 0, 1000) > 0) { }
}

I don't really get what does it want from me? It works when I use larger buffer (for example 4096). When I say it works I mean it really works (always), it was working for a while, until I changed buffer size. I guess it does some kind of asynchronous buffering inside and when I specify larger buffer then default buffering size it's just not used, but how to get rid of this?

Thanks

update

When I try to read it using BufferedStream I get the same issue

using (BufferedStream stream = new BufferedStream(OpenDisk("X:"), 4096))
{
    byte[] buffer = new byte[1000];
    while (stream.Read(buffer, 0, 1000) > 0) { }
}

Do I understand wrong purpose of BufferedStream? Shouldn't it read and cache chunks of specified size?

Was it helpful?

Solution

In short, reads from volumes are non-buffered and must be of whole sectors. A buffer size of 4096 achieves this. The error message is misleading because asynchronous I/O and non-buffering tend to go together. Some details:

From the CreateFile docs:

Volume handles can be opened as noncached at the discretion of the particular file system, even when the noncached option is not specified in CreateFile. You should assume that all Microsoft file systems open volume handles as noncached. The restrictions on noncached I/O for files also apply to volumes.

From the File Buffering docs:

  • File access sizes, including the optional file offset in the OVERLAPPED structure, if specified, must be for a number of bytes that is an integer multiple of the volume sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1,024, 1,536, or 2,048 bytes, but not of 335, 981, or 7,171 bytes.
  • File access buffer addresses for read and write operations should be physical sector-aligned, which means aligned on addresses in memory that are integer multiples of the volume's physical sector size. Depending on the disk, this requirement may not be enforced.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top