ISOイメージを作成することなく、CD-ROMから直接データを読み込んでMD5ハッシュ値を計算するための方法。

MD5.ComputeHashメソッドでMD5を計算する際、CD-ROMのデータを一度バイト配列に落としてからComputeHashメソッドに渡すのはムダが多いので、なんらかの方法でStreamから直接読み込ませる方法を考える。

§1 CdromIsoStreamクラス

まずは、FileStreamクラスを継承してCD-ROMのデータを直接読み込むためのクラスを作る。

注意: この実装を使った場合だとCD-ROMの最終セクタの途中までしか読み込まないようなので、ISOイメージ作成ツールを使ってダンプした場合とは異なるチェックサムとなる。 あくまで参考として掲載する。 なお、以下のコードを使用して作成したISOイメージは問題なくマウントできる模様。

CdromIsoStream
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public class CdromIsoStream : FileStream {
  public CdromIsoStream(DriveInfo drive)
    : base(Open(drive), FileAccess.Read)
  {
  }

  [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
  private static extern IntPtr CreateFile(string lpFIleName,
                                          uint dwDesiredAccess,
                                          uint dwShareMode,
                                          IntPtr lpSecurityAttributes,
                                          uint dwCreationDisposition,
                                          uint dwFlagsAndAttributes,
                                          IntPtr hTemplateFile);

  private const uint GENERIC_READ = 0x80000000;
  private const uint GENERIC_WRITE = 0x40000000;
  private const uint FILE_SHARE_READ = 0x00000001;
  private const uint FILE_SHARE_WRITE = 0x00000002;
  private const uint OPEN_EXISTING = 3;

  private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

  private static SafeFileHandle Open(DriveInfo drive)
  {
    if (drive == null)
      throw new ArgumentNullException("drive");

    var handle = CreateFile(string.Format(@"\\.\{0}:", drive.Name[0]),
                            GENERIC_READ,
                            FILE_SHARE_READ,
                            IntPtr.Zero,
                            OPEN_EXISTING,
                            0,
                            IntPtr.Zero);

    if (handle == INVALID_HANDLE_VALUE)
      throw new Win32Exception(Marshal.GetLastWin32Error());

    return new SafeFileHandle(handle, true);
  }
}

§2 MD5の計算

前述のクラスを使うことでCD-ROMのデータをStreamとして読み込めるようになったので、早速ComputeHashメソッドにこのインスタンスを渡してMD5を計算させる。

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;

class Sample {
  static void Main()
  {
    // 光学ドライブのDriveInfoを取得
    var drive = DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.CDRom).First();

    Console.WriteLine(drive);

    using (var cdromStream = new CdromIsoStream(drive)) {
      using (var md5 = MD5.Create()) {
        // StreamのMD5ハッシュ値を計算
        var md5hash = md5.ComputeHash(cdromStream);

        // 文字列形式に変換して表示
        var md5sum = BitConverter.ToString(md5hash).Replace("-", string.Empty).ToLowerInvariant();

        Console.WriteLine(md5sum);
      }
    }
  }
}

§3 ISOイメージの作成

MD5の計算以だけでなく、読み込んだデータをそのままFileStreamに書きだせばISOイメージを作成することができる。

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;

class Sample {
  static void Main()
  {
    // 光学ドライブのDriveInfoを取得
    var drive = DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.CDRom).First();

    Console.WriteLine(drive);

    using (var cdromStream = new CdromIsoStream(drive)) {
      using (var fileStream = File.Create("test.iso")) {
        cdromStream.CopyTo(fileStream);
      }
    }
  }
}

§4 メモ