USBストレージデバイスのすべてのバイトに0xFFを書き込むために、次のコードを記述しました。何らかの理由で、WriteFile()
セクター242で呼び出しがエラーになり始めます。これを2つの別々のUSBストレージデバイスで実行し、16進エディターでデバイスを調べました。セクター242は、FAT16形式のデバイスではファイルアロケーションテーブルの開始であり、NTFSデバイスではブートエリアの開始であるように見えます。これらの正確な場所でエラーが発生していることは確かではありませんが、この動作を変更する方法がわかりません。HRESULT
失敗したときに受け取っているのはWriteFile
-2147024891ですE_ACCESSDENIED
。何が問題を引き起こしているのか誰かが知っていますか?
注:ローカルシステムでこのコードを実行する場合は、USBデバイスの物理デバイスIDをハードコーディングしているため、十分に注意してください。書き込みを試みているデバイスでdeviceId変数を更新してください。あなたはあなたのハードドライブを破壊したくありません。
public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer([In] SafeFileHandle hFile, [In] long lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
[DllImport("kernel32.dll", SetLastError = true)]
internal extern static int WriteFile(SafeFileHandle handle, byte[] bytes, int numBytesToWrite, out int numBytesWritten, IntPtr overlapped_MustBeZero);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, byte[] lpInBuffer, int nInBufferSize, byte[] lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool CloseHandle(SafeFileHandle handle);
public void wipeDisk()
{
const uint OPEN_EXISTING = 3;
const uint GENERIC_WRITE = (0x40000000);
const uint FSCTL_LOCK_VOLUME = 0x00090018;
const uint FSCTL_UNLOCK_VOLUME = 0x0009001c;
const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
bool success = false;
int intOut;
string deviceId = @"\\.\PHYSICALDRIVE2";
long DiskSize = 2056320000;
SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (diskHandle.IsInvalid)
{
Console.WriteLine(deviceId + " open error.");
return;
}
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": opened.");
success = DeviceIoControl(diskHandle, FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
if (!success)
{
Console.WriteLine(deviceId + " lock error.");
CloseHandle(diskHandle);
return;
}
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": locked.");
success = DeviceIoControl(diskHandle, FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
if (!success)
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": dismount error.");
DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
CloseHandle(diskHandle);
return;
}
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unmounted.");
int numBytesPerSector = 512;
long numTotalSectors = DiskSize / 512;
byte[] junkBytes = new byte[512];
for (int x = 0; x < 512; x++)
{
junkBytes[x] = 0xFF;
}
for (long sectorNum = 0; sectorNum < numTotalSectors; sectorNum++)
{
int numBytesWritten = 0;
int moveToHigh;
uint rvalsfp = SetFilePointer(diskHandle, sectorNum * numBytesPerSector, out moveToHigh, EMoveMethod.Begin);
Console.WriteLine("File pointer set " + Marshal.GetHRForLastWin32Error().ToString() + ": " + (sectorNum * numBytesPerSector).ToString());
int rval = WriteFile(diskHandle, junkBytes, junkBytes.Length, out numBytesWritten, IntPtr.Zero);
if (numBytesWritten != junkBytes.Length)
{
Console.WriteLine("Write error on track " + sectorNum.ToString() + " from " + (sectorNum * numBytesPerSector).ToString() + "-" + moveToHigh.ToString() + " " + Marshal.GetHRForLastWin32Error().ToString() + ": Only " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
break;
}
else
{
Console.WriteLine("Write success " + Marshal.GetHRForLastWin32Error().ToString() + ": " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
}
}
success = DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
if (success)
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlocked.");
}
else
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlock error: " + Marshal.GetHRForLastWin32Error().ToString());
}
success = CloseHandle(diskHandle);
if (success)
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": handle closed.");
}
else
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": close handle error: " + Marshal.GetHRForLastWin32Error().ToString());
}
}
編集/更新
サードパーティのツールを使用してUSBデバイスの低レベルのワイプを実行した後、これを正常に機能させることができました。ドライブが完全にゼロになった後、デバイスに正常に書き込むことができました。有効なfatまたはntfsファイルシステムとの使用を認識するとすぐに、Windowsがデバイスをロックしているように見えます
const uint FSCTL_LOCK_VOLUME = 0x00090018;
const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
とペアリングされDeviceIoControl
ていると、デバイスのロックウィンドウが無効になっていないようです。
DeviceIoControl
有効なファイルシステムを備えたドライブを使用して、WindowsでリムーバブルUSBデバイスを正常にロックする方法を知っている人はいますか?
私は自分がやろうとしていることを実行するいくつかのサードパーティツールを使用しましたが、それらは正常に機能します。私はそれが可能であることを知っていますが、私が読んだすべてのMSDNドキュメントは問題の解決に役立っていません。
編集/更新2
アプリケーションは、DASD I / Oを発行する前に、ボリュームをロックするか、ボリュームをマウント解除するか、またはその両方を行う必要があります。これはWindowsVistaの新機能であり、潜在的に悪意のある手法に対処するために行われました。
ファイルシステムは、ディスクの予約済みセクションへのすべての書き込み操作をブロックします。この場合、これらの予約済みセクションには、MBRと2つのFATエリアが含まれます。これらの領域をブロックするには、FSCTL_LOCK_VOLUMEを送信してボリュームをロックする必要があります。この構造は、実際の書き込み操作を実行するのと同じボリュームハンドルで発行する必要があります。開いているファイルハンドルがある場合、この要求は失敗する可能性があります。この場合、アプリケーションはFSCTL_DISMOUNT_VOLUMEを発行することにより、ファイルシステムのマウント解除を強制できます。ただし、ファイルハンドルが閉じられるまで、ボリュームは実際にはマウント解除されません。それまで、アプリケーションは、現在開いているのと同じファイルハンドルを使用して、DASD I/Oを発行し続けることができます。
書き込み操作がブロックされるファイルシステムに認識されているボリュームスペースを超える拡張領域があります。この領域への書き込み操作を許可するには、ボリューム・ハンドルでFSCTL_ALLOW_EXTENDED_DASD_IOを発行する必要があります。
Win32 APIルーチンDeviceIoControlを使用して、以前のすべてのFSCTSを発行できます。
これはまさに上記のコードで実装しているものだと思いますが、正しく機能していないようです。ハンドルを取得し、デバイスをロックおよびマウント解除しているので、保護された領域に正しく書き込むことができるはずですか?
編集/更新3
これがディスクとボリュームを開く現在の順序です。ロック、マウント解除などの方法は、私たちが間違っていると思う順序で機能します。
SafeFileHandle volumeHandle = CreateFile("\\.\E:",...);
LockVolume(volumeHandle);
DismountVolume(volumeHandle);
SafeFileHandle diskHandle = CreateFile("\\.\PHYSICALDRIVE1"...);
WriteStuff(diskHandle);
//Fails...
UnlockVolume(volumeHandle);
CloseVolume(volumeHandle);
CloseDisk(diskHandle);
私はまだ同じ結果を得ています、それはディスクがゴミ箱に捨てられたときはいつでも機能します。