windows-nt/Source/XPSP1/NT/base/ntsetup/tools/dt/dt.cpp
2020-09-26 16:20:57 +08:00

715 lines
17 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
dt.cpp
Abstract:
Utility to do some disk related operations
Author:
Vijay Jayaseelan (vijayj) 26 April 2001
Revision History:
None
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <bootmbr.h>
#include <iostream>
#include <string>
#include <exception>
#include <windows.h>
#include <tchar.h>
#include <locale>
#include <winioctl.h>
//
// Usage format
//
PCWSTR Usage = L"Usage: dt.exe /?\r\n"
L"dt.exe /dump {[drive-letter] | [disk-number]} start-sector sector-count\r\n"
L"dt.exe /diskinfo disk-number\r\n";
//
// Helper dump operators
//
std::ostream& operator<<(std::ostream &os, const std::wstring &str) {
FILE *OutStream = (&os == &std::cerr) ? stderr : stdout;
fwprintf(OutStream, (PWSTR)str.c_str());
return os;
}
//
// Helper dump operators
//
std::ostream& operator<<(std::ostream &os, WCHAR *Str) {
std::wstring WStr = Str;
os << WStr;
return os;
}
//
// Exceptions
//
struct ProgramException : public std::exception {
virtual void Dump(std::ostream &os) = 0;
};
//
// Abstracts a Win32 error
//
struct W32Error : public ProgramException {
DWORD ErrorCode;
W32Error(DWORD ErrCode = GetLastError()) : ErrorCode(ErrCode){}
void Dump(std::ostream &os) {
WCHAR MsgBuffer[4096];
MsgBuffer[0] = UNICODE_NULL;
DWORD CharCount = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
MsgBuffer,
sizeof(MsgBuffer)/sizeof(WCHAR),
NULL);
if (CharCount) {
std::wstring Msg(MsgBuffer);
os << Msg;
} else {
os << std::hex << ErrorCode;
}
}
};
//
// Invalid arguments
//
struct InvalidArguments : public ProgramException {
const char *what() const throw() {
return "Invalid Arguments";
}
void Dump(std::ostream &os) {
os << what() << std::endl;
}
};
//
// Invalid arguments
//
struct ProgramUsage : public ProgramException {
std::wstring PrgUsage;
ProgramUsage(const std::wstring &Usg) : PrgUsage(Usg) {}
const char *what() const throw() {
return "Program Usage exception";
}
void Dump(std::ostream &os) {
os << PrgUsage << std::endl;
}
};
//
// Program Arguments abstraction
//
struct ProgramArguments {
bool DumpSectors;
ULONG DiskIndex;
std::wstring DriveLetter;
LONGLONG StartingSector;
ULONG NumSectors;
std::wstring DeviceName;
bool DumpDiskInfo;
ProgramArguments(INT Argc, WCHAR *Argv[]) {
bool ShowUsage = false;
DumpSectors = false;
DumpDiskInfo = false;
DiskIndex = -1;
StartingSector = -1;
NumSectors = -1;
for (ULONG Index=1; !ShowUsage && (Index < Argc); Index++) {
if (!_wcsicmp(Argv[Index], TEXT("/dump"))) {
ShowUsage = TRUE;
if (((Index + 4) == Argc)) {
Index++;
DriveLetter = Argv[Index++];
if ((DriveLetter.length() == 1)) {
if (iswdigit(DriveLetter[0])) {
WCHAR StrBuffer[64];
DiskIndex = _wtol(DriveLetter.c_str());
DriveLetter[0] = UNICODE_NULL;
swprintf(StrBuffer,
TEXT("\\\\.\\PHYSICALDRIVE%d"),
DiskIndex);
DeviceName = StrBuffer;
} else {
DeviceName = TEXT("\\\\.\\") + DriveLetter + TEXT(":");
}
StartingSector = (LONGLONG)(_wtoi64(Argv[Index++]));;
NumSectors = (ULONG)_wtol(Argv[Index++]);
ShowUsage = !(((DiskIndex != -1) || (DriveLetter[0])) &&
(NumSectors != 0));
DumpSectors = !ShowUsage;
}
}
} else if (!_wcsicmp(Argv[Index], TEXT("/diskinfo"))) {
DumpDiskInfo = TRUE;
ShowUsage = TRUE;
DriveLetter = Argv[++Index];
if ((DriveLetter.length() == 1)) {
if (iswdigit(DriveLetter[0])) {
WCHAR StrBuffer[64];
DiskIndex = _wtol(DriveLetter.c_str());
DriveLetter[0] = UNICODE_NULL;
swprintf(StrBuffer,
TEXT("\\\\.\\PHYSICALDRIVE%d"),
DiskIndex);
DeviceName = StrBuffer;
ShowUsage = FALSE;
}
}
} else {
ShowUsage = TRUE;
}
}
if (ShowUsage) {
throw new ProgramUsage(Usage);
}
}
};
//
// Dumps the given binary data of the specified size
// into the output stream with required indent size
//
void
DumpBinary(unsigned char *Data, int Size,
std::ostream& os, int Indent = 16)
{
if (Data && Size) {
int Index = 0;
int foo;
char szBuff[128] = {'.'};
int Ruler = 0;
while (Index < Size) {
if (!(Index % Indent)) {
if (Index) {
szBuff[Indent] = 0;
os << szBuff;
}
os << std::endl;
os.width(8);
os.fill('0');
os << Ruler << " ";
Ruler += Indent;
}
foo = *(Data + Index);
szBuff[Index % Indent] = ::isalnum(foo) ? (char)foo : (char)'.';
os.width(2);
os.fill('0');
os.flags(std::ios::uppercase | std::ios::hex);
os << foo << ' ';
Index++;
}
while (Index % Indent) {
os << ' ';
Index++;
szBuff[Index % Indent] = ' ';
}
szBuff[Indent] = 0;
os << szBuff;
} else {
os << std::endl << "no data" << std::endl;
}
}
//
// Abstracts block device (interface)
//
class W32BlockDevice {
public:
W32BlockDevice(const std::wstring &name, ULONG SecSize) :
SectorSize(SecSize), DeviceHandle(INVALID_HANDLE_VALUE), Name(name){
//
// Open the device
//
DeviceHandle = CreateFile(Name.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
DWORD LastError = GetLastError();
if (LastError) {
throw new W32Error(LastError);
}
}
virtual ~W32BlockDevice() {
if (DeviceHandle != INVALID_HANDLE_VALUE) {
CloseHandle(DeviceHandle);
}
};
ULONG GetSectorSize() const { return SectorSize; }
//
// Reads the requested size of data from the given sector
//
virtual DWORD ReadSectors(LONGLONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
LARGE_INTEGER MoveLength;
MoveLength.QuadPart = Index * SectorSize;
SetFilePointerEx(DeviceHandle,
MoveLength,
NULL,
FILE_BEGIN);
DWORD LastError = GetLastError();
if (!LastError) {
DWORD BytesRead = 0;
if (!ReadFile(DeviceHandle,
DataBuffer,
BufferSize,
&BytesRead,
NULL)) {
LastError = GetLastError();
}
}
return LastError;
}
//
// Writes the requested size of data to the specified sector
//
virtual DWORD WriteSectors(ULONG Index, PBYTE DataBuffer, ULONG BufferSize = 512) {
LARGE_INTEGER MoveLength;
MoveLength.QuadPart = Index * SectorSize;
SetFilePointerEx(DeviceHandle,
MoveLength,
NULL,
FILE_BEGIN);
DWORD LastError = GetLastError();
if (!LastError) {
DWORD BytesWritten = 0;
if (!WriteFile(DeviceHandle,
DataBuffer,
BufferSize,
&BytesWritten,
NULL)) {
LastError = GetLastError();
}
}
return LastError;
}
virtual std::ostream& Dump(std::ostream &os) {
os << TEXT("Device Name = ") << TEXT("(") << Name << TEXT(")") << std::endl;
return os;
}
const HANDLE GetHandle() const { return DeviceHandle; }
protected:
//
// Data members
//
HANDLE DeviceHandle;
ULONG SectorSize;
std::wstring Name;
};
VOID
DumpSectors(
IN ProgramArguments &Args
)
{
if (Args.DumpSectors) {
W32BlockDevice Device(Args.DeviceName, 512);
WCHAR LongString[64];
BYTE Sector[4096];
ULONG SectorCount = Args.NumSectors;
LONGLONG StartingSector = Args.StartingSector;
Device.Dump(std::cout);
while (SectorCount && (Device.ReadSectors(StartingSector, Sector) == NO_ERROR)) {
std::cout << std::endl << "Sector : " << std::dec;
LongString[0] = 0;
std::cout << _i64tow(StartingSector, LongString, 10);
DumpBinary(Sector, Device.GetSectorSize(), std::cout);
std::cout << std::endl;
SectorCount--;
StartingSector++;
}
} else {
SetLastError(ERROR_INVALID_PARAMETER);
}
DWORD LastError = GetLastError();
if (LastError != NO_ERROR) {
throw new W32Error(LastError);
}
}
#ifndef _WIN64
std::ostream&
operator<<(std::ostream &os, const ULONGLONG &LargeInteger) {
WCHAR Buffer[64];
swprintf(Buffer, L"%I64u", LargeInteger);
os << Buffer;
return os;
}
std::ostream&
operator<<(std::ostream &os, const LONGLONG &LargeInteger) {
WCHAR Buffer[64];
swprintf(Buffer, L"%I64d", LargeInteger);
os << Buffer;
return os;
}
#endif // ! _WIN64
inline
std::ostream&
operator<<(std::ostream &os, const LARGE_INTEGER &LargeInteger) {
return (os << LargeInteger.QuadPart);
}
inline
std::ostream&
operator<<(std::ostream &os, const GUID &Guid) {
WCHAR Buffer[MAX_PATH];
swprintf(Buffer,
TEXT("{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
Guid.Data1,
Guid.Data2,
Guid.Data3,
Guid.Data4[0],
Guid.Data4[1],
Guid.Data4[2],
Guid.Data4[3],
Guid.Data4[4],
Guid.Data4[5],
Guid.Data4[6],
Guid.Data4[7]);
os << Buffer;
return os;
}
inline
std::ostream&
operator<<(std::ostream &os, const PARTITION_INFORMATION_MBR &MbrPartInfo) {
WCHAR Buffer[MAX_PATH];
swprintf(Buffer,
TEXT("Type : 0x%02lX, Active : %ws, Recognized : %ws, Hidden Sectors : %d"),
MbrPartInfo.PartitionType,
(MbrPartInfo.BootIndicator ? TEXT("TRUE") : TEXT("FALSE")),
(MbrPartInfo.HiddenSectors ? TEXT("TRUE") : TEXT("FALSE")),
MbrPartInfo.HiddenSectors);
os << Buffer << std::endl;
return os;
}
inline
std::ostream&
operator<<(std::ostream &os, const PARTITION_INFORMATION_GPT &GptPartInfo) {
os << "Type : " << GptPartInfo.PartitionType << ", ";
os << "Id : " << GptPartInfo.PartitionId << ", ";
os << "Attrs : " << GptPartInfo.Attributes << ", ";
os << "Name : " << std::wstring(GptPartInfo.Name);
return os;
}
std::ostream&
operator<<(std::ostream &os, const PARTITION_INFORMATION_EX &PartInfo) {
os << "Partition# : " << std::dec << PartInfo.PartitionNumber;
os << ", Start : " << PartInfo.StartingOffset.QuadPart;
os << ", Length : " << PartInfo.PartitionLength.QuadPart << std::endl;
switch(PartInfo.PartitionStyle) {
case PARTITION_STYLE_MBR:
os << PartInfo.Mbr;
break;
case PARTITION_STYLE_GPT:
os << PartInfo.Gpt;
break;
default:
break;
}
os << std::endl;
return os;
}
std::ostream&
operator<<(std::ostream &os, const DRIVE_LAYOUT_INFORMATION_MBR &MbrInfo) {
os << "Signature : " << std::hex << MbrInfo.Signature;
return os;
}
std::ostream&
operator<<(std::ostream &os, const DRIVE_LAYOUT_INFORMATION_GPT &GptInfo) {
os << "Disk ID : " << GptInfo.DiskId << ", ";
os << "Starting Offset : " << std::dec << GptInfo.StartingUsableOffset << ", ";
os << "Usable Length : " << std::dec << GptInfo.UsableLength << ", ";
os << "Max Partition Count : " << std::dec << GptInfo.MaxPartitionCount;
return os;
}
std::ostream&
operator<<(std::ostream &os, const DRIVE_LAYOUT_INFORMATION_EX &DriveInfo) {
os << "Disk Type : ";
switch (DriveInfo.PartitionStyle) {
case PARTITION_STYLE_MBR:
os << "MBR";
break;
case PARTITION_STYLE_GPT:
os << "GPT";
break;
default:
os << "Unknown";
break;
}
os << ", Partition Count : " << std::dec << DriveInfo.PartitionCount << " ";
switch(DriveInfo.PartitionStyle) {
case PARTITION_STYLE_MBR:
os << DriveInfo.Mbr;
break;
case PARTITION_STYLE_GPT:
os << DriveInfo.Gpt;
break;
default:
break;
}
os << std::endl << std::endl;
for (ULONG Index = 0; Index < DriveInfo.PartitionCount; Index++) {
if (DriveInfo.PartitionEntry[Index].PartitionNumber) {
os << DriveInfo.PartitionEntry[Index];
os << std::endl;
}
}
os << std::endl;
return os;
}
std::ostream&
operator<<(std::ostream &os, const DISK_GEOMETRY &DiskInfo) {
os << "Heads : " << std::dec << DiskInfo.TracksPerCylinder;
os << ", Cylinders : " << DiskInfo.Cylinders;
os << ", Sectors/Track : " << std::dec << DiskInfo.SectorsPerTrack;
os << ", Bytes/Sector : " << std::dec << DiskInfo.BytesPerSector;
return os;
}
void
DumpDiskCharacteristics(
IN ProgramArguments &Args
)
{
DWORD LastError = NO_ERROR;
if (Args.DumpDiskInfo){
W32BlockDevice Device(Args.DeviceName, 512);
HANDLE DeviceHandle = (HANDLE)Device.GetHandle();
ULONG BufferLength = 16 * 1024;
PBYTE Buffer = new BYTE[BufferLength];
if (Buffer) {
DWORD BytesReturned = 0;
PDISK_GEOMETRY DiskInfo = (PDISK_GEOMETRY)Buffer;
Device.Dump(std::cout);
if (DeviceIoControl(DeviceHandle,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
Buffer,
BufferLength,
&BytesReturned,
NULL)) {
std::cout << (*DiskInfo) << std::endl;
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)Buffer;
if (DeviceIoControl(DeviceHandle,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
NULL,
0,
Buffer,
BufferLength,
&BytesReturned,
NULL)) {
//
// dump the disk information
//
std::cout << (*DriveLayout);
}
}
LastError = GetLastError();
delete []Buffer;
}
} else {
SetLastError(ERROR_INVALID_PARAMETER);
}
if (LastError == NO_ERROR) {
LastError = GetLastError();
}
if (LastError != NO_ERROR) {
throw new W32Error(LastError);
}
}
//
// main() entry point
//
int
__cdecl
wmain(
int Argc,
wchar_t *Argv[]
)
{
int Result = 0;
try {
ProgramArguments Args(Argc, Argv);
if (Args.DumpSectors) {
DumpSectors(Args);
} else if (Args.DumpDiskInfo) {
DumpDiskCharacteristics(Args);
} else {
throw new ProgramUsage(Usage);
}
}
catch(W32Error *W32Err) {
Result = 1;
if (W32Err) {
W32Err->Dump(std::cout);
delete W32Err;
}
}
catch(ProgramException *PrgExp) {
Result = 1;
if (PrgExp) {
PrgExp->Dump(std::cout);
delete PrgExp;
}
} catch (exception *Exp) {
Result = 1;
if (Exp) {
std::cout << Exp->what() << std::endl;
}
}
return Result;
}