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 if (!NT_SUCCESS(status)) 344 { 345 partEntry->PartitionNumber = 0; 346 continue; 347 } 348 349 // mark partition as removable if parent device is removable 350 if (FdoExtension->LowerDevice->Characteristics & FILE_REMOVABLE_MEDIA) 351 partitionDevice->Characteristics |= FILE_REMOVABLE_MEDIA; 352 353 totalPartitions++; 354 355 // insert the structure to the partition list 356 curEntry = FdoExtension->PartitionList.Next; 357 prevEntry = NULL; 358 while (curEntry != NULL) 359 { 360 PPARTITION_EXTENSION curPart = CONTAINING_RECORD(curEntry, 361 PARTITION_EXTENSION, 362 ListEntry); 363 if (curPart->OnDiskNumber < partNumber) 364 { 365 prevEntry = curEntry; 366 curEntry = curPart->ListEntry.Next; 367 } 368 else 369 { // we found where to put the partition 370 break; 371 } 372 } 373 374 PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension; 375 376 if (prevEntry) 377 { 378 // insert after prevEntry 379 partExt->ListEntry.Next = prevEntry->Next; 380 prevEntry->Next = &partExt->ListEntry; 381 } 382 else 383 { 384 // insert at the beginning 385 partExt->ListEntry.Next = FdoExtension->PartitionList.Next; 386 FdoExtension->PartitionList.Next = &partExt->ListEntry; 387 } 388 389 partExt->Attached = TRUE; 390 } 391 392 FdoExtension->EnumeratedPartitionsTotal = totalPartitions; 393 } 394 395 /** 396 * @brief 397 * Retrieves the disk partition layout from the given disk FDO. 398 * 399 * If the disk layout cache is valid, just return it; otherwise, 400 * read the partition table layout from disk and update the cache. 401 * 402 * @note Requires partitioning lock held. 403 **/ 404 static 405 CODE_SEG("PAGE") 406 NTSTATUS 407 PartMgrGetDriveLayout( 408 _In_ PFDO_EXTENSION FdoExtension, 409 _Out_ PDRIVE_LAYOUT_INFORMATION_EX *DriveLayout) 410 { 411 PAGED_CODE(); 412 413 if (FdoExtension->LayoutValid) 414 { 415 *DriveLayout = FdoExtension->LayoutCache; 416 return STATUS_SUCCESS; 417 } 418 419 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL; 420 NTSTATUS status = IoReadPartitionTableEx(FdoExtension->LowerDevice, &layoutEx); 421 if (!NT_SUCCESS(status)) 422 return status; 423 424 if (FdoExtension->LayoutCache) 425 ExFreePool(FdoExtension->LayoutCache); 426 427 FdoExtension->LayoutCache = layoutEx; 428 FdoExtension->LayoutValid = TRUE; 429 430 FdoExtension->DiskData.PartitionStyle = layoutEx->PartitionStyle; 431 if (FdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) 432 { 433 FdoExtension->DiskData.Mbr.Signature = layoutEx->Mbr.Signature; 434 // FdoExtension->DiskData.Mbr.Checksum = geometryEx.Partition.Mbr.CheckSum; 435 } 436 else 437 { 438 FdoExtension->DiskData.Gpt.DiskId = layoutEx->Gpt.DiskId; 439 } 440 441 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension); 442 443 *DriveLayout = layoutEx; 444 return status; 445 } 446 447 static 448 CODE_SEG("PAGE") 449 NTSTATUS 450 FdoIoctlDiskGetDriveGeometryEx( 451 _In_ PFDO_EXTENSION FdoExtension, 452 _In_ PIRP Irp) 453 { 454 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 455 456 PAGED_CODE(); 457 458 // We're patching the DISK_PARTITION_INFO part of the returned structure 459 // as disk.sys doesn't really know about the partition table on a disk 460 461 PDISK_GEOMETRY_EX_INTERNAL geometryEx = Irp->AssociatedIrp.SystemBuffer; 462 ULONG outBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength; 463 NTSTATUS status; 464 465 status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 466 FdoExtension->LowerDevice, 467 NULL, 468 0, 469 geometryEx, 470 outBufferLength, 471 FALSE); 472 473 if (!NT_SUCCESS(status)) 474 { 475 return status; 476 } 477 478 // if DISK_PARTITION_INFO fits the output size 479 if (outBufferLength >= FIELD_OFFSET(DISK_GEOMETRY_EX_INTERNAL, Detection)) 480 { 481 PartMgrAcquireLayoutLock(FdoExtension); 482 483 geometryEx->Partition.SizeOfPartitionInfo = sizeof(geometryEx->Partition); 484 geometryEx->Partition.PartitionStyle = FdoExtension->DiskData.PartitionStyle; 485 486 switch (geometryEx->Partition.PartitionStyle) 487 { 488 case PARTITION_STYLE_MBR: 489 geometryEx->Partition.Mbr.Signature = FdoExtension->DiskData.Mbr.Signature; 490 // checksum? 491 break; 492 493 case PARTITION_STYLE_GPT: 494 geometryEx->Partition.Gpt.DiskId = FdoExtension->DiskData.Gpt.DiskId; 495 break; 496 497 default: 498 RtlZeroMemory(&geometryEx->Partition, sizeof(geometryEx->Partition)); 499 } 500 501 PartMgrReleaseLayoutLock(FdoExtension); 502 } 503 504 // the logic is copied from disk.sys 505 Irp->IoStatus.Information = min(outBufferLength, sizeof(DISK_GEOMETRY_EX_INTERNAL)); 506 507 return status; 508 } 509 510 static 511 CODE_SEG("PAGE") 512 NTSTATUS 513 FdoIoctlDiskGetPartitionInfo( 514 _In_ PFDO_EXTENSION FdoExtension, 515 _In_ PIRP Irp) 516 { 517 PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer; 518 519 PAGED_CODE(); 520 521 if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfo))) 522 { 523 return STATUS_BUFFER_TOO_SMALL; 524 } 525 526 PartMgrAcquireLayoutLock(FdoExtension); 527 528 *partInfo = (PARTITION_INFORMATION){ 529 .PartitionType = PARTITION_ENTRY_UNUSED, 530 .StartingOffset.QuadPart = 0, 531 .PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize, 532 .HiddenSectors = 0, 533 .PartitionNumber = 0, 534 .BootIndicator = FALSE, 535 .RewritePartition = FALSE, 536 .RecognizedPartition = FALSE, 537 }; 538 539 PartMgrReleaseLayoutLock(FdoExtension); 540 541 Irp->IoStatus.Information = sizeof(*partInfo); 542 return STATUS_SUCCESS; 543 } 544 545 static 546 CODE_SEG("PAGE") 547 NTSTATUS 548 FdoIoctlDiskGetPartitionInfoEx( 549 _In_ PFDO_EXTENSION FdoExtension, 550 _In_ PIRP Irp) 551 { 552 PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer; 553 554 PAGED_CODE(); 555 556 if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfoEx))) 557 { 558 return STATUS_BUFFER_TOO_SMALL; 559 } 560 561 PartMgrAcquireLayoutLock(FdoExtension); 562 563 // most of the fields a zeroed for Partition0 564 *partInfoEx = (PARTITION_INFORMATION_EX){ 565 .PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize, 566 .PartitionStyle = FdoExtension->DiskData.PartitionStyle, 567 }; 568 569 PartMgrReleaseLayoutLock(FdoExtension); 570 571 Irp->IoStatus.Information = sizeof(*partInfoEx); 572 return STATUS_SUCCESS; 573 } 574 575 static 576 CODE_SEG("PAGE") 577 NTSTATUS 578 FdoIoctlDiskGetDriveLayout( 579 _In_ PFDO_EXTENSION FdoExtension, 580 _In_ PIRP Irp) 581 { 582 PAGED_CODE(); 583 584 PartMgrAcquireLayoutLock(FdoExtension); 585 586 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 587 NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx); 588 if (!NT_SUCCESS(status)) 589 { 590 PartMgrReleaseLayoutLock(FdoExtension); 591 return status; 592 } 593 594 // checking this value from layoutEx in case it has been changed 595 if (layoutEx->PartitionStyle != PARTITION_STYLE_MBR) 596 { 597 PartMgrReleaseLayoutLock(FdoExtension); 598 return STATUS_INVALID_DEVICE_REQUEST; 599 } 600 601 size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]); 602 size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION); 603 604 if (!VerifyIrpOutBufferSize(Irp, size)) 605 { 606 PartMgrReleaseLayoutLock(FdoExtension); 607 return STATUS_BUFFER_TOO_SMALL; 608 } 609 610 PDRIVE_LAYOUT_INFORMATION partitionList = PartMgrConvertExtendedToLayout(layoutEx); 611 612 PartMgrReleaseLayoutLock(FdoExtension); 613 614 if (partitionList == NULL) 615 { 616 Irp->IoStatus.Information = 0; 617 return STATUS_INSUFFICIENT_RESOURCES; 618 } 619 620 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, partitionList, size); 621 ExFreePoolWithTag(partitionList, TAG_PARTMGR); 622 623 Irp->IoStatus.Information = size; 624 return STATUS_SUCCESS; 625 } 626 627 static 628 CODE_SEG("PAGE") 629 NTSTATUS 630 FdoIoctlDiskGetDriveLayoutEx( 631 _In_ PFDO_EXTENSION FdoExtension, 632 _In_ PIRP Irp) 633 { 634 PAGED_CODE(); 635 636 PartMgrAcquireLayoutLock(FdoExtension); 637 638 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 639 NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx); 640 if (!NT_SUCCESS(status)) 641 { 642 PartMgrReleaseLayoutLock(FdoExtension); 643 return status; 644 } 645 646 size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]); 647 size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION_EX); 648 649 if (!VerifyIrpOutBufferSize(Irp, size)) 650 { 651 PartMgrReleaseLayoutLock(FdoExtension); 652 return STATUS_BUFFER_TOO_SMALL; 653 } 654 655 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, layoutEx, size); 656 657 PartMgrReleaseLayoutLock(FdoExtension); 658 659 Irp->IoStatus.Information = size; 660 return STATUS_SUCCESS; 661 } 662 663 static 664 CODE_SEG("PAGE") 665 NTSTATUS 666 FdoIoctlDiskSetDriveLayout( 667 _In_ PFDO_EXTENSION FdoExtension, 668 _In_ PIRP Irp) 669 { 670 PDRIVE_LAYOUT_INFORMATION layoutInfo = Irp->AssociatedIrp.SystemBuffer; 671 672 PAGED_CODE(); 673 674 if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutInfo))) 675 { 676 return STATUS_INFO_LENGTH_MISMATCH; 677 } 678 679 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]); 680 layoutSize += layoutInfo->PartitionCount * sizeof(PARTITION_INFORMATION); 681 682 if (!VerifyIrpInBufferSize(Irp, layoutSize)) 683 { 684 return STATUS_INFO_LENGTH_MISMATCH; 685 } 686 687 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = PartMgrConvertLayoutToExtended(layoutInfo); 688 689 if (layoutEx == NULL) 690 { 691 Irp->IoStatus.Information = 0; 692 return STATUS_INSUFFICIENT_RESOURCES; 693 } 694 695 PartMgrAcquireLayoutLock(FdoExtension); 696 697 // If the current disk is super-floppy but the user changes 698 // the number of partitions to > 1, fail the call. 699 if (FdoExtension->IsSuperFloppy && (layoutEx->PartitionCount > 1)) 700 { 701 PartMgrReleaseLayoutLock(FdoExtension); 702 return STATUS_INVALID_DEVICE_REQUEST; 703 } 704 705 // this in fact updates the bus relations 706 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx); 707 708 // write the partition table to the disk 709 NTSTATUS status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx); 710 if (NT_SUCCESS(status)) 711 { 712 // save the layout cache 713 if (FdoExtension->LayoutCache) 714 { 715 ExFreePool(FdoExtension->LayoutCache); 716 } 717 FdoExtension->LayoutCache = layoutEx; 718 FdoExtension->LayoutValid = TRUE; 719 720 // set updated partition numbers 721 for (UINT32 i = 0; i < layoutInfo->PartitionCount; i++) 722 { 723 PPARTITION_INFORMATION part = &layoutInfo->PartitionEntry[i]; 724 725 part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber; 726 } 727 728 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension); 729 } 730 else 731 { 732 FdoExtension->LayoutValid = FALSE; 733 } 734 735 PartMgrReleaseLayoutLock(FdoExtension); 736 737 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 738 739 // notify everyone that the disk layout has changed 740 TARGET_DEVICE_CUSTOM_NOTIFICATION notification; 741 742 notification.Event = GUID_IO_DISK_LAYOUT_CHANGE; 743 notification.Version = 1; 744 notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer); 745 notification.FileObject = NULL; 746 notification.NameBufferOffset = -1; 747 748 IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO, 749 ¬ification, 750 NULL, 751 NULL); 752 753 Irp->IoStatus.Information = layoutSize; 754 return STATUS_SUCCESS; 755 } 756 757 static 758 CODE_SEG("PAGE") 759 NTSTATUS 760 FdoIoctlDiskSetDriveLayoutEx( 761 _In_ PFDO_EXTENSION FdoExtension, 762 _In_ PIRP Irp) 763 { 764 PDRIVE_LAYOUT_INFORMATION_EX layoutEx, layoutUser = Irp->AssociatedIrp.SystemBuffer; 765 NTSTATUS status; 766 767 PAGED_CODE(); 768 769 if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutUser))) 770 { 771 return STATUS_INFO_LENGTH_MISMATCH; 772 } 773 774 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]); 775 layoutSize += layoutUser->PartitionCount * sizeof(PARTITION_INFORMATION_EX); 776 777 if (!VerifyIrpInBufferSize(Irp, layoutSize)) 778 { 779 return STATUS_INFO_LENGTH_MISMATCH; 780 } 781 782 // we need to copy the structure from the IRP input buffer 783 layoutEx = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR); 784 if (!layoutEx) 785 { 786 Irp->IoStatus.Information = 0; 787 return STATUS_INSUFFICIENT_RESOURCES; 788 } 789 790 RtlCopyMemory(layoutEx, layoutUser, layoutSize); 791 792 PartMgrAcquireLayoutLock(FdoExtension); 793 794 // If the current disk is super-floppy but the user changes either 795 // the disk type or the number of partitions to > 1, fail the call. 796 if (FdoExtension->IsSuperFloppy && 797 ((layoutEx->PartitionStyle != PARTITION_STYLE_MBR) || 798 (layoutEx->PartitionCount > 1))) 799 { 800 PartMgrReleaseLayoutLock(FdoExtension); 801 return STATUS_INVALID_DEVICE_REQUEST; 802 } 803 804 // if partition count is 0, it's the same as IOCTL_DISK_CREATE_DISK 805 if (layoutEx->PartitionCount == 0) 806 { 807 CREATE_DISK createDisk = {0}; 808 createDisk.PartitionStyle = layoutEx->PartitionStyle; 809 if (createDisk.PartitionStyle == PARTITION_STYLE_MBR) 810 { 811 createDisk.Mbr.Signature = layoutEx->Mbr.Signature; 812 } 813 else if (createDisk.PartitionStyle == PARTITION_STYLE_GPT) 814 { 815 createDisk.Gpt.DiskId = layoutEx->Gpt.DiskId; 816 } 817 818 status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk); 819 } 820 else 821 { 822 // this in fact updates the bus relations 823 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx); 824 825 // write the partition table to the disk 826 status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx); 827 if (NT_SUCCESS(status)) 828 { 829 // set updated partition numbers 830 for (UINT32 i = 0; i < layoutEx->PartitionCount; i++) 831 { 832 PPARTITION_INFORMATION_EX part = &layoutEx->PartitionEntry[i]; 833 834 part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber; 835 } 836 } 837 } 838 839 // update the layout cache 840 if (NT_SUCCESS(status)) 841 { 842 if (FdoExtension->LayoutCache) 843 { 844 ExFreePool(FdoExtension->LayoutCache); 845 } 846 FdoExtension->LayoutCache = layoutEx; 847 FdoExtension->LayoutValid = TRUE; 848 849 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension); 850 } 851 else 852 { 853 FdoExtension->LayoutValid = FALSE; 854 } 855 856 PartMgrReleaseLayoutLock(FdoExtension); 857 858 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 859 860 // notify everyone that the disk layout has changed 861 TARGET_DEVICE_CUSTOM_NOTIFICATION notification; 862 863 notification.Event = GUID_IO_DISK_LAYOUT_CHANGE; 864 notification.Version = 1; 865 notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer); 866 notification.FileObject = NULL; 867 notification.NameBufferOffset = -1; 868 869 IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO, 870 ¬ification, 871 NULL, 872 NULL); 873 874 Irp->IoStatus.Information = layoutSize; 875 return STATUS_SUCCESS; 876 } 877 878 static 879 CODE_SEG("PAGE") 880 NTSTATUS 881 FdoIoctlDiskUpdateProperties( 882 _In_ PFDO_EXTENSION FdoExtension, 883 _In_ PIRP Irp) 884 { 885 PAGED_CODE(); 886 887 PartMgrAcquireLayoutLock(FdoExtension); 888 FdoExtension->LayoutValid = FALSE; 889 PartMgrReleaseLayoutLock(FdoExtension); 890 891 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 892 return STATUS_SUCCESS; 893 } 894 895 static 896 CODE_SEG("PAGE") 897 NTSTATUS 898 FdoIoctlDiskCreateDisk( 899 _In_ PFDO_EXTENSION FdoExtension, 900 _In_ PIRP Irp) 901 { 902 PAGED_CODE(); 903 904 PCREATE_DISK createDisk = Irp->AssociatedIrp.SystemBuffer; 905 if (!VerifyIrpInBufferSize(Irp, sizeof(*createDisk))) 906 { 907 return STATUS_INFO_LENGTH_MISMATCH; 908 } 909 910 PartMgrAcquireLayoutLock(FdoExtension); 911 912 NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, createDisk); 913 914 FdoExtension->LayoutValid = FALSE; 915 PartMgrReleaseLayoutLock(FdoExtension); 916 917 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 918 return status; 919 } 920 921 static 922 CODE_SEG("PAGE") 923 NTSTATUS 924 FdoIoctlDiskDeleteDriveLayout( 925 _In_ PFDO_EXTENSION FdoExtension, 926 _In_ PIRP Irp) 927 { 928 CREATE_DISK createDisk = { .PartitionStyle = PARTITION_STYLE_RAW }; 929 930 PAGED_CODE(); 931 932 PartMgrAcquireLayoutLock(FdoExtension); 933 934 NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk); 935 936 FdoExtension->LayoutValid = FALSE; 937 PartMgrReleaseLayoutLock(FdoExtension); 938 939 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations); 940 return status; 941 } 942 943 static 944 CODE_SEG("PAGE") 945 NTSTATUS 946 FdoHandleStartDevice( 947 _In_ PFDO_EXTENSION FdoExtension, 948 _In_ PIRP Irp) 949 { 950 // Obtain the disk device number. 951 // It is not expected to change, thus not in PartMgrRefreshDiskData(). 952 STORAGE_DEVICE_NUMBER deviceNumber; 953 NTSTATUS status = IssueSyncIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, 954 FdoExtension->LowerDevice, 955 NULL, 956 0, 957 &deviceNumber, 958 sizeof(deviceNumber), 959 FALSE); 960 if (!NT_SUCCESS(status)) 961 { 962 return status; 963 } 964 965 FdoExtension->DiskData.DeviceNumber = deviceNumber.DeviceNumber; 966 967 // Register the disk interface. 968 // partmgr.sys from Windows 8.1 also registers a mysterious GUID_DEVINTERFACE_HIDDEN_DISK here. 969 UNICODE_STRING interfaceName; 970 status = IoRegisterDeviceInterface(FdoExtension->PhysicalDiskDO, 971 &GUID_DEVINTERFACE_DISK, 972 NULL, 973 &interfaceName); 974 if(!NT_SUCCESS(status)) 975 { 976 ERR("Failed to register GUID_DEVINTERFACE_DISK, status %x\n", status); 977 return status; 978 } 979 980 INFO("Disk interface %wZ\n", &interfaceName); 981 FdoExtension->DiskInterfaceName = interfaceName; 982 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 983 if (!NT_SUCCESS(status)) 984 { 985 RtlFreeUnicodeString(&interfaceName); 986 RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL); 987 } 988 989 return status; 990 } 991 992 /** 993 * @brief 994 * Refreshes all the cached disk FDO data. 995 * The geometry of the disk and its partition layout cache is updated. 996 * 997 * @note Requires partitioning lock held. 998 **/ 999 static 1000 CODE_SEG("PAGE") 1001 NTSTATUS 1002 PartMgrRefreshDiskData( 1003 _In_ PFDO_EXTENSION FdoExtension) 1004 { 1005 NTSTATUS status; 1006 1007 PAGED_CODE(); 1008 1009 // get the DiskSize and BytesPerSector 1010 DISK_GEOMETRY_EX geometryEx; 1011 status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 1012 FdoExtension->LowerDevice, 1013 NULL, 1014 0, 1015 &geometryEx, 1016 sizeof(geometryEx), 1017 FALSE); 1018 if (!NT_SUCCESS(status)) 1019 return status; 1020 1021 FdoExtension->DiskData.DiskSize = geometryEx.DiskSize.QuadPart; 1022 FdoExtension->DiskData.BytesPerSector = geometryEx.Geometry.BytesPerSector; 1023 1024 // get the partition style-related info 1025 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL; 1026 status = PartMgrGetDriveLayout(FdoExtension, &layoutEx); 1027 if (!NT_SUCCESS(status)) 1028 return status; 1029 1030 return STATUS_SUCCESS; 1031 } 1032 1033 static 1034 CODE_SEG("PAGE") 1035 NTSTATUS 1036 FdoHandleDeviceRelations( 1037 _In_ PFDO_EXTENSION FdoExtension, 1038 _In_ PIRP Irp) 1039 { 1040 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1041 DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type; 1042 1043 PAGED_CODE(); 1044 1045 if (type == BusRelations) 1046 { 1047 PartMgrAcquireLayoutLock(FdoExtension); 1048 1049 NTSTATUS status = PartMgrRefreshDiskData(FdoExtension); 1050 if (!NT_SUCCESS(status)) 1051 { 1052 PartMgrReleaseLayoutLock(FdoExtension); 1053 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1054 Irp->IoStatus.Information = 0; 1055 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1056 return Irp->IoStatus.Status; 1057 } 1058 1059 INFO("Partition style %u\n", FdoExtension->DiskData.PartitionStyle); 1060 1061 // PartMgrRefreshDiskData() calls PartMgrGetDriveLayout() inside 1062 // so we're sure here that it returns only the cached layout. 1063 PDRIVE_LAYOUT_INFORMATION_EX layoutEx; 1064 PartMgrGetDriveLayout(FdoExtension, &layoutEx); 1065 1066 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx); 1067 1068 // now fill the DeviceRelations structure 1069 TRACE("Reporting %u partitions\n", FdoExtension->EnumeratedPartitionsTotal); 1070 1071 PDEVICE_RELATIONS deviceRelations = 1072 ExAllocatePoolWithTag(PagedPool, 1073 sizeof(DEVICE_RELATIONS) 1074 + sizeof(PDEVICE_OBJECT) 1075 * (FdoExtension->EnumeratedPartitionsTotal - 1), 1076 TAG_PARTMGR); 1077 1078 if (!deviceRelations) 1079 { 1080 PartMgrReleaseLayoutLock(FdoExtension); 1081 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 1082 Irp->IoStatus.Information = 0; 1083 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1084 return Irp->IoStatus.Status; 1085 } 1086 1087 deviceRelations->Count = 0; 1088 1089 PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next; 1090 while (curEntry != NULL) 1091 { 1092 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, 1093 PARTITION_EXTENSION, 1094 ListEntry); 1095 1096 // mark the PDO to know that we don't need to manually delete it 1097 partExt->IsEnumerated = TRUE; 1098 deviceRelations->Objects[deviceRelations->Count++] = partExt->DeviceObject; 1099 ObReferenceObject(partExt->DeviceObject); 1100 1101 curEntry = partExt->ListEntry.Next; 1102 } 1103 1104 ASSERT(deviceRelations->Count == FdoExtension->EnumeratedPartitionsTotal); 1105 1106 PartMgrReleaseLayoutLock(FdoExtension); 1107 1108 Irp->IoStatus.Information = (ULONG_PTR)deviceRelations; 1109 Irp->IoStatus.Status = STATUS_SUCCESS; 1110 } 1111 1112 IoSkipCurrentIrpStackLocation(Irp); 1113 return IoCallDriver(FdoExtension->LowerDevice, Irp); 1114 } 1115 1116 static 1117 CODE_SEG("PAGE") 1118 NTSTATUS 1119 FdoHandleRemoveDevice( 1120 _In_ PFDO_EXTENSION FdoExtension, 1121 _In_ PIRP Irp) 1122 { 1123 PAGED_CODE(); 1124 1125 if (FdoExtension->DiskInterfaceName.Buffer) 1126 { 1127 IoSetDeviceInterfaceState(&FdoExtension->DiskInterfaceName, FALSE); 1128 RtlFreeUnicodeString(&FdoExtension->DiskInterfaceName); 1129 RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL); 1130 } 1131 1132 // Send the IRP down the stack 1133 IoSkipCurrentIrpStackLocation(Irp); 1134 Irp->IoStatus.Status = STATUS_SUCCESS; 1135 NTSTATUS status = IoCallDriver(FdoExtension->LowerDevice, Irp); 1136 1137 IoDetachDevice(FdoExtension->LowerDevice); 1138 IoDeleteDevice(FdoExtension->DeviceObject); 1139 return status; 1140 } 1141 1142 static 1143 CODE_SEG("PAGE") 1144 NTSTATUS 1145 FdoHandleSurpriseRemoval( 1146 _In_ PFDO_EXTENSION FdoExtension, 1147 _In_ PIRP Irp) 1148 { 1149 PAGED_CODE(); 1150 1151 // all enumerated child devices should receive IRP_MN_REMOVE_DEVICE 1152 // removing only non-enumerated ones here 1153 for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next; 1154 curEntry != NULL; 1155 curEntry = curEntry->Next) 1156 { 1157 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, 1158 PARTITION_EXTENSION, 1159 ListEntry); 1160 1161 if (partExt->IsEnumerated) 1162 { 1163 PartitionHandleRemove(partExt, TRUE); 1164 } 1165 } 1166 1167 // Send the IRP down the stack 1168 IoSkipCurrentIrpStackLocation(Irp); 1169 Irp->IoStatus.Status = STATUS_SUCCESS; 1170 return IoCallDriver(FdoExtension->LowerDevice, Irp); 1171 } 1172 1173 static 1174 CODE_SEG("PAGE") 1175 NTSTATUS 1176 NTAPI 1177 PartMgrAddDevice( 1178 _In_ PDRIVER_OBJECT DriverObject, 1179 _In_ PDEVICE_OBJECT PhysicalDeviceObject) 1180 { 1181 PDEVICE_OBJECT deviceObject; 1182 1183 PAGED_CODE(); 1184 1185 NTSTATUS status = IoCreateDevice(DriverObject, 1186 sizeof(FDO_EXTENSION), 1187 NULL, 1188 FILE_DEVICE_BUS_EXTENDER, 1189 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 1190 FALSE, 1191 &deviceObject); 1192 if (!NT_SUCCESS(status)) 1193 { 1194 ERR("Failed to create FDO 0x%x\n", status); 1195 return status; 1196 } 1197 1198 PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension; 1199 RtlZeroMemory(deviceExtension, sizeof(*deviceExtension)); 1200 1201 deviceExtension->IsFDO = TRUE; 1202 deviceExtension->DeviceObject = deviceObject; 1203 deviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject); 1204 if (!deviceExtension->LowerDevice) 1205 { 1206 // The attachment failed 1207 IoDeleteDevice(deviceObject); 1208 return STATUS_DEVICE_REMOVED; 1209 } 1210 deviceExtension->PhysicalDiskDO = PhysicalDeviceObject; 1211 KeInitializeEvent(&deviceExtension->SyncEvent, SynchronizationEvent, TRUE); 1212 1213 deviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; 1214 1215 // The device is initialized 1216 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 1217 return STATUS_SUCCESS; 1218 } 1219 1220 static 1221 NTSTATUS 1222 NTAPI 1223 PartMgrDeviceControl( 1224 _In_ PDEVICE_OBJECT DeviceObject, 1225 _In_ PIRP Irp) 1226 { 1227 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1228 PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1229 NTSTATUS status; 1230 1231 // Note: IRP_MJ_DEVICE_CONTROL handler in the storage stack must be able to pass IOCTLs 1232 // at an IRQL higher than PASSIVE_LEVEL 1233 1234 INFO("IRP_MJ_DEVICE_CONTROL %p Irp %p IOCTL %x isFdo: %u\n", 1235 DeviceObject, Irp, ioStack->Parameters.DeviceIoControl.IoControlCode, fdoExtension->IsFDO); 1236 1237 if (!fdoExtension->IsFDO) 1238 { 1239 return PartitionHandleDeviceControl(DeviceObject, Irp); 1240 } 1241 1242 switch (ioStack->Parameters.DeviceIoControl.IoControlCode) 1243 { 1244 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 1245 status = FdoIoctlDiskGetDriveGeometryEx(fdoExtension, Irp); 1246 break; 1247 1248 case IOCTL_DISK_GET_PARTITION_INFO: 1249 status = FdoIoctlDiskGetPartitionInfo(fdoExtension, Irp); 1250 break; 1251 1252 case IOCTL_DISK_GET_PARTITION_INFO_EX: 1253 status = FdoIoctlDiskGetPartitionInfoEx(fdoExtension, Irp); 1254 break; 1255 1256 case IOCTL_DISK_GET_DRIVE_LAYOUT: 1257 status = FdoIoctlDiskGetDriveLayout(fdoExtension, Irp); 1258 break; 1259 1260 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: 1261 status = FdoIoctlDiskGetDriveLayoutEx(fdoExtension, Irp); 1262 break; 1263 1264 case IOCTL_DISK_SET_DRIVE_LAYOUT: 1265 status = FdoIoctlDiskSetDriveLayout(fdoExtension, Irp); 1266 break; 1267 1268 case IOCTL_DISK_SET_DRIVE_LAYOUT_EX: 1269 status = FdoIoctlDiskSetDriveLayoutEx(fdoExtension, Irp); 1270 break; 1271 1272 case IOCTL_DISK_UPDATE_PROPERTIES: 1273 status = FdoIoctlDiskUpdateProperties(fdoExtension, Irp); 1274 break; 1275 1276 case IOCTL_DISK_CREATE_DISK: 1277 status = FdoIoctlDiskCreateDisk(fdoExtension, Irp); 1278 break; 1279 1280 case IOCTL_DISK_DELETE_DRIVE_LAYOUT: 1281 status = FdoIoctlDiskDeleteDriveLayout(fdoExtension, Irp); 1282 break; 1283 // case IOCTL_DISK_GROW_PARTITION: // todo 1284 default: 1285 return ForwardIrpAndForget(DeviceObject, Irp); 1286 } 1287 1288 Irp->IoStatus.Status = status; 1289 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1290 return status; 1291 } 1292 1293 static 1294 CODE_SEG("PAGE") 1295 NTSTATUS 1296 NTAPI 1297 PartMgrPnp( 1298 _In_ PDEVICE_OBJECT DeviceObject, 1299 _In_ PIRP Irp) 1300 { 1301 PAGED_CODE(); 1302 1303 PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1304 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1305 1306 INFO("IRP_MJ_PNP %p Irp %p %s isFDO: %u\n", 1307 DeviceObject, Irp, GetIRPMinorFunctionString(ioStack->MinorFunction), fdoExtension->IsFDO); 1308 1309 if (!fdoExtension->IsFDO) 1310 { 1311 return PartitionHandlePnp(DeviceObject, Irp); 1312 } 1313 1314 switch (ioStack->MinorFunction) { 1315 1316 case IRP_MN_START_DEVICE: 1317 { 1318 NTSTATUS status; 1319 1320 // if this is sent to the FDO so we should forward it down the 1321 // attachment chain before we can start the FDO 1322 1323 if (!IoForwardIrpSynchronously(fdoExtension->LowerDevice, Irp)) 1324 { 1325 status = STATUS_UNSUCCESSFUL; 1326 } 1327 else 1328 { 1329 status = FdoHandleStartDevice(fdoExtension, Irp); 1330 } 1331 1332 Irp->IoStatus.Status = status; 1333 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1334 return status; 1335 } 1336 case IRP_MN_QUERY_DEVICE_RELATIONS: 1337 { 1338 return FdoHandleDeviceRelations(fdoExtension, Irp); 1339 } 1340 case IRP_MN_SURPRISE_REMOVAL: 1341 { 1342 return FdoHandleSurpriseRemoval(fdoExtension, Irp); 1343 } 1344 case IRP_MN_REMOVE_DEVICE: 1345 { 1346 return FdoHandleRemoveDevice(fdoExtension, Irp); 1347 } 1348 case IRP_MN_QUERY_STOP_DEVICE: 1349 case IRP_MN_QUERY_REMOVE_DEVICE: 1350 case IRP_MN_CANCEL_STOP_DEVICE: 1351 case IRP_MN_CANCEL_REMOVE_DEVICE: 1352 case IRP_MN_STOP_DEVICE: 1353 { 1354 Irp->IoStatus.Status = STATUS_SUCCESS; 1355 // fallthrough 1356 } 1357 default: 1358 { 1359 IoSkipCurrentIrpStackLocation(Irp); 1360 return IoCallDriver(fdoExtension->LowerDevice, Irp); 1361 } 1362 } 1363 } 1364 1365 static 1366 NTSTATUS 1367 NTAPI 1368 PartMgrReadWrite( 1369 _In_ PDEVICE_OBJECT DeviceObject, 1370 _In_ PIRP Irp) 1371 { 1372 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 1373 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1374 1375 if (!partExt->IsFDO) 1376 { 1377 if (!partExt->IsEnumerated) 1378 { 1379 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 1380 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1381 return STATUS_DEVICE_DOES_NOT_EXIST; 1382 } 1383 else 1384 { 1385 ioStack->Parameters.Read.ByteOffset.QuadPart += partExt->StartingOffset; 1386 } 1387 } 1388 1389 IoSkipCurrentIrpStackLocation(Irp); 1390 return IoCallDriver(partExt->LowerDevice, Irp); 1391 } 1392 1393 DRIVER_DISPATCH PartMgrPower; 1394 NTSTATUS 1395 NTAPI 1396 PartMgrPower( 1397 _In_ PDEVICE_OBJECT DeviceObject, 1398 _In_ PIRP Irp) 1399 { 1400 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 1401 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 1402 1403 PoStartNextPowerIrp(Irp); 1404 1405 if (!partExt->IsFDO) 1406 { 1407 NTSTATUS status; 1408 1409 if (!partExt->IsEnumerated) 1410 { 1411 status = STATUS_DEVICE_DOES_NOT_EXIST; 1412 } 1413 else if (ioStack->MinorFunction == IRP_MN_SET_POWER || 1414 ioStack->MinorFunction == IRP_MN_QUERY_POWER) 1415 { 1416 status = STATUS_SUCCESS; 1417 } 1418 else 1419 { 1420 status = Irp->IoStatus.Status; 1421 } 1422 1423 Irp->IoStatus.Status = status; 1424 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1425 return status; 1426 } 1427 else 1428 { 1429 IoSkipCurrentIrpStackLocation(Irp); 1430 return PoCallDriver(partExt->LowerDevice, Irp); 1431 } 1432 } 1433 1434 DRIVER_DISPATCH PartMgrShutdownFlush; 1435 NTSTATUS 1436 NTAPI 1437 PartMgrShutdownFlush( 1438 _In_ PDEVICE_OBJECT DeviceObject, 1439 _In_ PIRP Irp) 1440 { 1441 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 1442 PDEVICE_OBJECT lowerDevice; 1443 1444 // forward to the partition0 device in both cases 1445 if (!partExt->IsFDO) 1446 { 1447 if (!partExt->IsEnumerated) 1448 { 1449 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 1450 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1451 return STATUS_DEVICE_DOES_NOT_EXIST; 1452 } 1453 else 1454 { 1455 PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension; 1456 lowerDevice = fdoExtension->LowerDevice; 1457 } 1458 } 1459 else 1460 { 1461 lowerDevice = partExt->LowerDevice; 1462 } 1463 1464 IoSkipCurrentIrpStackLocation(Irp); 1465 return IoCallDriver(lowerDevice, Irp); 1466 } 1467 1468 CODE_SEG("PAGE") 1469 VOID 1470 NTAPI 1471 PartMgrUnload( 1472 _In_ PDRIVER_OBJECT DriverObject) 1473 { 1474 1475 } 1476 1477 CODE_SEG("INIT") 1478 NTSTATUS 1479 NTAPI 1480 DriverEntry( 1481 _In_ PDRIVER_OBJECT DriverObject, 1482 _In_ PUNICODE_STRING RegistryPath) 1483 { 1484 DriverObject->DriverUnload = PartMgrUnload; 1485 DriverObject->DriverExtension->AddDevice = PartMgrAddDevice; 1486 DriverObject->MajorFunction[IRP_MJ_CREATE] = ForwardIrpAndForget; 1487 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ForwardIrpAndForget; 1488 DriverObject->MajorFunction[IRP_MJ_READ] = PartMgrReadWrite; 1489 DriverObject->MajorFunction[IRP_MJ_WRITE] = PartMgrReadWrite; 1490 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PartMgrDeviceControl; 1491 DriverObject->MajorFunction[IRP_MJ_PNP] = PartMgrPnp; 1492 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = PartMgrShutdownFlush; 1493 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = PartMgrShutdownFlush; 1494 DriverObject->MajorFunction[IRP_MJ_POWER] = PartMgrPower; 1495 1496 return STATUS_SUCCESS; 1497 } 1498