ReactOS 0.4.16-dev-197-g92996da
partlist.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Partition list functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2018-2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
7 */
8
9#include "precomp.h"
10#include <ntddscsi.h>
11
12#include "partlist.h"
13#include "volutil.h"
14#include "fsrec.h" // For FileSystemToMBRPartitionType()
15
16#include "registry.h"
17
18#define NDEBUG
19#include <debug.h>
20
21// #define DUMP_PARTITION_TABLE
22
23#include <pshpack1.h>
25{
29#include <poppack.h>
30
31
32/* FUNCTIONS ****************************************************************/
33
34#ifdef DUMP_PARTITION_TABLE
35static
36VOID
37DumpPartitionTable(
38 PDISKENTRY DiskEntry)
39{
41 ULONG i;
42
43 DbgPrint("\n");
44 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
45 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
46
47 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
48 {
50 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
51 i,
52 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
53 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
54 PartitionInfo->HiddenSectors,
55 PartitionInfo->PartitionNumber,
56 PartitionInfo->PartitionType,
57 PartitionInfo->BootIndicator ? '*': ' ',
58 PartitionInfo->RewritePartition ? 'Y': 'N');
59 }
60
61 DbgPrint("\n");
62}
63#endif
64
65
70{
71 ULONGLONG Temp;
72
73 Temp = Value / Alignment;
74
75 return Temp * Alignment;
76}
77
82{
83 ULONGLONG Temp, Result;
84
85 Temp = Value / Alignment;
86
87 Result = Temp * Alignment;
88 if (Value % Alignment)
90
91 return Result;
92}
93
96 IN ULONGLONG Dividend,
98{
99 return (Dividend + Divisor / 2) / Divisor;
100}
101
102
103static
104VOID
106 IN PDISKENTRY DiskEntry)
107{
109 WCHAR KeyName[32];
111
112 RtlInitUnicodeString(&DiskEntry->DriverName, NULL);
113
115 L"\\Scsi\\Scsi Port %hu",
116 DiskEntry->Port);
117
119
120 QueryTable[0].Name = L"Driver";
122 QueryTable[0].EntryContext = &DiskEntry->DriverName;
123
124 /* This will allocate DiskEntry->DriverName if needed */
126 KeyName,
128 NULL,
129 NULL);
130 if (!NT_SUCCESS(Status))
131 {
132 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
133 }
134}
135
136static
137VOID
140{
141 PDISKENTRY DiskEntry;
142 PPARTENTRY PartEntry;
143 PLIST_ENTRY Entry1;
144 PLIST_ENTRY Entry2;
146
147 Letter = L'C';
148
149 /* Assign drive letters to primary partitions */
150 for (Entry1 = List->DiskListHead.Flink;
151 Entry1 != &List->DiskListHead;
152 Entry1 = Entry1->Flink)
153 {
154 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
155
156 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
157 Entry2 != &DiskEntry->PrimaryPartListHead;
158 Entry2 = Entry2->Flink)
159 {
160 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
161
162 if (!PartEntry->Volume)
163 continue;
164 PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
165
166 if (PartEntry->IsPartitioned &&
167 !IsContainerPartition(PartEntry->PartitionType) &&
169 PartEntry->SectorCount.QuadPart != 0LL))
170 {
171 if (Letter <= L'Z')
172 PartEntry->Volume->Info.DriveLetter = Letter++;
173 }
174 }
175 }
176
177 /* Assign drive letters to logical drives */
178 for (Entry1 = List->DiskListHead.Flink;
179 Entry1 != &List->DiskListHead;
180 Entry1 = Entry1->Flink)
181 {
182 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
183
184 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
185 Entry2 != &DiskEntry->LogicalPartListHead;
186 Entry2 = Entry2->Flink)
187 {
188 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
189
190 if (!PartEntry->Volume)
191 continue;
192 PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
193
194 if (PartEntry->IsPartitioned &&
196 PartEntry->SectorCount.QuadPart != 0LL))
197 {
198 if (Letter <= L'Z')
199 PartEntry->Volume->Info.DriveLetter = Letter++;
200 }
201 }
202 }
203}
204
205static NTSTATUS
206NTAPI
214{
215 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
216 UNICODE_STRING NameU;
217
218 if (ValueType == REG_SZ &&
219 ValueLength == 20 * sizeof(WCHAR) &&
220 ((PWCHAR)ValueData)[8] == L'-')
221 {
222 NameU.Buffer = (PWCHAR)ValueData;
223 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
224 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
225
226 NameU.Buffer = (PWCHAR)ValueData + 9;
227 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
228
229 return STATUS_SUCCESS;
230 }
231
232 return STATUS_UNSUCCESSFUL;
233}
234
235static NTSTATUS
236NTAPI
244{
245 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
246 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
248 ULONG i;
249
252 return STATUS_UNSUCCESSFUL;
253
254 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
255
256 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
257#if 0
258 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
259 FullResourceDescriptor->PartialResourceList.Revision != 1)
260 return STATUS_UNSUCCESSFUL;
261#endif
262
263 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
264 {
267 continue;
268
269 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
270 BiosDiskEntry->DiskGeometry = *DiskGeometry;
271
272 return STATUS_SUCCESS;
273 }
274
275 return STATUS_UNSUCCESSFUL;
276}
277
278static NTSTATUS
279NTAPI
287{
288 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
290 ULONG i;
291
294 return STATUS_UNSUCCESSFUL;
295
296 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
297
298 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
299#if 0
300 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
301 FullResourceDescriptor->PartialResourceList.Revision != 1)
302 return STATUS_UNSUCCESSFUL;
303#endif
304
305 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
306 {
308 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
309 continue;
310
312 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
313 if (*Int13Drives == NULL)
314 return STATUS_NO_MEMORY;
315
316 memcpy(*Int13Drives,
317 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
318 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
319 return STATUS_SUCCESS;
320 }
321
322 return STATUS_UNSUCCESSFUL;
323}
324
325
326static VOID
328 IN PPARTLIST PartList)
329{
331 WCHAR Name[120];
332 ULONG AdapterCount;
334 ULONG DiskCount;
336 PCM_INT13_DRIVE_PARAMETER Int13Drives;
337 PBIOSDISKENTRY BiosDiskEntry;
338
339#define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
340
341 memset(QueryTable, 0, sizeof(QueryTable));
342
343 QueryTable[1].Name = L"Configuration Data";
345 Int13Drives = NULL;
347 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
348 &QueryTable[1],
349 (PVOID)&Int13Drives,
350 NULL);
351 if (!NT_SUCCESS(Status))
352 {
353 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
354 return;
355 }
356
357 for (AdapterCount = 0; ; ++AdapterCount)
358 {
360 L"%s\\%lu",
361 ROOT_NAME, AdapterCount);
363 Name,
364 &QueryTable[2],
365 NULL,
366 NULL);
367 if (!NT_SUCCESS(Status))
368 {
369 break;
370 }
371
373 L"%s\\%lu\\DiskController",
374 ROOT_NAME, AdapterCount);
376 Name,
377 &QueryTable[2],
378 NULL,
379 NULL);
380 if (NT_SUCCESS(Status))
381 {
382 for (ControllerCount = 0; ; ++ControllerCount)
383 {
385 L"%s\\%lu\\DiskController\\%lu",
386 ROOT_NAME, AdapterCount, ControllerCount);
388 Name,
389 &QueryTable[2],
390 NULL,
391 NULL);
392 if (!NT_SUCCESS(Status))
393 {
394 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
395 return;
396 }
397
399 L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral",
400 ROOT_NAME, AdapterCount, ControllerCount);
402 Name,
403 &QueryTable[2],
404 NULL,
405 NULL);
406 if (NT_SUCCESS(Status))
407 {
408 QueryTable[0].Name = L"Identifier";
410 QueryTable[1].Name = L"Configuration Data";
412
413 for (DiskCount = 0; ; ++DiskCount)
414 {
416 if (BiosDiskEntry == NULL)
417 {
418 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
419 return;
420 }
421
423 L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu",
424 ROOT_NAME, AdapterCount, ControllerCount, DiskCount);
426 Name,
428 (PVOID)BiosDiskEntry,
429 NULL);
430 if (!NT_SUCCESS(Status))
431 {
432 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
433 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
434 return;
435 }
436
437 BiosDiskEntry->AdapterNumber = 0; // And NOT "AdapterCount" as it needs to be hardcoded for BIOS!
438 BiosDiskEntry->ControllerNumber = ControllerCount;
439 BiosDiskEntry->DiskNumber = DiskCount;
440 BiosDiskEntry->DiskEntry = NULL;
441
442 if (DiskCount < Int13Drives[0].NumberDrives)
443 {
444 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
445 }
446 else
447 {
448 DPRINT1("Didn't find Int13 drive data for disk %u\n", DiskCount);
449 }
450
451 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
452
453 DPRINT("--->\n");
454 DPRINT("AdapterNumber: %lu\n", BiosDiskEntry->AdapterNumber);
455 DPRINT("ControllerNumber: %lu\n", BiosDiskEntry->ControllerNumber);
456 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
457 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
458 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
459 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
460 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
461 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
462 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
463 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
464 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
465 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
466 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
467 DPRINT("<---\n");
468 }
469 }
470 }
471 }
472 }
473
474 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
475
476#undef ROOT_NAME
477}
478
479
480/*
481 * Detects whether a disk is a "super-floppy", i.e. an unpartitioned
482 * disk with only a valid VBR, as reported by IoReadPartitionTable()
483 * and IoWritePartitionTable():
484 * only one single partition starting at offset zero and spanning the
485 * whole disk, without hidden sectors, whose type is FAT16 non-bootable.
486 *
487 * Accessing \Device\HarddiskN\Partition0 or Partition1 on such disks
488 * returns the same data.
489 */
492 _In_ const DISK_PARTITION_INFO* DiskInfo,
493 _In_opt_ const ULONGLONG* DiskSize,
495{
496 /* Structure size must be valid */
497 if (DiskInfo->SizeOfPartitionInfo < RTL_SIZEOF_THROUGH_FIELD(DISK_PARTITION_INFO, Mbr))
498 return FALSE;
499
500 /* The layout must be MBR */
501 if (DiskInfo->PartitionStyle != PARTITION_STYLE_MBR)
502 return FALSE;
503
504 /* The single partition must start at the beginning of the disk */
505 if (!(PartitionInfo->StartingOffset.QuadPart == 0 &&
506 PartitionInfo->HiddenSectors == 0))
507 {
508 return FALSE;
509 }
510
511 /* The disk signature is usually set to 1; warn in case it's not */
512 if (DiskInfo->Mbr.Signature != 1)
513 {
514 DPRINT1("Super-Floppy signature %08x != 1\n", DiskInfo->Mbr.Signature);
515 }
516
517 /* The partition must be recognized and report as FAT16 non-bootable */
518 if ((PartitionInfo->RecognizedPartition != TRUE) ||
519 (PartitionInfo->PartitionType != PARTITION_FAT_16) ||
520 (PartitionInfo->BootIndicator != FALSE))
521 {
522 DPRINT1("Super-Floppy does not return default settings:\n"
523 " RecognizedPartition = %s, expected TRUE\n"
524 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n"
525 " BootIndicator = %s, expected FALSE\n",
526 PartitionInfo->RecognizedPartition ? "TRUE" : "FALSE",
527 PartitionInfo->PartitionType,
528 PartitionInfo->BootIndicator ? "TRUE" : "FALSE");
529 }
530
531 /* The partition and disk sizes should agree */
532 if (DiskSize && (PartitionInfo->PartitionLength.QuadPart != *DiskSize))
533 {
534 DPRINT1("PartitionLength = %I64u is different from DiskSize = %I64u\n",
535 PartitionInfo->PartitionLength.QuadPart, *DiskSize);
536 }
537
538 return TRUE;
539}
540
543 _In_ const DRIVE_LAYOUT_INFORMATION* Layout,
544 _In_opt_ const ULONGLONG* DiskSize)
545{
546 DISK_PARTITION_INFO DiskInfo;
547
548 /* The layout must contain only one partition */
549 if (Layout->PartitionCount != 1)
550 return FALSE;
551
552 /* Build the disk partition info */
553 DiskInfo.SizeOfPartitionInfo = RTL_SIZEOF_THROUGH_FIELD(DISK_PARTITION_INFO, Mbr);
554 DiskInfo.PartitionStyle = PARTITION_STYLE_MBR;
555 DiskInfo.Mbr.Signature = Layout->Signature;
556 DiskInfo.Mbr.CheckSum = 0; // Dummy value
557
558 /* Call the helper on the single partition entry */
559 return IsDiskSuperFloppy2(&DiskInfo, DiskSize, Layout->PartitionEntry);
560}
561
564 _In_ const DRIVE_LAYOUT_INFORMATION_EX* LayoutEx,
565 _In_opt_ const ULONGLONG* DiskSize)
566{
567 DISK_PARTITION_INFO DiskInfo;
568 const PARTITION_INFORMATION_EX* PartitionInfoEx;
570
571 /* The layout must be MBR and contain only one partition */
572 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR)
573 return FALSE;
574 if (LayoutEx->PartitionCount != 1)
575 return FALSE;
576
577 /* Build the disk partition info */
578 DiskInfo.SizeOfPartitionInfo = RTL_SIZEOF_THROUGH_FIELD(DISK_PARTITION_INFO, Mbr);
579 DiskInfo.PartitionStyle = PARTITION_STYLE_MBR; // LayoutEx->PartitionStyle;
580 DiskInfo.Mbr.Signature = LayoutEx->Mbr.Signature;
581 DiskInfo.Mbr.CheckSum = 0; // Dummy value
582
583 /* Convert the single partition entry */
584 PartitionInfoEx = LayoutEx->PartitionEntry;
585
586 PartitionInfo.StartingOffset = PartitionInfoEx->StartingOffset;
587 PartitionInfo.PartitionLength = PartitionInfoEx->PartitionLength;
588 PartitionInfo.HiddenSectors = PartitionInfoEx->Mbr.HiddenSectors;
589 PartitionInfo.PartitionNumber = PartitionInfoEx->PartitionNumber;
590 PartitionInfo.PartitionType = PartitionInfoEx->Mbr.PartitionType;
591 PartitionInfo.BootIndicator = PartitionInfoEx->Mbr.BootIndicator;
592 PartitionInfo.RecognizedPartition = PartitionInfoEx->Mbr.RecognizedPartition;
593 PartitionInfo.RewritePartition = PartitionInfoEx->RewritePartition;
594
595 /* Call the helper on the single partition entry */
596 return IsDiskSuperFloppy2(&DiskInfo, DiskSize, &PartitionInfo);
597}
598
601 _In_ PDISKENTRY DiskEntry)
602{
603 ULONGLONG DiskSize;
604
605 /* No layout buffer: we cannot say anything yet */
606 if (!DiskEntry->LayoutBuffer)
607 return FALSE;
608
609 /* The disk must be MBR */
610 if (DiskEntry->DiskStyle != PARTITION_STYLE_MBR)
611 return FALSE;
612
613 DiskSize = GetDiskSizeInBytes(DiskEntry);
614 return IsDiskSuperFloppy(DiskEntry->LayoutBuffer, &DiskSize);
615}
616
617
618/*
619 * Inserts the disk region represented by PartEntry into either
620 * the primary or the logical partition list of the given disk.
621 * The lists are kept sorted by increasing order of start sectors.
622 * Of course no disk region should overlap at all with one another.
623 */
624static
627 IN PDISKENTRY DiskEntry,
628 IN PPARTENTRY PartEntry,
630{
633 PPARTENTRY PartEntry2;
634
635 /* Use the correct partition list */
637 List = &DiskEntry->LogicalPartListHead;
638 else
639 List = &DiskEntry->PrimaryPartListHead;
640
641 /* Find the first disk region before which we need to insert the new one */
642 for (Entry = List->Flink; Entry != List; Entry = Entry->Flink)
643 {
644 PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
645
646 /* Ignore any unused empty region */
647 if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED &&
648 PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0)
649 {
650 continue;
651 }
652
653 /* If the current region ends before the one to be inserted, try again */
654 if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart)
655 continue;
656
657 /*
658 * One of the disk region boundaries crosses the desired region
659 * (it starts after the desired region, or ends before the end
660 * of the desired region): this is an impossible situation because
661 * disk regions (partitions) cannot overlap!
662 * Throw an error and bail out.
663 */
664 if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart)
665 <=
666 min( PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
667 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1))
668 {
669 DPRINT1("Disk region overlap problem, stopping there!\n"
670 "Partition to be inserted:\n"
671 " StartSector = %I64u ; EndSector = %I64u\n"
672 "Existing disk region:\n"
673 " StartSector = %I64u ; EndSector = %I64u\n",
674 PartEntry->StartSector.QuadPart,
675 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
676 PartEntry2->StartSector.QuadPart,
677 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1);
678 return FALSE;
679 }
680
681 /* We have found the first region before which the new one has to be inserted */
682 break;
683 }
684
685 /* Insert the disk region */
686 InsertTailList(Entry, &PartEntry->ListEntry);
687 return TRUE;
688}
689
690static
693 IN PDISKENTRY DiskEntry,
694 IN OUT PLIST_ENTRY ListHead,
695 IN ULONGLONG StartSector,
697 IN BOOLEAN LogicalSpace)
698{
699 PPARTENTRY NewPartEntry;
700
701 NewPartEntry = RtlAllocateHeap(ProcessHeap,
703 sizeof(PARTENTRY));
704 if (!NewPartEntry)
705 return NULL;
706
707 NewPartEntry->DiskEntry = DiskEntry;
708
709 NewPartEntry->StartSector.QuadPart = StartSector;
710 NewPartEntry->SectorCount.QuadPart = SectorCount;
711
712 NewPartEntry->LogicalPartition = LogicalSpace;
713 NewPartEntry->IsPartitioned = FALSE;
715 NewPartEntry->Volume = NULL;
716
717 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
718 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
719 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
720
721 /* Insert the new entry into the list */
722 InsertTailList(ListHead, &NewPartEntry->ListEntry);
723
724 return NewPartEntry;
725}
726
727static
728VOID
730 _Inout_ PPARTENTRY PartEntry)
731{
732 // RemoveEntryList(&PartEntry->Volume->ListEntry);
733 if (PartEntry->Volume)
734 RtlFreeHeap(ProcessHeap, 0, PartEntry->Volume);
735 RtlFreeHeap(ProcessHeap, 0, PartEntry);
736}
737
738static
739VOID
741 _In_ PDISKENTRY DiskEntry)
742{
743 ULONGLONG StartSector;
745 PPARTENTRY NewPartEntry;
746
747 DPRINT("AddLogicalDiskSpace()\n");
748
749 /* Create a partition entry that represents the empty space in the container partition */
750
751 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
752 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
753
754 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
755 &DiskEntry->LogicalPartListHead,
756 StartSector,
758 TRUE);
759 if (!NewPartEntry)
760 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
761}
762
763// TODO: Improve upon the PartitionInfo parameter later
764// (see VDS::CREATE_PARTITION_PARAMETERS and PPARTITION_INFORMATION_MBR/GPT for example)
765// So far we only use it as the optional type of the partition to create.
766//
767// See also CreatePartition().
768static
771 _Inout_ PPARTENTRY PartEntry,
772 _In_opt_ ULONGLONG SizeBytes,
774{
775 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
778
779 DPRINT1("Current entry sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
780
781 /* The entry must not be already partitioned and not be void */
782 ASSERT(!PartEntry->IsPartitioned);
783 ASSERT(PartEntry->SectorCount.QuadPart);
784 ASSERT(!PartEntry->Volume);
785
786 /* Either we create a primary/logical partition, or we create an
787 * extended partition but the entry must not be logical space */
788 ASSERT(!isContainer || !PartEntry->LogicalPartition);
789
790 /* Convert the size in bytes to sector count. SizeBytes being
791 * zero means the caller wants to use all the empty space. */
792 if ((SizeBytes == 0) || (SizeBytes == GetPartEntrySizeInBytes(PartEntry)))
793 {
794 /* Use all of the unpartitioned disk space */
795 SectorCount = PartEntry->SectorCount.QuadPart;
796 }
797 else
798 {
799 SectorCount = SizeBytes / DiskEntry->BytesPerSector;
800 if (SectorCount == 0)
801 {
802 /* SizeBytes was certainly less than the minimal size, so fail */
803 DPRINT1("Partition size %I64u too small\n", SizeBytes);
804 return FALSE;
805 }
806 }
807 DPRINT1(" New sector count: %I64u\n", SectorCount);
808
809 /* Fail if we request more sectors than what the entry actually contains */
810 if (SectorCount > PartEntry->SectorCount.QuadPart)
811 return FALSE;
812
813 if ((SectorCount == 0) ||
814 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
815 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
816 {
817 /* Reuse the whole current entry */
818 }
819 else
820 {
821 ULONGLONG StartSector;
822 ULONGLONG SectorCount2;
823 PPARTENTRY NewPartEntry;
824
825 /* Create a partition entry that represents the remaining space
826 * after the partition to be initialized */
827
828 StartSector = AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment);
829 SectorCount2 = PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - StartSector;
830
831 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
832 PartEntry->ListEntry.Flink,
833 StartSector,
834 SectorCount2,
835 PartEntry->LogicalPartition);
836 if (!NewPartEntry)
837 {
838 DPRINT1("Failed to create a new empty region for disk space!\n");
839 return FALSE;
840 }
841
842 /* Resize down the partition entry; its StartSector remains the same */
843 PartEntry->SectorCount.QuadPart = StartSector - PartEntry->StartSector.QuadPart;
844 }
845
846 /* Convert to a new partition entry */
847 PartEntry->New = TRUE;
848 PartEntry->IsPartitioned = TRUE;
849
850 PartEntry->BootIndicator = FALSE;
851 if (PartitionInfo)
852 {
853 if (!isContainer)
854 {
855 PartEntry->PartitionType = (UCHAR)PartitionInfo;
856 }
857 else
858 {
859 /* Set the correct extended container partition type,
860 * depending on whether it is contained below or above
861 * the 1024-cylinder (usually 8.4GB/7.8GiB) boundary:
862 * - below: INT13h CHS partition;
863 * - above: Extended INT13h LBA partition. */
864 if ((PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1)
865 / (DiskEntry->TracksPerCylinder * DiskEntry->SectorsPerTrack) < 1024)
866 {
867 PartEntry->PartitionType = PARTITION_EXTENDED;
868 }
869 else
870 {
871 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
872 }
873 }
874 }
875 else
876 {
877// FIXME: Use FileSystemToMBRPartitionType() only for MBR, otherwise use PARTITION_BASIC_DATA_GUID.
878 ASSERT(!isContainer);
879 PartEntry->PartitionType = FileSystemToMBRPartitionType(L"RAW",
880 PartEntry->StartSector.QuadPart,
881 PartEntry->SectorCount.QuadPart);
882 }
883 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
884
885 if (isContainer)
886 {
887 DiskEntry->ExtendedPartition = PartEntry;
888 AddLogicalDiskSpace(DiskEntry);
889 }
890
891 DPRINT1("First Sector : %I64u\n", PartEntry->StartSector.QuadPart);
892 DPRINT1("Last Sector : %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
893 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
894
895 return TRUE;
896}
897
898static
899VOID
901 _Inout_ PPARTENTRY PartEntry)
902{
904
905 /* Ignore if this is a container partition */
906 if (IsContainerPartition(PartEntry->PartitionType))
907 return;
908 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
909
910 /* Make a device name for the partition */
911 Status = RtlStringCchPrintfW(PartEntry->DeviceName,
912 _countof(PartEntry->DeviceName),
913 L"\\Device\\Harddisk%lu\\Partition%lu",
914 PartEntry->DiskEntry->DiskNumber,
915 PartEntry->PartitionNumber);
917}
918
919static
920VOID
923{
925 PPARTENTRY PartEntry;
926
927 /* If we already have a volume device name, do nothing more */
928 if (*Volume->Info.DeviceName)
929 return;
930
931 /* Use the partition device name as a temporary volume device name */
932 // TODO: Ask instead the MOUNTMGR for the name.
933 PartEntry = Volume->PartEntry;
934 ASSERT(PartEntry);
935 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
936
937 /* Copy the volume device name */
938 Status = RtlStringCchCopyW(Volume->Info.DeviceName,
939 _countof(Volume->Info.DeviceName),
940 PartEntry->DeviceName);
942}
943
944static
948 _In_opt_ PPARTENTRY PartEntry)
949{
951
954 sizeof(VOLENTRY));
955 if (!Volume)
956 return NULL;
957
958 /* Reset some volume information */
959
960 /* No device name for now */
961 Volume->Info.DeviceName[0] = UNICODE_NULL;
962 // Volume->Info.VolumeName[0] = UNICODE_NULL;
963
964 /* Initialize the volume letter and label */
965 Volume->Info.DriveLetter = UNICODE_NULL;
966 Volume->Info.VolumeLabel[0] = UNICODE_NULL;
967
968 /* Specify the volume as initially unformatted */
969 Volume->Info.FileSystem[0] = UNICODE_NULL;
970 Volume->FormatState = Unformatted;
971 Volume->NeedsCheck = FALSE;
972 Volume->New = TRUE;
973
974 if (PartEntry)
975 {
976 ASSERT(PartEntry->DiskEntry->PartList == List);
977 Volume->PartEntry = PartEntry;
978 }
979 InsertTailList(&List->VolumesList, &Volume->ListEntry);
980 return Volume;
981}
982
983static
984VOID
986 IN ULONG DiskNumber,
987 IN PDISKENTRY DiskEntry,
988 IN ULONG PartitionIndex,
990{
992 PPARTENTRY PartEntry;
993
994 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
995
996 /* Ignore empty partitions */
997 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED)
998 return;
999 /* Request must be consistent, though! */
1001
1002 PartEntry = RtlAllocateHeap(ProcessHeap,
1004 sizeof(PARTENTRY));
1005 if (!PartEntry)
1006 return;
1007
1008 PartEntry->DiskEntry = DiskEntry;
1009
1010 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
1011 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
1012
1013 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
1014 PartEntry->PartitionType = PartitionInfo->PartitionType;
1015
1017 PartEntry->IsPartitioned = TRUE;
1018 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
1019 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
1020 PartEntry->PartitionIndex = PartitionIndex;
1021 InitPartitionDeviceName(PartEntry);
1022
1023 /* No volume initially */
1024 PartEntry->Volume = NULL;
1025
1026 if (IsContainerPartition(PartEntry->PartitionType))
1027 {
1028 if (!LogicalPartition && DiskEntry->ExtendedPartition == NULL)
1029 DiskEntry->ExtendedPartition = PartEntry;
1030 }
1031 else if (IsRecognizedPartition(PartEntry->PartitionType) || // PartitionInfo->RecognizedPartition
1032 IsOEMPartition(PartEntry->PartitionType))
1033 {
1036
1037 ASSERT(PartEntry->PartitionNumber != 0);
1038
1039 /* The PARTMGR should have notified the MOUNTMGR that a volume
1040 * associated with this partition had to be created */
1041 Volume = InitVolume(DiskEntry->PartList, PartEntry);
1042 if (!Volume)
1043 {
1044 DPRINT1("Couldn't allocate a volume for device '%S'\n",
1045 PartEntry->DeviceName);
1046 goto SkipVolume;
1047 }
1048 PartEntry->Volume = Volume;
1050 Volume->New = FALSE;
1051
1052 /* Attach and mount the volume */
1053 Status = MountVolume(&Volume->Info, PartEntry->PartitionType);
1054 if (!NT_SUCCESS(Status))
1055 {
1056 DPRINT1("Failed to mount volume '%S', Status 0x%08lx\n",
1057 Volume->Info.DeviceName, Status);
1058 }
1059
1060 //
1061 // FIXME: TEMP Backward-compatibility: Set the FormatState
1062 // flag in accordance with the FileSystem volume value.
1063 //
1064 /*
1065 * MountVolume() determines whether the given volume is actually
1066 * unformatted, if it was mounted with RawFS and the partition
1067 * type has specific values for FAT volumes. If so, the volume
1068 * stays mounted with RawFS (the FileSystem is "RAW"). However,
1069 * if the partition type has different values, the volume is
1070 * considered as having an unknown format (it may or may not be
1071 * formatted) and the FileSystem value has been emptied.
1072 */
1073 if (IsUnknown(&Volume->Info))
1074 Volume->FormatState = UnknownFormat;
1075 else if (IsUnformatted(&Volume->Info)) // FileSystem is "RAW"
1076 Volume->FormatState = Unformatted;
1077 else // !IsUnknown && !IsUnformatted == IsFormatted
1078 Volume->FormatState = Formatted;
1079SkipVolume:;
1080 }
1081 else
1082 {
1083 /* Unknown partition (may or may not be actually formatted):
1084 * the partition is hidden, hence no volume */
1085 DPRINT1("Disk %lu Partition %lu is not recognized (Type 0x%02x)\n",
1086 DiskEntry->DiskNumber, PartEntry->PartitionNumber,
1087 PartEntry->PartitionType);
1088 }
1089
1090 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
1091}
1092
1093static
1094VOID
1096 IN PDISKENTRY DiskEntry)
1097{
1098 ULONGLONG StartSector;
1100 ULONGLONG LastStartSector;
1101 ULONGLONG LastSectorCount;
1102 ULONGLONG LastUnusedSectorCount;
1103 PPARTENTRY PartEntry;
1104 PPARTENTRY NewPartEntry;
1106
1107 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1108
1109 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1110 {
1111 DPRINT1("No primary partition!\n");
1112
1113 /* Create a partition entry that represents the empty disk */
1114
1115 if (DiskEntry->SectorAlignment < 2048)
1116 StartSector = 2048ULL;
1117 else
1118 StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1119 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
1120
1121 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1122 &DiskEntry->PrimaryPartListHead,
1123 StartSector,
1125 FALSE);
1126 if (!NewPartEntry)
1127 DPRINT1("Failed to create a new empty region for full disk space!\n");
1128
1129 return;
1130 }
1131
1132 /* Start partition at head 1, cylinder 0 */
1133 if (DiskEntry->SectorAlignment < 2048)
1134 LastStartSector = 2048ULL;
1135 else
1136 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1137 LastSectorCount = 0ULL;
1138 LastUnusedSectorCount = 0ULL;
1139
1140 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1141 Entry != &DiskEntry->PrimaryPartListHead;
1142 Entry = Entry->Flink)
1143 {
1144 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1145
1146 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1147 PartEntry->SectorCount.QuadPart != 0ULL)
1148 {
1149 LastUnusedSectorCount =
1150 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
1151
1152 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
1153 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1154 {
1155 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1156
1157 StartSector = LastStartSector + LastSectorCount;
1158 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1159
1160 /* Insert the table into the list */
1161 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1162 &PartEntry->ListEntry,
1163 StartSector,
1165 FALSE);
1166 if (!NewPartEntry)
1167 {
1168 DPRINT1("Failed to create a new empty region for disk space!\n");
1169 return;
1170 }
1171 }
1172
1173 LastStartSector = PartEntry->StartSector.QuadPart;
1174 LastSectorCount = PartEntry->SectorCount.QuadPart;
1175 }
1176 }
1177
1178 /* Check for trailing unpartitioned disk space */
1179 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
1180 {
1181 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1182
1183 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1184 {
1185 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1186
1187 StartSector = LastStartSector + LastSectorCount;
1188 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1189
1190 /* Append the table to the list */
1191 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1192 &DiskEntry->PrimaryPartListHead,
1193 StartSector,
1195 FALSE);
1196 if (!NewPartEntry)
1197 {
1198 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1199 return;
1200 }
1201 }
1202 }
1203
1204 if (DiskEntry->ExtendedPartition != NULL)
1205 {
1206 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
1207 {
1208 DPRINT1("No logical partition!\n");
1209
1210 /* Create a partition entry that represents the empty extended partition */
1211 AddLogicalDiskSpace(DiskEntry);
1212 return;
1213 }
1214
1215 /* Start partition at head 1, cylinder 0 */
1216 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1217 LastSectorCount = 0ULL;
1218 LastUnusedSectorCount = 0ULL;
1219
1220 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1221 Entry != &DiskEntry->LogicalPartListHead;
1222 Entry = Entry->Flink)
1223 {
1224 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1225
1226 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1227 PartEntry->SectorCount.QuadPart != 0ULL)
1228 {
1229 LastUnusedSectorCount =
1230 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
1231
1232 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
1233 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1234 {
1235 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1236
1237 StartSector = LastStartSector + LastSectorCount;
1238 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1239
1240 /* Insert the table into the list */
1241 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1242 &PartEntry->ListEntry,
1243 StartSector,
1245 TRUE);
1246 if (!NewPartEntry)
1247 {
1248 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1249 return;
1250 }
1251 }
1252
1253 LastStartSector = PartEntry->StartSector.QuadPart;
1254 LastSectorCount = PartEntry->SectorCount.QuadPart;
1255 }
1256 }
1257
1258 /* Check for trailing unpartitioned disk space */
1259 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1260 {
1261 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
1262 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
1263 DiskEntry->SectorAlignment);
1264
1265 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1266 {
1267 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1268
1269 StartSector = LastStartSector + LastSectorCount;
1270 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1271
1272 /* Append the table to the list */
1273 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1274 &DiskEntry->LogicalPartListHead,
1275 StartSector,
1277 TRUE);
1278 if (!NewPartEntry)
1279 {
1280 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1281 return;
1282 }
1283 }
1284 }
1285 }
1286
1287 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1288}
1289
1290static
1291VOID
1294 IN PDISKENTRY DiskEntry)
1295{
1296 LARGE_INTEGER SystemTime;
1298 PLIST_ENTRY Entry2;
1299 PDISKENTRY DiskEntry2;
1300 PUCHAR Buffer;
1301
1302 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1303 {
1304 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1305 return;
1306 }
1307
1308 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1309
1310 while (TRUE)
1311 {
1312 NtQuerySystemTime(&SystemTime);
1313 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1314
1315 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1316 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1317 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1318 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1319
1320 if (DiskEntry->LayoutBuffer->Signature == 0)
1321 {
1322 continue;
1323 }
1324
1325 /* Check if the signature already exist */
1326 /* FIXME:
1327 * Check also signatures from disks, which are
1328 * not visible (bootable) by the BIOS.
1329 */
1330 for (Entry2 = List->DiskListHead.Flink;
1331 Entry2 != &List->DiskListHead;
1332 Entry2 = Entry2->Flink)
1333 {
1334 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1335
1336 if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT)
1337 {
1338 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1339 continue;
1340 }
1341
1342 if (DiskEntry != DiskEntry2 &&
1343 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1344 break;
1345 }
1346
1347 if (Entry2 == &List->DiskListHead)
1348 break;
1349 }
1350}
1351
1352static
1353VOID
1356{
1358 PDISKENTRY DiskEntry;
1359
1360 /* Update each disk */
1361 for (Entry = List->DiskListHead.Flink;
1362 Entry != &List->DiskListHead;
1363 Entry = Entry->Flink)
1364 {
1365 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1366
1367 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1368 {
1369 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1370 continue;
1371 }
1372
1373 if (DiskEntry->LayoutBuffer &&
1374 DiskEntry->LayoutBuffer->Signature == 0)
1375 {
1376 SetDiskSignature(List, DiskEntry);
1378 }
1379 }
1380}
1381
1382static
1383VOID
1386{
1387 PLIST_ENTRY ListEntry;
1388 PBIOSDISKENTRY BiosDiskEntry;
1389 PDISKENTRY DiskEntry;
1390 ULONG HwAdapterNumber = 0;
1391 ULONG HwControllerNumber = 0;
1392 ULONG RemovableDiskCount = 0;
1393
1394 /*
1395 * Enumerate the disks recognized by the BIOS and recompute the disk
1396 * numbers on the system when *ALL* removable disks are not connected.
1397 * The entries are inserted in increasing order of AdapterNumber,
1398 * ControllerNumber and DiskNumber.
1399 */
1400 for (ListEntry = List->BiosDiskListHead.Flink;
1401 ListEntry != &List->BiosDiskListHead;
1402 ListEntry = ListEntry->Flink)
1403 {
1404 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1405 DiskEntry = BiosDiskEntry->DiskEntry;
1406
1407 /*
1408 * If the adapter or controller numbers change, update them and reset
1409 * the number of removable disks on this adapter/controller.
1410 */
1411 if (HwAdapterNumber != BiosDiskEntry->AdapterNumber ||
1412 HwControllerNumber != BiosDiskEntry->ControllerNumber)
1413 {
1414 HwAdapterNumber = BiosDiskEntry->AdapterNumber;
1415 HwControllerNumber = BiosDiskEntry->ControllerNumber;
1416 RemovableDiskCount = 0;
1417 }
1418
1419 /* Adjust the actual hardware disk number */
1420 if (DiskEntry)
1421 {
1422 ASSERT(DiskEntry->HwDiskNumber == BiosDiskEntry->DiskNumber);
1423
1424 if (DiskEntry->MediaType == RemovableMedia)
1425 {
1426 /* Increase the number of removable disks and set the disk number to zero */
1427 ++RemovableDiskCount;
1428 DiskEntry->HwFixedDiskNumber = 0;
1429 }
1430 else // if (DiskEntry->MediaType == FixedMedia)
1431 {
1432 /* Adjust the fixed disk number, offset by the number of removable disks found before this one */
1433 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber - RemovableDiskCount;
1434 }
1435 }
1436 else
1437 {
1438 DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry->DiskNumber);
1439 }
1440 }
1441}
1442
1443static
1444VOID
1447 IN ULONG DiskNumber,
1449{
1450 DISK_GEOMETRY DiskGeometry;
1451 SCSI_ADDRESS ScsiAddress;
1452 PDISKENTRY DiskEntry;
1456 PULONG Buffer;
1458 WCHAR Identifier[20];
1459 ULONG Checksum;
1461 ULONG i;
1462 PLIST_ENTRY ListEntry;
1463 PBIOSDISKENTRY BiosDiskEntry;
1464 ULONG LayoutBufferSize;
1465 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1466
1467 /* Retrieve the drive geometry */
1469 NULL,
1470 NULL,
1471 NULL,
1472 &Iosb,
1474 NULL,
1475 0,
1476 &DiskGeometry,
1477 sizeof(DiskGeometry));
1478 if (!NT_SUCCESS(Status))
1479 return;
1480
1481 if (DiskGeometry.MediaType != FixedMedia &&
1482 DiskGeometry.MediaType != RemovableMedia)
1483 {
1484 return;
1485 }
1486
1487 /*
1488 * FIXME: Here we suppose the disk is always SCSI. What if it is
1489 * of another type? To check this we need to retrieve the name of
1490 * the driver the disk device belongs to.
1491 */
1493 NULL,
1494 NULL,
1495 NULL,
1496 &Iosb,
1498 NULL,
1499 0,
1500 &ScsiAddress,
1501 sizeof(ScsiAddress));
1502 if (!NT_SUCCESS(Status))
1503 return;
1504
1505 /*
1506 * Check whether the disk is initialized, by looking at its MBR.
1507 * NOTE that this must be generalized to GPT disks as well!
1508 */
1509
1511 0,
1512 DiskGeometry.BytesPerSector);
1513 if (Mbr == NULL)
1514 return;
1515
1516 FileOffset.QuadPart = 0;
1518 NULL,
1519 NULL,
1520 NULL,
1521 &Iosb,
1522 (PVOID)Mbr,
1523 DiskGeometry.BytesPerSector,
1524 &FileOffset,
1525 NULL);
1526 if (!NT_SUCCESS(Status))
1527 {
1528 RtlFreeHeap(ProcessHeap, 0, Mbr);
1529 DPRINT1("NtReadFile failed, status=%x\n", Status);
1530 return;
1531 }
1532 Signature = Mbr->Signature;
1533
1534 /* Calculate the MBR checksum */
1535 Checksum = 0;
1536 Buffer = (PULONG)Mbr;
1537 for (i = 0; i < 128; i++)
1538 {
1539 Checksum += Buffer[i];
1540 }
1541 Checksum = ~Checksum + 1;
1542
1544 L"%08x-%08x-%c",
1545 Checksum, Signature,
1546 (Mbr->Magic == PARTITION_MAGIC) ? L'A' : L'X');
1547 DPRINT("Identifier: %S\n", Identifier);
1548
1549 DiskEntry = RtlAllocateHeap(ProcessHeap,
1551 sizeof(DISKENTRY));
1552 if (DiskEntry == NULL)
1553 {
1554 RtlFreeHeap(ProcessHeap, 0, Mbr);
1555 DPRINT1("Failed to allocate a new disk entry.\n");
1556 return;
1557 }
1558
1559 DiskEntry->PartList = List;
1560
1561#if 0
1562 {
1563 FILE_FS_DEVICE_INFORMATION FileFsDevice;
1564
1565 /* Query the device for its type */
1567 &Iosb,
1568 &FileFsDevice,
1569 sizeof(FileFsDevice),
1571 if (!NT_SUCCESS(Status))
1572 {
1573 DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber, Identifier);
1574 }
1575 else
1576 {
1577 DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber, FileFsDevice.DeviceType, FileFsDevice.Characteristics);
1578 }
1579 }
1580 // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation).
1581#endif
1582 DiskEntry->MediaType = DiskGeometry.MediaType;
1583 if (DiskEntry->MediaType == RemovableMedia)
1584 {
1585 DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber, Identifier);
1586 }
1587 else // if (DiskEntry->MediaType == FixedMedia)
1588 {
1589 DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber, Identifier);
1590 }
1591
1592// DiskEntry->Checksum = Checksum;
1593// DiskEntry->Signature = Signature;
1594 DiskEntry->BiosFound = FALSE;
1595
1596 /*
1597 * Check if this disk has a valid MBR: verify its signature,
1598 * and whether its two first bytes are a valid instruction
1599 * (related to this, see IsThereAValidBootSector() in partlist.c).
1600 *
1601 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1602 */
1603
1604 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1605
1606 /* If we have not the 0xAA55 then it's raw partition */
1607 if (Mbr->Magic != PARTITION_MAGIC)
1608 {
1609 DiskEntry->DiskStyle = PARTITION_STYLE_RAW;
1610 }
1611 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1612 else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
1613 Mbr->Partition[1].PartitionType == 0 &&
1614 Mbr->Partition[2].PartitionType == 0 &&
1615 Mbr->Partition[3].PartitionType == 0)
1616 {
1617 DiskEntry->DiskStyle = PARTITION_STYLE_GPT;
1618 }
1619 /* Otherwise, partition table is in MBR */
1620 else
1621 {
1622 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
1623 }
1624
1625 /* Free the MBR sector buffer */
1626 RtlFreeHeap(ProcessHeap, 0, Mbr);
1627
1628
1629 for (ListEntry = List->BiosDiskListHead.Flink;
1630 ListEntry != &List->BiosDiskListHead;
1631 ListEntry = ListEntry->Flink)
1632 {
1633 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1634 /* FIXME:
1635 * Compare the size from BIOS and the reported size from driver.
1636 * If we have more than one disk with a zero or with the same signature
1637 * we must create new signatures and reboot. After the reboot,
1638 * it is possible to identify the disks.
1639 */
1640 if (BiosDiskEntry->Signature == Signature &&
1641 BiosDiskEntry->Checksum == Checksum &&
1642 BiosDiskEntry->DiskEntry == NULL)
1643 {
1644 if (!DiskEntry->BiosFound)
1645 {
1646 DiskEntry->HwAdapterNumber = BiosDiskEntry->AdapterNumber;
1647 DiskEntry->HwControllerNumber = BiosDiskEntry->ControllerNumber;
1648 DiskEntry->HwDiskNumber = BiosDiskEntry->DiskNumber;
1649
1650 if (DiskEntry->MediaType == RemovableMedia)
1651 {
1652 /* Set the removable disk number to zero */
1653 DiskEntry->HwFixedDiskNumber = 0;
1654 }
1655 else // if (DiskEntry->MediaType == FixedMedia)
1656 {
1657 /* The fixed disk number will later be adjusted using the number of removable disks */
1658 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber;
1659 }
1660
1661 DiskEntry->BiosFound = TRUE;
1662 BiosDiskEntry->DiskEntry = DiskEntry;
1663 break;
1664 }
1665 else
1666 {
1667 // FIXME: What to do?
1668 DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber, Identifier);
1669 }
1670 }
1671 }
1672
1673 if (!DiskEntry->BiosFound)
1674 {
1675 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber);
1676 }
1677
1678 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1679 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1680 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1681 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1682
1683 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1684 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1685 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1686 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1687
1688 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1689 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1690 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1691
1692 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1693 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1694 DiskGeometry.SectorsPerTrack;
1695
1696 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1697 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1698
1699 DiskEntry->DiskNumber = DiskNumber;
1700 DiskEntry->Port = ScsiAddress.PortNumber;
1701 DiskEntry->Bus = ScsiAddress.PathId;
1702 DiskEntry->Id = ScsiAddress.TargetId;
1703
1704 GetDriverName(DiskEntry);
1705 /*
1706 * Actually it would be more correct somehow to use:
1707 *
1708 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1709 * ULONG ReturnedLength;
1710 *
1711 * Status = NtQueryObject(SomeHandleToTheDisk,
1712 * ObjectNameInformation,
1713 * &NameInfo,
1714 * sizeof(NameInfo),
1715 * &ReturnedLength);
1716 * etc...
1717 *
1718 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1719 */
1720
1723
1724 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1725
1726
1727 /*
1728 * We now retrieve the disk partition layout
1729 */
1730
1731 /*
1732 * Stop there now if the disk is GPT-partitioned,
1733 * since we currently do not support such disks.
1734 */
1735 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1736 {
1737 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1738 return;
1739 }
1740
1741 /* Allocate a layout buffer with 4 partition entries first */
1742 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1743 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1746 LayoutBufferSize);
1747 if (DiskEntry->LayoutBuffer == NULL)
1748 {
1749 DPRINT1("Failed to allocate the disk layout buffer!\n");
1750 return;
1751 }
1752
1753 /* Keep looping while the drive layout buffer is too small */
1754 for (;;)
1755 {
1756 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1758 NULL,
1759 NULL,
1760 NULL,
1761 &Iosb,
1763 NULL,
1764 0,
1765 DiskEntry->LayoutBuffer,
1766 LayoutBufferSize);
1767 if (NT_SUCCESS(Status))
1768 break;
1769
1771 {
1772 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1773 return;
1774 }
1775
1776 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1777 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1779 DiskEntry->LayoutBuffer,
1780 LayoutBufferSize);
1781 if (NewLayoutBuffer == NULL)
1782 {
1783 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1784 return;
1785 }
1786
1787 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1788 }
1789
1790 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1791
1792#ifdef DUMP_PARTITION_TABLE
1793 DumpPartitionTable(DiskEntry);
1794#endif
1795
1796 if (IsSuperFloppy(DiskEntry))
1797 DPRINT1("Disk %lu is a super-floppy\n", DiskNumber);
1798
1799 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1802 {
1803 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1804 {
1805 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1806 }
1807 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1808 {
1809 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1810 }
1811 else
1812 {
1813 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1814 }
1815 }
1816 else
1817 {
1818 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1819 }
1820
1821 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1822 {
1823 DiskEntry->NewDisk = TRUE;
1824 DiskEntry->LayoutBuffer->PartitionCount = 4;
1825
1826 for (i = 0; i < 4; i++)
1827 {
1829 }
1830 }
1831 else
1832 {
1833 /* Enumerate and add the first four primary partitions */
1834 for (i = 0; i < 4; i++)
1835 {
1836 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1837 }
1838
1839 /* Enumerate and add the remaining partitions as logical ones */
1840 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1841 {
1842 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1843 }
1844 }
1845
1847}
1848
1849/*
1850 * Retrieve the system disk, i.e. the fixed disk that is accessible by the
1851 * firmware during boot time and where the system partition resides.
1852 * If no system partition has been determined, we retrieve the first disk
1853 * that verifies the mentioned criteria above.
1854 */
1855static
1859{
1861 PDISKENTRY DiskEntry;
1862
1863 /* Check for empty disk list */
1864 if (IsListEmpty(&List->DiskListHead))
1865 return NULL;
1866
1867 /*
1868 * If we already have a system partition, the system disk
1869 * is the one on which the system partition resides.
1870 */
1871 if (List->SystemPartition)
1872 return List->SystemPartition->DiskEntry;
1873
1874 /* Loop over the disks and find the correct one */
1875 for (Entry = List->DiskListHead.Flink;
1876 Entry != &List->DiskListHead;
1877 Entry = Entry->Flink)
1878 {
1879 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1880
1881 /* The disk must be a fixed disk and be found by the firmware */
1882 if (DiskEntry->MediaType == FixedMedia && DiskEntry->BiosFound)
1883 {
1884 break;
1885 }
1886 }
1887 if (Entry == &List->DiskListHead)
1888 {
1889 /* We haven't encountered any suitable disk */
1890 return NULL;
1891 }
1892
1893 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1894 {
1895 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
1896 }
1897
1898 return DiskEntry;
1899}
1900
1901/*
1902 * Retrieve the actual "active" partition of the given disk.
1903 * On MBR disks, partition with the Active/Boot flag set;
1904 * on GPT disks, partition with the correct GUID.
1905 */
1906BOOLEAN
1908 IN PPARTENTRY PartEntry)
1909{
1910 // TODO: Support for GPT disks!
1911
1912 if (IsContainerPartition(PartEntry->PartitionType))
1913 return FALSE;
1914
1915 /* Check if the partition is partitioned, used and active */
1916 if (PartEntry->IsPartitioned &&
1917 // !IsContainerPartition(PartEntry->PartitionType) &&
1918 PartEntry->BootIndicator)
1919 {
1920 /* Yes it is */
1921 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
1922 return TRUE;
1923 }
1924
1925 return FALSE;
1926}
1927
1928static
1931 IN PDISKENTRY DiskEntry)
1932{
1933 PLIST_ENTRY ListEntry;
1934 PPARTENTRY PartEntry;
1935 PPARTENTRY ActivePartition = NULL;
1936
1937 /* Check for empty disk list */
1938 // ASSERT(DiskEntry);
1939 if (!DiskEntry)
1940 return NULL;
1941
1942 /* Check for empty partition list */
1943 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1944 return NULL;
1945
1946 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1947 {
1948 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1949 return NULL;
1950 }
1951
1952 /* Scan all (primary) partitions to find the active disk partition */
1953 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
1954 ListEntry != &DiskEntry->PrimaryPartListHead;
1955 ListEntry = ListEntry->Flink)
1956 {
1957 /* Retrieve the partition */
1958 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
1959 if (IsPartitionActive(PartEntry))
1960 {
1961 /* Yes, we've found it */
1962 ASSERT(DiskEntry == PartEntry->DiskEntry);
1963 ASSERT(PartEntry->IsPartitioned);
1964 ASSERT(PartEntry->Volume);
1965
1966 ActivePartition = PartEntry;
1967
1968 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
1969 PartEntry->PartitionNumber, DiskEntry->DiskNumber,
1970 !PartEntry->Volume->Info.DriveLetter ? L'-' : PartEntry->Volume->Info.DriveLetter);
1971 break;
1972 }
1973 }
1974
1975 /* Check if the disk is new and if so, use its first partition as the active system partition */
1976 if (DiskEntry->NewDisk && ActivePartition != NULL)
1977 {
1978 // FIXME: What to do??
1979 DPRINT1("NewDisk TRUE but already existing active partition?\n");
1980 }
1981
1982 /* Return the active partition found (or none) */
1983 return ActivePartition;
1984}
1985
1988{
1990 PDISKENTRY SystemDisk;
1994 ULONG ReturnSize;
1996 ULONG DiskNumber;
2000
2002 0,
2003 sizeof(PARTLIST));
2004 if (!List)
2005 return NULL;
2006
2007 List->SystemPartition = NULL;
2008
2009 InitializeListHead(&List->DiskListHead);
2010 InitializeListHead(&List->BiosDiskListHead);
2011 InitializeListHead(&List->VolumesList);
2012
2013 /*
2014 * Enumerate the disks seen by the BIOS; this will be used later
2015 * to map drives seen by NTOS with their corresponding BIOS names.
2016 */
2018
2019 /* Enumerate disks seen by NTOS */
2021 &Sdi,
2022 sizeof(Sdi),
2023 &ReturnSize);
2024 if (!NT_SUCCESS(Status))
2025 {
2026 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx\n", Status);
2028 return NULL;
2029 }
2030
2031 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
2032 {
2034 L"\\Device\\Harddisk%lu\\Partition0",
2035 DiskNumber);
2037
2039 &Name,
2041 NULL,
2042 NULL);
2043
2047 &Iosb,
2050 if (NT_SUCCESS(Status))
2051 {
2052 AddDiskToList(FileHandle, DiskNumber, List);
2054 }
2055 }
2056
2060
2061 /*
2062 * Retrieve the system partition: the active partition on the system
2063 * disk (the one that will be booted by default by the hardware).
2064 */
2065 SystemDisk = GetSystemDisk(List);
2066 List->SystemPartition = (SystemDisk ? GetActiveDiskPartition(SystemDisk) : NULL);
2067
2068 return List;
2069}
2070
2071VOID
2074{
2075 PDISKENTRY DiskEntry;
2076 PBIOSDISKENTRY BiosDiskEntry;
2077 PPARTENTRY PartEntry;
2079
2080 /* Release disk and partition info */
2081 while (!IsListEmpty(&List->DiskListHead))
2082 {
2083 Entry = RemoveHeadList(&List->DiskListHead);
2084 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2085
2086 /* Release driver name */
2087 RtlFreeUnicodeString(&DiskEntry->DriverName);
2088
2089 /* Release primary partition list */
2090 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
2091 {
2093 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2094 DestroyRegion(PartEntry);
2095 }
2096
2097 /* Release logical partition list */
2098 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2099 {
2101 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2102 DestroyRegion(PartEntry);
2103 }
2104
2105 /* Release layout buffer */
2106 if (DiskEntry->LayoutBuffer != NULL)
2107 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
2108
2109 /* Release disk entry */
2110 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
2111 }
2112
2113 /* Release the BIOS disk info */
2114 while (!IsListEmpty(&List->BiosDiskListHead))
2115 {
2116 Entry = RemoveHeadList(&List->BiosDiskListHead);
2117 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
2118 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
2119 }
2120
2121 /* Release list head */
2123}
2124
2128 _In_ ULONG HwDiskNumber)
2129{
2130 PDISKENTRY DiskEntry;
2132
2133 /* Loop over the disks and find the correct one */
2134 for (Entry = List->DiskListHead.Flink;
2135 Entry != &List->DiskListHead;
2136 Entry = Entry->Flink)
2137 {
2138 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2139
2140 if (DiskEntry->HwDiskNumber == HwDiskNumber)
2141 return DiskEntry; /* Disk found, return it */
2142 }
2143
2144 /* Disk not found, stop there */
2145 return NULL;
2146}
2147
2151 _In_ ULONG DiskNumber)
2152{
2153 PDISKENTRY DiskEntry;
2155
2156 /* Loop over the disks and find the correct one */
2157 for (Entry = List->DiskListHead.Flink;
2158 Entry != &List->DiskListHead;
2159 Entry = Entry->Flink)
2160 {
2161 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2162
2163 if (DiskEntry->DiskNumber == DiskNumber)
2164 return DiskEntry; /* Disk found, return it */
2165 }
2166
2167 /* Disk not found, stop there */
2168 return NULL;
2169}
2170
2175 _In_ USHORT Bus,
2176 _In_ USHORT Id)
2177{
2178 PDISKENTRY DiskEntry;
2180
2181 /* Loop over the disks and find the correct one */
2182 for (Entry = List->DiskListHead.Flink;
2183 Entry != &List->DiskListHead;
2184 Entry = Entry->Flink)
2185 {
2186 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2187
2188 if (DiskEntry->Port == Port &&
2189 DiskEntry->Bus == Bus &&
2190 DiskEntry->Id == Id)
2191 {
2192 /* Disk found, return it */
2193 return DiskEntry;
2194 }
2195 }
2196
2197 /* Disk not found, stop there */
2198 return NULL;
2199}
2200
2205{
2206 PDISKENTRY DiskEntry;
2208
2209 /* Loop over the disks and find the correct one */
2210 for (Entry = List->DiskListHead.Flink;
2211 Entry != &List->DiskListHead;
2212 Entry = Entry->Flink)
2213 {
2214 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2215
2216 if (DiskEntry->LayoutBuffer->Signature == Signature)
2217 return DiskEntry; /* Disk found, return it */
2218 }
2219
2220 /* Disk not found, stop there */
2221 return NULL;
2222}
2223
2226 _In_ PDISKENTRY DiskEntry,
2228{
2229 PPARTENTRY PartEntry;
2231
2232 /* Forbid whole-disk or extended container partition access */
2233 if (PartitionNumber == 0)
2234 return NULL;
2235
2236 /* Loop over the primary partitions first... */
2237 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2238 Entry != &DiskEntry->PrimaryPartListHead;
2239 Entry = Entry->Flink)
2240 {
2241 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2242
2243 if (PartEntry->PartitionNumber == PartitionNumber)
2244 return PartEntry; /* Partition found, return it */
2245 }
2246
2247 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2248 return NULL;
2249
2250 /* ... then over the logical partitions if needed */
2251 for (Entry = DiskEntry->LogicalPartListHead.Flink;
2252 Entry != &DiskEntry->LogicalPartListHead;
2253 Entry = Entry->Flink)
2254 {
2255 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2256
2257 if (PartEntry->PartitionNumber == PartitionNumber)
2258 return PartEntry; /* Partition found, return it */
2259 }
2260
2261 /* The partition was not found on the disk, stop there */
2262 return NULL;
2263}
2264
2268 _In_ ULONG DiskNumber,
2270{
2271 PDISKENTRY DiskEntry;
2272 PPARTENTRY PartEntry;
2273
2274 /* Find the disk */
2275 DiskEntry = GetDiskByNumber(List, DiskNumber);
2276 if (!DiskEntry)
2277 return NULL;
2278 ASSERT(DiskEntry->DiskNumber == DiskNumber);
2279
2280 /* Find the partition */
2281 PartEntry = GetPartition(DiskEntry, PartitionNumber);
2282 if (!PartEntry)
2283 return NULL;
2284 ASSERT(PartEntry->DiskEntry == DiskEntry);
2285 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
2286
2287 return PartEntry;
2288}
2289
2293 IN PPARTENTRY CurrentPart OPTIONAL)
2294{
2295 PLIST_ENTRY DiskListEntry;
2296 PLIST_ENTRY PartListEntry;
2298
2299 /* Fail if no disks are available */
2300 if (IsListEmpty(&List->DiskListHead))
2301 return NULL;
2302
2303 /* Check for the next usable entry on the current partition's disk */
2304 if (CurrentPart != NULL)
2305 {
2306 CurrentDisk = CurrentPart->DiskEntry;
2307
2308 if (CurrentPart->LogicalPartition)
2309 {
2310 /* Logical partition */
2311
2312 PartListEntry = CurrentPart->ListEntry.Flink;
2313 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2314 {
2315 /* Next logical partition */
2316 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2317 return CurrentPart;
2318 }
2319 else
2320 {
2321 PartListEntry = CurrentDisk->ExtendedPartition->ListEntry.Flink;
2322 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2323 {
2324 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2325 return CurrentPart;
2326 }
2327 }
2328 }
2329 else
2330 {
2331 /* Primary or extended partition */
2332
2333 if (CurrentPart->IsPartitioned &&
2334 IsContainerPartition(CurrentPart->PartitionType))
2335 {
2336 /* First logical partition */
2337 PartListEntry = CurrentDisk->LogicalPartListHead.Flink;
2338 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2339 {
2340 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2341 return CurrentPart;
2342 }
2343 }
2344 else
2345 {
2346 /* Next primary partition */
2347 PartListEntry = CurrentPart->ListEntry.Flink;
2348 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2349 {
2350 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2351 return CurrentPart;
2352 }
2353 }
2354 }
2355 }
2356
2357 /* Search for the first partition entry on the next disk */
2358 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Flink
2359 : List->DiskListHead.Flink);
2360 DiskListEntry != &List->DiskListHead;
2361 DiskListEntry = DiskListEntry->Flink)
2362 {
2363 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2364
2366 {
2367 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2368 continue;
2369 }
2370
2371 PartListEntry = CurrentDisk->PrimaryPartListHead.Flink;
2372 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2373 {
2374 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2375 return CurrentPart;
2376 }
2377 }
2378
2379 return NULL;
2380}
2381
2385 IN PPARTENTRY CurrentPart OPTIONAL)
2386{
2387 PLIST_ENTRY DiskListEntry;
2388 PLIST_ENTRY PartListEntry;
2390
2391 /* Fail if no disks are available */
2392 if (IsListEmpty(&List->DiskListHead))
2393 return NULL;
2394
2395 /* Check for the previous usable entry on the current partition's disk */
2396 if (CurrentPart != NULL)
2397 {
2398 CurrentDisk = CurrentPart->DiskEntry;
2399
2400 if (CurrentPart->LogicalPartition)
2401 {
2402 /* Logical partition */
2403
2404 PartListEntry = CurrentPart->ListEntry.Blink;
2405 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2406 {
2407 /* Previous logical partition */
2408 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2409 }
2410 else
2411 {
2412 /* Extended partition */
2413 CurrentPart = CurrentDisk->ExtendedPartition;
2414 }
2415 return CurrentPart;
2416 }
2417 else
2418 {
2419 /* Primary or extended partition */
2420
2421 PartListEntry = CurrentPart->ListEntry.Blink;
2422 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2423 {
2424 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2425
2426 if (CurrentPart->IsPartitioned &&
2427 IsContainerPartition(CurrentPart->PartitionType))
2428 {
2429 PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
2430 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2431 }
2432
2433 return CurrentPart;
2434 }
2435 }
2436 }
2437
2438 /* Search for the last partition entry on the previous disk */
2439 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Blink
2440 : List->DiskListHead.Blink);
2441 DiskListEntry != &List->DiskListHead;
2442 DiskListEntry = DiskListEntry->Blink)
2443 {
2444 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2445
2447 {
2448 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2449 continue;
2450 }
2451
2452 PartListEntry = CurrentDisk->PrimaryPartListHead.Blink;
2453 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2454 {
2455 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2456
2457 if (CurrentPart->IsPartitioned &&
2458 IsContainerPartition(CurrentPart->PartitionType))
2459 {
2460 PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
2461 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2462 {
2463 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2464 return CurrentPart;
2465 }
2466 }
2467 else
2468 {
2469 return CurrentPart;
2470 }
2471 }
2472 }
2473
2474 return NULL;
2475}
2476
2477static inline
2478BOOLEAN
2481{
2482 return (PartitionInfo->StartingOffset.QuadPart == 0 &&
2483 PartitionInfo->PartitionLength.QuadPart == 0);
2484}
2485
2486static inline
2487BOOLEAN
2490 _In_ PPARTENTRY PartEntry)
2491{
2492 return ((PartitionInfo->StartingOffset.QuadPart == GetPartEntryOffsetInBytes(PartEntry)) &&
2493 (PartitionInfo->PartitionLength.QuadPart == GetPartEntrySizeInBytes(PartEntry)));
2494// PartitionInfo->PartitionType == PartEntry->PartitionType
2495}
2496
2497
2502static
2503ULONG
2505 _In_ PLIST_ENTRY PartListHead)
2506{
2508 PPARTENTRY PartEntry;
2509 ULONG Count = 0;
2510
2511 for (Entry = PartListHead->Flink;
2512 Entry != PartListHead;
2513 Entry = Entry->Flink)
2514 {
2515 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2516 if (PartEntry->IsPartitioned)
2517 ++Count;
2518 }
2519
2520 return Count;
2521}
2522
2523#define GetPrimaryPartitionCount(DiskEntry) \
2524 GetPartitionCount(&(DiskEntry)->PrimaryPartListHead)
2525
2526#define GetLogicalPartitionCount(DiskEntry) \
2527 (((DiskEntry)->DiskStyle == PARTITION_STYLE_MBR) \
2528 ? GetPartitionCount(&(DiskEntry)->LogicalPartListHead) : 0)
2529
2530
2531static
2532BOOLEAN
2534 IN PDISKENTRY DiskEntry)
2535{
2536 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2537 ULONG NewPartitionCount;
2538 ULONG CurrentPartitionCount = 0;
2539 ULONG LayoutBufferSize;
2540 ULONG i;
2541
2542 DPRINT1("ReAllocateLayoutBuffer()\n");
2543
2544 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2545
2546 if (DiskEntry->LayoutBuffer)
2547 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2548
2549 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2550 CurrentPartitionCount, NewPartitionCount);
2551
2552 if (CurrentPartitionCount == NewPartitionCount)
2553 return TRUE;
2554
2555 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2556 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2557 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2559 DiskEntry->LayoutBuffer,
2560 LayoutBufferSize);
2561 if (NewLayoutBuffer == NULL)
2562 {
2563 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2564 return FALSE;
2565 }
2566
2567 NewLayoutBuffer->PartitionCount = NewPartitionCount;
2568
2569 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2570 if (NewPartitionCount > CurrentPartitionCount)
2571 {
2572 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2573 {
2574 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2575 }
2576 }
2577
2578 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2579
2580 return TRUE;
2581}
2582
2583static
2584VOID
2586 IN PDISKENTRY DiskEntry)
2587{
2589 PPARTITION_INFORMATION LinkInfo;
2590 PLIST_ENTRY ListEntry;
2591 PPARTENTRY PartEntry;
2592 LARGE_INTEGER HiddenSectors64;
2593 ULONG Index;
2595
2596 DPRINT1("UpdateDiskLayout()\n");
2597
2598 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2599 {
2600 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2601 return;
2602 }
2603
2604 /* Resize the layout buffer if necessary */
2605 if (!ReAllocateLayoutBuffer(DiskEntry))
2606 {
2607 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2608 return;
2609 }
2610
2611 /* Update the primary partition table */
2612 Index = 0;
2613 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2614 ListEntry != &DiskEntry->PrimaryPartListHead;
2615 ListEntry = ListEntry->Flink)
2616 {
2617 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2618
2619 if (PartEntry->IsPartitioned)
2620 {
2622
2623 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2624 PartEntry->PartitionIndex = Index;
2625
2626 /* Reset the current partition number only for not-yet written partitions */
2627 if (PartEntry->New)
2628 PartEntry->PartitionNumber = 0;
2629
2631
2632 if (!IsSamePrimaryLayoutEntry(PartitionInfo, PartEntry))
2633 {
2634 DPRINT1("Updating primary partition entry %lu\n", Index);
2635
2636 PartitionInfo->StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry);
2637 PartitionInfo->PartitionLength.QuadPart = GetPartEntrySizeInBytes(PartEntry);
2638 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2639 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2640 PartitionInfo->PartitionType = PartEntry->PartitionType;
2641 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2642 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2643 PartitionInfo->RewritePartition = TRUE;
2644 }
2645
2646 if (!IsContainerPartition(PartEntry->PartitionType))
2648
2649 Index++;
2650 }
2651 }
2652
2653 ASSERT(Index <= 4);
2654
2655 /* Update the logical partition table */
2656 LinkInfo = NULL;
2657 Index = 4;
2658 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2659 ListEntry != &DiskEntry->LogicalPartListHead;
2660 ListEntry = ListEntry->Flink)
2661 {
2662 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2663
2664 if (PartEntry->IsPartitioned)
2665 {
2667
2668 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2669 PartEntry->PartitionIndex = Index;
2670
2671 /* Reset the current partition number only for not-yet written partitions */
2672 if (PartEntry->New)
2673 PartEntry->PartitionNumber = 0;
2674
2676
2677 DPRINT1("Updating logical partition entry %lu\n", Index);
2678
2679 PartitionInfo->StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry);
2680 PartitionInfo->PartitionLength.QuadPart = GetPartEntrySizeInBytes(PartEntry);
2681 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2682 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2683 PartitionInfo->PartitionType = PartEntry->PartitionType;
2684 PartitionInfo->BootIndicator = FALSE;
2685 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2686 PartitionInfo->RewritePartition = TRUE;
2687
2688 /* Fill the link entry of the previous partition entry */
2689 if (LinkInfo)
2690 {
2691 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2692 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2693 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2694 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2695 LinkInfo->PartitionNumber = 0;
2696
2697 /* Extended partition links only use type 0x05, as observed
2698 * on Windows NT. Alternatively they could inherit the type
2699 * of the main extended container. */
2700 LinkInfo->PartitionType = PARTITION_EXTENDED; // DiskEntry->ExtendedPartition->PartitionType;
2701
2702 LinkInfo->BootIndicator = FALSE;
2703 LinkInfo->RecognizedPartition = FALSE;
2704 LinkInfo->RewritePartition = TRUE;
2705 }
2706
2707 /* Save a pointer to the link entry of the current partition entry */
2708 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2709
2711 Index += 4;
2712 }
2713 }
2714
2715 /* Wipe unused primary partition entries */
2716 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2717 {
2718 DPRINT1("Primary partition entry %lu\n", Index);
2719
2720 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2721
2723 {
2724 DPRINT1("Wiping primary partition entry %lu\n", Index);
2725
2726 PartitionInfo->StartingOffset.QuadPart = 0;
2727 PartitionInfo->PartitionLength.QuadPart = 0;
2728 PartitionInfo->HiddenSectors = 0;
2729 PartitionInfo->PartitionNumber = 0;
2730 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2731 PartitionInfo->BootIndicator = FALSE;
2732 PartitionInfo->RecognizedPartition = FALSE;
2733 PartitionInfo->RewritePartition = TRUE;
2734 }
2735 }
2736
2737 /* Wipe unused logical partition entries */
2738 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2739 {
2740 if (Index % 4 >= 2)
2741 {
2742 DPRINT1("Logical partition entry %lu\n", Index);
2743
2744 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2745
2747 {
2748 DPRINT1("Wiping partition entry %lu\n", Index);
2749
2750 PartitionInfo->StartingOffset.QuadPart = 0;
2751 PartitionInfo->PartitionLength.QuadPart = 0;
2752 PartitionInfo->HiddenSectors = 0;
2753 PartitionInfo->PartitionNumber = 0;
2754 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2755 PartitionInfo->BootIndicator = FALSE;
2756 PartitionInfo->RecognizedPartition = FALSE;
2757 PartitionInfo->RewritePartition = TRUE;
2758 }
2759 }
2760 }
2761
2762 // HACK: See the FIXMEs in WritePartitions(): (Re)set the PartitionStyle to MBR.
2763 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
2764
2765 DiskEntry->Dirty = TRUE;
2766
2767#ifdef DUMP_PARTITION_TABLE
2768 DumpPartitionTable(DiskEntry);
2769#endif
2770}
2771
2787 _In_ PPARTENTRY PartEntry,
2789{
2790 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2791 PLIST_ENTRY ListHead, AdjEntry;
2792
2793 /* In case of MBR disks only, check the logical partitions if necessary */
2794 if ((DiskEntry->DiskStyle == PARTITION_STYLE_MBR) &&
2795 PartEntry->LogicalPartition)
2796 {
2797 ListHead = &DiskEntry->LogicalPartListHead;
2798 }
2799 else
2800 {
2801 ListHead = &DiskEntry->PrimaryPartListHead;
2802 }
2803
2804 if (Direction)
2805 AdjEntry = PartEntry->ListEntry.Flink; // Next region.
2806 else
2807 AdjEntry = PartEntry->ListEntry.Blink; // Previous region.
2808
2809 if (AdjEntry != ListHead)
2810 {
2811 PartEntry = CONTAINING_RECORD(AdjEntry, PARTENTRY, ListEntry);
2812 if (!PartEntry->IsPartitioned)
2813 {
2814 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
2815 return PartEntry;
2816 }
2817 }
2818 return NULL;
2819}
2820
2823 _In_ PPARTENTRY PartEntry)
2824{
2825 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2826
2827 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2828 {
2829 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2830 return ERROR_WARN_PARTITION;
2831 }
2832
2833 /* Fail if the partition is already in use */
2834 if (PartEntry->IsPartitioned)
2835 return ERROR_NEW_PARTITION;
2836
2837 /*
2838 * For primary partitions
2839 */
2840 if (!PartEntry->LogicalPartition)
2841 {
2842 /* Only one primary partition is allowed on super-floppy */
2843 if (IsSuperFloppy(DiskEntry))
2845
2846 /* Fail if there are already 4 primary partitions in the list */
2847 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
2849 }
2850 /*
2851 * For logical partitions
2852 */
2853 else
2854 {
2855 // TODO: Check that we are inside an extended partition!!
2856 // Then the following check will be useless.
2857
2858 /* Only one (primary) partition is allowed on super-floppy */
2859 if (IsSuperFloppy(DiskEntry))
2861 }
2862
2863 return ERROR_SUCCESS;
2864}
2865
2868 _In_ PPARTENTRY PartEntry)
2869{
2870 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2871
2872 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2873 {
2874 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2875 return ERROR_WARN_PARTITION;
2876 }
2877
2878 /* Fail if the partition is already in use */
2879 if (PartEntry->IsPartitioned)
2880 return ERROR_NEW_PARTITION;
2881
2882 /* Cannot create an extended partition within logical partition space */
2883 if (PartEntry->LogicalPartition)
2885
2886 /* Only one primary partition is allowed on super-floppy */
2887 if (IsSuperFloppy(DiskEntry))
2889
2890 /* Fail if there are already 4 primary partitions in the list */
2891 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
2893
2894 /* Fail if there is another extended partition in the list */
2895 if (DiskEntry->ExtendedPartition)
2897
2898 return ERROR_SUCCESS;
2899}
2900
2901// TODO: Improve upon the PartitionInfo parameter later
2902// (see VDS::CREATE_PARTITION_PARAMETERS and PPARTITION_INFORMATION_MBR/GPT for example)
2903// So far we only use it as the optional type of the partition to create.
2904BOOLEAN
2907 _Inout_ PPARTENTRY PartEntry,
2908 _In_opt_ ULONGLONG SizeBytes,
2910{
2913 PDISKENTRY DiskEntry;
2914 PCSTR mainType = "Primary";
2915
2916 if (isContainer)
2917 mainType = "Extended";
2918 else if (PartEntry && PartEntry->LogicalPartition)
2919 mainType = "Logical";
2920
2921 DPRINT1("CreatePartition(%s, %I64u bytes)\n", mainType, SizeBytes);
2922
2923 if (!List || !PartEntry ||
2924 !PartEntry->DiskEntry || PartEntry->IsPartitioned)
2925 {
2926 return FALSE;
2927 }
2928
2929 if (isContainer)
2931 else
2932 Error = PartitionCreationChecks(PartEntry);
2933 if (Error != NOT_AN_ERROR)
2934 {
2935 DPRINT1("PartitionCreationChecks(%s) failed with error %lu\n", mainType, Error);
2936 return FALSE;
2937 }
2938
2939 /* Initialize the partition entry, inserting a new blank region if needed */
2940 if (!InitializePartitionEntry(PartEntry, SizeBytes, PartitionInfo))
2941 return FALSE;
2942
2943 DiskEntry = PartEntry->DiskEntry;
2944 UpdateDiskLayout(DiskEntry);
2945
2946 ASSERT(!PartEntry->Volume);
2947 if (!isContainer)
2948 {
2949 /* We create a primary/logical partition: initialize a new basic
2950 * volume entry. When the partition will actually be written onto
2951 * the disk, the PARTMGR will notify the MOUNTMGR that a volume
2952 * associated with this partition has to be created. */
2953 PartEntry->Volume = InitVolume(DiskEntry->PartList, PartEntry);
2954 ASSERT(PartEntry->Volume);
2955 }
2956
2958
2959 return TRUE;
2960}
2961
2962static NTSTATUS
2965 _In_ PPARTENTRY PartEntry)
2966{
2968 PVOLENTRY Volume = PartEntry->Volume;
2969
2970 ASSERT(PartEntry->DiskEntry->PartList == List);
2971
2972 /* Check whether the partition is valid and was mounted by the system */
2973 if (!PartEntry->IsPartitioned ||
2974 IsContainerPartition(PartEntry->PartitionType) ||
2975 !IsRecognizedPartition(PartEntry->PartitionType) ||
2976 !Volume || Volume->FormatState == UnknownFormat ||
2977 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means
2978 // it has been usually mounted with RawFS and thus needs to be dismounted.
2979 PartEntry->PartitionNumber == 0)
2980 {
2981 /* The partition is not mounted, so just return success */
2982 return STATUS_SUCCESS;
2983 }
2984
2985 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
2986 ASSERT(Volume->PartEntry == PartEntry);
2987
2988 /* Unlink the basic volume from the volumes list and dismount it */
2989 PartEntry->Volume = NULL;
2990 Volume->PartEntry = NULL;
2991 RemoveEntryList(&Volume->ListEntry);
2992 Status = DismountVolume(&Volume->Info, TRUE);
2994 return Status;
2995}
2996
2997BOOLEAN
3000 _In_ PPARTENTRY PartEntry,
3001 _Out_opt_ PPARTENTRY* FreeRegion)
3002{
3003 PDISKENTRY DiskEntry;
3004 PPARTENTRY PrevPartEntry;
3005 PPARTENTRY NextPartEntry;
3006 PPARTENTRY LogicalPartEntry;
3008
3009 if (!List || !PartEntry ||
3010 !PartEntry->DiskEntry || !PartEntry->IsPartitioned)
3011 {
3012 return FALSE;
3013 }
3014
3015 ASSERT(PartEntry->DiskEntry->PartList == List);
3016 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
3017
3018 /* Clear the system partition if it is being deleted */
3019 if (List->SystemPartition == PartEntry)
3020 {
3021 ASSERT(List->SystemPartition);
3022 List->SystemPartition = NULL;
3023 }
3024
3025 DiskEntry = PartEntry->DiskEntry;
3026
3027 /* Check which type of partition (primary/logical or extended) is being deleted */
3028 if (DiskEntry->ExtendedPartition == PartEntry)
3029 {
3030 /* An extended partition is being deleted: delete all logical partition entries */
3031 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
3032 {
3034 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3035
3036 /* Dismount the logical partition and delete it */
3037 DismountPartition(List, LogicalPartEntry);
3038 DestroyRegion(LogicalPartEntry);
3039 }
3040
3041 DiskEntry->ExtendedPartition = NULL;
3042 }
3043 else
3044 {
3045 /* A primary/logical partition is being deleted: dismount it */
3046 DismountPartition(List, PartEntry);
3047 }
3048
3049 /* Adjust the unpartitioned disk space entries */
3050
3051 /* Get pointer to previous and next unpartitioned entries */
3052 PrevPartEntry = GetAdjUnpartitionedEntry(PartEntry, FALSE);
3053 NextPartEntry = GetAdjUnpartitionedEntry(PartEntry, TRUE);
3054
3055 if (PrevPartEntry != NULL && NextPartEntry != NULL)
3056 {
3057 /* Merge the previous, current and next unpartitioned entries */
3058
3059 /* Adjust the previous entry length */
3060 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
3061
3062 /* Remove the current and next entries */
3063 RemoveEntryList(&PartEntry->ListEntry);
3064 DestroyRegion(PartEntry);
3065 RemoveEntryList(&NextPartEntry->ListEntry);
3066 DestroyRegion(NextPartEntry);
3067
3068 /* Optionally return the freed region */
3069 if (FreeRegion)
3070 *FreeRegion = PrevPartEntry;
3071 }
3072 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
3073 {
3074 /* Merge the current and the previous unpartitioned entries */
3075
3076 /* Adjust the previous entry length */
3077 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3078
3079 /* Remove the current entry */
3080 RemoveEntryList(&PartEntry->ListEntry);
3081 DestroyRegion(PartEntry);
3082
3083 /* Optionally return the freed region */
3084 if (FreeRegion)
3085 *FreeRegion = PrevPartEntry;
3086 }
3087 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
3088 {
3089 /* Merge the current and the next unpartitioned entries */
3090
3091 /* Adjust the next entry offset and length */
3092 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3093 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3094
3095 /* Remove the current entry */
3096 RemoveEntryList(&PartEntry->ListEntry);
3097 DestroyRegion(PartEntry);
3098
3099 /* Optionally return the freed region */
3100 if (FreeRegion)
3101 *FreeRegion = NextPartEntry;
3102 }
3103 else
3104 {
3105 /* Nothing to merge but change the current entry */
3106 PartEntry->New = FALSE;
3107 PartEntry->IsPartitioned = FALSE;
3108 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3109 PartEntry->OnDiskPartitionNumber = 0;
3110 PartEntry->PartitionNumber = 0;
3111 // PartEntry->PartitionIndex = 0;
3112 PartEntry->BootIndicator = FALSE;
3113 PartEntry->DeviceName[0] = UNICODE_NULL;
3114
3115 if (PartEntry->Volume)
3116 {
3117 RemoveEntryList(&PartEntry->Volume->ListEntry);
3118 RtlFreeHeap(ProcessHeap, 0, PartEntry->Volume);
3119 }
3120 PartEntry->Volume = NULL;
3121
3122 /* Optionally return the freed region */
3123 if (FreeRegion)
3124 *FreeRegion = PartEntry;
3125 }
3126
3127 UpdateDiskLayout(DiskEntry);
3129
3130 return TRUE;
3131}
3132
3133static
3134BOOLEAN
3136 IN PPARTENTRY PartEntry)
3137{
3139
3140 /* Check the type and the file system of this partition */
3141
3142 /*
3143 * We do not support extended partition containers (on MBR disks) marked
3144 * as active, and containing code inside their extended boot records.
3145 */
3146 if (IsContainerPartition(PartEntry->PartitionType))
3147 {
3148 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3149 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3150 return FALSE;
3151 }
3152
3153 Volume = PartEntry->Volume;
3154 if (!Volume)
3155 {
3156 /* Still no recognizable volume mounted: partition not supported */
3157 return FALSE;
3158 }
3159
3160 /*
3161 * ADDITIONAL CHECKS / BIG HACK:
3162 *
3163 * Retrieve its file system and check whether we have
3164 * write support for it. If that is the case we are fine
3165 * and we can use it directly. However if we don't have
3166 * write support we will need to change the active system
3167 * partition.
3168 *
3169 * NOTE that this is completely useless on architectures
3170 * where a real system partition is required, as on these
3171 * architectures the partition uses the FAT FS, for which
3172 * we do have write support.
3173 * NOTE also that for those architectures looking for a
3174 * partition boot indicator is insufficient.
3175 */
3176 if (Volume->FormatState == Unformatted)
3177 {
3178 /* If this partition is mounted, it would use RawFS ("RAW") */
3179 return TRUE;
3180 }
3181 else if (Volume->FormatState == Formatted)
3182 {
3183 ASSERT(*Volume->Info.FileSystem);
3184
3185 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3186 if (_wcsicmp(Volume->Info.FileSystem, L"FAT") == 0 ||
3187 _wcsicmp(Volume->Info.FileSystem, L"FAT32") == 0 ||
3188 // _wcsicmp(Volume->Info.FileSystem, L"NTFS") == 0 ||
3189 _wcsicmp(Volume->Info.FileSystem, L"BTRFS") == 0)
3190 {
3191 return TRUE;
3192 }
3193 else
3194 {
3195 // WARNING: We cannot write on this FS yet!
3196 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3197 Volume->Info.FileSystem);
3198 return FALSE;
3199 }
3200 }
3201 else // if (Volume->FormatState == UnknownFormat)
3202 {
3203 ASSERT(!*Volume->Info.FileSystem);
3204
3205 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3206 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3207 return FALSE;
3208 }
3209
3210 // HACK: WARNING: We cannot write on this FS yet!
3211 // See fsutil.c:InferFileSystem()
3212 if (PartEntry->PartitionType == PARTITION_IFS)
3213 {
3214 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3215 Volume->Info.FileSystem);
3216 return FALSE;
3217 }
3218
3219 return TRUE;
3220}
3221
3225 IN BOOLEAN ForceSelect,
3226 IN PDISKENTRY AlternativeDisk OPTIONAL,
3227 IN PPARTENTRY AlternativePart OPTIONAL)
3228{
3229 PLIST_ENTRY ListEntry;
3230 PDISKENTRY DiskEntry;
3231 PPARTENTRY PartEntry;
3232 PPARTENTRY ActivePartition;
3233 PPARTENTRY CandidatePartition = NULL;
3234
3235 /* Check for empty disk list */
3236 if (IsListEmpty(&List->DiskListHead))
3237 {
3238 /* No system partition! */
3239 ASSERT(List->SystemPartition == NULL);
3240 goto NoSystemPartition;
3241 }
3242
3243 /* Adjust the optional alternative disk if needed */
3244 if (!AlternativeDisk && AlternativePart)
3245 AlternativeDisk = AlternativePart->DiskEntry;
3246
3247 /* Ensure that the alternative partition is on the alternative disk */
3248 if (AlternativePart)
3249 ASSERT(AlternativeDisk && (AlternativePart->DiskEntry == AlternativeDisk));
3250
3251 /* Ensure that the alternative disk is in the list */
3252 if (AlternativeDisk)
3253 ASSERT(AlternativeDisk->PartList == List);
3254
3255 /* Start fresh */
3256 CandidatePartition = NULL;
3257
3258//
3259// Step 1 : Check the system disk.
3260//
3261
3262 /*
3263 * First, check whether the system disk, i.e. the one that will be booted
3264 * by default by the hardware, contains an active partition. If so this
3265 * should be our system partition.
3266 */
3267 DiskEntry = GetSystemDisk(List);
3268 if (!DiskEntry)
3269 {
3270 /* No system disk found, directly go check the alternative disk */
3271 goto UseAlternativeDisk;
3272 }
3273
3274 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3275 {
3276 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3277 goto UseAlternativeDisk;
3278 }
3279
3280 /* If we have a system partition (in the system disk), validate it */
3281 ActivePartition = List->SystemPartition;
3282 if (ActivePartition && IsSupportedActivePartition(ActivePartition))
3283 {
3284 CandidatePartition = ActivePartition;
3285
3286 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3287 CandidatePartition->PartitionNumber,
3288 CandidatePartition->DiskEntry->DiskNumber,
3289 !CandidatePartition->Volume->Info.DriveLetter ? L'-' : CandidatePartition->Volume->Info.DriveLetter);
3290
3291 /* Return the candidate system partition */
3292 return CandidatePartition;
3293 }
3294
3295 /* If the system disk is not the optional alternative disk, perform the minimal checks */
3296 if (DiskEntry != AlternativeDisk)
3297 {
3298 /*
3299 * No active partition has been recognized. Enumerate all the (primary)
3300 * partitions in the system disk, excluding the possible current active
3301 * partition, to find a new candidate.
3302 */
3303 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3304 ListEntry != &DiskEntry->PrimaryPartListHead;
3305 ListEntry = ListEntry->Flink)
3306 {
3307 /* Retrieve the partition */
3308 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3309
3310 /* Skip the current active partition */
3311 if (PartEntry == ActivePartition)
3312 continue;
3313
3314 /* Check if the partition is partitioned and used */
3315 if (PartEntry->IsPartitioned &&
3317 {
3319
3320 /* If we get a candidate active partition in the disk, validate it */
3321 if (IsSupportedActivePartition(PartEntry))
3322 {
3323 CandidatePartition = PartEntry;
3324 goto UseAlternativePartition;
3325 }
3326 }
3327
3328#if 0
3329 /* Check if the partition is partitioned and used */
3330 if (!PartEntry->IsPartitioned)
3331 {
3333
3334 // TODO: Check for minimal size!!
3335 CandidatePartition = PartEntry;
3336 goto UseAlternativePartition;
3337 }
3338#endif
3339 }
3340
3341 /*
3342 * Still nothing, look whether there is some free space that we can use
3343 * for the new system partition. We must be sure that the total number
3344 * of partition is less than the maximum allowed, and that the minimal
3345 * size is fine.
3346 */
3347//
3348// TODO: Fix the handling of system partition being created in unpartitioned space!!
3349// --> When to partition it? etc...
3350//
3351 if (GetPrimaryPartitionCount(DiskEntry) < 4)
3352 {
3353 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3354 ListEntry != &DiskEntry->PrimaryPartListHead;
3355 ListEntry = ListEntry->Flink)
3356 {
3357 /* Retrieve the partition */
3358 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3359
3360 /* Skip the current active partition */
3361 if (PartEntry == ActivePartition)
3362 continue;
3363
3364 /* Check for unpartitioned space */
3365 if (!PartEntry->IsPartitioned)
3366 {
3368
3369 // TODO: Check for minimal size!!
3370 CandidatePartition = PartEntry;
3371 goto UseAlternativePartition;
3372 }
3373 }
3374 }
3375 }
3376
3377
3378//
3379// Step 2 : No active partition found: Check the alternative disk if specified.
3380//
3381
3382UseAlternativeDisk:
3383 if (!AlternativeDisk || (!ForceSelect && (DiskEntry != AlternativeDisk)))
3384 goto NoSystemPartition;
3385
3386 if (AlternativeDisk->DiskStyle == PARTITION_STYLE_GPT)
3387 {
3388 DPRINT1("Alternative disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3389 goto NoSystemPartition;
3390 }
3391
3392 if (DiskEntry != AlternativeDisk)
3393 {
3394 /* Choose the alternative disk */
3395 DiskEntry = AlternativeDisk;
3396
3397 /* If we get a candidate active partition, validate it */
3398 ActivePartition = GetActiveDiskPartition(DiskEntry);
3399 if (ActivePartition && IsSupportedActivePartition(ActivePartition))
3400 {
3401 CandidatePartition = ActivePartition;
3402 goto UseAlternativePartition;
3403 }
3404 }
3405
3406 /* We now may have an unsupported active partition, or none */
3407
3408/***
3409 *** TODO: Improve the selection:
3410 *** - If we want a really separate system partition from the partition where
3411 *** we install, do something similar to what's done below in the code.
3412 *** - Otherwise if we allow for the system partition to be also the partition
3413 *** where we install, just directly fall down to using AlternativePart.
3414 ***/
3415
3416 /* Retrieve the first partition of the disk */
3417 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3418 PARTENTRY, ListEntry);
3419 ASSERT(DiskEntry == PartEntry->DiskEntry);
3420
3421 CandidatePartition = PartEntry;
3422
3423 //
3424 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3425 //
3426
3427 /* Check if the disk is new and if so, use its first partition as the active system partition */
3428 if (DiskEntry->NewDisk)
3429 {
3430 // !IsContainerPartition(PartEntry->PartitionType);
3431 if (!CandidatePartition->IsPartitioned || !CandidatePartition->BootIndicator) /* CandidatePartition != ActivePartition */
3432 {
3433 ASSERT(DiskEntry == CandidatePartition->DiskEntry);
3434
3435 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3436 CandidatePartition->PartitionNumber,
3437 CandidatePartition->DiskEntry->DiskNumber,
3438 !CandidatePartition->Volume->Info.DriveLetter ? L'-' : CandidatePartition->Volume->Info.DriveLetter);
3439
3440 /* Return the candidate system partition */
3441 return CandidatePartition;
3442 }
3443
3444 // FIXME: What to do??
3445 DPRINT1("NewDisk TRUE but first partition is used?\n");
3446 }
3447
3448 /*
3449 * The disk is not new, check if any partition is initialized;
3450 * if not, the first one becomes the system partition.
3451 */
3452 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3453 ListEntry != &DiskEntry->PrimaryPartListHead;
3454 ListEntry = ListEntry->Flink)
3455 {
3456 /* Retrieve the partition */
3457 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3458
3459 /* Check if the partition is partitioned and is used */
3460 // !IsContainerPartition(PartEntry->PartitionType);
3461 if (/* PartEntry->IsPartitioned && */
3462 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator)
3463 {
3464 break;
3465 }
3466 }
3467 if (ListEntry == &DiskEntry->PrimaryPartListHead)
3468 {
3469 /*
3470 * OK we haven't encountered any used and active partition,
3471 * so use the first one as the system partition.
3472 */
3473 ASSERT(DiskEntry == CandidatePartition->DiskEntry);
3474
3475 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3476 CandidatePartition->PartitionNumber,
3477 CandidatePartition->DiskEntry->DiskNumber,
3478 !CandidatePartition->Volume->Info.DriveLetter ? L'-' : CandidatePartition->Volume->Info.DriveLetter);
3479
3480 /* Return the candidate system partition */
3481 return CandidatePartition;
3482 }
3483
3484 /*
3485 * The disk is not new, we did not find any actual active partition,
3486 * or the one we found was not supported, or any possible other candidate
3487 * is not supported. We then use the alternative partition if specified.
3488 */
3489 if (AlternativePart)
3490 {
3491 DPRINT1("No valid or supported system partition has been found, use the alternative partition!\n");
3492 CandidatePartition = AlternativePart;
3493 goto UseAlternativePartition;
3494 }
3495 else
3496 {
3497NoSystemPartition:
3498 DPRINT1("No valid or supported system partition has been found on this system!\n");
3499 return NULL;
3500 }
3501
3502UseAlternativePartition:
3503 /*
3504 * We are here because we did not find any (active) candidate system
3505 * partition that we know how to support. What we are going to do is
3506 * to change the existing system partition and use the alternative partition
3507 * (e.g. on which we install ReactOS) as the new system partition.
3508 * Then we will need to add in FreeLdr's boot menu an entry for booting
3509 * from the original system partition.
3510 */
3511 ASSERT(CandidatePartition);
3512
3513 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3514 CandidatePartition->PartitionNumber,
3515 CandidatePartition->DiskEntry->DiskNumber,
3516 !CandidatePartition->Volume->Info.DriveLetter ? L'-' : CandidatePartition->Volume->Info.DriveLetter);
3517
3518 /* Return the candidate system partition */
3519 return CandidatePartition;
3520}
3521
3522BOOLEAN
3525 IN PPARTENTRY PartEntry,
3526 IN PPARTENTRY OldActivePart OPTIONAL)
3527{
3528 /* Check for empty disk list */
3529 if (IsListEmpty(&List->DiskListHead))
3530 return FALSE;
3531
3532 /* Validate the partition entry */
3533 if (!PartEntry)
3534 return FALSE;
3535
3536 /*
3537 * If the partition entry is already the system partition, or if it is
3538 * the same as the old active partition hint the user provided (and if
3539 * it is already active), just return success.
3540 */
3541 if ((PartEntry == List->SystemPartition) ||
3542 ((PartEntry == OldActivePart) && IsPartitionActive(OldActivePart)))
3543 {
3544 return TRUE;
3545 }
3546
3547 ASSERT(PartEntry->DiskEntry);
3548
3549 /* Ensure that the partition's disk is in the list */
3550 ASSERT(PartEntry->DiskEntry->PartList == List);
3551
3552 /*
3553 * If the user provided an old active partition hint, verify that it is
3554 * indeed active and belongs to the same disk where the new partition
3555 * belongs. Otherwise determine the current active partition on the disk
3556 * where the new partition belongs.
3557 */
3558 if (!(OldActivePart && IsPartitionActive(OldActivePart) && (OldActivePart->DiskEntry == PartEntry->DiskEntry)))
3559 {
3560 /* It's not, determine the current active partition for the disk */
3561 OldActivePart = GetActiveDiskPartition(PartEntry->DiskEntry);
3562 }
3563
3564 /* Unset the old active partition if it exists */
3565 if (OldActivePart)
3566 {
3567 OldActivePart->BootIndicator = FALSE;
3568 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].BootIndicator = FALSE;
3569 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].RewritePartition = TRUE;
3570 OldActivePart->DiskEntry->Dirty = TRUE;
3571 }
3572
3573 /* Modify the system partition if the new partition is on the system disk */
3574 if (PartEntry->DiskEntry == GetSystemDisk(List))
3575 List->SystemPartition = PartEntry;
3576
3577 /* Set the new active partition */
3578 PartEntry->BootIndicator = TRUE;
3579 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
3580 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3581 PartEntry->DiskEntry->Dirty = TRUE;
3582
3583 return TRUE;
3584}
3585
3588 IN PDISKENTRY DiskEntry)
3589{
3597 ULONG PartitionCount;
3598 PLIST_ENTRY ListEntry;
3599 PPARTENTRY PartEntry;
3601
3602 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3603
3604 /* If the disk is not dirty, there is nothing to do */
3605 if (!DiskEntry->Dirty)
3606 return STATUS_SUCCESS;
3607
3609 L"\\Device\\Harddisk%lu\\Partition0",
3610 DiskEntry->DiskNumber);
3612
3614 &Name,
3616 NULL,
3617 NULL);
3618
3622 &Iosb,
3623 0,
3625 if (!NT_SUCCESS(Status))
3626 {
3627 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3628 return Status;
3629 }
3630
3631#ifdef DUMP_PARTITION_TABLE
3632 DumpPartitionTable(DiskEntry);
3633#endif
3634
3635 //
3636 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3637 // the disk in MBR or GPT format in case the disk was not initialized!!
3638 // For this we must ask the user which format to use.
3639 //
3640
3641 /* Save the original partition count to be restored later (see comment below) */
3642 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
3643
3644 /* Set the new disk layout and retrieve its updated version with
3645 * new partition numbers for the new partitions. The PARTMGR will
3646 * automatically notify the MOUNTMGR of new or deleted volumes. */
3648 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3650 NULL,
3651 NULL,
3652 NULL,
3653 &Iosb,
3655 DiskEntry->LayoutBuffer,
3656 BufferSize,
3657 DiskEntry->LayoutBuffer,
3658 BufferSize);
3660
3661 /*
3662 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3663 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3664 * where such a table is expected to enumerate up to 4 partitions:
3665 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3666 * Due to this we need to restore the original PartitionCount number.
3667 */
3668 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
3669
3670 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3671 if (!NT_SUCCESS(Status))
3672 {
3673 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3674 return Status;
3675 }
3676
3677#ifdef DUMP_PARTITION_TABLE
3678 DumpPartitionTable(DiskEntry);
3679#endif
3680
3681 /* Update the partition numbers and device names */
3682
3683 /* Update the primary partition table */
3684 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3685 ListEntry != &DiskEntry->PrimaryPartListHead;
3686 ListEntry = ListEntry->Flink)
3687 {
3688 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3689 if (!PartEntry->IsPartitioned)
3690 continue;
3692
3693 /*
3694 * Initialize the partition's number and its device name only
3695 * if the partition was new. Note that the partition number
3696 * should not change if this partition has not been deleted
3697 * during repartitioning.
3698 */
3699 // FIXME: Our PartMgr currently returns modified numbers
3700 // in the layout, this needs to be investigated and fixed.
3701 if (PartEntry->New)
3702 {
3703 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3704 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3705 InitPartitionDeviceName(PartEntry);
3706 }
3707 PartEntry->New = FALSE;
3708 }
3709
3710 /* Update the logical partition table */
3711 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
3712 ListEntry != &DiskEntry->LogicalPartListHead;
3713 ListEntry = ListEntry->Flink)
3714 {
3715 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3716 if (!PartEntry->IsPartitioned)
3717 continue;
3719
3720 /* See comment above */
3721 if (PartEntry->New)
3722 {
3723 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3724 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3725 InitPartitionDeviceName(PartEntry);
3726 }
3727 PartEntry->New = FALSE;
3728 }
3729
3730 //
3731 // NOTE: Originally (see r40437), we used to install here also a new MBR
3732 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3733 // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0.
3734 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3735 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3736 // was called too, the installation test was modified by checking whether
3737 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3738 //
3739
3740 // HACK: Parts of FIXMEs described above: (Re)set the PartitionStyle to MBR.
3741 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
3742
3743 /* The layout has been successfully updated, the disk is not dirty anymore */
3744 DiskEntry->Dirty = FALSE;
3745
3746 return Status;
3747}
3748
3749BOOLEAN
3752{
3755 PDISKENTRY DiskEntry;
3757
3758 if (!List)
3759 return TRUE;
3760
3761 /* Write all the partitions to all the disks */
3762 for (Entry = List->DiskListHead.Flink;
3763 Entry != &List->DiskListHead;
3764 Entry = Entry->Flink)
3765 {
3766 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3767
3768 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3769 {
3770 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3771 continue;
3772 }
3773
3774 if (DiskEntry->Dirty != FALSE)
3775 {
3776 Status = WritePartitions(DiskEntry);
3777 if (!NT_SUCCESS(Status))
3778 {
3779 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
3780 DiskEntry->DiskNumber, Status);
3781 }
3782 }
3783 }
3784
3785 /* The PARTMGR should have notified the MOUNTMGR that new volumes
3786 * associated with the new partitions had to be created */
3787
3788 /* Assign valid device names to new volumes */
3789 for (Entry = List->VolumesList.Flink;
3790 Entry != &List->VolumesList;
3791 Entry = Entry->Flink)
3792 {
3793 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
3795 }
3796
3797 return TRUE;
3798}
3799
3800
3806static BOOLEAN
3809{
3810 PPARTENTRY PartEntry = Volume->PartEntry;
3811 WCHAR Letter = Volume->Info.DriveLetter;
3814 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\MountedDevices");
3816 WCHAR Buffer[16];
3818 REG_DISK_MOUNT_INFO MountInfo;
3819
3820 /* Ignore no letter */
3821 if (!Letter)
3822 return TRUE;
3823
3825 L"\\DosDevices\\%c:", Letter);
3827
3829 &KeyName,
3832 NULL);
3833
3837 if (!NT_SUCCESS(Status))
3838 {
3842 0,
3843 NULL,
3845 NULL);
3846 }
3847 if (!NT_SUCCESS(Status))
3848 {
3849 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3850 return FALSE;
3851 }
3852
3853 MountInfo.Signature = PartEntry->DiskEntry->LayoutBuffer->Signature;
3854 MountInfo.StartingOffset = GetPartEntryOffsetInBytes(PartEntry);
3856 &ValueName,
3857 0,
3858 REG_BINARY,
3859 (PVOID)&MountInfo,
3860 sizeof(MountInfo));
3862 if (!NT_SUCCESS(Status))
3863 {
3864 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
3865 return FALSE;
3866 }
3867
3868 return TRUE;
3869}
3870
3871BOOLEAN
3874{
3877
3878 if (!List)
3879 return FALSE;
3880
3881 for (Entry = List->VolumesList.Flink;
3882 Entry != &List->VolumesList;
3883 Entry = Entry->Flink)
3884 {
3885 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
3886
3887 /* Assign a "\DosDevices\#:" mount point to this volume */
3889 return FALSE;
3890 }
3891
3892 return TRUE;
3893}
3894
3895VOID
3897 IN PPARTENTRY PartEntry,
3899{
3900 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
3901
3902 ASSERT(DiskEntry->DiskStyle == PARTITION_STYLE_MBR);
3903
3904 /* Nothing to do if we assign the same type */
3905 if (PartitionType == PartEntry->PartitionType)
3906 return;
3907
3908 // TODO: We might need to remount the associated basic volume...
3909
3910 PartEntry->PartitionType = PartitionType;
3911
3912 DiskEntry->Dirty = TRUE;
3913 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
3914 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType);
3915 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3916}
3917
3918/* EOF */
DWORD Id
WCHAR Letter
unsigned char BOOLEAN
struct NameRec_ * Name
Definition: cdprocs.h:460
@ Identifier
Definition: asmpp.cpp:95
LONG NTSTATUS
Definition: precomp.h:26
HANDLE ProcessHeap
Definition: servman.c:15
#define DPRINT1
Definition: precomp.h:8
HANDLE GetRootKeyByPredefKey(IN HANDLE KeyHandle, OUT PCWSTR *RootKeyMountPoint OPTIONAL)
Definition: registry.c:90
BOOL Error
Definition: chkdsk.c:66
#define PARTITION_IFS
Definition: disk.h:94
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:87
#define PARTITION_EXTENDED
Definition: disk.h:92
#define PARTITION_FAT_16
Definition: disk.h:91
#define PARTITION_XINT13_EXTENDED
Definition: disk.h:99
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:160
#define IOCTL_DISK_GET_DRIVE_GEOMETRY
Definition: cdrw_usr.h:169
Definition: bufpool.h:45
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define BufferSize
Definition: mmc.h:75
#define ERROR_SUCCESS
Definition: deptool.c:10
PDISKENTRY CurrentDisk
Definition: partlist.c:74
@ LogicalPartition
Definition: disksup.c:48
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define FILE_SHARE_READ
Definition: compat.h:136
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
static const WCHAR Signature[]
Definition: parser.c:141
return Iosb
Definition: create.c:4402
BOOLEAN RtlTimeToTimeFields(IN PLARGE_INTEGER Time, IN PTIME_FIELDS TimeFields)
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
enum _ERROR_NUMBER ERROR_NUMBER
@ NOT_AN_ERROR
Definition: errorcode.h:17
@ ERROR_WARN_PARTITION
Definition: errorcode.h:33
@ ERROR_NEW_PARTITION
Definition: errorcode.h:34
@ ERROR_ONLY_ONE_EXTENDED
Definition: errorcode.h:59
@ ERROR_PARTITION_TABLE_FULL
Definition: errorcode.h:58
ULONG ControllerCount
Definition: fdc.c:18
@ SystemDeviceInformation
Definition: ntddk_ex.h:18
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
@ FileFsDeviceInformation
Definition: from_kernel.h:222
UCHAR FileSystemToMBRPartitionType(IN PCWSTR FileSystem, IN ULONGLONG StartSector, IN ULONGLONG SectorCount)
Definition: fsrec.c:333
union Alignment_ Alignment
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define DbgPrint
Definition: hal.h:12
CPPORT Port[4]
Definition: headless.c:35
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
struct _CM_FULL_RESOURCE_DESCRIPTOR * PCM_FULL_RESOURCE_DESCRIPTOR
#define CmResourceTypeDeviceSpecific
Definition: hwresource.cpp:127
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
NTSYSAPI PVOID WINAPI RtlReAllocateHeap(HANDLE, ULONG, PVOID, SIZE_T)
Definition: heap.c:2686
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define REG_SZ
Definition: layer.c:22
#define IsOEMPartition(PartitionType)
Definition: partlist.h:22
struct _PARTLIST * PPARTLIST
struct _BIOSDISKENTRY * PBIOSDISKENTRY
@ UnknownFormat
Definition: partlist.h:36
@ Formatted
Definition: partlist.h:37
@ Unformatted
Definition: partlist.h:34
#define GetDiskSizeInBytes(DiskEntry)
Definition: partlist.h:257
#define EFI_PMBR_OSTYPE_EFI
Definition: partlist.h:196
#define PARTITION_MAGIC
Definition: partlist.h:193
#define GetPartEntryOffsetInBytes(PartEntry)
Definition: partlist.h:251
#define GetPartEntrySizeInBytes(PartEntry)
Definition: partlist.h:254
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define ASSERT(a)
Definition: mode.c:44
#define for
Definition: utility.h:88
@ PARTITION_STYLE_GPT
Definition: imports.h:202
@ PARTITION_STYLE_MBR
Definition: imports.h:201
#define ULL(a, b)
Definition: format_msg.c:27
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
static PTIME_FIELDS TimeFields
Definition: time.c:104
#define min(a, b)
Definition: monoChain.cc:55
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_
Definition: ms_sal.h:378
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4219
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4220
int Count
Definition: noreturn.cpp:7
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3952
NTSYSAPI NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: ntapi.c:336
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
NTSYSAPI NTSTATUS NTAPI NtSetValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex OPTIONAL, IN ULONG Type, IN PVOID Data, IN ULONG DataSize)
Definition: ntapi.c:859
#define REG_BINARY
Definition: nt_native.h:1496
#define FILE_READ_DATA
Definition: nt_native.h:628
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
NTSYSAPI NTSTATUS NTAPI RtlUnicodeStringToInteger(PUNICODE_STRING String, ULONG Base, PULONG Value)
NTSYSAPI NTSTATUS NTAPI NtDeviceIoControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
#define RTL_REGISTRY_DEVICEMAP
Definition: nt_native.h:165
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define GENERIC_WRITE
Definition: nt_native.h:90
#define REG_FULL_RESOURCE_DESCRIPTOR
Definition: nt_native.h:1503
NTSTATUS NTAPI NtCreateKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL)
Definition: ntapi.c:240
#define UNICODE_NULL
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
#define IOCTL_DISK_SET_DRIVE_LAYOUT
Definition: ntdddisk.h:205
#define IsContainerPartition(PartitionType)
Definition: ntdddisk.h:321
#define IsRecognizedPartition(PartitionType)
Definition: ntdddisk.h:342
#define IOCTL_DISK_GET_DRIVE_LAYOUT
Definition: ntdddisk.h:91
struct _PARTITION_INFORMATION PARTITION_INFORMATION
@ RemovableMedia
Definition: ntdddisk.h:382
@ FixedMedia
Definition: ntdddisk.h:383
struct _DRIVE_LAYOUT_INFORMATION DRIVE_LAYOUT_INFORMATION
NTSTATUS NTAPI NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
Definition: time.c:569
NTSTRSAFEAPI RtlStringCchCopyW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:127
NTSTRSAFEVAPI RtlStringCchPrintfW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1110
#define L(x)
Definition: ntvdm.h:50
ULONG SectorCount
Definition: part_xbox.c:31
CHAR PartitionType
Definition: part_xbox.c:32
unsigned short USHORT
Definition: pedump.c:61
#define IOCTL_SCSI_GET_ADDRESS
Definition: scsi_port.h:52
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define memset(x, y, z)
Definition: compat.h:39
IN HANDLE DstPath
Definition: fsutil.h:76
ERROR_NUMBER ExtendedPartitionCreationChecks(_In_ PPARTENTRY PartEntry)
Definition: partlist.c:2867
BOOLEAN SetMountedDeviceValues(_In_ PPARTLIST List)
Definition: partlist.c:3872
VOID DestroyPartitionList(IN PPARTLIST List)
Definition: partlist.c:2072
static VOID AddPartitionToDisk(IN ULONG DiskNumber, IN PDISKENTRY DiskEntry, IN ULONG PartitionIndex, IN BOOLEAN LogicalPartition)
Definition: partlist.c:985
ERROR_NUMBER PartitionCreationChecks(_In_ PPARTENTRY PartEntry)
Definition: partlist.c:2822
BOOLEAN IsDiskSuperFloppy2(_In_ const DISK_PARTITION_INFO *DiskInfo, _In_opt_ const ULONGLONG *DiskSize, _In_ const PARTITION_INFORMATION *PartitionInfo)
Definition: partlist.c:491
PPARTENTRY GetAdjUnpartitionedEntry(_In_ PPARTENTRY PartEntry, _In_ BOOLEAN Direction)
Retrieves, if any, the unpartitioned disk region that is adjacent (next or previous) to the specified...
Definition: partlist.c:2786
static BOOLEAN SetMountedDeviceValue(_In_ PVOLENTRY Volume)
Assign a "\DosDevices\#:" mount point drive letter to a disk partition or volume, specified by a give...
Definition: partlist.c:3807
static VOID GetDriverName(IN PDISKENTRY DiskEntry)
Definition: partlist.c:105
struct _REG_DISK_MOUNT_INFO * PREG_DISK_MOUNT_INFO
static PDISKENTRY GetSystemDisk(IN PPARTLIST List)
Definition: partlist.c:1857
ULONGLONG AlignUp(IN ULONGLONG Value, IN ULONG Alignment)
Definition: partlist.c:79
static VOID UpdateDiskLayout(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2585
static VOID DestroyRegion(_Inout_ PPARTENTRY PartEntry)
Definition: partlist.c:729
BOOLEAN WritePartitionsToDisk(IN PPARTLIST List)
Definition: partlist.c:3750
ULONGLONG RoundingDivide(IN ULONGLONG Dividend, IN ULONGLONG Divisor)
Definition: partlist.c:95
VOID SetMBRPartitionType(IN PPARTENTRY PartEntry, IN UCHAR PartitionType)
Definition: partlist.c:3896
BOOLEAN IsSuperFloppy(_In_ PDISKENTRY DiskEntry)
Definition: partlist.c:600
static VOID AssignDriveLetters(IN PPARTLIST List)
Definition: partlist.c:138
static ULONG GetPartitionCount(_In_ PLIST_ENTRY PartListHead)
Counts the number of partitioned disk regions in a given partition list.
Definition: partlist.c:2504
BOOLEAN CreatePartition(_In_ PPARTLIST List, _Inout_ PPARTENTRY PartEntry, _In_opt_ ULONGLONG SizeBytes, _In_opt_ ULONG_PTR PartitionInfo)
Definition: partlist.c:2905
static VOID InitPartitionDeviceName(_Inout_ PPARTENTRY PartEntry)
Definition: partlist.c:900
static BOOLEAN IsSamePrimaryLayoutEntry(_In_ PPARTITION_INFORMATION PartitionInfo, _In_ PPARTENTRY PartEntry)
Definition: partlist.c:2488
PPARTENTRY GetPrevPartition(IN PPARTLIST List, IN PPARTENTRY CurrentPart OPTIONAL)
Definition: partlist.c:2383
ULONGLONG AlignDown(IN ULONGLONG Value, IN ULONG Alignment)
Definition: partlist.c:67
static VOID SetDiskSignature(IN PPARTLIST List, IN PDISKENTRY DiskEntry)
Definition: partlist.c:1292
BOOLEAN DeletePartition(_In_ PPARTLIST List, _In_ PPARTENTRY PartEntry, _Out_opt_ PPARTENTRY *FreeRegion)
Definition: partlist.c:2998
PDISKENTRY GetDiskByBiosNumber(_In_ PPARTLIST List, _In_ ULONG HwDiskNumber)
Definition: partlist.c:2126
PDISKENTRY GetDiskBySCSI(_In_ PPARTLIST List, _In_ USHORT Port, _In_ USHORT Bus, _In_ USHORT Id)
Definition: partlist.c:2172
PDISKENTRY GetDiskBySignature(_In_ PPARTLIST List, _In_ ULONG Signature)
Definition: partlist.c:2202
static NTSTATUS NTAPI DiskConfigurationDataQueryRoutine(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
Definition: partlist.c:237
PPARTLIST CreatePartitionList(VOID)
Definition: partlist.c:1987
#define ROOT_NAME
PPARTENTRY GetPartition(_In_ PDISKENTRY DiskEntry, _In_ ULONG PartitionNumber)
Definition: partlist.c:2225
PPARTENTRY GetNextPartition(IN PPARTLIST List, IN PPARTENTRY CurrentPart OPTIONAL)
Definition: partlist.c:2291
static VOID AddDiskToList(IN HANDLE FileHandle, IN ULONG DiskNumber, IN PPARTLIST List)
Definition: partlist.c:1445
static VOID ScanForUnpartitionedDiskSpace(IN PDISKENTRY DiskEntry)
Definition: partlist.c:1095
static NTSTATUS NTAPI SystemConfigurationDataQueryRoutine(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
Definition: partlist.c:280
BOOLEAN IsPartitionActive(IN PPARTENTRY PartEntry)
Definition: partlist.c:1907
static NTSTATUS DismountPartition(_In_ PPARTLIST List, _In_ PPARTENTRY PartEntry)
Definition: partlist.c:2963
static VOID UpdateDiskSignatures(IN PPARTLIST List)
Definition: partlist.c:1354
BOOLEAN SetActivePartition(IN PPARTLIST List, IN PPARTENTRY PartEntry, IN PPARTENTRY OldActivePart OPTIONAL)
Definition: partlist.c:3523
static VOID EnumerateBiosDiskEntries(IN PPARTLIST PartList)
Definition: partlist.c:327
static PPARTENTRY CreateInsertBlankRegion(IN PDISKENTRY DiskEntry, IN OUT PLIST_ENTRY ListHead, IN ULONGLONG StartSector, IN ULONGLONG SectorCount, IN BOOLEAN LogicalSpace)
Definition: partlist.c:692
static PPARTENTRY GetActiveDiskPartition(IN PDISKENTRY DiskEntry)
Definition: partlist.c:1930
struct _REG_DISK_MOUNT_INFO REG_DISK_MOUNT_INFO
static PVOLENTRY InitVolume(_In_ PPARTLIST List, _In_opt_ PPARTENTRY PartEntry)
Definition: partlist.c:946
static VOID InitVolumeDeviceName(_Inout_ PVOLENTRY Volume)
Definition: partlist.c:921
BOOLEAN IsDiskSuperFloppyEx(_In_ const DRIVE_LAYOUT_INFORMATION_EX *LayoutEx, _In_opt_ const ULONGLONG *DiskSize)
Definition: partlist.c:563
PPARTENTRY SelectPartition(_In_ PPARTLIST List, _In_ ULONG DiskNumber, _In_ ULONG PartitionNumber)
Definition: partlist.c:2266
static BOOLEAN InsertDiskRegion(IN PDISKENTRY DiskEntry, IN PPARTENTRY PartEntry, IN BOOLEAN LogicalPartition)
Definition: partlist.c:626
static BOOLEAN IsEmptyLayoutEntry(_In_ PPARTITION_INFORMATION PartitionInfo)
Definition: partlist.c:2479
PDISKENTRY GetDiskByNumber(_In_ PPARTLIST List, _In_ ULONG DiskNumber)
Definition: partlist.c:2149
static VOID UpdateHwDiskNumbers(IN PPARTLIST List)
Definition: partlist.c:1384
static BOOLEAN ReAllocateLayoutBuffer(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2533
#define GetLogicalPartitionCount(DiskEntry)
Definition: partlist.c:2526
PPARTENTRY FindSupportedSystemPartition(IN PPARTLIST List, IN BOOLEAN ForceSelect, IN PDISKENTRY AlternativeDisk OPTIONAL, IN PPARTENTRY AlternativePart OPTIONAL)
Definition: partlist.c:3223
static BOOLEAN IsSupportedActivePartition(IN PPARTENTRY PartEntry)
Definition: partlist.c:3135
static BOOLEAN InitializePartitionEntry(_Inout_ PPARTENTRY PartEntry, _In_opt_ ULONGLONG SizeBytes, _In_opt_ ULONG_PTR PartitionInfo)
Definition: partlist.c:770
#define GetPrimaryPartitionCount(DiskEntry)
Definition: partlist.c:2523
static NTSTATUS NTAPI DiskIdentifierQueryRoutine(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
Definition: partlist.c:207
NTSTATUS WritePartitions(IN PDISKENTRY DiskEntry)
Definition: partlist.c:3587
BOOLEAN IsDiskSuperFloppy(_In_ const DRIVE_LAYOUT_INFORMATION *Layout, _In_opt_ const ULONGLONG *DiskSize)
Definition: partlist.c:542
static VOID AddLogicalDiskSpace(_In_ PDISKENTRY DiskEntry)
Definition: partlist.c:740
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
#define DPRINT
Definition: sndvol32.h:73
#define _countof(array)
Definition: sndvol32.h:70
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
NTSYSAPI NTSTATUS NTAPI NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInfoClass, OUT PVOID SystemInfoBuffer, IN ULONG SystemInfoBufferSize, OUT PULONG BytesReturned OPTIONAL)
base of all file and directory entries
Definition: entries.h:83
ULONG AdapterNumber
Definition: partlist.h:160
ULONG ControllerNumber
Definition: partlist.h:161
ULONG DiskNumber
Definition: partlist.h:162
ULONG Checksum
Definition: partlist.h:164
ULONG Signature
Definition: partlist.h:163
PDISKENTRY DiskEntry
Definition: partlist.h:165
CM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
Definition: partlist.h:166
CM_PARTIAL_RESOURCE_LIST PartialResourceList
Definition: hwresource.cpp:160
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@391::@400 DeviceSpecificData
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@391 u
CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]
Definition: hwresource.cpp:119
ULONG HwAdapterNumber
Definition: partlist.h:121
ULONG SectorAlignment
Definition: partlist.h:116
ULARGE_INTEGER SectorCount
Definition: partlist.h:115
UNICODE_STRING DriverName
Definition: partlist.h:141
ULONG HwControllerNumber
Definition: partlist.h:122
ULONG HwDiskNumber
Definition: partlist.h:123
ULONG SectorsPerTrack
Definition: partlist.h:112
PPARTENTRY ExtendedPartition
Definition: partlist.h:153
LIST_ENTRY LogicalPartListHead
Definition: partlist.h:150
struct _PARTLIST * PartList
Definition: partlist.h:104
BOOLEAN NewDisk
Definition: partlist.h:138
ULONG DiskNumber
Definition: partlist.h:129
ULONG BytesPerSector
Definition: partlist.h:113
BOOLEAN BiosFound
Definition: partlist.h:120
ULONGLONG Cylinders
Definition: partlist.h:110
USHORT Bus
Definition: partlist.h:132
USHORT Id
Definition: partlist.h:133
LIST_ENTRY ListEntry
Definition: partlist.h:101
BOOLEAN Dirty
Definition: partlist.h:136
USHORT Port
Definition: partlist.h:131
PARTITION_STYLE DiskStyle
Definition: partlist.h:139
ULONG TracksPerCylinder
Definition: partlist.h:111
LIST_ENTRY PrimaryPartListHead
Definition: partlist.h:149
MEDIA_TYPE MediaType
Definition: partlist.h:106
ULONG HwFixedDiskNumber
Definition: partlist.h:124
ULONG CylinderAlignment
Definition: partlist.h:117
PDRIVE_LAYOUT_INFORMATION LayoutBuffer
Definition: partlist.h:143
MEDIA_TYPE MediaType
Definition: ntdddisk.h:401
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:400
ULONG TracksPerCylinder
Definition: ntdddisk.h:402
ULONG SectorsPerTrack
Definition: ntdddisk.h:403
ULONG BytesPerSector
Definition: ntdddisk.h:404
PARTITION_INFORMATION PartitionEntry[1]
Definition: ntdddisk.h:421
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
BOOLEAN IsPartitioned
Definition: partlist.h:82
UCHAR PartitionType
Definition: partlist.h:73
BOOLEAN New
Definition: partlist.h:85
ULARGE_INTEGER SectorCount
Definition: partlist.h:70
BOOLEAN BootIndicator
Definition: partlist.h:72
WCHAR DeviceName[MAX_PATH]
NT device name: "\Device\HarddiskM\PartitionN".
Definition: partlist.h:77
PVOLENTRY Volume
Definition: partlist.h:95
struct _DISKENTRY * DiskEntry
Definition: partlist.h:66
BOOLEAN LogicalPartition
Definition: partlist.h:79
ULONG OnDiskPartitionNumber
Definition: partlist.h:74
LIST_ENTRY ListEntry
Definition: partlist.h:63
ULONG PartitionNumber
Definition: partlist.h:75
ULARGE_INTEGER StartSector
Definition: partlist.h:69
ULONG PartitionIndex
Definition: partlist.h:76
LARGE_INTEGER StartingOffset
Definition: imports.h:221
PARTITION_INFORMATION_MBR Mbr
Definition: imports.h:226
LARGE_INTEGER PartitionLength
Definition: imports.h:222
LARGE_INTEGER StartingOffset
Definition: ntdddisk.h:408
LARGE_INTEGER PartitionLength
Definition: ntdddisk.h:409
BOOLEAN RecognizedPartition
Definition: ntdddisk.h:414
BOOLEAN RewritePartition
Definition: ntdddisk.h:415
PARTITION Partition[PARTITION_TBL_SIZE]
Definition: partlist.h:219
unsigned char PartitionType
Definition: partlist.h:206
ULONGLONG StartingOffset
Definition: partlist.c:27
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
UCHAR PathId
Definition: scsi_port.h:149
UCHAR TargetId
Definition: scsi_port.h:150
UCHAR PortNumber
Definition: scsi_port.h:148
USHORT Milliseconds
Definition: env_spec_w32.h:717
$ULONG LowPart
Definition: ntbasedef.h:569
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOLINFO Info
Definition: partlist.h:47
WCHAR DriveLetter
Definition: volutil.h:15
#define max(a, b)
Definition: svc.c:63
#define LL
Definition: tui.h:167
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
#define ANYSIZE_ARRAY
Definition: typedefs.h:46
#define NTAPI
Definition: typedefs.h:36
const char * PCSTR
Definition: typedefs.h:52
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
NTSTATUS DismountVolume(_Inout_ PVOLINFO Volume, _In_ BOOLEAN Force)
Attempts to dismount the designated volume.
Definition: volutil.c:152
NTSTATUS MountVolume(_Inout_ PVOLINFO Volume, _In_opt_ UCHAR MbrPartitionType)
Definition: volutil.c:23
#define IsUnknown(VolInfo)
Definition: volutil.h:28
#define IsUnformatted(VolInfo)
Definition: volutil.h:31
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2699
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION Direction
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:282
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
struct _CM_DISK_GEOMETRY_DEVICE_DATA * PCM_DISK_GEOMETRY_DEVICE_DATA
_In_ ULONG _In_ struct _SET_PARTITION_INFORMATION_EX * PartitionInfo
Definition: iofuncs.h:2105
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2061
_In_ LARGE_INTEGER Divisor
Definition: rtlfuncs.h:3058
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180