xref: /reactos/drivers/storage/partmgr/partition.c (revision fc3ccb39)
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%u\\Partition%u";
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 
29     // create the device object
30 
31     swprintf(nameBuf, L"\\Device\\HarddiskVolume%u", HarddiskVolumeNextId++);
32     RtlCreateUnicodeString(&deviceName, nameBuf);
33 
34     PDEVICE_OBJECT partitionDevice;
35     NTSTATUS status = IoCreateDevice(FDObject->DriverObject,
36                                      sizeof(PARTITION_EXTENSION),
37                                      &deviceName,
38                                      FILE_DEVICE_DISK,
39                                      FILE_DEVICE_SECURE_OPEN,
40                                      FALSE,
41                                      &partitionDevice);
42 
43     if (!NT_SUCCESS(status))
44     {
45         ERR("Unable to create device object %wZ\n", &deviceName);
46         return status;
47     }
48 
49     INFO("Created device object %p %wZ\n", partitionDevice, &deviceName);
50 
51     PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension;
52     RtlZeroMemory(partExt, sizeof(*partExt));
53 
54     partitionDevice->StackSize = FDObject->StackSize;
55     partitionDevice->Flags |= DO_DIRECT_IO;
56 
57     if (PartitionStyle == PARTITION_STYLE_MBR)
58     {
59         partExt->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType;
60         partExt->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator;
61         partExt->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors;
62     }
63     else
64     {
65         partExt->Gpt.PartitionType = PartitionEntry->Gpt.PartitionType;
66         partExt->Gpt.PartitionId = PartitionEntry->Gpt.PartitionType;
67         partExt->Gpt.Attributes = PartitionEntry->Gpt.Attributes;
68 
69         RtlCopyMemory(partExt->Gpt.Name, PartitionEntry->Gpt.Name, sizeof(partExt->Gpt.Name));
70     }
71 
72     partExt->DeviceName = deviceName;
73     partExt->StartingOffset = PartitionEntry->StartingOffset.QuadPart;
74     partExt->PartitionLength = PartitionEntry->PartitionLength.QuadPart;
75     partExt->OnDiskNumber = PartitionEntry->PartitionNumber; // the "physical" partition number
76     partExt->DetectedNumber = PdoNumber; // counts only partitions with PDO created
77 
78     partExt->DeviceObject = partitionDevice;
79     partExt->LowerDevice = FDObject;
80 
81     partitionDevice->Flags &= ~DO_DEVICE_INITIALIZING;
82 
83     *PDO = partitionDevice;
84 
85     return status;
86 }
87 
88 static
89 CODE_SEG("PAGE")
90 NTSTATUS
91 PartitionHandleStartDevice(
92     _In_ PPARTITION_EXTENSION PartExt,
93     _In_ PIRP Irp)
94 {
95     PAGED_CODE();
96 
97     // fix the damn kernel!
98     if (PartExt->DeviceRemoved)
99     {
100         DPRINT1("IRP_MN_START_DEVICE after IRP_MN_REMOVE_DEVICE!\n");
101         return STATUS_SUCCESS;
102     }
103 
104     // first, create a symbolic link for our device
105     WCHAR nameBuf[64];
106     UNICODE_STRING partitionSymlink, interfaceName;
107     PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension;
108 
109     // \\Device\\Harddisk%u\\Partition%u
110     swprintf(nameBuf, PartitionSymLinkFormat,
111         fdoExtension->DiskData.DeviceNumber, PartExt->DetectedNumber);
112 
113     if (!RtlCreateUnicodeString(&partitionSymlink, nameBuf))
114     {
115         return STATUS_INSUFFICIENT_RESOURCES;
116     }
117 
118     NTSTATUS status = IoCreateSymbolicLink(&partitionSymlink, &PartExt->DeviceName);
119 
120     if (!NT_SUCCESS(status))
121     {
122         return status;
123     }
124 
125     PartExt->SymlinkCreated = TRUE;
126 
127     TRACE("Symlink created %wZ -> %wZ\n", &PartExt->DeviceName, &partitionSymlink);
128 
129     // our partition device will have two interfaces:
130     // GUID_DEVINTERFACE_PARTITION and GUID_DEVINTERFACE_VOLUME
131     // the former one is used to notify mountmgr about new device
132 
133     status = IoRegisterDeviceInterface(PartExt->DeviceObject,
134                                        &GUID_DEVINTERFACE_PARTITION,
135                                        NULL,
136                                        &interfaceName);
137 
138     if (!NT_SUCCESS(status))
139     {
140         return status;
141     }
142 
143     PartExt->PartitionInterfaceName = interfaceName;
144     status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
145 
146     INFO("Partition interface %wZ\n", &interfaceName);
147 
148     if (!NT_SUCCESS(status))
149     {
150         RtlFreeUnicodeString(&interfaceName);
151         RtlInitUnicodeString(&PartExt->PartitionInterfaceName, NULL);
152         return status;
153     }
154 
155     status = IoRegisterDeviceInterface(PartExt->DeviceObject,
156                                        &GUID_DEVINTERFACE_VOLUME,
157                                        NULL,
158                                        &interfaceName);
159 
160     if (!NT_SUCCESS(status))
161     {
162         return status;
163     }
164 
165     PartExt->VolumeInterfaceName = interfaceName;
166     status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
167 
168     INFO("Volume interface %wZ\n", &interfaceName);
169 
170     if (!NT_SUCCESS(status))
171     {
172         RtlFreeUnicodeString(&interfaceName);
173         RtlInitUnicodeString(&PartExt->VolumeInterfaceName, NULL);
174         return status;
175     }
176 
177     return STATUS_SUCCESS;
178 }
179 
180 CODE_SEG("PAGE")
181 NTSTATUS
182 PartitionHandleRemove(
183     _In_ PPARTITION_EXTENSION PartExt,
184     _In_ BOOLEAN FinalRemove)
185 {
186     NTSTATUS status;
187 
188     PAGED_CODE();
189 
190     // remove the symbolic link
191     if (PartExt->SymlinkCreated)
192     {
193         WCHAR nameBuf[64];
194         UNICODE_STRING partitionSymlink;
195         PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension;
196 
197         swprintf(nameBuf, PartitionSymLinkFormat,
198             fdoExtension->DiskData.DeviceNumber, PartExt->DetectedNumber);
199 
200         RtlInitUnicodeString(&partitionSymlink, nameBuf);
201 
202         status = IoDeleteSymbolicLink(&partitionSymlink);
203 
204         if (!NT_SUCCESS(status))
205         {
206             return status;
207         }
208         PartExt->SymlinkCreated = FALSE;
209 
210         INFO("Symlink removed %wZ -> %wZ\n", &PartExt->DeviceName, &partitionSymlink);
211     }
212 
213     // release device interfaces
214     if (PartExt->PartitionInterfaceName.Buffer)
215     {
216         status = IoSetDeviceInterfaceState(&PartExt->PartitionInterfaceName, FALSE);
217         if (!NT_SUCCESS(status))
218         {
219             return status;
220         }
221         RtlFreeUnicodeString(&PartExt->PartitionInterfaceName);
222         RtlInitUnicodeString(&PartExt->PartitionInterfaceName, NULL);
223     }
224 
225     if (PartExt->VolumeInterfaceName.Buffer)
226     {
227         status = IoSetDeviceInterfaceState(&PartExt->VolumeInterfaceName, FALSE);
228         if (!NT_SUCCESS(status))
229         {
230             return status;
231         }
232         RtlFreeUnicodeString(&PartExt->VolumeInterfaceName);
233         RtlInitUnicodeString(&PartExt->VolumeInterfaceName, NULL);
234     }
235 
236     if (FinalRemove)
237     {
238         // fix the damn kernel!
239         if (PartExt->DeviceRemoved)
240         {
241             DPRINT1("Double IRP_MN_REMOVE_DEVICE!\n");
242             return STATUS_SUCCESS;
243         }
244 
245         PartExt->DeviceRemoved = TRUE;
246 
247         ASSERT(PartExt->DeviceName.Buffer);
248         if (PartExt->DeviceName.Buffer)
249         {
250             INFO("Removed device %wZ\n", &PartExt->DeviceName);
251             RtlFreeUnicodeString(&PartExt->DeviceName);
252         }
253 
254         IoDeleteDevice(PartExt->DeviceObject);
255     }
256 
257     return STATUS_SUCCESS;
258 }
259 
260 static
261 CODE_SEG("PAGE")
262 NTSTATUS
263 PartitionHandleDeviceRelations(
264     _In_ PPARTITION_EXTENSION PartExt,
265     _In_ PIRP Irp)
266 {
267     PAGED_CODE();
268 
269     // fix the damn kernel!
270     if (PartExt->DeviceRemoved)
271     {
272         DPRINT1("QDR after device removal!\n");
273         return STATUS_DEVICE_DOES_NOT_EXIST;
274     }
275 
276     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
277     DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type;
278 
279     if (type == TargetDeviceRelation)
280     {
281         // Device relations has one entry built in to it's size.
282         PDEVICE_RELATIONS deviceRelations =
283             ExAllocatePoolZero(PagedPool, sizeof(DEVICE_RELATIONS), TAG_PARTMGR);
284 
285         if (deviceRelations != NULL)
286         {
287             deviceRelations->Count = 1;
288             deviceRelations->Objects[0] = PartExt->DeviceObject;
289             ObReferenceObject(deviceRelations->Objects[0]);
290 
291             Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
292             return STATUS_SUCCESS;
293         }
294         else
295         {
296             return STATUS_INSUFFICIENT_RESOURCES;
297         }
298     }
299     else
300     {
301         Irp->IoStatus.Information = 0;
302         return Irp->IoStatus.Status;
303     }
304 }
305 
306 static
307 CODE_SEG("PAGE")
308 NTSTATUS
309 PartitionHandleQueryId(
310     _In_ PPARTITION_EXTENSION PartExt,
311     _In_ PIRP Irp)
312 {
313     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
314     BUS_QUERY_ID_TYPE idType = ioStack->Parameters.QueryId.IdType;
315     UNICODE_STRING idString;
316     NTSTATUS status;
317 
318     PAGED_CODE();
319 
320     switch (idType)
321     {
322         case BusQueryDeviceID:
323             status = RtlCreateUnicodeString(&idString, L"STORAGE\\Partition")
324                      ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
325             break;
326         case BusQueryHardwareIDs:
327         case BusQueryCompatibleIDs:
328         {
329             static WCHAR volumeID[] = L"STORAGE\\Volume\0";
330 
331             idString.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(volumeID), TAG_PARTMGR);
332             RtlCopyMemory(idString.Buffer, volumeID, sizeof(volumeID));
333 
334             status = STATUS_SUCCESS;
335             break;
336         }
337         case BusQueryInstanceID:
338         {
339             WCHAR string[64];
340             PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension;
341 
342             PartMgrAcquireLayoutLock(fdoExtension);
343 
344             if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
345             {
346                 swprintf(string, L"S%08lx_O%I64x_L%I64x",
347                          fdoExtension->DiskData.Mbr.Signature,
348                          PartExt->StartingOffset,
349                          PartExt->PartitionLength);
350             }
351             else
352             {
353                 swprintf(string,
354                         L"S%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02xS_O%I64x_L%I64x",
355                         fdoExtension->DiskData.Gpt.DiskId.Data1,
356                         fdoExtension->DiskData.Gpt.DiskId.Data2,
357                         fdoExtension->DiskData.Gpt.DiskId.Data3,
358                         fdoExtension->DiskData.Gpt.DiskId.Data4[0],
359                         fdoExtension->DiskData.Gpt.DiskId.Data4[1],
360                         fdoExtension->DiskData.Gpt.DiskId.Data4[2],
361                         fdoExtension->DiskData.Gpt.DiskId.Data4[3],
362                         fdoExtension->DiskData.Gpt.DiskId.Data4[4],
363                         fdoExtension->DiskData.Gpt.DiskId.Data4[5],
364                         fdoExtension->DiskData.Gpt.DiskId.Data4[6],
365                         fdoExtension->DiskData.Gpt.DiskId.Data4[7],
366                         PartExt->StartingOffset,
367                         PartExt->PartitionLength);
368             }
369 
370             PartMgrReleaseLayoutLock(fdoExtension);
371 
372             status = RtlCreateUnicodeString(&idString, string)
373                      ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
374             break;
375         }
376         default:
377             status = STATUS_NOT_SUPPORTED;
378             break;
379     }
380 
381     Irp->IoStatus.Information = NT_SUCCESS(status) ? (ULONG_PTR) idString.Buffer : 0;
382     return status;
383 }
384 
385 static
386 CODE_SEG("PAGE")
387 NTSTATUS
388 PartitionHandleQueryCapabilities(
389     _In_ PPARTITION_EXTENSION PartExt,
390     _In_ PIRP Irp)
391 {
392     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
393     PDEVICE_CAPABILITIES devCaps = ioStack->Parameters.DeviceCapabilities.Capabilities;
394 
395     PAGED_CODE();
396     ASSERT(devCaps);
397 
398     devCaps->SilentInstall = TRUE;
399     devCaps->RawDeviceOK = TRUE;
400     devCaps->NoDisplayInUI = TRUE;
401     devCaps->Address = PartExt->OnDiskNumber;
402     devCaps->UniqueID = 1;
403 
404     return STATUS_SUCCESS;
405 }
406 
407 CODE_SEG("PAGE")
408 NTSTATUS
409 PartitionHandlePnp(
410     _In_ PDEVICE_OBJECT DeviceObject,
411     _In_ PIRP Irp)
412 {
413     PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
414     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
415     NTSTATUS status;
416 
417     PAGED_CODE();
418 
419     switch (ioStack->MinorFunction)
420     {
421         case IRP_MN_START_DEVICE:
422         {
423             status = PartitionHandleStartDevice(partExt, Irp);
424             break;
425         }
426         case IRP_MN_QUERY_DEVICE_RELATIONS:
427         {
428             status = PartitionHandleDeviceRelations(partExt, Irp);
429             break;
430         }
431         case IRP_MN_QUERY_STOP_DEVICE:
432         case IRP_MN_QUERY_REMOVE_DEVICE:
433         case IRP_MN_CANCEL_STOP_DEVICE:
434         case IRP_MN_CANCEL_REMOVE_DEVICE:
435         case IRP_MN_STOP_DEVICE:
436         {
437             status = STATUS_SUCCESS;
438             break;
439         }
440         case IRP_MN_SURPRISE_REMOVAL:
441         {
442             status = PartitionHandleRemove(partExt, FALSE);
443             break;
444         }
445         case IRP_MN_REMOVE_DEVICE:
446         {
447             status = PartitionHandleRemove(partExt, TRUE);
448             break;
449         }
450         case IRP_MN_QUERY_ID:
451         {
452             status = PartitionHandleQueryId(partExt, Irp);
453             break;
454         }
455         case IRP_MN_QUERY_CAPABILITIES:
456         {
457             status = PartitionHandleQueryCapabilities(partExt, Irp);
458             break;
459         }
460         default:
461         {
462             Irp->IoStatus.Information = 0;
463             status = STATUS_NOT_SUPPORTED;
464         }
465     }
466 
467     Irp->IoStatus.Status = status;
468     IoCompleteRequest(Irp, IO_NO_INCREMENT);
469     return status;
470 }
471 
472 NTSTATUS
473 PartitionHandleDeviceControl(
474     _In_ PDEVICE_OBJECT DeviceObject,
475     _In_ PIRP Irp)
476 {
477     PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
478     PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
479     PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension;
480     NTSTATUS status;
481 
482     ASSERT(!partExt->IsFDO);
483 
484     if (!partExt->IsEnumerated)
485     {
486         Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
487         IoCompleteRequest(Irp, IO_NO_INCREMENT);
488         return STATUS_DEVICE_DOES_NOT_EXIST;
489     }
490 
491     switch (ioStack->Parameters.DeviceIoControl.IoControlCode)
492     {
493         // disk stuff
494         case IOCTL_DISK_GET_PARTITION_INFO:
495         {
496             if (!VerifyIrpOutBufferSize(Irp, sizeof(PARTITION_INFORMATION)))
497             {
498                 status = STATUS_BUFFER_TOO_SMALL;
499                 break;
500             }
501 
502             PartMgrAcquireLayoutLock(fdoExtension);
503 
504             // not supported on anything other than MBR
505             if (fdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_MBR)
506             {
507                 status = STATUS_INVALID_DEVICE_REQUEST;
508                 PartMgrReleaseLayoutLock(fdoExtension);
509                 break;
510             }
511 
512             PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer;
513 
514             *partInfo = (PARTITION_INFORMATION){
515                 .PartitionType = partExt->Mbr.PartitionType,
516                 .StartingOffset.QuadPart = partExt->StartingOffset,
517                 .PartitionLength.QuadPart = partExt->PartitionLength,
518                 .HiddenSectors = partExt->Mbr.HiddenSectors,
519                 .PartitionNumber = partExt->DetectedNumber,
520                 .BootIndicator = partExt->Mbr.BootIndicator,
521                 .RecognizedPartition = partExt->Mbr.RecognizedPartition,
522                 .RewritePartition = FALSE,
523             };
524 
525             PartMgrReleaseLayoutLock(fdoExtension);
526 
527             Irp->IoStatus.Information = sizeof(*partInfo);
528             status = STATUS_SUCCESS;
529             break;
530         }
531         case IOCTL_DISK_GET_PARTITION_INFO_EX:
532         {
533             if (!VerifyIrpOutBufferSize(Irp, sizeof(PARTITION_INFORMATION_EX)))
534             {
535                 status = STATUS_BUFFER_TOO_SMALL;
536                 break;
537             }
538 
539             PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer;
540 
541             PartMgrAcquireLayoutLock(fdoExtension);
542 
543             *partInfoEx = (PARTITION_INFORMATION_EX){
544                 .StartingOffset.QuadPart = partExt->StartingOffset,
545                 .PartitionLength.QuadPart = partExt->PartitionLength,
546                 .PartitionNumber = partExt->DetectedNumber,
547                 .PartitionStyle = fdoExtension->DiskData.PartitionStyle,
548                 .RewritePartition = FALSE,
549             };
550 
551             if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
552             {
553                 partInfoEx->Mbr = (PARTITION_INFORMATION_MBR){
554                     .PartitionType = partExt->Mbr.PartitionType,
555                     .HiddenSectors = partExt->Mbr.HiddenSectors,
556                     .BootIndicator = partExt->Mbr.BootIndicator,
557                     .RecognizedPartition = partExt->Mbr.RecognizedPartition,
558                 };
559             }
560             else
561             {
562                 partInfoEx->Gpt = (PARTITION_INFORMATION_GPT){
563                     .PartitionType = partExt->Gpt.PartitionType,
564                     .PartitionId = partExt->Gpt.PartitionId,
565                     .Attributes = partExt->Gpt.Attributes,
566                 };
567 
568                 RtlCopyMemory(partInfoEx->Gpt.Name,
569                               partExt->Gpt.Name,
570                               sizeof(partInfoEx->Gpt.Name));
571             }
572 
573             PartMgrReleaseLayoutLock(fdoExtension);
574 
575             Irp->IoStatus.Information = sizeof(*partInfoEx);
576             status = STATUS_SUCCESS;
577             break;
578         }
579         case IOCTL_DISK_SET_PARTITION_INFO:
580         {
581             PSET_PARTITION_INFORMATION inputBuffer = Irp->AssociatedIrp.SystemBuffer;
582             if (!VerifyIrpInBufferSize(Irp, sizeof(*inputBuffer)))
583             {
584                 status = STATUS_INFO_LENGTH_MISMATCH;
585                 break;
586             }
587 
588             PartMgrAcquireLayoutLock(fdoExtension);
589 
590             // these functions use on disk numbers, not detected ones
591             status = IoSetPartitionInformation(fdoExtension->LowerDevice,
592                                                fdoExtension->DiskData.BytesPerSector,
593                                                partExt->OnDiskNumber,
594                                                inputBuffer->PartitionType);
595 
596             if (NT_SUCCESS(status))
597             {
598                 partExt->Mbr.PartitionType = inputBuffer->PartitionType;
599             }
600 
601             PartMgrReleaseLayoutLock(fdoExtension);
602 
603             Irp->IoStatus.Information = 0;
604             break;
605         }
606         case IOCTL_DISK_SET_PARTITION_INFO_EX:
607         {
608             PSET_PARTITION_INFORMATION_EX inputBuffer = Irp->AssociatedIrp.SystemBuffer;
609             if (!VerifyIrpInBufferSize(Irp, sizeof(*inputBuffer)))
610             {
611                 status = STATUS_INFO_LENGTH_MISMATCH;
612                 break;
613             }
614 
615             PartMgrAcquireLayoutLock(fdoExtension);
616 
617             // these functions use on disk numbers, not detected ones
618             status = IoSetPartitionInformationEx(fdoExtension->LowerDevice,
619                                                  partExt->OnDiskNumber,
620                                                  inputBuffer);
621 
622             if (NT_SUCCESS(status))
623             {
624                 if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
625                 {
626                     partExt->Mbr.PartitionType = inputBuffer->Mbr.PartitionType;
627                 }
628                 else
629                 {
630                     partExt->Gpt.PartitionType = inputBuffer->Gpt.PartitionType;
631                     partExt->Gpt.PartitionId = inputBuffer->Gpt.PartitionId;
632                     partExt->Gpt.Attributes = inputBuffer->Gpt.Attributes;
633 
634                     RtlMoveMemory(partExt->Gpt.Name,
635                                   inputBuffer->Gpt.Name,
636                                   sizeof(partExt->Gpt.Name));
637                 }
638             }
639 
640             PartMgrReleaseLayoutLock(fdoExtension);
641 
642             Irp->IoStatus.Information = 0;
643             break;
644         }
645         case IOCTL_DISK_GET_LENGTH_INFO:
646         {
647             PGET_LENGTH_INFORMATION lengthInfo = Irp->AssociatedIrp.SystemBuffer;
648             if (!VerifyIrpOutBufferSize(Irp, sizeof(*lengthInfo)))
649             {
650                 status = STATUS_BUFFER_TOO_SMALL;
651                 break;
652             }
653 
654             PartMgrAcquireLayoutLock(fdoExtension);
655 
656             lengthInfo->Length.QuadPart = partExt->PartitionLength;
657 
658             PartMgrReleaseLayoutLock(fdoExtension);
659 
660             status = STATUS_SUCCESS;
661             Irp->IoStatus.Information = sizeof(*lengthInfo);
662             break;
663         }
664         case IOCTL_DISK_VERIFY:
665         {
666             PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
667             if (!VerifyIrpInBufferSize(Irp, sizeof(*verifyInfo)))
668             {
669                 status = STATUS_INFO_LENGTH_MISMATCH;
670                 break;
671             }
672 
673             // Partition device should just adjust the starting offset
674             verifyInfo->StartingOffset.QuadPart += partExt->StartingOffset;
675             return ForwardIrpAndForget(DeviceObject, Irp);
676         }
677         case IOCTL_DISK_UPDATE_PROPERTIES:
678         {
679             fdoExtension->LayoutValid = FALSE;
680             IoInvalidateDeviceRelations(fdoExtension->PhysicalDiskDO, BusRelations);
681 
682             status = STATUS_SUCCESS;
683             break;
684         }
685         case IOCTL_STORAGE_MEDIA_REMOVAL:
686         {
687             return ForwardIrpAndForget(DeviceObject, Irp);
688         }
689         // volume stuff (most of that should be in volmgr.sys one it is implemented)
690         case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
691         {
692             PVOLUME_DISK_EXTENTS volExts = Irp->AssociatedIrp.SystemBuffer;
693 
694             // we fill only one extent entry so sizeof(*volExts) is enough
695             if (!VerifyIrpOutBufferSize(Irp, sizeof(*volExts)))
696             {
697                 status = STATUS_BUFFER_TOO_SMALL;
698                 break;
699             }
700 
701             PartMgrAcquireLayoutLock(fdoExtension);
702 
703             // the only type of volume we support right now is disk partition
704             // so this structure is simple
705 
706             *volExts = (VOLUME_DISK_EXTENTS) {
707                 .NumberOfDiskExtents = 1,
708                 .Extents = {{
709                     .DiskNumber = fdoExtension->DiskData.DeviceNumber,
710                     .StartingOffset.QuadPart = partExt->StartingOffset,
711                     .ExtentLength.QuadPart = partExt->PartitionLength
712                 }}
713             };
714 
715             PartMgrReleaseLayoutLock(fdoExtension);
716 
717             status = STATUS_SUCCESS;
718             Irp->IoStatus.Information = sizeof(*volExts);
719             break;
720         }
721         case IOCTL_VOLUME_ONLINE:
722         {
723             status = STATUS_SUCCESS;
724             break;
725         }
726         case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
727         {
728             PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION gptAttrs = Irp->AssociatedIrp.SystemBuffer;
729             if (!VerifyIrpOutBufferSize(Irp, sizeof(*gptAttrs)))
730             {
731                 status = STATUS_BUFFER_TOO_SMALL;
732                 break;
733             }
734 
735             // not supported on anything other than GPT
736             if (fdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_GPT)
737             {
738                 status = STATUS_INVALID_DEVICE_REQUEST;
739                 break;
740             }
741 
742             gptAttrs->GptAttributes = partExt->Gpt.Attributes;
743 
744             status = STATUS_SUCCESS;
745             Irp->IoStatus.Information = sizeof(*gptAttrs);
746             break;
747         }
748         // mountmgr stuff
749         case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
750         {
751             PMOUNTDEV_NAME name = Irp->AssociatedIrp.SystemBuffer;
752 
753             if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT)))
754             {
755                 status = STATUS_BUFFER_TOO_SMALL;
756                 break;
757             }
758 
759             name->NameLength = partExt->DeviceName.Length;
760 
761             // return NameLength back
762             if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT) + name->NameLength))
763             {
764                 Irp->IoStatus.Information = sizeof(USHORT);
765                 status = STATUS_BUFFER_OVERFLOW;
766                 break;
767             }
768 
769             RtlCopyMemory(name->Name, partExt->DeviceName.Buffer, name->NameLength);
770 
771             status = STATUS_SUCCESS;
772             Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength;
773             break;
774         }
775         case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
776         {
777             PMOUNTDEV_UNIQUE_ID uniqueId = Irp->AssociatedIrp.SystemBuffer;
778 
779             if (!partExt->VolumeInterfaceName.Buffer)
780             {
781                 status = STATUS_INVALID_PARAMETER;
782                 break;
783             }
784 
785             if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT)))
786             {
787                 status = STATUS_BUFFER_TOO_SMALL;
788                 break;
789             }
790 
791             uniqueId->UniqueIdLength = partExt->VolumeInterfaceName.Length;
792 
793             // return UniqueIdLength back
794             if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT) + uniqueId->UniqueIdLength))
795             {
796                 Irp->IoStatus.Information = sizeof(USHORT);
797                 status = STATUS_BUFFER_OVERFLOW;
798                 break;
799             }
800 
801             RtlCopyMemory(uniqueId->UniqueId,
802                           partExt->VolumeInterfaceName.Buffer,
803                           uniqueId->UniqueIdLength);
804 
805             status = STATUS_SUCCESS;
806             Irp->IoStatus.Information = sizeof(USHORT) + uniqueId->UniqueIdLength;
807             break;
808         }
809         default:
810             return ForwardIrpAndForget(DeviceObject, Irp);
811     }
812 
813     Irp->IoStatus.Status = status;
814     IoCompleteRequest(Irp, IO_NO_INCREMENT);
815     return status;
816 }
817