Reactos
1/*
2 * PROJECT: ReactOS DiskPart
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/diskpart/partlist.c
5 * PURPOSE: Manages all the partitions of the OS in an interactive way.
6 * PROGRAMMERS: Eric Kohl
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "diskpart.h"
12
13#define NDEBUG
14#include <debug.h>
15
16#define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\
17{\
18 PLIST_ENTRY current;\
19\
20 current = (ListHead)->Flink;\
21 while (current != (ListHead))\
22 {\
23 if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\
24 (NewEntry)->SortField)\
25 {\
26 break;\
27 }\
28 current = current->Flink;\
29 }\
30\
31 InsertTailList(current, &((NewEntry)->ListEntryField));\
32}
33
34/* We have to define it there, because it is not in the MS DDK */
35#define PARTITION_LINUX 0x83
36
37#define PARTITION_TBL_SIZE 4
38
39#define MBR_MAGIC 0xAA55
40
41#include <pshpack1.h>
42
43typedef struct _PARTITION
44{
45 unsigned char BootFlags; /* bootable? 0=no, 128=yes */
46 unsigned char StartingHead; /* beginning head number */
47 unsigned char StartingSector; /* beginning sector number */
48 unsigned char StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */
49 unsigned char PartitionType; /* Operating System type indicator code */
50 unsigned char EndingHead; /* ending head number */
51 unsigned char EndingSector; /* ending sector number */
52 unsigned char EndingCylinder; /* also a 10 bit nmbr, with same high 2 bit trick */
53 unsigned int StartingBlock; /* first sector relative to start of disk */
54 unsigned int SectorCount; /* number of sectors in partition */
55} PARTITION, *PPARTITION;
56
57typedef struct _PARTITION_SECTOR
58{
59 UCHAR BootCode[440]; /* 0x000 */
60 ULONG Signature; /* 0x1B8 */
61 UCHAR Reserved[2]; /* 0x1BC */
62 PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */
63 USHORT Magic; /* 0x1FE */
64} PARTITION_SECTOR, *PPARTITION_SECTOR;
65
66#include <poppack.h>
67
68
69/* GLOBALS ********************************************************************/
70
71LIST_ENTRY DiskListHead;
72LIST_ENTRY BiosDiskListHead;
73LIST_ENTRY VolumeListHead;
74
75PDISKENTRY CurrentDisk = NULL;
76PPARTENTRY CurrentPartition = NULL;
77PVOLENTRY CurrentVolume = NULL;
78
79
80/* FUNCTIONS ******************************************************************/
81
82#ifdef DUMP_PARTITION_TABLE
83VOID
84DumpPartitionTable(
85 _In_ PDISKENTRY DiskEntry)
86{
87 PPARTITION_INFORMATION_EX PartitionInfo;
88 ULONG i;
89
90 DbgPrint("\n");
91
92 if (DiskEntry->LayoutBuffer->PartitionStyle == PARTITION_STYLE_MBR)
93 {
94 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
95 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
96
97 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
98 {
99 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
100 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
101 i,
102 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
103 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
104 PartitionInfo->Mbr.HiddenSectors,
105 PartitionInfo->PartitionNumber,
106 PartitionInfo->Mbr.PartitionType,
107 PartitionInfo->Mbr.BootIndicator ? '*': ' ',
108 PartitionInfo->RewritePartition ? 'Y': 'N');
109 }
110 }
111 else if (DiskEntry->LayoutBuffer->PartitionStyle == PARTITION_STYLE_GPT)
112 {
113 DbgPrint("Index Start Length Nr RW Type \n");
114 DbgPrint("----- ------------ ------------ -- -- --------\n");
115 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
116 {
117 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
118
119 DbgPrint(" %3lu %12I64u %12I64u %2lu %c %08lx\n",
120 i,
121 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
122 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
123 PartitionInfo->PartitionNumber,
124 PartitionInfo->RewritePartition ? 'Y': 'N',
125 PartitionInfo->Gpt.PartitionType.Data1);
126 }
127 }
128
129 DbgPrint("\n");
130}
131#endif
132
133#ifdef DUMP_PARTITION_LIST
134VOID
135DumpPartitionList(
136 _In_ PDISKENTRY DiskEntry)
137{
138 PLIST_ENTRY ListEntry;
139 PPARTENTRY PartEntry;
140
141 DbgPrint("\n");
142
143 if (DiskEntry->PartitionStyle == PARTITION_STYLE_GPT)
144 {
145 DbgPrint("Disk Start Disk End Disk Length \n");
146 DbgPrint("------------ ------------ ------------\n");
147 DbgPrint("%12I64u %12I64u %12I64u\n",
148 DiskEntry->StartSector.QuadPart,
149 DiskEntry->EndSector.QuadPart,
150 DiskEntry->EndSector.QuadPart - DiskEntry->StartSector.QuadPart + 1);
151
152 DbgPrint("\n");
153
154 DbgPrint("Start End Length Nr Type P\n");
155 DbgPrint("------------ ------------ ------------ --- -------- --\n");
156
157 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
158 ListEntry != &DiskEntry->PrimaryPartListHead;
159 ListEntry = ListEntry->Flink)
160 {
161 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
162
163 DbgPrint("%12I64u %12I64u %12I64u %3lu %08lx %c\n",
164 PartEntry->StartSector.QuadPart,
165 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
166 PartEntry->SectorCount.QuadPart,
167 PartEntry->PartitionNumber,
168 PartEntry->Gpt.PartitionType.Data1,
169 PartEntry->IsPartitioned ? 'Y': 'N');
170 }
171 }
172 else if (DiskEntry->PartitionStyle == PARTITION_STYLE_MBR)
173 {
174 DbgPrint("Disk Start Disk End Disk Length \n");
175 DbgPrint("------------ ------------ ------------\n");
176 DbgPrint("%12I64u %12I64u %12I64u\n",
177 DiskEntry->StartSector.QuadPart,
178 DiskEntry->EndSector.QuadPart,
179 DiskEntry->EndSector.QuadPart - DiskEntry->StartSector.QuadPart + 1);
180
181 }
182
183 DbgPrint("\n");
184}
185#endif
186
187
188ULONGLONG
189AlignDown(
190 _In_ ULONGLONG Value,
191 _In_ ULONG Alignment)
192{
193 ULONGLONG Temp;
194
195 Temp = Value / Alignment;
196
197 return Temp * Alignment;
198}
199
200static
201VOID
202GetDriverName(
203 PDISKENTRY DiskEntry)
204{
205 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
206 WCHAR KeyName[32];
207 NTSTATUS Status;
208
209 RtlInitUnicodeString(&DiskEntry->DriverName,
210 NULL);
211
212 StringCchPrintfW(KeyName, ARRAYSIZE(KeyName),
213 L"\\Scsi\\Scsi Port %lu",
214 DiskEntry->Port);
215
216 RtlZeroMemory(&QueryTable,
217 sizeof(QueryTable));
218
219 QueryTable[0].Name = L"Driver";
220 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
221 QueryTable[0].EntryContext = &DiskEntry->DriverName;
222
223 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
224 KeyName,
225 QueryTable,
226 NULL,
227 NULL);
228 if (!NT_SUCCESS(Status))
229 {
230 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
231 }
232}
233
234static
235NTSTATUS
236NTAPI
237DiskIdentifierQueryRoutine(
238 PWSTR ValueName,
239 ULONG ValueType,
240 PVOID ValueData,
241 ULONG ValueLength,
242 PVOID Context,
243 PVOID EntryContext)
244{
245 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
246 UNICODE_STRING NameU;
247
248 if (ValueType == REG_SZ &&
249 ValueLength == 20 * sizeof(WCHAR))
250 {
251 NameU.Buffer = (PWCHAR)ValueData;
252 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
253 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
254
255 NameU.Buffer = (PWCHAR)ValueData + 9;
256 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
257
258 return STATUS_SUCCESS;
259 }
260
261 return STATUS_UNSUCCESSFUL;
262}
263
264static
265NTSTATUS
266NTAPI
267DiskConfigurationDataQueryRoutine(
268 PWSTR ValueName,
269 ULONG ValueType,
270 PVOID ValueData,
271 ULONG ValueLength,
272 PVOID Context,
273 PVOID EntryContext)
274{
275 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
276 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
277 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
278 ULONG i;
279
280 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
281 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
282 return STATUS_UNSUCCESSFUL;
283
284 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
285
286 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
287#if 0
288 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
289 FullResourceDescriptor->PartialResourceList.Revision != 1)
290 return STATUS_UNSUCCESSFUL;
291#endif
292
293 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
294 {
295 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
296 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
297 continue;
298
299 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
300 BiosDiskEntry->DiskGeometry = *DiskGeometry;
301
302 return STATUS_SUCCESS;
303 }
304
305 return STATUS_UNSUCCESSFUL;
306}
307
308static
309NTSTATUS
310NTAPI
311SystemConfigurationDataQueryRoutine(
312 PWSTR ValueName,
313 ULONG ValueType,
314 PVOID ValueData,
315 ULONG ValueLength,
316 PVOID Context,
317 PVOID EntryContext)
318{
319 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
320 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
321 ULONG i;
322
323 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
324 ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR))
325 return STATUS_UNSUCCESSFUL;
326
327 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
328
329 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
330#if 0
331 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
332 FullResourceDescriptor->PartialResourceList.Revision != 1)
333 return STATUS_UNSUCCESSFUL;
334#endif
335
336 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
337 {
338 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
339 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
340 continue;
341
342 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(RtlGetProcessHeap(), 0,
343 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
344 if (*Int13Drives == NULL)
345 return STATUS_NO_MEMORY;
346
347 memcpy(*Int13Drives,
348 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
349 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
350 return STATUS_SUCCESS;
351 }
352
353 return STATUS_UNSUCCESSFUL;
354}
355
356
357#define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
358
359static
360VOID
361EnumerateBiosDiskEntries(VOID)
362{
363 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
364 WCHAR Name[120];
365 ULONG AdapterCount;
366 ULONG DiskCount;
367 NTSTATUS Status;
368 PCM_INT13_DRIVE_PARAMETER Int13Drives;
369 PBIOSDISKENTRY BiosDiskEntry;
370
371 memset(QueryTable, 0, sizeof(QueryTable));
372
373 QueryTable[1].Name = L"Configuration Data";
374 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
375 Int13Drives = NULL;
376 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
377 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
378 &QueryTable[1],
379 (PVOID)&Int13Drives,
380 NULL);
381 if (!NT_SUCCESS(Status))
382 {
383 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
384 return;
385 }
386
387 AdapterCount = 0;
388 while (1)
389 {
390 StringCchPrintfW(Name, ARRAYSIZE(Name),
391 L"%s\\%lu", ROOT_NAME, AdapterCount);
392 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
393 Name,
394 &QueryTable[2],
395 NULL,
396 NULL);
397 if (!NT_SUCCESS(Status))
398 {
399 break;
400 }
401
402 StringCchPrintfW(Name, ARRAYSIZE(Name),
403 L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
404 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
405 Name,
406 &QueryTable[2],
407 NULL,
408 NULL);
409 if (NT_SUCCESS(Status))
410 {
411 while (1)
412 {
413 StringCchPrintfW(Name, ARRAYSIZE(Name),
414 L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
415 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
416 Name,
417 &QueryTable[2],
418 NULL,
419 NULL);
420 if (!NT_SUCCESS(Status))
421 {
422 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
423 return;
424 }
425
426 StringCchPrintfW(Name, ARRAYSIZE(Name),
427 L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
428 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
429 Name,
430 &QueryTable[2],
431 NULL,
432 NULL);
433 if (NT_SUCCESS(Status))
434 {
435 QueryTable[0].Name = L"Identifier";
436 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
437 QueryTable[1].Name = L"Configuration Data";
438 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
439
440 DiskCount = 0;
441 while (1)
442 {
443 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
444 if (BiosDiskEntry == NULL)
445 {
446 break;
447 }
448
449 StringCchPrintfW(Name, ARRAYSIZE(Name),
450 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
451 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
452 Name,
453 QueryTable,
454 (PVOID)BiosDiskEntry,
455 NULL);
456 if (!NT_SUCCESS(Status))
457 {
458 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry);
459 break;
460 }
461
462 BiosDiskEntry->DiskNumber = DiskCount;
463 BiosDiskEntry->Recognized = FALSE;
464
465 if (DiskCount < Int13Drives[0].NumberDrives)
466 {
467 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
468 }
469 else
470 {
471 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
472 }
473
474 InsertTailList(&BiosDiskListHead, &BiosDiskEntry->ListEntry);
475
476 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
477 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
478 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
479 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
480 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
481 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
482 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
483 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
484 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
485 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
486 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
487
488 DiskCount++;
489 }
490 }
491
492 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
493 return;
494 }
495 }
496
497 AdapterCount++;
498 }
499
500 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
501}
502
503
504static
505VOID
506AddMbrPartitionToDisk(
507 ULONG DiskNumber,
508 PDISKENTRY DiskEntry,
509 ULONG PartitionIndex,
510 BOOLEAN LogicalPartition)
511{
512 PPARTITION_INFORMATION_EX PartitionInfo;
513 PPARTENTRY PartEntry;
514
515 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
516 if (PartitionInfo->Mbr.PartitionType == 0 ||
517 (LogicalPartition == TRUE && IsContainerPartition(PartitionInfo->Mbr.PartitionType)))
518 return;
519
520 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
521 HEAP_ZERO_MEMORY,
522 sizeof(PARTENTRY));
523 if (PartEntry == NULL)
524 {
525 /* TODO: Error message */
526 return;
527 }
528
529 PartEntry->DiskEntry = DiskEntry;
530
531 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
532 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
533
534 PartEntry->Mbr.BootIndicator = PartitionInfo->Mbr.BootIndicator;
535 PartEntry->Mbr.PartitionType = PartitionInfo->Mbr.PartitionType;
536
537 PartEntry->LogicalPartition = LogicalPartition;
538 PartEntry->IsPartitioned = TRUE;
539 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
540 PartEntry->PartitionIndex = PartitionIndex;
541
542 if (IsContainerPartition(PartEntry->Mbr.PartitionType))
543 {
544 PartEntry->FormatState = Unformatted;
545
546 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
547 DiskEntry->ExtendedPartition = PartEntry;
548 }
549 else if ((PartEntry->Mbr.PartitionType == PARTITION_FAT_12) ||
550 (PartEntry->Mbr.PartitionType == PARTITION_FAT_16) ||
551 (PartEntry->Mbr.PartitionType == PARTITION_HUGE) ||
552 (PartEntry->Mbr.PartitionType == PARTITION_XINT13) ||
553 (PartEntry->Mbr.PartitionType == PARTITION_FAT32) ||
554 (PartEntry->Mbr.PartitionType == PARTITION_FAT32_XINT13))
555 {
556#if 0
557 if (CheckFatFormat())
558 {
559 PartEntry->FormatState = Preformatted;
560 }
561 else
562 {
563 PartEntry->FormatState = Unformatted;
564 }
565#endif
566 PartEntry->FormatState = Preformatted;
567 }
568 else if (PartEntry->Mbr.PartitionType == PARTITION_LINUX)
569 {
570#if 0
571 if (CheckExt2Format())
572 {
573 PartEntry->FormatState = Preformatted;
574 }
575 else
576 {
577 PartEntry->FormatState = Unformatted;
578 }
579#endif
580 PartEntry->FormatState = Preformatted;
581 }
582 else if (PartEntry->Mbr.PartitionType == PARTITION_IFS)
583 {
584#if 0
585 if (CheckNtfsFormat())
586 {
587 PartEntry->FormatState = Preformatted;
588 }
589 else if (CheckHpfsFormat())
590 {
591 PartEntry->FormatState = Preformatted;
592 }
593 else
594 {
595 PartEntry->FormatState = Unformatted;
596 }
597#endif
598 PartEntry->FormatState = Preformatted;
599 }
600 else
601 {
602 PartEntry->FormatState = UnknownFormat;
603 }
604
605 if (LogicalPartition)
606 InsertTailList(&DiskEntry->LogicalPartListHead,
607 &PartEntry->ListEntry);
608 else
609 InsertTailList(&DiskEntry->PrimaryPartListHead,
610 &PartEntry->ListEntry);
611}
612
613
614static
615VOID
616AddGptPartitionToDisk(
617 ULONG DiskNumber,
618 PDISKENTRY DiskEntry,
619 ULONG PartitionIndex)
620{
621 PPARTITION_INFORMATION_EX PartitionInfo;
622 PPARTENTRY PartEntry;
623
624 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
625 if (IsEqualGUID(&PartitionInfo->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID))
626 return;
627
628 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
629 HEAP_ZERO_MEMORY,
630 sizeof(PARTENTRY));
631 if (PartEntry == NULL)
632 {
633 /* TODO: Error message */
634 return;
635 }
636
637 PartEntry->DiskEntry = DiskEntry;
638
639 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
640 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
641
642 CopyMemory(&PartEntry->Gpt.PartitionType, &PartitionInfo->Gpt.PartitionType, sizeof(GUID));
643 CopyMemory(&PartEntry->Gpt.PartitionId, &PartitionInfo->Gpt.PartitionId, sizeof(GUID));
644 PartEntry->Gpt.Attributes = PartitionInfo->Gpt.Attributes;
645
646 PartEntry->LogicalPartition = FALSE;
647 PartEntry->IsPartitioned = TRUE;
648 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
649 PartEntry->PartitionIndex = PartitionIndex;
650
651 /* TODO: Determine the format state */
652 PartEntry->FormatState = Unformatted;
653
654 InsertTailList(&DiskEntry->PrimaryPartListHead,
655 &PartEntry->ListEntry);
656}
657
658
659VOID
660ScanForUnpartitionedMbrDiskSpace(
661 PDISKENTRY DiskEntry)
662{
663 ULONGLONG StartSector, EndSector;
664 ULONGLONG LastStartSector;
665 ULONGLONG LastSectorCount;
666 ULONGLONG LastUnusedSectorCount;
667 PPARTENTRY PartEntry;
668 PPARTENTRY NewPartEntry;
669 PLIST_ENTRY Entry;
670
671 DPRINT("ScanForUnpartitionedMbrDiskSpace()\n");
672
673 /* Calculate the disk sector limits */
674 /* Limit the SectorCount to 2^32 sectors for MBR disks */
675 StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
676 EndSector = min(DiskEntry->SectorCount.QuadPart, 0x100000000) - 1;
677
678 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
679 {
680 DPRINT1("No primary partition!\n");
681
682 /* Create a partition table that represents the empty disk */
683 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
684 HEAP_ZERO_MEMORY,
685 sizeof(PARTENTRY));
686 if (NewPartEntry == NULL)
687 return;
688
689 NewPartEntry->DiskEntry = DiskEntry;
690
691 NewPartEntry->IsPartitioned = FALSE;
692 NewPartEntry->StartSector.QuadPart = StartSector;
693 NewPartEntry->SectorCount.QuadPart = AlignDown(EndSector + 1, DiskEntry->SectorAlignment) -
694 NewPartEntry->StartSector.QuadPart;
695
696 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
697 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
698 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
699
700 NewPartEntry->FormatState = Unformatted;
701
702 InsertTailList(&DiskEntry->PrimaryPartListHead,
703 &NewPartEntry->ListEntry);
704
705 return;
706 }
707
708 /* Start at the first usable sector */
709 LastStartSector = StartSector;
710 LastSectorCount = 0ULL;
711 LastUnusedSectorCount = 0ULL;
712
713 Entry = DiskEntry->PrimaryPartListHead.Flink;
714 while (Entry != &DiskEntry->PrimaryPartListHead)
715 {
716 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
717
718 if (PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED ||
719 PartEntry->SectorCount.QuadPart != 0ULL)
720 {
721 LastUnusedSectorCount =
722 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
723
724 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
725 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
726 {
727 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
728
729 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
730 HEAP_ZERO_MEMORY,
731 sizeof(PARTENTRY));
732 if (NewPartEntry == NULL)
733 return;
734
735 NewPartEntry->DiskEntry = DiskEntry;
736
737 NewPartEntry->IsPartitioned = FALSE;
738 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
739 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
740 NewPartEntry->StartSector.QuadPart;
741
742 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
743 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
744 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
745
746 NewPartEntry->FormatState = Unformatted;
747
748 /* Insert the table into the list */
749 InsertTailList(&PartEntry->ListEntry,
750 &NewPartEntry->ListEntry);
751 }
752
753 LastStartSector = PartEntry->StartSector.QuadPart;
754 LastSectorCount = PartEntry->SectorCount.QuadPart;
755 }
756
757 Entry = Entry->Flink;
758 }
759
760 /* Check for trailing unpartitioned disk space */
761 if ((LastStartSector + LastSectorCount) < (EndSector + 1))
762 {
763 LastUnusedSectorCount = AlignDown((EndSector + 1) - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
764
765 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
766 {
767 DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
768
769 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
770 HEAP_ZERO_MEMORY,
771 sizeof(PARTENTRY));
772 if (NewPartEntry == NULL)
773 return;
774
775 NewPartEntry->DiskEntry = DiskEntry;
776
777 NewPartEntry->IsPartitioned = FALSE;
778 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
779 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
780 NewPartEntry->StartSector.QuadPart;
781
782 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
783 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
784 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
785
786 NewPartEntry->FormatState = Unformatted;
787
788 /* Append the table to the list */
789 InsertTailList(&DiskEntry->PrimaryPartListHead,
790 &NewPartEntry->ListEntry);
791 }
792 }
793
794 if (DiskEntry->ExtendedPartition != NULL)
795 {
796 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
797 {
798 DPRINT1("No logical partition!\n");
799
800 /* Create a partition table entry that represents the empty extended partition */
801 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
802 HEAP_ZERO_MEMORY,
803 sizeof(PARTENTRY));
804 if (NewPartEntry == NULL)
805 return;
806
807 NewPartEntry->DiskEntry = DiskEntry;
808 NewPartEntry->LogicalPartition = TRUE;
809
810 NewPartEntry->IsPartitioned = FALSE;
811 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
812 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
813
814 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
815 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
816 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
817
818 NewPartEntry->FormatState = Unformatted;
819
820 InsertTailList(&DiskEntry->LogicalPartListHead,
821 &NewPartEntry->ListEntry);
822
823 return;
824 }
825
826 /* Start partition at head 1, cylinder 0 */
827 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
828 LastSectorCount = 0ULL;
829 LastUnusedSectorCount = 0ULL;
830
831 Entry = DiskEntry->LogicalPartListHead.Flink;
832 while (Entry != &DiskEntry->LogicalPartListHead)
833 {
834 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
835
836 if (PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED ||
837 PartEntry->SectorCount.QuadPart != 0ULL)
838 {
839 LastUnusedSectorCount =
840 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
841
842 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
843 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
844 {
845 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
846
847 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
848 HEAP_ZERO_MEMORY,
849 sizeof(PARTENTRY));
850 if (NewPartEntry == NULL)
851 return;
852
853 NewPartEntry->DiskEntry = DiskEntry;
854 NewPartEntry->LogicalPartition = TRUE;
855
856 NewPartEntry->IsPartitioned = FALSE;
857 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
858 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
859 NewPartEntry->StartSector.QuadPart;
860
861 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
862 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
863 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
864
865 NewPartEntry->FormatState = Unformatted;
866
867 /* Insert the table into the list */
868 InsertTailList(&PartEntry->ListEntry,
869 &NewPartEntry->ListEntry);
870 }
871
872 LastStartSector = PartEntry->StartSector.QuadPart;
873 LastSectorCount = PartEntry->SectorCount.QuadPart;
874 }
875
876 Entry = Entry->Flink;
877 }
878
879 /* Check for trailing unpartitioned disk space */
880 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
881 {
882 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
883 DiskEntry->SectorAlignment);
884
885 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
886 {
887 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
888
889 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
890 HEAP_ZERO_MEMORY,
891 sizeof(PARTENTRY));
892 if (NewPartEntry == NULL)
893 return;
894
895 NewPartEntry->DiskEntry = DiskEntry;
896 NewPartEntry->LogicalPartition = TRUE;
897
898 NewPartEntry->IsPartitioned = FALSE;
899 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
900 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
901 NewPartEntry->StartSector.QuadPart;
902
903 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
904 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
905 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
906
907 NewPartEntry->FormatState = Unformatted;
908
909 /* Append the table to the list */
910 InsertTailList(&DiskEntry->LogicalPartListHead,
911 &NewPartEntry->ListEntry);
912 }
913 }
914 }
915
916 DPRINT("ScanForUnpartitionedMbrDiskSpace() done\n");
917}
918
919
920VOID
921ScanForUnpartitionedGptDiskSpace(
922 PDISKENTRY DiskEntry)
923{
924 ULONGLONG LastStartSector;
925 ULONGLONG LastSectorCount;
926 ULONGLONG LastUnusedSectorCount;
927 PPARTENTRY PartEntry;
928 PPARTENTRY NewPartEntry;
929 PLIST_ENTRY Entry;
930
931 DPRINT("ScanForUnpartitionedGptDiskSpace()\n");
932
933#ifdef DUMP_PARTITION_LIST
934 DumpPartitionList(DiskEntry);
935#endif
936
937 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
938 {
939 DPRINT("No partitions!\n");
940
941 /* Create a partition table that represents the empty disk */
942 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
943 HEAP_ZERO_MEMORY,
944 sizeof(PARTENTRY));
945 if (NewPartEntry == NULL)
946 return;
947
948 NewPartEntry->DiskEntry = DiskEntry;
949
950 NewPartEntry->IsPartitioned = FALSE;
951 NewPartEntry->StartSector.QuadPart = DiskEntry->StartSector.QuadPart;
952 NewPartEntry->SectorCount.QuadPart = DiskEntry->EndSector.QuadPart - DiskEntry->StartSector.QuadPart + 1;
953
954 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
955 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
956 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
957
958 NewPartEntry->FormatState = Unformatted;
959
960 InsertTailList(&DiskEntry->PrimaryPartListHead,
961 &NewPartEntry->ListEntry);
962
963#ifdef DUMP_PARTITION_LIST
964 DumpPartitionList(DiskEntry);
965#endif
966
967 return;
968 }
969
970 /* Start at the first usable sector */
971 LastStartSector = DiskEntry->StartSector.QuadPart;
972 LastSectorCount = 0ULL;
973 LastUnusedSectorCount = 0ULL;
974
975 Entry = DiskEntry->PrimaryPartListHead.Flink;
976 while (Entry != &DiskEntry->PrimaryPartListHead)
977 {
978 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
979
980 if (!IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID) ||
981 PartEntry->SectorCount.QuadPart != 0ULL)
982 {
983 LastUnusedSectorCount =
984 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
985
986 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
987 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
988 {
989 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
990
991 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
992 HEAP_ZERO_MEMORY,
993 sizeof(PARTENTRY));
994 if (NewPartEntry == NULL)
995 return;
996
997 NewPartEntry->DiskEntry = DiskEntry;
998
999 NewPartEntry->IsPartitioned = FALSE;
1000 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
1001 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
1002 NewPartEntry->StartSector.QuadPart;
1003
1004 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
1005 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
1006 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
1007
1008 NewPartEntry->FormatState = Unformatted;
1009
1010 /* Insert the table into the list */
1011 InsertTailList(&PartEntry->ListEntry,
1012 &NewPartEntry->ListEntry);
1013 }
1014
1015 LastStartSector = PartEntry->StartSector.QuadPart;
1016 LastSectorCount = PartEntry->SectorCount.QuadPart;
1017 }
1018
1019 Entry = Entry->Flink;
1020 }
1021
1022 /* Check for trailing unpartitioned disk space */
1023 if ((LastStartSector + LastSectorCount) < DiskEntry->EndSector.QuadPart + 1)
1024 {
1025 LastUnusedSectorCount = AlignDown(DiskEntry->EndSector.QuadPart + 1 - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1026
1027 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1028 {
1029 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1030
1031 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
1032 HEAP_ZERO_MEMORY,
1033 sizeof(PARTENTRY));
1034 if (NewPartEntry == NULL)
1035 return;
1036
1037 NewPartEntry->DiskEntry = DiskEntry;
1038
1039 NewPartEntry->IsPartitioned = FALSE;
1040 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
1041 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
1042 NewPartEntry->StartSector.QuadPart;
1043
1044 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
1045 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
1046 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
1047
1048 NewPartEntry->FormatState = Unformatted;
1049
1050 /* Append the table to the list */
1051 InsertTailList(&DiskEntry->PrimaryPartListHead,
1052 &NewPartEntry->ListEntry);
1053 }
1054 }
1055
1056#ifdef DUMP_PARTITION_LIST
1057 DumpPartitionList(DiskEntry);
1058#endif
1059
1060 DPRINT("ScanForUnpartitionedGptDiskSpace() done\n");
1061}
1062
1063
1064VOID
1065ReadLayoutBuffer(
1066 _In_ HANDLE FileHandle,
1067 _In_ PDISKENTRY DiskEntry)
1068{
1069 ULONG LayoutBufferSize;
1070 PDRIVE_LAYOUT_INFORMATION_EX NewLayoutBuffer;
1071 IO_STATUS_BLOCK Iosb;
1072 NTSTATUS Status;
1073
1074 /* Allocate a layout buffer with 4 partition entries first */
1075 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
1076 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX));
1077 DiskEntry->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
1078 HEAP_ZERO_MEMORY,
1079 LayoutBufferSize);
1080 if (DiskEntry->LayoutBuffer == NULL)
1081 {
1082 DPRINT1("Failed to allocate the disk layout buffer!\n");
1083 return;
1084 }
1085
1086 for (;;)
1087 {
1088 DPRINT("Buffer size: %lu\n", LayoutBufferSize);
1089 Status = NtDeviceIoControlFile(FileHandle,
1090 NULL,
1091 NULL,
1092 NULL,
1093 &Iosb,
1094 IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
1095 NULL,
1096 0,
1097 DiskEntry->LayoutBuffer,
1098 LayoutBufferSize);
1099 if (NT_SUCCESS(Status))
1100 break;
1101
1102 if (Status != STATUS_BUFFER_TOO_SMALL)
1103 {
1104 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1105 return;
1106 }
1107
1108 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION_EX);
1109 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(),
1110 HEAP_ZERO_MEMORY,
1111 DiskEntry->LayoutBuffer,
1112 LayoutBufferSize);
1113 if (NewLayoutBuffer == NULL)
1114 {
1115 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1116 return;
1117 }
1118
1119 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1120 }
1121}
1122
1123
1124static
1125VOID
1126AddDiskToList(
1127 HANDLE FileHandle,
1128 ULONG DiskNumber)
1129{
1130 DISK_GEOMETRY DiskGeometry;
1131 SCSI_ADDRESS ScsiAddress;
1132 PDISKENTRY DiskEntry;
1133 IO_STATUS_BLOCK Iosb;
1134 NTSTATUS Status;
1135 PPARTITION_SECTOR Mbr;
1136 PULONG Buffer;
1137 LARGE_INTEGER FileOffset;
1138 WCHAR Identifier[20];
1139 ULONG Checksum;
1140 ULONG Signature;
1141 ULONG i;
1142 PLIST_ENTRY ListEntry;
1143 PBIOSDISKENTRY BiosDiskEntry;
1144
1145 Status = NtDeviceIoControlFile(FileHandle,
1146 NULL,
1147 NULL,
1148 NULL,
1149 &Iosb,
1150 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1151 NULL,
1152 0,
1153 &DiskGeometry,
1154 sizeof(DISK_GEOMETRY));
1155 if (!NT_SUCCESS(Status))
1156 {
1157 return;
1158 }
1159
1160 if (DiskGeometry.MediaType != FixedMedia &&
1161 DiskGeometry.MediaType != RemovableMedia)
1162 {
1163 return;
1164 }
1165
1166 Status = NtDeviceIoControlFile(FileHandle,
1167 NULL,
1168 NULL,
1169 NULL,
1170 &Iosb,
1171 IOCTL_SCSI_GET_ADDRESS,
1172 NULL,
1173 0,
1174 &ScsiAddress,
1175 sizeof(SCSI_ADDRESS));
1176 if (!NT_SUCCESS(Status))
1177 {
1178 return;
1179 }
1180
1181 PBYTE pBuffer = NULL;
1182
1183 pBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
1184 HEAP_ZERO_MEMORY,
1185 1024);
1186
1187 STORAGE_PROPERTY_QUERY StoragePropertyQuery;
1188 StoragePropertyQuery.PropertyId = StorageDeviceProperty;
1189 StoragePropertyQuery.QueryType = PropertyStandardQuery;
1190 Status = NtDeviceIoControlFile(FileHandle,
1191 NULL,
1192 NULL,
1193 NULL,
1194 &Iosb,
1195 IOCTL_STORAGE_QUERY_PROPERTY,
1196 &StoragePropertyQuery,
1197 sizeof(STORAGE_PROPERTY_QUERY),
1198 pBuffer,
1199 1024);
1200 if (!NT_SUCCESS(Status))
1201 {
1202 RtlFreeHeap(RtlGetProcessHeap(), 0, pBuffer);
1203 pBuffer = NULL;
1204 }
1205
1206
1207 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(RtlGetProcessHeap(),
1208 0,
1209 DiskGeometry.BytesPerSector);
1210 if (Mbr == NULL)
1211 {
1212 return;
1213 }
1214
1215 FileOffset.QuadPart = 0;
1216 Status = NtReadFile(FileHandle,
1217 NULL,
1218 NULL,
1219 NULL,
1220 &Iosb,
1221 (PVOID)Mbr,
1222 DiskGeometry.BytesPerSector,
1223 &FileOffset,
1224 NULL);
1225 if (!NT_SUCCESS(Status))
1226 {
1227 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
1228 DPRINT1("NtReadFile failed, status=%x\n", Status);
1229 return;
1230 }
1231 Signature = Mbr->Signature;
1232
1233 /* Calculate the MBR checksum */
1234 Checksum = 0;
1235 Buffer = (PULONG)Mbr;
1236 for (i = 0; i < 128; i++)
1237 {
1238 Checksum += Buffer[i];
1239 }
1240 Checksum = ~Checksum + 1;
1241
1242 StringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1243 L"%08x-%08x-A", Checksum, Signature);
1244 DPRINT("Identifier: %S\n", Identifier);
1245
1246 DiskEntry = RtlAllocateHeap(RtlGetProcessHeap(),
1247 HEAP_ZERO_MEMORY,
1248 sizeof(DISKENTRY));
1249 if (DiskEntry == NULL)
1250 {
1251 if (pBuffer)
1252 RtlFreeHeap(RtlGetProcessHeap(), 0, pBuffer);
1253 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
1254 return;
1255 }
1256
1257 if (pBuffer)
1258 {
1259 PSTORAGE_DESCRIPTOR_HEADER pDescriptorHeader;
1260
1261 pDescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)pBuffer;
1262 DPRINT("DescriptorHeader.Size %lu\n", pDescriptorHeader->Size);
1263
1264 if (pDescriptorHeader->Size <= 1024)
1265 {
1266 PSTORAGE_DEVICE_DESCRIPTOR pDeviceDescriptor;
1267 pDeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)pBuffer;
1268 DPRINT("VendorIdOffset %lu\n", pDeviceDescriptor->VendorIdOffset);
1269 DPRINT("ProductIdOffset %lu\n", pDeviceDescriptor->ProductIdOffset);
1270 DPRINT("ProductRevisionOffset %lu\n", pDeviceDescriptor->ProductRevisionOffset);
1271 DPRINT("SerialNumberOffset %lu\n", pDeviceDescriptor->SerialNumberOffset);
1272 DPRINT("BusType: %u\n", pDeviceDescriptor->BusType);
1273 if (pDeviceDescriptor->VendorIdOffset)
1274 {
1275 DPRINT("Vendor: %s\n", (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->VendorIdOffset));
1276 }
1277
1278 if (pDeviceDescriptor->ProductIdOffset)
1279 {
1280 DPRINT("Product: %s\n", (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->ProductIdOffset));
1281 }
1282
1283 INT VendorLength = 0, ProductLength = 0;
1284 PWSTR VendorBuffer = NULL, ProductBuffer = NULL;
1285
1286 if (pDeviceDescriptor->VendorIdOffset)
1287 {
1288 VendorLength = MultiByteToWideChar(437,
1289 0,
1290 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->VendorIdOffset),
1291 -1,
1292 NULL,
1293 0);
1294 VendorBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
1295 HEAP_ZERO_MEMORY,
1296 VendorLength * sizeof(WCHAR));
1297 if (VendorBuffer)
1298 MultiByteToWideChar(437,
1299 0,
1300 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->VendorIdOffset),
1301 -1,
1302 VendorBuffer,
1303 VendorLength);
1304 }
1305
1306 if (pDeviceDescriptor->ProductIdOffset)
1307 {
1308 ProductLength = MultiByteToWideChar(437,
1309 0,
1310 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->ProductIdOffset),
1311 -1,
1312 NULL,
1313 0);
1314
1315 ProductBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
1316 HEAP_ZERO_MEMORY,
1317 ProductLength * sizeof(WCHAR));
1318 if (ProductBuffer)
1319 MultiByteToWideChar(437,
1320 0,
1321 (PSTR)((ULONG_PTR)pBuffer + pDeviceDescriptor->ProductIdOffset),
1322 -1,
1323 ProductBuffer,
1324 ProductLength);
1325 }
1326
1327 DiskEntry->Description = RtlAllocateHeap(RtlGetProcessHeap(),
1328 HEAP_ZERO_MEMORY,
1329 (VendorLength + ProductLength + 2) * sizeof(WCHAR));
1330 if (VendorBuffer)
1331 wcscat(DiskEntry->Description, VendorBuffer);
1332
1333 if ((VendorLength > 0) && (ProductLength > 0))
1334 wcscat(DiskEntry->Description, L" ");
1335
1336 if (ProductBuffer)
1337 wcscat(DiskEntry->Description, ProductBuffer);
1338
1339 DiskEntry->BusType = pDeviceDescriptor->BusType;
1340
1341 if (VendorBuffer)
1342 RtlFreeHeap(RtlGetProcessHeap(), 0, VendorBuffer);
1343
1344 if (ProductBuffer)
1345 RtlFreeHeap(RtlGetProcessHeap(), 0, ProductBuffer);
1346 }
1347
1348 RtlFreeHeap(RtlGetProcessHeap(), 0, pBuffer);
1349 }
1350
1351// DiskEntry->Checksum = Checksum;
1352// DiskEntry->Signature = Signature;
1353 DiskEntry->BiosFound = FALSE;
1354
1355 /* Check the disk partition style */
1356 if (Mbr->Magic != MBR_MAGIC)
1357 {
1358 DPRINT("Partition style: RAW\n");
1359 DiskEntry->PartitionStyle = PARTITION_STYLE_RAW;
1360 }
1361 else
1362 {
1363 if (Mbr->Partition[0].PartitionType == PARTITION_GPT)
1364 {
1365 DPRINT("Partition style: GPT\n");
1366 DiskEntry->PartitionStyle = PARTITION_STYLE_GPT;
1367 }
1368 else
1369 {
1370 DPRINT("Partition style: MBR\n");
1371 DiskEntry->PartitionStyle = PARTITION_STYLE_MBR;
1372 }
1373 }
1374
1375 /* Free Mbr sector buffer */
1376 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
1377
1378 ListEntry = BiosDiskListHead.Flink;
1379 while (ListEntry != &BiosDiskListHead)
1380 {
1381 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1382 /* FIXME:
1383 * Compare the size from bios and the reported size from driver.
1384 * If we have more than one disk with a zero or with the same signatur
1385 * we must create new signatures and reboot. After the reboot,
1386 * it is possible to identify the disks.
1387 */
1388 if (BiosDiskEntry->Signature == Signature &&
1389 BiosDiskEntry->Checksum == Checksum &&
1390 !BiosDiskEntry->Recognized)
1391 {
1392 if (!DiskEntry->BiosFound)
1393 {
1394 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1395 DiskEntry->BiosFound = TRUE;
1396 BiosDiskEntry->Recognized = TRUE;
1397 }
1398 else
1399 {
1400 }
1401 }
1402 ListEntry = ListEntry->Flink;
1403 }
1404
1405 if (!DiskEntry->BiosFound)
1406 {
1407#if 0
1408 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1409 return;
1410#else
1411 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1412#endif
1413 }
1414
1415 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1416 InitializeListHead(&DiskEntry->LogicalPartListHead);
1417
1418 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1419 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1420 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1421 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1422
1423 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1424 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder);
1425 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack);
1426 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector);
1427
1428 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1429 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1430 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1431
1432// DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1433// DiskEntry->CylinderAlignment = DiskGeometry.SectorsPerTrack * DiskGeometry.TracksPerCylinder;
1434 DiskEntry->SectorAlignment = (1024 * 1024) / DiskGeometry.BytesPerSector;
1435 DiskEntry->CylinderAlignment = (1024 * 1024) / DiskGeometry.BytesPerSector;
1436
1437 DPRINT("SectorCount: %I64u\n", DiskEntry->SectorCount);
1438 DPRINT("SectorAlignment: %lu\n", DiskEntry->SectorAlignment);
1439 DPRINT("CylinderAlignment: %lu\n", DiskEntry->CylinderAlignment);
1440
1441 DiskEntry->DiskNumber = DiskNumber;
1442 DiskEntry->Port = ScsiAddress.PortNumber;
1443 DiskEntry->PathId = ScsiAddress.PathId;
1444 DiskEntry->TargetId = ScsiAddress.TargetId;
1445 DiskEntry->Lun = ScsiAddress.Lun;
1446
1447 GetDriverName(DiskEntry);
1448
1449 InsertAscendingList(&DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1450
1451 ReadLayoutBuffer(FileHandle, DiskEntry);
1452
1453 DPRINT("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1454
1455#ifdef DUMP_PARTITION_TABLE
1456 DumpPartitionTable(DiskEntry);
1457#endif
1458
1459 if (DiskEntry->PartitionStyle == PARTITION_STYLE_MBR)
1460 {
1461 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1462 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1463 DiskEntry->LayoutBuffer->PartitionEntry[0].Mbr.PartitionType != 0)
1464 {
1465 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1466 {
1467 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1468 }
1469 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1470 {
1471 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1472 }
1473 else
1474 {
1475 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1476 }
1477 }
1478 else
1479 {
1480 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1481 }
1482
1483 /* Calculate the number of usable sectors */
1484 /* Limit the number of usable sectors to 2^32 */
1485 DiskEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
1486 DiskEntry->EndSector.QuadPart = min(DiskEntry->SectorCount.QuadPart, 0x100000000) - 1;
1487
1488 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1489 {
1490 DiskEntry->NewDisk = TRUE;
1491 DiskEntry->LayoutBuffer->PartitionCount = 4;
1492
1493 for (i = 0; i < 4; i++)
1494 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1495 }
1496 else
1497 {
1498 for (i = 0; i < 4; i++)
1499 {
1500 AddMbrPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1501 }
1502
1503 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1504 {
1505 AddMbrPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1506 }
1507 }
1508
1509 ScanForUnpartitionedMbrDiskSpace(DiskEntry);
1510 }
1511 else if (DiskEntry->PartitionStyle == PARTITION_STYLE_GPT)
1512 {
1513 /* Calculate the number of usable sectors */
1514 DiskEntry->StartSector.QuadPart = AlignDown(DiskEntry->LayoutBuffer->Gpt.StartingUsableOffset.QuadPart / DiskEntry->BytesPerSector,
1515 DiskEntry->SectorAlignment) + (ULONGLONG)DiskEntry->SectorAlignment;
1516 DiskEntry->EndSector.QuadPart = AlignDown(DiskEntry->StartSector.QuadPart + (DiskEntry->LayoutBuffer->Gpt.UsableLength.QuadPart / DiskEntry->BytesPerSector) - 1,
1517 DiskEntry->SectorAlignment);
1518
1519 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1520 {
1521 DiskEntry->NewDisk = TRUE;
1522 }
1523 else
1524 {
1525 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
1526 {
1527 AddGptPartitionToDisk(DiskNumber, DiskEntry, i);
1528 }
1529 }
1530
1531 ScanForUnpartitionedGptDiskSpace(DiskEntry);
1532 }
1533}
1534
1535
1536NTSTATUS
1537CreatePartitionList(VOID)
1538{
1539 OBJECT_ATTRIBUTES ObjectAttributes;
1540 SYSTEM_DEVICE_INFORMATION Sdi;
1541 IO_STATUS_BLOCK Iosb;
1542 ULONG ReturnSize;
1543 NTSTATUS Status;
1544 ULONG DiskNumber;
1545 WCHAR Buffer[MAX_PATH];
1546 UNICODE_STRING Name;
1547 HANDLE FileHandle;
1548
1549 CurrentDisk = NULL;
1550 CurrentPartition = NULL;
1551
1552// BootDisk = NULL;
1553// BootPartition = NULL;
1554
1555// TempDisk = NULL;
1556// TempPartition = NULL;
1557// FormatState = Start;
1558
1559 InitializeListHead(&DiskListHead);
1560 InitializeListHead(&BiosDiskListHead);
1561
1562 EnumerateBiosDiskEntries();
1563
1564 Status = NtQuerySystemInformation(SystemDeviceInformation,
1565 &Sdi,
1566 sizeof(SYSTEM_DEVICE_INFORMATION),
1567 &ReturnSize);
1568 if (!NT_SUCCESS(Status))
1569 {
1570 return Status;
1571 }
1572
1573 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1574 {
1575 StringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
1576 L"\\Device\\Harddisk%d\\Partition0",
1577 DiskNumber);
1578
1579 RtlInitUnicodeString(&Name,
1580 Buffer);
1581
1582 InitializeObjectAttributes(&ObjectAttributes,
1583 &Name,
1584 0,
1585 NULL,
1586 NULL);
1587
1588 Status = NtOpenFile(&FileHandle,
1589 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1590 &ObjectAttributes,
1591 &Iosb,
1592 FILE_SHARE_READ,
1593 FILE_SYNCHRONOUS_IO_NONALERT);
1594 if (NT_SUCCESS(Status))
1595 {
1596 AddDiskToList(FileHandle, DiskNumber);
1597
1598 NtClose(FileHandle);
1599 }
1600 }
1601
1602// UpdateDiskSignatures(List);
1603
1604// AssignDriveLetters(List);
1605
1606 return STATUS_SUCCESS;
1607}
1608
1609
1610VOID
1611DestroyPartitionList(VOID)
1612{
1613 PDISKENTRY DiskEntry;
1614 PBIOSDISKENTRY BiosDiskEntry;
1615 PPARTENTRY PartEntry;
1616 PLIST_ENTRY Entry;
1617
1618 CurrentDisk = NULL;
1619 CurrentPartition = NULL;
1620
1621 /* Release disk and partition info */
1622 while (!IsListEmpty(&DiskListHead))
1623 {
1624 Entry = RemoveHeadList(&DiskListHead);
1625 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1626
1627 /* Release driver name */
1628 RtlFreeUnicodeString(&DiskEntry->DriverName);
1629
1630 /* Release primary partition list */
1631 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1632 {
1633 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1634 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1635
1636 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
1637 }
1638
1639 /* Release logical partition list */
1640 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1641 {
1642 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1643 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1644
1645 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
1646 }
1647
1648 /* Release layout buffer */
1649 if (DiskEntry->LayoutBuffer != NULL)
1650 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->LayoutBuffer);
1651
1652 if (DiskEntry->Description != NULL)
1653 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->Description);
1654
1655 if (DiskEntry->Location != NULL)
1656 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->Location);
1657
1658 /* Release disk entry */
1659 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry);
1660 }
1661
1662 /* Release the bios disk info */
1663 while (!IsListEmpty(&BiosDiskListHead))
1664 {
1665 Entry = RemoveHeadList(&BiosDiskListHead);
1666 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1667
1668 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry);
1669 }
1670}
1671
1672
1673static
1674VOID
1675GetVolumeExtents(
1676 _In_ HANDLE VolumeHandle,
1677 _In_ PVOLENTRY VolumeEntry)
1678{
1679 DWORD dwBytesReturned = 0, dwLength, i;
1680 PVOLUME_DISK_EXTENTS pExtents;
1681 BOOL bResult;
1682 DWORD dwError;
1683
1684 dwLength = sizeof(VOLUME_DISK_EXTENTS);
1685 pExtents = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
1686 if (pExtents == NULL)
1687 return;
1688
1689 bResult = DeviceIoControl(VolumeHandle,
1690 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
1691 NULL,
1692 0,
1693 pExtents,
1694 dwLength,
1695 &dwBytesReturned,
1696 NULL);
1697 if (!bResult)
1698 {
1699 dwError = GetLastError();
1700
1701 if (dwError != ERROR_MORE_DATA)
1702 {
1703 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents);
1704 return;
1705 }
1706 else
1707 {
1708 dwLength = sizeof(VOLUME_DISK_EXTENTS) + ((pExtents->NumberOfDiskExtents - 1) * sizeof(DISK_EXTENT));
1709 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents);
1710 pExtents = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
1711 if (pExtents == NULL)
1712 {
1713 return;
1714 }
1715
1716 bResult = DeviceIoControl(VolumeHandle,
1717 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
1718 NULL,
1719 0,
1720 pExtents,
1721 dwLength,
1722 &dwBytesReturned,
1723 NULL);
1724 if (!bResult)
1725 {
1726 RtlFreeHeap(RtlGetProcessHeap(), 0, pExtents);
1727 return;
1728 }
1729 }
1730 }
1731
1732 for (i = 0; i < pExtents->NumberOfDiskExtents; i++)
1733 VolumeEntry->Size.QuadPart += pExtents->Extents[i].ExtentLength.QuadPart;
1734
1735 VolumeEntry->pExtents = pExtents;
1736}
1737
1738
1739static
1740VOID
1741GetVolumeType(
1742 _In_ HANDLE VolumeHandle,
1743 _In_ PVOLENTRY VolumeEntry)
1744{
1745 FILE_FS_DEVICE_INFORMATION DeviceInfo;
1746 IO_STATUS_BLOCK IoStatusBlock;
1747 NTSTATUS Status;
1748
1749 Status = NtQueryVolumeInformationFile(VolumeHandle,
1750 &IoStatusBlock,
1751 &DeviceInfo,
1752 sizeof(FILE_FS_DEVICE_INFORMATION),
1753 FileFsDeviceInformation);
1754 if (!NT_SUCCESS(Status))
1755 return;
1756
1757 switch (DeviceInfo.DeviceType)
1758 {
1759 case FILE_DEVICE_CD_ROM:
1760 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
1761 VolumeEntry->VolumeType = VOLUME_TYPE_CDROM;
1762 break;
1763
1764 case FILE_DEVICE_DISK:
1765 case FILE_DEVICE_DISK_FILE_SYSTEM:
1766 if (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA)
1767 VolumeEntry->VolumeType = VOLUME_TYPE_REMOVABLE;
1768 else
1769 VolumeEntry->VolumeType = VOLUME_TYPE_PARTITION;
1770 break;
1771
1772 default:
1773 VolumeEntry->VolumeType = VOLUME_TYPE_UNKNOWN;
1774 break;
1775 }
1776}
1777
1778
1779static
1780VOID
1781GetVolumeSize(
1782 _In_ HANDLE VolumeHandle,
1783 _In_ PVOLENTRY VolumeEntry)
1784{
1785 FILE_FS_FULL_SIZE_INFORMATION SizeInfo;
1786 FILE_FS_FULL_SIZE_INFORMATION FullSizeInfo;
1787 IO_STATUS_BLOCK IoStatusBlock;
1788 NTSTATUS Status;
1789
1790 ZeroMemory(&FullSizeInfo, sizeof(FullSizeInfo));
1791 Status = NtQueryVolumeInformationFile(VolumeHandle,
1792 &IoStatusBlock,
1793 &FullSizeInfo,
1794 sizeof(FILE_FS_FULL_SIZE_INFORMATION),
1795 FileFsFullSizeInformation);
1796 if (NT_SUCCESS(Status))
1797 {
1798 DPRINT("FullSizeInfo.TotalAllocationUnits %I64u\n", FullSizeInfo.TotalAllocationUnits.QuadPart);
1799 DPRINT("FullSizeInfo.SectorsPerAllocationUnit %lu\n", FullSizeInfo.SectorsPerAllocationUnit);
1800 DPRINT("FullSizeInfo.BytesPerSector %lu\n", FullSizeInfo.BytesPerSector);
1801
1802 VolumeEntry->TotalAllocationUnits.QuadPart = FullSizeInfo.TotalAllocationUnits.QuadPart;
1803 VolumeEntry->SectorsPerAllocationUnit = FullSizeInfo.SectorsPerAllocationUnit;
1804 VolumeEntry->BytesPerSector = FullSizeInfo.BytesPerSector;
1805 }
1806 else
1807 {
1808 ZeroMemory(&SizeInfo, sizeof(SizeInfo));
1809 Status = NtQueryVolumeInformationFile(VolumeHandle,
1810 &IoStatusBlock,
1811 &SizeInfo,
1812 sizeof(FILE_FS_SIZE_INFORMATION),
1813 FileFsSizeInformation);
1814 if (NT_SUCCESS(Status))
1815 {
1816 DPRINT("SizeInfo.TotalAllocationUnits %I64u\n", SizeInfo.TotalAllocationUnits.QuadPart);
1817 DPRINT("SizeInfo.SectorsPerAllocationUnit %lu\n", SizeInfo.SectorsPerAllocationUnit);
1818 DPRINT("SizeInfo.BytesPerSector %lu\n", SizeInfo.BytesPerSector);
1819
1820 VolumeEntry->TotalAllocationUnits.QuadPart = SizeInfo.TotalAllocationUnits.QuadPart;
1821 VolumeEntry->SectorsPerAllocationUnit = SizeInfo.SectorsPerAllocationUnit;
1822 VolumeEntry->BytesPerSector = SizeInfo.BytesPerSector;
1823 }
1824 else
1825 {
1826 DPRINT("GetVolumeSize() failed!\n");
1827 }
1828 }
1829}
1830
1831
1832static
1833PDISKENTRY
1834GetDiskForVolume(
1835 _In_ PVOLENTRY VolumeEntry)
1836{
1837 PLIST_ENTRY Entry;
1838 PDISKENTRY DiskEntry;
1839 INT i;
1840
1841 DPRINT("GetDiskFromVolume(%p)\n", VolumeEntry);
1842
1843 DPRINT("Extents: %p\n", VolumeEntry->pExtents);
1844 if (VolumeEntry->pExtents == NULL)
1845 return NULL;
1846
1847 DPRINT("Extents: %lu\n", VolumeEntry->pExtents->NumberOfDiskExtents);
1848
1849 Entry = DiskListHead.Flink;
1850 while (Entry != &DiskListHead)
1851 {
1852 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1853
1854 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++)
1855 {
1856 DPRINT("DiskNumber: %lu -- %lu\n", VolumeEntry->pExtents->Extents[i].DiskNumber, DiskEntry->DiskNumber);
1857 if (VolumeEntry->pExtents->Extents[i].DiskNumber == DiskEntry->DiskNumber)
1858 return DiskEntry;
1859 }
1860
1861 Entry = Entry->Flink;
1862 }
1863
1864 return NULL;
1865}
1866
1867
1868static
1869PPARTENTRY
1870GetPartitionForVolume(
1871 _In_ PVOLENTRY VolumeEntry)
1872{
1873 PLIST_ENTRY Entry1, Entry2;
1874 PDISKENTRY DiskEntry;
1875 PPARTENTRY PartEntry;
1876 INT i;
1877
1878 DPRINT("GetPartitionFromVolume(%p)\n", VolumeEntry);
1879
1880 DPRINT("Extents: %p\n", VolumeEntry->pExtents);
1881 if (VolumeEntry->pExtents == NULL)
1882 return NULL;
1883
1884 DPRINT("Extents: %lu\n", VolumeEntry->pExtents->NumberOfDiskExtents);
1885
1886 Entry1 = DiskListHead.Flink;
1887 while (Entry1 != &DiskListHead)
1888 {
1889 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
1890
1891 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++)
1892 {
1893 DPRINT("DiskNumber: %lu -- %lu\n", VolumeEntry->pExtents->Extents[i].DiskNumber, DiskEntry->DiskNumber);
1894 if (VolumeEntry->pExtents->Extents[i].DiskNumber == DiskEntry->DiskNumber)
1895 {
1896
1897 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
1898 while (Entry2 != &DiskEntry->PrimaryPartListHead)
1899 {
1900 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1901
1902 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) &&
1903 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector))
1904 return PartEntry;
1905
1906 Entry2 = Entry2->Flink;
1907 }
1908
1909 Entry2 = DiskEntry->LogicalPartListHead.Flink;
1910 while (Entry2 != &DiskEntry->LogicalPartListHead)
1911 {
1912 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
1913
1914 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) &&
1915 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector))
1916 return PartEntry;
1917
1918 Entry2 = Entry2->Flink;
1919 }
1920 }
1921 }
1922
1923 Entry1 = Entry1->Flink;
1924 }
1925
1926 return NULL;
1927}
1928
1929
1930static
1931VOID
1932IsVolumeSystem(
1933 _In_ PVOLENTRY VolumeEntry)
1934{
1935 WCHAR szSystemPartition[MAX_PATH];
1936 PPARTENTRY PartEntry;
1937 HKEY hKey;
1938 DWORD dwError, dwLength;
1939
1940 DPRINT("IsVolumeSystem()\n");
1941
1942 VolumeEntry->IsSystem = FALSE;
1943
1944 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1945 L"SYSTEM\\Setup",
1946 0,
1947 KEY_READ,
1948 &hKey);
1949 if (dwError != ERROR_SUCCESS)
1950 {
1951 DPRINT1("\n");
1952 return;
1953 }
1954
1955 dwLength = sizeof(szSystemPartition);
1956 dwError = RegQueryValueExW(hKey,
1957 L"SystemPartition",
1958 NULL,
1959 NULL,
1960 (PBYTE)szSystemPartition,
1961 &dwLength);
1962 RegCloseKey(hKey);
1963
1964 if (dwError != ERROR_SUCCESS)
1965 {
1966 DPRINT1("\n");
1967 return;
1968 }
1969
1970 DPRINT("SystemPartition: %S\n", szSystemPartition);
1971 DPRINT("DeviceName: %S\n", VolumeEntry->DeviceName);
1972
1973 if (_wcsnicmp(szSystemPartition, VolumeEntry->DeviceName, wcslen(szSystemPartition)) == 0)
1974 {
1975 VolumeEntry->IsSystem = TRUE;
1976
1977 PartEntry = GetPartitionForVolume(VolumeEntry);
1978 if (PartEntry)
1979 PartEntry->IsSystem = TRUE;
1980 }
1981}
1982
1983
1984static
1985VOID
1986IsVolumeBoot(
1987 _In_ PVOLENTRY VolumeEntry)
1988{
1989 WCHAR szSystemDir[MAX_PATH];
1990 PDISKENTRY DiskEntry;
1991 PPARTENTRY PartEntry;
1992
1993 DPRINT("IsVolumeBoot()\n");
1994
1995 VolumeEntry->IsBoot = FALSE;
1996
1997 if (VolumeEntry->DriveLetter == UNICODE_NULL)
1998 return;
1999
2000 GetSystemDirectoryW(szSystemDir,
2001 ARRAYSIZE(szSystemDir));
2002
2003 DPRINT("SystemDirectory: %S\n", szSystemDir);
2004 DPRINT("DriveLetter: %C\n", VolumeEntry->DriveLetter);
2005
2006 if (szSystemDir[0] == VolumeEntry->DriveLetter)
2007 {
2008 VolumeEntry->IsBoot = TRUE;
2009
2010 PartEntry = GetPartitionForVolume(VolumeEntry);
2011 if (PartEntry)
2012 PartEntry->IsBoot = TRUE;
2013
2014 DiskEntry = GetDiskForVolume(VolumeEntry);
2015 if (DiskEntry)
2016 DiskEntry->IsBoot = TRUE;
2017 }
2018}
2019
2020
2021static
2022VOID
2023AddVolumeToList(
2024 ULONG ulVolumeNumber,
2025 PWSTR pszVolumeName)
2026{
2027 PVOLENTRY VolumeEntry;
2028 HANDLE VolumeHandle;
2029
2030 DWORD dwError, dwLength;
2031 WCHAR szPathNames[MAX_PATH + 1];
2032 WCHAR szVolumeName[MAX_PATH + 1];
2033 WCHAR szFilesystem[MAX_PATH + 1];
2034
2035 DWORD CharCount = 0;
2036 size_t Index = 0;
2037
2038 OBJECT_ATTRIBUTES ObjectAttributes;
2039 UNICODE_STRING Name;
2040 IO_STATUS_BLOCK Iosb;
2041 NTSTATUS Status;
2042
2043 DPRINT("AddVolumeToList(%S)\n", pszVolumeName);
2044
2045 VolumeEntry = RtlAllocateHeap(RtlGetProcessHeap(),
2046 HEAP_ZERO_MEMORY,
2047 sizeof(VOLENTRY));
2048 if (VolumeEntry == NULL)
2049 return;
2050
2051 VolumeEntry->VolumeNumber = ulVolumeNumber;
2052 wcscpy(VolumeEntry->VolumeName, pszVolumeName);
2053
2054 Index = wcslen(pszVolumeName) - 1;
2055
2056 pszVolumeName[Index] = L'\0';
2057
2058 CharCount = QueryDosDeviceW(&pszVolumeName[4], VolumeEntry->DeviceName, ARRAYSIZE(VolumeEntry->DeviceName));
2059
2060 pszVolumeName[Index] = L'\\';
2061
2062 if (CharCount == 0)
2063 {
2064 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry);
2065 return;
2066 }
2067
2068 DPRINT("DeviceName: %S\n", VolumeEntry->DeviceName);
2069
2070 RtlInitUnicodeString(&Name, VolumeEntry->DeviceName);
2071
2072 InitializeObjectAttributes(&ObjectAttributes,
2073 &Name,
2074 0,
2075 NULL,
2076 NULL);
2077
2078 Status = NtOpenFile(&VolumeHandle,
2079 SYNCHRONIZE,
2080 &ObjectAttributes,
2081 &Iosb,
2082 0,
2083 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
2084 if (NT_SUCCESS(Status))
2085 {
2086 GetVolumeType(VolumeHandle, VolumeEntry);
2087 GetVolumeExtents(VolumeHandle, VolumeEntry);
2088 GetVolumeSize(VolumeHandle, VolumeEntry);
2089 NtClose(VolumeHandle);
2090 }
2091
2092 if (GetVolumeInformationW(pszVolumeName,
2093 szVolumeName,
2094 MAX_PATH + 1,
2095 &VolumeEntry->SerialNumber,
2096 NULL,
2097 NULL,
2098 szFilesystem,
2099 MAX_PATH + 1))
2100 {
2101 VolumeEntry->pszLabel = RtlAllocateHeap(RtlGetProcessHeap(),
2102 0,
2103 (wcslen(szVolumeName) + 1) * sizeof(WCHAR));
2104 if (VolumeEntry->pszLabel)
2105 wcscpy(VolumeEntry->pszLabel, szVolumeName);
2106
2107 VolumeEntry->pszFilesystem = RtlAllocateHeap(RtlGetProcessHeap(),
2108 0,
2109 (wcslen(szFilesystem) + 1) * sizeof(WCHAR));
2110 if (VolumeEntry->pszFilesystem)
2111 wcscpy(VolumeEntry->pszFilesystem, szFilesystem);
2112 }
2113 else
2114 {
2115 dwError = GetLastError();
2116 if (dwError == ERROR_UNRECOGNIZED_VOLUME)
2117 {
2118 VolumeEntry->pszFilesystem = RtlAllocateHeap(RtlGetProcessHeap(),
2119 0,
2120 (3 + 1) * sizeof(WCHAR));
2121 if (VolumeEntry->pszFilesystem)
2122 wcscpy(VolumeEntry->pszFilesystem, L"RAW");
2123 VolumeEntry->SerialNumber = 0;
2124 VolumeEntry->SectorsPerAllocationUnit = 1;
2125 VolumeEntry->BytesPerSector = 512;
2126 VolumeEntry->VolumeType = VOLUME_TYPE_PARTITION;
2127 }
2128 }
2129
2130 if (GetVolumePathNamesForVolumeNameW(pszVolumeName,
2131 szPathNames,
2132 ARRAYSIZE(szPathNames),
2133 &dwLength))
2134 {
2135 INT nPathLength;
2136 PWSTR pszPath = szPathNames;
2137 while (*pszPath != UNICODE_NULL)
2138 {
2139 DPRINT("PathName: %S\n", pszPath);
2140 nPathLength = wcslen(pszPath);
2141 if ((nPathLength == 3) && (iswalpha(pszPath[0])) &&
2142 (pszPath[1] == L':') && (pszPath[2] == L'\\'))
2143 VolumeEntry->DriveLetter = pszPath[0];
2144
2145 pszPath += (nPathLength + 1);
2146 }
2147 }
2148
2149 IsVolumeSystem(VolumeEntry);
2150 IsVolumeBoot(VolumeEntry);
2151
2152 InsertTailList(&VolumeListHead,
2153 &VolumeEntry->ListEntry);
2154}
2155
2156
2157NTSTATUS
2158CreateVolumeList(VOID)
2159{
2160 HANDLE hVolume = INVALID_HANDLE_VALUE;
2161 WCHAR szVolumeName[MAX_PATH];
2162 ULONG ulVolumeNumber = 0;
2163 BOOL Success;
2164
2165 CurrentVolume = NULL;
2166
2167 InitializeListHead(&VolumeListHead);
2168
2169 hVolume = FindFirstVolumeW(szVolumeName, ARRAYSIZE(szVolumeName));
2170 if (hVolume == INVALID_HANDLE_VALUE)
2171 {
2172
2173 return STATUS_UNSUCCESSFUL;
2174 }
2175
2176 AddVolumeToList(ulVolumeNumber++, szVolumeName);
2177
2178 for (;;)
2179 {
2180 Success = FindNextVolumeW(hVolume, szVolumeName, ARRAYSIZE(szVolumeName));
2181 if (!Success)
2182 {
2183 break;
2184 }
2185
2186 AddVolumeToList(ulVolumeNumber++, szVolumeName);
2187 }
2188
2189 FindVolumeClose(hVolume);
2190
2191 return STATUS_SUCCESS;
2192}
2193
2194
2195VOID
2196DestroyVolumeList(VOID)
2197{
2198 PLIST_ENTRY Entry;
2199 PVOLENTRY VolumeEntry;
2200
2201 CurrentVolume = NULL;
2202
2203 /* Release disk and partition info */
2204 while (!IsListEmpty(&VolumeListHead))
2205 {
2206 Entry = RemoveHeadList(&VolumeListHead);
2207 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
2208
2209 if (VolumeEntry->pszLabel)
2210 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszLabel);
2211
2212 if (VolumeEntry->pszFilesystem)
2213 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszFilesystem);
2214
2215 if (VolumeEntry->pExtents)
2216 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pExtents);
2217
2218 /* Release disk entry */
2219 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry);
2220 }
2221}
2222
2223
2224NTSTATUS
2225WriteMbrPartitions(
2226 _In_ PDISKENTRY DiskEntry)
2227{
2228 NTSTATUS Status;
2229 OBJECT_ATTRIBUTES ObjectAttributes;
2230 UNICODE_STRING Name;
2231 HANDLE FileHandle;
2232 IO_STATUS_BLOCK Iosb;
2233 ULONG BufferSize;
2234 PPARTITION_INFORMATION_EX PartitionInfo;
2235 ULONG PartitionCount;
2236 PLIST_ENTRY ListEntry;
2237 PPARTENTRY PartEntry;
2238 WCHAR DstPath[MAX_PATH];
2239
2240 DPRINT("WriteMbrPartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2241
2242 /* If the disk is not dirty, there is nothing to do */
2243 if (!DiskEntry->Dirty)
2244 return STATUS_SUCCESS;
2245
2246 StringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
2247 L"\\Device\\Harddisk%lu\\Partition0",
2248 DiskEntry->DiskNumber);
2249 RtlInitUnicodeString(&Name, DstPath);
2250
2251 InitializeObjectAttributes(&ObjectAttributes,
2252 &Name,
2253 OBJ_CASE_INSENSITIVE,
2254 NULL,
2255 NULL);
2256
2257 Status = NtOpenFile(&FileHandle,
2258 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2259 &ObjectAttributes,
2260 &Iosb,
2261 0,
2262 FILE_SYNCHRONOUS_IO_NONALERT);
2263 if (!NT_SUCCESS(Status))
2264 {
2265 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2266 return Status;
2267 }
2268
2269 //
2270 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
2271 // the disk in MBR or GPT format in case the disk was not initialized!!
2272 // For this we must ask the user which format to use.
2273 //
2274
2275 /* Save the original partition count to be restored later (see comment below) */
2276 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2277
2278 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
2279 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
2280 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX));
2281 Status = NtDeviceIoControlFile(FileHandle,
2282 NULL,
2283 NULL,
2284 NULL,
2285 &Iosb,
2286 IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
2287 DiskEntry->LayoutBuffer,
2288 BufferSize,
2289 DiskEntry->LayoutBuffer,
2290 BufferSize);
2291 NtClose(FileHandle);
2292
2293 /*
2294 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
2295 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
2296 * where such a table is expected to enumerate up to 4 partitions:
2297 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
2298 * Due to this we need to restore the original PartitionCount number.
2299 */
2300 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
2301
2302 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
2303 if (!NT_SUCCESS(Status))
2304 {
2305 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
2306 return Status;
2307 }
2308
2309 /* Update the partition numbers */
2310
2311 /* Update the primary partition table */
2312 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2313 ListEntry != &DiskEntry->PrimaryPartListHead;
2314 ListEntry = ListEntry->Flink)
2315 {
2316 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2317
2318 if (PartEntry->IsPartitioned)
2319 {
2320 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED);
2321 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
2322 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
2323 }
2324 }
2325
2326 /* Update the logical partition table */
2327 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2328 ListEntry != &DiskEntry->LogicalPartListHead;
2329 ListEntry = ListEntry->Flink)
2330 {
2331 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2332
2333 if (PartEntry->IsPartitioned)
2334 {
2335 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED);
2336 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
2337 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
2338 }
2339 }
2340
2341 /* The layout has been successfully updated, the disk is not dirty anymore */
2342 DiskEntry->Dirty = FALSE;
2343
2344 return Status;
2345}
2346
2347
2348NTSTATUS
2349WriteGptPartitions(
2350 _In_ PDISKENTRY DiskEntry)
2351{
2352 NTSTATUS Status;
2353 OBJECT_ATTRIBUTES ObjectAttributes;
2354 UNICODE_STRING Name;
2355 HANDLE FileHandle;
2356 IO_STATUS_BLOCK Iosb;
2357 ULONG BufferSize;
2358 WCHAR DstPath[MAX_PATH];
2359
2360 DPRINT("WriteGptPartitions() Disk: %lu\n", DiskEntry->DiskNumber);
2361
2362 /* If the disk is not dirty, there is nothing to do */
2363 if (!DiskEntry->Dirty)
2364 return STATUS_SUCCESS;
2365
2366 StringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
2367 L"\\Device\\Harddisk%lu\\Partition0",
2368 DiskEntry->DiskNumber);
2369 RtlInitUnicodeString(&Name, DstPath);
2370
2371 InitializeObjectAttributes(&ObjectAttributes,
2372 &Name,
2373 OBJ_CASE_INSENSITIVE,
2374 NULL,
2375 NULL);
2376
2377 Status = NtOpenFile(&FileHandle,
2378 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2379 &ObjectAttributes,
2380 &Iosb,
2381 0,
2382 FILE_SYNCHRONOUS_IO_NONALERT);
2383 if (!NT_SUCCESS(Status))
2384 {
2385 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
2386 return Status;
2387 }
2388
2389 //
2390 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
2391 // the disk in MBR or GPT format in case the disk was not initialized!!
2392 // For this we must ask the user which format to use.
2393 //
2394
2395 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
2396 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
2397 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX));
2398 Status = NtDeviceIoControlFile(FileHandle,
2399 NULL,
2400 NULL,
2401 NULL,
2402 &Iosb,
2403 IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
2404 DiskEntry->LayoutBuffer,
2405 BufferSize,
2406 DiskEntry->LayoutBuffer,
2407 BufferSize);
2408 NtClose(FileHandle);
2409
2410 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT_EX call succeeded */
2411 if (!NT_SUCCESS(Status))
2412 {
2413 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed (Status 0x%08lx)\n", Status);
2414 return Status;
2415 }
2416
2417 /* The layout has been successfully updated, the disk is not dirty anymore */
2418 DiskEntry->Dirty = FALSE;
2419
2420 return Status;
2421}
2422
2423
2424static
2425BOOLEAN
2426IsEmptyLayoutEntry(
2427 IN PPARTITION_INFORMATION_EX PartitionInfo)
2428{
2429 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2430 PartitionInfo->PartitionLength.QuadPart == 0)
2431 {
2432 return TRUE;
2433 }
2434
2435 return FALSE;
2436}
2437
2438
2439static
2440BOOLEAN
2441IsSamePrimaryLayoutEntry(
2442 IN PPARTITION_INFORMATION_EX PartitionInfo,
2443 IN PDISKENTRY DiskEntry,
2444 IN PPARTENTRY PartEntry)
2445{
2446 if ((PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector) &&
2447 (PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector))
2448 {
2449 return TRUE;
2450 }
2451
2452 return FALSE;
2453}
2454
2455
2456ULONG
2457GetPrimaryPartitionCount(
2458 _In_ PDISKENTRY DiskEntry)
2459{
2460 PLIST_ENTRY Entry;
2461 PPARTENTRY PartEntry;
2462 ULONG Count = 0;
2463
2464 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2465 Entry != &DiskEntry->PrimaryPartListHead;
2466 Entry = Entry->Flink)
2467 {
2468 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2469 if (PartEntry->IsPartitioned)
2470 Count++;
2471 }
2472
2473 return Count;
2474}
2475
2476
2477static
2478ULONG
2479GetLogicalPartitionCount(
2480 _In_ PDISKENTRY DiskEntry)
2481{
2482 PLIST_ENTRY ListEntry;
2483 PPARTENTRY PartEntry;
2484 ULONG Count = 0;
2485
2486 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2487 ListEntry != &DiskEntry->LogicalPartListHead;
2488 ListEntry = ListEntry->Flink)
2489 {
2490 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2491 if (PartEntry->IsPartitioned)
2492 Count++;
2493 }
2494
2495 return Count;
2496}
2497
2498
2499static
2500BOOLEAN
2501ReAllocateLayoutBuffer(
2502 _In_ PDISKENTRY DiskEntry)
2503{
2504 PDRIVE_LAYOUT_INFORMATION_EX NewLayoutBuffer;
2505 ULONG NewPartitionCount;
2506 ULONG CurrentPartitionCount = 0;
2507 ULONG LayoutBufferSize;
2508 ULONG i;
2509
2510 DPRINT1("ReAllocateLayoutBuffer()\n");
2511
2512 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2513
2514 if (DiskEntry->LayoutBuffer)
2515 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2516
2517 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2518 CurrentPartitionCount, NewPartitionCount);
2519
2520 if (CurrentPartitionCount == NewPartitionCount)
2521 return TRUE;
2522
2523 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
2524 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX));
2525 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(),
2526 HEAP_ZERO_MEMORY,
2527 DiskEntry->LayoutBuffer,
2528 LayoutBufferSize);
2529 if (NewLayoutBuffer == NULL)
2530 {
2531 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2532 return FALSE;
2533 }
2534
2535 NewLayoutBuffer->PartitionCount = NewPartitionCount;
2536
2537 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2538 if (NewPartitionCount > CurrentPartitionCount)
2539 {
2540 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2541 {
2542 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2543 }
2544 }
2545
2546 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2547
2548 return TRUE;
2549}
2550
2551
2552VOID
2553UpdateMbrDiskLayout(
2554 _In_ PDISKENTRY DiskEntry)
2555{
2556 PPARTITION_INFORMATION_EX PartitionInfo;
2557 PPARTITION_INFORMATION_EX LinkInfo = NULL;
2558 PLIST_ENTRY ListEntry;
2559 PPARTENTRY PartEntry;
2560 LARGE_INTEGER HiddenSectors64;
2561 ULONG Index;
2562 ULONG PartitionNumber = 1;
2563
2564 DPRINT("UpdateMbrDiskLayout()\n");
2565
2566 /* Resize the layout buffer if necessary */
2567 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2568 {
2569 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2570 return;
2571 }
2572
2573 DiskEntry->LayoutBuffer->PartitionStyle = PARTITION_STYLE_MBR;
2574
2575 /* Update the primary partition table */
2576 Index = 0;
2577 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2578 ListEntry != &DiskEntry->PrimaryPartListHead;
2579 ListEntry = ListEntry->Flink)
2580 {
2581 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2582
2583 if (PartEntry->IsPartitioned)
2584 {
2585 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED);
2586
2587 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2588 PartEntry->PartitionIndex = Index;
2589
2590 /* Reset the current partition number only for newly-created (unmounted) partitions */
2591 if (PartEntry->New)
2592 PartEntry->PartitionNumber = 0;
2593
2594 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->Mbr.PartitionType) ? PartitionNumber : 0);
2595
2596 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2597 {
2598 DPRINT1("Updating primary partition entry %lu\n", Index);
2599
2600 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
2601 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2602 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2603 PartitionInfo->Mbr.HiddenSectors = PartEntry->StartSector.LowPart;
2604 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2605 PartitionInfo->Mbr.PartitionType = PartEntry->Mbr.PartitionType;
2606 PartitionInfo->Mbr.BootIndicator = PartEntry->Mbr.BootIndicator;
2607 PartitionInfo->Mbr.RecognizedPartition = IsRecognizedPartition(PartEntry->Mbr.PartitionType);
2608 PartitionInfo->RewritePartition = TRUE;
2609 }
2610
2611 if (!IsContainerPartition(PartEntry->Mbr.PartitionType))
2612 PartitionNumber++;
2613
2614 Index++;
2615 }
2616 }
2617
2618 ASSERT(Index <= 4);
2619
2620 /* Update the logical partition table */
2621 Index = 4;
2622 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2623 ListEntry != &DiskEntry->LogicalPartListHead;
2624 ListEntry = ListEntry->Flink)
2625 {
2626 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2627
2628 if (PartEntry->IsPartitioned)
2629 {
2630 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED);
2631
2632 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2633 PartEntry->PartitionIndex = Index;
2634
2635 /* Reset the current partition number only for newly-created (unmounted) partitions */
2636 if (PartEntry->New)
2637 PartEntry->PartitionNumber = 0;
2638
2639 PartEntry->OnDiskPartitionNumber = PartitionNumber;
2640
2641 DPRINT1("Updating logical partition entry %lu\n", Index);
2642
2643 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
2644 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2645 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2646 PartitionInfo->Mbr.HiddenSectors = DiskEntry->SectorAlignment;
2647 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2648 PartitionInfo->Mbr.PartitionType = PartEntry->Mbr.PartitionType;
2649 PartitionInfo->Mbr.BootIndicator = FALSE;
2650 PartitionInfo->Mbr.RecognizedPartition = IsRecognizedPartition(PartEntry->Mbr.PartitionType);
2651 PartitionInfo->RewritePartition = TRUE;
2652
2653 /* Fill the link entry of the previous partition entry */
2654 if (LinkInfo != NULL)
2655 {
2656 LinkInfo->PartitionStyle = PARTITION_STYLE_MBR;
2657 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2658 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2659 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2660 LinkInfo->Mbr.HiddenSectors = HiddenSectors64.LowPart;
2661 LinkInfo->PartitionNumber = 0;
2662 LinkInfo->Mbr.PartitionType = PARTITION_EXTENDED;
2663 LinkInfo->Mbr.BootIndicator = FALSE;
2664 LinkInfo->Mbr.RecognizedPartition = FALSE;
2665 LinkInfo->RewritePartition = TRUE;
2666 }
2667
2668 /* Save a pointer to the link entry of the current partition entry */
2669 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2670
2671 PartitionNumber++;
2672 Index += 4;
2673 }
2674 }
2675
2676 /* Wipe unused primary partition entries */
2677 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2678 {
2679 DPRINT1("Primary partition entry %lu\n", Index);
2680
2681 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2682
2683 if (!IsEmptyLayoutEntry(PartitionInfo))
2684 {
2685 DPRINT1("Wiping primary partition entry %lu\n", Index);
2686
2687 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
2688 PartitionInfo->StartingOffset.QuadPart = 0;
2689 PartitionInfo->PartitionLength.QuadPart = 0;
2690 PartitionInfo->Mbr.HiddenSectors = 0;
2691 PartitionInfo->PartitionNumber = 0;
2692 PartitionInfo->Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
2693 PartitionInfo->Mbr.BootIndicator = FALSE;
2694 PartitionInfo->Mbr.RecognizedPartition = FALSE;
2695 PartitionInfo->RewritePartition = TRUE;
2696 }
2697 }
2698
2699 /* Wipe unused logical partition entries */
2700 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2701 {
2702 if (Index % 4 >= 2)
2703 {
2704 DPRINT1("Logical partition entry %lu\n", Index);
2705
2706 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2707
2708 if (!IsEmptyLayoutEntry(PartitionInfo))
2709 {
2710 DPRINT1("Wiping partition entry %lu\n", Index);
2711
2712 PartitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
2713 PartitionInfo->StartingOffset.QuadPart = 0;
2714 PartitionInfo->PartitionLength.QuadPart = 0;
2715 PartitionInfo->Mbr.HiddenSectors = 0;
2716 PartitionInfo->PartitionNumber = 0;
2717 PartitionInfo->Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
2718 PartitionInfo->Mbr.BootIndicator = FALSE;
2719 PartitionInfo->Mbr.RecognizedPartition = FALSE;
2720 PartitionInfo->RewritePartition = TRUE;
2721 }
2722 }
2723 }
2724
2725 DiskEntry->Dirty = TRUE;
2726}
2727
2728
2729VOID
2730UpdateGptDiskLayout(
2731 _In_ PDISKENTRY DiskEntry,
2732 _In_ BOOL DeleteEntry)
2733{
2734 PLIST_ENTRY ListEntry;
2735 PPARTENTRY PartEntry;
2736 PPARTITION_INFORMATION_EX PartitionInfo;
2737 ULONG Count, Index;
2738
2739 DPRINT("UpdateGptDiskLayout()\n");
2740
2741 /* Count used partition entries */
2742 Count = 0;
2743 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2744 ListEntry != &DiskEntry->PrimaryPartListHead;
2745 ListEntry = ListEntry->Flink)
2746 {
2747 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2748
2749 if (!IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID))
2750 Count++;
2751 }
2752
2753 DPRINT("Used partition entries: %lu\n", Count);
2754
2755 if (DeleteEntry)
2756 Count++;
2757
2758 /* Reallocate the layout buffer */
2759 if (Count != DiskEntry->LayoutBuffer->PartitionCount)
2760 {
2761 PDRIVE_LAYOUT_INFORMATION_EX NewLayoutBuffer;
2762 ULONG NewLayoutBufferSize;
2763
2764 NewLayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
2765 ((Count - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION_EX));
2766 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(),
2767 HEAP_ZERO_MEMORY,
2768 DiskEntry->LayoutBuffer,
2769 NewLayoutBufferSize);
2770 if (NewLayoutBuffer == NULL)
2771 {
2772 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", NewLayoutBufferSize);
2773 return;
2774 }
2775
2776 NewLayoutBuffer->PartitionCount = Count;
2777 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2778 }
2779
2780 /* Fill the new layout buffer */
2781 Index = 0;
2782 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2783 ListEntry != &DiskEntry->PrimaryPartListHead;
2784 ListEntry = ListEntry->Flink)
2785 {
2786 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2787
2788 if (!IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID))
2789 {
2790 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2791 PartEntry->PartitionIndex = Index;
2792
2793 DPRINT("Updating primary partition entry %lu\n", Index);
2794 PartitionInfo->PartitionStyle = PARTITION_STYLE_GPT;
2795 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2796 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2797 PartitionInfo->PartitionNumber = Index + 1;
2798 PartitionInfo->RewritePartition = TRUE;
2799 CopyMemory(&PartitionInfo->Gpt.PartitionType, &PartEntry->Gpt.PartitionType, sizeof(GUID));
2800 CopyMemory(&PartitionInfo->Gpt.PartitionId, &PartEntry->Gpt.PartitionId, sizeof(GUID));
2801 PartitionInfo->Gpt.Attributes = PartEntry->Gpt.Attributes;
2802 ZeroMemory(&PartitionInfo->Gpt.Name, 36 * sizeof(WCHAR)); /* ??? */
2803
2804 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
2805
2806 Index++;
2807 }
2808 }
2809
2810 if (DeleteEntry)
2811 {
2812 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2813 ZeroMemory(PartitionInfo, sizeof(PARTITION_INFORMATION_EX));
2814 PartitionInfo->RewritePartition = TRUE;
2815 }
2816}
2817
2818
2819PPARTENTRY
2820GetPrevUnpartitionedEntry(
2821 _In_ PPARTENTRY PartEntry)
2822{
2823 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2824 PPARTENTRY PrevPartEntry;
2825 PLIST_ENTRY ListHead;
2826
2827 if (PartEntry->LogicalPartition)
2828 ListHead = &DiskEntry->LogicalPartListHead;
2829 else
2830 ListHead = &DiskEntry->PrimaryPartListHead;
2831
2832 if (PartEntry->ListEntry.Blink != ListHead)
2833 {
2834 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2835 PARTENTRY,
2836 ListEntry);
2837 if (!PrevPartEntry->IsPartitioned)
2838 {
2839 ASSERT(PrevPartEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED);
2840 return PrevPartEntry;
2841 }
2842 }
2843
2844 return NULL;
2845}
2846
2847
2848PPARTENTRY
2849GetNextUnpartitionedEntry(
2850 _In_ PPARTENTRY PartEntry)
2851{
2852 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2853 PPARTENTRY NextPartEntry;
2854 PLIST_ENTRY ListHead;
2855
2856 if (PartEntry->LogicalPartition)
2857 ListHead = &DiskEntry->LogicalPartListHead;
2858 else
2859 ListHead = &DiskEntry->PrimaryPartListHead;
2860
2861 if (PartEntry->ListEntry.Flink != ListHead)
2862 {
2863 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2864 PARTENTRY,
2865 ListEntry);
2866 if (!NextPartEntry->IsPartitioned)
2867 {
2868 ASSERT(NextPartEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED);
2869 return NextPartEntry;
2870 }
2871 }
2872
2873 return NULL;
2874}
2875
2876
2877NTSTATUS
2878DismountVolume(
2879 _In_ PPARTENTRY PartEntry)
2880{
2881 NTSTATUS Status;
2882 NTSTATUS LockStatus;
2883 UNICODE_STRING Name;
2884 OBJECT_ATTRIBUTES ObjectAttributes;
2885 IO_STATUS_BLOCK IoStatusBlock;
2886 HANDLE PartitionHandle;
2887 WCHAR Buffer[MAX_PATH];
2888
2889 /* Check whether the partition is valid and was mounted by the system */
2890 if (PartEntry->DiskEntry->PartitionStyle == PARTITION_STYLE_MBR)
2891 {
2892 if (!PartEntry->IsPartitioned ||
2893 IsContainerPartition(PartEntry->Mbr.PartitionType) ||
2894 !IsRecognizedPartition(PartEntry->Mbr.PartitionType) ||
2895 PartEntry->FormatState == UnknownFormat ||
2896 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means
2897 // it has been usually mounted with RawFS and thus needs to be dismounted.
2898/* !*PartEntry->FileSystem || */
2899 PartEntry->PartitionNumber == 0)
2900 {
2901 /* The partition is not mounted, so just return success */
2902 return STATUS_SUCCESS;
2903 }
2904
2905 ASSERT(PartEntry->Mbr.PartitionType != PARTITION_ENTRY_UNUSED);
2906 }
2907 else if (PartEntry->DiskEntry->PartitionStyle == PARTITION_STYLE_GPT)
2908 {
2909 if (!PartEntry->IsPartitioned ||
2910 IsEqualGUID(&PartEntry->Gpt.PartitionType, &PARTITION_ENTRY_UNUSED_GUID) ||
2911 (PartEntry->FormatState == UnknownFormat))
2912 {
2913 /* The partition is not mounted, so just return success */
2914 return STATUS_SUCCESS;
2915 }
2916 }
2917
2918 /* Open the volume */
2919 StringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
2920 L"\\Device\\Harddisk%lu\\Partition%lu",
2921 PartEntry->DiskEntry->DiskNumber,
2922 PartEntry->PartitionNumber);
2923 RtlInitUnicodeString(&Name, Buffer);
2924
2925 InitializeObjectAttributes(&ObjectAttributes,
2926 &Name,
2927 OBJ_CASE_INSENSITIVE,
2928 NULL,
2929 NULL);
2930
2931 Status = NtOpenFile(&PartitionHandle,
2932 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2933 &ObjectAttributes,
2934 &IoStatusBlock,
2935 FILE_SHARE_READ | FILE_SHARE_WRITE,
2936 FILE_SYNCHRONOUS_IO_NONALERT);
2937 if (!NT_SUCCESS(Status))
2938 {
2939 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status);
2940 return Status;
2941 }
2942
2943 /* Lock the volume */
2944 LockStatus = NtFsControlFile(PartitionHandle,
2945 NULL,
2946 NULL,
2947 NULL,
2948 &IoStatusBlock,
2949 FSCTL_LOCK_VOLUME,
2950 NULL,
2951 0,
2952 NULL,
2953 0);
2954 if (!NT_SUCCESS(LockStatus))
2955 {
2956 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus);
2957 }
2958
2959 /* Dismount the volume */
2960 Status = NtFsControlFile(PartitionHandle,
2961 NULL,
2962 NULL,
2963 NULL,
2964 &IoStatusBlock,
2965 FSCTL_DISMOUNT_VOLUME,
2966 NULL,
2967 0,
2968 NULL,
2969 0);
2970 if (!NT_SUCCESS(Status))
2971 {
2972 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status);
2973 }
2974
2975 /* Unlock the volume */
2976 LockStatus = NtFsControlFile(PartitionHandle,
2977 NULL,
2978 NULL,
2979 NULL,
2980 &IoStatusBlock,
2981 FSCTL_UNLOCK_VOLUME,
2982 NULL,
2983 0,
2984 NULL,
2985 0);
2986 if (!NT_SUCCESS(LockStatus))
2987 {
2988 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus);
2989 }
2990
2991 /* Close the volume */
2992 NtClose(PartitionHandle);
2993
2994 return Status;
2995}
2996
2997
2998PVOLENTRY
2999GetVolumeFromPartition(
3000 _In_ PPARTENTRY PartEntry)
3001{
3002 PLIST_ENTRY Entry;
3003 PVOLENTRY VolumeEntry;
3004 ULONG i;
3005
3006 if ((PartEntry == NULL) ||
3007 (PartEntry->DiskEntry == NULL))
3008 return NULL;
3009
3010 Entry = VolumeListHead.Flink;
3011 while (Entry != &VolumeListHead)
3012 {
3013 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
3014
3015 if (VolumeEntry->pExtents == NULL)
3016 return NULL;
3017
3018 for (i = 0; i < VolumeEntry->pExtents->NumberOfDiskExtents; i++)
3019 {
3020 if (VolumeEntry->pExtents->Extents[i].DiskNumber == PartEntry->DiskEntry->DiskNumber)
3021 {
3022 if ((VolumeEntry->pExtents->Extents[i].StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * PartEntry->DiskEntry->BytesPerSector) &&
3023 (VolumeEntry->pExtents->Extents[i].ExtentLength.QuadPart == PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector))
3024 return VolumeEntry;
3025 }
3026 }
3027
3028 Entry = Entry->Flink;
3029 }
3030
3031 return NULL;
3032}
3033
3034
3035VOID
3036RemoveVolume(
3037 _In_ PVOLENTRY VolumeEntry)
3038{
3039 if (VolumeEntry == NULL)
3040 return;
3041
3042 if (VolumeEntry == CurrentVolume)
3043 CurrentVolume = NULL;
3044
3045 RemoveEntryList(&VolumeEntry->ListEntry);
3046
3047 if (VolumeEntry->pszLabel)
3048 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszLabel);
3049
3050 if (VolumeEntry->pszFilesystem)
3051 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pszFilesystem);
3052
3053 if (VolumeEntry->pExtents)
3054 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry->pExtents);
3055
3056 /* Release disk entry */
3057 RtlFreeHeap(RtlGetProcessHeap(), 0, VolumeEntry);
3058}
3059
3060/* EOF */