1 /*
2 * PROJECT: Partition manager driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Main file
5 * COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
6 */
7
8 /* The Partition Manager Driver in ReactOS complements disk.sys/classpnp.sys drivers
9 * (which are derived from Windows 10 drivers) so does not do exactly what Windows 2003 partmgr.sys
10 * does. Here is acts like both partition and volume manager, because volmgr.sys does not (yet)
11 * exist in ReactOS. Thus handles some IOCTL_VOLUME_*, and IOCTL_MOUNTMGR_* IOCTLs.
12 */
13
14 #include "partmgr.h"
15
16
17 static
18 CODE_SEG("PAGE")
19 PDRIVE_LAYOUT_INFORMATION
PartMgrConvertExtendedToLayout(_In_ CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)20 PartMgrConvertExtendedToLayout(
21 _In_ CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)
22 {
23 PDRIVE_LAYOUT_INFORMATION Layout;
24 PPARTITION_INFORMATION Partition;
25 PPARTITION_INFORMATION_EX PartitionEx;
26
27 PAGED_CODE();
28
29 ASSERT(LayoutEx);
30
31 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR)
32 {
33 ASSERT(FALSE);
34 return NULL;
35 }
36
37 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
38 LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
39
40 Layout = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR);
41
42 if (Layout == NULL)
43 {
44 return NULL;
45 }
46
47 Layout->Signature = LayoutEx->Mbr.Signature;
48 Layout->PartitionCount = LayoutEx->PartitionCount;
49
50 for (UINT32 i = 0; i < LayoutEx->PartitionCount; i++)
51 {
52 Partition = &Layout->PartitionEntry[i];
53 PartitionEx = &LayoutEx->PartitionEntry[i];
54
55 Partition->StartingOffset = PartitionEx->StartingOffset;
56 Partition->PartitionLength = PartitionEx->PartitionLength;
57 Partition->RewritePartition = PartitionEx->RewritePartition;
58 Partition->PartitionNumber = PartitionEx->PartitionNumber;
59
60 Partition->PartitionType = PartitionEx->Mbr.PartitionType;
61 Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
62 Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
63 Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
64 }
65
66 return Layout;
67 }
68
69 static
70 CODE_SEG("PAGE")
71 PDRIVE_LAYOUT_INFORMATION_EX
PartMgrConvertLayoutToExtended(_In_ CONST PDRIVE_LAYOUT_INFORMATION Layout)72 PartMgrConvertLayoutToExtended(
73 _In_ CONST PDRIVE_LAYOUT_INFORMATION Layout)
74 {
75 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
76
77 PAGED_CODE();
78
79 ASSERT(Layout != NULL);
80
81 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
82 Layout->PartitionCount * sizeof (PARTITION_INFORMATION_EX);
83
84 layoutEx = ExAllocatePoolUninitialized(PagedPool, layoutSize, TAG_PARTMGR);
85
86 if (layoutEx == NULL)
87 {
88 return NULL;
89 }
90
91 layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
92 layoutEx->PartitionCount = Layout->PartitionCount;
93 layoutEx->Mbr.Signature = Layout->Signature;
94
95 for (UINT32 i = 0; i < Layout->PartitionCount; i++)
96 {
97 PPARTITION_INFORMATION part = &Layout->PartitionEntry[i];
98
99 layoutEx->PartitionEntry[i] = (PARTITION_INFORMATION_EX) {
100 .PartitionStyle = PARTITION_STYLE_MBR,
101 .StartingOffset = part->StartingOffset,
102 .PartitionLength = part->PartitionLength,
103 .RewritePartition = part->RewritePartition,
104 .PartitionNumber = part->PartitionNumber,
105 .Mbr = {
106 .PartitionType = part->PartitionType,
107 .BootIndicator = part->BootIndicator,
108 .RecognizedPartition = part->RecognizedPartition,
109 .HiddenSectors = part->HiddenSectors,
110 }
111 };
112 }
113
114 return layoutEx;
115 }
116
117 /**
118 * @brief
119 * Detects whether a disk is a "super-floppy", i.e. an unpartitioned
120 * disk with only a valid VBR, as reported by IoReadPartitionTable()
121 * and IoWritePartitionTable():
122 * only one single partition starting at offset zero and spanning the
123 * whole disk, without hidden sectors, whose type is FAT16 non-bootable.
124 *
125 * Accessing \Device\HarddiskN\Partition0 or Partition1 on such disks
126 * returns the same data.
127 *
128 * @note
129 * - Requires partitioning lock held.
130 * - Uses the cached disk partition layout.
131 **/
132 static
133 CODE_SEG("PAGE")
134 BOOLEAN
PartMgrIsDiskSuperFloppy(_In_ PFDO_EXTENSION FdoExtension)135 PartMgrIsDiskSuperFloppy(
136 _In_ PFDO_EXTENSION FdoExtension)
137 {
138 PPARTITION_INFORMATION_EX PartitionInfo;
139
140 PAGED_CODE();
141
142 ASSERT(FdoExtension->LayoutValid && FdoExtension->LayoutCache);
143
144 /* We must be MBR and have only one partition */
145 ASSERT(FdoExtension->DiskData.PartitionStyle == FdoExtension->LayoutCache->PartitionStyle);
146 if (FdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_MBR)
147 return FALSE;
148 if (FdoExtension->LayoutCache->PartitionCount != 1)
149 return FALSE;
150
151 /* Get the single partition entry */
152 PartitionInfo = FdoExtension->LayoutCache->PartitionEntry;
153 ASSERT(FdoExtension->DiskData.PartitionStyle == PartitionInfo->PartitionStyle);
154
155 /* The single partition must start at the beginning of the disk */
156 if (!(PartitionInfo->StartingOffset.QuadPart == 0 &&
157 PartitionInfo->Mbr.HiddenSectors == 0))
158 {
159 return FALSE;
160 }
161
162 /* The disk signature is usually set to 1; warn in case it's not */
163 ASSERT(FdoExtension->DiskData.Mbr.Signature == FdoExtension->LayoutCache->Mbr.Signature);
164 if (FdoExtension->DiskData.Mbr.Signature != 1)
165 {
166 WARN("Super-Floppy disk %lu signature %08x != 1!\n",
167 FdoExtension->DiskData.DeviceNumber, FdoExtension->DiskData.Mbr.Signature);
168 }
169
170 /* The partition must be recognized and report as FAT16 non-bootable */
171 if ((PartitionInfo->Mbr.RecognizedPartition != TRUE) ||
172 (PartitionInfo->Mbr.PartitionType != PARTITION_FAT_16) ||
173 (PartitionInfo->Mbr.BootIndicator != FALSE))
174 {
175 WARN("Super-Floppy disk %lu does not return default settings!\n"
176 " RecognizedPartition = %s, expected TRUE\n"
177 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n"
178 " BootIndicator = %s, expected FALSE\n",
179 FdoExtension->DiskData.DeviceNumber,
180 PartitionInfo->Mbr.RecognizedPartition ? "TRUE" : "FALSE",
181 PartitionInfo->Mbr.PartitionType,
182 PartitionInfo->Mbr.BootIndicator ? "TRUE" : "FALSE");
183 }
184
185 /* The partition and disk sizes should agree */
186 if (PartitionInfo->PartitionLength.QuadPart != FdoExtension->DiskData.DiskSize)
187 {
188 WARN("PartitionLength = %I64u is different from DiskSize = %I64u\n",
189 PartitionInfo->PartitionLength.QuadPart, FdoExtension->DiskData.DiskSize);
190 }
191
192 return TRUE;
193 }
194
195 static
196 CODE_SEG("PAGE")
197 VOID
PartMgrUpdatePartitionDevices(_In_ PFDO_EXTENSION FdoExtension,_Inout_ PDRIVE_LAYOUT_INFORMATION_EX NewLayout)198 PartMgrUpdatePartitionDevices(
199 _In_ PFDO_EXTENSION FdoExtension,
200 _Inout_ PDRIVE_LAYOUT_INFORMATION_EX NewLayout)
201 {
202 NTSTATUS status;
203 PSINGLE_LIST_ENTRY curEntry, prevEntry;
204 UINT32 totalPartitions = 0;
205
206 // Clear the partition numbers from the list entries
207 for (UINT32 i = 0; i < NewLayout->PartitionCount; i++)
208 {
209 NewLayout->PartitionEntry[i].PartitionNumber = 0;
210 }
211
212 // iterate over old partition list
213 prevEntry = &FdoExtension->PartitionList;
214 curEntry = FdoExtension->PartitionList.Next;
215 while (curEntry != NULL)
216 {
217 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, PARTITION_EXTENSION, ListEntry);
218 UINT32 partNumber = 0; // count detected partitions for device symlinks
219 BOOLEAN found = FALSE;
220 PPARTITION_INFORMATION_EX partEntry;
221
222 // trying to find this partition in returned layout
223 for (UINT32 i = 0; i < NewLayout->PartitionCount; i++)
224 {
225 partEntry = &NewLayout->PartitionEntry[i];
226
227 // skip unused and container partitions
228 if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR &&
229 (partEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
230 IsContainerPartition(partEntry->Mbr.PartitionType)))
231 {
232 continue;
233 }
234
235 partNumber++;
236
237 // skip already found partitions
238 if (partEntry->PartitionNumber)
239 {
240 continue;
241 }
242
243 // skip if partitions are not equal
244 if (partEntry->StartingOffset.QuadPart != partExt->StartingOffset ||
245 partEntry->PartitionLength.QuadPart != partExt->PartitionLength)
246 {
247 continue;
248 }
249
250 // found matching partition - processing it
251 found = TRUE;
252 break;
253 }
254
255 if (found)
256 {
257 // update (possibly changed) partition metadata
258 if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR)
259 {
260 partExt->Mbr.PartitionType = partEntry->Mbr.PartitionType;
261 partExt->Mbr.BootIndicator = partEntry->Mbr.BootIndicator;
262 }
263 else
264 {
265 partExt->Gpt.PartitionType = partEntry->Gpt.PartitionType;
266 partExt->Gpt.PartitionId = partEntry->Gpt.PartitionId;
267 partExt->Gpt.Attributes = partEntry->Gpt.Attributes;
268
269 RtlCopyMemory(partExt->Gpt.Name, partEntry->Gpt.Name, sizeof(partExt->Gpt.Name));
270 }
271
272 partExt->OnDiskNumber = partNumber;
273 partEntry->PartitionNumber = partNumber; // mark it as a found one
274 totalPartitions++;
275 }
276 else
277 {
278 // detach the device from the list
279 prevEntry->Next = curEntry->Next;
280 curEntry = prevEntry;
281 partExt->Attached = FALSE;
282
283 // enumerated PDOs will receive IRP_MN_REMOVE_DEVICE
284 if (!partExt->IsEnumerated)
285 {
286 PartitionHandleRemove(partExt, TRUE);
287 }
288 }
289
290 prevEntry = curEntry;
291 curEntry = curEntry->Next;
292 }
293
294 UINT32 partNumber = 0;
295 UINT32 pdoNumber = 1;
296
297 // now looking through remaining "new" partitions
298 for (UINT32 i = 0; i < NewLayout->PartitionCount; i++)
299 {
300 PPARTITION_INFORMATION_EX partEntry = &NewLayout->PartitionEntry[i];
301
302 // again, skip unused and container partitions
303 if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR &&
304 (partEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
305 IsContainerPartition(partEntry->Mbr.PartitionType)))
306 {
307 continue;
308 }
309
310 partNumber++;
311
312 // and skip processed partitions
313 if (partEntry->PartitionNumber != 0)
314 {
315 continue;
316 }
317
318 // find the first free PDO index
319 for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
320 curEntry != NULL;
321 curEntry = curEntry->Next)
322 {
323 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
324 PARTITION_EXTENSION,
325 ListEntry);
326
327 if (partExt->DetectedNumber == pdoNumber)
328 {
329 // found a matching pdo number - restart the search
330 curEntry = FdoExtension->PartitionList.Next;
331 pdoNumber++;
332 }
333 }
334
335 partEntry->PartitionNumber = partNumber;
336
337 PDEVICE_OBJECT partitionDevice;
338 status = PartitionCreateDevice(FdoExtension->DeviceObject,
339 partEntry,
340 pdoNumber,
341 NewLayout->PartitionStyle,
342 &partitionDevice);
343 if (!NT_SUCCESS(status))
344 {
345 partEntry->PartitionNumber = 0;
346 continue;
347 }
348
349 // mark partition as removable if parent device is removable
350 if (FdoExtension->LowerDevice->Characteristics & FILE_REMOVABLE_MEDIA)
351 partitionDevice->Characteristics |= FILE_REMOVABLE_MEDIA;
352
353 totalPartitions++;
354
355 // insert the structure to the partition list
356 curEntry = FdoExtension->PartitionList.Next;
357 prevEntry = NULL;
358 while (curEntry != NULL)
359 {
360 PPARTITION_EXTENSION curPart = CONTAINING_RECORD(curEntry,
361 PARTITION_EXTENSION,
362 ListEntry);
363 if (curPart->OnDiskNumber < partNumber)
364 {
365 prevEntry = curEntry;
366 curEntry = curPart->ListEntry.Next;
367 }
368 else
369 { // we found where to put the partition
370 break;
371 }
372 }
373
374 PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension;
375
376 if (prevEntry)
377 {
378 // insert after prevEntry
379 partExt->ListEntry.Next = prevEntry->Next;
380 prevEntry->Next = &partExt->ListEntry;
381 }
382 else
383 {
384 // insert at the beginning
385 partExt->ListEntry.Next = FdoExtension->PartitionList.Next;
386 FdoExtension->PartitionList.Next = &partExt->ListEntry;
387 }
388
389 partExt->Attached = TRUE;
390 }
391
392 FdoExtension->EnumeratedPartitionsTotal = totalPartitions;
393 }
394
395 /**
396 * @brief
397 * Retrieves the disk partition layout from the given disk FDO.
398 *
399 * If the disk layout cache is valid, just return it; otherwise,
400 * read the partition table layout from disk and update the cache.
401 *
402 * @note Requires partitioning lock held.
403 **/
404 static
405 CODE_SEG("PAGE")
406 NTSTATUS
PartMgrGetDriveLayout(_In_ PFDO_EXTENSION FdoExtension,_Out_ PDRIVE_LAYOUT_INFORMATION_EX * DriveLayout)407 PartMgrGetDriveLayout(
408 _In_ PFDO_EXTENSION FdoExtension,
409 _Out_ PDRIVE_LAYOUT_INFORMATION_EX *DriveLayout)
410 {
411 PAGED_CODE();
412
413 if (FdoExtension->LayoutValid)
414 {
415 *DriveLayout = FdoExtension->LayoutCache;
416 return STATUS_SUCCESS;
417 }
418
419 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL;
420 NTSTATUS status = IoReadPartitionTableEx(FdoExtension->LowerDevice, &layoutEx);
421 if (!NT_SUCCESS(status))
422 return status;
423
424 if (FdoExtension->LayoutCache)
425 ExFreePool(FdoExtension->LayoutCache);
426
427 FdoExtension->LayoutCache = layoutEx;
428 FdoExtension->LayoutValid = TRUE;
429
430 FdoExtension->DiskData.PartitionStyle = layoutEx->PartitionStyle;
431 if (FdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
432 {
433 FdoExtension->DiskData.Mbr.Signature = layoutEx->Mbr.Signature;
434 // FdoExtension->DiskData.Mbr.Checksum = geometryEx.Partition.Mbr.CheckSum;
435 }
436 else
437 {
438 FdoExtension->DiskData.Gpt.DiskId = layoutEx->Gpt.DiskId;
439 }
440
441 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension);
442
443 *DriveLayout = layoutEx;
444 return status;
445 }
446
447 static
448 CODE_SEG("PAGE")
449 NTSTATUS
FdoIoctlDiskGetDriveGeometryEx(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)450 FdoIoctlDiskGetDriveGeometryEx(
451 _In_ PFDO_EXTENSION FdoExtension,
452 _In_ PIRP Irp)
453 {
454 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
455
456 PAGED_CODE();
457
458 // We're patching the DISK_PARTITION_INFO part of the returned structure
459 // as disk.sys doesn't really know about the partition table on a disk
460
461 PDISK_GEOMETRY_EX_INTERNAL geometryEx = Irp->AssociatedIrp.SystemBuffer;
462 ULONG outBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength;
463 NTSTATUS status;
464
465 status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
466 FdoExtension->LowerDevice,
467 NULL,
468 0,
469 geometryEx,
470 outBufferLength,
471 FALSE);
472
473 if (!NT_SUCCESS(status))
474 {
475 return status;
476 }
477
478 // if DISK_PARTITION_INFO fits the output size
479 if (outBufferLength >= FIELD_OFFSET(DISK_GEOMETRY_EX_INTERNAL, Detection))
480 {
481 PartMgrAcquireLayoutLock(FdoExtension);
482
483 geometryEx->Partition.SizeOfPartitionInfo = sizeof(geometryEx->Partition);
484 geometryEx->Partition.PartitionStyle = FdoExtension->DiskData.PartitionStyle;
485
486 switch (geometryEx->Partition.PartitionStyle)
487 {
488 case PARTITION_STYLE_MBR:
489 geometryEx->Partition.Mbr.Signature = FdoExtension->DiskData.Mbr.Signature;
490 // checksum?
491 break;
492
493 case PARTITION_STYLE_GPT:
494 geometryEx->Partition.Gpt.DiskId = FdoExtension->DiskData.Gpt.DiskId;
495 break;
496
497 default:
498 RtlZeroMemory(&geometryEx->Partition, sizeof(geometryEx->Partition));
499 }
500
501 PartMgrReleaseLayoutLock(FdoExtension);
502 }
503
504 // the logic is copied from disk.sys
505 Irp->IoStatus.Information = min(outBufferLength, sizeof(DISK_GEOMETRY_EX_INTERNAL));
506
507 return status;
508 }
509
510 static
511 CODE_SEG("PAGE")
512 NTSTATUS
FdoIoctlDiskGetPartitionInfo(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)513 FdoIoctlDiskGetPartitionInfo(
514 _In_ PFDO_EXTENSION FdoExtension,
515 _In_ PIRP Irp)
516 {
517 PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer;
518
519 PAGED_CODE();
520
521 if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfo)))
522 {
523 return STATUS_BUFFER_TOO_SMALL;
524 }
525
526 PartMgrAcquireLayoutLock(FdoExtension);
527
528 *partInfo = (PARTITION_INFORMATION){
529 .PartitionType = PARTITION_ENTRY_UNUSED,
530 .StartingOffset.QuadPart = 0,
531 .PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize,
532 .HiddenSectors = 0,
533 .PartitionNumber = 0,
534 .BootIndicator = FALSE,
535 .RewritePartition = FALSE,
536 .RecognizedPartition = FALSE,
537 };
538
539 PartMgrReleaseLayoutLock(FdoExtension);
540
541 Irp->IoStatus.Information = sizeof(*partInfo);
542 return STATUS_SUCCESS;
543 }
544
545 static
546 CODE_SEG("PAGE")
547 NTSTATUS
FdoIoctlDiskGetPartitionInfoEx(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)548 FdoIoctlDiskGetPartitionInfoEx(
549 _In_ PFDO_EXTENSION FdoExtension,
550 _In_ PIRP Irp)
551 {
552 PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer;
553
554 PAGED_CODE();
555
556 if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfoEx)))
557 {
558 return STATUS_BUFFER_TOO_SMALL;
559 }
560
561 PartMgrAcquireLayoutLock(FdoExtension);
562
563 // most of the fields a zeroed for Partition0
564 *partInfoEx = (PARTITION_INFORMATION_EX){
565 .PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize,
566 .PartitionStyle = FdoExtension->DiskData.PartitionStyle,
567 };
568
569 PartMgrReleaseLayoutLock(FdoExtension);
570
571 Irp->IoStatus.Information = sizeof(*partInfoEx);
572 return STATUS_SUCCESS;
573 }
574
575 static
576 CODE_SEG("PAGE")
577 NTSTATUS
FdoIoctlDiskGetDriveLayout(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)578 FdoIoctlDiskGetDriveLayout(
579 _In_ PFDO_EXTENSION FdoExtension,
580 _In_ PIRP Irp)
581 {
582 PAGED_CODE();
583
584 PartMgrAcquireLayoutLock(FdoExtension);
585
586 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
587 NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx);
588 if (!NT_SUCCESS(status))
589 {
590 PartMgrReleaseLayoutLock(FdoExtension);
591 return status;
592 }
593
594 // checking this value from layoutEx in case it has been changed
595 if (layoutEx->PartitionStyle != PARTITION_STYLE_MBR)
596 {
597 PartMgrReleaseLayoutLock(FdoExtension);
598 return STATUS_INVALID_DEVICE_REQUEST;
599 }
600
601 size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]);
602 size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION);
603
604 if (!VerifyIrpOutBufferSize(Irp, size))
605 {
606 PartMgrReleaseLayoutLock(FdoExtension);
607 return STATUS_BUFFER_TOO_SMALL;
608 }
609
610 PDRIVE_LAYOUT_INFORMATION partitionList = PartMgrConvertExtendedToLayout(layoutEx);
611
612 PartMgrReleaseLayoutLock(FdoExtension);
613
614 if (partitionList == NULL)
615 {
616 Irp->IoStatus.Information = 0;
617 return STATUS_INSUFFICIENT_RESOURCES;
618 }
619
620 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, partitionList, size);
621 ExFreePoolWithTag(partitionList, TAG_PARTMGR);
622
623 Irp->IoStatus.Information = size;
624 return STATUS_SUCCESS;
625 }
626
627 static
628 CODE_SEG("PAGE")
629 NTSTATUS
FdoIoctlDiskGetDriveLayoutEx(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)630 FdoIoctlDiskGetDriveLayoutEx(
631 _In_ PFDO_EXTENSION FdoExtension,
632 _In_ PIRP Irp)
633 {
634 PAGED_CODE();
635
636 PartMgrAcquireLayoutLock(FdoExtension);
637
638 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
639 NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx);
640 if (!NT_SUCCESS(status))
641 {
642 PartMgrReleaseLayoutLock(FdoExtension);
643 return status;
644 }
645
646 size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]);
647 size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION_EX);
648
649 if (!VerifyIrpOutBufferSize(Irp, size))
650 {
651 PartMgrReleaseLayoutLock(FdoExtension);
652 return STATUS_BUFFER_TOO_SMALL;
653 }
654
655 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, layoutEx, size);
656
657 PartMgrReleaseLayoutLock(FdoExtension);
658
659 Irp->IoStatus.Information = size;
660 return STATUS_SUCCESS;
661 }
662
663 static
664 CODE_SEG("PAGE")
665 NTSTATUS
FdoIoctlDiskSetDriveLayout(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)666 FdoIoctlDiskSetDriveLayout(
667 _In_ PFDO_EXTENSION FdoExtension,
668 _In_ PIRP Irp)
669 {
670 PDRIVE_LAYOUT_INFORMATION layoutInfo = Irp->AssociatedIrp.SystemBuffer;
671
672 PAGED_CODE();
673
674 if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutInfo)))
675 {
676 return STATUS_INFO_LENGTH_MISMATCH;
677 }
678
679 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]);
680 layoutSize += layoutInfo->PartitionCount * sizeof(PARTITION_INFORMATION);
681
682 if (!VerifyIrpInBufferSize(Irp, layoutSize))
683 {
684 return STATUS_INFO_LENGTH_MISMATCH;
685 }
686
687 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = PartMgrConvertLayoutToExtended(layoutInfo);
688
689 if (layoutEx == NULL)
690 {
691 Irp->IoStatus.Information = 0;
692 return STATUS_INSUFFICIENT_RESOURCES;
693 }
694
695 PartMgrAcquireLayoutLock(FdoExtension);
696
697 // If the current disk is super-floppy but the user changes
698 // the number of partitions to > 1, fail the call.
699 if (FdoExtension->IsSuperFloppy && (layoutEx->PartitionCount > 1))
700 {
701 PartMgrReleaseLayoutLock(FdoExtension);
702 return STATUS_INVALID_DEVICE_REQUEST;
703 }
704
705 // this in fact updates the bus relations
706 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx);
707
708 // write the partition table to the disk
709 NTSTATUS status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx);
710 if (NT_SUCCESS(status))
711 {
712 // save the layout cache
713 if (FdoExtension->LayoutCache)
714 {
715 ExFreePool(FdoExtension->LayoutCache);
716 }
717 FdoExtension->LayoutCache = layoutEx;
718 FdoExtension->LayoutValid = TRUE;
719
720 // set updated partition numbers
721 for (UINT32 i = 0; i < layoutInfo->PartitionCount; i++)
722 {
723 PPARTITION_INFORMATION part = &layoutInfo->PartitionEntry[i];
724
725 part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber;
726 }
727
728 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension);
729 }
730 else
731 {
732 FdoExtension->LayoutValid = FALSE;
733 }
734
735 PartMgrReleaseLayoutLock(FdoExtension);
736
737 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
738
739 // notify everyone that the disk layout has changed
740 TARGET_DEVICE_CUSTOM_NOTIFICATION notification;
741
742 notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
743 notification.Version = 1;
744 notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
745 notification.FileObject = NULL;
746 notification.NameBufferOffset = -1;
747
748 IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO,
749 ¬ification,
750 NULL,
751 NULL);
752
753 Irp->IoStatus.Information = layoutSize;
754 return STATUS_SUCCESS;
755 }
756
757 static
758 CODE_SEG("PAGE")
759 NTSTATUS
FdoIoctlDiskSetDriveLayoutEx(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)760 FdoIoctlDiskSetDriveLayoutEx(
761 _In_ PFDO_EXTENSION FdoExtension,
762 _In_ PIRP Irp)
763 {
764 PDRIVE_LAYOUT_INFORMATION_EX layoutEx, layoutUser = Irp->AssociatedIrp.SystemBuffer;
765 NTSTATUS status;
766
767 PAGED_CODE();
768
769 if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutUser)))
770 {
771 return STATUS_INFO_LENGTH_MISMATCH;
772 }
773
774 size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]);
775 layoutSize += layoutUser->PartitionCount * sizeof(PARTITION_INFORMATION_EX);
776
777 if (!VerifyIrpInBufferSize(Irp, layoutSize))
778 {
779 return STATUS_INFO_LENGTH_MISMATCH;
780 }
781
782 // we need to copy the structure from the IRP input buffer
783 layoutEx = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR);
784 if (!layoutEx)
785 {
786 Irp->IoStatus.Information = 0;
787 return STATUS_INSUFFICIENT_RESOURCES;
788 }
789
790 RtlCopyMemory(layoutEx, layoutUser, layoutSize);
791
792 PartMgrAcquireLayoutLock(FdoExtension);
793
794 // If the current disk is super-floppy but the user changes either
795 // the disk type or the number of partitions to > 1, fail the call.
796 if (FdoExtension->IsSuperFloppy &&
797 ((layoutEx->PartitionStyle != PARTITION_STYLE_MBR) ||
798 (layoutEx->PartitionCount > 1)))
799 {
800 PartMgrReleaseLayoutLock(FdoExtension);
801 return STATUS_INVALID_DEVICE_REQUEST;
802 }
803
804 // if partition count is 0, it's the same as IOCTL_DISK_CREATE_DISK
805 if (layoutEx->PartitionCount == 0)
806 {
807 CREATE_DISK createDisk = {0};
808 createDisk.PartitionStyle = layoutEx->PartitionStyle;
809 if (createDisk.PartitionStyle == PARTITION_STYLE_MBR)
810 {
811 createDisk.Mbr.Signature = layoutEx->Mbr.Signature;
812 }
813 else if (createDisk.PartitionStyle == PARTITION_STYLE_GPT)
814 {
815 createDisk.Gpt.DiskId = layoutEx->Gpt.DiskId;
816 }
817
818 status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk);
819 }
820 else
821 {
822 // this in fact updates the bus relations
823 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx);
824
825 // write the partition table to the disk
826 status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx);
827 if (NT_SUCCESS(status))
828 {
829 // set updated partition numbers
830 for (UINT32 i = 0; i < layoutEx->PartitionCount; i++)
831 {
832 PPARTITION_INFORMATION_EX part = &layoutEx->PartitionEntry[i];
833
834 part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber;
835 }
836 }
837 }
838
839 // update the layout cache
840 if (NT_SUCCESS(status))
841 {
842 if (FdoExtension->LayoutCache)
843 {
844 ExFreePool(FdoExtension->LayoutCache);
845 }
846 FdoExtension->LayoutCache = layoutEx;
847 FdoExtension->LayoutValid = TRUE;
848
849 FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension);
850 }
851 else
852 {
853 FdoExtension->LayoutValid = FALSE;
854 }
855
856 PartMgrReleaseLayoutLock(FdoExtension);
857
858 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
859
860 // notify everyone that the disk layout has changed
861 TARGET_DEVICE_CUSTOM_NOTIFICATION notification;
862
863 notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
864 notification.Version = 1;
865 notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
866 notification.FileObject = NULL;
867 notification.NameBufferOffset = -1;
868
869 IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO,
870 ¬ification,
871 NULL,
872 NULL);
873
874 Irp->IoStatus.Information = layoutSize;
875 return STATUS_SUCCESS;
876 }
877
878 static
879 CODE_SEG("PAGE")
880 NTSTATUS
FdoIoctlDiskUpdateProperties(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)881 FdoIoctlDiskUpdateProperties(
882 _In_ PFDO_EXTENSION FdoExtension,
883 _In_ PIRP Irp)
884 {
885 PAGED_CODE();
886
887 PartMgrAcquireLayoutLock(FdoExtension);
888 FdoExtension->LayoutValid = FALSE;
889 PartMgrReleaseLayoutLock(FdoExtension);
890
891 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
892 return STATUS_SUCCESS;
893 }
894
895 static
896 CODE_SEG("PAGE")
897 NTSTATUS
FdoIoctlDiskCreateDisk(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)898 FdoIoctlDiskCreateDisk(
899 _In_ PFDO_EXTENSION FdoExtension,
900 _In_ PIRP Irp)
901 {
902 PAGED_CODE();
903
904 PCREATE_DISK createDisk = Irp->AssociatedIrp.SystemBuffer;
905 if (!VerifyIrpInBufferSize(Irp, sizeof(*createDisk)))
906 {
907 return STATUS_INFO_LENGTH_MISMATCH;
908 }
909
910 PartMgrAcquireLayoutLock(FdoExtension);
911
912 NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, createDisk);
913
914 FdoExtension->LayoutValid = FALSE;
915 PartMgrReleaseLayoutLock(FdoExtension);
916
917 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
918 return status;
919 }
920
921 static
922 CODE_SEG("PAGE")
923 NTSTATUS
FdoIoctlDiskDeleteDriveLayout(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)924 FdoIoctlDiskDeleteDriveLayout(
925 _In_ PFDO_EXTENSION FdoExtension,
926 _In_ PIRP Irp)
927 {
928 CREATE_DISK createDisk = { .PartitionStyle = PARTITION_STYLE_RAW };
929
930 PAGED_CODE();
931
932 PartMgrAcquireLayoutLock(FdoExtension);
933
934 NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk);
935
936 FdoExtension->LayoutValid = FALSE;
937 PartMgrReleaseLayoutLock(FdoExtension);
938
939 IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
940 return status;
941 }
942
943 static
944 CODE_SEG("PAGE")
945 NTSTATUS
FdoHandleStartDevice(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)946 FdoHandleStartDevice(
947 _In_ PFDO_EXTENSION FdoExtension,
948 _In_ PIRP Irp)
949 {
950 // Obtain the disk device number.
951 // It is not expected to change, thus not in PartMgrRefreshDiskData().
952 STORAGE_DEVICE_NUMBER deviceNumber;
953 NTSTATUS status = IssueSyncIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
954 FdoExtension->LowerDevice,
955 NULL,
956 0,
957 &deviceNumber,
958 sizeof(deviceNumber),
959 FALSE);
960 if (!NT_SUCCESS(status))
961 {
962 return status;
963 }
964
965 FdoExtension->DiskData.DeviceNumber = deviceNumber.DeviceNumber;
966
967 // Register the disk interface.
968 // partmgr.sys from Windows 8.1 also registers a mysterious GUID_DEVINTERFACE_HIDDEN_DISK here.
969 UNICODE_STRING interfaceName;
970 status = IoRegisterDeviceInterface(FdoExtension->PhysicalDiskDO,
971 &GUID_DEVINTERFACE_DISK,
972 NULL,
973 &interfaceName);
974 if(!NT_SUCCESS(status))
975 {
976 ERR("Failed to register GUID_DEVINTERFACE_DISK, status %x\n", status);
977 return status;
978 }
979
980 INFO("Disk interface %wZ\n", &interfaceName);
981 FdoExtension->DiskInterfaceName = interfaceName;
982 status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
983 if (!NT_SUCCESS(status))
984 {
985 RtlFreeUnicodeString(&interfaceName);
986 RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL);
987 }
988
989 return status;
990 }
991
992 /**
993 * @brief
994 * Refreshes all the cached disk FDO data.
995 * The geometry of the disk and its partition layout cache is updated.
996 *
997 * @note Requires partitioning lock held.
998 **/
999 static
1000 CODE_SEG("PAGE")
1001 NTSTATUS
PartMgrRefreshDiskData(_In_ PFDO_EXTENSION FdoExtension)1002 PartMgrRefreshDiskData(
1003 _In_ PFDO_EXTENSION FdoExtension)
1004 {
1005 NTSTATUS status;
1006
1007 PAGED_CODE();
1008
1009 // get the DiskSize and BytesPerSector
1010 DISK_GEOMETRY_EX geometryEx;
1011 status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
1012 FdoExtension->LowerDevice,
1013 NULL,
1014 0,
1015 &geometryEx,
1016 sizeof(geometryEx),
1017 FALSE);
1018 if (!NT_SUCCESS(status))
1019 return status;
1020
1021 FdoExtension->DiskData.DiskSize = geometryEx.DiskSize.QuadPart;
1022 FdoExtension->DiskData.BytesPerSector = geometryEx.Geometry.BytesPerSector;
1023
1024 // get the partition style-related info
1025 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL;
1026 status = PartMgrGetDriveLayout(FdoExtension, &layoutEx);
1027 if (!NT_SUCCESS(status))
1028 return status;
1029
1030 return STATUS_SUCCESS;
1031 }
1032
1033 static
1034 CODE_SEG("PAGE")
1035 NTSTATUS
FdoHandleDeviceRelations(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)1036 FdoHandleDeviceRelations(
1037 _In_ PFDO_EXTENSION FdoExtension,
1038 _In_ PIRP Irp)
1039 {
1040 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
1041 DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type;
1042
1043 PAGED_CODE();
1044
1045 if (type == BusRelations)
1046 {
1047 PartMgrAcquireLayoutLock(FdoExtension);
1048
1049 NTSTATUS status = PartMgrRefreshDiskData(FdoExtension);
1050 if (!NT_SUCCESS(status))
1051 {
1052 PartMgrReleaseLayoutLock(FdoExtension);
1053 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1054 Irp->IoStatus.Information = 0;
1055 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1056 return Irp->IoStatus.Status;
1057 }
1058
1059 INFO("Partition style %u\n", FdoExtension->DiskData.PartitionStyle);
1060
1061 // PartMgrRefreshDiskData() calls PartMgrGetDriveLayout() inside
1062 // so we're sure here that it returns only the cached layout.
1063 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
1064 PartMgrGetDriveLayout(FdoExtension, &layoutEx);
1065
1066 PartMgrUpdatePartitionDevices(FdoExtension, layoutEx);
1067
1068 // now fill the DeviceRelations structure
1069 TRACE("Reporting %u partitions\n", FdoExtension->EnumeratedPartitionsTotal);
1070
1071 PDEVICE_RELATIONS deviceRelations =
1072 ExAllocatePoolWithTag(PagedPool,
1073 sizeof(DEVICE_RELATIONS)
1074 + sizeof(PDEVICE_OBJECT)
1075 * (FdoExtension->EnumeratedPartitionsTotal - 1),
1076 TAG_PARTMGR);
1077
1078 if (!deviceRelations)
1079 {
1080 PartMgrReleaseLayoutLock(FdoExtension);
1081 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1082 Irp->IoStatus.Information = 0;
1083 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1084 return Irp->IoStatus.Status;
1085 }
1086
1087 deviceRelations->Count = 0;
1088
1089 PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
1090 while (curEntry != NULL)
1091 {
1092 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
1093 PARTITION_EXTENSION,
1094 ListEntry);
1095
1096 // mark the PDO to know that we don't need to manually delete it
1097 partExt->IsEnumerated = TRUE;
1098 deviceRelations->Objects[deviceRelations->Count++] = partExt->DeviceObject;
1099 ObReferenceObject(partExt->DeviceObject);
1100
1101 curEntry = partExt->ListEntry.Next;
1102 }
1103
1104 ASSERT(deviceRelations->Count == FdoExtension->EnumeratedPartitionsTotal);
1105
1106 PartMgrReleaseLayoutLock(FdoExtension);
1107
1108 Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
1109 Irp->IoStatus.Status = STATUS_SUCCESS;
1110 }
1111
1112 IoSkipCurrentIrpStackLocation(Irp);
1113 return IoCallDriver(FdoExtension->LowerDevice, Irp);
1114 }
1115
1116 static
1117 CODE_SEG("PAGE")
1118 NTSTATUS
FdoHandleRemoveDevice(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)1119 FdoHandleRemoveDevice(
1120 _In_ PFDO_EXTENSION FdoExtension,
1121 _In_ PIRP Irp)
1122 {
1123 PAGED_CODE();
1124
1125 if (FdoExtension->DiskInterfaceName.Buffer)
1126 {
1127 IoSetDeviceInterfaceState(&FdoExtension->DiskInterfaceName, FALSE);
1128 RtlFreeUnicodeString(&FdoExtension->DiskInterfaceName);
1129 RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL);
1130 }
1131
1132 // Send the IRP down the stack
1133 IoSkipCurrentIrpStackLocation(Irp);
1134 Irp->IoStatus.Status = STATUS_SUCCESS;
1135 NTSTATUS status = IoCallDriver(FdoExtension->LowerDevice, Irp);
1136
1137 IoDetachDevice(FdoExtension->LowerDevice);
1138 IoDeleteDevice(FdoExtension->DeviceObject);
1139 return status;
1140 }
1141
1142 static
1143 CODE_SEG("PAGE")
1144 NTSTATUS
FdoHandleSurpriseRemoval(_In_ PFDO_EXTENSION FdoExtension,_In_ PIRP Irp)1145 FdoHandleSurpriseRemoval(
1146 _In_ PFDO_EXTENSION FdoExtension,
1147 _In_ PIRP Irp)
1148 {
1149 PAGED_CODE();
1150
1151 // all enumerated child devices should receive IRP_MN_REMOVE_DEVICE
1152 // removing only non-enumerated ones here
1153 for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
1154 curEntry != NULL;
1155 curEntry = curEntry->Next)
1156 {
1157 PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
1158 PARTITION_EXTENSION,
1159 ListEntry);
1160
1161 if (partExt->IsEnumerated)
1162 {
1163 PartitionHandleRemove(partExt, TRUE);
1164 }
1165 }
1166
1167 // Send the IRP down the stack
1168 IoSkipCurrentIrpStackLocation(Irp);
1169 Irp->IoStatus.Status = STATUS_SUCCESS;
1170 return IoCallDriver(FdoExtension->LowerDevice, Irp);
1171 }
1172
1173 static
1174 CODE_SEG("PAGE")
1175 NTSTATUS
1176 NTAPI
PartMgrAddDevice(_In_ PDRIVER_OBJECT DriverObject,_In_ PDEVICE_OBJECT PhysicalDeviceObject)1177 PartMgrAddDevice(
1178 _In_ PDRIVER_OBJECT DriverObject,
1179 _In_ PDEVICE_OBJECT PhysicalDeviceObject)
1180 {
1181 PDEVICE_OBJECT deviceObject;
1182
1183 PAGED_CODE();
1184
1185 /*
1186 * Create the disk FDO. Use FILE_DEVICE_MASS_STORAGE type (or any other
1187 * one that is NOT FILE_DEVICE_[DISK|VIRTUAL_DISK|CD_ROM|TAPE]), so that
1188 * IoCreateDevice() doesn't automatically create a VPB for this device,
1189 * even if we will later want this device to inherit the type of the
1190 * underlying PDO which can have any of the types mentioned above.
1191 */
1192 NTSTATUS status = IoCreateDevice(DriverObject,
1193 sizeof(FDO_EXTENSION),
1194 NULL,
1195 FILE_DEVICE_MASS_STORAGE,
1196 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
1197 FALSE,
1198 &deviceObject);
1199 if (!NT_SUCCESS(status))
1200 {
1201 ERR("Failed to create FDO 0x%x\n", status);
1202 return status;
1203 }
1204
1205 PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension;
1206 RtlZeroMemory(deviceExtension, sizeof(*deviceExtension));
1207
1208 deviceExtension->IsFDO = TRUE;
1209 deviceExtension->DeviceObject = deviceObject;
1210 deviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
1211 if (!deviceExtension->LowerDevice)
1212 {
1213 // The attachment failed
1214 IoDeleteDevice(deviceObject);
1215 return STATUS_DEVICE_REMOVED;
1216 }
1217 deviceExtension->PhysicalDiskDO = PhysicalDeviceObject;
1218 KeInitializeEvent(&deviceExtension->SyncEvent, SynchronizationEvent, TRUE);
1219
1220 // Update now the device type with the actual underlying device type
1221 deviceObject->DeviceType = deviceExtension->LowerDevice->DeviceType;
1222
1223 deviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
1224
1225 // The device is initialized
1226 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1227 return STATUS_SUCCESS;
1228 }
1229
1230 static
1231 NTSTATUS
1232 NTAPI
PartMgrDeviceControl(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)1233 PartMgrDeviceControl(
1234 _In_ PDEVICE_OBJECT DeviceObject,
1235 _In_ PIRP Irp)
1236 {
1237 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
1238 PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1239 NTSTATUS status;
1240
1241 // Note: IRP_MJ_DEVICE_CONTROL handler in the storage stack must be able to pass IOCTLs
1242 // at an IRQL higher than PASSIVE_LEVEL
1243
1244 INFO("IRP_MJ_DEVICE_CONTROL %p Irp %p IOCTL %x isFdo: %u\n",
1245 DeviceObject, Irp, ioStack->Parameters.DeviceIoControl.IoControlCode, fdoExtension->IsFDO);
1246
1247 if (!fdoExtension->IsFDO)
1248 {
1249 return PartitionHandleDeviceControl(DeviceObject, Irp);
1250 }
1251
1252 switch (ioStack->Parameters.DeviceIoControl.IoControlCode)
1253 {
1254 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
1255 status = FdoIoctlDiskGetDriveGeometryEx(fdoExtension, Irp);
1256 break;
1257
1258 case IOCTL_DISK_GET_PARTITION_INFO:
1259 status = FdoIoctlDiskGetPartitionInfo(fdoExtension, Irp);
1260 break;
1261
1262 case IOCTL_DISK_GET_PARTITION_INFO_EX:
1263 status = FdoIoctlDiskGetPartitionInfoEx(fdoExtension, Irp);
1264 break;
1265
1266 case IOCTL_DISK_GET_DRIVE_LAYOUT:
1267 status = FdoIoctlDiskGetDriveLayout(fdoExtension, Irp);
1268 break;
1269
1270 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
1271 status = FdoIoctlDiskGetDriveLayoutEx(fdoExtension, Irp);
1272 break;
1273
1274 case IOCTL_DISK_SET_DRIVE_LAYOUT:
1275 status = FdoIoctlDiskSetDriveLayout(fdoExtension, Irp);
1276 break;
1277
1278 case IOCTL_DISK_SET_DRIVE_LAYOUT_EX:
1279 status = FdoIoctlDiskSetDriveLayoutEx(fdoExtension, Irp);
1280 break;
1281
1282 case IOCTL_DISK_UPDATE_PROPERTIES:
1283 status = FdoIoctlDiskUpdateProperties(fdoExtension, Irp);
1284 break;
1285
1286 case IOCTL_DISK_CREATE_DISK:
1287 status = FdoIoctlDiskCreateDisk(fdoExtension, Irp);
1288 break;
1289
1290 case IOCTL_DISK_DELETE_DRIVE_LAYOUT:
1291 status = FdoIoctlDiskDeleteDriveLayout(fdoExtension, Irp);
1292 break;
1293 // case IOCTL_DISK_GROW_PARTITION: // todo
1294 default:
1295 return ForwardIrpAndForget(DeviceObject, Irp);
1296 }
1297
1298 Irp->IoStatus.Status = status;
1299 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1300 return status;
1301 }
1302
1303 static
1304 CODE_SEG("PAGE")
1305 NTSTATUS
1306 NTAPI
PartMgrPnp(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)1307 PartMgrPnp(
1308 _In_ PDEVICE_OBJECT DeviceObject,
1309 _In_ PIRP Irp)
1310 {
1311 PAGED_CODE();
1312
1313 PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1314 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
1315
1316 INFO("IRP_MJ_PNP %p Irp %p %s isFDO: %u\n",
1317 DeviceObject, Irp, GetIRPMinorFunctionString(ioStack->MinorFunction), fdoExtension->IsFDO);
1318
1319 if (!fdoExtension->IsFDO)
1320 {
1321 return PartitionHandlePnp(DeviceObject, Irp);
1322 }
1323
1324 switch (ioStack->MinorFunction) {
1325
1326 case IRP_MN_START_DEVICE:
1327 {
1328 NTSTATUS status;
1329
1330 // if this is sent to the FDO so we should forward it down the
1331 // attachment chain before we can start the FDO
1332
1333 if (!IoForwardIrpSynchronously(fdoExtension->LowerDevice, Irp))
1334 {
1335 status = STATUS_UNSUCCESSFUL;
1336 }
1337 else
1338 {
1339 status = FdoHandleStartDevice(fdoExtension, Irp);
1340 }
1341
1342 Irp->IoStatus.Status = status;
1343 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1344 return status;
1345 }
1346 case IRP_MN_QUERY_DEVICE_RELATIONS:
1347 {
1348 return FdoHandleDeviceRelations(fdoExtension, Irp);
1349 }
1350 case IRP_MN_SURPRISE_REMOVAL:
1351 {
1352 return FdoHandleSurpriseRemoval(fdoExtension, Irp);
1353 }
1354 case IRP_MN_REMOVE_DEVICE:
1355 {
1356 return FdoHandleRemoveDevice(fdoExtension, Irp);
1357 }
1358 case IRP_MN_QUERY_STOP_DEVICE:
1359 case IRP_MN_QUERY_REMOVE_DEVICE:
1360 case IRP_MN_CANCEL_STOP_DEVICE:
1361 case IRP_MN_CANCEL_REMOVE_DEVICE:
1362 case IRP_MN_STOP_DEVICE:
1363 {
1364 Irp->IoStatus.Status = STATUS_SUCCESS;
1365 // fallthrough
1366 }
1367 default:
1368 {
1369 IoSkipCurrentIrpStackLocation(Irp);
1370 return IoCallDriver(fdoExtension->LowerDevice, Irp);
1371 }
1372 }
1373 }
1374
1375 static
1376 NTSTATUS
1377 NTAPI
PartMgrReadWrite(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)1378 PartMgrReadWrite(
1379 _In_ PDEVICE_OBJECT DeviceObject,
1380 _In_ PIRP Irp)
1381 {
1382 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
1383 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
1384
1385 if (!partExt->IsFDO)
1386 {
1387 if (!partExt->IsEnumerated)
1388 {
1389 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
1390 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1391 return STATUS_DEVICE_DOES_NOT_EXIST;
1392 }
1393 else
1394 {
1395 ioStack->Parameters.Read.ByteOffset.QuadPart += partExt->StartingOffset;
1396 }
1397 }
1398
1399 IoSkipCurrentIrpStackLocation(Irp);
1400 return IoCallDriver(partExt->LowerDevice, Irp);
1401 }
1402
1403 DRIVER_DISPATCH PartMgrPower;
1404 NTSTATUS
1405 NTAPI
PartMgrPower(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)1406 PartMgrPower(
1407 _In_ PDEVICE_OBJECT DeviceObject,
1408 _In_ PIRP Irp)
1409 {
1410 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
1411 PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
1412
1413 PoStartNextPowerIrp(Irp);
1414
1415 if (!partExt->IsFDO)
1416 {
1417 NTSTATUS status;
1418
1419 if (!partExt->IsEnumerated)
1420 {
1421 status = STATUS_DEVICE_DOES_NOT_EXIST;
1422 }
1423 else if (ioStack->MinorFunction == IRP_MN_SET_POWER ||
1424 ioStack->MinorFunction == IRP_MN_QUERY_POWER)
1425 {
1426 status = STATUS_SUCCESS;
1427 }
1428 else
1429 {
1430 status = Irp->IoStatus.Status;
1431 }
1432
1433 Irp->IoStatus.Status = status;
1434 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1435 return status;
1436 }
1437 else
1438 {
1439 IoSkipCurrentIrpStackLocation(Irp);
1440 return PoCallDriver(partExt->LowerDevice, Irp);
1441 }
1442 }
1443
1444 DRIVER_DISPATCH PartMgrShutdownFlush;
1445 NTSTATUS
1446 NTAPI
PartMgrShutdownFlush(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)1447 PartMgrShutdownFlush(
1448 _In_ PDEVICE_OBJECT DeviceObject,
1449 _In_ PIRP Irp)
1450 {
1451 PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
1452 PDEVICE_OBJECT lowerDevice;
1453
1454 // forward to the partition0 device in both cases
1455 if (!partExt->IsFDO)
1456 {
1457 if (!partExt->IsEnumerated)
1458 {
1459 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
1460 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1461 return STATUS_DEVICE_DOES_NOT_EXIST;
1462 }
1463 else
1464 {
1465 PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension;
1466 lowerDevice = fdoExtension->LowerDevice;
1467 }
1468 }
1469 else
1470 {
1471 lowerDevice = partExt->LowerDevice;
1472 }
1473
1474 IoSkipCurrentIrpStackLocation(Irp);
1475 return IoCallDriver(lowerDevice, Irp);
1476 }
1477
1478 CODE_SEG("PAGE")
1479 VOID
1480 NTAPI
PartMgrUnload(_In_ PDRIVER_OBJECT DriverObject)1481 PartMgrUnload(
1482 _In_ PDRIVER_OBJECT DriverObject)
1483 {
1484
1485 }
1486
1487 CODE_SEG("INIT")
1488 NTSTATUS
1489 NTAPI
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath)1490 DriverEntry(
1491 _In_ PDRIVER_OBJECT DriverObject,
1492 _In_ PUNICODE_STRING RegistryPath)
1493 {
1494 DriverObject->DriverUnload = PartMgrUnload;
1495 DriverObject->DriverExtension->AddDevice = PartMgrAddDevice;
1496 DriverObject->MajorFunction[IRP_MJ_CREATE] = ForwardIrpAndForget;
1497 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ForwardIrpAndForget;
1498 DriverObject->MajorFunction[IRP_MJ_READ] = PartMgrReadWrite;
1499 DriverObject->MajorFunction[IRP_MJ_WRITE] = PartMgrReadWrite;
1500 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PartMgrDeviceControl;
1501 DriverObject->MajorFunction[IRP_MJ_PNP] = PartMgrPnp;
1502 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = PartMgrShutdownFlush;
1503 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = PartMgrShutdownFlush;
1504 DriverObject->MajorFunction[IRP_MJ_POWER] = PartMgrPower;
1505
1506 return STATUS_SUCCESS;
1507 }
1508