summaryrefslogtreecommitdiff
path: root/storage/class/disk/src/enum.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-04-29 09:48:49 -0700
committerDave Wilson <[email protected]>2015-04-29 10:47:29 -0700
commitd40232638faaab19de557e70a3ee938da7a35295 (patch)
tree14e61c973745949af186b7940e3a53d25322f5de /storage/class/disk/src/enum.c
parent02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff)
samples update for //build
Diffstat (limited to 'storage/class/disk/src/enum.c')
-rw-r--r--storage/class/disk/src/enum.c1313
1 files changed, 1313 insertions, 0 deletions
diff --git a/storage/class/disk/src/enum.c b/storage/class/disk/src/enum.c
new file mode 100644
index 00000000..d5521caf
--- /dev/null
+++ b/storage/class/disk/src/enum.c
@@ -0,0 +1,1313 @@
+/*++
+
+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"
+#include "ntintsafe.h"
+
+#ifdef DEBUG_USE_WPP
+#include "enum.tmh"
+#endif
+
+#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;
+ NTSTATUS status;
+
+ PAGED_CODE ();
+
+ NT_ASSERT ( LayoutEx );
+
+
+ //
+ // The only valid conversion is from an MBR extended layout structure to
+ // the old structure.
+ //
+
+ if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
+ NT_ASSERT ( FALSE );
+ return NULL;
+ }
+
+ //
+ // Use safe interger function
+ //
+
+ status = RtlULongMult(LayoutEx->PartitionCount, sizeof(PARTITION_INFORMATION), &LayoutSize);
+ if (!NT_SUCCESS(status)) {
+ return NULL;
+ }
+ status = RtlULongAdd(LayoutSize, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]),
+ &LayoutSize);
+ if (!NT_SUCCESS(status)) {
+ return NULL;
+ }
+
+ Layout = ExAllocatePoolWithTag (
+ NonPagedPoolNx,
+ 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 ();
+
+ NT_ASSERT ( PartitionEx != NULL );
+ NT_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;
+ NTSTATUS status;
+
+ PAGED_CODE ();
+
+ NT_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.
+ //
+
+ //
+ // Use safe interger function
+ //
+
+ status = RtlULongMult(Layout->PartitionCount, sizeof(PARTITION_INFORMATION_EX), &size);
+ if (!NT_SUCCESS(status)) {
+ return NULL;
+ }
+ status = RtlULongAdd(size, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]),
+ &size);
+ if (!NT_SUCCESS(status)) {
+ return NULL;
+ }
+
+ layoutEx = ExAllocatePoolWithTag(
+ NonPagedPoolNx,
+ 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;
+ PDRIVE_LAYOUT_INFORMATION_EX partitionList;
+ NTSTATUS status;
+ BOOLEAN freePartitionList = FALSE;
+
+ NT_ASSERT(commonExtension->IsFdo);
+
+ PAGED_CODE();
+
+ //
+ // If our cached partition table is valid, there is nothing to be done
+ //
+
+ if ( diskData->CachedPartitionTableValid == TRUE )
+ {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // 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(NonPagedPoolNx,
+ 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;
+
+ freePartitionList = TRUE;
+
+ status = STATUS_SUCCESS;
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (NT_SUCCESS(status)) {
+
+ diskData->UpdatePartitionRoutine(Fdo, partitionList);
+ }
+
+ DiskReleasePartitioningLock(fdoExtension);
+
+ if (freePartitionList) {
+ FREE_POOL(partitionList);
+ }
+
+ 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();
+
+ NT_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 = { 0 };
+ PDEVICE_OBJECT pdo;
+
+ //
+ // There is no PDO currently. Create one and pre-initialize it with
+ // a zero length.
+ //
+
+ tmpPartitionEntry.PartitionNumber = 1;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: Creating RM partition\n"));
+
+ status = DiskCreatePdo(Fdo,
+ 0,
+ &tmpPartitionEntry,
+ partitionStyle,
+ &pdo);
+
+ if(!NT_SUCCESS(status)) {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: error %lx creating "
+ "new PDO for RM partition\n",
+ status));
+
+ goto DiskUpdateRemovablePartitionsExit;
+ }
+
+ //
+ // 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.
+ //
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, "
+ "ordinal %d\n",
+ &pdoExtension->CommonExtension.DeviceName,
+ partitionEntry->PartitionNumber,
+ partitionOrdinal));
+
+
+ partitionEntry->PartitionNumber = 1;
+
+ pdoData->PartitionStyle = partitionStyle;
+ pdoData->PartitionOrdinal = partitionOrdinal;
+ NT_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;
+ goto DiskUpdateRemovablePartitionsExit;
+ }
+
+ //
+ // 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;
+
+DiskUpdateRemovablePartitionsExit:
+
+ //
+ // Update the parent device object
+ //
+
+ {
+ PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
+ PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
+
+ if (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;
+ }
+ }
+
+ 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) {
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal "
+ "%d\n",
+ &pdoExtension->CommonExtension.DeviceName,
+ partitionEntry->PartitionNumber,
+ partitionOrdinal));
+
+ NT_ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
+ // NT_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 {
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "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;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Deleting %wZ\n",
+ &pdoExtension->CommonExtension.DeviceName));
+
+ if (partitionStyle == PARTITION_STYLE_GPT) {
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "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.
+ //
+
+ NT_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;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "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)) {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "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.
+ //
+
+ }
+ }
+
+ //
+ // Update the parent device object
+ //
+
+ {
+ PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
+ PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
+
+ if (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;
+ }
+ }
+
+ 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)) {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskCreatePdo - Can't generate name %lx\n", status));
+ return status;
+ }
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskCreatePdo: Create device object %s\n", deviceName));
+
+ status = ClassCreateDeviceObject(Fdo->DriverObject,
+ deviceName,
+ Fdo,
+ FALSE,
+ &pdo);
+
+ if (!NT_SUCCESS(status)) {
+
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName));
+
+ FREE_POOL(deviceName);
+ return status;
+ }
+
+ FREE_POOL(deviceName);
+
+ //
+ // 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.
+ //
+
+ diskData->PartitionStyle = PartitionStyle;
+
+ 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.PartitionId;
+ diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes;
+ RtlCopyMemory (diskData->Efi.PartitionName,
+ PartitionEntry->Gpt.Name,
+ sizeof (diskData->Efi.PartitionName)
+ );
+ }
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskEnumerateDevice: Partition type is %x\n",
+ diskData->Mbr.PartitionType));
+
+ pdoExtension->CommonExtension.StartingOffset =
+ PartitionEntry->StartingOffset;
+
+ pdoExtension->CommonExtension.PartitionLength =
+ PartitionEntry->PartitionLength;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "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;
+}
+
+
+/*
+ * DiskAcquirePartitioningLock
+ *
+ * Acquire the PartitioningEvent.
+ *
+ * NOTE: This function is called by several ioctl handlers which run in user context.
+ * Because we are acquiring an exclusion object in a user thread, we have to make sure
+ * that the thread is not killed or suspended while we are holding the event.
+ * So we call KeEnterCriticalRegion/KeLeaveCriticalRegion while holding the PartitioningEvent.
+ * THEREFORE, it is VERY IMPORTANT that DiskAcquirePartitioningLock and DiskReleasePartitioningLock
+ * are called on the SAME THREAD.
+ */
+VOID
+DiskAcquirePartitioningLock(
+ IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
+ )
+{
+ PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
+
+ PAGED_CODE();
+
+ ASSERT_FDO(FdoExtension->DeviceObject);
+
+ /*
+ * Don't let user-mode thread get suspended while we are holding the partitioning lock
+ */
+ KeEnterCriticalRegion();
+
+ KeWaitForSingleObject(&(diskData->PartitioningEvent),
+ UserRequest,
+ KernelMode,
+ 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);
+
+ KeLeaveCriticalRegion();
+
+ return;
+}