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