1249 lines
32 KiB
C
1249 lines
32 KiB
C
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||
|
||
Module Name:
|
||
|
||
pnp.c
|
||
|
||
Abstract:
|
||
|
||
SCSI disk class driver
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "disk.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
|
||
#pragma alloc_text(PAGE, DiskConvertExtendedToLayout)
|
||
#pragma alloc_text(PAGE, DiskConvertPartitionToExtended)
|
||
#pragma alloc_text(PAGE, DiskConvertLayoutToExtended)
|
||
#pragma alloc_text(PAGE, DiskCreatePdo)
|
||
#pragma alloc_text(PAGE, DiskEnumerateDevice)
|
||
#pragma alloc_text(PAGE, DiskUpdateRemovablePartitions)
|
||
#pragma alloc_text(PAGE, DiskUpdatePartitions)
|
||
#pragma alloc_text(PAGE, DiskCreatePdo)
|
||
|
||
#endif
|
||
|
||
PDRIVE_LAYOUT_INFORMATION
|
||
DiskConvertExtendedToLayout(
|
||
IN CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
|
||
)
|
||
{
|
||
ULONG i;
|
||
ULONG LayoutSize;
|
||
PDRIVE_LAYOUT_INFORMATION Layout;
|
||
PPARTITION_INFORMATION Partition;
|
||
PPARTITION_INFORMATION_EX PartitionEx;
|
||
|
||
PAGED_CODE ();
|
||
|
||
ASSERT ( LayoutEx );
|
||
|
||
|
||
//
|
||
// The only valid conversion is from an MBR extended layout structure to
|
||
// the old structure.
|
||
//
|
||
|
||
if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
|
||
ASSERT ( FALSE );
|
||
return NULL;
|
||
}
|
||
|
||
LayoutSize = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
|
||
LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
|
||
|
||
Layout = ExAllocatePoolWithTag (
|
||
NonPagedPool,
|
||
LayoutSize,
|
||
DISK_TAG_PART_LIST
|
||
);
|
||
|
||
if ( Layout == NULL ) {
|
||
return NULL;
|
||
}
|
||
|
||
Layout->Signature = LayoutEx->Mbr.Signature;
|
||
Layout->PartitionCount = LayoutEx->PartitionCount;
|
||
|
||
for (i = 0; i < LayoutEx->PartitionCount; i++) {
|
||
|
||
Partition = &Layout->PartitionEntry[i];
|
||
PartitionEx = &LayoutEx->PartitionEntry[i];
|
||
|
||
Partition->StartingOffset = PartitionEx->StartingOffset;
|
||
Partition->PartitionLength = PartitionEx->PartitionLength;
|
||
Partition->RewritePartition = PartitionEx->RewritePartition;
|
||
Partition->PartitionNumber = PartitionEx->PartitionNumber;
|
||
|
||
Partition->PartitionType = PartitionEx->Mbr.PartitionType;
|
||
Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
|
||
Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
|
||
Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
|
||
}
|
||
|
||
return Layout;
|
||
}
|
||
|
||
VOID
|
||
DiskConvertPartitionToExtended(
|
||
IN PPARTITION_INFORMATION Partition,
|
||
OUT PPARTITION_INFORMATION_EX PartitionEx
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Convert a PARTITION_INFORMATION structure to a PARTITION_INFORMATION_EX
|
||
structure.
|
||
|
||
Arguments:
|
||
|
||
Partition - A pointer to the PARTITION_INFORMATION structure to convert.
|
||
|
||
PartitionEx - A pointer to a buffer where the converted
|
||
PARTITION_INFORMATION_EX structure is to be stored.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE ();
|
||
|
||
ASSERT ( PartitionEx != NULL );
|
||
ASSERT ( Partition != NULL );
|
||
|
||
PartitionEx->PartitionStyle = PARTITION_STYLE_MBR;
|
||
PartitionEx->StartingOffset = Partition->StartingOffset;
|
||
PartitionEx->PartitionLength = Partition->PartitionLength;
|
||
PartitionEx->RewritePartition = Partition->RewritePartition;
|
||
PartitionEx->PartitionNumber = Partition->PartitionNumber;
|
||
|
||
PartitionEx->Mbr.PartitionType = Partition->PartitionType;
|
||
PartitionEx->Mbr.BootIndicator = Partition->BootIndicator;
|
||
PartitionEx->Mbr.RecognizedPartition = Partition->RecognizedPartition;
|
||
PartitionEx->Mbr.HiddenSectors = Partition->HiddenSectors;
|
||
}
|
||
|
||
|
||
PDRIVE_LAYOUT_INFORMATION_EX
|
||
DiskConvertLayoutToExtended(
|
||
IN CONST PDRIVE_LAYOUT_INFORMATION Layout
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Convert a DRIVE_LAYOUT_INFORMATION structure into a
|
||
DRIVE_LAYOUT_INFORMATION_EX structure.
|
||
|
||
Arguments:
|
||
|
||
Layout - The source DRIVE_LAYOUT_INFORMATION structure.
|
||
|
||
Return Values:
|
||
|
||
The resultant DRIVE_LAYOUT_INFORMATION_EX structure. This buffer must
|
||
be freed by the callee using ExFreePool.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
ULONG size;
|
||
PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
|
||
|
||
PAGED_CODE ();
|
||
|
||
ASSERT ( Layout != NULL );
|
||
|
||
|
||
//
|
||
// Allocate enough space for a DRIVE_LAYOUT_INFORMATION_EX structure
|
||
// plus as many PARTITION_INFORMATION_EX structures as are in the
|
||
// source array.
|
||
//
|
||
|
||
size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
|
||
Layout->PartitionCount * sizeof ( PARTITION_INFORMATION_EX );
|
||
|
||
layoutEx = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
size,
|
||
DISK_TAG_PART_LIST
|
||
);
|
||
|
||
if ( layoutEx == NULL ) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Convert the disk information.
|
||
//
|
||
|
||
layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
|
||
layoutEx->PartitionCount = Layout->PartitionCount;
|
||
layoutEx->Mbr.Signature = Layout->Signature;
|
||
|
||
for (i = 0; i < Layout->PartitionCount; i++) {
|
||
|
||
//
|
||
// Convert each entry.
|
||
//
|
||
|
||
DiskConvertPartitionToExtended (
|
||
&Layout->PartitionEntry[i],
|
||
&layoutEx->PartitionEntry[i]
|
||
);
|
||
}
|
||
|
||
return layoutEx;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DiskEnumerateDevice(
|
||
IN PDEVICE_OBJECT Fdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by the class driver to update the PDO list off
|
||
of this FDO. The disk driver also calls it internally to re-create
|
||
device objects.
|
||
|
||
This routine will read the partition table and create new PDO objects as
|
||
necessary. PDO's that no longer exist will be pulled out of the PDO list
|
||
so that pnp will destroy them.
|
||
|
||
Arguments:
|
||
|
||
Fdo - a pointer to the FDO being re-enumerated
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
|
||
{
|
||
PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
|
||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
||
|
||
PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
|
||
|
||
PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
|
||
|
||
PDEVICE_OBJECT pdo = NULL;
|
||
|
||
ULONG numberListElements = 0;
|
||
|
||
PDRIVE_LAYOUT_INFORMATION_EX partitionList;
|
||
|
||
NTSTATUS status;
|
||
|
||
ASSERT(commonExtension->IsFdo);
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Update our image of the size of the drive. This may be necessary if
|
||
// the drive size is extended or we just released a reservation to
|
||
// ensure the kernel doesn't reject the partition table.
|
||
//
|
||
|
||
DiskReadDriveCapacity(Fdo);
|
||
|
||
//
|
||
// Lock out anyone else trying to repartition the disk.
|
||
//
|
||
|
||
DiskAcquirePartitioningLock(fdoExtension);
|
||
|
||
//
|
||
// Create objects for all the partitions on the device.
|
||
//
|
||
|
||
status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionList);
|
||
|
||
//
|
||
// If the I/O read partition table failed and this is a removable device,
|
||
// then fix up the partition list to make it look like there is one
|
||
// zero length partition.
|
||
//
|
||
|
||
if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
|
||
Fdo->Characteristics & FILE_REMOVABLE_MEDIA) {
|
||
|
||
SIZE_T partitionListSize;
|
||
|
||
//
|
||
// Remember whether the drive is ready.
|
||
//
|
||
|
||
diskData->ReadyStatus = status;
|
||
|
||
//
|
||
// Allocate and zero a partition list.
|
||
//
|
||
|
||
partitionListSize =
|
||
FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
|
||
|
||
partitionList = ExAllocatePoolWithTag(NonPagedPool,
|
||
partitionListSize,
|
||
DISK_TAG_PART_LIST);
|
||
|
||
if (partitionList != NULL) {
|
||
|
||
RtlZeroMemory( partitionList, partitionListSize );
|
||
|
||
//
|
||
// Set the partition count to one and the status to success
|
||
// so one device object will be created. Set the partition type
|
||
// to a bogus value.
|
||
//
|
||
|
||
partitionList->PartitionStyle = PARTITION_STYLE_MBR;
|
||
partitionList->PartitionCount = 1;
|
||
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
diskData->UpdatePartitionRoutine(Fdo, partitionList);
|
||
|
||
//
|
||
// Record disk signature.
|
||
//
|
||
|
||
if (partitionList->PartitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
diskData->PartitionStyle = PARTITION_STYLE_MBR;
|
||
diskData->Mbr.Signature = partitionList->Mbr.Signature;
|
||
|
||
} else {
|
||
|
||
diskData->PartitionStyle = PARTITION_STYLE_GPT;
|
||
diskData->Efi.DiskId = partitionList->Gpt.DiskId;
|
||
}
|
||
}
|
||
|
||
DiskReleasePartitioningLock(fdoExtension);
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
} // end DiskEnumerateDevice()
|
||
|
||
|
||
VOID
|
||
DiskUpdateRemovablePartitions(
|
||
IN PDEVICE_OBJECT Fdo,
|
||
IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by the class DLL to update the PDO list off of this
|
||
FDO. The disk driver also calls it internally to re-create device objects.
|
||
|
||
This routine will read the partition table and update the size of the
|
||
single partition device object which always exists for removable devices.
|
||
|
||
Arguments:
|
||
|
||
Fdo - a pointer to the FDO being reenumerated.
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
||
|
||
PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
|
||
|
||
ULONG partitionCount;
|
||
|
||
ULONG partitionNumber;
|
||
ULONG partitionOrdinal = 0;
|
||
ULONG newPartitionNumber;
|
||
|
||
PDISK_DATA pdoData;
|
||
NTSTATUS status;
|
||
|
||
PPARTITION_INFORMATION_EX partitionEntry;
|
||
PARTITION_STYLE partitionStyle;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT(Fdo->Characteristics & FILE_REMOVABLE_MEDIA);
|
||
|
||
partitionStyle = PartitionList->PartitionStyle;
|
||
partitionCount = PartitionList->PartitionCount;
|
||
|
||
for(partitionNumber = 0;
|
||
partitionNumber < partitionCount;
|
||
partitionNumber++) {
|
||
|
||
partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
|
||
|
||
partitionEntry->PartitionNumber = 0;
|
||
}
|
||
|
||
//
|
||
// Get exclusive access to the child list while repartitioning.
|
||
//
|
||
|
||
ClassAcquireChildLock(fdoExtension);
|
||
|
||
//
|
||
// Removable media should never have more than one PDO.
|
||
//
|
||
|
||
pdoExtension = fdoExtension->CommonExtension.ChildList;
|
||
|
||
if(pdoExtension == NULL) {
|
||
|
||
PARTITION_INFORMATION_EX tmpPartitionEntry;
|
||
PDEVICE_OBJECT pdo;
|
||
|
||
//
|
||
// There is no PDO currently. Create one and pre-initialize it with
|
||
// a zero length.
|
||
//
|
||
|
||
RtlZeroMemory(&tmpPartitionEntry, sizeof(tmpPartitionEntry));
|
||
|
||
tmpPartitionEntry.PartitionNumber = 1;
|
||
|
||
DebugPrint((1, "DiskUpdateRemovablePartitions: Creating RM partition\n"));
|
||
|
||
status = DiskCreatePdo(Fdo,
|
||
0,
|
||
&tmpPartitionEntry,
|
||
partitionStyle,
|
||
&pdo);
|
||
|
||
if(!NT_SUCCESS(status)) {
|
||
|
||
DebugPrint((1, "DiskUpdateRemovablePartitions: error %lx creating "
|
||
"new PDO for RM partition\n",
|
||
status));
|
||
|
||
ClassReleaseChildLock(fdoExtension);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// mark the new device as enumerated
|
||
//
|
||
|
||
pdoExtension = pdo->DeviceExtension;
|
||
pdoExtension->IsMissing = FALSE;
|
||
|
||
}
|
||
|
||
pdoData = pdoExtension->CommonExtension.DriverData;
|
||
|
||
//
|
||
// Search the partition list for a valid entry. We're looking for a
|
||
// primary partition since we only support the one.
|
||
//
|
||
|
||
for(partitionNumber = 0;
|
||
partitionNumber < partitionCount;
|
||
partitionNumber++) {
|
||
|
||
partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
|
||
|
||
|
||
//
|
||
// Is this partition interesting?
|
||
//
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
if(partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
|
||
IsContainerPartition(partitionEntry->Mbr.PartitionType)) {
|
||
|
||
continue;
|
||
}
|
||
}
|
||
|
||
partitionOrdinal++;
|
||
|
||
//
|
||
// We have found the first and thus only partition allowed on
|
||
// this disk. Update the information in the PDO to match the new
|
||
// partition.
|
||
//
|
||
DebugPrint((1, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, "
|
||
"ordinal %d\n",
|
||
&pdoExtension->CommonExtension.DeviceName,
|
||
partitionEntry->PartitionNumber,
|
||
partitionOrdinal));
|
||
|
||
|
||
partitionEntry->PartitionNumber = 1;
|
||
|
||
pdoData->PartitionStyle = partitionStyle;
|
||
pdoData->PartitionOrdinal = partitionOrdinal;
|
||
ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
|
||
|
||
pdoExtension->CommonExtension.StartingOffset =
|
||
partitionEntry->StartingOffset;
|
||
|
||
pdoExtension->CommonExtension.PartitionLength =
|
||
partitionEntry->PartitionLength;
|
||
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
|
||
pdoData->Mbr.BootIndicator = partitionEntry->Mbr.BootIndicator;
|
||
|
||
|
||
//
|
||
// If this partition is being re-written then update the type
|
||
// information as well
|
||
//
|
||
|
||
if (partitionEntry->RewritePartition) {
|
||
pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
|
||
}
|
||
|
||
} else {
|
||
|
||
pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
|
||
pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
|
||
pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
|
||
|
||
RtlCopyMemory(
|
||
pdoData->Efi.PartitionName,
|
||
partitionEntry->Gpt.Name,
|
||
sizeof (pdoData->Efi.PartitionName)
|
||
);
|
||
}
|
||
|
||
//
|
||
// Mark this one as found
|
||
//
|
||
|
||
pdoExtension->IsMissing = FALSE;
|
||
ClassReleaseChildLock(fdoExtension);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// No interesting partition was found.
|
||
//
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
pdoData->Mbr.HiddenSectors = 0;
|
||
pdoData->Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
|
||
|
||
} else {
|
||
|
||
RtlZeroMemory (&pdoData->Efi,
|
||
sizeof (pdoData->Efi)
|
||
);
|
||
}
|
||
|
||
pdoExtension->CommonExtension.StartingOffset.QuadPart = 0;
|
||
pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
|
||
|
||
ClassReleaseChildLock(fdoExtension);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
DiskUpdatePartitions(
|
||
IN PDEVICE_OBJECT Fdo,
|
||
IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will synchronize the information held in the partition list
|
||
with the device objects hanging off this Fdo. Any new partition objects
|
||
will be created, any non-existant ones will be marked as un-enumerated.
|
||
|
||
This will be done in several stages:
|
||
|
||
* Clear state (partition number) from every entry in the partition
|
||
list
|
||
|
||
* Set IsMissing flag on every child of this FDO
|
||
|
||
* For each child of the FDO:
|
||
if a matching partition exists in the partition list,
|
||
update the partition number in the table, update the
|
||
ordinal in the object and mark the object as enumerated
|
||
|
||
* For each un-enumerated device object
|
||
zero out the partition information to invalidate the device
|
||
delete the symbolic link if any
|
||
|
||
* For each un-matched entry in the partition list:
|
||
create a new partition object
|
||
update the partition number in the list entry
|
||
create a new symbolic link if necessary
|
||
|
||
Arguments:
|
||
|
||
Fdo - a pointer to the functional device object this partition list is for
|
||
|
||
PartitionList - a pointer to the partition list being updated
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
||
|
||
PPHYSICAL_DEVICE_EXTENSION oldChildList = NULL;
|
||
PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
|
||
|
||
ULONG partitionCount;
|
||
|
||
ULONG partitionNumber;
|
||
ULONG partitionOrdinal;
|
||
ULONG newPartitionNumber;
|
||
|
||
PPARTITION_INFORMATION_EX partitionEntry;
|
||
PDISK_DATA pdoData;
|
||
PARTITION_STYLE partitionStyle;
|
||
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get exclusive access to the child list.
|
||
//
|
||
|
||
ClassAcquireChildLock(fdoExtension);
|
||
|
||
partitionStyle = PartitionList->PartitionStyle;
|
||
|
||
partitionCount = PartitionList->PartitionCount;
|
||
|
||
//
|
||
// Pull all the child device objects off the children list. We'll
|
||
// add them back later.
|
||
//
|
||
|
||
oldChildList = fdoExtension->CommonExtension.ChildList;
|
||
fdoExtension->CommonExtension.ChildList = NULL;
|
||
|
||
//
|
||
// Clear the partition numbers from the list entries
|
||
//
|
||
|
||
for(partitionNumber = 0;
|
||
partitionNumber < partitionCount;
|
||
partitionNumber++) {
|
||
|
||
partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
|
||
partitionEntry->PartitionNumber = 0;
|
||
}
|
||
|
||
//
|
||
// Now match each child partition to it's entry (if any) in the partition
|
||
// list.
|
||
//
|
||
|
||
while(oldChildList != NULL) {
|
||
|
||
pdoExtension = oldChildList;
|
||
pdoData = pdoExtension->CommonExtension.DriverData;
|
||
|
||
//
|
||
// Check all partition entries for a match on offset and length
|
||
//
|
||
|
||
partitionOrdinal = 0;
|
||
|
||
for(partitionNumber = 0;
|
||
partitionNumber < partitionCount;
|
||
partitionNumber++) {
|
||
|
||
partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
|
||
|
||
//
|
||
// Is this an interesting partition entry?
|
||
//
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
|
||
(IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
|
||
|
||
continue;
|
||
}
|
||
}
|
||
|
||
partitionOrdinal++;
|
||
|
||
if(partitionEntry->PartitionNumber) {
|
||
|
||
//
|
||
// This partition has already been found - skip it
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Let's see if the partition information matches
|
||
//
|
||
|
||
if(partitionEntry->StartingOffset.QuadPart !=
|
||
pdoExtension->CommonExtension.StartingOffset.QuadPart) {
|
||
continue;
|
||
}
|
||
|
||
if(partitionEntry->PartitionLength.QuadPart !=
|
||
pdoExtension->CommonExtension.PartitionLength.QuadPart) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Yep - it matches. Update the information in the entry
|
||
//
|
||
|
||
partitionEntry->PartitionNumber = pdoExtension->CommonExtension.PartitionNumber;
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
|
||
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
if(partitionNumber != partitionCount) {
|
||
|
||
DebugPrint((1, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal "
|
||
"%d\n",
|
||
&pdoExtension->CommonExtension.DeviceName,
|
||
partitionEntry->PartitionNumber,
|
||
partitionOrdinal));
|
||
|
||
ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
|
||
// ASSERT(pdoExtension->CommonExtension.PartitionLength.QuadPart != 0);
|
||
|
||
pdoData->PartitionStyle = partitionStyle;
|
||
|
||
//
|
||
// we found a match - update the information in the device object
|
||
// extension and driverdata
|
||
//
|
||
|
||
pdoData->PartitionOrdinal = partitionOrdinal;
|
||
|
||
//
|
||
// If this partition is being re-written then update the type
|
||
// information as well
|
||
//
|
||
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
if(partitionEntry->RewritePartition) {
|
||
pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
|
||
}
|
||
|
||
} else {
|
||
|
||
DebugPrint((1, "DiskUpdatePartitions: EFI Partition %ws\n",
|
||
pdoData->Efi.PartitionName
|
||
));
|
||
|
||
pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
|
||
pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
|
||
pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
|
||
|
||
RtlCopyMemory(
|
||
pdoData->Efi.PartitionName,
|
||
partitionEntry->Gpt.Name,
|
||
sizeof (pdoData->Efi.PartitionName)
|
||
);
|
||
}
|
||
|
||
//
|
||
// Mark this one as found.
|
||
//
|
||
|
||
pdoExtension->IsMissing = FALSE;
|
||
|
||
//
|
||
// Pull it out of the old child list and add it into the
|
||
// real one.
|
||
//
|
||
|
||
oldChildList = pdoExtension->CommonExtension.ChildList;
|
||
|
||
pdoExtension->CommonExtension.ChildList =
|
||
fdoExtension->CommonExtension.ChildList;
|
||
|
||
fdoExtension->CommonExtension.ChildList = pdoExtension;
|
||
|
||
} else {
|
||
|
||
PDEVICE_OBJECT nextPdo;
|
||
|
||
DebugPrint ((1, "DiskUpdatePartitions: Deleting %wZ\n",
|
||
&pdoExtension->CommonExtension.DeviceName));
|
||
|
||
if (partitionStyle == PARTITION_STYLE_GPT) {
|
||
|
||
DebugPrint ((1, "DiskUpdatePartitions: EFI Partition %ws\n",
|
||
pdoData->Efi.PartitionName
|
||
));
|
||
}
|
||
//
|
||
// no matching entry in the partition list - throw this partition
|
||
// object away
|
||
//
|
||
|
||
pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
|
||
|
||
//
|
||
// grab a pointer to the next child before we mark this one as
|
||
// missing since missing devices could vanish at any time.
|
||
//
|
||
|
||
oldChildList = pdoExtension->CommonExtension.ChildList;
|
||
pdoExtension->CommonExtension.ChildList = (PVOID) -1;
|
||
|
||
//
|
||
// Now tell the class driver that this child is "missing" - this
|
||
// will cause it to be deleted.
|
||
//
|
||
|
||
|
||
ClassMarkChildMissing(pdoExtension, FALSE);
|
||
}
|
||
}
|
||
|
||
//
|
||
// At this point the old child list had best be empty.
|
||
//
|
||
|
||
ASSERT(oldChildList == NULL);
|
||
|
||
//
|
||
// Iterate through the partition entries and create any partition
|
||
// objects that don't already exist
|
||
//
|
||
|
||
partitionOrdinal = 0;
|
||
newPartitionNumber = 0;
|
||
|
||
for(partitionNumber = 0;
|
||
partitionNumber < partitionCount;
|
||
partitionNumber++) {
|
||
|
||
PDEVICE_OBJECT pdo;
|
||
|
||
partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
|
||
|
||
//
|
||
// Is this partition interesting
|
||
//
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
|
||
(IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
|
||
|
||
continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Increment the count of interesting partitions
|
||
//
|
||
|
||
partitionOrdinal++;
|
||
newPartitionNumber++;
|
||
|
||
//
|
||
// Has this already been matched
|
||
//
|
||
|
||
if(partitionEntry->PartitionNumber == 0) {
|
||
|
||
LONG i;
|
||
|
||
//
|
||
// find the first safe partition number for this device
|
||
//
|
||
|
||
for(i = 0; i < (LONG) partitionCount; i++) {
|
||
|
||
|
||
PPARTITION_INFORMATION_EX tmp = &(PartitionList->PartitionEntry[i]);
|
||
|
||
if (partitionStyle == PARTITION_STYLE_MBR) {
|
||
if (tmp->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
|
||
IsContainerPartition(tmp->Mbr.PartitionType)) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if(tmp->PartitionNumber == newPartitionNumber) {
|
||
|
||
//
|
||
// Found a matching partition number - increment the count
|
||
// and restart the scan.
|
||
//
|
||
|
||
newPartitionNumber++;
|
||
i = -1;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Assign this partition a partition number
|
||
//
|
||
|
||
partitionEntry->PartitionNumber = newPartitionNumber;
|
||
|
||
DebugPrint((1, "DiskUpdatePartitions: Found new partition #%d, ord %d "
|
||
"starting at %#016I64x and running for %#016I64x\n",
|
||
partitionEntry->PartitionNumber,
|
||
partitionOrdinal,
|
||
partitionEntry->StartingOffset.QuadPart,
|
||
partitionEntry->PartitionLength.QuadPart));
|
||
|
||
ClassReleaseChildLock(fdoExtension);
|
||
|
||
status = DiskCreatePdo(Fdo,
|
||
partitionOrdinal,
|
||
partitionEntry,
|
||
partitionStyle,
|
||
&pdo);
|
||
|
||
ClassAcquireChildLock(fdoExtension);
|
||
|
||
if(!NT_SUCCESS(status)) {
|
||
|
||
DebugPrint((1, "DiskUpdatePartitions: error %lx creating "
|
||
"new PDO for partition ordinal %d, number %d\n",
|
||
status,
|
||
partitionOrdinal,
|
||
partitionEntry->PartitionNumber));
|
||
|
||
//
|
||
// don't increment the partition number - we'll try to reuse
|
||
// it for the next child.
|
||
//
|
||
|
||
partitionEntry->PartitionNumber = 0;
|
||
newPartitionNumber--;
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// mark the new device as enumerated
|
||
//
|
||
|
||
pdoExtension = pdo->DeviceExtension;
|
||
pdoExtension->IsMissing = FALSE;
|
||
|
||
//
|
||
// This number's taken already - try to scanning the partition
|
||
// table more than once for a new number.
|
||
//
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// ISSUE - 2000/02/09 - math: Review.
|
||
// Is PartitionStyle the only field that needs updating?
|
||
//
|
||
|
||
{
|
||
PCOMMON_DEVICE_EXTENSION commonExtension;
|
||
PDISK_DATA diskData;
|
||
|
||
commonExtension = Fdo->DeviceExtension;
|
||
diskData = (PDISK_DATA)(commonExtension->DriverData);
|
||
|
||
diskData->PartitionStyle = partitionStyle;
|
||
}
|
||
|
||
ClassReleaseChildLock(fdoExtension);
|
||
return;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DiskCreatePdo(
|
||
IN PDEVICE_OBJECT Fdo,
|
||
IN ULONG PartitionOrdinal,
|
||
IN PPARTITION_INFORMATION_EX PartitionEntry,
|
||
IN PARTITION_STYLE PartitionStyle,
|
||
OUT PDEVICE_OBJECT *Pdo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will create and initialize a new partition device object
|
||
(PDO) and insert it into the FDO partition list.
|
||
|
||
Arguments:
|
||
|
||
Fdo - a pointer to the functional device object this PDO will be a child
|
||
of
|
||
|
||
PartitionOrdinal - the partition ordinal for this PDO
|
||
|
||
PartitionEntry - the partition information for this device object
|
||
|
||
PartitionStyle - what style of partition table entry PartitionEntry is;
|
||
currently either MBR or EFI
|
||
|
||
Pdo - a location to store the pdo pointer upon successful completion
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
|
||
{
|
||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
||
|
||
PDEVICE_OBJECT pdo = NULL;
|
||
PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
|
||
|
||
PUCHAR deviceName = NULL;
|
||
|
||
PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
|
||
|
||
ULONG numberListElements;
|
||
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Create partition object and set up partition parameters.
|
||
//
|
||
|
||
status = DiskGenerateDeviceName(FALSE,
|
||
fdoExtension->DeviceNumber,
|
||
PartitionEntry->PartitionNumber,
|
||
&PartitionEntry->StartingOffset,
|
||
&PartitionEntry->PartitionLength,
|
||
&deviceName);
|
||
|
||
if(!NT_SUCCESS(status)) {
|
||
|
||
DebugPrint((1, "DiskCreatePdo - Can't generate name %lx\n", status));
|
||
return status;
|
||
}
|
||
|
||
DebugPrint((2, "DiskCreatePdo: Create device object %s\n", deviceName));
|
||
|
||
status = ClassCreateDeviceObject(Fdo->DriverObject,
|
||
deviceName,
|
||
Fdo,
|
||
FALSE,
|
||
&pdo);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
DebugPrint((1, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName));
|
||
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Set up device extension fields.
|
||
//
|
||
|
||
pdoExtension = pdo->DeviceExtension;
|
||
|
||
//
|
||
// Set up device object fields.
|
||
//
|
||
|
||
SET_FLAG(pdo->Flags, DO_DIRECT_IO);
|
||
|
||
pdo->StackSize = (CCHAR)
|
||
pdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1;
|
||
|
||
//
|
||
// Get pointer to new disk data.
|
||
//
|
||
|
||
diskData = (PDISK_DATA) pdoExtension->CommonExtension.DriverData;
|
||
|
||
//
|
||
// Set the alignment requirements for the device based on the
|
||
// host adapter requirements
|
||
//
|
||
|
||
if (Fdo->AlignmentRequirement > pdo->AlignmentRequirement) {
|
||
pdo->AlignmentRequirement = Fdo->AlignmentRequirement;
|
||
}
|
||
|
||
if (fdoExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
|
||
numberListElements = 30;
|
||
} else {
|
||
numberListElements = 8;
|
||
}
|
||
|
||
//
|
||
// Build the lookaside list for srb's for this partition based on
|
||
// whether the adapter and disk can do tagged queueing. Don't bother to
|
||
// check the status - this can't fail when called for a PDO.
|
||
//
|
||
|
||
ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) pdoExtension,
|
||
numberListElements);
|
||
|
||
//
|
||
// Set the sense-data pointer in the device extension.
|
||
//
|
||
|
||
diskData->PartitionOrdinal = PartitionOrdinal;
|
||
pdoExtension->CommonExtension.PartitionNumber = PartitionEntry->PartitionNumber;
|
||
|
||
//
|
||
// Initialize relevant data.
|
||
//
|
||
|
||
if (PartitionStyle == PARTITION_STYLE_MBR) {
|
||
|
||
diskData->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType;
|
||
diskData->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator;
|
||
diskData->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors;
|
||
|
||
} else {
|
||
|
||
diskData->Efi.PartitionType = PartitionEntry->Gpt.PartitionType;
|
||
diskData->Efi.PartitionId = PartitionEntry->Gpt.PartitionType;
|
||
diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes;
|
||
RtlCopyMemory (diskData->Efi.PartitionName,
|
||
PartitionEntry->Gpt.Name,
|
||
sizeof (diskData->Efi.PartitionName)
|
||
);
|
||
}
|
||
|
||
DebugPrint((2, "DiskEnumerateDevice: Partition type is %x\n",
|
||
diskData->Mbr.PartitionType));
|
||
|
||
pdoExtension->CommonExtension.StartingOffset =
|
||
PartitionEntry->StartingOffset;
|
||
|
||
pdoExtension->CommonExtension.PartitionLength =
|
||
PartitionEntry->PartitionLength;
|
||
|
||
|
||
DebugPrint((1, "DiskCreatePdo: hidden sectors value for pdo %#p set to %#x\n",
|
||
pdo,
|
||
diskData->Mbr.HiddenSectors));
|
||
|
||
//
|
||
// Check for removable media support.
|
||
//
|
||
|
||
if (fdoExtension->DeviceDescriptor->RemovableMedia) {
|
||
SET_FLAG(pdo->Characteristics, FILE_REMOVABLE_MEDIA);
|
||
}
|
||
|
||
pdoExtension->CommonExtension.DeviceObject = pdo;
|
||
|
||
CLEAR_FLAG(pdo->Flags, DO_DEVICE_INITIALIZING);
|
||
|
||
*Pdo = pdo;
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
VOID
|
||
DiskAcquirePartitioningLock(
|
||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||
)
|
||
{
|
||
PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT_FDO(FdoExtension->DeviceObject);
|
||
|
||
KeWaitForSingleObject(&(diskData->PartitioningEvent),
|
||
UserRequest,
|
||
UserMode,
|
||
FALSE,
|
||
NULL);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
DiskReleasePartitioningLock(
|
||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||
)
|
||
{
|
||
PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT_FDO(FdoExtension->DeviceObject);
|
||
|
||
KeSetEvent(&(diskData->PartitioningEvent), IO_NO_INCREMENT, FALSE);
|
||
return;
|
||
}
|