[ROSAPPS:PARTINFO] Implement display of IOCTL_DISK_GET_DRIVE_LAYOUT_EX info, for...
[reactos.git] / modules / rosapps / applications / sysutils / utils / partinfo / partinfo.c
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 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 // #define DUMP_DATA
19 #define DUMP_SIZE_INFO
20
21
22 /* FORMATTING HELPERS *******************************************************/
23
24 static PCSTR PartitionStyleNames[] = {"MBR", "GPT", "RAW", "Unknown"};
25 #define PARTITION_STYLE_NAME(PartStyle) \
26 ( ((PartStyle) <= PARTITION_STYLE_RAW) \
27 ? PartitionStyleNames[(PartStyle)] \
28 : PartitionStyleNames[_countof(PartitionStyleNames)-1] )
29
30 #define GUID_FORMAT_STR "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
31 #define GUID_ELEMENTS(Guid) \
32 (Guid)->Data1, (Guid)->Data2, (Guid)->Data3, \
33 (Guid)->Data4[0], (Guid)->Data4[1], (Guid)->Data4[2], (Guid)->Data4[3], \
34 (Guid)->Data4[4], (Guid)->Data4[5], (Guid)->Data4[6], (Guid)->Data4[7]
35
36
37 /* FUNCTIONS ****************************************************************/
38
39 #ifdef DUMP_DATA
40 void HexDump(
41 IN PVOID buffer,
42 IN ULONG size)
43 {
44 ULONG_PTR offset = 0;
45 PUCHAR ptr;
46
47 while (offset < (size & ~15))
48 {
49 ptr = (PUCHAR)((ULONG_PTR)buffer + offset);
50 printf("%08lx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx-%02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx\n",
51 offset,
52 ptr[0], ptr[1], ptr[2] , ptr[3] , ptr[4] , ptr[5] , ptr[6] , ptr[7],
53 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
54 offset += 16;
55 }
56
57 ptr = (PUCHAR)((ULONG_PTR)buffer + offset);
58 printf("%08lx ", offset);
59 while (offset < size)
60 {
61 printf(" %02hx", *ptr);
62 offset++;
63 ptr++;
64 }
65
66 printf("\n\n\n");
67 }
68 #endif
69
70 void Usage(void)
71 {
72 puts("Usage: partinfo <drive number>");
73 }
74
75 int main(int argc, char *argv[])
76 {
77 NTSTATUS Status;
78 ULONG ulDrive;
79 HANDLE hDisk;
80 DWORD dwRead;
81 DWORD dwLastError;
82 DWORD i;
83 SYSTEM_DEVICE_INFORMATION DeviceInfo;
84 DISK_GEOMETRY DiskGeometry;
85 ULONG BufferSize;
86 PDRIVE_LAYOUT_INFORMATION LayoutBuffer;
87 PDRIVE_LAYOUT_INFORMATION_EX LayoutBufferEx;
88 PVOID ptr;
89 GUID Guid;
90 WCHAR DriveName[40];
91
92 if (argc != 2)
93 {
94 Usage();
95 return 0;
96 }
97
98 ulDrive = strtoul(argv[1], NULL, 10);
99 if (errno != 0)
100 {
101 printf("Error: Malformed drive number\n");
102 return 0;
103 }
104
105 /*
106 * Retrieve the number of disks on the system.
107 */
108 Status = NtQuerySystemInformation(SystemDeviceInformation,
109 &DeviceInfo,
110 sizeof(DeviceInfo),
111 &i);
112 if (!NT_SUCCESS(Status))
113 {
114 printf("NtQuerySystemInformation() failed (Status 0x%lx)\n", Status);
115 return 0;
116 }
117 if (DeviceInfo.NumberOfDisks == 0)
118 {
119 printf("No disk drive installed!\n");
120 return 0;
121 }
122
123 if (ulDrive >= DeviceInfo.NumberOfDisks)
124 {
125 printf("Invalid disk drive number! Valid drive numbers: [0-%lu]\n",
126 DeviceInfo.NumberOfDisks-1);
127 return 0;
128 }
129
130 /* Build the full drive name */
131 swprintf(DriveName, L"\\\\.\\PHYSICALDRIVE%lu", ulDrive);
132
133 /* Open the drive */
134 hDisk = CreateFileW(DriveName,
135 GENERIC_READ,
136 FILE_SHARE_READ | FILE_SHARE_WRITE,
137 NULL,
138 OPEN_EXISTING,
139 0,
140 NULL);
141 if (hDisk == INVALID_HANDLE_VALUE)
142 {
143 printf("Could not open drive!");
144 return 0;
145 }
146
147
148 /*
149 * Get the drive geometry.
150 */
151 if (!DeviceIoControl(hDisk,
152 IOCTL_DISK_GET_DRIVE_GEOMETRY,
153 NULL,
154 0,
155 &DiskGeometry,
156 sizeof(DiskGeometry),
157 &dwRead,
158 NULL))
159 {
160 printf("DeviceIoControl(IOCTL_DISK_GET_DRIVE_GEOMETRY) failed! Error: %lu\n",
161 GetLastError());
162 CloseHandle(hDisk);
163 return 0;
164 }
165
166 #ifdef DUMP_DATA
167 HexDump(&DiskGeometry, dwRead);
168 #endif
169 printf("Drive number: %lu\n\n", ulDrive);
170
171 printf("IOCTL_DISK_GET_DRIVE_GEOMETRY\n"
172 "Cylinders: %I64u\nMediaType: %x\nTracksPerCylinder: %lu\n"
173 "SectorsPerTrack: %lu\nBytesPerSector: %lu\n\n",
174 DiskGeometry.Cylinders.QuadPart,
175 DiskGeometry.MediaType,
176 DiskGeometry.TracksPerCylinder,
177 DiskGeometry.SectorsPerTrack,
178 DiskGeometry.BytesPerSector);
179
180 #if 0 // TODO!
181 /* Get extended drive geometry */
182 // IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
183 #endif
184
185
186 /*
187 * Retrieve the legacy partition layout
188 */
189
190 /* Allocate a layout buffer with 4 partition entries first */
191 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
192 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
193 LayoutBuffer = malloc(BufferSize);
194 if (!LayoutBuffer)
195 {
196 printf("Out of memory!");
197 CloseHandle(hDisk);
198 return 0;
199 }
200 memset(LayoutBuffer, 0, BufferSize);
201
202 /* Keep looping while the drive layout buffer is too small */
203 for (;;)
204 {
205 if (DeviceIoControl(hDisk,
206 IOCTL_DISK_GET_DRIVE_LAYOUT,
207 NULL,
208 0,
209 LayoutBuffer,
210 BufferSize,
211 &dwRead,
212 NULL))
213 {
214 dwLastError = ERROR_SUCCESS;
215 break;
216 }
217
218 dwLastError = GetLastError();
219 if (dwLastError != ERROR_INSUFFICIENT_BUFFER)
220 {
221 printf("DeviceIoControl(IOCTL_DISK_GET_DRIVE_LAYOUT) failed! Error: %lu\n",
222 dwLastError);
223
224 /* Bail out if any other error than "invalid function" has been emitted.
225 * This happens for example when calling it on GPT disks. */
226 if (dwLastError != ERROR_INVALID_FUNCTION)
227 {
228 free(LayoutBuffer);
229 CloseHandle(hDisk);
230 return 0;
231 }
232 else
233 {
234 /* Just stop getting this information */
235 break;
236 }
237 }
238
239 /* Reallocate the buffer */
240 BufferSize += 4 * sizeof(PARTITION_INFORMATION);
241 ptr = realloc(LayoutBuffer, BufferSize);
242 if (!ptr)
243 {
244 printf("Out of memory!");
245 free(LayoutBuffer);
246 CloseHandle(hDisk);
247 return 0;
248 }
249 LayoutBuffer = ptr;
250 memset(LayoutBuffer, 0, BufferSize);
251 }
252
253 if (dwLastError == ERROR_SUCCESS)
254 {
255 #ifdef DUMP_DATA
256 HexDump(LayoutBuffer, dwRead);
257 #endif
258
259 printf("IOCTL_DISK_GET_DRIVE_LAYOUT\n"
260 "Partitions: %lu Signature: 0x%08lx\n",
261 LayoutBuffer->PartitionCount,
262 LayoutBuffer->Signature);
263
264 for (i = 0; i < LayoutBuffer->PartitionCount; i++)
265 {
266 printf(" %ld: nr: %ld boot: %1x type: %x start: 0x%016I64x count: 0x%016I64x hidden: 0x%lx\n",
267 i,
268 LayoutBuffer->PartitionEntry[i].PartitionNumber,
269 LayoutBuffer->PartitionEntry[i].BootIndicator,
270 LayoutBuffer->PartitionEntry[i].PartitionType,
271 LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart,
272 LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart,
273 LayoutBuffer->PartitionEntry[i].HiddenSectors);
274 }
275
276 free(LayoutBuffer);
277 }
278
279
280 /*
281 * Retrieve the extended partition layout
282 */
283 printf("\n");
284
285 /* Allocate a layout buffer with 4 partition entries first */
286 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
287 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX));
288 LayoutBufferEx = malloc(BufferSize);
289 if (!LayoutBufferEx)
290 {
291 printf("Out of memory!");
292 CloseHandle(hDisk);
293 return 0;
294 }
295 memset(LayoutBufferEx, 0, BufferSize);
296
297 /* Keep looping while the drive layout buffer is too small */
298 for (;;)
299 {
300 if (DeviceIoControl(hDisk,
301 IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
302 NULL,
303 0,
304 LayoutBufferEx,
305 BufferSize,
306 &dwRead,
307 NULL))
308 {
309 dwLastError = ERROR_SUCCESS;
310 break;
311 }
312
313 dwLastError = GetLastError();
314 if (dwLastError != ERROR_INSUFFICIENT_BUFFER)
315 {
316 printf("DeviceIoControl(IOCTL_DISK_GET_DRIVE_LAYOUT_EX) failed! Error: %lu\n",
317 dwLastError);
318
319 /* Bail out if any other error than "invalid function" has been emitted */
320 if (dwLastError != ERROR_INVALID_FUNCTION)
321 {
322 free(LayoutBufferEx);
323 CloseHandle(hDisk);
324 return 0;
325 }
326 else
327 {
328 /* Just stop getting this information */
329 break;
330 }
331 }
332
333 /* Reallocate the buffer */
334 BufferSize += 4 * sizeof(PARTITION_INFORMATION_EX);
335 ptr = realloc(LayoutBufferEx, BufferSize);
336 if (!ptr)
337 {
338 printf("Out of memory!");
339 free(LayoutBufferEx);
340 CloseHandle(hDisk);
341 return 0;
342 }
343 LayoutBufferEx = ptr;
344 memset(LayoutBufferEx, 0, BufferSize);
345 }
346
347 if (dwLastError == ERROR_SUCCESS)
348 {
349 #ifdef DUMP_DATA
350 HexDump(LayoutBufferEx, dwRead);
351 #endif
352
353 printf("IOCTL_DISK_GET_DRIVE_LAYOUT_EX\n"
354 "PartitionStyle: [%s]\n",
355 PARTITION_STYLE_NAME(LayoutBufferEx->PartitionStyle));
356
357 if (LayoutBufferEx->PartitionStyle == PARTITION_STYLE_MBR)
358 {
359 printf("Partitions: %lu Signature: 0x%08lx",
360 LayoutBufferEx->PartitionCount,
361 LayoutBufferEx->Mbr.Signature);
362 #if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
363 printf(" Checksum 0x%08lx\n",
364 LayoutBufferEx->Mbr.CheckSum);
365 #else
366 printf("\n");
367 #endif
368
369 for (i = 0; i < LayoutBufferEx->PartitionCount; i++)
370 {
371 printf(" %ld: nr: %ld [%s] boot: %1x type: %x start: 0x%016I64x count: 0x%016I64x hidden: 0x%lx\n",
372 i,
373 LayoutBufferEx->PartitionEntry[i].PartitionNumber,
374 PARTITION_STYLE_NAME(LayoutBufferEx->PartitionEntry[i].PartitionStyle),
375 LayoutBufferEx->PartitionEntry[i].Mbr.BootIndicator,
376 LayoutBufferEx->PartitionEntry[i].Mbr.PartitionType,
377 LayoutBufferEx->PartitionEntry[i].StartingOffset.QuadPart,
378 LayoutBufferEx->PartitionEntry[i].PartitionLength.QuadPart,
379 LayoutBufferEx->PartitionEntry[i].Mbr.HiddenSectors);
380 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
381 Guid = LayoutBufferEx->PartitionEntry[i].Mbr.PartitionId;
382 printf(" PartitionId: {" GUID_FORMAT_STR "}\n",
383 GUID_ELEMENTS(&Guid));
384 #endif
385 }
386 }
387 else if (LayoutBufferEx->PartitionStyle == PARTITION_STYLE_GPT)
388 {
389 Guid = LayoutBufferEx->Gpt.DiskId;
390 printf("Partitions: %lu MaxPartitionCount: %lu\n"
391 "DiskId: {" GUID_FORMAT_STR "}\n"
392 "StartingUsableOffset: 0x%016I64x UsableLength: 0x%016I64x\n",
393 LayoutBufferEx->PartitionCount,
394 LayoutBufferEx->Gpt.MaxPartitionCount,
395 GUID_ELEMENTS(&Guid),
396 LayoutBufferEx->Gpt.StartingUsableOffset.QuadPart,
397 LayoutBufferEx->Gpt.UsableLength.QuadPart);
398
399 for (i = 0; i < LayoutBufferEx->PartitionCount; i++)
400 {
401 printf(" %ld: nr: %ld [%s]\n"
402 " type : {" GUID_FORMAT_STR "}\n"
403 " id : {" GUID_FORMAT_STR "}\n"
404 " attrs: 0x%016I64x\n"
405 " name : '%.*S'\n"
406 " start: 0x%016I64x count: 0x%016I64x\n",
407 i,
408 LayoutBufferEx->PartitionEntry[i].PartitionNumber,
409 PARTITION_STYLE_NAME(LayoutBufferEx->PartitionEntry[i].PartitionStyle),
410 GUID_ELEMENTS(&LayoutBufferEx->PartitionEntry[i].Gpt.PartitionType),
411 GUID_ELEMENTS(&LayoutBufferEx->PartitionEntry[i].Gpt.PartitionId),
412 LayoutBufferEx->PartitionEntry[i].Gpt.Attributes,
413 _countof(LayoutBufferEx->PartitionEntry[i].Gpt.Name),
414 LayoutBufferEx->PartitionEntry[i].Gpt.Name,
415 LayoutBufferEx->PartitionEntry[i].StartingOffset.QuadPart,
416 LayoutBufferEx->PartitionEntry[i].PartitionLength.QuadPart);
417 }
418 }
419
420 free(LayoutBufferEx);
421 }
422
423 CloseHandle(hDisk);
424
425 return 0;
426 }