1 /* 2 * PROJECT: Partition manager driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Partition device code 5 * COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin@reactos.org) 6 */ 7 8 #include "partmgr.h" 9 10 static const WCHAR PartitionSymLinkFormat[] = L"\\Device\\Harddisk%lu\\Partition%lu"; 11 12 13 CODE_SEG("PAGE") 14 NTSTATUS 15 PartitionCreateDevice( 16 _In_ PDEVICE_OBJECT FDObject, 17 _In_ PPARTITION_INFORMATION_EX PartitionEntry, 18 _In_ UINT32 PdoNumber, 19 _In_ PARTITION_STYLE PartitionStyle, 20 _Out_ PDEVICE_OBJECT *PDO) 21 { 22 PAGED_CODE(); 23 24 static UINT32 HarddiskVolumeNextId = 1; // this is 1-based 25 26 WCHAR nameBuf[64]; 27 UNICODE_STRING deviceName; 28 UINT32 volumeNum; 29 30 // create the device object 31 32 volumeNum = HarddiskVolumeNextId++; 33 swprintf(nameBuf, L"\\Device\\HarddiskVolume%lu", volumeNum); 34 RtlCreateUnicodeString(&deviceName, nameBuf); 35 36 PDEVICE_OBJECT partitionDevice; 37 NTSTATUS status = IoCreateDevice(FDObject->DriverObject, 38 sizeof(PARTITION_EXTENSION), 39 &deviceName, 40 FILE_DEVICE_DISK, 41 FILE_DEVICE_SECURE_OPEN, 42 FALSE, 43 &partitionDevice); 44 45 if (!NT_SUCCESS(status)) 46 { 47 ERR("Unable to create device object %wZ\n", &deviceName); 48 return status; 49 } 50 51 INFO("Created device object %p %wZ\n", partitionDevice, &deviceName); 52 53 PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension; 54 RtlZeroMemory(partExt, sizeof(*partExt)); 55 56 partitionDevice->StackSize = FDObject->StackSize; 57 partitionDevice->Flags |= DO_DIRECT_IO; 58 59 if (PartitionStyle == PARTITION_STYLE_MBR) 60 { 61 partExt->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType; 62 partExt->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator; 63 partExt->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors; 64 } 65 else 66 { 67 partExt->Gpt.PartitionType = PartitionEntry->Gpt.PartitionType; 68 partExt->Gpt.PartitionId = PartitionEntry->Gpt.PartitionId; 69 partExt->Gpt.Attributes = PartitionEntry->Gpt.Attributes; 70 71 RtlCopyMemory(partExt->Gpt.Name, PartitionEntry->Gpt.Name, sizeof(partExt->Gpt.Name)); 72 } 73 74 partExt->DeviceName = deviceName; 75 partExt->StartingOffset = PartitionEntry->StartingOffset.QuadPart; 76 partExt->PartitionLength = PartitionEntry->PartitionLength.QuadPart; 77 partExt->OnDiskNumber = PartitionEntry->PartitionNumber; // the "physical" partition number 78 partExt->DetectedNumber = PdoNumber; // counts only partitions with PDO created 79 partExt->VolumeNumber = volumeNum; 80 81 partExt->DeviceObject = partitionDevice; 82 partExt->LowerDevice = FDObject; 83 84 partitionDevice->Flags &= ~DO_DEVICE_INITIALIZING; 85 86 *PDO = partitionDevice; 87 88 return status; 89 } 90 91 static 92 CODE_SEG("PAGE") 93 NTSTATUS 94 PartitionHandleStartDevice( 95 _In_ PPARTITION_EXTENSION PartExt, 96 _In_ PIRP Irp) 97 { 98 PAGED_CODE(); 99 100 // first, create a symbolic link for our device 101 WCHAR nameBuf[64]; 102 UNICODE_STRING partitionSymlink, interfaceName; 103 PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension; 104 105 // \\Device\\Harddisk%lu\\Partition%lu 106 swprintf(nameBuf, PartitionSymLinkFormat, 107 fdoExtension->DiskData.DeviceNumber, PartExt->DetectedNumber); 108 109 if (!RtlCreateUnicodeString(&partitionSymlink, nameBuf)) 110 { 111 return STATUS_INSUFFICIENT_RESOURCES; 112 } 113 114 NTSTATUS status = IoCreateSymbolicLink(&partitionSymlink, &PartExt->DeviceName); 115 116 if (!NT_SUCCESS(status)) 117 { 118 return status; 119 } 120 121 PartExt->SymlinkCreated = TRUE; 122 123 INFO("Symlink created %wZ -> %wZ\n", &partitionSymlink, &PartExt->DeviceName); 124 125 // Our partition device will have two interfaces: 126 // GUID_DEVINTERFACE_PARTITION and GUID_DEVINTERFACE_VOLUME 127 // (aka. MOUNTDEV_MOUNTED_DEVICE_GUID). 128 // The latter one is used to notify MountMgr about the new volume. 129 130 status = IoRegisterDeviceInterface(PartExt->DeviceObject, 131 &GUID_DEVINTERFACE_PARTITION, 132 NULL, 133 &interfaceName); 134 if (!NT_SUCCESS(status)) 135 { 136 return status; 137 } 138 139 PartExt->PartitionInterfaceName = interfaceName; 140 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 141 142 INFO("Partition interface %wZ\n", &interfaceName); 143 144 if (!NT_SUCCESS(status)) 145 { 146 RtlFreeUnicodeString(&interfaceName); 147 RtlInitUnicodeString(&PartExt->PartitionInterfaceName, NULL); 148 return status; 149 } 150 151 status = IoRegisterDeviceInterface(PartExt->DeviceObject, 152 &GUID_DEVINTERFACE_VOLUME, 153 NULL, 154 &interfaceName); 155 if (!NT_SUCCESS(status)) 156 { 157 return status; 158 } 159 160 PartExt->VolumeInterfaceName = interfaceName; 161 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 162 163 INFO("Volume interface %wZ\n", &interfaceName); 164 165 if (!NT_SUCCESS(status)) 166 { 167 RtlFreeUnicodeString(&interfaceName); 168 RtlInitUnicodeString(&PartExt->VolumeInterfaceName, NULL); 169 return status; 170 } 171 172 return STATUS_SUCCESS; 173 } 174 175 /** 176 * @brief 177 * Notifies MountMgr to delete all mount points 178 * associated with the given volume. 179 * 180 * @note This should belong to volmgr.sys and act on a PVOLUME_EXTENSION. 181 **/ 182 static 183 CODE_SEG("PAGE") 184 NTSTATUS 185 VolumeDeleteMountPoints( 186 _In_ PPARTITION_EXTENSION PartExt) 187 { 188 NTSTATUS Status; 189 UNICODE_STRING MountMgr; 190 ULONG InputSize, OutputSize; 191 LOGICAL Retry; 192 PUNICODE_STRING DeviceName; 193 PDEVICE_OBJECT DeviceObject; 194 PFILE_OBJECT FileObject = NULL; 195 PMOUNTMGR_MOUNT_POINT InputBuffer = NULL; 196 PMOUNTMGR_MOUNT_POINTS OutputBuffer = NULL; 197 198 PAGED_CODE(); 199 200 /* Get the device pointer to the MountMgr */ 201 RtlInitUnicodeString(&MountMgr, MOUNTMGR_DEVICE_NAME); 202 Status = IoGetDeviceObjectPointer(&MountMgr, 203 FILE_READ_ATTRIBUTES, 204 &FileObject, 205 &DeviceObject); 206 if (!NT_SUCCESS(Status)) 207 return Status; 208 209 /* Setup the volume device name for deleting its mount points */ 210 DeviceName = &PartExt->DeviceName; 211 212 /* Allocate the input buffer */ 213 InputSize = sizeof(*InputBuffer) + DeviceName->Length; 214 InputBuffer = ExAllocatePoolWithTag(PagedPool, InputSize, TAG_PARTMGR); 215 if (!InputBuffer) 216 { 217 Status = STATUS_INSUFFICIENT_RESOURCES; 218 goto Quit; 219 } 220 221 /* Fill it in */ 222 RtlZeroMemory(InputBuffer, sizeof(*InputBuffer)); 223 InputBuffer->DeviceNameOffset = sizeof(*InputBuffer); 224 InputBuffer->DeviceNameLength = DeviceName->Length; 225 RtlCopyMemory(&InputBuffer[1], DeviceName->Buffer, DeviceName->Length); 226 227 /* 228 * IOCTL_MOUNTMGR_DELETE_POINTS needs a large-enough scratch output buffer 229 * to work with. (It uses it to query the mount points, before deleting 230 * them.) Start with a guessed size and call the IOCTL. If the buffer is 231 * not big enough, use the value retrieved in MOUNTMGR_MOUNT_POINTS::Size 232 * to re-allocate a larger buffer and call the IOCTL once more. 233 */ 234 OutputSize = max(PAGE_SIZE, sizeof(*OutputBuffer)); 235 for (Retry = 0; Retry < 2; ++Retry) 236 { 237 OutputBuffer = ExAllocatePoolWithTag(PagedPool, OutputSize, TAG_PARTMGR); 238 if (!OutputBuffer) 239 { 240 Status = STATUS_INSUFFICIENT_RESOURCES; 241 break; 242 } 243 244 /* Call the MountMgr to delete the drive letter */ 245 Status = IssueSyncIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS, 246 DeviceObject, 247 InputBuffer, 248 InputSize, 249 OutputBuffer, 250 OutputSize, 251 FALSE); 252 253 /* Adjust the allocation size if it was too small */ 254 if (Status == STATUS_BUFFER_OVERFLOW) 255 { 256 OutputSize = OutputBuffer->Size; 257 ExFreePoolWithTag(OutputBuffer, TAG_PARTMGR); 258 continue; 259 } 260 /* Success or failure: stop the loop */ 261 break; 262 } 263 264 Quit: 265 if (OutputBuffer) 266 ExFreePoolWithTag(OutputBuffer, TAG_PARTMGR); 267 if (InputBuffer) 268 ExFreePoolWithTag(InputBuffer, TAG_PARTMGR); 269 if (FileObject) 270 ObDereferenceObject(FileObject); 271 return Status; 272 } 273 274 CODE_SEG("PAGE") 275 NTSTATUS 276 PartitionHandleRemove( 277 _In_ PPARTITION_EXTENSION PartExt, 278 _In_ BOOLEAN FinalRemove) 279 { 280 NTSTATUS status; 281 282 PAGED_CODE(); 283 284 // remove the symbolic link 285 if (PartExt->SymlinkCreated) 286 { 287 WCHAR nameBuf[64]; 288 UNICODE_STRING partitionSymlink; 289 PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension; 290 291 swprintf(nameBuf, PartitionSymLinkFormat, 292 fdoExtension->DiskData.DeviceNumber, PartExt->DetectedNumber); 293 294 RtlInitUnicodeString(&partitionSymlink, nameBuf); 295 296 status = IoDeleteSymbolicLink(&partitionSymlink); 297 298 if (!NT_SUCCESS(status)) 299 { 300 return status; 301 } 302 PartExt->SymlinkCreated = FALSE; 303 304 INFO("Symlink removed %wZ -> %wZ\n", &partitionSymlink, &PartExt->DeviceName); 305 } 306 307 // release device interfaces 308 if (PartExt->PartitionInterfaceName.Buffer) 309 { 310 status = IoSetDeviceInterfaceState(&PartExt->PartitionInterfaceName, FALSE); 311 if (!NT_SUCCESS(status)) 312 { 313 return status; 314 } 315 RtlFreeUnicodeString(&PartExt->PartitionInterfaceName); 316 RtlInitUnicodeString(&PartExt->PartitionInterfaceName, NULL); 317 } 318 319 if (PartExt->VolumeInterfaceName.Buffer) 320 { 321 /* Notify MountMgr to delete all associated mount points. 322 * MountMgr does not automatically remove these in order to support 323 * drive letter persistence for online/offline volume transitions, 324 * or volumes arrival/removal on removable devices. */ 325 status = VolumeDeleteMountPoints(PartExt); 326 if (!NT_SUCCESS(status)) 327 { 328 ERR("VolumeDeleteMountPoints(%wZ) failed with status 0x%08lx\n", 329 &PartExt->DeviceName, status); 330 /* Failure isn't major, continue proceeding with volume removal */ 331 } 332 333 /* Notify MountMgr of volume removal */ 334 status = IoSetDeviceInterfaceState(&PartExt->VolumeInterfaceName, FALSE); 335 if (!NT_SUCCESS(status)) 336 { 337 return status; 338 } 339 RtlFreeUnicodeString(&PartExt->VolumeInterfaceName); 340 RtlInitUnicodeString(&PartExt->VolumeInterfaceName, NULL); 341 } 342 343 if (FinalRemove) 344 { 345 ASSERT(PartExt->DeviceName.Buffer); 346 if (PartExt->DeviceName.Buffer) 347 { 348 INFO("Removed device %wZ\n", &PartExt->DeviceName); 349 RtlFreeUnicodeString(&PartExt->DeviceName); 350 } 351 352 IoDeleteDevice(PartExt->DeviceObject); 353 } 354 355 return STATUS_SUCCESS; 356 } 357 358 static 359 CODE_SEG("PAGE") 360 NTSTATUS 361 PartitionHandleDeviceRelations( 362 _In_ PPARTITION_EXTENSION PartExt, 363 _In_ PIRP Irp) 364 { 365 PAGED_CODE(); 366 367 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 368 DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type; 369 370 if (type == TargetDeviceRelation) 371 { 372 // Device relations have one entry built into their size. 373 PDEVICE_RELATIONS deviceRelations = 374 ExAllocatePoolZero(PagedPool, sizeof(DEVICE_RELATIONS), TAG_PARTMGR); 375 376 if (deviceRelations != NULL) 377 { 378 deviceRelations->Count = 1; 379 deviceRelations->Objects[0] = PartExt->DeviceObject; 380 ObReferenceObject(deviceRelations->Objects[0]); 381 382 Irp->IoStatus.Information = (ULONG_PTR)deviceRelations; 383 return STATUS_SUCCESS; 384 } 385 else 386 { 387 return STATUS_INSUFFICIENT_RESOURCES; 388 } 389 } 390 else 391 { 392 Irp->IoStatus.Information = 0; 393 return Irp->IoStatus.Status; 394 } 395 } 396 397 static 398 CODE_SEG("PAGE") 399 NTSTATUS 400 PartitionHandleQueryId( 401 _In_ PPARTITION_EXTENSION PartExt, 402 _In_ PIRP Irp) 403 { 404 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 405 BUS_QUERY_ID_TYPE idType = ioStack->Parameters.QueryId.IdType; 406 UNICODE_STRING idString; 407 NTSTATUS status; 408 409 PAGED_CODE(); 410 411 switch (idType) 412 { 413 case BusQueryDeviceID: 414 status = RtlCreateUnicodeString(&idString, L"STORAGE\\Partition") 415 ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 416 break; 417 case BusQueryHardwareIDs: 418 { 419 static WCHAR volumeID[] = L"STORAGE\\Volume\0"; 420 421 idString.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(volumeID), TAG_PARTMGR); 422 RtlCopyMemory(idString.Buffer, volumeID, sizeof(volumeID)); 423 424 status = STATUS_SUCCESS; 425 break; 426 } 427 case BusQueryInstanceID: 428 { 429 WCHAR string[64]; 430 PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension; 431 432 PartMgrAcquireLayoutLock(fdoExtension); 433 434 if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) 435 { 436 swprintf(string, L"S%08lx_O%I64x_L%I64x", 437 fdoExtension->DiskData.Mbr.Signature, 438 PartExt->StartingOffset, 439 PartExt->PartitionLength); 440 } 441 else 442 { 443 swprintf(string, 444 L"S%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02xS_O%I64x_L%I64x", 445 fdoExtension->DiskData.Gpt.DiskId.Data1, 446 fdoExtension->DiskData.Gpt.DiskId.Data2, 447 fdoExtension->DiskData.Gpt.DiskId.Data3, 448 fdoExtension->DiskData.Gpt.DiskId.Data4[0], 449 fdoExtension->DiskData.Gpt.DiskId.Data4[1], 450 fdoExtension->DiskData.Gpt.DiskId.Data4[2], 451 fdoExtension->DiskData.Gpt.DiskId.Data4[3], 452 fdoExtension->DiskData.Gpt.DiskId.Data4[4], 453 fdoExtension->DiskData.Gpt.DiskId.Data4[5], 454 fdoExtension->DiskData.Gpt.DiskId.Data4[6], 455 fdoExtension->DiskData.Gpt.DiskId.Data4[7], 456 PartExt->StartingOffset, 457 PartExt->PartitionLength); 458 } 459 460 PartMgrReleaseLayoutLock(fdoExtension); 461 462 status = RtlCreateUnicodeString(&idString, string) 463 ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 464 break; 465 } 466 default: 467 status = STATUS_NOT_SUPPORTED; 468 break; 469 } 470 471 Irp->IoStatus.Information = NT_SUCCESS(status) ? (ULONG_PTR) idString.Buffer : 0; 472 return status; 473 } 474 475 static 476 CODE_SEG("PAGE") 477 NTSTATUS 478 PartitionHandleQueryCapabilities( 479 _In_ PPARTITION_EXTENSION PartExt, 480 _In_ PIRP Irp) 481 { 482 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 483 PDEVICE_CAPABILITIES devCaps = ioStack->Parameters.DeviceCapabilities.Capabilities; 484 485 PAGED_CODE(); 486 ASSERT(devCaps); 487 488 devCaps->SilentInstall = TRUE; 489 devCaps->RawDeviceOK = TRUE; 490 devCaps->NoDisplayInUI = TRUE; 491 devCaps->Address = PartExt->OnDiskNumber; 492 devCaps->UniqueID = FALSE; 493 494 return STATUS_SUCCESS; 495 } 496 497 CODE_SEG("PAGE") 498 NTSTATUS 499 PartitionHandlePnp( 500 _In_ PDEVICE_OBJECT DeviceObject, 501 _In_ PIRP Irp) 502 { 503 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 504 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 505 NTSTATUS status; 506 507 PAGED_CODE(); 508 509 switch (ioStack->MinorFunction) 510 { 511 case IRP_MN_START_DEVICE: 512 { 513 status = PartitionHandleStartDevice(partExt, Irp); 514 break; 515 } 516 case IRP_MN_QUERY_DEVICE_RELATIONS: 517 { 518 status = PartitionHandleDeviceRelations(partExt, Irp); 519 break; 520 } 521 case IRP_MN_QUERY_STOP_DEVICE: 522 case IRP_MN_QUERY_REMOVE_DEVICE: 523 case IRP_MN_CANCEL_STOP_DEVICE: 524 case IRP_MN_CANCEL_REMOVE_DEVICE: 525 case IRP_MN_STOP_DEVICE: 526 { 527 status = STATUS_SUCCESS; 528 break; 529 } 530 case IRP_MN_SURPRISE_REMOVAL: 531 { 532 status = PartitionHandleRemove(partExt, FALSE); 533 break; 534 } 535 case IRP_MN_REMOVE_DEVICE: 536 { 537 status = PartitionHandleRemove(partExt, TRUE); 538 break; 539 } 540 case IRP_MN_QUERY_ID: 541 { 542 status = PartitionHandleQueryId(partExt, Irp); 543 break; 544 } 545 case IRP_MN_QUERY_CAPABILITIES: 546 { 547 status = PartitionHandleQueryCapabilities(partExt, Irp); 548 break; 549 } 550 default: 551 { 552 Irp->IoStatus.Information = 0; 553 status = STATUS_NOT_SUPPORTED; 554 } 555 } 556 557 Irp->IoStatus.Status = status; 558 IoCompleteRequest(Irp, IO_NO_INCREMENT); 559 return status; 560 } 561 562 NTSTATUS 563 PartitionHandleDeviceControl( 564 _In_ PDEVICE_OBJECT DeviceObject, 565 _In_ PIRP Irp) 566 { 567 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp); 568 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension; 569 PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension; 570 NTSTATUS status; 571 572 ASSERT(!partExt->IsFDO); 573 574 if (!partExt->IsEnumerated) 575 { 576 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 577 IoCompleteRequest(Irp, IO_NO_INCREMENT); 578 return STATUS_DEVICE_DOES_NOT_EXIST; 579 } 580 581 switch (ioStack->Parameters.DeviceIoControl.IoControlCode) 582 { 583 // disk stuff 584 case IOCTL_DISK_GET_PARTITION_INFO: 585 { 586 if (!VerifyIrpOutBufferSize(Irp, sizeof(PARTITION_INFORMATION))) 587 { 588 status = STATUS_BUFFER_TOO_SMALL; 589 break; 590 } 591 592 PartMgrAcquireLayoutLock(fdoExtension); 593 594 // not supported on anything other than MBR 595 if (fdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_MBR) 596 { 597 status = STATUS_INVALID_DEVICE_REQUEST; 598 PartMgrReleaseLayoutLock(fdoExtension); 599 break; 600 } 601 602 PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer; 603 604 *partInfo = (PARTITION_INFORMATION){ 605 .PartitionType = partExt->Mbr.PartitionType, 606 .StartingOffset.QuadPart = partExt->StartingOffset, 607 .PartitionLength.QuadPart = partExt->PartitionLength, 608 .HiddenSectors = partExt->Mbr.HiddenSectors, 609 .PartitionNumber = partExt->DetectedNumber, 610 .BootIndicator = partExt->Mbr.BootIndicator, 611 .RecognizedPartition = partExt->Mbr.RecognizedPartition, 612 .RewritePartition = FALSE, 613 }; 614 615 PartMgrReleaseLayoutLock(fdoExtension); 616 617 Irp->IoStatus.Information = sizeof(*partInfo); 618 status = STATUS_SUCCESS; 619 break; 620 } 621 case IOCTL_DISK_GET_PARTITION_INFO_EX: 622 { 623 if (!VerifyIrpOutBufferSize(Irp, sizeof(PARTITION_INFORMATION_EX))) 624 { 625 status = STATUS_BUFFER_TOO_SMALL; 626 break; 627 } 628 629 PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer; 630 631 PartMgrAcquireLayoutLock(fdoExtension); 632 633 *partInfoEx = (PARTITION_INFORMATION_EX){ 634 .StartingOffset.QuadPart = partExt->StartingOffset, 635 .PartitionLength.QuadPart = partExt->PartitionLength, 636 .PartitionNumber = partExt->DetectedNumber, 637 .PartitionStyle = fdoExtension->DiskData.PartitionStyle, 638 .RewritePartition = FALSE, 639 }; 640 641 if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) 642 { 643 partInfoEx->Mbr = (PARTITION_INFORMATION_MBR){ 644 .PartitionType = partExt->Mbr.PartitionType, 645 .HiddenSectors = partExt->Mbr.HiddenSectors, 646 .BootIndicator = partExt->Mbr.BootIndicator, 647 .RecognizedPartition = partExt->Mbr.RecognizedPartition, 648 }; 649 } 650 else 651 { 652 partInfoEx->Gpt = (PARTITION_INFORMATION_GPT){ 653 .PartitionType = partExt->Gpt.PartitionType, 654 .PartitionId = partExt->Gpt.PartitionId, 655 .Attributes = partExt->Gpt.Attributes, 656 }; 657 658 RtlCopyMemory(partInfoEx->Gpt.Name, 659 partExt->Gpt.Name, 660 sizeof(partInfoEx->Gpt.Name)); 661 } 662 663 PartMgrReleaseLayoutLock(fdoExtension); 664 665 Irp->IoStatus.Information = sizeof(*partInfoEx); 666 status = STATUS_SUCCESS; 667 break; 668 } 669 case IOCTL_DISK_SET_PARTITION_INFO: 670 { 671 PSET_PARTITION_INFORMATION inputBuffer = Irp->AssociatedIrp.SystemBuffer; 672 if (!VerifyIrpInBufferSize(Irp, sizeof(*inputBuffer))) 673 { 674 status = STATUS_INFO_LENGTH_MISMATCH; 675 break; 676 } 677 678 PartMgrAcquireLayoutLock(fdoExtension); 679 680 // these functions use on disk numbers, not detected ones 681 status = IoSetPartitionInformation(fdoExtension->LowerDevice, 682 fdoExtension->DiskData.BytesPerSector, 683 partExt->OnDiskNumber, 684 inputBuffer->PartitionType); 685 686 if (NT_SUCCESS(status)) 687 { 688 partExt->Mbr.PartitionType = inputBuffer->PartitionType; 689 } 690 691 PartMgrReleaseLayoutLock(fdoExtension); 692 693 Irp->IoStatus.Information = 0; 694 break; 695 } 696 case IOCTL_DISK_SET_PARTITION_INFO_EX: 697 { 698 PSET_PARTITION_INFORMATION_EX inputBuffer = Irp->AssociatedIrp.SystemBuffer; 699 if (!VerifyIrpInBufferSize(Irp, sizeof(*inputBuffer))) 700 { 701 status = STATUS_INFO_LENGTH_MISMATCH; 702 break; 703 } 704 705 PartMgrAcquireLayoutLock(fdoExtension); 706 707 // these functions use on disk numbers, not detected ones 708 status = IoSetPartitionInformationEx(fdoExtension->LowerDevice, 709 partExt->OnDiskNumber, 710 inputBuffer); 711 712 if (NT_SUCCESS(status)) 713 { 714 if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) 715 { 716 partExt->Mbr.PartitionType = inputBuffer->Mbr.PartitionType; 717 } 718 else 719 { 720 partExt->Gpt.PartitionType = inputBuffer->Gpt.PartitionType; 721 partExt->Gpt.PartitionId = inputBuffer->Gpt.PartitionId; 722 partExt->Gpt.Attributes = inputBuffer->Gpt.Attributes; 723 724 RtlMoveMemory(partExt->Gpt.Name, 725 inputBuffer->Gpt.Name, 726 sizeof(partExt->Gpt.Name)); 727 } 728 } 729 730 PartMgrReleaseLayoutLock(fdoExtension); 731 732 Irp->IoStatus.Information = 0; 733 break; 734 } 735 case IOCTL_DISK_GET_LENGTH_INFO: 736 { 737 PGET_LENGTH_INFORMATION lengthInfo = Irp->AssociatedIrp.SystemBuffer; 738 if (!VerifyIrpOutBufferSize(Irp, sizeof(*lengthInfo))) 739 { 740 status = STATUS_BUFFER_TOO_SMALL; 741 break; 742 } 743 744 PartMgrAcquireLayoutLock(fdoExtension); 745 746 lengthInfo->Length.QuadPart = partExt->PartitionLength; 747 748 PartMgrReleaseLayoutLock(fdoExtension); 749 750 status = STATUS_SUCCESS; 751 Irp->IoStatus.Information = sizeof(*lengthInfo); 752 break; 753 } 754 case IOCTL_DISK_VERIFY: 755 { 756 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer; 757 if (!VerifyIrpInBufferSize(Irp, sizeof(*verifyInfo))) 758 { 759 status = STATUS_INFO_LENGTH_MISMATCH; 760 break; 761 } 762 763 // Partition device should just adjust the starting offset 764 verifyInfo->StartingOffset.QuadPart += partExt->StartingOffset; 765 return ForwardIrpAndForget(DeviceObject, Irp); 766 } 767 case IOCTL_DISK_UPDATE_PROPERTIES: 768 { 769 fdoExtension->LayoutValid = FALSE; 770 IoInvalidateDeviceRelations(fdoExtension->PhysicalDiskDO, BusRelations); 771 772 status = STATUS_SUCCESS; 773 break; 774 } 775 case IOCTL_STORAGE_MEDIA_REMOVAL: 776 { 777 return ForwardIrpAndForget(DeviceObject, Irp); 778 } 779 // volume stuff (most of that should be in volmgr.sys once it is implemented) 780 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: 781 { 782 PVOLUME_DISK_EXTENTS volExts = Irp->AssociatedIrp.SystemBuffer; 783 784 // we fill only one extent entry so sizeof(*volExts) is enough 785 if (!VerifyIrpOutBufferSize(Irp, sizeof(*volExts))) 786 { 787 status = STATUS_BUFFER_TOO_SMALL; 788 break; 789 } 790 791 PartMgrAcquireLayoutLock(fdoExtension); 792 793 // the only type of volume we support right now is disk partition 794 // so this structure is simple 795 796 *volExts = (VOLUME_DISK_EXTENTS) { 797 .NumberOfDiskExtents = 1, 798 .Extents = {{ 799 .DiskNumber = fdoExtension->DiskData.DeviceNumber, 800 .StartingOffset.QuadPart = partExt->StartingOffset, 801 .ExtentLength.QuadPart = partExt->PartitionLength 802 }} 803 }; 804 805 PartMgrReleaseLayoutLock(fdoExtension); 806 807 status = STATUS_SUCCESS; 808 Irp->IoStatus.Information = sizeof(*volExts); 809 break; 810 } 811 case IOCTL_VOLUME_QUERY_VOLUME_NUMBER: 812 { 813 PVOLUME_NUMBER volNum = Irp->AssociatedIrp.SystemBuffer; 814 if (!VerifyIrpOutBufferSize(Irp, sizeof(*volNum))) 815 { 816 status = STATUS_BUFFER_TOO_SMALL; 817 break; 818 } 819 820 PartMgrAcquireLayoutLock(fdoExtension); 821 822 volNum->VolumeNumber = partExt->VolumeNumber; 823 RtlCopyMemory(volNum->VolumeManagerName, 824 L"VOLMGR ", // Must be 8 space-padded characters 825 sizeof(volNum->VolumeManagerName)); 826 827 PartMgrReleaseLayoutLock(fdoExtension); 828 829 status = STATUS_SUCCESS; 830 Irp->IoStatus.Information = sizeof(*volNum); 831 break; 832 } 833 case IOCTL_VOLUME_IS_PARTITION: 834 { 835 // The only type of volume we support right now is disk partition 836 // so we just return success. A more robust algorithm would be 837 // to check whether the volume has only one single extent, that 838 // covers the whole partition on which it lies upon. If this is 839 // not the case, return STATUS_UNSUCCESSFUL instead. 840 status = STATUS_SUCCESS; 841 break; 842 } 843 case IOCTL_VOLUME_ONLINE: 844 { 845 status = STATUS_SUCCESS; 846 break; 847 } 848 case IOCTL_VOLUME_GET_GPT_ATTRIBUTES: 849 { 850 PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION gptAttrs = Irp->AssociatedIrp.SystemBuffer; 851 if (!VerifyIrpOutBufferSize(Irp, sizeof(*gptAttrs))) 852 { 853 status = STATUS_BUFFER_TOO_SMALL; 854 break; 855 } 856 857 // not supported on anything other than GPT 858 if (fdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_GPT) 859 { 860 status = STATUS_INVALID_DEVICE_REQUEST; 861 break; 862 } 863 864 gptAttrs->GptAttributes = partExt->Gpt.Attributes; 865 866 status = STATUS_SUCCESS; 867 Irp->IoStatus.Information = sizeof(*gptAttrs); 868 break; 869 } 870 // mountmgr notifications (these should be in volmgr.sys once it is implemented) 871 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: 872 { 873 PMOUNTDEV_NAME name = Irp->AssociatedIrp.SystemBuffer; 874 875 if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT))) 876 { 877 status = STATUS_BUFFER_TOO_SMALL; 878 break; 879 } 880 881 name->NameLength = partExt->DeviceName.Length; 882 883 // return NameLength back 884 if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT) + name->NameLength)) 885 { 886 Irp->IoStatus.Information = sizeof(USHORT); 887 status = STATUS_BUFFER_OVERFLOW; 888 break; 889 } 890 891 RtlCopyMemory(name->Name, partExt->DeviceName.Buffer, name->NameLength); 892 893 status = STATUS_SUCCESS; 894 Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength; 895 break; 896 } 897 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: 898 { 899 const SIZE_T headerSize = FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId); 900 PMOUNTDEV_UNIQUE_ID uniqueId = Irp->AssociatedIrp.SystemBuffer; 901 PBASIC_VOLUME_UNIQUE_ID basicVolId = (PBASIC_VOLUME_UNIQUE_ID)&uniqueId->UniqueId; 902 PUNICODE_STRING InterfaceName; 903 904 // Check whether the minimal header size was provided 905 if (!VerifyIrpOutBufferSize(Irp, headerSize)) 906 { 907 status = STATUS_BUFFER_TOO_SMALL; 908 break; 909 } 910 911 PartMgrAcquireLayoutLock(fdoExtension); 912 913 InterfaceName = &partExt->VolumeInterfaceName; 914 if (fdoExtension->IsSuperFloppy) 915 InterfaceName = &fdoExtension->DiskInterfaceName; 916 917 // Calculate and return the necessary data size 918 if ((fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) && 919 !fdoExtension->IsSuperFloppy) 920 { 921 uniqueId->UniqueIdLength = sizeof(basicVolId->Mbr); 922 } 923 else if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_GPT) 924 { 925 uniqueId->UniqueIdLength = sizeof(basicVolId->Gpt); 926 } 927 else 928 { 929 if (!InterfaceName->Buffer || !InterfaceName->Length) 930 { 931 PartMgrReleaseLayoutLock(fdoExtension); 932 status = STATUS_INVALID_PARAMETER; 933 break; 934 } 935 uniqueId->UniqueIdLength = InterfaceName->Length; 936 } 937 938 // Return UniqueIdLength back 939 if (!VerifyIrpOutBufferSize(Irp, headerSize + uniqueId->UniqueIdLength)) 940 { 941 PartMgrReleaseLayoutLock(fdoExtension); 942 Irp->IoStatus.Information = headerSize; 943 status = STATUS_BUFFER_OVERFLOW; 944 break; 945 } 946 947 // 948 // Write the UniqueId 949 // 950 // Format: 951 // - Basic volume on MBR disk: disk Mbr.Signature + partition StartingOffset (length: 0x0C) 952 // - Basic volume on GPT disk: "DMIO:ID:" + Gpt.PartitionGuid (length: 0x18) 953 // - Volume on Basic disk (NT <= 4): 8-byte FTDisk identifier (length: 0x08) 954 // - Volume on Dynamic disk (NT 5+): "DMIO:ID:" + dmio VolumeGuid (length: 0x18) 955 // - Super-floppy (single-partition with StartingOffset == 0), 956 // or Removable media: DiskInterfaceName. 957 // - As fallback, we use the VolumeInterfaceName. 958 // 959 if ((fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR) && 960 !fdoExtension->IsSuperFloppy) 961 { 962 basicVolId->Mbr.Signature = fdoExtension->DiskData.Mbr.Signature; 963 basicVolId->Mbr.StartingOffset = partExt->StartingOffset; 964 } 965 else if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_GPT) 966 { 967 basicVolId->Gpt.Signature = DMIO_ID_SIGNATURE; 968 basicVolId->Gpt.PartitionGuid = partExt->Gpt.PartitionId; 969 } 970 else 971 { 972 RtlCopyMemory(uniqueId->UniqueId, 973 InterfaceName->Buffer, 974 uniqueId->UniqueIdLength); 975 } 976 977 PartMgrReleaseLayoutLock(fdoExtension); 978 979 status = STATUS_SUCCESS; 980 Irp->IoStatus.Information = headerSize + uniqueId->UniqueIdLength; 981 break; 982 } 983 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: 984 case IOCTL_MOUNTDEV_LINK_CREATED: 985 case IOCTL_MOUNTDEV_LINK_DELETED: 986 #if (NTDDI_VERSION >= NTDDI_WS03) 987 /* Deprecated Windows 2000/XP versions of IOCTL_MOUNTDEV_LINK_[CREATED|DELETED] 988 * without access protection, that were updated in Windows 2003 */ 989 case CTL_CODE(MOUNTDEVCONTROLTYPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS): 990 case CTL_CODE(MOUNTDEVCONTROLTYPE, 5, METHOD_BUFFERED, FILE_ANY_ACCESS): 991 #endif 992 case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: 993 case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY: 994 { 995 WARN("Ignored MountMgr notification: 0x%lX\n", 996 ioStack->Parameters.DeviceIoControl.IoControlCode); 997 status = STATUS_NOT_IMPLEMENTED; 998 break; 999 } 1000 default: 1001 return ForwardIrpAndForget(DeviceObject, Irp); 1002 } 1003 1004 Irp->IoStatus.Status = status; 1005 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1006 return status; 1007 } 1008