windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/sys/disk.cpp

587 lines
12 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//
// DISK.CPP - Classes for partition table manipulation
//
// Revision History:
//
#include "disk.h"
#include <stdio.h>
#include <rpc.h>
#include <rpcdce.h>
#include <bootmbr.h>
HRESULT
CDrive::Initialize(
LPCTSTR lpszLogicalDrive
)
{
HANDLE handle;
HRESULT hr;
DISK_GEOMETRY geom;
ULONG bps;
PVOID unalignedBuffer;
PVOID buffer;
/*
* Open the disk device
*/
handle = LowOpenPartition(lpszLogicalDrive);
if (handle == INVALID_HANDLE_VALUE) {
return E_INVALIDARG;
}
/*
* Get the geometry
*/
hr = LowGetGeometry(handle, &geom);
if (FAILED(hr)) {
CloseHandle(handle);
return hr;
}
m_geometry.cylinders = geom.Cylinders.QuadPart;
m_geometry.mediaType = geom.MediaType;
m_geometry.tracksPerCylinder = geom.TracksPerCylinder;
m_geometry.sectorsPerTrack = geom.SectorsPerTrack;
m_geometry.bytesPerSector = geom.BytesPerSector;
m_geometry.bytesPerTrack = m_geometry.sectorsPerTrack *
m_geometry.bytesPerSector;
m_geometry.bytesPerCylinder = m_geometry.tracksPerCylinder *
m_geometry.bytesPerTrack;
m_geometry.totalSectorCount = (ULONGLONG)(m_geometry.cylinders *
m_geometry.bytesPerCylinder);
m_length = m_geometry.cylinders * m_geometry.bytesPerCylinder;
if (m_length == 0) {
// Probably no media is present in the drive
return E_INVALIDARG;
}
/*
* Get the true length of the drive
*/
hr = LowGetLength(handle, &m_trueLength);
if (FAILED(hr)) {
CloseHandle(handle);
return hr;
}
/*
* Check whether this is a NEC98 disk
*/
m_isNEC98 = FALSE;
bps = m_geometry.bytesPerSector;
unalignedBuffer = (PVOID) new char[2 * bps];
if (!unalignedBuffer) {
CloseHandle(handle);
return E_OUTOFMEMORY;
}
buffer = (PVOID) (((ULONG_PTR)unalignedBuffer + bps) & ~((ULONG_PTR)(bps - 1)));
hr = LowReadSectors(handle, bps, 0, 1, buffer);
if (FAILED(hr)) {
delete [] (char*) unalignedBuffer;
CloseHandle(handle);
return hr;
}
if (IsNEC_98) {
if (((unsigned char *)buffer)[0x1fe] == 0x55 && ((unsigned char *)buffer)[0x1ff] == 0xaa) {
if (((unsigned char *)buffer)[4] == 'I' && ((unsigned char *)buffer)[5] == 'P' &&
((unsigned char *)buffer)[6] == 'L' && ((unsigned char *)buffer)[7] == '1') {
m_isNEC98 = TRUE;
}
} else {
m_isNEC98 = TRUE;
}
}
delete [] (char*) unalignedBuffer;
/*
* We have all the information we need. Return.
*/
CloseHandle(handle);
return S_OK;
}
CDrive::~CDrive(
)
{
}
HRESULT
CDrive::ReadBootRecord(
LPCTSTR lpszLogicalDrive,
UINT nSectors,
PBYTE *buffer
)
{
HANDLE hPartition;
HRESULT hr;
*buffer = new BYTE[m_geometry.bytesPerSector * nSectors];
// Do disk ops, read bootcode
//
hPartition = LowOpenPartition(lpszLogicalDrive);
if ( hPartition == INVALID_HANDLE_VALUE )
{
delete[] *buffer;
*buffer = NULL;
throw new W32Error();
}
hr = LowReadSectors(hPartition, m_geometry.bytesPerSector, 0, nSectors, *buffer);
if ( S_OK != hr )
{
delete[] *buffer;
*buffer = NULL;
CloseHandle( hPartition );
throw new W32Error();
}
CloseHandle( hPartition );
// The calling function is responsible for cleaning up the buffer.
//
return hr;
}
HRESULT
CDrive::WriteBootRecord(
LPCTSTR lpszLogicalDrive,
UINT nSectors,
PBYTE *buffer
)
{
HANDLE hPartition;
HRESULT hr;
UINT *uiBackupSector = NULL;
// Do disk ops, write bootcode
//
hPartition = LowOpenPartition(lpszLogicalDrive);
if ( INVALID_HANDLE_VALUE == hPartition )
{
throw new W32Error();
}
// Figure out where the backup boot sector is. It is at offset 0x32 in the boot record.
//
uiBackupSector = (UINT *) &((*buffer)[0x32]);
hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, 0, nSectors, *buffer);
if ( S_OK != hr )
{
CloseHandle(hPartition);
throw new W32Error();
}
if ( uiBackupSector )
{
hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, *uiBackupSector, nSectors, *buffer);
}
if ( S_OK != hr )
{
CloseHandle(hPartition);
throw new W32Error();
}
CloseHandle(hPartition);
return hr;
}
HRESULT
CDrive::WriteBootRecordXP(
LPCTSTR lpszLogicalDrive,
UINT nSectors,
PBYTE *buffer
)
{
HANDLE hPartition;
HRESULT hr;
UINT *uiBackupSector = NULL;
// Do disk ops, write bootcode
//
hPartition = LowOpenPartition(lpszLogicalDrive);
if ( INVALID_HANDLE_VALUE == hPartition )
{
throw new W32Error();
}
// Figure out where the backup boot sector is. It is at offset 0x32 in the boot record.
//
uiBackupSector = (UINT *) &((*buffer)[0x32]);
// Write out the first 2 sectors to sectors 0 and 1 on the disk. We will write the
// third sector to sector 12.
//
hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, 0, nSectors - 1, *buffer);
if ( S_OK != hr )
{
CloseHandle(hPartition);
throw new W32Error();
}
// For NT we need to write out the third sector of the bootcode to sector 12.
//
hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, 12, 1, *buffer + (2 * m_geometry.bytesPerSector));
if ( S_OK != hr )
{
CloseHandle(hPartition);
throw new W32Error();
}
if ( uiBackupSector )
{
hr = LowWriteSectors(hPartition, m_geometry.bytesPerSector, *uiBackupSector, nSectors, *buffer);
}
if ( S_OK != hr )
{
CloseHandle(hPartition);
throw new W32Error();
}
CloseHandle(hPartition);
return hr;
}
HANDLE
LowOpenDisk(
ULONG diskNumber
)
{
HANDLE handle = NULL;
int err = 0;
int i = 0;
WCHAR buffer[64];
swprintf(buffer, L"\\\\.\\PHYSICALDRIVE%lu", diskNumber);
for ( i = 0; i < 5; i++ )
{
handle = CreateFile(
buffer,
GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_DELETE |
FILE_SHARE_READ |
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (handle == INVALID_HANDLE_VALUE)
{
err = GetLastError();
if (err == ERROR_SHARING_VIOLATION) Sleep(2000);
else break;
}
else break;
}
return handle;
}
HANDLE
LowOpenPartition(
ULONG diskNumber,
ULONG partitionNumber
)
{
WCHAR buffer[64];
swprintf(buffer, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%lu\\Partition%lu",
diskNumber, partitionNumber);
return CreateFile(
buffer,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
HANDLE
LowOpenPartition(
LPCTSTR lpszLogicalDrive
)
{
return CreateFile(
lpszLogicalDrive,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
}
HRESULT
LowGetGeometry(
HANDLE handle,
PDISK_GEOMETRY geometry
)
{
ULONG size;
if (!DeviceIoControl(
handle,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
geometry,
sizeof(DISK_GEOMETRY),
&size,
NULL)) {
return E_FAIL;
}
return S_OK;
}
HRESULT
LowGetLength(
HANDLE handle,
PLONGLONG length
)
{
PARTITION_INFORMATION_EX partInfoEx;
PARTITION_INFORMATION partInfo;
ULONG size;
/*
* Try first the new ioctl
*/
if (DeviceIoControl(
handle,
IOCTL_DISK_GET_PARTITION_INFO_EX,
NULL,
0,
&partInfoEx,
sizeof(PARTITION_INFORMATION_EX),
&size,
NULL)) {
*length = partInfoEx.PartitionLength.QuadPart;
return S_OK;
}
/*
* For Win2K systems we should use the old ioctl
*/
if (DeviceIoControl(
handle,
IOCTL_DISK_GET_PARTITION_INFO,
NULL,
0,
&partInfo,
sizeof(PARTITION_INFORMATION),
&size,
NULL)) {
*length = partInfo.PartitionLength.QuadPart;
return S_OK;
}
return E_FAIL;
}
HRESULT
LowReadSectors(
HANDLE handle,
ULONG sectorSize,
ULONG startingSector,
ULONG numberOfSectors,
PVOID buffer
)
{
IO_STATUS_BLOCK statusBlock;
LARGE_INTEGER byteOffset;
byteOffset.QuadPart = UInt32x32To64(startingSector, sectorSize);
statusBlock.Status = 0;
statusBlock.Information = 0;
if (!NT_SUCCESS(NtReadFile(
handle,
0,
NULL,
NULL,
&statusBlock,
buffer,
numberOfSectors * sectorSize,
&byteOffset,
NULL))) {
return E_FAIL;
}
return S_OK;
}
HRESULT
LowWriteSectors(
HANDLE handle,
ULONG sectorSize,
ULONG startingSector,
ULONG numberOfSectors,
PVOID buffer
)
{
IO_STATUS_BLOCK statusBlock;
LARGE_INTEGER byteOffset;
byteOffset.QuadPart = UInt32x32To64(startingSector, sectorSize);
statusBlock.Status = 0;
statusBlock.Information = 0;
if (!NT_SUCCESS(NtWriteFile(
handle,
0,
NULL,
NULL,
&statusBlock,
buffer,
numberOfSectors * sectorSize,
&byteOffset,
NULL))) {
return E_FAIL;
}
return S_OK;
}
HRESULT
LowFsLock(
HANDLE handle
)
{
ULONG size;
if (!DeviceIoControl(
handle,
FSCTL_LOCK_VOLUME,
NULL,
0,
NULL,
0,
&size,
NULL)) {
return E_FAIL;
}
return S_OK;
}
HRESULT
LowFsUnlock(
HANDLE handle
)
{
ULONG size;
if (!DeviceIoControl(
handle,
FSCTL_UNLOCK_VOLUME,
NULL,
0,
NULL,
0,
&size,
NULL)) {
return E_FAIL;
}
return S_OK;
}
HRESULT
LowFsDismount(
HANDLE handle
)
{
ULONG size;
if (!DeviceIoControl(
handle,
FSCTL_DISMOUNT_VOLUME,
NULL,
0,
NULL,
0,
&size,
NULL)) {
return E_FAIL;
}
return S_OK;
}
LONGLONG
RoundUp(
LONGLONG value,
LONGLONG factor
)
/*
* Rounds a value up to a multiple of a given number
*/
{
// This is the most common case so treat it separately
if (value % factor == 0) {
return value;
}
// And this is the generic formula
return ((LONGLONG)((value + factor - 1) / factor)) * factor;
}
LONGLONG
RoundDown(
LONGLONG value,
LONGLONG factor
)
/*
* Rounds a value down to a multiple of a given number
*/
{
// This is the most common case so treat it separately
if (value % factor == 0) {
return value;
}
//And this the generic formula
return ((LONGLONG)(value / factor)) * factor;
}