windows-nt/Source/XPSP1/NT/base/fs/utils/asrtools/wipedisk/wipedisk.cpp
2020-09-26 16:20:57 +08:00

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());
}