1 /* 2 * PROJECT: Partition manager driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Main file 5 * COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin@reactos.org) 6 */ 7 8 /* The Partition Manager Driver in ReactOS complements disk.sys/classpnp.sys drivers 9 * (which are derived from Windows 10 drivers) so does not do exactly what Windows 2003 partmgr.sys 10 * does. Here is acts like both partition and volume manager, because volmgr.sys does not (yet) 11 * exist in ReactOS. Thus handles some IOCTL_VOLUME_*, and IOCTL_MOUNTMGR_* IOCTLs. 12 */ 13 14 #include "partmgr.h" 15 16 17 static 18 CODE_SEG("PAGE") 19 PDRIVE_LAYOUT_INFORMATION 20 PartMgrConvertExtendedToLayout( 21 _In_ CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx) 22 { 23 PDRIVE_LAYOUT_INFORMATION Layout; 24 PPARTITION_INFORMATION Partition; 25 PPARTITION_INFORMATION_EX PartitionEx; 26 27 PAGED_CODE(); 28 29 ASSERT(LayoutEx); 30 31 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) 32 { 33 ASSERT(FALSE); 34 return NULL; 35 } 36 37 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) + 38 LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION); 39 40 Layout = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR); 41 42 if (Layout == NULL) 43 { 44 return NULL; 45 } 46 47 Layout->Signature = LayoutEx->Mbr.Signature; 48 Layout->PartitionCount = LayoutEx->PartitionCount; 49 50 for (UINT32 i = 0; i < LayoutEx->PartitionCount; i++) 51 { 52 Partition = &Layout->PartitionEntry[i]; 53 PartitionEx = &LayoutEx->PartitionEntry[i]; 54 55 Partition->StartingOffset = PartitionEx->StartingOffset; 56 Partition->PartitionLength = PartitionEx->PartitionLength; 57 Partition->RewritePartition = PartitionEx->RewritePartition; 58 Partition->PartitionNumber = PartitionEx->PartitionNumber; 59 60 Partition->PartitionType = PartitionEx->Mbr.PartitionType; 61 Partition->BootIndicator = PartitionEx->Mbr.BootIndicator; 62 Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition; 63 Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors; 64 } 65 66 return Layout; 67 } 68 69 static 70 CODE_SEG("PAGE") 71 PDRIVE_LAYOUT_INFORMATION_EX 72 PartMgrConvertLayoutToExtended( 73 _In_ CONST PDRIVE_LAYOUT_INFORMATION Layout) 74 { 75 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 76 77 PAGED_CODE(); 78 79 ASSERT(Layout != NULL); 80 81 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) + 82 Layout->PartitionCount * sizeof (PARTITION_INFORMATION_EX); 83 84 layoutEx = ExAllocatePoolUninitialized(PagedPool, layoutSize, TAG_PARTMGR); 85 86 if (layoutEx == NULL) 87 { 88 return NULL; 89 } 90 91 layoutEx->PartitionStyle = PARTITION_STYLE_MBR; 92 layoutEx->PartitionCount = Layout->PartitionCount; 93 layoutEx->Mbr.Signature = Layout->Signature; 94 95 for (UINT32 i = 0; i < Layout->PartitionCount; i++) 96 { 97 PPARTITION_INFORMATION part = &Layout->PartitionEntry[i]; 98 99 layoutEx->PartitionEntry[i] = (PARTITION_INFORMATION_EX) { 100 .PartitionStyle = PARTITION_STYLE_MBR, 101 .StartingOffset = part->StartingOffset, 102 .PartitionLength = part->PartitionLength, 103 .RewritePartition = part->RewritePartition, 104 .PartitionNumber = part->PartitionNumber, 105 .Mbr = { 106 .PartitionType = part->PartitionType, 107 .BootIndicator = part->BootIndicator, 108 .RecognizedPartition = part->RecognizedPartition, 109 .HiddenSectors = part->HiddenSectors, 110 } 111 }; 112 } 113 114 return layoutEx; 115 } 116 117 /** 118 * @brief 119 * Detects whether a disk is a "super-floppy", i.e. an unpartitioned 120 * disk with only a valid VBR, as reported by IoReadPartitionTable() 121 * and IoWritePartitionTable(): 122 * only one single partition starting at offset zero and spanning the 123 * whole disk, without hidden sectors, whose type is FAT16 non-bootable. 124 * 125 * Accessing \Device\HarddiskN\Partition0 or Partition1 on such disks 126 * returns the same data. 127 * 128 * @note 129 * - Requires partitioning lock held. 130 * - Uses the cached disk partition layout. 131 **/ 132 static 133 CODE_SEG("PAGE") 134 BOOLEAN 135 PartMgrIsDiskSuperFloppy( 136 _In_ PFDO_EXTENSION FdoExtension) 137 { 138 PPARTITION_INFORMATION_EX PartitionInfo; 139 140 PAGED_CODE(); 141 142 ASSERT(FdoExtension->LayoutValid && FdoExtension->LayoutCache); 143 144 /* We must be MBR and have only one partition */ 145 ASSERT(FdoExtension->DiskData.PartitionStyle == FdoExtension->LayoutCache->PartitionStyle); 146 if (FdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_MBR) 147 return FALSE; 148 if (FdoExtension->LayoutCache->PartitionCount != 1) 149 return FALSE; 150 151 /* Get the single partition entry */ 152 PartitionInfo = FdoExtension->LayoutCache->PartitionEntry; 153 ASSERT(FdoExtension->DiskData.PartitionStyle == PartitionInfo->PartitionStyle); 154 155 /* The single partition must start at the beginning of the disk */ 156 if (!(PartitionInfo->StartingOffset.QuadPart == 0 && 157 PartitionInfo->Mbr.HiddenSectors == 0)) 158 { 159 return FALSE; 160 } 161 162 /* The disk signature is usually set to 1; warn in case it's not */ 163 ASSERT(FdoExtension->DiskData.Mbr.Signature == FdoExtension->LayoutCache->Mbr.Signature); 164 if (FdoExtension->DiskData.Mbr.Signature != 1) 165 { 166 WARN("Super-Floppy disk %lu signature %08x != 1!\n", 167 FdoExtension->DiskData.DeviceNumber, FdoExtension->DiskData.Mbr.Signature); 168 } 169 170 /* The partition must be recognized and report as FAT16 non-bootable */ 171 if ((PartitionInfo->Mbr.RecognizedPartition != TRUE) || 172 (PartitionInfo->Mbr.PartitionType != PARTITION_FAT_16) || 173 (PartitionInfo->Mbr.BootIndicator != FALSE)) 174 { 175 WARN("Super-Floppy disk %lu does not return default settings!\n" 176 " RecognizedPartition = %s, expected TRUE\n" 177 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n" 178 " BootIndicator = %s, expected FALSE\n", 179 FdoExtension->DiskData.DeviceNumber, 180 PartitionInfo->Mbr.RecognizedPartition ? "TRUE" : "FALSE", 181 PartitionInfo->Mbr.PartitionType, 182 PartitionInfo->Mbr.BootIndicator ? "TRUE" : "FALSE"); 183 } 184 185 /* The partition and disk sizes should agree */ 186 if (PartitionInfo->PartitionLength.QuadPart != FdoExtension->DiskData.DiskSize) 187 { 188 WARN("PartitionLength = %I64u is different from DiskSize = %I64u\n", 189 PartitionInfo->PartitionLength.QuadPart, FdoExtension->DiskData.DiskSize); 190 } 191 192 return TRUE; 193 } 194 195 static 196 CODE_SEG("PAGE") 197 VOID 198 PartMgrUpdatePartitionDevices( 199 _In_ PFDO_EXTENSION FdoExtension, 200 _Inout_ PDRIVE_LAYOUT_INFORMATION_EX NewLayout) 201 { 202 NTSTATUS status; 203 PSINGLE_LIST_ENTRY curEntry, prevEntry; 204 UINT32 totalPartitions = 0; 205 206 // Clear the partition numbers from the list entries 207 for (UINT32 i = 0; i < NewLayout->PartitionCount; i++) 208 { 209 NewLayout->PartitionEntry[i].PartitionNumber = 0; 210 } 211 212 // iterate over old partition list 213 prevEntry = &FdoExtension->PartitionList; 214 curEntry = FdoExtension->PartitionList.Next; 215 while (curEntry != NULL) 216 { 217 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, PARTITION_EXTENSION, ListEntry); 218 UINT32 partNumber = 0; // count detected partitions for device symlinks 219 BOOLEAN found = FALSE; 220 PPARTITION_INFORMATION_EX partEntry; 221 222 // trying to find this partition in returned layout 223 for (UINT32 i = 0; i < NewLayout->PartitionCount; i++) 224 { 225 partEntry = &NewLayout->PartitionEntry[i]; 226 227 // skip unused and container partitions 228 if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR && 229 (partEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || 230 IsContainerPartition(partEntry->Mbr.PartitionType))) 231 { 232 continue; 233 } 234 235 partNumber++; 236 237 // skip already found partitions 238 if (partEntry->PartitionNumber) 239 { 240 continue; 241 } 242 243 // skip if partitions are not equal 244 if (partEntry->StartingOffset.QuadPart != partExt->StartingOffset || 245 partEntry->PartitionLength.QuadPart != partExt->PartitionLength) 246 { 247 continue; 248 } 249 250 // found matching partition - processing it 251 found = TRUE; 252 break; 253 } 254 255 if (found) 256 { 257 // update (possibly changed) partition metadata 258 if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR) 259 { 260 partExt->Mbr.PartitionType = partEntry->Mbr.PartitionType; 261 partExt->Mbr.BootIndicator = partEntry->Mbr.BootIndicator; 262 } 263 else 264 { 265 partExt->Gpt.PartitionType = partEntry->Gpt.PartitionType; 266 partExt->Gpt.PartitionId = partEntry->Gpt.PartitionId; 267 partExt->Gpt.Attributes = partEntry->Gpt.Attributes; 268 269 RtlCopyMemory(partExt->Gpt.Name, partEntry->Gpt.Name, sizeof(partExt->Gpt.Name)); 270 } 271 272 partExt->OnDiskNumber = partNumber; 273 partEntry->PartitionNumber = partNumber; // mark it as a found one 274 totalPartitions++; 275 } 276 else 277 { 278 // detach the device from the list 279 prevEntry->Next = curEntry->Next; 280 curEntry = prevEntry; 281 partExt->Attached = FALSE; 282 283 // enumerated PDOs will receive IRP_MN_REMOVE_DEVICE 284 if (!partExt->IsEnumerated) 285 { 286 PartitionHandleRemove(partExt, TRUE); 287 } 288 } 289 290 prevEntry = curEntry; 291 curEntry = curEntry->Next; 292 } 293 294 UINT32 partNumber = 0; 295 UINT32 pdoNumber = 1; 296 297 // now looking through remaining "new" partitions 298 for (UINT32 i = 0; i < NewLayout->PartitionCount; i++) 299 { 300 PPARTITION_INFORMATION_EX partEntry = &NewLayout->PartitionEntry[i]; 301 302 // again, skip unused and container partitions 303 if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR && 304 (partEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || 305 IsContainerPartition(partEntry->Mbr.PartitionType))) 306 { 307 continue; 308 } 309 310 partNumber++; 311 312 // and skip processed partitions 313 if (partEntry->PartitionNumber != 0) 314 { 315 continue; 316 } 317 318 // find the first free PDO index 319 for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next; 320 curEntry != NULL; 321 curEntry = curEntry->Next) 322 { 323 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, 324 PARTITION_EXTENSION, 325 ListEntry); 326 327 if (partExt->DetectedNumber == pdoNumber) 328 { 329 // found a matching pdo number - restart the search 330 curEntry = FdoExtension->PartitionList.Next; 331 pdoNumber++; 332 } 333 } 334 335 partEntry->PartitionNumber = partNumber; 336 337 PDEVICE_OBJECT partitionDevice; 338 status = PartitionCreateDevice(FdoExtension->DeviceObject, 339 partEntry, 340 pdoNumber, 341 NewLayout->PartitionStyle, 342 &partitionDevice); 343 344 if (!NT_SUCCESS(status)) 345 { 346 partEntry->PartitionNumber = 0; 347 continue; 348 } 349 350 // mark partition as removable if parent device is removable 351 if (FdoExtension->LowerDevice->Characteristics & FILE_REMOVABLE_MEDIA) 352 partitionDevice->Characteristics |= FILE_REMOVABLE_MEDIA; 353 354 totalPartitions++; 355 356 // insert the structure to the partition list 357 curEntry = FdoExtension->PartitionList.Next; 358 prevEntry = NULL; 359 while (curEntry != NULL) 360 { 361 PPARTITION_EXTENSION curPart = CONTAINING_RECORD(curEntry, 362 PARTITION_EXTENSION, 363 ListEntry); 364 if (curPart->OnDiskNumber < partNumber) 365 { 366 prevEntry = curEntry; 367 curEntry = curPart->ListEntry.Next; 368 } 369 else 370 { // we found where to put the partition 371 break; 372 } 373 } 374 375 PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension; 376 377 if (prevEntry) 378 { 379 // insert after prevEntry 380 partExt->ListEntry.Next = prevEntry->Next; 381 prevEntry->Next = &partExt->ListEntry; 382 } 383 else 384 { 385 // insert at the beginning 386 partExt->ListEntry.Next = FdoExtension->PartitionList.Next; 387 FdoExtension->PartitionList.Next = &partExt->ListEntry; 388 } 389 390 partExt->Attached = TRUE; 391 } 392 393 FdoExtension->EnumeratedPartitionsTotal = totalPartitions; 394 } 395 396 /** 397 * @brief 398 * Retrieves the disk partition layout from the given disk FDO. 399 * 400 * If the disk layout cache is valid, just return it; otherwise, 401 * read the partition table layout from disk and update the cache. 402 * 403 * @note Requires partitioning lock held. 404 **/ 405 static 406 CODE_SEG("PAGE") 407 NTSTATUS 408 PartMgrGetDriveLayout( 409 _In_ PFDO_EXTENSION FdoExtension, 410 _Out_ PDRIVE_LAYOUT_INFORMATION_EX *DriveLayout) 411 { 412 PAGED_CODE(); 413 414 if (FdoExtension->LayoutValid) 415 { 416 *DriveLayout = FdoExtension->LayoutCache; 417 return STATUS_SUCCESS; 418 } 419 420 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL; 421 NTSTATUS status = IoReadPartitionTableEx(FdoExtension->LowerDevice, &layoutEx); 422 if (!NT_SUCCESS(status)) 423 return status; 424 425 if (FdoExtension->LayoutCache) 426 ExFreePool(FdoExtension->LayoutCache); 427 428 FdoExtension->LayoutCache = layoutEx; 429 FdoExtension->LayoutValid = TRUE; 430 431 FdoExtension->DiskData.PartitionStyle = layoutEx->PartitionStyle; 432 if (FdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) 433 { 434 FdoExtension->DiskData.Mbr.Signature = layoutEx->Mbr.Signature; 435 // FdoExtension->DiskData.Mbr.Checksum = geometryEx.Partition.Mbr.CheckSum; 436 } 437 else 438 { 439 FdoExtension->DiskData.Gpt.DiskId = layoutEx->Gpt.DiskId; 440 } 441 442 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension); 443 444 *DriveLayout = layoutEx; 445 return status; 446 } 447 448 static 449 CODE_SEG("PAGE") 450 NTSTATUS 451 FdoIoctlDiskGetDriveGeometryEx( 452 _In_ PFDO_EXTENSION FdoExtension, 453 _In_ PIRP Irp) 454 { 455 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 456 457 PAGED_CODE(); 458 459 // We're patching the DISK_PARTITION_INFO part of the returned structure 460 // as disk.sys doesn't really know about the partition table on a disk 461 462 PDISK_GEOMETRY_EX_INTERNAL geometryEx = Irp->AssociatedIrp.SystemBuffer; 463 ULONG outBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; 464 NTSTATUS status; 465 466 status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 467 FdoExtension->LowerDevice, 468 NULL, 469 0, 470 geometryEx, 471 outBufferLength, 472 FALSE); 473 474 if (!NT_SUCCESS(status)) 475 { 476 return status; 477 } 478 479 // if DISK_PARTITION_INFO fits the output size 480 if (outBufferLength >= FIELD_OFFSET(DISK_GEOMETRY_EX_INTERNAL, Detection)) 481 { 482 PartMgrAcquireLayoutLock(FdoExtension); 483 484 geometryEx->Partition.SizeOfPartitionInfo = sizeof(geometryEx->Partition); 485 geometryEx->Partition.PartitionStyle = FdoExtension->DiskData.PartitionStyle; 486 487 switch (geometryEx->Partition.PartitionStyle) 488 { 489 case PARTITION_STYLE_MBR: 490 geometryEx->Partition.Mbr.Signature = FdoExtension->DiskData.Mbr.Signature; 491 // checksum? 492 break; 493 494 case PARTITION_STYLE_GPT: 495 geometryEx->Partition.Gpt.DiskId = FdoExtension->DiskData.Gpt.DiskId; 496 break; 497 498 default: 499 RtlZeroMemory(&geometryEx->Partition, sizeof(geometryEx->Partition)); 500 } 501 502 PartMgrReleaseLayoutLock(FdoExtension); 503 } 504 505 // the logic is copied from disk.sys 506 Irp->IoStatus.Information = min(outBufferLength, sizeof(DISK_GEOMETRY_EX_INTERNAL)); 507 508 return status; 509 } 510 511 static 512 CODE_SEG("PAGE") 513 NTSTATUS 514 FdoIoctlDiskGetPartitionInfo( 515 _In_ PFDO_EXTENSION FdoExtension, 516 _In_ PIRP Irp) 517 { 518 PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer; 519 520 PAGED_CODE(); 521 522 if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfo))) 523 { 524 return STATUS_BUFFER_TOO_SMALL; 525 } 526 527 PartMgrAcquireLayoutLock(FdoExtension); 528 529 *partInfo = (PARTITION_INFORMATION){ 530 .PartitionType = PARTITION_ENTRY_UNUSED, 531 .StartingOffset.QuadPart = 0, 532 .PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize, 533 .HiddenSectors = 0, 534 .PartitionNumber = 0, 535 .BootIndicator = FALSE, 536 .RewritePartition = FALSE, 537 .RecognizedPartition = FALSE, 538 }; 539 540 PartMgrReleaseLayoutLock(FdoExtension); 541 542 Irp->IoStatus.Information = sizeof(*partInfo); 543 return STATUS_SUCCESS; 544 } 545 546 static 547 CODE_SEG("PAGE") 548 NTSTATUS 549 FdoIoctlDiskGetPartitionInfoEx( 550 _In_ PFDO_EXTENSION FdoExtension, 551 _In_ PIRP Irp) 552 { 553 PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer; 554 555 PAGED_CODE(); 556 557 if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfoEx))) 558 { 559 return STATUS_BUFFER_TOO_SMALL; 560 } 561 562 PartMgrAcquireLayoutLock(FdoExtension); 563 564 // most of the fields a zeroed for Partition0 565 *partInfoEx = (PARTITION_INFORMATION_EX){ 566 .PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize, 567 .PartitionStyle = FdoExtension->DiskData.PartitionStyle, 568 }; 569 570 PartMgrReleaseLayoutLock(FdoExtension); 571 572 Irp->IoStatus.Information = sizeof(*partInfoEx); 573 return STATUS_SUCCESS; 574 } 575 576 static 577 CODE_SEG("PAGE") 578 NTSTATUS 579 FdoIoctlDiskGetDriveLayout( 580 _In_ PFDO_EXTENSION FdoExtension, 581 _In_ PIRP Irp) 582 { 583 PAGED_CODE(); 584 585 PartMgrAcquireLayoutLock(FdoExtension); 586 587 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 588 NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx); 589 if (!NT_SUCCESS(status)) 590 { 591 PartMgrReleaseLayoutLock(FdoExtension); 592 return status; 593 } 594 595 // checking this value from layoutEx in case it has been changed 596 if (layoutEx->PartitionStyle != PARTITION_STYLE_MBR) 597 { 598 PartMgrReleaseLayoutLock(FdoExtension); 599 return STATUS_INVALID_DEVICE_REQUEST; 600 } 601 602 size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]); 603 size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION); 604 605 if (!VerifyIrpOutBufferSize(Irp, size)) 606 { 607 PartMgrReleaseLayoutLock(FdoExtension); 608 return STATUS_BUFFER_TOO_SMALL; 609 } 610 611 PDRIVE_LAYOUT_INFORMATION partitionList = PartMgrConvertExtendedToLayout(layoutEx); 612 613 PartMgrReleaseLayoutLock(FdoExtension); 614 615 if (partitionList == NULL) 616 { 617 Irp->IoStatus.Information = 0; 618 return STATUS_INSUFFICIENT_RESOURCES; 619 } 620 621 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, partitionList, size); 622 ExFreePoolWithTag(partitionList, TAG_PARTMGR); 623 624 Irp->IoStatus.Information = size; 625 return STATUS_SUCCESS; 626 } 627 628 static 629 CODE_SEG("PAGE") 630 NTSTATUS 631 FdoIoctlDiskGetDriveLayoutEx( 632 _In_ PFDO_EXTENSION FdoExtension, 633 _In_ PIRP Irp) 634 { 635 PAGED_CODE(); 636 637 PartMgrAcquireLayoutLock(FdoExtension); 638 639 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 640 NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx); 641 if (!NT_SUCCESS(status)) 642 { 643 PartMgrReleaseLayoutLock(FdoExtension); 644 return status; 645 } 646 647 size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]); 648 size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION_EX); 649 650 if (!VerifyIrpOutBufferSize(Irp, size)) 651 { 652 PartMgrReleaseLayoutLock(FdoExtension); 653 return STATUS_BUFFER_TOO_SMALL; 654 } 655 656 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, layoutEx, size); 657 658 PartMgrReleaseLayoutLock(FdoExtension); 659 660 Irp->IoStatus.Information = size; 661 return STATUS_SUCCESS; 662 } 663 664 static 665 CODE_SEG("PAGE") 666 NTSTATUS 667 FdoIoctlDiskSetDriveLayout( 668 _In_ PFDO_EXTENSION FdoExtension, 669 _In_ PIRP Irp) 670 { 671 PDRIVE_LAYOUT_INFORMATION layoutInfo = Irp->AssociatedIrp.SystemBuffer; 672 673 PAGED_CODE(); 674 675 if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutInfo))) 676 { 677 return STATUS_INFO_LENGTH_MISMATCH; 678 } 679 680 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]); 681 layoutSize += layoutInfo->PartitionCount * sizeof(PARTITION_INFORMATION); 682 683 if (!VerifyIrpInBufferSize(Irp, layoutSize)) 684 { 685 return STATUS_INFO_LENGTH_MISMATCH; 686 } 687 688 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = PartMgrConvertLayoutToExtended(layoutInfo); 689 690 if (layoutEx == NULL) 691 { 692 Irp->IoStatus.Information = 0; 693 return STATUS_INSUFFICIENT_RESOURCES; 694 } 695 696 PartMgrAcquireLayoutLock(FdoExtension); 697 698 // If the current disk is super-floppy but the user changes 699 // the number of partitions to > 1, fail the call. 700 if (FdoExtension->IsSuperFloppy && (layoutEx->PartitionCount > 1)) 701 { 702 PartMgrReleaseLayoutLock(FdoExtension); 703 return STATUS_INVALID_DEVICE_REQUEST; 704 } 705 706 // this in fact updates the bus relations 707 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx); 708 709 // write the partition table to the disk 710 NTSTATUS status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx); 711 if (NT_SUCCESS(status)) 712 { 713 // save the layout cache 714 if (FdoExtension->LayoutCache) 715 { 716 ExFreePool(FdoExtension->LayoutCache); 717 } 718 FdoExtension->LayoutCache = layoutEx; 719 FdoExtension->LayoutValid = TRUE; 720 721 // set updated partition numbers 722 for (UINT32 i = 0; i < layoutInfo->PartitionCount; i++) 723 { 724 PPARTITION_INFORMATION part = &layoutInfo->PartitionEntry[i]; 725 726 part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber; 727 } 728 729 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension); 730 } 731 else 732 { 733 FdoExtension->LayoutValid = FALSE; 734 } 735 736 PartMgrReleaseLayoutLock(FdoExtension); 737 738 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 739 740 // notify everyone that the disk layout has changed 741 TARGET_DEVICE_CUSTOM_NOTIFICATION notification; 742 743 notification.Event = GUID_IO_DISK_LAYOUT_CHANGE; 744 notification.Version = 1; 745 notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer); 746 notification.FileObject = NULL; 747 notification.NameBufferOffset = -1; 748 749 IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO, 750 ¬ification, 751 NULL, 752 NULL); 753 754 Irp->IoStatus.Information = layoutSize; 755 return STATUS_SUCCESS; 756 } 757 758 static 759 CODE_SEG("PAGE") 760 NTSTATUS 761 FdoIoctlDiskSetDriveLayoutEx( 762 _In_ PFDO_EXTENSION FdoExtension, 763 _In_ PIRP Irp) 764 { 765 PDRIVE_LAYOUT_INFORMATION_EX layoutEx, layoutUser = Irp->AssociatedIrp.SystemBuffer; 766 NTSTATUS status; 767 768 PAGED_CODE(); 769 770 if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutUser))) 771 { 772 return STATUS_INFO_LENGTH_MISMATCH; 773 } 774 775 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]); 776 layoutSize += layoutUser->PartitionCount * sizeof(PARTITION_INFORMATION_EX); 777 778 if (!VerifyIrpInBufferSize(Irp, layoutSize)) 779 { 780 return STATUS_INFO_LENGTH_MISMATCH; 781 } 782 783 // we need to copy the structure from the IRP input buffer 784 layoutEx = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR); 785 if (!layoutEx) 786 { 787 Irp->IoStatus.Information = 0; 788 return STATUS_INSUFFICIENT_RESOURCES; 789 } 790 791 RtlCopyMemory(layoutEx, layoutUser, layoutSize); 792 793 PartMgrAcquireLayoutLock(FdoExtension); 794 795 // If the current disk is super-floppy but the user changes either 796 // the disk type or the number of partitions to > 1, fail the call. 797 if (FdoExtension->IsSuperFloppy && 798 ((layoutEx->PartitionStyle != PARTITION_STYLE_MBR) || 799 (layoutEx->PartitionCount > 1))) 800 { 801 PartMgrReleaseLayoutLock(FdoExtension); 802 return STATUS_INVALID_DEVICE_REQUEST; 803 } 804 805 // if partition count is 0, it's the same as IOCTL_DISK_CREATE_DISK 806 if (layoutEx->PartitionCount == 0) 807 { 808 CREATE_DISK createDisk = {0}; 809 createDisk.PartitionStyle = layoutEx->PartitionStyle; 810 if (createDisk.PartitionStyle == PARTITION_STYLE_MBR) 811 { 812 createDisk.Mbr.Signature = layoutEx->Mbr.Signature; 813 } 814 else if (createDisk.PartitionStyle == PARTITION_STYLE_GPT) 815 { 816 createDisk.Gpt.DiskId = layoutEx->Gpt.DiskId; 817 } 818 819 status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk); 820 } 821 else 822 { 823 // this in fact updates the bus relations 824 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx); 825 826 // write the partition table to the disk 827 status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx); 828 if (NT_SUCCESS(status)) 829 { 830 // set updated partition numbers 831 for (UINT32 i = 0; i < layoutEx->PartitionCount; i++) 832 { 833 PPARTITION_INFORMATION_EX part = &layoutEx->PartitionEntry[i]; 834 835 part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber; 836 } 837 } 838 } 839 840 // update the layout cache 841 if (NT_SUCCESS(status)) 842 { 843 if (FdoExtension->LayoutCache) 844 { 845 ExFreePool(FdoExtension->LayoutCache); 846 } 847 FdoExtension->LayoutCache = layoutEx; 848 FdoExtension->LayoutValid = TRUE; 849 850 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension); 851 } 852 else 853 { 854 FdoExtension->LayoutValid = FALSE; 855 } 856 857 PartMgrReleaseLayoutLock(FdoExtension); 858 859 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 860 861 // notify everyone that the disk layout has changed 862 TARGET_DEVICE_CUSTOM_NOTIFICATION notification; 863 864 notification.Event = GUID_IO_DISK_LAYOUT_CHANGE; 865 notification.Version = 1; 866 notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer); 867 notification.FileObject = NULL; 868 notification.NameBufferOffset = -1; 869 870 IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO, 871 ¬ification, 872 NULL, 873 NULL); 874 875 Irp->IoStatus.Information = layoutSize; 876 return STATUS_SUCCESS; 877 } 878 879 static 880 CODE_SEG("PAGE") 881 NTSTATUS 882 FdoIoctlDiskUpdateProperties( 883 _In_ PFDO_EXTENSION FdoExtension, 884 _In_ PIRP Irp) 885 { 886 PAGED_CODE(); 887 888 PartMgrAcquireLayoutLock(FdoExtension); 889 FdoExtension->LayoutValid = FALSE; 890 PartMgrReleaseLayoutLock(FdoExtension); 891 892 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 893 return STATUS_SUCCESS; 894 } 895 896 static 897 CODE_SEG("PAGE") 898 NTSTATUS 899 FdoIoctlDiskCreateDisk( 900 _In_ PFDO_EXTENSION FdoExtension, 901 _In_ PIRP Irp) 902 { 903 PAGED_CODE(); 904 905 PCREATE_DISK createDisk = Irp->AssociatedIrp.SystemBuffer; 906 if (!VerifyIrpInBufferSize(Irp, sizeof(*createDisk))) 907 { 908 return STATUS_INFO_LENGTH_MISMATCH; 909 } 910 911 PartMgrAcquireLayoutLock(FdoExtension); 912 913 NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, createDisk); 914 915 FdoExtension->LayoutValid = FALSE; 916 PartMgrReleaseLayoutLock(FdoExtension); 917 918 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 919 return status; 920 } 921 922 static 923 CODE_SEG("PAGE") 924 NTSTATUS 925 FdoIoctlDiskDeleteDriveLayout( 926 _In_ PFDO_EXTENSION FdoExtension, 927 _In_ PIRP Irp) 928 { 929 CREATE_DISK createDisk = { .PartitionStyle = PARTITION_STYLE_RAW }; 930 931 PAGED_CODE(); 932 933 PartMgrAcquireLayoutLock(FdoExtension); 934 935 NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk); 936 937 FdoExtension->LayoutValid = FALSE; 938 PartMgrReleaseLayoutLock(FdoExtension); 939 940 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 941 return status; 942 } 943 944 static 945 CODE_SEG("PAGE") 946 NTSTATUS 947 FdoHandleStartDevice( 948 _In_ PFDO_EXTENSION FdoExtension, 949 _In_ PIRP Irp) 950 { 951 // obtain the disk device number 952 // this is not expected to change thus not in PartMgrRefreshDiskData 953 STORAGE_DEVICE_NUMBER deviceNumber; 954 NTSTATUS status = IssueSyncIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, 955 FdoExtension->LowerDevice, 956 NULL, 957 0, 958 &deviceNumber, 959 sizeof(deviceNumber), 960 FALSE); 961 if (!NT_SUCCESS(status)) 962 { 963 return status; 964 } 965 966 FdoExtension->DiskData.DeviceNumber = deviceNumber.DeviceNumber; 967 968 // register the disk interface 969 // partmgr.sys from Windows 8.1 also registers a mysterious GUID_DEVINTERFACE_HIDDEN_DISK here 970 UNICODE_STRING interfaceName; 971 status = IoRegisterDeviceInterface(FdoExtension->PhysicalDiskDO, 972 &GUID_DEVINTERFACE_DISK, 973 NULL, 974 &interfaceName); 975 976 if(!NT_SUCCESS(status)) 977 { 978 ERR("Failed to register GUID_DEVINTERFACE_DISK, status %x\n", status); 979 return status; 980 } 981 982 FdoExtension->DiskInterfaceName = interfaceName; 983 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 984 985 INFO("Disk interface %wZ\n", &interfaceName); 986 987 if (!NT_SUCCESS(status)) 988 { 989 RtlFreeUnicodeString(&interfaceName); 990 RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL); 991 } 992 993 return status; 994 } 995 996 /** 997 * @brief 998 * Refreshes all the cached disk FDO data. 999 * The geometry of the disk and its partition layout cache is updated. 1000 * 1001 * @note Requires partitioning lock held. 1002 **/ 1003 static 1004 CODE_SEG("PAGE") 1005 NTSTATUS 1006 PartMgrRefreshDiskData( 1007 _In_ PFDO_EXTENSION FdoExtension) 1008 { 1009 NTSTATUS status; 1010 1011 PAGED_CODE(); 1012 1013 // get the DiskSize and BytesPerSector 1014 DISK_GEOMETRY_EX geometryEx; 1015 status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 1016 FdoExtension->LowerDevice, 1017 NULL, 1018 0, 1019 &geometryEx, 1020 sizeof(geometryEx), 1021 FALSE); 1022 if (!NT_SUCCESS(status)) 1023 return status; 1024 1025 FdoExtension->DiskData.DiskSize = geometryEx.DiskSize.QuadPart; 1026 FdoExtension->DiskData.BytesPerSector = geometryEx.Geometry.BytesPerSector; 1027 1028 // get the partition style-related info 1029 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL; 1030 status = PartMgrGetDriveLayout(FdoExtension, &layoutEx); 1031 if (!NT_SUCCESS(status)) 1032 return status; 1033 1034 return STATUS_SUCCESS; 1035 } 1036 1037 static 1038 CODE_SEG("PAGE") 1039 NTSTATUS 1040 FdoHandleDeviceRelations( 1041 _In_ PFDO_EXTENSION FdoExtension, 1042 _In_ PIRP Irp) 1043 { 1044 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1045 DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type; 1046 1047 PAGED_CODE(); 1048 1049 if (type == BusRelations) 1050 { 1051 PartMgrAcquireLayoutLock(FdoExtension); 1052 1053 NTSTATUS status = PartMgrRefreshDiskData(FdoExtension); 1054 if (!NT_SUCCESS(status)) 1055 { 1056 PartMgrReleaseLayoutLock(FdoExtension); 1057 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1058 Irp->IoStatus.Information = 0; 1059 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1060 return Irp->IoStatus.Status; 1061 } 1062 1063 INFO("Partition style %u\n", FdoExtension->DiskData.PartitionStyle); 1064 1065 // PartMgrRefreshDiskData() calls PartMgrGetDriveLayout() inside 1066 // so we're sure here that it returns only the cached layout. 1067 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 1068 PartMgrGetDriveLayout(FdoExtension, &layoutEx); 1069 1070 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx); 1071 1072 // now fill the DeviceRelations structure 1073 TRACE("Reporting %u partitions\n", FdoExtension->EnumeratedPartitionsTotal); 1074 1075 PDEVICE_RELATIONS deviceRelations = 1076 ExAllocatePoolWithTag(PagedPool, 1077 sizeof(DEVICE_RELATIONS) 1078 + sizeof(PDEVICE_OBJECT) 1079 * (FdoExtension->EnumeratedPartitionsTotal - 1), 1080 TAG_PARTMGR); 1081 1082 if (!deviceRelations) 1083 { 1084 PartMgrReleaseLayoutLock(FdoExtension); 1085 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1086 Irp->IoStatus.Information = 0; 1087 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1088 return Irp->IoStatus.Status; 1089 } 1090 1091 deviceRelations->Count = 0; 1092 1093 PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next; 1094 while (curEntry != NULL) 1095 { 1096 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, 1097 PARTITION_EXTENSION, 1098 ListEntry); 1099 1100 // mark the PDO to know that we don't need to manually delete it 1101 partExt->IsEnumerated = TRUE; 1102 deviceRelations->Objects[deviceRelations->Count++] = partExt->DeviceObject; 1103 ObReferenceObject(partExt->DeviceObject); 1104 1105 curEntry = partExt->ListEntry.Next; 1106 } 1107 1108 ASSERT(deviceRelations->Count == FdoExtension->EnumeratedPartitionsTotal); 1109 1110 PartMgrReleaseLayoutLock(FdoExtension); 1111 1112 Irp->IoStatus.Information = (ULONG_PTR)deviceRelations; 1113 Irp->IoStatus.Status = STATUS_SUCCESS; 1114 } 1115 1116 IoSkipCurrentIrpStackLocation(Irp); 1117 return IoCallDriver(FdoExtension->LowerDevice, Irp); 1118 } 1119 1120 static 1121 CODE_SEG("PAGE") 1122 NTSTATUS 1123 FdoHandleRemoveDevice( 1124 _In_ PFDO_EXTENSION FdoExtension, 1125 _In_ PIRP Irp) 1126 { 1127 PAGED_CODE(); 1128 1129 if (FdoExtension->DiskInterfaceName.Buffer) 1130 { 1131 IoSetDeviceInterfaceState(&FdoExtension->DiskInterfaceName, FALSE); 1132 RtlFreeUnicodeString(&FdoExtension->DiskInterfaceName); 1133 RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL); 1134 } 1135 1136 // Send the IRP down the stack 1137 IoSkipCurrentIrpStackLocation(Irp); 1138 Irp->IoStatus.Status = STATUS_SUCCESS; 1139 NTSTATUS status = IoCallDriver(FdoExtension->LowerDevice, Irp); 1140 1141 IoDetachDevice(FdoExtension->LowerDevice); 1142 IoDeleteDevice(FdoExtension->DeviceObject); 1143 return status; 1144 } 1145 1146 static 1147 CODE_SEG("PAGE") 1148 NTSTATUS 1149 FdoHandleSurpriseRemoval( 1150 _In_ PFDO_EXTENSION FdoExtension, 1151 _In_ PIRP Irp) 1152 { 1153 PAGED_CODE(); 1154 1155 // all enumerated child devices should receive IRP_MN_REMOVE_DEVICE 1156 // removing only non-enumerated ones here 1157 for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next; 1158 curEntry != NULL; 1159 curEntry = curEntry->Next) 1160 { 1161 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, 1162 PARTITION_EXTENSION, 1163 ListEntry); 1164 1165 if (partExt->IsEnumerated) 1166 { 1167 PartitionHandleRemove(partExt, TRUE); 1168 } 1169 } 1170 1171 // Send the IRP down the stack 1172 IoSkipCurrentIrpStackLocation(Irp); 1173 Irp->IoStatus.Status = STATUS_SUCCESS; 1174 return IoCallDriver(FdoExtension->LowerDevice, Irp); 1175 } 1176 1177 static 1178 CODE_SEG("PAGE") 1179 NTSTATUS 1180 NTAPI 1181 PartMgrAddDevice( 1182 _In_ PDRIVER_OBJECT DriverObject, 1183 _In_ PDEVICE_OBJECT PhysicalDeviceObject) 1184 { 1185 PDEVICE_OBJECT deviceObject; 1186 1187 PAGED_CODE(); 1188 1189 NTSTATUS status = IoCreateDevice(DriverObject, 1190 sizeof(FDO_EXTENSION), 1191 0, 1192 FILE_DEVICE_BUS_EXTENDER, 1193 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 1194 FALSE, 1195 &deviceObject); 1196 1197 if (!NT_SUCCESS(status)) 1198 { 1199 ERR("Failed to create FDO 0x%x\n", status); 1200 return status; 1201 } 1202 1203 PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension; 1204 RtlZeroMemory(deviceExtension, sizeof(*deviceExtension)); 1205 1206 deviceExtension->IsFDO = TRUE; 1207 deviceExtension->DeviceObject = deviceObject; 1208 deviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject); 1209 deviceExtension->PhysicalDiskDO = PhysicalDeviceObject; 1210 KeInitializeEvent(&deviceExtension->SyncEvent, SynchronizationEvent, TRUE); 1211 1212 // the the attaching failed 1213 if (!deviceExtension->LowerDevice) 1214 { 1215 IoDeleteDevice(deviceObject); 1216 1217 return STATUS_DEVICE_REMOVED; 1218 } 1219 deviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; 1220 1221 // device is initialized 1222 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1223 1224 return STATUS_SUCCESS; 1225 } 1226 1227 static 1228 NTSTATUS 1229 NTAPI 1230 PartMgrDeviceControl( 1231 _In_ PDEVICE_OBJECT DeviceObject, 1232 _In_ PIRP Irp) 1233 { 1234 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1235 PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1236 NTSTATUS status; 1237 1238 // Note: IRP_MJ_DEVICE_CONTROL handler in the storage stack must be able to pass IOCTLs 1239 // at an IRQL higher than PASSIVE_LEVEL 1240 1241 INFO("IRP_MJ_DEVICE_CONTROL %p Irp %p IOCTL %x isFdo: %u\n", 1242 DeviceObject, Irp, ioStack->Parameters.DeviceIoControl.IoControlCode, fdoExtension->IsFDO); 1243 1244 if (!fdoExtension->IsFDO) 1245 { 1246 return PartitionHandleDeviceControl(DeviceObject, Irp); 1247 } 1248 1249 switch (ioStack->Parameters.DeviceIoControl.IoControlCode) 1250 { 1251 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 1252 status = FdoIoctlDiskGetDriveGeometryEx(fdoExtension, Irp); 1253 break; 1254 1255 case IOCTL_DISK_GET_PARTITION_INFO: 1256 status = FdoIoctlDiskGetPartitionInfo(fdoExtension, Irp); 1257 break; 1258 1259 case IOCTL_DISK_GET_PARTITION_INFO_EX: 1260 status = FdoIoctlDiskGetPartitionInfoEx(fdoExtension, Irp); 1261 break; 1262 1263 case IOCTL_DISK_GET_DRIVE_LAYOUT: 1264 status = FdoIoctlDiskGetDriveLayout(fdoExtension, Irp); 1265 break; 1266 1267 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: 1268 status = FdoIoctlDiskGetDriveLayoutEx(fdoExtension, Irp); 1269 break; 1270 1271 case IOCTL_DISK_SET_DRIVE_LAYOUT: 1272 status = FdoIoctlDiskSetDriveLayout(fdoExtension, Irp); 1273 break; 1274 1275 case IOCTL_DISK_SET_DRIVE_LAYOUT_EX: 1276 status = FdoIoctlDiskSetDriveLayoutEx(fdoExtension, Irp); 1277 break; 1278 1279 case IOCTL_DISK_UPDATE_PROPERTIES: 1280 status = FdoIoctlDiskUpdateProperties(fdoExtension, Irp); 1281 break; 1282 1283 case IOCTL_DISK_CREATE_DISK: 1284 status = FdoIoctlDiskCreateDisk(fdoExtension, Irp); 1285 break; 1286 1287 case IOCTL_DISK_DELETE_DRIVE_LAYOUT: 1288 status = FdoIoctlDiskDeleteDriveLayout(fdoExtension, Irp); 1289 break; 1290 // case IOCTL_DISK_GROW_PARTITION: // todo 1291 default: 1292 return ForwardIrpAndForget(DeviceObject, Irp); 1293 } 1294 1295 Irp->IoStatus.Status = status; 1296 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1297 return status; 1298 } 1299 1300 static 1301 CODE_SEG("PAGE") 1302 NTSTATUS 1303 NTAPI 1304 PartMgrPnp( 1305 _In_ PDEVICE_OBJECT DeviceObject, 1306 _In_ PIRP Irp) 1307 { 1308 PAGED_CODE(); 1309 1310 PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1311 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1312 1313 INFO("IRP_MJ_PNP %p Irp %p %s isFDO: %u\n", 1314 DeviceObject, Irp, GetIRPMinorFunctionString(ioStack->MinorFunction), fdoExtension->IsFDO); 1315 1316 if (!fdoExtension->IsFDO) 1317 { 1318 return PartitionHandlePnp(DeviceObject, Irp); 1319 } 1320 1321 switch (ioStack->MinorFunction) { 1322 1323 case IRP_MN_START_DEVICE: 1324 { 1325 NTSTATUS status; 1326 1327 // if this is sent to the FDO so we should forward it down the 1328 // attachment chain before we can start the FDO 1329 1330 if (!IoForwardIrpSynchronously(fdoExtension->LowerDevice, Irp)) 1331 { 1332 status = STATUS_UNSUCCESSFUL; 1333 } 1334 else 1335 { 1336 status = FdoHandleStartDevice(fdoExtension, Irp); 1337 } 1338 1339 Irp->IoStatus.Status = status; 1340 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1341 return status; 1342 } 1343 case IRP_MN_QUERY_DEVICE_RELATIONS: 1344 { 1345 return FdoHandleDeviceRelations(fdoExtension, Irp); 1346 } 1347 case IRP_MN_SURPRISE_REMOVAL: 1348 { 1349 return FdoHandleSurpriseRemoval(fdoExtension, Irp); 1350 } 1351 case IRP_MN_REMOVE_DEVICE: 1352 { 1353 return FdoHandleRemoveDevice(fdoExtension, Irp); 1354 } 1355 case IRP_MN_QUERY_STOP_DEVICE: 1356 case IRP_MN_QUERY_REMOVE_DEVICE: 1357 case IRP_MN_CANCEL_STOP_DEVICE: 1358 case IRP_MN_CANCEL_REMOVE_DEVICE: 1359 case IRP_MN_STOP_DEVICE: 1360 { 1361 Irp->IoStatus.Status = STATUS_SUCCESS; 1362 // fallthrough 1363 } 1364 default: 1365 { 1366 IoSkipCurrentIrpStackLocation(Irp); 1367 return IoCallDriver(fdoExtension->LowerDevice, Irp); 1368 } 1369 } 1370 } 1371 1372 static 1373 NTSTATUS 1374 NTAPI 1375 PartMgrReadWrite( 1376 _In_ PDEVICE_OBJECT DeviceObject, 1377 _In_ PIRP Irp) 1378 { 1379 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 1380 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1381 1382 if (!partExt->IsFDO) 1383 { 1384 if (!partExt->IsEnumerated) 1385 { 1386 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 1387 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1388 return STATUS_DEVICE_DOES_NOT_EXIST; 1389 } 1390 else 1391 { 1392 ioStack->Parameters.Read.ByteOffset.QuadPart += partExt->StartingOffset; 1393 } 1394 } 1395 1396 IoSkipCurrentIrpStackLocation(Irp); 1397 return IoCallDriver(partExt->LowerDevice, Irp); 1398 } 1399 1400 DRIVER_DISPATCH PartMgrPower; 1401 NTSTATUS 1402 NTAPI 1403 PartMgrPower( 1404 _In_ PDEVICE_OBJECT DeviceObject, 1405 _In_ PIRP Irp) 1406 { 1407 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 1408 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1409 1410 PoStartNextPowerIrp(Irp); 1411 1412 if (!partExt->IsFDO) 1413 { 1414 NTSTATUS status; 1415 1416 if (!partExt->IsEnumerated) 1417 { 1418 status = STATUS_DEVICE_DOES_NOT_EXIST; 1419 } 1420 else if (ioStack->MinorFunction == IRP_MN_SET_POWER || 1421 ioStack->MinorFunction == IRP_MN_QUERY_POWER) 1422 { 1423 status = STATUS_SUCCESS; 1424 } 1425 else 1426 { 1427 status = Irp->IoStatus.Status; 1428 } 1429 1430 Irp->IoStatus.Status = status; 1431 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1432 return status; 1433 } 1434 else 1435 { 1436 IoSkipCurrentIrpStackLocation(Irp); 1437 return PoCallDriver(partExt->LowerDevice, Irp); 1438 } 1439 } 1440 1441 DRIVER_DISPATCH PartMgrShutdownFlush; 1442 NTSTATUS 1443 NTAPI 1444 PartMgrShutdownFlush( 1445 _In_ PDEVICE_OBJECT DeviceObject, 1446 _In_ PIRP Irp) 1447 { 1448 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 1449 PDEVICE_OBJECT lowerDevice; 1450 1451 // forward to the partition0 device in both cases 1452 if (!partExt->IsFDO) 1453 { 1454 if (!partExt->IsEnumerated) 1455 { 1456 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 1457 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1458 return STATUS_DEVICE_DOES_NOT_EXIST; 1459 } 1460 else 1461 { 1462 PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension; 1463 lowerDevice = fdoExtension->LowerDevice; 1464 } 1465 } 1466 else 1467 { 1468 lowerDevice = partExt->LowerDevice; 1469 } 1470 1471 IoSkipCurrentIrpStackLocation(Irp); 1472 return IoCallDriver(lowerDevice, Irp); 1473 } 1474 1475 CODE_SEG("PAGE") 1476 VOID 1477 NTAPI 1478 PartMgrUnload( 1479 _In_ PDRIVER_OBJECT DriverObject) 1480 { 1481 1482 } 1483 1484 CODE_SEG("INIT") 1485 NTSTATUS 1486 NTAPI 1487 DriverEntry( 1488 _In_ PDRIVER_OBJECT DriverObject, 1489 _In_ PUNICODE_STRING RegistryPath) 1490 { 1491 DriverObject->DriverUnload = PartMgrUnload; 1492 DriverObject->DriverExtension->AddDevice = PartMgrAddDevice; 1493 DriverObject->MajorFunction[IRP_MJ_CREATE] = ForwardIrpAndForget; 1494 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ForwardIrpAndForget; 1495 DriverObject->MajorFunction[IRP_MJ_READ] = PartMgrReadWrite; 1496 DriverObject->MajorFunction[IRP_MJ_WRITE] = PartMgrReadWrite; 1497 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PartMgrDeviceControl; 1498 DriverObject->MajorFunction[IRP_MJ_PNP] = PartMgrPnp; 1499 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = PartMgrShutdownFlush; 1500 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = PartMgrShutdownFlush; 1501 DriverObject->MajorFunction[IRP_MJ_POWER] = PartMgrPower; 1502 1503 return STATUS_SUCCESS; 1504 } 1505