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