573 lines
14 KiB
C++
573 lines
14 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
wipedisk.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Utility program to zero out the partition-tables and first/last
|
||
|
few sectors of disks
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Guhan Suriyanarayanan (guhans) 30-Sep-2000
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User-mode only.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
30-Sep-2000 guhans
|
||
|
Initial creation
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <windows.h>
|
||
|
#include <ntdddisk.h>
|
||
|
|
||
|
BOOL g_bPrompt = TRUE;
|
||
|
|
||
|
//
|
||
|
// write in 64K chunks.
|
||
|
//
|
||
|
#define BUFFER_SIZE_BYTES (64 * 1024)
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
pSetSignature(
|
||
|
IN CONST ULONG ulDiskNumber,
|
||
|
IN CONST DWORD dwNewSignature
|
||
|
)
|
||
|
{
|
||
|
DWORD dwStatus = ERROR_SUCCESS,
|
||
|
dwBytesReturned = 0,
|
||
|
dwBufferSize = 0;
|
||
|
|
||
|
PDRIVE_LAYOUT_INFORMATION_EX driveLayoutEx;
|
||
|
|
||
|
int i = 0, loopTimes = 0;
|
||
|
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
HANDLE hDisk = NULL,
|
||
|
hHeap = NULL;
|
||
|
|
||
|
WCHAR szFriendlyName[100]; // For display "Disk 2"
|
||
|
WCHAR szDiskPath[100]; // For CreateFile "\\.\PhysicalDrive2"
|
||
|
|
||
|
wsprintf(szFriendlyName, L"Disk %lu", ulDiskNumber);
|
||
|
wsprintf(szDiskPath, L"\\\\.\\PhysicalDrive%lu", ulDiskNumber);
|
||
|
hHeap = GetProcessHeap();
|
||
|
|
||
|
hDisk = CreateFile(
|
||
|
szDiskPath, // lpFileName
|
||
|
GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess
|
||
|
FILE_SHARE_READ, // dwShareMode
|
||
|
NULL, // lpSecurityAttributes
|
||
|
OPEN_EXISTING, // dwCreationFlags
|
||
|
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, // dwFlagsAndAttributes
|
||
|
NULL // hTemplateFile
|
||
|
);
|
||
|
|
||
|
if ((INVALID_HANDLE_VALUE == hDisk) || (NULL == hDisk)) {
|
||
|
//
|
||
|
// Couldn't open a handle.
|
||
|
//
|
||
|
wprintf(L"Unable to open a handle to %ws (%lu)\n", szDiskPath, GetLastError());
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dwBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
|
||
|
(sizeof(PARTITION_INFORMATION_EX) * 3);
|
||
|
|
||
|
driveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
|
||
|
hHeap,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
dwBufferSize
|
||
|
);
|
||
|
if (!driveLayoutEx) {
|
||
|
wprintf(L"Could not allocate memory\n");
|
||
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
bResult = FALSE;
|
||
|
while (!bResult) {
|
||
|
|
||
|
bResult = DeviceIoControl(
|
||
|
hDisk,
|
||
|
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
||
|
NULL,
|
||
|
0L,
|
||
|
driveLayoutEx,
|
||
|
dwBufferSize,
|
||
|
&dwBytesReturned,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (!bResult) {
|
||
|
dwStatus = GetLastError();
|
||
|
HeapFree(hHeap, 0L, driveLayoutEx);
|
||
|
driveLayoutEx = NULL;
|
||
|
|
||
|
//
|
||
|
// If the buffer is of insufficient size, resize the buffer.
|
||
|
// Note that get-drive-layout-ex could return error-insufficient-
|
||
|
// buffer (instead of? in addition to? error-more-data)
|
||
|
//
|
||
|
if ((ERROR_MORE_DATA == dwStatus) ||
|
||
|
(ERROR_INSUFFICIENT_BUFFER == dwStatus)
|
||
|
) {
|
||
|
dwStatus = ERROR_SUCCESS;
|
||
|
dwBufferSize += sizeof(PARTITION_INFORMATION_EX) * 4;
|
||
|
|
||
|
driveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
|
||
|
hHeap,
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
dwBufferSize
|
||
|
);
|
||
|
if (!driveLayoutEx) {
|
||
|
wprintf(L"Could not allocate memory\n");
|
||
|
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
goto EXIT;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// some other error occurred, EXIT, and go to the next drive.
|
||
|
//
|
||
|
wprintf(L"Could not get the drive layout for %ws (%lu)\n", szDiskPath, dwStatus);
|
||
|
goto EXIT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Now modify the signature, and set the layout again
|
||
|
//
|
||
|
driveLayoutEx->Mbr.Signature = dwNewSignature;
|
||
|
|
||
|
bResult = DeviceIoControl(
|
||
|
hDisk,
|
||
|
IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
|
||
|
driveLayoutEx,
|
||
|
dwBufferSize,
|
||
|
NULL,
|
||
|
0L,
|
||
|
&dwBytesReturned,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (!bResult) {
|
||
|
//
|
||
|
// SET_DRIVE_LAYOUT failed
|
||
|
//
|
||
|
dwStatus = GetLastError();
|
||
|
wprintf(L"Could not SET the drive layout for %ws (%lu)\n", szDiskPath, dwStatus);
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
|
||
|
EXIT:
|
||
|
|
||
|
if (driveLayoutEx) {
|
||
|
HeapFree(hHeap, 0L, driveLayoutEx);
|
||
|
driveLayoutEx = NULL;
|
||
|
}
|
||
|
|
||
|
if ((hDisk) && (INVALID_HANDLE_VALUE != hDisk)) {
|
||
|
CloseHandle(hDisk);
|
||
|
hDisk = NULL;
|
||
|
}
|
||
|
|
||
|
SetLastError(dwStatus);
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
pConfirmWipe(
|
||
|
IN CONST PCWSTR szDiskDisplayName
|
||
|
)
|
||
|
{
|
||
|
|
||
|
WCHAR szInput[10];
|
||
|
|
||
|
wprintf(L"\nWARNING. This will delete all partitions from %ws\n", szDiskDisplayName);
|
||
|
wprintf(L"Are you sure you want to continue [y/n]? ");
|
||
|
wscanf(L"%ws", szInput);
|
||
|
|
||
|
wprintf(L"\n");
|
||
|
return ((L'Y' == szInput[0]) || (L'y' == szInput[0]));
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
pWipeDisk(
|
||
|
IN CONST ULONG ulDiskNumber,
|
||
|
IN CONST ULONG ulFirstMB,
|
||
|
IN CONST ULONG ulLastMB
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Deletes the drive layout for disk, and writes 0's at the start and end of the disk.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ulDiskNumber - DiskNumber to wipe
|
||
|
|
||
|
ulFirstMB - Number of MB to erase at the beginning of the disk
|
||
|
|
||
|
ulLastMB - Number of MB to erase at the end of the disk
|
||
|
|
||
|
Return Values:
|
||
|
|
||
|
If the function succeeds, the return value is a nonzero value.
|
||
|
|
||
|
If the function fails, the return value is zero. To get extended error
|
||
|
information, call GetLastError().
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
DWORD dwStatus = ERROR_SUCCESS,
|
||
|
dwBytes = 0;
|
||
|
|
||
|
BYTE Buffer[BUFFER_SIZE_BYTES];
|
||
|
int i = 0, loopTimes = 0;
|
||
|
|
||
|
BOOL bResult = FALSE;
|
||
|
|
||
|
HANDLE hDisk = NULL;
|
||
|
WCHAR szFriendlyName[100]; // For display "Disk 2"
|
||
|
WCHAR szDiskPath[100]; // For CreateFile "\\.\PhysicalDrive2"
|
||
|
|
||
|
PARTITION_INFORMATION_EX ptnInfo;
|
||
|
|
||
|
wsprintf(szFriendlyName, L"Disk %lu", ulDiskNumber);
|
||
|
wsprintf(szDiskPath, L"\\\\.\\PhysicalDrive%lu", ulDiskNumber);
|
||
|
|
||
|
ZeroMemory(Buffer, BUFFER_SIZE_BYTES);
|
||
|
|
||
|
|
||
|
if (g_bPrompt && !pConfirmWipe(szFriendlyName)) {
|
||
|
//
|
||
|
// User didn't want to continue
|
||
|
//
|
||
|
SetLastError(ERROR_CANCELLED);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the signature to something random. We need to do this before
|
||
|
// deleting the layout for the boot disk.
|
||
|
//
|
||
|
pSetSignature(ulDiskNumber, 0);
|
||
|
|
||
|
|
||
|
hDisk = CreateFile(
|
||
|
szDiskPath, // lpFileName
|
||
|
GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess
|
||
|
FILE_SHARE_READ, // dwShareMode
|
||
|
NULL, // lpSecurityAttributes
|
||
|
OPEN_EXISTING, // dwCreationFlags
|
||
|
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, // dwFlagsAndAttributes
|
||
|
NULL // hTemplateFile
|
||
|
);
|
||
|
|
||
|
if ((INVALID_HANDLE_VALUE == hDisk) || (NULL == hDisk)) {
|
||
|
//
|
||
|
// Couldn't open a handle.
|
||
|
//
|
||
|
wprintf(L"Unable to open a handle to %ws (%lu)\n", szDiskPath, GetLastError());
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Zero out the first two sectors of each partition?
|
||
|
//
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Delete the drive layout
|
||
|
//
|
||
|
wprintf(L"Deleting partitions on %ws ...\n", szFriendlyName);
|
||
|
bResult = DeviceIoControl(
|
||
|
hDisk,
|
||
|
IOCTL_DISK_DELETE_DRIVE_LAYOUT,
|
||
|
NULL,
|
||
|
0L,
|
||
|
NULL,
|
||
|
0L,
|
||
|
&dwBytes,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
bResult = TRUE;
|
||
|
if (!bResult) {
|
||
|
wprintf(L"Unable to delete partitions on %ws (%lu)\n", szDiskPath, GetLastError());
|
||
|
|
||
|
CloseHandle(hDisk);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Erase MB at the start of the disk
|
||
|
//
|
||
|
if (ulFirstMB > 0) {
|
||
|
|
||
|
wprintf(L"Erasing first %lu MB on %ws ...\n", ulFirstMB, szFriendlyName);
|
||
|
|
||
|
//
|
||
|
// Write 0's to disk in BUFFER_SIZE chunks
|
||
|
//
|
||
|
loopTimes = (ulFirstMB * 1024 * 1024 / BUFFER_SIZE_BYTES);
|
||
|
for (i = 0; i < loopTimes; i++) {
|
||
|
bResult = WriteFile(
|
||
|
hDisk,
|
||
|
&Buffer,
|
||
|
BUFFER_SIZE_BYTES,
|
||
|
&dwBytes,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (!bResult) {
|
||
|
wprintf(L"Error while writing to %ws (%d, %lu)\n", szDiskPath, i, GetLastError());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!bResult) {
|
||
|
CloseHandle(hDisk);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Erase MB at the end of the disk
|
||
|
//
|
||
|
if (ulLastMB > 0) {
|
||
|
|
||
|
wprintf(L"Erasing last %lu MB on %ws ...\n", ulLastMB, szFriendlyName);
|
||
|
|
||
|
//
|
||
|
// Find the end of the disk
|
||
|
//
|
||
|
bResult = DeviceIoControl(
|
||
|
hDisk,
|
||
|
IOCTL_DISK_GET_PARTITION_INFO_EX,
|
||
|
NULL,
|
||
|
0,
|
||
|
&ptnInfo,
|
||
|
sizeof(PARTITION_INFORMATION_EX),
|
||
|
&dwBytes,
|
||
|
NULL
|
||
|
);
|
||
|
if (!bResult) {
|
||
|
wprintf(L"Could not find size of disk %ws (%lu)\n", szDiskPath, GetLastError());
|
||
|
CloseHandle(hDisk);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find offset we'd like to start zero-ing out from
|
||
|
// (end of disk - bytes to zero out)
|
||
|
//
|
||
|
ptnInfo.PartitionLength.QuadPart -= (ulLastMB * 1024 * 1024);
|
||
|
|
||
|
dwBytes = SetFilePointer(hDisk, (ptnInfo.PartitionLength.LowPart), &(ptnInfo.PartitionLength.HighPart), FILE_BEGIN);
|
||
|
if ((INVALID_SET_FILE_POINTER == dwBytes) && (NO_ERROR != GetLastError())) {
|
||
|
wprintf(L"Could not move to end of disk for %ws (%lu)\n", szDiskPath, GetLastError());
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Write 0's to disk in BUFFER_SIZE chunks
|
||
|
//
|
||
|
loopTimes = (ulLastMB * 1024 * 1024 / BUFFER_SIZE_BYTES);
|
||
|
for (i = 0; i < loopTimes; i++) {
|
||
|
bResult = WriteFile(
|
||
|
hDisk,
|
||
|
&Buffer,
|
||
|
BUFFER_SIZE_BYTES,
|
||
|
&dwBytes,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (!bResult) {
|
||
|
wprintf(L"Error while writing to %ws (%d, %lu)\n", szDiskPath, i, GetLastError());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!bResult) {
|
||
|
CloseHandle(hDisk);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CloseHandle(hDisk);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
pPrintUsage(
|
||
|
IN CONST PCWSTR szArgV0
|
||
|
) {
|
||
|
|
||
|
wprintf(L"usage: %ws [/f] disk-number [mb-at-start [mb-at-end]]\n"
|
||
|
L" %ws /s new-signature disk-number\n"
|
||
|
L"\n"
|
||
|
L" /f: Suppress the prompt to confirm action\n"
|
||
|
L"\n"
|
||
|
L" disk-number: The NT disk-number of the disk that\n"
|
||
|
L" the operation is to be performed\n"
|
||
|
L"\n"
|
||
|
L" mb-at-start: The number of MB to zero-out at\n"
|
||
|
L" the start of the disk. Default is 1\n"
|
||
|
L"\n"
|
||
|
L" mb-at-end: The number of MB to zero-out at\n"
|
||
|
L" the end of the disk. Default is 4\n"
|
||
|
L"\n",
|
||
|
L" /s: Set the signature of disk\n"
|
||
|
L"\n"
|
||
|
L" new-signature: Value to set the disk signature to.\n"
|
||
|
L" Specify 0 to use a randomly generated\n"
|
||
|
L" value\n"
|
||
|
L"\n",
|
||
|
szArgV0,
|
||
|
szArgV0
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
int __cdecl
|
||
|
wmain(
|
||
|
int argc,
|
||
|
WCHAR *argv[],
|
||
|
WCHAR *envp[]
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Entry point to wipedisk.exe.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
argc - Number of command-line parameters used to invoke the app
|
||
|
|
||
|
argv - The command-line parameters as an array of strings.
|
||
|
argv[1] (required) is expected to be the disk number
|
||
|
argv[2] (optional) is the initial MB to erase, default 1
|
||
|
argv[3] (optional) is the last MB to erase, default 4
|
||
|
|
||
|
envp - The process environment block, not currently used
|
||
|
|
||
|
Return Values:
|
||
|
|
||
|
If the function succeeds, the exit code is zero.
|
||
|
|
||
|
If the function fails, the exit code is a win-32 error code.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
BOOL bResult = TRUE,
|
||
|
bSetSignature = FALSE;
|
||
|
|
||
|
ULONG ulDiskNumber = 0,
|
||
|
ulInitialMB = 1,
|
||
|
ulFinalMB = 4;
|
||
|
|
||
|
DWORD dwNewSignature = 0L;
|
||
|
|
||
|
int shift = 0;
|
||
|
|
||
|
SetLastError(ERROR_CAN_NOT_COMPLETE); // for unexpected failures
|
||
|
|
||
|
if (argc >= 2) {
|
||
|
if ((L'-' == argv[1][0]) || (L'/' == argv[1][0])) {
|
||
|
//
|
||
|
// Parse the options
|
||
|
//
|
||
|
|
||
|
switch (argv[1][1]) {
|
||
|
case L'f':
|
||
|
case L'F': {
|
||
|
|
||
|
g_bPrompt = FALSE;
|
||
|
shift = 1; // account for /f
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case L's':
|
||
|
case L'S': {
|
||
|
|
||
|
bSetSignature = TRUE;
|
||
|
shift = 2; // account for /s <New Signature>
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (argc >= shift + 2) {
|
||
|
swscanf(argv[shift + 1], L"%lu", &ulDiskNumber);
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// We need at least one argument--the disk number
|
||
|
//
|
||
|
pPrintUsage(argv[0]);
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (bSetSignature) {
|
||
|
|
||
|
//
|
||
|
// Set the signature of the disk to a new value
|
||
|
//
|
||
|
swscanf(argv[shift], L"%lu", &dwNewSignature);
|
||
|
bResult = pSetSignature(ulDiskNumber, dwNewSignature);
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// Wipe the disk. Get the amount to zero-out at the start
|
||
|
// and end of disk
|
||
|
//
|
||
|
if (argc >= shift + 3) {
|
||
|
swscanf(argv[shift + 2], L"%lu", &ulInitialMB);
|
||
|
|
||
|
if (argc >= shift + 4) {
|
||
|
swscanf(argv[shift + 3], L"%lu", &ulFinalMB);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bResult = pWipeDisk(ulDiskNumber, ulInitialMB, ulFinalMB);
|
||
|
}
|
||
|
|
||
|
if (bResult) {
|
||
|
wprintf(L"Done.\n");
|
||
|
}
|
||
|
|
||
|
return (bResult ? 0 : GetLastError());
|
||
|
}
|