1 /*
2  * PROJECT:     ReactOS Partition Information Tool
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Displays disk and partition information for MBR and GPT disks.
5  * COPYRIGHT:   Copyright 2001-2002 Eric Kohl
6  *              Copyright 2020-2021 Hermes Belusca-Maito
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 #define WIN32_NO_STATUS
15 #include <windows.h>
16 #include <ntndk.h>
17 
18 /* The maximum information a DISK_GEOMETRY_EX dynamic structure can contain */
19 typedef struct _DISK_GEOMETRY_EX_INTERNAL
20 {
21     DISK_GEOMETRY Geometry;
22     LARGE_INTEGER DiskSize;
23     DISK_PARTITION_INFO Partition;
24     DISK_DETECTION_INFO Detection;
25 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
26 
27 #define DRIVE_LAYOUT_INFO_ENTRY_SIZE \
28     RTL_FIELD_SIZE(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0])
29 
30 #define DRIVE_LAYOUT_INFO_SIZE(n) \
31     (FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) + \
32         ((n) * DRIVE_LAYOUT_INFO_ENTRY_SIZE))
33 
34 #define DRIVE_LAYOUT_INFOEX_ENTRY_SIZE \
35     RTL_FIELD_SIZE(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0])
36 
37 #define DRIVE_LAYOUT_INFOEX_SIZE(n) \
38     (FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) + \
39         ((n) * DRIVE_LAYOUT_INFOEX_ENTRY_SIZE))
40 
41 
42 /* Rounding up for number; not the same as ROUND_UP() with power-of-two sizes */
43 #define ROUND_UP_NUM(num, up)   ((((num) + (up) - 1) / (up)) * (up))
44 
45 
46 // #define DUMP_DATA
47 
48 
49 /* FORMATTING HELPERS *******************************************************/
50 
51 static PCSTR PartitionStyleNames[] = {"MBR", "GPT", "RAW", "Unknown"};
52 #define PARTITION_STYLE_NAME(PartStyle) \
53     ( ((PartStyle) <= PARTITION_STYLE_RAW)   \
54           ? PartitionStyleNames[(PartStyle)] \
55           : PartitionStyleNames[_countof(PartitionStyleNames)-1] )
56 
57 static PCSTR DetectTypeNames[] = { "None", "DetectInt13", "DetectExInt13", "Unknown" };
58 #define DETECT_TYPE_NAME(DetectType) \
59     ( ((DetectType) <= DetectExInt13)   \
60           ? DetectTypeNames[(DetectType)] \
61           : DetectTypeNames[_countof(DetectTypeNames)-1] )
62 
63 #define GUID_FORMAT_STR "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
64 #define GUID_ELEMENTS(Guid) \
65     (Guid)->Data1, (Guid)->Data2, (Guid)->Data3, \
66     (Guid)->Data4[0], (Guid)->Data4[1], (Guid)->Data4[2], (Guid)->Data4[3], \
67     (Guid)->Data4[4], (Guid)->Data4[5], (Guid)->Data4[6], (Guid)->Data4[7]
68 
69 
70 /* FUNCTIONS ****************************************************************/
71 
72 #ifdef DUMP_DATA
HexDump(IN PVOID buffer,IN ULONG size)73 void HexDump(
74     IN PVOID buffer,
75     IN ULONG size)
76 {
77     ULONG_PTR offset = 0;
78     PUCHAR ptr;
79 
80     while (offset < (size & ~15))
81     {
82         ptr = (PUCHAR)((ULONG_PTR)buffer + offset);
83         printf("%08lx  %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx-%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx\n",
84                offset,
85                ptr[0], ptr[1], ptr[2] , ptr[3] , ptr[4] , ptr[5] , ptr[6] , ptr[7],
86                ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
87       offset += 16;
88     }
89 
90     if (offset < size)
91     {
92         ptr = (PUCHAR)((ULONG_PTR)buffer + offset);
93         printf("%08lx ", offset);
94         while (offset < size)
95         {
96             printf(" %02hx", *ptr);
97             offset++;
98             ptr++;
99         }
100         printf("\n");
101     }
102 
103     printf("\n");
104 }
105 #endif
106 
Usage(void)107 void Usage(void)
108 {
109     puts("Usage: partinfo <drive number>");
110 }
111 
main(int argc,char * argv[])112 int main(int argc, char *argv[])
113 {
114     NTSTATUS Status;
115     ULONG ulDrive;
116     HANDLE hDisk;
117     ULONG i;
118     SYSTEM_DEVICE_INFORMATION DeviceInfo;
119     IO_STATUS_BLOCK Iosb;
120     ULONG BufferSize;
121     union
122     {
123         DISK_GEOMETRY Info;
124         DISK_GEOMETRY_EX_INTERNAL InfoEx;
125     } DiskGeometry;
126     PDISK_GEOMETRY pDiskGeometry;
127     union
128     {
129         PARTITION_INFORMATION Info;
130         PARTITION_INFORMATION_EX InfoEx;
131     } PartInfo;
132     PPARTITION_INFORMATION pPartInfo;
133     PPARTITION_INFORMATION_EX pPartInfoEx;
134     union
135     {
136         PDRIVE_LAYOUT_INFORMATION Info;
137         PDRIVE_LAYOUT_INFORMATION_EX InfoEx;
138     } LayoutBuffer;
139     PVOID ptr;
140     WCHAR DriveName[40];
141 
142     if (argc != 2)
143     {
144         Usage();
145         return 0;
146     }
147 
148     ulDrive = strtoul(argv[1], NULL, 10);
149     if (errno != 0)
150     {
151         printf("Error: Malformed drive number\n");
152         return 0;
153     }
154 
155     /*
156      * Retrieve the number of disks on the system.
157      */
158     Status = NtQuerySystemInformation(SystemDeviceInformation,
159                                       &DeviceInfo,
160                                       sizeof(DeviceInfo),
161                                       &i);
162     if (!NT_SUCCESS(Status))
163     {
164         printf("NtQuerySystemInformation() failed (Status 0x%lx)\n", Status);
165         return 0;
166     }
167     if (DeviceInfo.NumberOfDisks == 0)
168     {
169         printf("No disk drive installed!\n");
170         return 0;
171     }
172 
173     if (ulDrive >= DeviceInfo.NumberOfDisks)
174     {
175         printf("Invalid disk drive number! Valid drive numbers: [0-%lu]\n",
176                DeviceInfo.NumberOfDisks-1);
177         return 0;
178     }
179 
180     /* Build the full drive name */
181     swprintf(DriveName, L"\\\\.\\PHYSICALDRIVE%lu", ulDrive);
182 
183     /* Open the drive */
184     hDisk = CreateFileW(DriveName,
185                         GENERIC_READ,
186                         FILE_SHARE_READ | FILE_SHARE_WRITE,
187                         NULL,
188                         OPEN_EXISTING,
189                         0,
190                         NULL);
191     if (hDisk == INVALID_HANDLE_VALUE)
192     {
193         printf("Could not open drive!");
194         return 0;
195     }
196 
197     printf("Drive number: %lu\n\n", ulDrive);
198 
199 
200     /*
201      * Get the drive geometry.
202      */
203     Status = NtDeviceIoControlFile(hDisk,
204                                    NULL,
205                                    NULL,
206                                    NULL,
207                                    &Iosb,
208                                    IOCTL_DISK_GET_DRIVE_GEOMETRY,
209                                    NULL,
210                                    0,
211                                    &DiskGeometry.Info,
212                                    sizeof(DiskGeometry.Info));
213     if (!NT_SUCCESS(Status))
214     {
215         printf("NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_GEOMETRY) failed! (Status 0x%lx)\n", Status);
216     }
217     else
218     {
219         pDiskGeometry = &DiskGeometry.Info;
220 
221 #ifdef DUMP_DATA
222         HexDump(&DiskGeometry.Info, (ULONG)Iosb.Information);
223 #endif
224         printf("IOCTL_DISK_GET_DRIVE_GEOMETRY\n"
225                "Cylinders: %I64u\nMediaType: 0x%x\nTracksPerCylinder: %lu\n"
226                "SectorsPerTrack: %lu\nBytesPerSector: %lu\n",
227                pDiskGeometry->Cylinders.QuadPart,
228                pDiskGeometry->MediaType,
229                pDiskGeometry->TracksPerCylinder,
230                pDiskGeometry->SectorsPerTrack,
231                pDiskGeometry->BytesPerSector);
232     }
233 
234 
235     /*
236      * Get the extended drive geometry.
237      */
238     printf("\n");
239     Status = NtDeviceIoControlFile(hDisk,
240                                    NULL,
241                                    NULL,
242                                    NULL,
243                                    &Iosb,
244                                    IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
245                                    NULL,
246                                    0,
247                                    &DiskGeometry.InfoEx,
248                                    sizeof(DiskGeometry.InfoEx));
249     if (!NT_SUCCESS(Status))
250     {
251         printf("NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX) failed! (Status 0x%lx)\n", Status);
252     }
253     else
254     {
255         // PDISK_DETECTION_INFO DiskDetectInfo = &DiskGeometry.InfoEx.Detection; // DiskGeometryGetDetect(&DiskGeometry.InfoEx);
256         // PDISK_PARTITION_INFO DiskPartInfo = &DiskGeometry.InfoEx.Partition; // DiskGeometryGetPartition(&DiskGeometry.InfoEx);
257         pDiskGeometry = &DiskGeometry.InfoEx.Geometry;
258 
259 #ifdef DUMP_DATA
260         HexDump(&DiskGeometry.InfoEx, (ULONG)Iosb.Information);
261 #endif
262         printf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX\n"
263                "Cylinders: %I64u\nMediaType: 0x%x\nTracksPerCylinder: %lu\n"
264                "SectorsPerTrack: %lu\nBytesPerSector: %lu\n"
265                "DiskSize: %I64u\n",
266                pDiskGeometry->Cylinders.QuadPart,
267                pDiskGeometry->MediaType,
268                pDiskGeometry->TracksPerCylinder,
269                pDiskGeometry->SectorsPerTrack,
270                pDiskGeometry->BytesPerSector,
271                DiskGeometry.InfoEx.DiskSize.QuadPart);
272 
273         printf("SizeOfDetectInfo: %lu  DetectionType: %u (%s)\n",
274                DiskGeometry.InfoEx.Detection.SizeOfDetectInfo,
275                DiskGeometry.InfoEx.Detection.DetectionType,
276                DETECT_TYPE_NAME(DiskGeometry.InfoEx.Detection.DetectionType));
277         switch (DiskGeometry.InfoEx.Detection.DetectionType)
278         {
279         case DetectInt13:
280         {
281             PDISK_INT13_INFO pInt13 = &DiskGeometry.InfoEx.Detection.Int13;
282             printf("  DriveSelect: %u  MaxCylinders: %lu  SectorsPerTrack: %u  MaxHeads: %u  NumberDrives: %u\n",
283                    pInt13->DriveSelect, pInt13->MaxCylinders,
284                    pInt13->SectorsPerTrack, pInt13->MaxHeads,
285                    pInt13->NumberDrives);
286             break;
287         }
288 
289         case DetectExInt13:
290         {
291             PDISK_EX_INT13_INFO pExInt13 = &DiskGeometry.InfoEx.Detection.ExInt13;
292             printf("  ExBufferSize: %u  ExFlags: %u\n"
293                    "  ExCylinders: %lu  ExHeads: %lu  ExSectorsPerTrack: %lu\n"
294                    "  ExSectorsPerDrive: %I64u  ExSectorSize: %u  ExReserved: %u\n",
295                    pExInt13->ExBufferSize, pExInt13->ExFlags,
296                    pExInt13->ExCylinders,  pExInt13->ExHeads,
297                    pExInt13->ExSectorsPerTrack, pExInt13->ExSectorsPerDrive,
298                    pExInt13->ExSectorSize, pExInt13->ExReserved);
299             break;
300         }
301 
302         case DetectNone:
303         default:
304             break;
305         }
306 
307         printf("SizeOfPartitionInfo: %lu  PartitionStyle: %u [%s]\n",
308                DiskGeometry.InfoEx.Partition.SizeOfPartitionInfo,
309                DiskGeometry.InfoEx.Partition.PartitionStyle,
310                PARTITION_STYLE_NAME(DiskGeometry.InfoEx.Partition.PartitionStyle));
311 
312         if (DiskGeometry.InfoEx.Partition.PartitionStyle == PARTITION_STYLE_MBR)
313         {
314             printf("  Signature: 0x%08lx  Checksum 0x%08lx\n",
315                    DiskGeometry.InfoEx.Partition.Mbr.Signature,
316                    DiskGeometry.InfoEx.Partition.Mbr.CheckSum);
317         }
318         else if (DiskGeometry.InfoEx.Partition.PartitionStyle == PARTITION_STYLE_GPT)
319         {
320             printf("  DiskId: {" GUID_FORMAT_STR "}\n",
321                    GUID_ELEMENTS(&DiskGeometry.InfoEx.Partition.Gpt.DiskId));
322         }
323         else
324         {
325             /* Unknown */
326             printf("\n");
327         }
328     }
329 
330 
331     /*
332      * Display partition 0 (i.e. the whole disk) information.
333      */
334     printf("\n");
335     Status = NtDeviceIoControlFile(hDisk,
336                                    NULL,
337                                    NULL,
338                                    NULL,
339                                    &Iosb,
340                                    IOCTL_DISK_GET_PARTITION_INFO,
341                                    NULL,
342                                    0,
343                                    &PartInfo.Info,
344                                    sizeof(PartInfo.Info));
345     if (!NT_SUCCESS(Status))
346     {
347         printf("NtDeviceIoControlFile(IOCTL_DISK_GET_PARTITION_INFO) failed! (Status 0x%lx)\n", Status);
348     }
349     else
350     {
351         pPartInfo = &PartInfo.Info;
352 
353 #ifdef DUMP_DATA
354         HexDump(&PartInfo.Info, (ULONG)Iosb.Information);
355 #endif
356         printf("IOCTL_DISK_GET_PARTITION_INFO\n"
357                "nr: %ld boot: %1x type: 0x%x (%s) start: 0x%016I64x count: 0x%016I64x hidden: 0x%lx\n",
358                pPartInfo->PartitionNumber,
359                pPartInfo->BootIndicator,
360                pPartInfo->PartitionType,
361                pPartInfo->RecognizedPartition ? "Recognized" : "Not recognized",
362                pPartInfo->StartingOffset.QuadPart,
363                pPartInfo->PartitionLength.QuadPart,
364                pPartInfo->HiddenSectors);
365     }
366 
367     printf("\n");
368     Status = NtDeviceIoControlFile(hDisk,
369                                    NULL,
370                                    NULL,
371                                    NULL,
372                                    &Iosb,
373                                    IOCTL_DISK_GET_PARTITION_INFO_EX,
374                                    NULL,
375                                    0,
376                                    &PartInfo.InfoEx,
377                                    sizeof(PartInfo.InfoEx));
378     if (!NT_SUCCESS(Status))
379     {
380         printf("NtDeviceIoControlFile(IOCTL_DISK_GET_PARTITION_INFO_EX) failed! (Status 0x%lx)\n", Status);
381     }
382     else
383     {
384         pPartInfoEx = &PartInfo.InfoEx;
385 
386 #ifdef DUMP_DATA
387         HexDump(&PartInfo.InfoEx, (ULONG)Iosb.Information);
388 #endif
389         printf("IOCTL_DISK_GET_PARTITION_INFO_EX\n");
390 
391         if (pPartInfoEx->PartitionStyle == PARTITION_STYLE_MBR)
392         {
393             printf("nr: %ld [%s] boot: %1x type: 0x%x (%s) start: 0x%016I64x count: 0x%016I64x hidden: 0x%lx\n",
394                    pPartInfoEx->PartitionNumber,
395                    PARTITION_STYLE_NAME(pPartInfoEx->PartitionStyle),
396                    pPartInfoEx->Mbr.BootIndicator,
397                    pPartInfoEx->Mbr.PartitionType,
398                    pPartInfoEx->Mbr.RecognizedPartition ? "Recognized" : "Not recognized",
399                    pPartInfoEx->StartingOffset.QuadPart,
400                    pPartInfoEx->PartitionLength.QuadPart,
401                    pPartInfoEx->Mbr.HiddenSectors);
402 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
403             printf("    PartitionId: {" GUID_FORMAT_STR "}\n",
404                    GUID_ELEMENTS(&pPartInfoEx->Mbr.PartitionId));
405 #endif
406         }
407         else if (pPartInfoEx->PartitionStyle == PARTITION_STYLE_GPT)
408         {
409             printf("nr: %ld [%s]\n"
410                    "    type : {" GUID_FORMAT_STR "}\n"
411                    "    id   : {" GUID_FORMAT_STR "}\n"
412                    "    attrs: 0x%016I64x\n"
413                    "    name : '%.*S'\n"
414                    "    start: 0x%016I64x count: 0x%016I64x\n",
415                    pPartInfoEx->PartitionNumber,
416                    PARTITION_STYLE_NAME(pPartInfoEx->PartitionStyle),
417                    GUID_ELEMENTS(&pPartInfoEx->Gpt.PartitionType),
418                    GUID_ELEMENTS(&pPartInfoEx->Gpt.PartitionId),
419                    pPartInfoEx->Gpt.Attributes,
420                    (int)_countof(pPartInfoEx->Gpt.Name),
421                    pPartInfoEx->Gpt.Name,
422                    pPartInfoEx->StartingOffset.QuadPart,
423                    pPartInfoEx->PartitionLength.QuadPart);
424         }
425     }
426 
427 
428     /*
429      * Retrieve the legacy partition layout
430      */
431     printf("\n");
432 
433     /* Allocate a layout buffer with initially 4 partition entries (or 16 for NEC PC-98) */
434     BufferSize = DRIVE_LAYOUT_INFO_SIZE(IsNEC_98 ? 16 : 4);
435     LayoutBuffer.Info = RtlAllocateHeap(RtlGetProcessHeap(),
436                                         HEAP_ZERO_MEMORY,
437                                         BufferSize);
438     if (!LayoutBuffer.Info)
439     {
440         printf("Out of memory!");
441         goto Quit;
442     }
443 
444     /*
445      * Keep looping while the drive layout buffer is too small.
446      * Iosb.Information or PartitionCount only contain actual info only
447      * once NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_LAYOUT) succeeds.
448      */
449     for (;;)
450     {
451         Status = NtDeviceIoControlFile(hDisk,
452                                        NULL,
453                                        NULL,
454                                        NULL,
455                                        &Iosb,
456                                        IOCTL_DISK_GET_DRIVE_LAYOUT,
457                                        NULL,
458                                        0,
459                                        LayoutBuffer.Info,
460                                        BufferSize);
461         if (NT_SUCCESS(Status))
462         {
463             /* We succeeded; compactify the layout structure but keep the
464              * number of partition entries rounded up to a multiple of 4. */
465 #if 1
466             BufferSize = DRIVE_LAYOUT_INFO_SIZE(ROUND_UP_NUM(LayoutBuffer.Info->PartitionCount, 4));
467 #else
468             BufferSize = (ULONG)Iosb.Information;
469 #endif
470             ptr = RtlReAllocateHeap(RtlGetProcessHeap(),
471                                     HEAP_REALLOC_IN_PLACE_ONLY,
472                                     LayoutBuffer.Info, BufferSize);
473             if (!ptr)
474             {
475                 printf("Compactification failed; keeping original structure.\n");
476             }
477             else
478             {
479                 LayoutBuffer.Info = ptr;
480             }
481             Status = STATUS_SUCCESS;
482             break;
483         }
484 
485         if (Status != STATUS_BUFFER_TOO_SMALL)
486         {
487             printf("NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_LAYOUT) failed! (Status 0x%lx)\n", Status);
488 
489             /* Bail out if any other error than "invalid function" has been emitted.
490              * This happens for example when calling it on GPT disks. */
491             if (Status != STATUS_INVALID_DEVICE_REQUEST)
492             {
493                 RtlFreeHeap(RtlGetProcessHeap(), 0, LayoutBuffer.Info);
494                 goto Quit;
495             }
496             else
497             {
498                 /* Just stop getting this information */
499                 break;
500             }
501         }
502 
503         /* Reallocate the buffer by chunks of 4 entries */
504         BufferSize += 4 * DRIVE_LAYOUT_INFO_ENTRY_SIZE;
505         ptr = RtlReAllocateHeap(RtlGetProcessHeap(),
506                                 HEAP_ZERO_MEMORY,
507                                 LayoutBuffer.Info, BufferSize);
508         if (!ptr)
509         {
510             printf("Out of memory!");
511             RtlFreeHeap(RtlGetProcessHeap(), 0, LayoutBuffer.Info);
512             goto Quit;
513         }
514         LayoutBuffer.Info = ptr;
515     }
516 
517     if (Status == STATUS_SUCCESS)
518     {
519 #ifdef DUMP_DATA
520         HexDump(LayoutBuffer.Info, (ULONG)Iosb.Information);
521 #endif
522         printf("IOCTL_DISK_GET_DRIVE_LAYOUT\n"
523                "Partitions: %lu  Signature: 0x%08lx\n",
524                LayoutBuffer.Info->PartitionCount,
525                LayoutBuffer.Info->Signature);
526 
527         for (i = 0; i < LayoutBuffer.Info->PartitionCount; i++)
528         {
529             pPartInfo = &LayoutBuffer.Info->PartitionEntry[i];
530 
531             printf(" %ld: nr: %ld boot: %1x type: 0x%x (%s) start: 0x%016I64x count: 0x%016I64x hidden: 0x%lx\n",
532                    i,
533                    pPartInfo->PartitionNumber,
534                    pPartInfo->BootIndicator,
535                    pPartInfo->PartitionType,
536                    pPartInfo->RecognizedPartition ? "Recognized" : "Not recognized",
537                    pPartInfo->StartingOffset.QuadPart,
538                    pPartInfo->PartitionLength.QuadPart,
539                    pPartInfo->HiddenSectors);
540         }
541     }
542     RtlFreeHeap(RtlGetProcessHeap(), 0, LayoutBuffer.Info);
543 
544 
545     /*
546      * Retrieve the extended partition layout
547      */
548     printf("\n");
549 
550     /* Allocate a layout buffer with initially 4 partition entries (or 16 for NEC PC-98) */
551     BufferSize = DRIVE_LAYOUT_INFOEX_SIZE(IsNEC_98 ? 16 : 4);
552     LayoutBuffer.InfoEx = RtlAllocateHeap(RtlGetProcessHeap(),
553                                           HEAP_ZERO_MEMORY,
554                                           BufferSize);
555     if (!LayoutBuffer.InfoEx)
556     {
557         printf("Out of memory!");
558         goto Quit;
559     }
560 
561     /*
562      * Keep looping while the drive layout buffer is too small.
563      * Iosb.Information or PartitionCount only contain actual info only
564      * once NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_LAYOUT_EX) succeeds.
565      */
566     for (;;)
567     {
568         Status = NtDeviceIoControlFile(hDisk,
569                                        NULL,
570                                        NULL,
571                                        NULL,
572                                        &Iosb,
573                                        IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
574                                        NULL,
575                                        0,
576                                        LayoutBuffer.InfoEx,
577                                        BufferSize);
578         if (NT_SUCCESS(Status))
579         {
580             /* We succeeded; compactify the layout structure but keep the
581              * number of partition entries rounded up to a multiple of 4. */
582 #if 1
583             BufferSize = DRIVE_LAYOUT_INFOEX_SIZE(ROUND_UP_NUM(LayoutBuffer.InfoEx->PartitionCount, 4));
584 #else
585             BufferSize = (ULONG)Iosb.Information;
586 #endif
587             ptr = RtlReAllocateHeap(RtlGetProcessHeap(),
588                                     HEAP_REALLOC_IN_PLACE_ONLY,
589                                     LayoutBuffer.InfoEx, BufferSize);
590             if (!ptr)
591             {
592                 printf("Compactification failed; keeping original structure.\n");
593             }
594             else
595             {
596                 LayoutBuffer.InfoEx = ptr;
597             }
598             Status = STATUS_SUCCESS;
599             break;
600         }
601 
602         if (Status != STATUS_BUFFER_TOO_SMALL)
603         {
604             printf("NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_LAYOUT_EX) failed! (Status 0x%lx)\n", Status);
605 
606             /* Bail out if any other error than "invalid function" has been emitted */
607             if (Status != STATUS_INVALID_DEVICE_REQUEST)
608             {
609                 RtlFreeHeap(RtlGetProcessHeap(), 0, LayoutBuffer.InfoEx);
610                 goto Quit;
611             }
612             else
613             {
614                 /* Just stop getting this information */
615                 break;
616             }
617         }
618 
619         /* Reallocate the buffer by chunks of 4 entries */
620         BufferSize += 4 * DRIVE_LAYOUT_INFOEX_ENTRY_SIZE;
621         ptr = RtlReAllocateHeap(RtlGetProcessHeap(),
622                                 HEAP_ZERO_MEMORY,
623                                 LayoutBuffer.InfoEx, BufferSize);
624         if (!ptr)
625         {
626             printf("Out of memory!");
627             RtlFreeHeap(RtlGetProcessHeap(), 0, LayoutBuffer.InfoEx);
628             goto Quit;
629         }
630         LayoutBuffer.InfoEx = ptr;
631     }
632 
633     if (Status == STATUS_SUCCESS)
634     {
635 #ifdef DUMP_DATA
636         HexDump(LayoutBuffer.InfoEx, (ULONG)Iosb.Information);
637 #endif
638         printf("IOCTL_DISK_GET_DRIVE_LAYOUT_EX\n"
639                "PartitionStyle: %lu [%s]\n",
640                LayoutBuffer.InfoEx->PartitionStyle,
641                PARTITION_STYLE_NAME(LayoutBuffer.InfoEx->PartitionStyle));
642 
643         if (LayoutBuffer.InfoEx->PartitionStyle == PARTITION_STYLE_MBR)
644         {
645             printf("Partitions: %lu  Signature: 0x%08lx",
646                    LayoutBuffer.InfoEx->PartitionCount,
647                    LayoutBuffer.InfoEx->Mbr.Signature);
648 #if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
649             printf("  Checksum 0x%08lx\n",
650                    LayoutBuffer.InfoEx->Mbr.CheckSum);
651 #else
652             printf("\n");
653 #endif
654 
655             for (i = 0; i < LayoutBuffer.InfoEx->PartitionCount; i++)
656             {
657                 pPartInfoEx = &LayoutBuffer.InfoEx->PartitionEntry[i];
658 
659                 printf(" %ld: nr: %ld [%s] boot: %1x type: 0x%x (%s) start: 0x%016I64x count: 0x%016I64x hidden: 0x%lx\n",
660                        i,
661                        pPartInfoEx->PartitionNumber,
662                        PARTITION_STYLE_NAME(pPartInfoEx->PartitionStyle),
663                        pPartInfoEx->Mbr.BootIndicator,
664                        pPartInfoEx->Mbr.PartitionType,
665                        pPartInfoEx->Mbr.RecognizedPartition ? "Recognized" : "Not recognized",
666                        pPartInfoEx->StartingOffset.QuadPart,
667                        pPartInfoEx->PartitionLength.QuadPart,
668                        pPartInfoEx->Mbr.HiddenSectors);
669 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
670                 printf("    PartitionId: {" GUID_FORMAT_STR "}\n",
671                        GUID_ELEMENTS(&pPartInfoEx->Mbr.PartitionId));
672 #endif
673             }
674         }
675         else if (LayoutBuffer.InfoEx->PartitionStyle == PARTITION_STYLE_GPT)
676         {
677             printf("Partitions: %lu  MaxPartitionCount: %lu\n"
678                    "DiskId: {" GUID_FORMAT_STR "}\n"
679                    "StartingUsableOffset: 0x%016I64x  UsableLength: 0x%016I64x\n",
680                    LayoutBuffer.InfoEx->PartitionCount,
681                    LayoutBuffer.InfoEx->Gpt.MaxPartitionCount,
682                    GUID_ELEMENTS(&LayoutBuffer.InfoEx->Gpt.DiskId),
683                    LayoutBuffer.InfoEx->Gpt.StartingUsableOffset.QuadPart,
684                    LayoutBuffer.InfoEx->Gpt.UsableLength.QuadPart);
685 
686             for (i = 0; i < LayoutBuffer.InfoEx->PartitionCount; i++)
687             {
688                 pPartInfoEx = &LayoutBuffer.InfoEx->PartitionEntry[i];
689 
690                 printf(" %ld: nr: %ld [%s]\n"
691                        "    type : {" GUID_FORMAT_STR "}\n"
692                        "    id   : {" GUID_FORMAT_STR "}\n"
693                        "    attrs: 0x%016I64x\n"
694                        "    name : '%.*S'\n"
695                        "    start: 0x%016I64x count: 0x%016I64x\n",
696                        i,
697                        pPartInfoEx->PartitionNumber,
698                        PARTITION_STYLE_NAME(pPartInfoEx->PartitionStyle),
699                        GUID_ELEMENTS(&pPartInfoEx->Gpt.PartitionType),
700                        GUID_ELEMENTS(&pPartInfoEx->Gpt.PartitionId),
701                        pPartInfoEx->Gpt.Attributes,
702                        (int)_countof(pPartInfoEx->Gpt.Name),
703                        pPartInfoEx->Gpt.Name,
704                        pPartInfoEx->StartingOffset.QuadPart,
705                        pPartInfoEx->PartitionLength.QuadPart);
706             }
707         }
708     }
709     RtlFreeHeap(RtlGetProcessHeap(), 0, LayoutBuffer.InfoEx);
710 
711 Quit:
712     CloseHandle(hDisk);
713     return 0;
714 }
715