4424 lines
121 KiB
C++
4424 lines
121 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1996 - 1999
|
||
|
||
Module Name:
|
||
|
||
ondisk.cxx
|
||
|
||
Abstract:
|
||
|
||
This file contains the implementation for the classes defined in
|
||
ondisk.hxx
|
||
|
||
Author:
|
||
|
||
Norbert Kusters 15-July-1996
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
extern "C" {
|
||
#include <ntddk.h>
|
||
}
|
||
|
||
#include <ftdisk.h>
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma code_seg("PAGE")
|
||
#endif
|
||
|
||
NTSTATUS
|
||
IsFormatMediaTypeNEC_98(
|
||
IN PDEVICE_OBJECT WholeDisk,
|
||
IN ULONG SectorSize,
|
||
OUT PBOOLEAN FormatMediaTypeIsNEC_98
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine format media type, PC-9800 architecture or PC/AT architecture
|
||
Logic of determination:
|
||
[removable] - PC/AT architecture
|
||
[fixed] and [0x55AA exist] and [non "IPL1"] - PC/AT architecture
|
||
[fixed] and [0x55AA exist] and ["IPL1" exist] - PC-9800 architecture
|
||
[fixed] and [non 0x55AA ] - PC-9800 architecture
|
||
|
||
Arguments:
|
||
|
||
WholeDisk - Supplies the device object.
|
||
|
||
SectorSize - Supplies the sector size.
|
||
|
||
FormatMediaTypeIsNEC_98 - Return format type
|
||
TRUE - The media was formated by PC-9800 architecture
|
||
FALSE - The media was formated by PC/AT architecture
|
||
or it was not formated
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
KEVENT event;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
PIRP irp;
|
||
NTSTATUS status;
|
||
ULONG readSize;
|
||
PVOID readBuffer;
|
||
LARGE_INTEGER byteOffset;
|
||
|
||
#define IPL1_OFFSET 4
|
||
#define BOOT_SIGNATURE_OFFSET ((0x200 / 2) -1)
|
||
#define BOOT_RECORD_SIGNATURE (0xAA55)
|
||
|
||
*FormatMediaTypeIsNEC_98 = FALSE;
|
||
|
||
// Is this removable?
|
||
|
||
if (WholeDisk->Characteristics&FILE_REMOVABLE_MEDIA) {
|
||
|
||
// Removable media is PC/AT architecture.
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
// Start at sector 0 of the device.
|
||
|
||
readSize = SectorSize;
|
||
byteOffset.QuadPart = 0;
|
||
|
||
if (readSize < 512) {
|
||
readSize = 512;
|
||
}
|
||
|
||
readBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
|
||
readSize < PAGE_SIZE ? PAGE_SIZE : readSize);
|
||
if (!readBuffer) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, WholeDisk,
|
||
readBuffer, readSize, &byteOffset,
|
||
&event, &ioStatus);
|
||
|
||
if (!irp) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
status = IoCallDriver(WholeDisk, irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(readBuffer);
|
||
return status;
|
||
}
|
||
|
||
if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] ==
|
||
BOOT_RECORD_SIGNATURE) {
|
||
|
||
if (!strncmp((PCHAR) readBuffer + IPL1_OFFSET, "IPL1",
|
||
sizeof("IPL1") - 1)) {
|
||
|
||
// It's PC-9800 Architecture.
|
||
*FormatMediaTypeIsNEC_98 = TRUE;
|
||
}
|
||
} else {
|
||
|
||
// It's PC-9800 Architecture.
|
||
*FormatMediaTypeIsNEC_98 = TRUE;
|
||
}
|
||
|
||
ExFreePool(readBuffer);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION::Initialize(
|
||
IN PROOT_EXTENSION RootExtension,
|
||
IN OUT PDEVICE_OBJECT WholeDiskPdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reads in the on disk information on the given device
|
||
into memory.
|
||
|
||
Arguments:
|
||
|
||
RootExtension - Supplies the root extension.
|
||
|
||
WholeDiskPdo - Supplies the device object for the whole physical disk PDO.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
KEVENT event;
|
||
PIRP irp;
|
||
STORAGE_DEVICE_NUMBER deviceNumber;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
NTSTATUS status;
|
||
DISK_GEOMETRY geometry;
|
||
PDRIVE_LAYOUT_INFORMATION_EX layout;
|
||
ULONG i;
|
||
LONGLONG offset, minStartingOffset;
|
||
PVOID buffer;
|
||
BOOLEAN formatMediaTypeIsNEC_98;
|
||
|
||
_rootExtension = RootExtension;
|
||
_wholeDisk = IoGetAttachedDeviceReference(WholeDiskPdo);
|
||
_wholeDiskPdo = WholeDiskPdo;
|
||
_diskBuffer = NULL;
|
||
_isDiskSuitableForFtOnDisk = TRUE;
|
||
|
||
status = FtpQueryPartitionInformation(RootExtension, _wholeDisk,
|
||
&_diskNumber, NULL, NULL, NULL,
|
||
NULL, NULL, NULL, NULL, NULL);
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||
_wholeDisk, NULL, 0, &geometry,
|
||
sizeof(geometry), FALSE, &event,
|
||
&ioStatus);
|
||
if (!irp) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
status = IoCallDriver(_wholeDisk, irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = ioStatus.Status;
|
||
}
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
_sectorSize = geometry.BytesPerSector;
|
||
|
||
_byteOffset.QuadPart = 1024;
|
||
|
||
HalExamineMBR(_wholeDisk, _sectorSize, 0x55, &buffer);
|
||
if (buffer) {
|
||
_byteOffset.QuadPart = 0x3000;
|
||
ExFreePool(buffer);
|
||
}
|
||
|
||
if (IsNEC_98) {
|
||
status = IsFormatMediaTypeNEC_98(_wholeDisk, _sectorSize,
|
||
&formatMediaTypeIsNEC_98);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
FtpLogError(_rootExtension, _diskNumber, FT_CANT_READ_ON_DISK,
|
||
status, 0);
|
||
_isDiskSuitableForFtOnDisk = FALSE;
|
||
return status;
|
||
}
|
||
|
||
if (formatMediaTypeIsNEC_98) {
|
||
_byteOffset.QuadPart = 17*_sectorSize;
|
||
}
|
||
}
|
||
|
||
|
||
if (_byteOffset.QuadPart < _sectorSize) {
|
||
_byteOffset.QuadPart = _sectorSize;
|
||
}
|
||
|
||
status = FtpReadPartitionTableEx(_wholeDisk, &layout);
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
minStartingOffset = 0x4000;
|
||
for (i = 0; i < layout->PartitionCount; i++) {
|
||
offset = layout->PartitionEntry[i].StartingOffset.QuadPart;
|
||
if (!offset) {
|
||
continue;
|
||
}
|
||
if (offset < minStartingOffset) {
|
||
minStartingOffset = offset;
|
||
}
|
||
}
|
||
|
||
ExFreePool(layout);
|
||
|
||
_length = (4095/_sectorSize + 1)*_sectorSize;
|
||
if (_byteOffset.QuadPart + _length > minStartingOffset) {
|
||
if (_byteOffset.QuadPart < minStartingOffset) {
|
||
_length = (ULONG) (minStartingOffset - _byteOffset.QuadPart);
|
||
} else {
|
||
_length = 0;
|
||
}
|
||
}
|
||
|
||
if (_length) {
|
||
_diskBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
|
||
_length < PAGE_SIZE ? PAGE_SIZE : _length);
|
||
if (!_diskBuffer) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, _wholeDisk,
|
||
_diskBuffer, _length, &_byteOffset,
|
||
&event, &ioStatus);
|
||
|
||
if (!irp) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
status = IoCallDriver(_wholeDisk, irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
FtpLogError(_rootExtension, _diskNumber, FT_CANT_READ_ON_DISK,
|
||
status, 0);
|
||
_isDiskSuitableForFtOnDisk = FALSE;
|
||
RtlZeroMemory(_diskBuffer, _length);
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
} else {
|
||
_diskBuffer = NULL;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION::Write(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine writes out the changes in the disk buffer
|
||
back out to disk.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
KEVENT event;
|
||
PIRP irp;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
NTSTATUS status;
|
||
|
||
if (!_length) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
if (!_isDiskSuitableForFtOnDisk) {
|
||
ASSERT(FALSE);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, _wholeDisk,
|
||
_diskBuffer, _length, &_byteOffset,
|
||
&event, &ioStatus);
|
||
|
||
if (!irp) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
status = IoCallDriver(_wholeDisk, irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
FtpLogError(GetRootExtension(), QueryDiskNumber(),
|
||
FT_CANT_WRITE_ON_DISK, status, 0);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
FT_LOGICAL_DISK_INFORMATION::AddLogicalDiskDescription(
|
||
IN PFT_LOGICAL_DISK_DESCRIPTION LogicalDiskDescription
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds a new logical disk description at the end of the
|
||
list of logical disk descriptions.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskDescription - Supplies a new logical disk description.
|
||
|
||
Return Value:
|
||
|
||
A pointer into the on disk buffer where the new logical disk
|
||
description was added or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, last;
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
|
||
if (!_length) {
|
||
return NULL;
|
||
}
|
||
|
||
if (!_isDiskSuitableForFtOnDisk) {
|
||
FtpLogError(GetRootExtension(), QueryDiskNumber(), FT_NOT_FT_CAPABLE,
|
||
STATUS_SUCCESS, 0);
|
||
return NULL;
|
||
}
|
||
|
||
last = NULL;
|
||
for (p = GetFirstLogicalDiskDescription(); p;
|
||
p = GetNextLogicalDiskDescription(p)) {
|
||
|
||
last = p;
|
||
}
|
||
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
|
||
if (preamble->FtOnDiskSignature == FT_ON_DISK_SIGNATURE &&
|
||
preamble->DiskDescriptionVersionNumber !=
|
||
FT_ON_DISK_DESCRIPTION_VERSION_NUMBER) {
|
||
|
||
FtpLogError(GetRootExtension(), QueryDiskNumber(), FT_WRONG_VERSION,
|
||
STATUS_SUCCESS, 0);
|
||
return NULL;
|
||
}
|
||
|
||
if (last) {
|
||
p = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
((PCHAR) last + last->DiskDescriptionSize);
|
||
} else {
|
||
|
||
preamble->FtOnDiskSignature = FT_ON_DISK_SIGNATURE;
|
||
preamble->DiskDescriptionVersionNumber =
|
||
FT_ON_DISK_DESCRIPTION_VERSION_NUMBER;
|
||
|
||
preamble->ByteOffsetToFirstFtLogicalDiskDescription =
|
||
sizeof(FT_ON_DISK_PREAMBLE);
|
||
preamble->ByteOffsetToReplaceLog = 0;
|
||
|
||
p = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
((PCHAR) preamble +
|
||
preamble->ByteOffsetToFirstFtLogicalDiskDescription);
|
||
}
|
||
|
||
if ((PCHAR) p - (PCHAR) preamble +
|
||
LogicalDiskDescription->DiskDescriptionSize + sizeof(USHORT) >
|
||
_length) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
ClearReplaceLog();
|
||
|
||
RtlMoveMemory(p, LogicalDiskDescription,
|
||
LogicalDiskDescription->DiskDescriptionSize);
|
||
|
||
last = (PFT_LOGICAL_DISK_DESCRIPTION) ((PCHAR) p + p->DiskDescriptionSize);
|
||
last->DiskDescriptionSize = 0;
|
||
|
||
return p;
|
||
}
|
||
|
||
ULONG
|
||
FT_LOGICAL_DISK_INFORMATION::QueryDiskDescriptionFreeSpace(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the free space for new disk
|
||
descriptions.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
The free space for new disk descriptions.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, last;
|
||
|
||
if (!_length) {
|
||
return 0;
|
||
}
|
||
|
||
if (!_isDiskSuitableForFtOnDisk) {
|
||
FtpLogError(GetRootExtension(), QueryDiskNumber(), FT_NOT_FT_CAPABLE,
|
||
STATUS_SUCCESS, 0);
|
||
return 0;
|
||
}
|
||
|
||
last = NULL;
|
||
for (p = GetFirstLogicalDiskDescription(); p;
|
||
p = GetNextLogicalDiskDescription(p)) {
|
||
|
||
last = p;
|
||
}
|
||
|
||
if (last) {
|
||
return _length - ((ULONG)((PCHAR) last - (PCHAR) _diskBuffer) +
|
||
last->DiskDescriptionSize + sizeof(USHORT));
|
||
} else {
|
||
return _length - sizeof(USHORT) - sizeof(FT_ON_DISK_PREAMBLE);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
FT_LOGICAL_DISK_INFORMATION::DeleteLogicalDiskDescription(
|
||
IN PFT_LOGICAL_DISK_DESCRIPTION LogicalDiskDescription
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes the given logical disk description from the
|
||
logical disk description list.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskDescription - Supplies the logical disk description to
|
||
delete.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, last;
|
||
BOOLEAN exists;
|
||
ULONG moveLength;
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
|
||
exists = FALSE;
|
||
last = NULL;
|
||
for (p = GetFirstLogicalDiskDescription(); p;
|
||
p = GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p == LogicalDiskDescription) {
|
||
exists = TRUE;
|
||
}
|
||
|
||
last = p;
|
||
}
|
||
|
||
if (!exists) {
|
||
ASSERT(FALSE);
|
||
return;
|
||
}
|
||
|
||
moveLength = (ULONG)((PCHAR) last - (PCHAR) LogicalDiskDescription) +
|
||
last->DiskDescriptionSize + sizeof(USHORT) -
|
||
LogicalDiskDescription->DiskDescriptionSize;
|
||
|
||
RtlMoveMemory(LogicalDiskDescription,
|
||
(PCHAR) LogicalDiskDescription +
|
||
LogicalDiskDescription->DiskDescriptionSize,
|
||
moveLength);
|
||
|
||
if (!GetFirstLogicalDiskDescription()) {
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
preamble->FtOnDiskSignature = 0;
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION::AddReplaceLog(
|
||
IN FT_LOGICAL_DISK_ID ReplacedMemberLogicalDiskId,
|
||
IN FT_LOGICAL_DISK_ID NewMemberLogicalDiskId,
|
||
IN ULONG NumberOfChangedDiskIds,
|
||
IN PFT_LOGICAL_DISK_ID OldLogicalDiskIds,
|
||
IN PFT_LOGICAL_DISK_ID NewLogicalDiskIds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds the given replace log to the on disk structure.
|
||
|
||
Arguments:
|
||
|
||
NumberOfChangedDiskIds - Supplies the number of replaced disk ids.
|
||
|
||
OldLogicalDiskIds - Supplies the old logical disk ids.
|
||
|
||
NewLogicalDiskIds - Supplies the new logical disk ids.
|
||
|
||
Return Value:
|
||
|
||
FALSE - Insufficient disk space.
|
||
|
||
TRUE - Success.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, last = NULL;
|
||
PFT_LOGICAL_DISK_ID diskId;
|
||
ULONG offset, freeSpace, i;
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
|
||
for (p = GetFirstLogicalDiskDescription(); p;
|
||
p = GetNextLogicalDiskDescription(p)) {
|
||
|
||
last = p;
|
||
}
|
||
|
||
if (!last) {
|
||
return TRUE;
|
||
}
|
||
|
||
diskId = (PFT_LOGICAL_DISK_ID)
|
||
((ULONG_PTR) ((PCHAR) last + last->DiskDescriptionSize +
|
||
2*sizeof(FT_LOGICAL_DISK_ID))/
|
||
(2*sizeof(FT_LOGICAL_DISK_ID))*
|
||
(2*sizeof(FT_LOGICAL_DISK_ID)));
|
||
|
||
offset = (ULONG) ((PCHAR) diskId - (PCHAR) _diskBuffer);
|
||
freeSpace = _length - offset;
|
||
if (freeSpace <
|
||
2*(NumberOfChangedDiskIds + 2)*sizeof(FT_LOGICAL_DISK_ID)) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
preamble->ByteOffsetToReplaceLog = offset;
|
||
diskId[0] = ReplacedMemberLogicalDiskId;
|
||
diskId[1] = NewMemberLogicalDiskId;
|
||
for (i = 0; i < NumberOfChangedDiskIds; i++) {
|
||
diskId[2*(i + 1)] = OldLogicalDiskIds[i];
|
||
diskId[2*(i + 1) + 1] = NewLogicalDiskIds[i];
|
||
}
|
||
diskId[2*(i + 1)] = 0;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION::ClearReplaceLog(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine clears the replace log.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
if (preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
|
||
preamble->DiskDescriptionVersionNumber !=
|
||
FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
|
||
!preamble->ByteOffsetToReplaceLog) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
preamble->ByteOffsetToReplaceLog = 0;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION::BackOutReplaceOperation(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine backs out the given replace operation.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
FALSE - No change was made to the on disk structures.
|
||
|
||
TRUE - A change was made to the on disk structures.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
PFT_LOGICAL_DISK_ID diskId;
|
||
PFT_LOGICAL_DISK_DESCRIPTION partition;
|
||
FT_LOGICAL_DISK_ID child;
|
||
BOOLEAN needsBackout;
|
||
PFT_LOGICAL_DISK_DESCRIPTION other;
|
||
ULONG i;
|
||
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
if (preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
|
||
preamble->DiskDescriptionVersionNumber !=
|
||
FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
|
||
!preamble->ByteOffsetToReplaceLog) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
diskId = (PFT_LOGICAL_DISK_ID)
|
||
((PCHAR) _diskBuffer + preamble->ByteOffsetToReplaceLog);
|
||
|
||
for (partition = GetFirstLogicalDiskDescription(); partition;
|
||
partition = GetNextLogicalDiskDescription(partition)) {
|
||
|
||
if (partition->LogicalDiskType != FtPartition) {
|
||
continue;
|
||
}
|
||
|
||
child = partition->LogicalDiskId;
|
||
needsBackout = TRUE;
|
||
|
||
for (other = GetNextLogicalDiskDescription(partition); other;
|
||
other = GetNextLogicalDiskDescription(other)) {
|
||
|
||
if (other->LogicalDiskType == FtPartition ||
|
||
other->u.Other.ThisMemberLogicalDiskId != child) {
|
||
|
||
continue;
|
||
}
|
||
|
||
if (child == diskId[1]) {
|
||
needsBackout = FALSE;
|
||
break;
|
||
}
|
||
|
||
child = other->LogicalDiskId;
|
||
}
|
||
|
||
if (!needsBackout) {
|
||
continue;
|
||
}
|
||
|
||
child = partition->LogicalDiskId;
|
||
|
||
for (other = GetNextLogicalDiskDescription(partition); other;
|
||
other = GetNextLogicalDiskDescription(other)) {
|
||
|
||
if (other->LogicalDiskType == FtPartition ||
|
||
other->u.Other.ThisMemberLogicalDiskId != child) {
|
||
|
||
continue;
|
||
}
|
||
|
||
child = other->LogicalDiskId;
|
||
|
||
for (i = 2; diskId[i]; i += 2) {
|
||
if (other->LogicalDiskId == diskId[i + 1]) {
|
||
other->LogicalDiskId = diskId[i];
|
||
} else if (other->u.Other.ThisMemberLogicalDiskId ==
|
||
diskId[i + 1]) {
|
||
|
||
other->u.Other.ThisMemberLogicalDiskId = diskId[i];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
preamble->ByteOffsetToReplaceLog = 0;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION::BackOutReplaceOperationIf(
|
||
IN PFT_LOGICAL_DISK_INFORMATION LogicalDiskInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine backs out the given replace operation on this
|
||
logical disk information if there is evidence from the given
|
||
logical disk information that this logical disk information is
|
||
invalid.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskInformation - Supplies the logical disk information.
|
||
|
||
Return Value:
|
||
|
||
FALSE - No change was made to the on disk structures.
|
||
|
||
TRUE - A change was made to the on disk structures.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
PFT_LOGICAL_DISK_ID diskId;
|
||
ULONG i;
|
||
FT_LOGICAL_DISK_ID oldRootDiskId, replacedDiskId;
|
||
PFT_LOGICAL_DISK_DESCRIPTION partition;
|
||
FT_LOGICAL_DISK_ID child;
|
||
PFT_LOGICAL_DISK_DESCRIPTION other;
|
||
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
if (!preamble ||
|
||
preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
|
||
preamble->DiskDescriptionVersionNumber !=
|
||
FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
|
||
!preamble->ByteOffsetToReplaceLog) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
diskId = (PFT_LOGICAL_DISK_ID)
|
||
((PCHAR) _diskBuffer + preamble->ByteOffsetToReplaceLog);
|
||
|
||
for (i = 0; ; i++) {
|
||
if (!diskId[i]) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
oldRootDiskId = diskId[i - 2];
|
||
replacedDiskId = diskId[0];
|
||
|
||
for (partition = LogicalDiskInformation->GetFirstLogicalDiskDescription();
|
||
partition; partition =
|
||
LogicalDiskInformation->GetNextLogicalDiskDescription(partition)) {
|
||
|
||
if (partition->LogicalDiskType != FtPartition) {
|
||
continue;
|
||
}
|
||
|
||
child = partition->LogicalDiskId;
|
||
|
||
for (other =
|
||
LogicalDiskInformation->GetNextLogicalDiskDescription(partition);
|
||
other; other =
|
||
LogicalDiskInformation->GetNextLogicalDiskDescription(other)) {
|
||
|
||
if (other->LogicalDiskType == FtPartition ||
|
||
other->u.Other.ThisMemberLogicalDiskId != child) {
|
||
|
||
continue;
|
||
}
|
||
|
||
if (child == replacedDiskId) {
|
||
break;
|
||
}
|
||
|
||
child = other->LogicalDiskId;
|
||
}
|
||
|
||
if (child == oldRootDiskId) {
|
||
return BackOutReplaceOperation();
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
ULONGLONG
|
||
FT_LOGICAL_DISK_INFORMATION::GetGptAttributes(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the simulated GPT attribute bits on sector 2 if
|
||
present, otherwise it returns 0.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
GPT attribute bits.
|
||
|
||
--*/
|
||
|
||
{
|
||
GUID* pguid;
|
||
PULONGLONG p;
|
||
|
||
pguid = (GUID*) _diskBuffer;
|
||
if (!pguid) {
|
||
return 0;
|
||
}
|
||
|
||
if (!IsEqualGUID(*pguid, PARTITION_BASIC_DATA_GUID)) {
|
||
return 0;
|
||
}
|
||
|
||
p = (PULONGLONG) ((PCHAR) _diskBuffer + sizeof(GUID));
|
||
|
||
return *p;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION::SetGptAttributes(
|
||
IN ULONGLONG GptAttributes
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the GPT simulated attributes bits on sector 2 of this
|
||
MBR disk.
|
||
|
||
Arguments:
|
||
|
||
GptAttributes - Supplies the GPT attributes.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
LONGLONG offset;
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
GUID* pguid;
|
||
PULONGLONG p;
|
||
|
||
offset = 1024;
|
||
if (offset < _sectorSize) {
|
||
offset = _sectorSize;
|
||
}
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
if (!_diskBuffer || !_isDiskSuitableForFtOnDisk ||
|
||
_byteOffset.QuadPart != offset ||
|
||
preamble->FtOnDiskSignature == FT_ON_DISK_SIGNATURE) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
pguid = (GUID*) _diskBuffer;
|
||
*pguid = PARTITION_BASIC_DATA_GUID;
|
||
p = (PULONGLONG) ((PCHAR) _diskBuffer + sizeof(GUID));
|
||
*p = GptAttributes;
|
||
|
||
return Write();
|
||
}
|
||
|
||
FT_LOGICAL_DISK_INFORMATION::~FT_LOGICAL_DISK_INFORMATION(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the destructor for this class.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (_wholeDisk != _wholeDiskPdo) {
|
||
ObDereferenceObject(_wholeDisk);
|
||
}
|
||
if (_diskBuffer) {
|
||
ExFreePool(_diskBuffer);
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::Initialize(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the class for use.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
_numberOfLogicalDiskInformations = 0;
|
||
_arrayOfLogicalDiskInformations = NULL;
|
||
_numberOfRootLogicalDisksIds = 0;
|
||
_arrayOfRootLogicalDiskIds = NULL;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::AddLogicalDiskInformation(
|
||
IN PFT_LOGICAL_DISK_INFORMATION LogicalDiskInformation,
|
||
OUT PBOOLEAN ChangedLogicalDiskIds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds a logical disk information structure to this
|
||
set of logical disk information structures.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskInformation - Supplies the disk information to add.
|
||
|
||
ChangedLogicalDiskIds - Returns whether or not any existing logical
|
||
disk ids have changed.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PDRIVE_LAYOUT_INFORMATION_EX layout;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, q, r;
|
||
ULONG numEntries, i, j;
|
||
PFT_LOGICAL_DISK_INFORMATION* n;
|
||
BOOLEAN error;
|
||
PPARTITION_INFORMATION_EX partInfo;
|
||
ULONG configLength, stateLength;
|
||
PCHAR pc, qc;
|
||
ULONG uniqueError;
|
||
|
||
if (ChangedLogicalDiskIds) {
|
||
*ChangedLogicalDiskIds = FALSE;
|
||
}
|
||
|
||
|
||
// Check for any partial replace operations that need to be backed out.
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
if (_arrayOfLogicalDiskInformations[i]->BackOutReplaceOperationIf(
|
||
LogicalDiskInformation)) {
|
||
|
||
_arrayOfLogicalDiskInformations[i]->Write();
|
||
|
||
if (ChangedLogicalDiskIds) {
|
||
*ChangedLogicalDiskIds = TRUE;
|
||
}
|
||
}
|
||
|
||
if (LogicalDiskInformation->BackOutReplaceOperationIf(
|
||
_arrayOfLogicalDiskInformations[i])) {
|
||
|
||
LogicalDiskInformation->Write();
|
||
}
|
||
}
|
||
|
||
|
||
// Read in the partition table for future reference.
|
||
|
||
status = FtpReadPartitionTableEx(LogicalDiskInformation->GetWholeDisk(),
|
||
&layout);
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
|
||
// First count how many entries are in the given list and also perform
|
||
// a sanity check on these entries.
|
||
|
||
numEntries = 0;
|
||
for (p = LogicalDiskInformation->GetFirstLogicalDiskDescription(); p; ) {
|
||
|
||
if (!p->DiskDescriptionSize) {
|
||
break;
|
||
}
|
||
|
||
error = FALSE;
|
||
|
||
if (p->DiskDescriptionSize < sizeof(FT_LOGICAL_DISK_DESCRIPTION) ||
|
||
p->LogicalDiskId == 0) {
|
||
|
||
DbgPrint("Disk Description too small, %x, or no logical disk id %I64x\n",
|
||
p->DiskDescriptionSize, p->LogicalDiskId);
|
||
error = TRUE;
|
||
uniqueError = 1;
|
||
}
|
||
|
||
if (!error && p->LogicalDiskType == FtPartition) {
|
||
|
||
for (i = 0; i < layout->PartitionCount; i++) {
|
||
partInfo = &layout->PartitionEntry[i];
|
||
if (partInfo->StartingOffset.QuadPart ==
|
||
p->u.FtPartition.ByteOffset &&
|
||
(partInfo->Mbr.PartitionType&0x80)) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == layout->PartitionCount) {
|
||
error = TRUE;
|
||
uniqueError = 2;
|
||
DbgPrint("Partition not found in partition table.\n");
|
||
DbgPrint("Partition start = %I64x\n", p->u.FtPartition.ByteOffset);
|
||
DbgPrint("Drive layout partition count = %d\n", layout->PartitionCount);
|
||
} else if (GetLogicalDiskDescription(p->LogicalDiskId, 0)) {
|
||
error = TRUE;
|
||
uniqueError = 3;
|
||
DbgPrint("Duplicate logical disk description on other disk: %I64x\n",
|
||
p->LogicalDiskId);
|
||
} else {
|
||
|
||
for (q = LogicalDiskInformation->GetFirstLogicalDiskDescription();
|
||
q != p;
|
||
q = LogicalDiskInformation->GetNextLogicalDiskDescription(q)) {
|
||
|
||
if (p->LogicalDiskId == q->LogicalDiskId) {
|
||
error = TRUE;
|
||
uniqueError = 4;
|
||
DbgPrint("Duplicate logical disk description on same disk: %I64x\n",
|
||
p->LogicalDiskId);
|
||
} else if (q->LogicalDiskType == FtPartition &&
|
||
p->u.FtPartition.ByteOffset ==
|
||
q->u.FtPartition.ByteOffset) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 100;
|
||
DbgPrint("%I64x and %I64x are FtPartitions pointing to offset %x\n",
|
||
p->LogicalDiskId, q->LogicalDiskId,
|
||
p->u.FtPartition.ByteOffset);
|
||
}
|
||
}
|
||
}
|
||
|
||
} else if (!error) {
|
||
|
||
for (q = LogicalDiskInformation->GetFirstLogicalDiskDescription();
|
||
q != p;
|
||
q = LogicalDiskInformation->GetNextLogicalDiskDescription(q)) {
|
||
|
||
if (p->u.Other.ThisMemberLogicalDiskId == q->LogicalDiskId) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p == q) {
|
||
error = TRUE;
|
||
uniqueError = 5;
|
||
DbgPrint("This member logical disk id not found %I64x\n",
|
||
p->u.Other.ThisMemberLogicalDiskId);
|
||
}
|
||
|
||
if (p->u.Other.ThisMemberNumber >= p->u.Other.NumberOfMembers) {
|
||
error = TRUE;
|
||
uniqueError = 6;
|
||
DbgPrint("This member number %d >= number of members %d\n",
|
||
p->u.Other.ThisMemberNumber, p->u.Other.NumberOfMembers);
|
||
}
|
||
|
||
if (p->u.Other.ThisMemberLogicalDiskId == p->LogicalDiskId) {
|
||
error = TRUE;
|
||
uniqueError = 7;
|
||
DbgPrint("This member logical disk == logical disk == %I64x\n",
|
||
p->LogicalDiskId);
|
||
}
|
||
|
||
if (p->u.Other.ByteOffsetToConfigurationInformation &&
|
||
p->u.Other.ByteOffsetToConfigurationInformation <
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 8;
|
||
DbgPrint("Byte offset to config info too small: %d\n",
|
||
p->u.Other.ByteOffsetToConfigurationInformation);
|
||
}
|
||
|
||
if (p->u.Other.ByteOffsetToStateInformation &&
|
||
p->u.Other.ByteOffsetToStateInformation <
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 9;
|
||
DbgPrint("Byte offset to state info too small: %d\n",
|
||
p->u.Other.ByteOffsetToStateInformation);
|
||
}
|
||
|
||
if (p->u.Other.ByteOffsetToConfigurationInformation &&
|
||
p->u.Other.ByteOffsetToStateInformation &&
|
||
p->u.Other.ByteOffsetToConfigurationInformation >=
|
||
p->u.Other.ByteOffsetToStateInformation) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 10;
|
||
DbgPrint("Config info %d past state info %d\n",
|
||
p->u.Other.ByteOffsetToConfigurationInformation,
|
||
p->u.Other.ByteOffsetToStateInformation);
|
||
}
|
||
|
||
if (p->u.Other.ByteOffsetToConfigurationInformation >=
|
||
p->DiskDescriptionSize) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 11;
|
||
DbgPrint("Byte offset to config info too large: %d vs. %d\n",
|
||
p->u.Other.ByteOffsetToConfigurationInformation,
|
||
p->DiskDescriptionSize);
|
||
}
|
||
|
||
if (p->u.Other.ByteOffsetToStateInformation >=
|
||
p->DiskDescriptionSize) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 12;
|
||
DbgPrint("Byte offset to state info too large: %d vs. %d\n",
|
||
p->u.Other.ByteOffsetToStateInformation,
|
||
p->DiskDescriptionSize);
|
||
}
|
||
|
||
if (!error && p->u.Other.ByteOffsetToConfigurationInformation) {
|
||
if (p->u.Other.ByteOffsetToStateInformation) {
|
||
configLength = p->u.Other.ByteOffsetToStateInformation -
|
||
p->u.Other.ByteOffsetToConfigurationInformation;
|
||
} else {
|
||
configLength = p->DiskDescriptionSize -
|
||
p->u.Other.ByteOffsetToConfigurationInformation;
|
||
}
|
||
|
||
switch (p->LogicalDiskType) {
|
||
case FtStripeSet:
|
||
if (configLength <
|
||
sizeof(FT_STRIPE_SET_CONFIGURATION_INFORMATION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 13;
|
||
DbgPrint("Stripe config too small: %d\n",
|
||
configLength);
|
||
}
|
||
break;
|
||
|
||
case FtMirrorSet:
|
||
if (configLength <
|
||
sizeof(FT_MIRROR_SET_CONFIGURATION_INFORMATION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 14;
|
||
DbgPrint("Mirror config too small: %d\n",
|
||
configLength);
|
||
}
|
||
break;
|
||
|
||
case FtStripeSetWithParity:
|
||
if (configLength <
|
||
sizeof(FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 15;
|
||
DbgPrint("SWP config too small: %d\n",
|
||
configLength);
|
||
}
|
||
break;
|
||
|
||
case FtRedistribution:
|
||
if (configLength <
|
||
sizeof(FT_REDISTRIBUTION_CONFIGURATION_INFORMATION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 16;
|
||
DbgPrint("Redistrubution config too small: %d\n",
|
||
configLength);
|
||
}
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
|
||
if (!error && p->u.Other.ByteOffsetToStateInformation) {
|
||
stateLength = p->DiskDescriptionSize -
|
||
p->u.Other.ByteOffsetToStateInformation;
|
||
|
||
switch (p->LogicalDiskType) {
|
||
case FtMirrorSet:
|
||
case FtStripeSetWithParity:
|
||
if (stateLength <
|
||
sizeof(FT_MIRROR_AND_SWP_STATE_INFORMATION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 17;
|
||
DbgPrint("State too small: %d\n", stateLength);
|
||
}
|
||
break;
|
||
|
||
case FtRedistribution:
|
||
if (stateLength <
|
||
sizeof(FT_REDISTRIBUTION_STATE_INFORMATION)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 18;
|
||
DbgPrint("Redist State too small: %d\n", stateLength);
|
||
}
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
if (error) {
|
||
q = NULL;
|
||
} else {
|
||
if (!(q = GetLogicalDiskDescription(p->LogicalDiskId, 0))) {
|
||
|
||
for (q = LogicalDiskInformation->GetFirstLogicalDiskDescription();
|
||
q != p;
|
||
q = LogicalDiskInformation->GetNextLogicalDiskDescription(q)) {
|
||
|
||
if (q->LogicalDiskId == p->LogicalDiskId) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (q == p) {
|
||
q = NULL;
|
||
}
|
||
|
||
if (q) {
|
||
for (r = q; r != p;
|
||
r = LogicalDiskInformation->
|
||
GetNextLogicalDiskDescription(r)) {
|
||
|
||
if (r->LogicalDiskId == p->LogicalDiskId) {
|
||
if (p->u.Other.ThisMemberNumber ==
|
||
r->u.Other.ThisMemberNumber ||
|
||
p->u.Other.ThisMemberLogicalDiskId ==
|
||
r->u.Other.ThisMemberLogicalDiskId) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 19;
|
||
DbgPrint("Matching logical disks %I64x\n",
|
||
p->LogicalDiskId);
|
||
DbgPrint("have same member number %d, %d\n",
|
||
p->u.Other.ThisMemberNumber,
|
||
r->u.Other.ThisMemberNumber);
|
||
DbgPrint("or same member disk id %I64x, %I64x\n",
|
||
p->u.Other.ThisMemberLogicalDiskId,
|
||
r->u.Other.ThisMemberLogicalDiskId);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (q) {
|
||
if (p->DiskDescriptionSize != q->DiskDescriptionSize ||
|
||
p->LogicalDiskType != q->LogicalDiskType ||
|
||
p->u.Other.NumberOfMembers !=
|
||
q->u.Other.NumberOfMembers ||
|
||
p->u.Other.ByteOffsetToConfigurationInformation !=
|
||
q->u.Other.ByteOffsetToConfigurationInformation ||
|
||
p->u.Other.ByteOffsetToStateInformation !=
|
||
q->u.Other.ByteOffsetToStateInformation) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 20;
|
||
DbgPrint("Matching logical disks %I64x\n", p->LogicalDiskId);
|
||
DbgPrint("have different description size %d, %d\n",
|
||
p->DiskDescriptionSize, q->DiskDescriptionSize);
|
||
DbgPrint("or different logical disk type %d, %d\n",
|
||
p->LogicalDiskType, q->LogicalDiskType);
|
||
DbgPrint("or different number of members %d, %d\n",
|
||
p->u.Other.NumberOfMembers, q->u.Other.NumberOfMembers);
|
||
DbgPrint("or different offsets to config %d, %d\n",
|
||
p->u.Other.ByteOffsetToConfigurationInformation,
|
||
q->u.Other.ByteOffsetToConfigurationInformation);
|
||
DbgPrint("or different offsets to state %d, %d\n",
|
||
p->u.Other.ByteOffsetToStateInformation,
|
||
q->u.Other.ByteOffsetToStateInformation);
|
||
}
|
||
|
||
if (!error &&
|
||
p->u.Other.ByteOffsetToConfigurationInformation) {
|
||
|
||
pc = (PCHAR) p +
|
||
p->u.Other.ByteOffsetToConfigurationInformation;
|
||
qc = (PCHAR) q +
|
||
q->u.Other.ByteOffsetToConfigurationInformation;
|
||
|
||
if (RtlCompareMemory(pc, qc, configLength) !=
|
||
configLength) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 21;
|
||
DbgPrint("Matching logical disks %I64x\n",
|
||
p->LogicalDiskId);
|
||
DbgPrint("have different configuration information\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!error) {
|
||
|
||
for (i = 0; q = GetLogicalDiskDescription(p->LogicalDiskId, i);
|
||
i++) {
|
||
|
||
if (q->u.Other.ThisMemberLogicalDiskId ==
|
||
p->u.Other.ThisMemberLogicalDiskId &&
|
||
q->u.Other.ThisMemberNumber !=
|
||
p->u.Other.ThisMemberNumber) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 22;
|
||
DbgPrint("Different members map to the same disk\n");
|
||
DbgPrint("--- %I64x, member %d and member %d\n",
|
||
p->u.Other.ThisMemberLogicalDiskId,
|
||
q->u.Other.ThisMemberNumber,
|
||
p->u.Other.ThisMemberNumber);
|
||
}
|
||
|
||
if (q->u.Other.ThisMemberNumber ==
|
||
p->u.Other.ThisMemberNumber &&
|
||
q->u.Other.ThisMemberLogicalDiskId !=
|
||
p->u.Other.ThisMemberLogicalDiskId) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 23;
|
||
DbgPrint("Member %d of %I64x is defined twice.\n",
|
||
q->u.Other.ThisMemberNumber,
|
||
p->LogicalDiskId);
|
||
DbgPrint("---- once as %I64x and then as %I64x.\n",
|
||
q->u.Other.ThisMemberLogicalDiskId,
|
||
p->u.Other.ThisMemberLogicalDiskId);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!error) {
|
||
|
||
q = GetParentLogicalDiskDescription(p->LogicalDiskId);
|
||
for (r = LogicalDiskInformation->
|
||
GetNextLogicalDiskDescription(p); r;
|
||
r = LogicalDiskInformation->
|
||
GetNextLogicalDiskDescription(r)) {
|
||
|
||
if (r->LogicalDiskType != FtPartition &&
|
||
r->u.Other.ThisMemberLogicalDiskId ==
|
||
p->LogicalDiskId) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (q) {
|
||
|
||
if (!r) {
|
||
|
||
// The set indicates that p->LogicalDiskId has a parent
|
||
// but this logical disk information does not have a
|
||
// parent. Therefore, add a parent to match.
|
||
|
||
LogicalDiskInformation->AddLogicalDiskDescription(q);
|
||
LogicalDiskInformation->Write();
|
||
|
||
} else if (q->LogicalDiskId != r->LogicalDiskId ||
|
||
q->u.Other.ThisMemberNumber !=
|
||
r->u.Other.ThisMemberNumber) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 24;
|
||
DbgPrint("No parent on this disk info for %I64x\n",
|
||
p->LogicalDiskId);
|
||
}
|
||
|
||
} else if (r && GetLogicalDiskDescription(p->LogicalDiskId, 0)) {
|
||
|
||
error = TRUE;
|
||
uniqueError = 25;
|
||
DbgPrint("Parent on this disk info that doesn't exist\n");
|
||
DbgPrint("in the set. %I64x\n", p->LogicalDiskId,
|
||
r->LogicalDiskId);
|
||
}
|
||
}
|
||
|
||
if (error) {
|
||
|
||
FtpLogError(LogicalDiskInformation->GetRootExtension(),
|
||
LogicalDiskInformation->QueryDiskNumber(),
|
||
FT_CORRUPT_DISK_DESCRIPTION, STATUS_SUCCESS,
|
||
uniqueError);
|
||
|
||
DbgPrint("Deleting logical disk description %I64x\n",
|
||
p->LogicalDiskId);
|
||
DbgPrint("Description size = %d\n", p->DiskDescriptionSize);
|
||
DbgPrint("Disk type = %d\n", p->LogicalDiskType);
|
||
if (p->LogicalDiskType == FtPartition) {
|
||
DbgPrint("Byte offset = %I64x\n", p->u.FtPartition.ByteOffset);
|
||
} else {
|
||
DbgPrint("This member = %I64x\n", p->u.Other.ThisMemberLogicalDiskId);
|
||
DbgPrint("This member number = %d\n", p->u.Other.ThisMemberNumber);
|
||
DbgPrint("Number of members = %d\n", p->u.Other.NumberOfMembers);
|
||
DbgPrint("Offset to config = %d\n", p->u.Other.ByteOffsetToConfigurationInformation);
|
||
DbgPrint("Offset to state = %d\n", p->u.Other.ByteOffsetToStateInformation);
|
||
}
|
||
|
||
LogicalDiskInformation->DeleteLogicalDiskDescription(p);
|
||
LogicalDiskInformation->Write();
|
||
} else {
|
||
p = LogicalDiskInformation->GetNextLogicalDiskDescription(p);
|
||
numEntries++;
|
||
}
|
||
}
|
||
|
||
ExFreePool(layout);
|
||
|
||
|
||
// Realloc the logical disk informations array.
|
||
|
||
n = (PFT_LOGICAL_DISK_INFORMATION*)
|
||
ExAllocatePool(NonPagedPool, sizeof(PFT_LOGICAL_DISK_INFORMATION)*
|
||
(_numberOfLogicalDiskInformations + 1));
|
||
if (!n) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
if (_numberOfLogicalDiskInformations) {
|
||
RtlMoveMemory(n, _arrayOfLogicalDiskInformations,
|
||
sizeof(PFT_LOGICAL_DISK_INFORMATION)*
|
||
_numberOfLogicalDiskInformations);
|
||
ExFreePool(_arrayOfLogicalDiskInformations);
|
||
}
|
||
_arrayOfLogicalDiskInformations = n;
|
||
|
||
|
||
// Realloc the root array so that it is at least large enough.
|
||
|
||
if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + numEntries)) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
// Now add the logical disk information to this list.
|
||
|
||
_arrayOfLogicalDiskInformations[_numberOfLogicalDiskInformations++] =
|
||
LogicalDiskInformation;
|
||
|
||
|
||
// Recompute the list of root disk ids.
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::RemoveLogicalDiskInformation(
|
||
IN OUT PDEVICE_OBJECT WholeDiskPdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine removes the logical disk information associated with the
|
||
given whole disk device object from the disk information set.
|
||
|
||
Arguments:
|
||
|
||
WholeDiskPdo - Supplies the device object.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->GetWholeDiskPdo() == WholeDiskPdo) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfLogicalDiskInformations) {
|
||
return STATUS_NOT_FOUND;
|
||
}
|
||
|
||
_numberOfLogicalDiskInformations--;
|
||
|
||
RtlMoveMemory(&_arrayOfLogicalDiskInformations[i],
|
||
&_arrayOfLogicalDiskInformations[i + 1],
|
||
(_numberOfLogicalDiskInformations - i)*
|
||
sizeof(PFT_LOGICAL_DISK_INFORMATION));
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
delete diskInfo;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION_SET::IsDiskInSet(
|
||
IN OUT PDEVICE_OBJECT WholeDiskPdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine removes the logical disk information associated with the
|
||
given whole disk device object from the disk information set.
|
||
|
||
Arguments:
|
||
|
||
WholeDiskPdo - Supplies the device object.
|
||
|
||
Return Value:
|
||
|
||
FALSE - The PDO is not in the set.
|
||
|
||
TRUE - The PDO is in the set.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->GetWholeDiskPdo() == WholeDiskPdo) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
FT_LOGICAL_DISK_INFORMATION_SET::GetLogicalDiskDescription(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
IN ULONG InstanceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the logical disk description for the given
|
||
instance number and logical disk id.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
InstanceNumber - Supplies the instance number.
|
||
|
||
Return Value:
|
||
|
||
A logical disk decription.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, instanceNumber;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
instanceNumber = 0;
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == LogicalDiskId) {
|
||
if (InstanceNumber == instanceNumber) {
|
||
return p;
|
||
} else {
|
||
instanceNumber++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
ULONG
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryNumberOfRootLogicalDiskIds(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the number of root logical disk ids.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
The number of root logical disk ids.
|
||
|
||
--*/
|
||
|
||
{
|
||
return _numberOfRootLogicalDisksIds;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_ID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryRootLogicalDiskId(
|
||
IN ULONG Index
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the 'Index'th root logical disk id.
|
||
|
||
Arguments:
|
||
|
||
Index - Supplies the 0 based index.
|
||
|
||
Return Value:
|
||
|
||
The 'Index'th root logical disk id.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (Index >= _numberOfRootLogicalDisksIds) {
|
||
return 0;
|
||
}
|
||
|
||
return _arrayOfRootLogicalDiskIds[Index];
|
||
}
|
||
|
||
FT_LOGICAL_DISK_ID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryRootLogicalDiskIdForContainedPartition(
|
||
IN ULONG DiskNumber,
|
||
IN LONGLONG Offset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the root logical disk id of the logical disk that
|
||
contains the given partition.
|
||
|
||
Arguments:
|
||
|
||
DiskNumber - Supplies the disk number of the whole disk
|
||
of the partition.
|
||
|
||
Offset - Supplies the offset of the partition.
|
||
|
||
Return Value:
|
||
|
||
The logical disk id of the root disk containing the given partition or 0.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
FT_LOGICAL_DISK_ID id;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->QueryDiskNumber() == DiskNumber) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfLogicalDiskInformations) {
|
||
return 0;
|
||
}
|
||
|
||
id = 0;
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (id) {
|
||
if (p->LogicalDiskType != FtPartition &&
|
||
p->u.Other.ThisMemberLogicalDiskId == id) {
|
||
|
||
id = p->LogicalDiskId;
|
||
}
|
||
} else {
|
||
if (p->LogicalDiskType == FtPartition &&
|
||
p->u.FtPartition.ByteOffset == Offset) {
|
||
|
||
id = p->LogicalDiskId;
|
||
}
|
||
}
|
||
}
|
||
|
||
return id;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_ID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryPartitionLogicalDiskId(
|
||
IN ULONG DiskNumber,
|
||
IN LONGLONG Offset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the logical disk id for the given partition.
|
||
|
||
Arguments:
|
||
|
||
DiskNumber - Supplies the disk number of the whole disk
|
||
of the partition.
|
||
|
||
Offset - Supplies the offset of the partition.
|
||
|
||
Return Value:
|
||
|
||
A logical disk id or 0.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->QueryDiskNumber() == DiskNumber) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfLogicalDiskInformations) {
|
||
return 0;
|
||
}
|
||
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskType == FtPartition &&
|
||
p->u.FtPartition.ByteOffset == Offset) {
|
||
|
||
return p->LogicalDiskId;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
USHORT
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryNumberOfMembersInLogicalDisk(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the number of members in a logical disk.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
The number of members in a logical disk.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
p = GetLogicalDiskDescription(LogicalDiskId, 0);
|
||
if (!p) {
|
||
ASSERT(FALSE);
|
||
return 0;
|
||
}
|
||
|
||
if (p->LogicalDiskType == FtPartition) {
|
||
return 0;
|
||
}
|
||
|
||
return p->u.Other.NumberOfMembers;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_ID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryMemberLogicalDiskId(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
IN USHORT MemberNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the logical disk id for the given member number.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
MemberNumber - Supplies the requested member number.
|
||
|
||
Return Value:
|
||
|
||
The logical disk id of the given member number.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == LogicalDiskId) {
|
||
ASSERT(p->LogicalDiskType != FtPartition);
|
||
if (p->u.Other.ThisMemberNumber == MemberNumber) {
|
||
return p->u.Other.ThisMemberLogicalDiskId;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_TYPE
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryLogicalDiskType(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the logical disk type for the given logical disk
|
||
id.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
The logical disk type for the given logical disk id.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
p = GetLogicalDiskDescription(LogicalDiskId, 0);
|
||
if (!p) {
|
||
ASSERT(FALSE);
|
||
return FtPartition;
|
||
}
|
||
|
||
return p->LogicalDiskType;
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryFtPartitionInformation(
|
||
IN FT_LOGICAL_DISK_ID PartitionLogicalDiskId,
|
||
OUT PLONGLONG Offset,
|
||
OUT PDEVICE_OBJECT* WholeDisk,
|
||
OUT PULONG DiskNumber,
|
||
OUT PULONG SectorSize,
|
||
OUT PLONGLONG PartitionSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns information about the given partition.
|
||
|
||
Arguments:
|
||
|
||
PartitionLogicalDiskId - Supplies the logical disk id.
|
||
|
||
Offset - Returns the partition offset.
|
||
|
||
WholeDisk - Returns the whole disk device object.
|
||
|
||
DiskNumber - Returns the disk number.
|
||
|
||
SectorSize - Returns the sector size.
|
||
|
||
PartitionSize - Returns the partition size.
|
||
|
||
Return Value:
|
||
|
||
FALSE - Failure.
|
||
|
||
TRUE - Success.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, instanceNumber;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
instanceNumber = 0;
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == PartitionLogicalDiskId) {
|
||
if (p->LogicalDiskType != FtPartition) {
|
||
return FALSE;
|
||
}
|
||
if (Offset) {
|
||
*Offset = p->u.FtPartition.ByteOffset;
|
||
}
|
||
if (WholeDisk) {
|
||
*WholeDisk = diskInfo->GetWholeDisk();
|
||
}
|
||
if (DiskNumber) {
|
||
*DiskNumber = diskInfo->QueryDiskNumber();
|
||
}
|
||
if (SectorSize) {
|
||
*SectorSize = diskInfo->QuerySectorSize();
|
||
}
|
||
if (PartitionSize) {
|
||
*PartitionSize = p->u.FtPartition.PartitionSize;
|
||
}
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
PVOID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::GetConfigurationInformation(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a pointer to the configuration information
|
||
for the given logical disk.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the configuration information for the given logical disk.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
p = GetLogicalDiskDescription(LogicalDiskId, 0);
|
||
if (!p) {
|
||
ASSERT(FALSE);
|
||
return NULL;
|
||
}
|
||
|
||
if (p->LogicalDiskType == FtPartition) {
|
||
ASSERT(FALSE);
|
||
return NULL;
|
||
}
|
||
|
||
if (!p->u.Other.ByteOffsetToConfigurationInformation) {
|
||
return NULL;
|
||
}
|
||
|
||
return ((PCHAR) p + p->u.Other.ByteOffsetToConfigurationInformation);
|
||
}
|
||
|
||
PVOID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::GetStateInformation(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a pointer to the state information
|
||
for the given logical disk.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the state information for the given logical disk.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
p = GetLogicalDiskDescription(LogicalDiskId, 0);
|
||
if (!p) {
|
||
ASSERT(FALSE);
|
||
return NULL;
|
||
}
|
||
|
||
if (p->LogicalDiskType == FtPartition ||
|
||
!p->u.Other.ByteOffsetToStateInformation) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
return ((PCHAR) p + p->u.Other.ByteOffsetToStateInformation);
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION_SET::IsLogicalDiskComplete(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine computes whether or not a given logical disk is
|
||
complete. In other words, whether or not it has all of its members
|
||
and its members' members etc...
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
FALSE - This logical disk is not complete.
|
||
|
||
TRUE - This logical disk is complete.
|
||
|
||
--*/
|
||
|
||
{
|
||
USHORT numMembers, i;
|
||
FT_LOGICAL_DISK_ID memberDiskId;
|
||
|
||
numMembers = QueryNumberOfMembersInLogicalDisk(LogicalDiskId);
|
||
for (i = 0; i < numMembers; i++) {
|
||
memberDiskId = QueryMemberLogicalDiskId(LogicalDiskId, i);
|
||
if (!memberDiskId || !IsLogicalDiskComplete(memberDiskId)) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
UCHAR
|
||
FT_LOGICAL_DISK_INFORMATION_SET::QueryDriveLetter(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the drive letter for the given logical disk.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
The drive letter or 0.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
p = GetLogicalDiskDescription(LogicalDiskId, 0);
|
||
if (!p) {
|
||
return 0;
|
||
}
|
||
|
||
return p->DriveLetter;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::SetDriveLetter(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
IN UCHAR DriveLetter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the drive letter for the given logical disk.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
DriveLetter - Supplies the drive letter.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
BOOLEAN found;
|
||
|
||
found = FALSE;
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == LogicalDiskId) {
|
||
p->DriveLetter = DriveLetter;
|
||
diskInfo->Write();
|
||
found = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return found ? STATUS_SUCCESS : STATUS_OBJECT_NAME_NOT_FOUND;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::WriteStateInformation(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
IN PVOID LogicalDiskState,
|
||
IN USHORT LogicalDiskStateSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine writes out the given state information to all on
|
||
disk instances of the given logical disk. If one of the instances
|
||
fails to commit to disk, this routine will continue to write out
|
||
all that it can and then return the error that it received.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
LogicalDiskState - Supplies the logical disk state to write.
|
||
|
||
LogicalDiskStateSize - Supplies the number of bytes in the given
|
||
logical disk state.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == LogicalDiskId) {
|
||
ASSERT(p->LogicalDiskType != FtPartition);
|
||
ASSERT(p->u.Other.ByteOffsetToStateInformation);
|
||
|
||
RtlMoveMemory((PCHAR) p +
|
||
p->u.Other.ByteOffsetToStateInformation,
|
||
LogicalDiskState,
|
||
LogicalDiskStateSize);
|
||
|
||
diskInfo->Write();
|
||
}
|
||
}
|
||
}
|
||
|
||
FtpCopyStateToRegistry(LogicalDiskId, LogicalDiskState,
|
||
LogicalDiskStateSize);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_ID
|
||
GenerateNewLogicalDiskId(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine computes a new, random, unique, logical disk id for
|
||
use to identify a new logical disk.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A new logical disk id.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
UUID uuid;
|
||
PUCHAR p;
|
||
FT_LOGICAL_DISK_ID diskId;
|
||
static LARGE_INTEGER lastSystemTime;
|
||
LARGE_INTEGER x;
|
||
ULONG i;
|
||
|
||
status = ExUuidCreate(&uuid);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
p = (PUCHAR) &uuid;
|
||
diskId = (*((PFT_LOGICAL_DISK_ID) p)) ^
|
||
(*((PFT_LOGICAL_DISK_ID) (p + sizeof(FT_LOGICAL_DISK_ID))));
|
||
|
||
return diskId;
|
||
}
|
||
|
||
x.QuadPart = 0;
|
||
while (x.QuadPart == 0) {
|
||
for (;;) {
|
||
KeQuerySystemTime(&x);
|
||
if (x.QuadPart != lastSystemTime.QuadPart) {
|
||
break;
|
||
}
|
||
}
|
||
lastSystemTime.QuadPart = x.QuadPart;
|
||
p = (PUCHAR) &x.QuadPart;
|
||
for (i = 0; i < sizeof(LONGLONG); i++) {
|
||
x.QuadPart += *p++;
|
||
x.QuadPart = (x.QuadPart >> 2) + (x.QuadPart << 62);
|
||
}
|
||
}
|
||
|
||
return x.QuadPart;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::CreatePartitionLogicalDisk(
|
||
IN ULONG DiskNumber,
|
||
IN LONGLONG PartitionOffset,
|
||
IN LONGLONG PartitionSize,
|
||
OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a DOS partition and assigns it a logical disk id.
|
||
|
||
Arguments:
|
||
|
||
DiskNumber - Supplies the disk number where the partition
|
||
resides.
|
||
|
||
PartitionOffset - Supplies the partition offset.
|
||
|
||
PartitionSize - Supplies the partition size.
|
||
|
||
NewLogicalDiskId - Returns the logical disk id.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION newLogicalDiskDescription, p;
|
||
NTSTATUS status;
|
||
|
||
// Find the disk information for the given device object.
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->QueryDiskNumber() == DiskNumber) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfLogicalDiskInformations) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
// Generate a new logical disk id for this one.
|
||
|
||
*NewLogicalDiskId = GenerateNewLogicalDiskId();
|
||
|
||
|
||
// Allocate and set up a new logical disk description.
|
||
|
||
newLogicalDiskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
ExAllocatePool(PagedPool, sizeof(FT_LOGICAL_DISK_DESCRIPTION));
|
||
if (!newLogicalDiskDescription) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
newLogicalDiskDescription->DiskDescriptionSize =
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION);
|
||
newLogicalDiskDescription->DriveLetter = 0;
|
||
newLogicalDiskDescription->Reserved = 0;
|
||
newLogicalDiskDescription->LogicalDiskType = FtPartition;
|
||
newLogicalDiskDescription->LogicalDiskId = *NewLogicalDiskId;
|
||
newLogicalDiskDescription->u.FtPartition.ByteOffset = PartitionOffset;
|
||
newLogicalDiskDescription->u.FtPartition.PartitionSize = PartitionSize;
|
||
|
||
|
||
// Check for enough free disk space.
|
||
|
||
if (newLogicalDiskDescription->DiskDescriptionSize >
|
||
diskInfo->QueryDiskDescriptionFreeSpace()) {
|
||
|
||
FtpLogError(diskInfo->GetRootExtension(),
|
||
diskInfo->QueryDiskNumber(),
|
||
FT_NOT_ENOUGH_ON_DISK_SPACE, STATUS_DISK_FULL, 0);
|
||
|
||
ExFreePool(newLogicalDiskDescription);
|
||
return STATUS_DISK_FULL;
|
||
}
|
||
|
||
|
||
// Now allocate the memory that we need to store this new logical
|
||
// disk.
|
||
|
||
if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
|
||
ExFreePool(newLogicalDiskDescription);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
// Write out the disk description.
|
||
|
||
p = diskInfo->AddLogicalDiskDescription(newLogicalDiskDescription);
|
||
ASSERT(p);
|
||
|
||
ExFreePool(newLogicalDiskDescription);
|
||
|
||
status = diskInfo->Write();
|
||
if (!NT_SUCCESS(status)) {
|
||
BreakLogicalDisk(*NewLogicalDiskId);
|
||
return status;
|
||
}
|
||
|
||
|
||
// Fix up the list of root entries.
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::AddNewLogicalDisk(
|
||
IN FT_LOGICAL_DISK_TYPE NewLogicalDiskType,
|
||
IN USHORT NumberOfMembers,
|
||
IN PFT_LOGICAL_DISK_ID ArrayOfMembers,
|
||
IN USHORT ConfigurationInformationSize,
|
||
IN PVOID ConfigurationInformation,
|
||
IN USHORT StateInformationSize,
|
||
IN PVOID StateInformation,
|
||
OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds the given logical disk to the system.
|
||
|
||
Arguments:
|
||
|
||
NewLogicalDiskType - Supplies the logical disk type of the
|
||
new logical disk.
|
||
|
||
NumberOfMembers - Supplies the number of members contained
|
||
in the new logical disk.
|
||
|
||
ArrayOfMembers - Supplies the array of members.
|
||
|
||
ConfigurationInformationSize - Supplies the configuration information
|
||
size.
|
||
|
||
ConfigurationInformation - Supplies the configuration information.
|
||
|
||
StateInformationSize - Supplies the state information size.
|
||
|
||
StateInformation - Supplies the state information.
|
||
|
||
NewLogicalDiskId - Returns the new logical disk id.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, j;
|
||
USHORT size;
|
||
UCHAR driveLetter;
|
||
PFT_LOGICAL_DISK_DESCRIPTION newLogicalDiskDescription;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, q;
|
||
NTSTATUS status;
|
||
ULONG numInstancesInThisInfo;
|
||
WCHAR name[3];
|
||
|
||
if (NewLogicalDiskType == FtPartition) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
// First make sure that the members are all root logical disks and
|
||
// are complete.
|
||
|
||
for (i = 0; i < NumberOfMembers; i++) {
|
||
if (!ArrayOfMembers[i]) {
|
||
continue;
|
||
}
|
||
|
||
for (j = 0; j < _numberOfRootLogicalDisksIds; j++) {
|
||
if (ArrayOfMembers[i] == _arrayOfRootLogicalDiskIds[j]) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (j == _numberOfRootLogicalDisksIds) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (!IsLogicalDiskComplete(ArrayOfMembers[i])) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
|
||
|
||
// In the mirror, volume set, and redist cases. Save the
|
||
// drive letter of the first member.
|
||
|
||
if (NewLogicalDiskType == FtVolumeSet ||
|
||
NewLogicalDiskType == FtMirrorSet ||
|
||
NewLogicalDiskType == FtRedistribution) {
|
||
|
||
driveLetter = QueryDriveLetter(ArrayOfMembers[0]);
|
||
|
||
} else {
|
||
driveLetter = 0;
|
||
}
|
||
|
||
for (i = 0; i < NumberOfMembers; i++) {
|
||
SetDriveLetter(ArrayOfMembers[i], 0);
|
||
}
|
||
|
||
*NewLogicalDiskId = GenerateNewLogicalDiskId();
|
||
|
||
|
||
// Construct the disk description record.
|
||
|
||
size = sizeof(FT_LOGICAL_DISK_DESCRIPTION) +
|
||
ConfigurationInformationSize + StateInformationSize;
|
||
|
||
size = (size + FILE_QUAD_ALIGNMENT)&(~FILE_QUAD_ALIGNMENT);
|
||
|
||
newLogicalDiskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
ExAllocatePool(PagedPool, size);
|
||
if (!newLogicalDiskDescription) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
newLogicalDiskDescription->DiskDescriptionSize = size;
|
||
newLogicalDiskDescription->DriveLetter = driveLetter;
|
||
newLogicalDiskDescription->Reserved = 0;
|
||
newLogicalDiskDescription->LogicalDiskType = NewLogicalDiskType;
|
||
newLogicalDiskDescription->LogicalDiskId = *NewLogicalDiskId;
|
||
newLogicalDiskDescription->u.Other.ThisMemberLogicalDiskId = 0;
|
||
newLogicalDiskDescription->u.Other.ThisMemberNumber = 0;
|
||
newLogicalDiskDescription->u.Other.NumberOfMembers = NumberOfMembers;
|
||
if (ConfigurationInformationSize) {
|
||
newLogicalDiskDescription->u.Other.
|
||
ByteOffsetToConfigurationInformation =
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION);
|
||
RtlMoveMemory((PCHAR) newLogicalDiskDescription +
|
||
newLogicalDiskDescription->u.Other.
|
||
ByteOffsetToConfigurationInformation,
|
||
ConfigurationInformation,
|
||
ConfigurationInformationSize);
|
||
} else {
|
||
newLogicalDiskDescription->u.Other.
|
||
ByteOffsetToConfigurationInformation = 0;
|
||
}
|
||
if (StateInformationSize) {
|
||
newLogicalDiskDescription->u.Other.ByteOffsetToStateInformation =
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION) +
|
||
ConfigurationInformationSize;
|
||
RtlMoveMemory((PCHAR) newLogicalDiskDescription +
|
||
newLogicalDiskDescription->u.Other.
|
||
ByteOffsetToStateInformation,
|
||
StateInformation,
|
||
StateInformationSize);
|
||
} else {
|
||
newLogicalDiskDescription->u.Other.ByteOffsetToStateInformation = 0;
|
||
}
|
||
|
||
|
||
// Figure out how many instances we're going to need and check to make
|
||
// sure that there is enough disk space for all of the instances.
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
|
||
numInstancesInThisInfo = 0;
|
||
for (j = 0; j < NumberOfMembers; j++) {
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == ArrayOfMembers[j]) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p) {
|
||
numInstancesInThisInfo++;
|
||
}
|
||
}
|
||
|
||
if (numInstancesInThisInfo) {
|
||
if (numInstancesInThisInfo*
|
||
newLogicalDiskDescription->DiskDescriptionSize >
|
||
diskInfo->QueryDiskDescriptionFreeSpace()) {
|
||
|
||
FtpLogError(diskInfo->GetRootExtension(),
|
||
diskInfo->QueryDiskNumber(),
|
||
FT_NOT_ENOUGH_ON_DISK_SPACE, STATUS_DISK_FULL, 0);
|
||
|
||
ExFreePool(newLogicalDiskDescription);
|
||
return STATUS_DISK_FULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// Now allocate the memory that we need to store this new logical
|
||
// disk.
|
||
|
||
if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
|
||
ExFreePool(newLogicalDiskDescription);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
// Now that we have the memory and disk space we can proceed with
|
||
// the changes. First fix up the logical disk entries and write out
|
||
// the structures to disk.
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
|
||
for (j = 0; j < NumberOfMembers; j++) {
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId == ArrayOfMembers[j]) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (p) {
|
||
newLogicalDiskDescription->u.Other.
|
||
ThisMemberLogicalDiskId = ArrayOfMembers[j];
|
||
newLogicalDiskDescription->u.Other.ThisMemberNumber =
|
||
(USHORT) j;
|
||
|
||
q = diskInfo->AddLogicalDiskDescription(
|
||
newLogicalDiskDescription);
|
||
ASSERT(q);
|
||
|
||
status = diskInfo->Write();
|
||
if (!NT_SUCCESS(status)) {
|
||
BreakLogicalDisk(*NewLogicalDiskId);
|
||
ExFreePool(newLogicalDiskDescription);
|
||
return status;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
ExFreePool(newLogicalDiskDescription);
|
||
|
||
|
||
// Fix up the list of root entries.
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::BreakLogicalDisk(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine breaks the given logical disk into its members.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the root logical disk id to break.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, j, numMembers;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
FT_LOGICAL_DISK_TYPE diskType;
|
||
UCHAR driveLetter;
|
||
PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
|
||
FT_LOGICAL_DISK_ID mainMember;
|
||
NTSTATUS status;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
|
||
// First make sure that the given logical disk id is a root.
|
||
|
||
for (i = 0; i < _numberOfRootLogicalDisksIds; i++) {
|
||
if (LogicalDiskId == _arrayOfRootLogicalDiskIds[i]) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfRootLogicalDisksIds) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
// Allocate the memory needed to grow the list of roots.
|
||
|
||
p = GetLogicalDiskDescription(LogicalDiskId, 0);
|
||
ASSERT(p);
|
||
|
||
diskType = p->LogicalDiskType;
|
||
driveLetter = p->DriveLetter;
|
||
if (diskType == FtPartition) {
|
||
numMembers = 0;
|
||
} else {
|
||
numMembers = p->u.Other.NumberOfMembers;
|
||
}
|
||
|
||
if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + numMembers)) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
DeleteFtRegistryInfo(LogicalDiskId);
|
||
|
||
if (diskType == FtMirrorSet) {
|
||
|
||
state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION)
|
||
GetStateInformation(LogicalDiskId);
|
||
ASSERT(state);
|
||
|
||
if (state->UnhealthyMemberState == FtMemberHealthy ||
|
||
state->UnhealthyMemberNumber == 1) {
|
||
|
||
mainMember = QueryMemberLogicalDiskId(LogicalDiskId, 0);
|
||
} else {
|
||
mainMember = QueryMemberLogicalDiskId(LogicalDiskId, 1);
|
||
}
|
||
|
||
SetDriveLetter(mainMember, driveLetter);
|
||
}
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
|
||
p = diskInfo->GetFirstLogicalDiskDescription();
|
||
while (p) {
|
||
if (p->LogicalDiskId == LogicalDiskId) {
|
||
|
||
diskInfo->DeleteLogicalDiskDescription(p);
|
||
if (!p->DiskDescriptionSize) {
|
||
p = NULL;
|
||
}
|
||
diskInfo->Write();
|
||
|
||
} else {
|
||
p = diskInfo->GetNextLogicalDiskDescription(p);
|
||
}
|
||
}
|
||
}
|
||
|
||
FtpDeleteStateInRegistry(LogicalDiskId);
|
||
|
||
|
||
// Recompute the list of roots.
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::ReplaceLogicalDiskMember(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
IN USHORT MemberNumberToReplace,
|
||
IN FT_LOGICAL_DISK_ID NewMemberLogicalDiskId,
|
||
OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine replaces the given member with the new given member.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk whose member we are
|
||
going to replace.
|
||
|
||
MemberNumberToReplace - Supplies the member number to replace.
|
||
|
||
NewMemberLogicalDiskId - Supplies the new member.
|
||
|
||
NewLogicalDiskId - Returns the new logical disk id for the set
|
||
containing the new member.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, j, numInstances, n;
|
||
PFT_LOGICAL_DISK_ID oldLogicalDiskIds;
|
||
PFT_LOGICAL_DISK_ID newLogicalDiskIds;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, q, newDiskDescription;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
NTSTATUS status;
|
||
BOOLEAN wroteLog;
|
||
FT_LOGICAL_DISK_ID replacedMemberDiskId, child;
|
||
UCHAR state[100];
|
||
USHORT stateSize;
|
||
|
||
|
||
// Make sure that the replacement is a root and is complete.
|
||
|
||
for (i = 0; i < _numberOfRootLogicalDisksIds; i++) {
|
||
if (NewMemberLogicalDiskId == _arrayOfRootLogicalDiskIds[i]) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfRootLogicalDisksIds ||
|
||
!IsLogicalDiskComplete(NewMemberLogicalDiskId)) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
DeleteFtRegistryInfo(LogicalDiskId);
|
||
|
||
|
||
// Figure out 'n' where n is how many new logical disk ids we need.
|
||
|
||
if (!ComputeNewParentLogicalDiskIds(LogicalDiskId, &n,
|
||
&oldLogicalDiskIds,
|
||
&newLogicalDiskIds)) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
// Copy back the new logical disk id.
|
||
|
||
*NewLogicalDiskId = newLogicalDiskIds[0];
|
||
|
||
|
||
// Figure out the logical disk id of the member to replace.
|
||
|
||
replacedMemberDiskId = QueryMemberLogicalDiskId(LogicalDiskId,
|
||
MemberNumberToReplace);
|
||
|
||
|
||
// Build up the new member into a new tree that will eventually
|
||
// replace the old tree of which this logical disk is a member.
|
||
|
||
for (i = 0; i < n; i++) {
|
||
|
||
if (i == 0) {
|
||
p = GetLogicalDiskDescription(oldLogicalDiskIds[i], 0);
|
||
} else {
|
||
p = GetParentLogicalDiskDescription(oldLogicalDiskIds[i - 1]);
|
||
}
|
||
if (!p || p->LogicalDiskType == FtPartition) {
|
||
ExFreePool(oldLogicalDiskIds);
|
||
ExFreePool(newLogicalDiskIds);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
newDiskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
ExAllocatePool(PagedPool, p->DiskDescriptionSize);
|
||
if (!newDiskDescription) {
|
||
ExFreePool(oldLogicalDiskIds);
|
||
ExFreePool(newLogicalDiskIds);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlMoveMemory(newDiskDescription, p, p->DiskDescriptionSize);
|
||
newDiskDescription->LogicalDiskId = newLogicalDiskIds[i];
|
||
if (i == 0) {
|
||
newDiskDescription->u.Other.ThisMemberLogicalDiskId =
|
||
NewMemberLogicalDiskId;
|
||
newDiskDescription->u.Other.ThisMemberNumber =
|
||
MemberNumberToReplace;
|
||
} else {
|
||
newDiskDescription->u.Other.ThisMemberLogicalDiskId =
|
||
newLogicalDiskIds[i - 1];
|
||
}
|
||
|
||
for (j = 0; j < _numberOfLogicalDiskInformations; j++) {
|
||
|
||
diskInfo = _arrayOfLogicalDiskInformations[j];
|
||
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskId !=
|
||
newDiskDescription->u.Other.ThisMemberLogicalDiskId) {
|
||
|
||
continue;
|
||
}
|
||
|
||
if (!diskInfo->AddLogicalDiskDescription(newDiskDescription)) {
|
||
|
||
FtpLogError(diskInfo->GetRootExtension(),
|
||
diskInfo->QueryDiskNumber(),
|
||
FT_NOT_ENOUGH_ON_DISK_SPACE, STATUS_DISK_FULL,
|
||
0);
|
||
|
||
ExFreePool(newDiskDescription);
|
||
ExFreePool(oldLogicalDiskIds);
|
||
ExFreePool(newLogicalDiskIds);
|
||
return STATUS_DISK_FULL;
|
||
}
|
||
|
||
status = diskInfo->Write();
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(newDiskDescription);
|
||
ExFreePool(oldLogicalDiskIds);
|
||
ExFreePool(newLogicalDiskIds);
|
||
return status;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
ExFreePool(newDiskDescription);
|
||
}
|
||
|
||
|
||
// Substitute new logical disk ids for old ones, logging the operation
|
||
// for a safe backout in the event of a crash.
|
||
|
||
status = STATUS_SUCCESS;
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
wroteLog = FALSE;
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskType != FtPartition) {
|
||
continue;
|
||
}
|
||
|
||
child = p->LogicalDiskId;
|
||
|
||
for (q = diskInfo->GetNextLogicalDiskDescription(p); q;
|
||
q = diskInfo->GetNextLogicalDiskDescription(q)) {
|
||
|
||
if (q->LogicalDiskType == FtPartition ||
|
||
q->u.Other.ThisMemberLogicalDiskId != child) {
|
||
|
||
continue;
|
||
}
|
||
|
||
if (q->LogicalDiskId == LogicalDiskId &&
|
||
q->u.Other.ThisMemberNumber == MemberNumberToReplace) {
|
||
|
||
break;
|
||
}
|
||
|
||
child = q->LogicalDiskId;
|
||
}
|
||
|
||
if (q) {
|
||
continue;
|
||
}
|
||
|
||
child = p->LogicalDiskId;
|
||
|
||
for (q = diskInfo->GetNextLogicalDiskDescription(p); q;
|
||
q = diskInfo->GetNextLogicalDiskDescription(q)) {
|
||
|
||
if (q->LogicalDiskType == FtPartition ||
|
||
q->u.Other.ThisMemberLogicalDiskId != child) {
|
||
|
||
continue;
|
||
}
|
||
|
||
child = q->LogicalDiskId;
|
||
|
||
for (j = 0; j < n; j++) {
|
||
if (q->LogicalDiskId == oldLogicalDiskIds[j]) {
|
||
if (!wroteLog) {
|
||
diskInfo->AddReplaceLog(replacedMemberDiskId,
|
||
NewMemberLogicalDiskId,
|
||
n, oldLogicalDiskIds,
|
||
newLogicalDiskIds);
|
||
wroteLog = TRUE;
|
||
}
|
||
q->LogicalDiskId = newLogicalDiskIds[j];
|
||
} else if (q->u.Other.ThisMemberLogicalDiskId ==
|
||
oldLogicalDiskIds[j]) {
|
||
if (!wroteLog) {
|
||
diskInfo->AddReplaceLog(replacedMemberDiskId,
|
||
NewMemberLogicalDiskId,
|
||
n, oldLogicalDiskIds,
|
||
newLogicalDiskIds);
|
||
wroteLog = TRUE;
|
||
}
|
||
q->u.Other.ThisMemberLogicalDiskId =
|
||
newLogicalDiskIds[j];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (wroteLog) {
|
||
status = diskInfo->Write();
|
||
if (!NT_SUCCESS(status)) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->ClearReplaceLog()) {
|
||
diskInfo->Write();
|
||
}
|
||
}
|
||
|
||
// Erase all logical disk descriptions that contain the old
|
||
// logical disk ids.
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
for (j = 0; j < n; j++) {
|
||
if (p->LogicalDiskId == oldLogicalDiskIds[j]) {
|
||
diskInfo->DeleteLogicalDiskDescription(p);
|
||
diskInfo->Write();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < n; i++) {
|
||
if (FtpQueryStateFromRegistry(oldLogicalDiskIds[i], state, 100,
|
||
&stateSize)) {
|
||
|
||
FtpDeleteStateInRegistry(oldLogicalDiskIds[i]);
|
||
FtpCopyStateToRegistry(newLogicalDiskIds[i], state, stateSize);
|
||
}
|
||
}
|
||
|
||
} else {
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->BackOutReplaceOperation()) {
|
||
diskInfo->Write();
|
||
}
|
||
}
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
for (i = n; i > 0; i--) {
|
||
BreakLogicalDisk(newLogicalDiskIds[i - 1]);
|
||
}
|
||
}
|
||
|
||
ExFreePool(oldLogicalDiskIds);
|
||
ExFreePool(newLogicalDiskIds);
|
||
|
||
|
||
// Recompute list of root entries.
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
return status;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_TYPE
|
||
TranslateFtDiskType(
|
||
IN FT_TYPE FtType
|
||
)
|
||
|
||
{
|
||
switch (FtType) {
|
||
case Mirror:
|
||
return FtMirrorSet;
|
||
|
||
case Stripe:
|
||
return FtStripeSet;
|
||
|
||
case StripeWithParity:
|
||
return FtStripeSetWithParity;
|
||
|
||
case VolumeSet:
|
||
return FtVolumeSet;
|
||
|
||
}
|
||
|
||
return FtPartition;
|
||
}
|
||
|
||
PFT_DESCRIPTION
|
||
GetFtDescription(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition
|
||
)
|
||
|
||
{
|
||
ULONG diskPartitionOffset;
|
||
PFT_REGISTRY ftRegistry;
|
||
PFT_DESCRIPTION ftDescription;
|
||
USHORT i, j;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
|
||
diskPartitionOffset = (ULONG) ((PUCHAR) DiskPartition - (PUCHAR) Registry);
|
||
ftRegistry = (PFT_REGISTRY) ((PUCHAR) Registry +
|
||
Registry->FtInformationOffset);
|
||
ftDescription = &ftRegistry->FtDescription[0];
|
||
for (i = 0; i < ftRegistry->NumberOfComponents; i++) {
|
||
for (j = 0; j < ftDescription->NumberOfMembers; j++) {
|
||
ftMember = &ftDescription->FtMemberDescription[j];
|
||
if (ftMember->OffsetToPartitionInfo == diskPartitionOffset) {
|
||
return ftDescription;
|
||
}
|
||
}
|
||
ftDescription = (PFT_DESCRIPTION) &ftDescription->FtMemberDescription[
|
||
ftDescription->NumberOfMembers];
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
USHORT
|
||
GetRegistryNumberOfMembers(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition
|
||
)
|
||
|
||
{
|
||
PFT_DESCRIPTION ftDescription;
|
||
|
||
ftDescription = GetFtDescription(Registry, DiskPartition);
|
||
if (!ftDescription) {
|
||
return 0;
|
||
}
|
||
|
||
return ftDescription->NumberOfMembers;
|
||
}
|
||
|
||
ULONG
|
||
FT_LOGICAL_DISK_INFORMATION_SET::DiskNumberFromSignature(
|
||
IN ULONG Signature
|
||
)
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (Signature == FtpQueryDiskSignature(diskInfo->GetWholeDiskPdo())) {
|
||
return diskInfo->QueryDiskNumber();
|
||
}
|
||
}
|
||
|
||
return 0xFFFFFFFF;
|
||
}
|
||
|
||
VOID
|
||
DeleteFtRegistryInformation(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition
|
||
)
|
||
|
||
{
|
||
PFT_DESCRIPTION ftDescription, next;
|
||
USHORT i;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
PDISK_PARTITION diskPartition;
|
||
PFT_REGISTRY ftRegistry;
|
||
|
||
ftDescription = GetFtDescription(Registry, DiskPartition);
|
||
if (!ftDescription) {
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < ftDescription->NumberOfMembers; i++) {
|
||
ftMember = &ftDescription->FtMemberDescription[i];
|
||
diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
|
||
ftMember->OffsetToPartitionInfo);
|
||
|
||
diskPartition->FtType = NotAnFtMember;
|
||
diskPartition->FtState = Healthy;
|
||
RtlZeroMemory(&diskPartition->FtLength.QuadPart, sizeof(LONGLONG));
|
||
diskPartition->FtGroup = (USHORT) -1;
|
||
diskPartition->FtMember = 0;
|
||
diskPartition->DriveLetter = 0;
|
||
}
|
||
|
||
next = (PFT_DESCRIPTION) &ftDescription->FtMemberDescription[
|
||
ftDescription->NumberOfMembers];
|
||
|
||
ftRegistry = (PFT_REGISTRY) ((PUCHAR) Registry +
|
||
Registry->FtInformationOffset);
|
||
|
||
RtlMoveMemory(ftDescription, next,
|
||
(PCHAR) ftRegistry + Registry->FtInformationSize -
|
||
(PCHAR) next);
|
||
|
||
ftRegistry->NumberOfComponents--;
|
||
}
|
||
|
||
VOID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::DeleteFtRegistryInfo(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId
|
||
)
|
||
|
||
{
|
||
USHORT n, i, j;
|
||
FT_LOGICAL_DISK_ID diskId;
|
||
LONGLONG offset;
|
||
PDEVICE_OBJECT wholeDisk;
|
||
ULONG diskNumber, signature;
|
||
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
||
ULONG registrySize;
|
||
NTSTATUS status;
|
||
PDISK_CONFIG_HEADER registry;
|
||
PFT_REGISTRY ftRegistry;
|
||
PFT_DESCRIPTION ftDescription;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
PDISK_PARTITION diskPartition;
|
||
LONGLONG tmp;
|
||
|
||
n = QueryNumberOfMembersInLogicalDisk(LogicalDiskId);
|
||
if (!n) {
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < n; i++) {
|
||
diskId = QueryMemberLogicalDiskId(LogicalDiskId, i);
|
||
if (diskId) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!diskId) {
|
||
return;
|
||
}
|
||
|
||
if (!QueryFtPartitionInformation(diskId, &offset, &wholeDisk, NULL, NULL,
|
||
NULL)) {
|
||
|
||
return;
|
||
}
|
||
|
||
signature = FtpQueryDiskSignature(wholeDisk);
|
||
if (!signature) {
|
||
return;
|
||
}
|
||
|
||
RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
|
||
queryTable[0].QueryRoutine = FtpDiskRegistryQueryRoutine;
|
||
queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
|
||
queryTable[0].Name = L"Information";
|
||
queryTable[0].EntryContext = ®istrySize;
|
||
|
||
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
|
||
queryTable, ®istry, NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return;
|
||
}
|
||
|
||
if (!registry->FtInformationSize) {
|
||
ExFreePool(registry);
|
||
return;
|
||
}
|
||
|
||
ftRegistry = (PFT_REGISTRY) ((PUCHAR) registry +
|
||
registry->FtInformationOffset);
|
||
ftDescription = &ftRegistry->FtDescription[0];
|
||
for (i = 0; i < ftRegistry->NumberOfComponents; i++) {
|
||
for (j = 0; j < ftDescription->NumberOfMembers; j++) {
|
||
ftMember = &ftDescription->FtMemberDescription[j];
|
||
diskPartition = (PDISK_PARTITION) ((PUCHAR) registry +
|
||
ftMember->OffsetToPartitionInfo);
|
||
|
||
RtlCopyMemory(&tmp, &diskPartition->StartingOffset.QuadPart,
|
||
sizeof(LONGLONG));
|
||
if (ftMember->Signature == signature && tmp == offset) {
|
||
DeleteFtRegistryInformation(registry, diskPartition);
|
||
goto Finish;
|
||
}
|
||
}
|
||
ftDescription = (PFT_DESCRIPTION) &ftDescription->FtMemberDescription[
|
||
ftDescription->NumberOfMembers];
|
||
}
|
||
|
||
Finish:
|
||
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
|
||
L"Information", REG_BINARY, registry,
|
||
registrySize);
|
||
|
||
ExFreePool(registry);
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_INFORMATION
|
||
FT_LOGICAL_DISK_INFORMATION_SET::FindLogicalDiskInformation(
|
||
IN PDEVICE_OBJECT WholeDiskPdo
|
||
)
|
||
|
||
{
|
||
ULONG i;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
if (_arrayOfLogicalDiskInformations[i]->GetWholeDiskPdo() ==
|
||
WholeDiskPdo) {
|
||
|
||
return _arrayOfLogicalDiskInformations[i];
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
LONGLONG
|
||
GetMemberSize(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition
|
||
)
|
||
|
||
{
|
||
PFT_DESCRIPTION ftDescription;
|
||
LONGLONG memberSize;
|
||
USHORT i;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
PDISK_PARTITION diskPartition;
|
||
LONGLONG tmp;
|
||
|
||
ftDescription = GetFtDescription(Registry, DiskPartition);
|
||
if (!ftDescription) {
|
||
return 0;
|
||
}
|
||
|
||
memberSize = 0;
|
||
|
||
for (i = 0; i < ftDescription->NumberOfMembers; i++) {
|
||
ftMember = &ftDescription->FtMemberDescription[i];
|
||
diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
|
||
ftMember->OffsetToPartitionInfo);
|
||
|
||
RtlCopyMemory(&tmp, &diskPartition->Length.QuadPart, sizeof(LONGLONG));
|
||
if (!memberSize || memberSize > tmp) {
|
||
RtlCopyMemory(&memberSize, &diskPartition->Length.QuadPart,
|
||
sizeof(LONGLONG));
|
||
}
|
||
}
|
||
|
||
return memberSize;
|
||
}
|
||
|
||
VOID
|
||
SetStateInfo(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition,
|
||
OUT PFT_MIRROR_AND_SWP_STATE_INFORMATION State
|
||
)
|
||
|
||
{
|
||
PFT_DESCRIPTION ftDescription;
|
||
USHORT i;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
PDISK_PARTITION diskPartition;
|
||
|
||
RtlZeroMemory(State, sizeof(FT_MIRROR_AND_SWP_STATE_INFORMATION));
|
||
if (Registry->DirtyShutdown) {
|
||
State->IsDirty = TRUE;
|
||
}
|
||
|
||
ftDescription = GetFtDescription(Registry, DiskPartition);
|
||
if (!ftDescription) {
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < ftDescription->NumberOfMembers; i++) {
|
||
ftMember = &ftDescription->FtMemberDescription[i];
|
||
diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
|
||
ftMember->OffsetToPartitionInfo);
|
||
|
||
switch (diskPartition->FtState) {
|
||
case Orphaned:
|
||
State->UnhealthyMemberNumber = i;
|
||
State->UnhealthyMemberState = FtMemberOrphaned;
|
||
break;
|
||
|
||
case Regenerating:
|
||
State->UnhealthyMemberNumber = i;
|
||
State->UnhealthyMemberState = FtMemberRegenerating;
|
||
break;
|
||
|
||
case Initializing:
|
||
State->IsInitializing = TRUE;
|
||
break;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION_SET::GetDiskDescription(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition,
|
||
IN PFT_LOGICAL_DISK_DESCRIPTION CheckDiskDescription,
|
||
OUT PFT_LOGICAL_DISK_DESCRIPTION* DiskDescription
|
||
)
|
||
|
||
{
|
||
PFT_DESCRIPTION ftDescription;
|
||
USHORT i;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
PDISK_PARTITION diskPartition;
|
||
FT_LOGICAL_DISK_ID partitionDiskId;
|
||
PFT_LOGICAL_DISK_DESCRIPTION diskDesc;
|
||
LONGLONG tmp;
|
||
|
||
ftDescription = GetFtDescription(Registry, DiskPartition);
|
||
if (!ftDescription) {
|
||
return FALSE;
|
||
}
|
||
|
||
for (i = 0; i < ftDescription->NumberOfMembers; i++) {
|
||
ftMember = &ftDescription->FtMemberDescription[i];
|
||
diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
|
||
ftMember->OffsetToPartitionInfo);
|
||
|
||
RtlCopyMemory(&tmp, &diskPartition->StartingOffset.QuadPart,
|
||
sizeof(LONGLONG));
|
||
partitionDiskId = QueryPartitionLogicalDiskId(
|
||
DiskNumberFromSignature(ftMember->Signature), tmp);
|
||
if (!partitionDiskId) {
|
||
continue;
|
||
}
|
||
|
||
diskDesc = GetParentLogicalDiskDescription(partitionDiskId);
|
||
if (!diskDesc) {
|
||
continue;
|
||
}
|
||
|
||
if (GetParentLogicalDiskDescription(diskDesc->LogicalDiskId)) {
|
||
continue;
|
||
}
|
||
|
||
if (diskDesc != CheckDiskDescription) {
|
||
*DiskDescription = diskDesc;
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
UCHAR
|
||
GetDriveLetter(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition
|
||
)
|
||
|
||
{
|
||
PFT_DESCRIPTION ftDescription;
|
||
USHORT i;
|
||
PFT_MEMBER_DESCRIPTION ftMember;
|
||
PDISK_PARTITION diskPartition;
|
||
|
||
ftDescription = GetFtDescription(Registry, DiskPartition);
|
||
if (!ftDescription) {
|
||
return 0;
|
||
}
|
||
|
||
for (i = 0; i < ftDescription->NumberOfMembers; i++) {
|
||
ftMember = &ftDescription->FtMemberDescription[i];
|
||
diskPartition = (PDISK_PARTITION) ((PUCHAR) Registry +
|
||
ftMember->OffsetToPartitionInfo);
|
||
|
||
if (diskPartition->AssignDriveLetter) {
|
||
if (diskPartition->DriveLetter >= 'A' &&
|
||
diskPartition->DriveLetter <= 'Z') {
|
||
|
||
return diskPartition->DriveLetter;
|
||
} else if (!diskPartition->DriveLetter) {
|
||
if (IsNEC_98) return 0; //For fresh assigning drive letter on NEC98.
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0xFF;
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
CreateDiskDescription(
|
||
IN PDISK_CONFIG_HEADER Registry,
|
||
IN PDISK_PARTITION DiskPartition,
|
||
IN FT_LOGICAL_DISK_ID PartitionDiskId
|
||
)
|
||
|
||
{
|
||
FT_LOGICAL_DISK_TYPE diskType;
|
||
USHORT configInfoSize, stateInfoSize, size;
|
||
PVOID configInfo, stateInfo;
|
||
FT_STRIPE_SET_CONFIGURATION_INFORMATION stripeConfig;
|
||
FT_MIRROR_SET_CONFIGURATION_INFORMATION mirrorConfig;
|
||
FT_MIRROR_AND_SWP_STATE_INFORMATION state;
|
||
FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION swpConfig;
|
||
PFT_LOGICAL_DISK_DESCRIPTION diskDesc;
|
||
|
||
diskType = TranslateFtDiskType(DiskPartition->FtType);
|
||
|
||
switch (diskType) {
|
||
case FtVolumeSet:
|
||
configInfoSize = 0;
|
||
configInfo = NULL;
|
||
stateInfoSize = 0;
|
||
stateInfo = NULL;
|
||
break;
|
||
|
||
case FtStripeSet:
|
||
RtlZeroMemory(&stripeConfig, sizeof(stripeConfig));
|
||
stripeConfig.StripeSize = STRIPE_SIZE;
|
||
configInfoSize = sizeof(stripeConfig);
|
||
configInfo = &stripeConfig;
|
||
stateInfoSize = 0;
|
||
stateInfo = NULL;
|
||
break;
|
||
|
||
case FtMirrorSet:
|
||
RtlZeroMemory(&mirrorConfig, sizeof(mirrorConfig));
|
||
mirrorConfig.MemberSize = GetMemberSize(Registry, DiskPartition);
|
||
configInfoSize = sizeof(mirrorConfig);
|
||
configInfo = &mirrorConfig;
|
||
stateInfoSize = sizeof(state);
|
||
stateInfo = &state;
|
||
SetStateInfo(Registry, DiskPartition, &state);
|
||
break;
|
||
|
||
case FtStripeSetWithParity:
|
||
RtlZeroMemory(&swpConfig, sizeof(swpConfig));
|
||
swpConfig.MemberSize = GetMemberSize(Registry, DiskPartition);
|
||
swpConfig.StripeSize = STRIPE_SIZE;
|
||
configInfoSize = sizeof(swpConfig);
|
||
configInfo = &swpConfig;
|
||
stateInfoSize = sizeof(state);
|
||
stateInfo = &state;
|
||
SetStateInfo(Registry, DiskPartition, &state);
|
||
break;
|
||
|
||
default:
|
||
return NULL;
|
||
|
||
}
|
||
|
||
size = sizeof(FT_LOGICAL_DISK_DESCRIPTION) + configInfoSize +
|
||
stateInfoSize;
|
||
|
||
size = (size + FILE_QUAD_ALIGNMENT)&(~FILE_QUAD_ALIGNMENT);
|
||
|
||
diskDesc = (PFT_LOGICAL_DISK_DESCRIPTION) ExAllocatePool(PagedPool, size);
|
||
if (!diskDesc) {
|
||
return NULL;
|
||
}
|
||
|
||
RtlZeroMemory(diskDesc, size);
|
||
diskDesc->DiskDescriptionSize = size;
|
||
diskDesc->DriveLetter = GetDriveLetter(Registry, DiskPartition);
|
||
diskDesc->LogicalDiskType = diskType;
|
||
diskDesc->LogicalDiskId = GenerateNewLogicalDiskId();
|
||
diskDesc->u.Other.ThisMemberLogicalDiskId = PartitionDiskId;
|
||
diskDesc->u.Other.ThisMemberNumber = DiskPartition->FtMember;
|
||
diskDesc->u.Other.NumberOfMembers = GetRegistryNumberOfMembers(Registry,
|
||
DiskPartition);
|
||
if (diskDesc->u.Other.ThisMemberNumber >=
|
||
diskDesc->u.Other.NumberOfMembers) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
if (configInfo) {
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation =
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION);
|
||
RtlMoveMemory((PCHAR) diskDesc +
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation,
|
||
configInfo, configInfoSize);
|
||
} else {
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation = 0;
|
||
}
|
||
|
||
if (stateInfo) {
|
||
diskDesc->u.Other.ByteOffsetToStateInformation =
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation +
|
||
configInfoSize;
|
||
RtlMoveMemory((PCHAR) diskDesc +
|
||
diskDesc->u.Other.ByteOffsetToStateInformation,
|
||
stateInfo, stateInfoSize);
|
||
} else {
|
||
diskDesc->u.Other.ByteOffsetToStateInformation = 0;
|
||
}
|
||
|
||
return diskDesc;
|
||
}
|
||
|
||
VOID
|
||
SetPartitionType(
|
||
IN PDEVICE_OBJECT Partition
|
||
)
|
||
|
||
{
|
||
KEVENT event;
|
||
PIRP irp;
|
||
PARTITION_INFORMATION partInfo;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
NTSTATUS status;
|
||
SET_PARTITION_INFORMATION setPartInfo;
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
|
||
Partition, NULL, 0, &partInfo,
|
||
sizeof(partInfo), FALSE, &event,
|
||
&ioStatus);
|
||
if (!irp) {
|
||
return;
|
||
}
|
||
|
||
status = IoCallDriver(Partition, irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return;
|
||
}
|
||
|
||
setPartInfo.PartitionType = (partInfo.PartitionType | (0x80));
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_PARTITION_INFO,
|
||
Partition, &setPartInfo,
|
||
sizeof(setPartInfo), NULL, 0, FALSE,
|
||
&event, &ioStatus);
|
||
if (!irp) {
|
||
return;
|
||
}
|
||
|
||
status = IoCallDriver(Partition, irp);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
DeleteAncestors(
|
||
IN PFT_LOGICAL_DISK_INFORMATION LogicalDiskInformation,
|
||
IN FT_LOGICAL_DISK_ID PartitionLogicalDiskId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes the disk descriptions which are ancestors
|
||
to the given partition disk description on the given logical
|
||
disk information.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskInformation - Supplies the logical disk information.
|
||
|
||
PartitionLogicalDiskId - Supplies the partition logical disk id.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo = LogicalDiskInformation;
|
||
FT_LOGICAL_DISK_ID diskId = PartitionLogicalDiskId;
|
||
PFT_LOGICAL_DISK_DESCRIPTION diskDesc;
|
||
|
||
diskDesc = diskInfo->GetFirstLogicalDiskDescription();
|
||
while (diskDesc && diskDesc->DiskDescriptionSize) {
|
||
|
||
if (diskDesc->LogicalDiskType == FtPartition ||
|
||
diskDesc->u.Other.ThisMemberLogicalDiskId != diskId) {
|
||
|
||
diskDesc = diskInfo->GetNextLogicalDiskDescription(diskDesc);
|
||
continue;
|
||
}
|
||
|
||
diskId = diskDesc->LogicalDiskId;
|
||
diskInfo->DeleteLogicalDiskDescription(diskDesc);
|
||
}
|
||
|
||
FtpLogError(diskInfo->GetRootExtension(), diskInfo->QueryDiskNumber(),
|
||
FT_STALE_ONDISK, STATUS_SUCCESS, 0);
|
||
}
|
||
|
||
NTSTATUS
|
||
FT_LOGICAL_DISK_INFORMATION_SET::MigrateRegistryInformation(
|
||
IN PDEVICE_OBJECT Partition,
|
||
IN ULONG DiskNumber,
|
||
IN LONGLONG Offset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine migrates the registry information for the given partition to
|
||
on disk structures. If all members of the FT set being migrated are on
|
||
disk then the registry information pertaining to the FT set is deleted.
|
||
|
||
Arguments:
|
||
|
||
DiskNumber - Supplies the disk number of the partition.
|
||
|
||
Offset - Supplies the partition offset.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, signature, registrySize, length;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
||
NTSTATUS status;
|
||
PDISK_CONFIG_HEADER registry;
|
||
PDISK_REGISTRY diskRegistry;
|
||
PDISK_PARTITION diskPartition;
|
||
FT_LOGICAL_DISK_ID partitionDiskId;
|
||
PFT_LOGICAL_DISK_DESCRIPTION diskDesc, newDesc, otherDesc;
|
||
PVOID config, newConfig;
|
||
PVOID state, newState;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
if (diskInfo->QueryDiskNumber() == DiskNumber) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (i == _numberOfLogicalDiskInformations) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
signature = FtpQueryDiskSignature(diskInfo->GetWholeDiskPdo());
|
||
if (!signature) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
|
||
queryTable[0].QueryRoutine = FtpDiskRegistryQueryRoutine;
|
||
queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
|
||
queryTable[0].Name = L"Information";
|
||
queryTable[0].EntryContext = ®istrySize;
|
||
|
||
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
|
||
queryTable, ®istry, NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
if (!registry->FtInformationSize) {
|
||
ExFreePool(registry);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
diskRegistry = (PDISK_REGISTRY)
|
||
((PUCHAR) registry + registry->DiskInformationOffset);
|
||
|
||
diskPartition = FtpFindDiskPartition(diskRegistry, signature, Offset);
|
||
if (!diskPartition || diskPartition->FtType == NotAnFtMember) {
|
||
ExFreePool(registry);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
if (!ReallocRootLogicalDiskIds(_numberOfRootLogicalDisksIds + 1)) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
partitionDiskId = QueryPartitionLogicalDiskId(DiskNumber, Offset);
|
||
if (!partitionDiskId) {
|
||
status = CreatePartitionLogicalDisk(DiskNumber, Offset, 0,
|
||
&partitionDiskId);
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(registry);
|
||
return status;
|
||
}
|
||
|
||
SetPartitionType(Partition);
|
||
}
|
||
|
||
diskDesc = GetParentLogicalDiskDescription(partitionDiskId);
|
||
newDesc = CreateDiskDescription(registry, diskPartition, partitionDiskId);
|
||
if (!newDesc) {
|
||
ExFreePool(registry);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
if (diskDesc && GetParentLogicalDiskDescription(diskDesc->LogicalDiskId)) {
|
||
DeleteAncestors(diskInfo, partitionDiskId);
|
||
diskDesc = NULL;
|
||
}
|
||
|
||
if (diskDesc) {
|
||
if (diskDesc->DiskDescriptionSize != newDesc->DiskDescriptionSize ||
|
||
diskDesc->LogicalDiskType != newDesc->LogicalDiskType ||
|
||
diskDesc->u.Other.ThisMemberNumber !=
|
||
newDesc->u.Other.ThisMemberNumber ||
|
||
diskDesc->u.Other.NumberOfMembers !=
|
||
newDesc->u.Other.NumberOfMembers ||
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation !=
|
||
newDesc->u.Other.ByteOffsetToConfigurationInformation ||
|
||
diskDesc->u.Other.ByteOffsetToStateInformation !=
|
||
newDesc->u.Other.ByteOffsetToStateInformation) {
|
||
|
||
DeleteAncestors(diskInfo, partitionDiskId);
|
||
diskDesc = NULL;
|
||
} else {
|
||
diskDesc->DriveLetter = newDesc->DriveLetter;
|
||
}
|
||
}
|
||
|
||
if (diskDesc && diskDesc->u.Other.ByteOffsetToConfigurationInformation) {
|
||
if (diskDesc->u.Other.ByteOffsetToStateInformation) {
|
||
length = diskDesc->u.Other.ByteOffsetToStateInformation -
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation;
|
||
} else {
|
||
length = diskDesc->DiskDescriptionSize -
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation;
|
||
}
|
||
|
||
config = (PCHAR) diskDesc +
|
||
diskDesc->u.Other.ByteOffsetToConfigurationInformation;
|
||
newConfig = (PCHAR) newDesc +
|
||
newDesc->u.Other.ByteOffsetToConfigurationInformation;
|
||
|
||
if (RtlCompareMemory(config, newConfig, length) != length) {
|
||
DeleteAncestors(diskInfo, partitionDiskId);
|
||
diskDesc = NULL;
|
||
}
|
||
}
|
||
|
||
if (diskDesc && diskDesc->u.Other.ByteOffsetToStateInformation) {
|
||
length = diskDesc->DiskDescriptionSize -
|
||
diskDesc->u.Other.ByteOffsetToStateInformation;
|
||
state = (PCHAR) diskDesc +
|
||
diskDesc->u.Other.ByteOffsetToStateInformation;
|
||
newState = (PCHAR) newDesc +
|
||
newDesc->u.Other.ByteOffsetToStateInformation;
|
||
|
||
RtlCopyMemory(state, newState, length);
|
||
}
|
||
|
||
if (!GetDiskDescription(registry, diskPartition, diskDesc, &otherDesc)) {
|
||
otherDesc = NULL;
|
||
}
|
||
|
||
if (diskDesc) {
|
||
diskDesc->DriveLetter = newDesc->DriveLetter;
|
||
} else {
|
||
diskDesc = diskInfo->AddLogicalDiskDescription(newDesc);
|
||
}
|
||
|
||
if (otherDesc &&
|
||
!QueryMemberLogicalDiskId(otherDesc->LogicalDiskId,
|
||
diskPartition->FtMember)) {
|
||
|
||
diskDesc->LogicalDiskId = otherDesc->LogicalDiskId;
|
||
}
|
||
|
||
if (IsLogicalDiskComplete(diskDesc->LogicalDiskId)) {
|
||
DeleteFtRegistryInformation(registry, diskPartition);
|
||
}
|
||
|
||
RecomputeArrayOfRootLogicalDiskIds();
|
||
|
||
diskInfo->Write();
|
||
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
|
||
L"Information", REG_BINARY, registry,
|
||
registrySize);
|
||
|
||
ExFreePool(newDesc);
|
||
ExFreePool(registry);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
FT_LOGICAL_DISK_INFORMATION_SET::~FT_LOGICAL_DISK_INFORMATION_SET(
|
||
)
|
||
|
||
{
|
||
ULONG i;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
delete _arrayOfLogicalDiskInformations[i];
|
||
}
|
||
if (_arrayOfLogicalDiskInformations) {
|
||
ExFreePool(_arrayOfLogicalDiskInformations);
|
||
}
|
||
|
||
if (_arrayOfRootLogicalDiskIds) {
|
||
ExFreePool(_arrayOfRootLogicalDiskIds);
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION_SET::ReallocRootLogicalDiskIds(
|
||
IN ULONG NewNumberOfEntries
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description;
|
||
|
||
This routine reallocs the root logical disk ids buffer to contain
|
||
the given number of entries. It does not change the number of
|
||
disk ids private member, it just enlarges the buffer.
|
||
|
||
Arguments:
|
||
|
||
NewNumberOfEntries - Supplies the new size of the buffer.
|
||
|
||
Return Value:
|
||
|
||
FALSE - Failure.
|
||
|
||
TRUE - Success.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_ID newLogicalDiskIdArray;
|
||
|
||
if (NewNumberOfEntries <= _numberOfRootLogicalDisksIds) {
|
||
return TRUE;
|
||
}
|
||
|
||
newLogicalDiskIdArray = (PFT_LOGICAL_DISK_ID)
|
||
ExAllocatePool(NonPagedPool, NewNumberOfEntries*
|
||
sizeof(FT_LOGICAL_DISK_ID));
|
||
if (!newLogicalDiskIdArray) {
|
||
return FALSE;
|
||
}
|
||
|
||
if (_arrayOfRootLogicalDiskIds) {
|
||
RtlMoveMemory(newLogicalDiskIdArray, _arrayOfRootLogicalDiskIds,
|
||
_numberOfRootLogicalDisksIds*sizeof(FT_LOGICAL_DISK_ID));
|
||
ExFreePool(_arrayOfRootLogicalDiskIds);
|
||
}
|
||
|
||
_arrayOfRootLogicalDiskIds = newLogicalDiskIdArray;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
VOID
|
||
FT_LOGICAL_DISK_INFORMATION_SET::RecomputeArrayOfRootLogicalDiskIds(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine computes the array of root logical disk ids.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, j;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p, q;
|
||
|
||
_numberOfRootLogicalDisksIds = 0;
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
for (q = diskInfo->GetFirstLogicalDiskDescription(); q;
|
||
q = diskInfo->GetNextLogicalDiskDescription(q)) {
|
||
|
||
if (q->LogicalDiskType != FtPartition &&
|
||
q->u.Other.ThisMemberLogicalDiskId == p->LogicalDiskId) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!q) {
|
||
for (j = 0; j < _numberOfRootLogicalDisksIds; j++) {
|
||
if (_arrayOfRootLogicalDiskIds[j] == p->LogicalDiskId) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (j == _numberOfRootLogicalDisksIds) {
|
||
_arrayOfRootLogicalDiskIds[j] = p->LogicalDiskId;
|
||
_numberOfRootLogicalDisksIds++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
FT_LOGICAL_DISK_INFORMATION_SET::ComputeNewParentLogicalDiskIds(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
OUT PULONG NumLogicalDiskIds,
|
||
OUT PFT_LOGICAL_DISK_ID* OldLogicalDiskIds,
|
||
OUT PFT_LOGICAL_DISK_ID* NewLogicalDiskIds
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds all of the parents of the given logical disk id and
|
||
computes replacement logical disk ids for them.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
NumLogicalDiskIds - Returns the number of parents.
|
||
|
||
OldLogicalDiskIds - Returns the existing geneology for the given
|
||
logical disk id.
|
||
|
||
NewLogicalDiskIds - Returns the new geneology for the given
|
||
logical disk id.
|
||
|
||
Return Value:
|
||
|
||
FALSE - Insufficient resources.
|
||
|
||
TRUE - Success.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
ULONG n, i;
|
||
|
||
n = 1;
|
||
for (p = GetParentLogicalDiskDescription(LogicalDiskId); p;
|
||
p = GetParentLogicalDiskDescription(p->LogicalDiskId)) {
|
||
|
||
n++;
|
||
}
|
||
|
||
*NumLogicalDiskIds = n;
|
||
*OldLogicalDiskIds = (PFT_LOGICAL_DISK_ID)
|
||
ExAllocatePool(PagedPool,
|
||
n*sizeof(FT_LOGICAL_DISK_ID));
|
||
if (!*OldLogicalDiskIds) {
|
||
return FALSE;
|
||
}
|
||
|
||
*NewLogicalDiskIds = (PFT_LOGICAL_DISK_ID)
|
||
ExAllocatePool(PagedPool,
|
||
n*sizeof(FT_LOGICAL_DISK_ID));
|
||
if (!*NewLogicalDiskIds) {
|
||
ExFreePool(*OldLogicalDiskIds);
|
||
return FALSE;
|
||
}
|
||
|
||
(*OldLogicalDiskIds)[0] = LogicalDiskId;
|
||
(*NewLogicalDiskIds)[0] = GenerateNewLogicalDiskId();
|
||
|
||
i = 1;
|
||
for (p = GetParentLogicalDiskDescription(LogicalDiskId); p;
|
||
p = GetParentLogicalDiskDescription(p->LogicalDiskId)) {
|
||
|
||
(*OldLogicalDiskIds)[i] = p->LogicalDiskId;
|
||
(*NewLogicalDiskIds)[i] = GenerateNewLogicalDiskId();
|
||
i++;
|
||
}
|
||
|
||
ASSERT(i == n);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma code_seg()
|
||
#endif
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
FT_LOGICAL_DISK_INFORMATION::GetNextLogicalDiskDescription(
|
||
IN PFT_LOGICAL_DISK_DESCRIPTION CurrentDiskDescription
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the next logical disk description for a
|
||
given logical disk description.
|
||
|
||
Arguments:
|
||
|
||
CurrentDiskDescription - Supplies the current disk description.
|
||
|
||
Return Value:
|
||
|
||
The next disk description or NULL if no more disk descriptions
|
||
are present.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_LOGICAL_DISK_DESCRIPTION next;
|
||
|
||
next = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
((PCHAR) CurrentDiskDescription +
|
||
CurrentDiskDescription->DiskDescriptionSize);
|
||
|
||
if ((ULONG) ((PCHAR) next - (PCHAR) _diskBuffer) >
|
||
_length - sizeof(USHORT)) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
if ((ULONG) ((PCHAR) next - (PCHAR) _diskBuffer +
|
||
next->DiskDescriptionSize) > _length) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
if (next->DiskDescriptionSize < sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
|
||
return NULL;
|
||
}
|
||
|
||
return next;
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
FT_LOGICAL_DISK_INFORMATION_SET::GetParentLogicalDiskDescription(
|
||
IN PFT_LOGICAL_DISK_DESCRIPTION LogicalDiskDescription,
|
||
IN ULONG DiskInformationNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets the parent logical disk description.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskDescription - Supplies the child logical disk description.
|
||
|
||
DiskInformationNumber - Supplies the disk information number.
|
||
|
||
Return Value:
|
||
|
||
The parent logical disk description or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
FT_LOGICAL_DISK_ID diskId;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
diskId = LogicalDiskDescription->LogicalDiskId;
|
||
diskInfo = _arrayOfLogicalDiskInformations[DiskInformationNumber];
|
||
for (p = diskInfo->GetNextLogicalDiskDescription(LogicalDiskDescription);
|
||
p; p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskType != FtPartition &&
|
||
p->u.Other.ThisMemberLogicalDiskId == diskId) {
|
||
|
||
return p;
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
FT_LOGICAL_DISK_INFORMATION_SET::GetParentLogicalDiskDescription(
|
||
IN FT_LOGICAL_DISK_ID LogicalDiskId,
|
||
OUT PULONG DiskInformationNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets the parent logical disk description for the
|
||
given logical disk id.
|
||
|
||
Arguments:
|
||
|
||
LogicalDiskId - Supplies the logical disk id.
|
||
|
||
DiskInformationNumber - Returns the disk information number.
|
||
|
||
Return Value:
|
||
|
||
The parent logical disk description or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PFT_LOGICAL_DISK_INFORMATION diskInfo;
|
||
PFT_LOGICAL_DISK_DESCRIPTION p;
|
||
|
||
for (i = 0; i < _numberOfLogicalDiskInformations; i++) {
|
||
diskInfo = _arrayOfLogicalDiskInformations[i];
|
||
for (p = diskInfo->GetFirstLogicalDiskDescription(); p;
|
||
p = diskInfo->GetNextLogicalDiskDescription(p)) {
|
||
|
||
if (p->LogicalDiskType != FtPartition &&
|
||
p->u.Other.ThisMemberLogicalDiskId == LogicalDiskId) {
|
||
|
||
if (DiskInformationNumber) {
|
||
*DiskInformationNumber = i;
|
||
}
|
||
return p;
|
||
}
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
PFT_LOGICAL_DISK_DESCRIPTION
|
||
FT_LOGICAL_DISK_INFORMATION::GetFirstLogicalDiskDescription(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the first logical disk description in the
|
||
list.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A pointer inside the buffer for the first logical disk description or
|
||
NULL if there are no logical disk descriptions.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFT_ON_DISK_PREAMBLE preamble;
|
||
PFT_LOGICAL_DISK_DESCRIPTION diskDescription;
|
||
|
||
if (!_length) {
|
||
return NULL;
|
||
}
|
||
|
||
preamble = (PFT_ON_DISK_PREAMBLE) _diskBuffer;
|
||
if (preamble->FtOnDiskSignature != FT_ON_DISK_SIGNATURE ||
|
||
preamble->DiskDescriptionVersionNumber != FT_ON_DISK_DESCRIPTION_VERSION_NUMBER ||
|
||
preamble->ByteOffsetToFirstFtLogicalDiskDescription <
|
||
sizeof(FT_ON_DISK_PREAMBLE) ||
|
||
preamble->ByteOffsetToFirstFtLogicalDiskDescription >
|
||
_length - sizeof(ULONG)) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
diskDescription = (PFT_LOGICAL_DISK_DESCRIPTION)
|
||
((PCHAR) preamble +
|
||
preamble->ByteOffsetToFirstFtLogicalDiskDescription);
|
||
|
||
if (diskDescription->DiskDescriptionSize <
|
||
sizeof(FT_LOGICAL_DISK_DESCRIPTION)) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
if ((ULONG) ((PCHAR) diskDescription - (PCHAR) _diskBuffer +
|
||
diskDescription->DiskDescriptionSize) > _length) {
|
||
|
||
return NULL;
|
||
}
|
||
|
||
return diskDescription;
|
||
}
|