2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Partition list functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2018-2019 Hermes Belusca-Maito
18 //#define DUMP_PARTITION_TABLE
22 typedef struct _REG_DISK_MOUNT_INFO
25 LARGE_INTEGER StartingOffset
;
26 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
31 /* HELPERS FOR PARTITION TYPES **********************************************/
34 * This partition type list was ripped from the kernelDisk.c module of
35 * the Visopsys Operating System (see license below), and completed with
36 * information from Paragon Hard-Disk Manager, and the following websites:
37 * http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
38 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
43 * Visopsys Operating System
44 * Copyright (C) 1998-2015 J. Andrew McLaughlin
46 * This program is free software; you can redistribute it and/or modify it
47 * under the terms of the GNU General Public License as published by the Free
48 * Software Foundation; either version 2 of the License, or (at your option)
51 * This program is distributed in the hope that it will be useful, but
52 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
53 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
56 * You should have received a copy of the GNU General Public License along
57 * with this program; if not, write to the Free Software Foundation, Inc.,
58 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
61 /* This is a table for keeping known partition type codes and descriptions */
62 PARTITION_TYPE PartitionTypes
[NUM_PARTITION_TYPE_ENTRIES
] =
66 { 0x02, "XENIX root" },
67 { 0x03, "XENIX usr" },
68 { 0x04, "FAT16 (< 32 MB)" },
71 { 0x07, "NTFS/HPFS/exFAT" },
72 { 0x08, "OS/2 or AIX boot" },
74 { 0x0A, "OS/2 Boot Manager" },
76 { 0x0C, "FAT32 (LBA)" },
77 { 0x0E, "FAT16 (LBA)" },
78 { 0x0F, "Extended (LBA)" },
80 { 0x11, "Hidden FAT12" },
81 { 0x12, "FAT diagnostic (Compaq)" },
83 { 0x14, "Hidden FAT16 (< 32 MB)" },
84 { 0x16, "Hidden FAT16" },
85 { 0x17, "Hidden HPFS or NTFS" },
86 { 0x18, "AST SmartSleep" },
87 { 0x1B, "Hidden FAT32" },
88 { 0x1C, "Hidden FAT32 (LBA)" },
89 { 0x1E, "Hidden FAT16 (LBA)" },
90 { 0x24, "NEC DOS 3.x" },
91 { 0x27, "Hidden WinRE NTFS" },
92 { 0x2A, "AtheOS File System (AFS)" },
93 { 0x2B, "SyllableSecure (SylStor)" },
95 { 0x35, "JFS on OS/2 or eCS" },
96 { 0x38, "THEOS v3.2 2GB partition" },
98 { 0x3A, "THEOS v4 4GB partition" },
99 { 0x3B, "THEOS v4 extended partition" },
100 { 0x3C, "PartitionMagic recovery partition" },
101 { 0x3D, "Hidden NetWare" },
103 { 0x41, "PowerPC PReP boot" },
104 { 0x42, "Win2K Dynamic Volume extended" },
105 { 0x43, "Old Linux" },
107 { 0x45, "Priam or Boot-US Boot Manager" },
109 { 0x4E, "QNX4.x 2nd partition" },
110 { 0x4F, "QNX4.x 3rd partition" },
111 { 0x50, "OnTrack Disk Manager R/O" },
112 { 0x51, "OnTrack Disk Manager R/W or Novell" },
114 { 0x53, "OnTrack DM6 Aux3" },
115 { 0x54, "OnTrack DM6 Dynamic Drive Overlay" },
116 { 0x55, "EZ-Drive" },
117 { 0x56, "Golden Bow VFeature Partitioned Volume" },
118 { 0x5C, "Priam EDisk" },
119 { 0x61, "SpeedStor" },
121 { 0x63, "GNU HURD or Unix System V (SCO, ISC Unix, UnixWare)" },
122 { 0x64, "Novell NetWare 286, 2.xx" },
123 { 0x65, "Novell NetWare 386, 3.xx or 4.xx" },
124 { 0x66, "Novell NetWare SMS Partition" },
127 { 0x69, "Novell NetWare 5+" },
128 { 0x70, "DiskSecure Multi-Boot" },
129 { 0x75, "IBM PC/IX" },
130 { 0x7E, "Veritas VxVM public" },
131 { 0x7F, "Veritas VxVM private" },
132 { 0x80, "Old MINIX" },
133 { 0x81, "Linux or MINIX" },
134 { 0x82, "Linux swap or Solaris" },
135 { 0x83, "Linux Native" },
136 { 0x84, "Hibernate" },
137 { 0x85, "Extended Linux" },
138 { 0x86, "FAT16 mirrored" },
139 { 0x87, "HPFS or NTFS mirrored" },
140 { 0x88, "Linux plaintext partition table" },
141 { 0x8B, "FAT32 mirrored" },
142 { 0x8C, "FAT32 (LBA) mirrored" },
143 { 0x8E, "Linux LVM" },
144 { 0x93, "Hidden Linux" },
145 { 0x94, "Amoeba BBT" },
146 { 0x96, "CDFS/ISO-9660" },
148 { 0xA0, "Laptop Hibernate" },
149 { 0xA1, "Laptop Hibernate (NEC 6000H)" },
150 { 0xA5, "BSD, NetBSD, FreeBSD" },
152 { 0xA7, "NeXTStep" },
153 { 0xA8, "Darwin UFS" }, // Also known as "OS-X"
155 { 0xAB, "Darwin boot" },
156 { 0xAF, "Apple HFS" },
157 { 0xB6, "NT FAT16 corrupt mirror" },
158 { 0xB7, "BSDI BSD/386 FS" }, // Alternatively, "NT NTFS corrupt mirror"
159 { 0xB8, "BSDI BSD/386 swap" },
160 { 0xBB, "Boot Wizard hidden" },
161 { 0xBC, "Paragon Backup capsule" },
162 { 0xBE, "Solaris 8 boot partition" },
163 { 0xBF, "Solaris 10 x86" },
164 { 0xC0, "NTFT" }, // Alternatively, "CTOS" or "REAL/32 or DR-DOS or Novell-DOS secure partition"
165 { 0xC1, "DR-DOS FAT12" },
166 { 0xC2, "Hidden Linux" },
167 { 0xC3, "Hidden Linux swap" },
168 { 0xC4, "DR-DOS FAT16 (< 32 MB)" },
169 { 0xC5, "DR-DOS Extended" },
170 { 0xC6, "DR-DOS FAT16" },
171 { 0xC7, "HPFS mirrored" }, // Alternatively, "Syrinx boot"
172 { 0xCB, "DR-DOS FAT32" },
173 { 0xCC, "DR-DOS FAT32 (LBA)" },
174 { 0xCE, "DR-DOS FAT16 (LBA)" },
176 { 0xD1, "MDOS FAT12" },
177 { 0xD4, "MDOS FAT16 (< 32 MB)" },
178 { 0xD5, "MDOS Extended" },
179 { 0xD6, "MDOS FAT16" },
181 { 0xDB, "Digital Research CP/M" },
182 { 0xDE, "Dell OEM" },
183 { 0xDF, "BootIt EMBRM (FAT16/32)" },
184 { 0xE1, "SpeedStor FAT12" },
185 { 0xE3, "SpeedStor (0xE3)" },
186 { 0xE4, "SpeedStor FAT16" },
187 { 0xE5, "Tandy MSDOS" },
188 { 0xE6, "SpeedStor (0xE6)" },
189 { 0xE8, "Linux Unified Key Setup partition" },
190 { 0xEA, "Rufus private partition" },
191 { 0xEB, "BeOS BFS" },
192 { 0xEC, "SkyOS SkyFS" },
193 { 0xEE, "EFI GPT protective" },
194 { 0xEF, "EFI System partition" },
195 { 0xF0, "Linux/PA-RISC boot loader" },
196 { 0xF1, "SpeedStor (0xF1)" },
197 { 0xF2, "DOS 3.3+ second" },
198 { 0xF4, "SpeedStor (0xF4)" },
199 { 0xF5, "SpeedStor (0xF5)" },
200 { 0xF6, "SpeedStor (0xF6)" },
202 { 0xFB, "VMware FS" },
203 { 0xFC, "VMware swap" },
204 { 0xFD, "Linux RAID auto" },
205 { 0xFE, "NT hidden partition" },
206 { 0xFF, "XENIX Bad Block Table" },
210 /* FUNCTIONS ****************************************************************/
212 #ifdef DUMP_PARTITION_TABLE
216 PDISKENTRY DiskEntry
)
218 PPARTITION_INFORMATION PartitionInfo
;
222 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
223 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
225 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
227 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
228 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
230 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
231 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
232 PartitionInfo
->HiddenSectors
,
233 PartitionInfo
->PartitionNumber
,
234 PartitionInfo
->PartitionType
,
235 PartitionInfo
->BootIndicator
? '*': ' ',
236 PartitionInfo
->RewritePartition
? 'Y': 'N');
251 Temp
= Value
/ Alignment
;
253 return Temp
* Alignment
;
261 ULONGLONG Temp
, Result
;
263 Temp
= Value
/ Alignment
;
265 Result
= Temp
* Alignment
;
266 if (Value
% Alignment
)
274 IN ULONGLONG Dividend
,
275 IN ULONGLONG Divisor
)
277 return (Dividend
+ Divisor
/ 2) / Divisor
;
284 IN PDISKENTRY DiskEntry
)
286 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
290 RtlInitUnicodeString(&DiskEntry
->DriverName
, NULL
);
292 RtlStringCchPrintfW(KeyName
, ARRAYSIZE(KeyName
),
293 L
"\\Scsi\\Scsi Port %hu",
296 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
298 QueryTable
[0].Name
= L
"Driver";
299 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
300 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
302 /* This will allocate DiskEntry->DriverName if needed */
303 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
308 if (!NT_SUCCESS(Status
))
310 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
319 PDISKENTRY DiskEntry
;
320 PPARTENTRY PartEntry
;
327 /* Assign drive letters to primary partitions */
328 for (Entry1
= List
->DiskListHead
.Flink
;
329 Entry1
!= &List
->DiskListHead
;
330 Entry1
= Entry1
->Flink
)
332 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
334 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
335 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
336 Entry2
= Entry2
->Flink
)
338 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
340 PartEntry
->DriveLetter
= 0;
342 if (PartEntry
->IsPartitioned
&&
343 !IsContainerPartition(PartEntry
->PartitionType
))
345 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
347 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
348 PartEntry
->SectorCount
.QuadPart
!= 0LL)
352 PartEntry
->DriveLetter
= Letter
;
360 /* Assign drive letters to logical drives */
361 for (Entry1
= List
->DiskListHead
.Flink
;
362 Entry1
!= &List
->DiskListHead
;
363 Entry1
= Entry1
->Flink
)
365 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
367 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
368 Entry2
!= &DiskEntry
->LogicalPartListHead
;
369 Entry2
= Entry2
->Flink
)
371 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
373 PartEntry
->DriveLetter
= 0;
375 if (PartEntry
->IsPartitioned
)
377 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
379 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
380 PartEntry
->SectorCount
.QuadPart
!= 0LL)
384 PartEntry
->DriveLetter
= Letter
;
395 DiskIdentifierQueryRoutine(
403 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
404 UNICODE_STRING NameU
;
406 if (ValueType
== REG_SZ
&&
407 ValueLength
== 20 * sizeof(WCHAR
) &&
408 ((PWCHAR
)ValueData
)[8] == L
'-')
410 NameU
.Buffer
= (PWCHAR
)ValueData
;
411 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
412 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
414 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
415 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
417 return STATUS_SUCCESS
;
420 return STATUS_UNSUCCESSFUL
;
425 DiskConfigurationDataQueryRoutine(
433 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
434 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
435 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
438 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
439 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
440 return STATUS_UNSUCCESSFUL
;
442 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
444 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
446 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
447 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
448 return STATUS_UNSUCCESSFUL
;
451 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
453 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
454 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
457 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
458 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
460 return STATUS_SUCCESS
;
463 return STATUS_UNSUCCESSFUL
;
468 SystemConfigurationDataQueryRoutine(
476 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
477 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
480 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
481 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
482 return STATUS_UNSUCCESSFUL
;
484 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
486 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
488 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
489 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
490 return STATUS_UNSUCCESSFUL
;
493 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
495 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
496 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
499 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(ProcessHeap
, 0,
500 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
501 if (*Int13Drives
== NULL
)
502 return STATUS_NO_MEMORY
;
505 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
506 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
507 return STATUS_SUCCESS
;
510 return STATUS_UNSUCCESSFUL
;
515 EnumerateBiosDiskEntries(
516 IN PPARTLIST PartList
)
518 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
521 ULONG ControllerCount
;
524 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
525 PBIOSDISKENTRY BiosDiskEntry
;
527 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
529 memset(QueryTable
, 0, sizeof(QueryTable
));
531 QueryTable
[1].Name
= L
"Configuration Data";
532 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
534 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
535 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
539 if (!NT_SUCCESS(Status
))
541 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
545 for (AdapterCount
= 0; ; ++AdapterCount
)
547 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
549 ROOT_NAME
, AdapterCount
);
550 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
555 if (!NT_SUCCESS(Status
))
560 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
561 L
"%s\\%lu\\DiskController",
562 ROOT_NAME
, AdapterCount
);
563 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
568 if (NT_SUCCESS(Status
))
570 for (ControllerCount
= 0; ; ++ControllerCount
)
572 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
573 L
"%s\\%lu\\DiskController\\%lu",
574 ROOT_NAME
, AdapterCount
, ControllerCount
);
575 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
580 if (!NT_SUCCESS(Status
))
582 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
586 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
587 L
"%s\\%lu\\DiskController\\%lu\\DiskPeripheral",
588 ROOT_NAME
, AdapterCount
, ControllerCount
);
589 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
594 if (NT_SUCCESS(Status
))
596 QueryTable
[0].Name
= L
"Identifier";
597 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
598 QueryTable
[1].Name
= L
"Configuration Data";
599 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
601 for (DiskCount
= 0; ; ++DiskCount
)
603 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
604 if (BiosDiskEntry
== NULL
)
606 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
610 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
611 L
"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu",
612 ROOT_NAME
, AdapterCount
, ControllerCount
, DiskCount
);
613 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
616 (PVOID
)BiosDiskEntry
,
618 if (!NT_SUCCESS(Status
))
620 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
621 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
625 BiosDiskEntry
->AdapterNumber
= 0; // And NOT "AdapterCount" as it needs to be hardcoded for BIOS!
626 BiosDiskEntry
->ControllerNumber
= ControllerCount
;
627 BiosDiskEntry
->DiskNumber
= DiskCount
;
628 BiosDiskEntry
->DiskEntry
= NULL
;
630 if (DiskCount
< Int13Drives
[0].NumberDrives
)
632 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
636 DPRINT1("Didn't find Int13 drive data for disk %u\n", DiskCount
);
639 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
642 DPRINT("AdapterNumber: %lu\n", BiosDiskEntry
->AdapterNumber
);
643 DPRINT("ControllerNumber: %lu\n", BiosDiskEntry
->ControllerNumber
);
644 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
645 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
646 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
647 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
648 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
649 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
650 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
651 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
652 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
653 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
654 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
662 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
669 * Detects whether a disk reports as a "super-floppy", i.e. an unpartitioned
670 * disk with a valid VBR, following the criteria used by IoReadPartitionTable()
671 * and IoWritePartitionTable():
672 * only one single partition starting at the beginning of the disk; the reported
673 * defaults are: partition number being zero and its type being FAT16 non-bootable.
674 * Note also that accessing \Device\HarddiskN\Partition0 or Partition1 returns
680 IN PDISKENTRY DiskEntry
)
682 PPARTITION_INFORMATION PartitionInfo
;
683 ULONGLONG PartitionLengthEstimate
;
685 /* No layout buffer: we cannot say anything yet */
686 if (DiskEntry
->LayoutBuffer
== NULL
)
689 /* We must have only one partition */
690 if (DiskEntry
->LayoutBuffer
->PartitionCount
!= 1)
693 /* Get the single partition entry */
694 PartitionInfo
= DiskEntry
->LayoutBuffer
->PartitionEntry
;
696 /* The single partition must start at the beginning of the disk */
697 if (!(PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
698 PartitionInfo
->HiddenSectors
== 0))
703 /* The disk signature is usually set to one; warn in case it's not */
704 if (DiskEntry
->LayoutBuffer
->Signature
!= 1)
706 DPRINT1("Super-Floppy disk %lu signature %08x != 1!\n",
707 DiskEntry
->DiskNumber
, DiskEntry
->LayoutBuffer
->Signature
);
711 * The partition number must be zero or one, be recognized,
712 * have FAT16 type and report as non-bootable.
714 if ((PartitionInfo
->PartitionNumber
!= 0 &&
715 PartitionInfo
->PartitionNumber
!= 1) ||
716 PartitionInfo
->RecognizedPartition
!= TRUE
||
717 PartitionInfo
->PartitionType
!= PARTITION_FAT_16
||
718 PartitionInfo
->BootIndicator
!= FALSE
)
720 DPRINT1("Super-Floppy disk %lu does not return default settings!\n"
721 " PartitionNumber = %lu, expected 0\n"
722 " RecognizedPartition = %s, expected TRUE\n"
723 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n"
724 " BootIndicator = %s, expected FALSE\n",
725 DiskEntry
->DiskNumber
,
726 PartitionInfo
->PartitionNumber
,
727 PartitionInfo
->RecognizedPartition
? "TRUE" : "FALSE",
728 PartitionInfo
->PartitionType
,
729 PartitionInfo
->BootIndicator
? "TRUE" : "FALSE");
732 /* The partition lengths should agree */
733 PartitionLengthEstimate
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
734 if (PartitionInfo
->PartitionLength
.QuadPart
!= PartitionLengthEstimate
)
736 DPRINT1("PartitionLength = %I64u is different from PartitionLengthEstimate = %I64u\n",
737 PartitionInfo
->PartitionLength
.QuadPart
, PartitionLengthEstimate
);
745 * Inserts the disk region represented by PartEntry into either the primary
746 * or the logical partition list of the given disk.
747 * The lists are kept sorted by increasing order of start sectors.
748 * Of course no disk region should overlap at all with one another.
753 IN PDISKENTRY DiskEntry
,
754 IN PPARTENTRY PartEntry
,
755 IN BOOLEAN LogicalPartition
)
759 PPARTENTRY PartEntry2
;
761 /* Use the correct partition list */
762 if (LogicalPartition
)
763 List
= &DiskEntry
->LogicalPartListHead
;
765 List
= &DiskEntry
->PrimaryPartListHead
;
767 /* Find the first disk region before which we need to insert the new one */
768 for (Entry
= List
->Flink
; Entry
!= List
; Entry
= Entry
->Flink
)
770 PartEntry2
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
772 /* Ignore any unused empty region */
773 if ((PartEntry2
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
774 PartEntry2
->StartSector
.QuadPart
== 0) || PartEntry2
->SectorCount
.QuadPart
== 0)
779 /* If the current region ends before the one to be inserted, try again */
780 if (PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1 < PartEntry
->StartSector
.QuadPart
)
784 * One of the disk region boundaries crosses the desired region
785 * (it starts after the desired region, or ends before the end
786 * of the desired region): this is an impossible situation because
787 * disk regions (partitions) cannot overlap!
788 * Throw an error and bail out.
790 if (max(PartEntry
->StartSector
.QuadPart
, PartEntry2
->StartSector
.QuadPart
)
792 min( PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
793 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1))
795 DPRINT1("Disk region overlap problem, stopping there!\n"
796 "Partition to be inserted:\n"
797 " StartSector = %I64u ; EndSector = %I64u\n"
798 "Existing disk region:\n"
799 " StartSector = %I64u ; EndSector = %I64u\n",
800 PartEntry
->StartSector
.QuadPart
,
801 PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
802 PartEntry2
->StartSector
.QuadPart
,
803 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1);
807 /* We have found the first region before which the new one has to be inserted */
811 /* Insert the disk region */
812 InsertTailList(Entry
, &PartEntry
->ListEntry
);
817 CreateInsertBlankRegion(
818 IN PDISKENTRY DiskEntry
,
819 IN OUT PLIST_ENTRY ListHead
,
820 IN ULONGLONG StartSector
,
821 IN ULONGLONG SectorCount
,
822 IN BOOLEAN LogicalSpace
)
824 PPARTENTRY NewPartEntry
;
826 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
829 if (NewPartEntry
== NULL
)
832 NewPartEntry
->DiskEntry
= DiskEntry
;
834 NewPartEntry
->StartSector
.QuadPart
= StartSector
;
835 NewPartEntry
->SectorCount
.QuadPart
= SectorCount
;
837 NewPartEntry
->IsPartitioned
= FALSE
;
838 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
839 NewPartEntry
->FormatState
= Unformatted
;
840 NewPartEntry
->FileSystem
[0] = L
'\0';
842 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
843 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
844 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
846 /* Insert the new entry into the list */
847 InsertTailList(ListHead
, &NewPartEntry
->ListEntry
);
855 InitializePartitionEntry(
856 IN PDISKENTRY DiskEntry
,
857 IN PPARTENTRY PartEntry
,
858 IN ULONGLONG SectorCount
,
859 IN BOOLEAN AutoCreate
)
861 PPARTENTRY NewPartEntry
;
863 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
865 if ((AutoCreate
!= FALSE
) ||
866 (AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
867 PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
))
869 DPRINT1("Convert existing partition entry\n");
871 NewPartEntry
= PartEntry
;
872 NewPartEntry
->AutoCreate
= AutoCreate
;
876 DPRINT1("Add new partition entry\n");
878 /* Insert and initialize a new partition entry */
879 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
882 if (NewPartEntry
== NULL
)
885 NewPartEntry
->DiskEntry
= DiskEntry
;
887 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
888 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
889 NewPartEntry
->StartSector
.QuadPart
;
891 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
892 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
894 /* Insert the new entry into the list */
895 InsertTailList(&PartEntry
->ListEntry
, &NewPartEntry
->ListEntry
);
898 /* Create entry as 'New (Unformatted)' */
899 NewPartEntry
->New
= TRUE
;
900 NewPartEntry
->IsPartitioned
= TRUE
;
902 NewPartEntry
->PartitionType
= FileSystemToPartitionType(L
"RAW", &NewPartEntry
->StartSector
, &NewPartEntry
->SectorCount
);
903 ASSERT(NewPartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
905 NewPartEntry
->FormatState
= Unformatted
;
906 NewPartEntry
->FileSystem
[0] = L
'\0';
907 // NewPartEntry->AutoCreate = AutoCreate;
908 NewPartEntry
->BootIndicator
= FALSE
;
909 NewPartEntry
->LogicalPartition
= FALSE
;
911 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
912 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
913 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
923 IN PDISKENTRY DiskEntry
,
924 IN ULONG PartitionIndex
,
925 IN BOOLEAN LogicalPartition
)
928 PPARTITION_INFORMATION PartitionInfo
;
929 PPARTENTRY PartEntry
;
930 HANDLE PartitionHandle
;
931 OBJECT_ATTRIBUTES ObjectAttributes
;
932 IO_STATUS_BLOCK IoStatusBlock
;
933 WCHAR PathBuffer
[MAX_PATH
];
935 UCHAR LabelBuffer
[sizeof(FILE_FS_VOLUME_INFORMATION
) + 256 * sizeof(WCHAR
)];
936 PFILE_FS_VOLUME_INFORMATION LabelInfo
= (PFILE_FS_VOLUME_INFORMATION
)LabelBuffer
;
938 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
940 if (PartitionInfo
->PartitionType
== PARTITION_ENTRY_UNUSED
||
941 ((LogicalPartition
!= FALSE
) && IsContainerPartition(PartitionInfo
->PartitionType
)))
946 PartEntry
= RtlAllocateHeap(ProcessHeap
,
949 if (PartEntry
== NULL
)
952 PartEntry
->DiskEntry
= DiskEntry
;
954 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
955 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
957 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
958 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
959 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
961 PartEntry
->LogicalPartition
= LogicalPartition
;
962 PartEntry
->IsPartitioned
= TRUE
;
963 PartEntry
->OnDiskPartitionNumber
= PartitionInfo
->PartitionNumber
;
964 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
965 PartEntry
->PartitionIndex
= PartitionIndex
;
967 /* Specify the partition as initially unformatted */
968 PartEntry
->FormatState
= Unformatted
;
969 PartEntry
->FileSystem
[0] = L
'\0';
971 /* Initialize the partition volume label */
972 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
974 if (IsContainerPartition(PartEntry
->PartitionType
))
976 PartEntry
->FormatState
= Unformatted
;
978 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
979 DiskEntry
->ExtendedPartition
= PartEntry
;
981 else if (IsRecognizedPartition(PartEntry
->PartitionType
))
983 ASSERT(PartitionInfo
->RecognizedPartition
);
984 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
986 /* Open the volume, ignore any errors */
987 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
988 L
"\\Device\\Harddisk%lu\\Partition%lu",
989 DiskEntry
->DiskNumber
,
990 PartEntry
->PartitionNumber
);
991 RtlInitUnicodeString(&Name
, PathBuffer
);
993 InitializeObjectAttributes(&ObjectAttributes
,
995 OBJ_CASE_INSENSITIVE
,
999 PartitionHandle
= NULL
;
1000 Status
= NtOpenFile(&PartitionHandle
,
1001 FILE_READ_DATA
| SYNCHRONIZE
,
1004 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1005 FILE_SYNCHRONOUS_IO_NONALERT
);
1006 if (!NT_SUCCESS(Status
))
1008 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status
);
1011 if (/* NT_SUCCESS(Status) && */ PartitionHandle
)
1013 /* We don't have a FS, try to guess one */
1014 Status
= InferFileSystemByHandle(PartitionHandle
,
1015 PartEntry
->PartitionType
,
1016 PartEntry
->FileSystem
,
1017 sizeof(PartEntry
->FileSystem
));
1018 if (!NT_SUCCESS(Status
))
1019 DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status
);
1021 if (*PartEntry
->FileSystem
)
1023 if (wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
1024 PartEntry
->FormatState
= Unformatted
;
1026 PartEntry
->FormatState
= Preformatted
;
1030 PartEntry
->FormatState
= UnknownFormat
;
1033 /* Retrieve the partition volume label */
1034 if (PartitionHandle
)
1036 Status
= NtQueryVolumeInformationFile(PartitionHandle
,
1039 sizeof(LabelBuffer
),
1040 FileFsVolumeInformation
);
1041 if (NT_SUCCESS(Status
))
1043 /* Copy the (possibly truncated) volume label and NULL-terminate it */
1044 RtlStringCbCopyNW(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
),
1045 LabelInfo
->VolumeLabel
, LabelInfo
->VolumeLabelLength
);
1049 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status
);
1053 /* Close the partition */
1054 if (PartitionHandle
)
1055 NtClose(PartitionHandle
);
1059 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
1060 PartEntry
->FormatState
= UnknownFormat
;
1063 InsertDiskRegion(DiskEntry
, PartEntry
, LogicalPartition
);
1068 ScanForUnpartitionedDiskSpace(
1069 IN PDISKENTRY DiskEntry
)
1071 ULONGLONG StartSector
;
1072 ULONGLONG SectorCount
;
1073 ULONGLONG LastStartSector
;
1074 ULONGLONG LastSectorCount
;
1075 ULONGLONG LastUnusedSectorCount
;
1076 PPARTENTRY PartEntry
;
1077 PPARTENTRY NewPartEntry
;
1080 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1082 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1084 DPRINT1("No primary partition!\n");
1086 /* Create a partition entry that represents the empty disk */
1088 if (DiskEntry
->SectorAlignment
< 2048)
1089 StartSector
= 2048ULL;
1091 StartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1092 SectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) - StartSector
;
1094 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1095 &DiskEntry
->PrimaryPartListHead
,
1099 if (NewPartEntry
== NULL
)
1100 DPRINT1("Failed to create a new empty region for full disk space!\n");
1105 /* Start partition at head 1, cylinder 0 */
1106 if (DiskEntry
->SectorAlignment
< 2048)
1107 LastStartSector
= 2048ULL;
1109 LastStartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1110 LastSectorCount
= 0ULL;
1111 LastUnusedSectorCount
= 0ULL;
1113 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1114 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1115 Entry
= Entry
->Flink
)
1117 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1119 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1120 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1122 LastUnusedSectorCount
=
1123 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
1125 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
1126 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1128 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1130 StartSector
= LastStartSector
+ LastSectorCount
;
1131 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1133 /* Insert the table into the list */
1134 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1135 &PartEntry
->ListEntry
,
1139 if (NewPartEntry
== NULL
)
1141 DPRINT1("Failed to create a new empty region for disk space!\n");
1146 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1147 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1151 /* Check for trailing unpartitioned disk space */
1152 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
1154 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
1156 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1158 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1160 StartSector
= LastStartSector
+ LastSectorCount
;
1161 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1163 /* Append the table to the list */
1164 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1165 &DiskEntry
->PrimaryPartListHead
,
1169 if (NewPartEntry
== NULL
)
1171 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1177 if (DiskEntry
->ExtendedPartition
!= NULL
)
1179 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1181 DPRINT1("No logical partition!\n");
1183 /* Create a partition entry that represents the empty extended partition */
1185 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1186 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
1188 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1189 &DiskEntry
->LogicalPartListHead
,
1193 if (NewPartEntry
== NULL
)
1195 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1198 NewPartEntry
->LogicalPartition
= TRUE
;
1203 /* Start partition at head 1, cylinder 0 */
1204 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1205 LastSectorCount
= 0ULL;
1206 LastUnusedSectorCount
= 0ULL;
1208 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1209 Entry
!= &DiskEntry
->LogicalPartListHead
;
1210 Entry
= Entry
->Flink
)
1212 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1214 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1215 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1217 LastUnusedSectorCount
=
1218 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
1220 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
1221 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1223 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1225 StartSector
= LastStartSector
+ LastSectorCount
;
1226 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1228 /* Insert the table into the list */
1229 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1230 &PartEntry
->ListEntry
,
1234 if (NewPartEntry
== NULL
)
1236 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1239 NewPartEntry
->LogicalPartition
= TRUE
;
1242 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1243 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1247 /* Check for trailing unpartitioned disk space */
1248 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
1250 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+
1251 DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
1252 DiskEntry
->SectorAlignment
);
1254 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1256 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1258 StartSector
= LastStartSector
+ LastSectorCount
;
1259 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1261 /* Append the table to the list */
1262 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1263 &DiskEntry
->LogicalPartListHead
,
1267 if (NewPartEntry
== NULL
)
1269 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1272 NewPartEntry
->LogicalPartition
= TRUE
;
1277 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1284 IN PDISKENTRY DiskEntry
)
1286 LARGE_INTEGER SystemTime
;
1287 TIME_FIELDS TimeFields
;
1289 PDISKENTRY DiskEntry2
;
1292 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1294 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1298 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1302 NtQuerySystemTime(&SystemTime
);
1303 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1305 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1306 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1307 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1308 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1310 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1315 /* Check if the signature already exist */
1317 * Check also signatures from disks, which are
1318 * not visible (bootable) by the bios.
1320 for (Entry2
= List
->DiskListHead
.Flink
;
1321 Entry2
!= &List
->DiskListHead
;
1322 Entry2
= Entry2
->Flink
)
1324 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1326 if (DiskEntry2
->DiskStyle
== PARTITION_STYLE_GPT
)
1328 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1332 if (DiskEntry
!= DiskEntry2
&&
1333 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1337 if (Entry2
== &List
->DiskListHead
)
1344 UpdateDiskSignatures(
1348 PDISKENTRY DiskEntry
;
1350 /* Update each disk */
1351 for (Entry
= List
->DiskListHead
.Flink
;
1352 Entry
!= &List
->DiskListHead
;
1353 Entry
= Entry
->Flink
)
1355 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1357 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1359 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1363 if (DiskEntry
->LayoutBuffer
&&
1364 DiskEntry
->LayoutBuffer
->Signature
== 0)
1366 SetDiskSignature(List
, DiskEntry
);
1367 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1374 UpdateHwDiskNumbers(
1377 PLIST_ENTRY ListEntry
;
1378 PBIOSDISKENTRY BiosDiskEntry
;
1379 PDISKENTRY DiskEntry
;
1380 ULONG HwAdapterNumber
= 0;
1381 ULONG HwControllerNumber
= 0;
1382 ULONG RemovableDiskCount
= 0;
1385 * Enumerate the disks recognized by the BIOS and recompute the disk
1386 * numbers on the system when *ALL* removable disks are not connected.
1387 * The entries are inserted in increasing order of AdapterNumber,
1388 * ControllerNumber and DiskNumber.
1390 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1391 ListEntry
!= &List
->BiosDiskListHead
;
1392 ListEntry
= ListEntry
->Flink
)
1394 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1395 DiskEntry
= BiosDiskEntry
->DiskEntry
;
1398 * If the adapter or controller numbers change, update them and reset
1399 * the number of removable disks on this adapter/controller.
1401 if (HwAdapterNumber
!= BiosDiskEntry
->AdapterNumber
||
1402 HwControllerNumber
!= BiosDiskEntry
->ControllerNumber
)
1404 HwAdapterNumber
= BiosDiskEntry
->AdapterNumber
;
1405 HwControllerNumber
= BiosDiskEntry
->ControllerNumber
;
1406 RemovableDiskCount
= 0;
1409 /* Adjust the actual hardware disk number */
1412 ASSERT(DiskEntry
->HwDiskNumber
== BiosDiskEntry
->DiskNumber
);
1414 if (DiskEntry
->MediaType
== RemovableMedia
)
1416 /* Increase the number of removable disks and set the disk number to zero */
1417 ++RemovableDiskCount
;
1418 DiskEntry
->HwFixedDiskNumber
= 0;
1420 else // if (DiskEntry->MediaType == FixedMedia)
1422 /* Adjust the fixed disk number, offset by the number of removable disks found before this one */
1423 DiskEntry
->HwFixedDiskNumber
= BiosDiskEntry
->DiskNumber
- RemovableDiskCount
;
1428 DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry
->DiskNumber
);
1436 IN HANDLE FileHandle
,
1437 IN ULONG DiskNumber
,
1440 DISK_GEOMETRY DiskGeometry
;
1441 SCSI_ADDRESS ScsiAddress
;
1442 PDISKENTRY DiskEntry
;
1443 IO_STATUS_BLOCK Iosb
;
1445 PPARTITION_SECTOR Mbr
;
1447 LARGE_INTEGER FileOffset
;
1448 WCHAR Identifier
[20];
1452 PLIST_ENTRY ListEntry
;
1453 PBIOSDISKENTRY BiosDiskEntry
;
1454 ULONG LayoutBufferSize
;
1455 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1457 /* Retrieve the drive geometry */
1458 Status
= NtDeviceIoControlFile(FileHandle
,
1463 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1467 sizeof(DiskGeometry
));
1468 if (!NT_SUCCESS(Status
))
1471 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1472 DiskGeometry
.MediaType
!= RemovableMedia
)
1478 * FIXME: Here we suppose the disk is always SCSI. What if it is
1479 * of another type? To check this we need to retrieve the name of
1480 * the driver the disk device belongs to.
1482 Status
= NtDeviceIoControlFile(FileHandle
,
1487 IOCTL_SCSI_GET_ADDRESS
,
1491 sizeof(ScsiAddress
));
1492 if (!NT_SUCCESS(Status
))
1496 * Check whether the disk is initialized, by looking at its MBR.
1497 * NOTE that this must be generalized to GPT disks as well!
1500 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1502 DiskGeometry
.BytesPerSector
);
1506 FileOffset
.QuadPart
= 0;
1507 Status
= NtReadFile(FileHandle
,
1513 DiskGeometry
.BytesPerSector
,
1516 if (!NT_SUCCESS(Status
))
1518 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1519 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1522 Signature
= Mbr
->Signature
;
1524 /* Calculate the MBR checksum */
1526 Buffer
= (PULONG
)Mbr
;
1527 for (i
= 0; i
< 128; i
++)
1529 Checksum
+= Buffer
[i
];
1531 Checksum
= ~Checksum
+ 1;
1533 RtlStringCchPrintfW(Identifier
, ARRAYSIZE(Identifier
),
1535 Checksum
, Signature
,
1536 (Mbr
->Magic
== PARTITION_MAGIC
) ? L
'A' : L
'X');
1537 DPRINT("Identifier: %S\n", Identifier
);
1539 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1542 if (DiskEntry
== NULL
)
1544 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1545 DPRINT1("Failed to allocate a new disk entry.\n");
1549 DiskEntry
->PartList
= List
;
1553 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
1555 /* Query the device for its type */
1556 Status
= NtQueryVolumeInformationFile(FileHandle
,
1559 sizeof(FileFsDevice
),
1560 FileFsDeviceInformation
);
1561 if (!NT_SUCCESS(Status
))
1563 DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber
, Identifier
);
1567 DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber
, FileFsDevice
.DeviceType
, FileFsDevice
.Characteristics
);
1570 // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation).
1572 DiskEntry
->MediaType
= DiskGeometry
.MediaType
;
1573 if (DiskEntry
->MediaType
== RemovableMedia
)
1575 DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber
, Identifier
);
1577 else // if (DiskEntry->MediaType == FixedMedia)
1579 DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber
, Identifier
);
1582 // DiskEntry->Checksum = Checksum;
1583 // DiskEntry->Signature = Signature;
1584 DiskEntry
->BiosFound
= FALSE
;
1587 * Check if this disk has a valid MBR: verify its signature,
1588 * and whether its two first bytes are a valid instruction
1589 * (related to this, see IsThereAValidBootSector() in partlist.c).
1591 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1594 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1596 /* If we have not the 0xAA55 then it's raw partition */
1597 if (Mbr
->Magic
!= PARTITION_MAGIC
)
1599 DiskEntry
->DiskStyle
= PARTITION_STYLE_RAW
;
1601 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1602 else if (Mbr
->Partition
[0].PartitionType
== EFI_PMBR_OSTYPE_EFI
&&
1603 Mbr
->Partition
[1].PartitionType
== 0 &&
1604 Mbr
->Partition
[2].PartitionType
== 0 &&
1605 Mbr
->Partition
[3].PartitionType
== 0)
1607 DiskEntry
->DiskStyle
= PARTITION_STYLE_GPT
;
1609 /* Otherwise, partition table is in MBR */
1612 DiskEntry
->DiskStyle
= PARTITION_STYLE_MBR
;
1615 /* Free the MBR sector buffer */
1616 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1619 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1620 ListEntry
!= &List
->BiosDiskListHead
;
1621 ListEntry
= ListEntry
->Flink
)
1623 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1625 * Compare the size from bios and the reported size from driver.
1626 * If we have more than one disk with a zero or with the same signature
1627 * we must create new signatures and reboot. After the reboot,
1628 * it is possible to identify the disks.
1630 if (BiosDiskEntry
->Signature
== Signature
&&
1631 BiosDiskEntry
->Checksum
== Checksum
&&
1632 BiosDiskEntry
->DiskEntry
== NULL
)
1634 if (!DiskEntry
->BiosFound
)
1636 DiskEntry
->HwAdapterNumber
= BiosDiskEntry
->AdapterNumber
;
1637 DiskEntry
->HwControllerNumber
= BiosDiskEntry
->ControllerNumber
;
1638 DiskEntry
->HwDiskNumber
= BiosDiskEntry
->DiskNumber
;
1640 if (DiskEntry
->MediaType
== RemovableMedia
)
1642 /* Set the removable disk number to zero */
1643 DiskEntry
->HwFixedDiskNumber
= 0;
1645 else // if (DiskEntry->MediaType == FixedMedia)
1647 /* The fixed disk number will later be adjusted using the number of removable disks */
1648 DiskEntry
->HwFixedDiskNumber
= BiosDiskEntry
->DiskNumber
;
1651 DiskEntry
->BiosFound
= TRUE
;
1652 BiosDiskEntry
->DiskEntry
= DiskEntry
;
1657 // FIXME: What to do?
1658 DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber
, Identifier
);
1663 if (!DiskEntry
->BiosFound
)
1665 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber
);
1668 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1669 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1670 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1671 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1673 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1674 DPRINT("TracksPerCylinder %lu\n", DiskEntry
->TracksPerCylinder
);
1675 DPRINT("SectorsPerTrack %lu\n", DiskEntry
->SectorsPerTrack
);
1676 DPRINT("BytesPerSector %lu\n", DiskEntry
->BytesPerSector
);
1678 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1679 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1680 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1682 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1683 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1684 DiskGeometry
.SectorsPerTrack
;
1686 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
.QuadPart
);
1687 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1689 DiskEntry
->DiskNumber
= DiskNumber
;
1690 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1691 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1692 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1694 GetDriverName(DiskEntry
);
1696 * Actually it would be more correct somehow to use:
1698 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1699 * ULONG ReturnedLength;
1701 * Status = NtQueryObject(SomeHandleToTheDisk,
1702 * ObjectNameInformation,
1708 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1711 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1712 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1714 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1718 * We now retrieve the disk partition layout
1722 * Stop there now if the disk is GPT-partitioned,
1723 * since we currently do not support such disks.
1725 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1727 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1731 /* Allocate a layout buffer with 4 partition entries first */
1732 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1733 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1734 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1737 if (DiskEntry
->LayoutBuffer
== NULL
)
1739 DPRINT1("Failed to allocate the disk layout buffer!\n");
1743 /* Keep looping while the drive layout buffer is too small */
1746 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1747 Status
= NtDeviceIoControlFile(FileHandle
,
1752 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1755 DiskEntry
->LayoutBuffer
,
1757 if (NT_SUCCESS(Status
))
1760 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1762 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1766 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1767 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1769 DiskEntry
->LayoutBuffer
,
1771 if (NewLayoutBuffer
== NULL
)
1773 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1777 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1780 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1782 #ifdef DUMP_PARTITION_TABLE
1783 DumpPartitionTable(DiskEntry
);
1786 if (IsSuperFloppy(DiskEntry
))
1787 DPRINT1("Disk %lu is a super-floppy\n", DiskNumber
);
1789 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1790 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1791 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= PARTITION_ENTRY_UNUSED
)
1793 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1795 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1797 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1799 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1803 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1808 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1811 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1813 DiskEntry
->NewDisk
= TRUE
;
1814 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1816 for (i
= 0; i
< 4; i
++)
1818 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1823 /* Enumerate and add the first four primary partitions */
1824 for (i
= 0; i
< 4; i
++)
1826 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, FALSE
);
1829 /* Enumerate and add the remaining partitions as logical ones */
1830 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1832 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, TRUE
);
1836 ScanForUnpartitionedDiskSpace(DiskEntry
);
1840 CreatePartitionList(VOID
)
1843 OBJECT_ATTRIBUTES ObjectAttributes
;
1844 SYSTEM_DEVICE_INFORMATION Sdi
;
1845 IO_STATUS_BLOCK Iosb
;
1849 WCHAR Buffer
[MAX_PATH
];
1850 UNICODE_STRING Name
;
1853 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1859 List
->SystemPartition
= NULL
;
1860 List
->OriginalSystemPartition
= NULL
;
1862 InitializeListHead(&List
->DiskListHead
);
1863 InitializeListHead(&List
->BiosDiskListHead
);
1866 * Enumerate the disks seen by the BIOS; this will be used later
1867 * to map drives seen by NTOS with their corresponding BIOS names.
1869 EnumerateBiosDiskEntries(List
);
1871 /* Enumerate disks seen by NTOS */
1872 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1876 if (!NT_SUCCESS(Status
))
1878 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status
);
1879 RtlFreeHeap(ProcessHeap
, 0, List
);
1883 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1885 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
1886 L
"\\Device\\Harddisk%lu\\Partition0",
1888 RtlInitUnicodeString(&Name
, Buffer
);
1890 InitializeObjectAttributes(&ObjectAttributes
,
1892 OBJ_CASE_INSENSITIVE
,
1896 Status
= NtOpenFile(&FileHandle
,
1897 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1900 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1901 FILE_SYNCHRONOUS_IO_NONALERT
);
1902 if (NT_SUCCESS(Status
))
1904 AddDiskToList(FileHandle
, DiskNumber
, List
);
1905 NtClose(FileHandle
);
1909 UpdateDiskSignatures(List
);
1910 UpdateHwDiskNumbers(List
);
1911 AssignDriveLetters(List
);
1917 DestroyPartitionList(
1920 PDISKENTRY DiskEntry
;
1921 PBIOSDISKENTRY BiosDiskEntry
;
1922 PPARTENTRY PartEntry
;
1925 /* Release disk and partition info */
1926 while (!IsListEmpty(&List
->DiskListHead
))
1928 Entry
= RemoveHeadList(&List
->DiskListHead
);
1929 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1931 /* Release driver name */
1932 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1934 /* Release primary partition list */
1935 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1937 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1938 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1940 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1943 /* Release logical partition list */
1944 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1946 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1947 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1949 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1952 /* Release layout buffer */
1953 if (DiskEntry
->LayoutBuffer
!= NULL
)
1954 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1956 /* Release disk entry */
1957 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1960 /* Release the bios disk info */
1961 while (!IsListEmpty(&List
->BiosDiskListHead
))
1963 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1964 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1966 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
1969 /* Release list head */
1970 RtlFreeHeap(ProcessHeap
, 0, List
);
1974 GetDiskByBiosNumber(
1976 IN ULONG HwDiskNumber
)
1978 PDISKENTRY DiskEntry
;
1981 /* Loop over the disks and find the correct one */
1982 for (Entry
= List
->DiskListHead
.Flink
;
1983 Entry
!= &List
->DiskListHead
;
1984 Entry
= Entry
->Flink
)
1986 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1988 if (DiskEntry
->HwDiskNumber
== HwDiskNumber
)
1995 /* Disk not found, stop there */
2002 IN ULONG DiskNumber
)
2004 PDISKENTRY DiskEntry
;
2007 /* Loop over the disks and find the correct one */
2008 for (Entry
= List
->DiskListHead
.Flink
;
2009 Entry
!= &List
->DiskListHead
;
2010 Entry
= Entry
->Flink
)
2012 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2014 if (DiskEntry
->DiskNumber
== DiskNumber
)
2021 /* Disk not found, stop there */
2032 PDISKENTRY DiskEntry
;
2035 /* Loop over the disks and find the correct one */
2036 for (Entry
= List
->DiskListHead
.Flink
;
2037 Entry
!= &List
->DiskListHead
;
2038 Entry
= Entry
->Flink
)
2040 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2042 if (DiskEntry
->Port
== Port
&&
2043 DiskEntry
->Bus
== Bus
&&
2044 DiskEntry
->Id
== Id
)
2051 /* Disk not found, stop there */
2060 PDISKENTRY DiskEntry
;
2063 /* Loop over the disks and find the correct one */
2064 for (Entry
= List
->DiskListHead
.Flink
;
2065 Entry
!= &List
->DiskListHead
;
2066 Entry
= Entry
->Flink
)
2068 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2070 if (DiskEntry
->LayoutBuffer
->Signature
== Signature
)
2077 /* Disk not found, stop there */
2083 // IN PPARTLIST List,
2084 IN PDISKENTRY DiskEntry
,
2085 IN ULONG PartitionNumber
)
2087 PPARTENTRY PartEntry
;
2090 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2092 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2096 /* Disk found, loop over the primary partitions first... */
2097 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2098 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2099 Entry
= Entry
->Flink
)
2101 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2103 if (PartEntry
->PartitionNumber
== PartitionNumber
)
2105 /* Partition found */
2110 /* ... then over the logical partitions if needed */
2111 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
2112 Entry
!= &DiskEntry
->LogicalPartListHead
;
2113 Entry
= Entry
->Flink
)
2115 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2117 if (PartEntry
->PartitionNumber
== PartitionNumber
)
2119 /* Partition found */
2124 /* The partition was not found on the disk, stop there */
2131 IN ULONG DiskNumber
,
2132 IN ULONG PartitionNumber OPTIONAL
,
2133 OUT PDISKENTRY
* pDiskEntry
,
2134 OUT PPARTENTRY
* pPartEntry OPTIONAL
)
2136 PDISKENTRY DiskEntry
;
2137 PPARTENTRY PartEntry
= NULL
;
2140 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
2144 /* If we have a partition (PartitionNumber != 0), find it */
2145 if (PartitionNumber
!= 0)
2147 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2149 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2153 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
2156 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2159 /* Return the disk (and optionally the partition) */
2160 *pDiskEntry
= DiskEntry
;
2161 if (pPartEntry
) *pPartEntry
= PartEntry
;
2166 // NOTE: Was introduced broken in r6258 by Casper
2171 IN ULONG DiskNumber
,
2172 IN ULONG PartitionNumber
)
2174 PDISKENTRY DiskEntry
;
2175 PPARTENTRY PartEntry
;
2177 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
2181 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
2185 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2186 ASSERT(DiskEntry
->DiskNumber
== DiskNumber
);
2187 ASSERT(PartEntry
->PartitionNumber
== PartitionNumber
);
2195 IN PPARTENTRY CurrentPart OPTIONAL
)
2197 PLIST_ENTRY DiskListEntry
;
2198 PLIST_ENTRY PartListEntry
;
2199 PDISKENTRY CurrentDisk
;
2201 /* Fail if no disks are available */
2202 if (IsListEmpty(&List
->DiskListHead
))
2205 /* Check for the next usable entry on the current partition's disk */
2206 if (CurrentPart
!= NULL
)
2208 CurrentDisk
= CurrentPart
->DiskEntry
;
2210 if (CurrentPart
->LogicalPartition
)
2212 /* Logical partition */
2214 PartListEntry
= CurrentPart
->ListEntry
.Flink
;
2215 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2217 /* Next logical partition */
2218 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2223 PartListEntry
= CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
2224 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2226 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2233 /* Primary or extended partition */
2235 if (CurrentPart
->IsPartitioned
&&
2236 IsContainerPartition(CurrentPart
->PartitionType
))
2238 /* First logical partition */
2239 PartListEntry
= CurrentDisk
->LogicalPartListHead
.Flink
;
2240 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2242 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2248 /* Next primary partition */
2249 PartListEntry
= CurrentPart
->ListEntry
.Flink
;
2250 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2252 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2259 /* Search for the first partition entry on the next disk */
2260 for (DiskListEntry
= (CurrentPart
? CurrentDisk
->ListEntry
.Flink
2261 : List
->DiskListHead
.Flink
);
2262 DiskListEntry
!= &List
->DiskListHead
;
2263 DiskListEntry
= DiskListEntry
->Flink
)
2265 CurrentDisk
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2267 if (CurrentDisk
->DiskStyle
== PARTITION_STYLE_GPT
)
2269 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2273 PartListEntry
= CurrentDisk
->PrimaryPartListHead
.Flink
;
2274 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2276 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2287 IN PPARTENTRY CurrentPart OPTIONAL
)
2289 PLIST_ENTRY DiskListEntry
;
2290 PLIST_ENTRY PartListEntry
;
2291 PDISKENTRY CurrentDisk
;
2293 /* Fail if no disks are available */
2294 if (IsListEmpty(&List
->DiskListHead
))
2297 /* Check for the previous usable entry on the current partition's disk */
2298 if (CurrentPart
!= NULL
)
2300 CurrentDisk
= CurrentPart
->DiskEntry
;
2302 if (CurrentPart
->LogicalPartition
)
2304 /* Logical partition */
2306 PartListEntry
= CurrentPart
->ListEntry
.Blink
;
2307 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2309 /* Previous logical partition */
2310 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2314 /* Extended partition */
2315 CurrentPart
= CurrentDisk
->ExtendedPartition
;
2321 /* Primary or extended partition */
2323 PartListEntry
= CurrentPart
->ListEntry
.Blink
;
2324 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2326 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2328 if (CurrentPart
->IsPartitioned
&&
2329 IsContainerPartition(CurrentPart
->PartitionType
))
2331 PartListEntry
= CurrentDisk
->LogicalPartListHead
.Blink
;
2332 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2340 /* Search for the last partition entry on the previous disk */
2341 for (DiskListEntry
= (CurrentPart
? CurrentDisk
->ListEntry
.Blink
2342 : List
->DiskListHead
.Blink
);
2343 DiskListEntry
!= &List
->DiskListHead
;
2344 DiskListEntry
= DiskListEntry
->Blink
)
2346 CurrentDisk
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2348 if (CurrentDisk
->DiskStyle
== PARTITION_STYLE_GPT
)
2350 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2354 PartListEntry
= CurrentDisk
->PrimaryPartListHead
.Blink
;
2355 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2357 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2359 if (CurrentPart
->IsPartitioned
&&
2360 IsContainerPartition(CurrentPart
->PartitionType
))
2362 PartListEntry
= CurrentDisk
->LogicalPartListHead
.Blink
;
2363 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2365 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2383 IN PPARTITION_INFORMATION PartitionInfo
)
2385 if (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2386 PartitionInfo
->PartitionLength
.QuadPart
== 0)
2397 IsSamePrimaryLayoutEntry(
2398 IN PPARTITION_INFORMATION PartitionInfo
,
2399 IN PDISKENTRY DiskEntry
,
2400 IN PPARTENTRY PartEntry
)
2402 if (PartitionInfo
->StartingOffset
.QuadPart
== PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
&&
2403 PartitionInfo
->PartitionLength
.QuadPart
== PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
)
2404 // PartitionInfo->PartitionType == PartEntry->PartitionType
2414 GetPrimaryPartitionCount(
2415 IN PDISKENTRY DiskEntry
)
2418 PPARTENTRY PartEntry
;
2421 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2423 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2427 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2428 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2429 Entry
= Entry
->Flink
)
2431 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2432 if (PartEntry
->IsPartitioned
)
2441 GetLogicalPartitionCount(
2442 IN PDISKENTRY DiskEntry
)
2444 PLIST_ENTRY ListEntry
;
2445 PPARTENTRY PartEntry
;
2448 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2450 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2454 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2455 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2456 ListEntry
= ListEntry
->Flink
)
2458 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2459 if (PartEntry
->IsPartitioned
)
2468 ReAllocateLayoutBuffer(
2469 IN PDISKENTRY DiskEntry
)
2471 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2472 ULONG NewPartitionCount
;
2473 ULONG CurrentPartitionCount
= 0;
2474 ULONG LayoutBufferSize
;
2477 DPRINT1("ReAllocateLayoutBuffer()\n");
2479 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2481 if (DiskEntry
->LayoutBuffer
)
2482 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2484 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2485 CurrentPartitionCount
, NewPartitionCount
);
2487 if (CurrentPartitionCount
== NewPartitionCount
)
2490 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2491 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2492 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2494 DiskEntry
->LayoutBuffer
,
2496 if (NewLayoutBuffer
== NULL
)
2498 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2502 NewLayoutBuffer
->PartitionCount
= NewPartitionCount
;
2504 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2505 if (NewPartitionCount
> CurrentPartitionCount
)
2507 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2509 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2513 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2521 IN PDISKENTRY DiskEntry
)
2523 PPARTITION_INFORMATION PartitionInfo
;
2524 PPARTITION_INFORMATION LinkInfo
= NULL
;
2525 PLIST_ENTRY ListEntry
;
2526 PPARTENTRY PartEntry
;
2527 LARGE_INTEGER HiddenSectors64
;
2529 ULONG PartitionNumber
= 1;
2531 DPRINT1("UpdateDiskLayout()\n");
2533 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2535 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2539 /* Resize the layout buffer if necessary */
2540 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2542 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2546 /* Update the primary partition table */
2548 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2549 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
2550 ListEntry
= ListEntry
->Flink
)
2552 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2554 if (PartEntry
->IsPartitioned
)
2556 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2558 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2559 PartEntry
->PartitionIndex
= Index
;
2561 /* Reset the current partition number only for newly-created (unmounted) partitions */
2563 PartEntry
->PartitionNumber
= 0;
2565 PartEntry
->OnDiskPartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
) ? PartitionNumber
: 0);
2567 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, DiskEntry
, PartEntry
))
2569 DPRINT1("Updating primary partition entry %lu\n", Index
);
2571 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2572 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2573 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2574 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2575 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2576 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2577 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2578 PartitionInfo
->RewritePartition
= TRUE
;
2581 if (!IsContainerPartition(PartEntry
->PartitionType
))
2590 /* Update the logical partition table */
2592 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2593 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2594 ListEntry
= ListEntry
->Flink
)
2596 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2598 if (PartEntry
->IsPartitioned
)
2600 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2602 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2603 PartEntry
->PartitionIndex
= Index
;
2605 /* Reset the current partition number only for newly-created (unmounted) partitions */
2607 PartEntry
->PartitionNumber
= 0;
2609 PartEntry
->OnDiskPartitionNumber
= PartitionNumber
;
2611 DPRINT1("Updating logical partition entry %lu\n", Index
);
2613 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2614 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2615 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2616 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2617 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2618 PartitionInfo
->BootIndicator
= FALSE
;
2619 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2620 PartitionInfo
->RewritePartition
= TRUE
;
2622 /* Fill the link entry of the previous partition entry */
2623 if (LinkInfo
!= NULL
)
2625 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2626 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2627 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2628 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2629 LinkInfo
->PartitionNumber
= 0;
2630 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2631 LinkInfo
->BootIndicator
= FALSE
;
2632 LinkInfo
->RecognizedPartition
= FALSE
;
2633 LinkInfo
->RewritePartition
= TRUE
;
2636 /* Save a pointer to the link entry of the current partition entry */
2637 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2644 /* Wipe unused primary partition entries */
2645 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2647 DPRINT1("Primary partition entry %lu\n", Index
);
2649 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2651 if (!IsEmptyLayoutEntry(PartitionInfo
))
2653 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2655 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2656 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2657 PartitionInfo
->HiddenSectors
= 0;
2658 PartitionInfo
->PartitionNumber
= 0;
2659 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2660 PartitionInfo
->BootIndicator
= FALSE
;
2661 PartitionInfo
->RecognizedPartition
= FALSE
;
2662 PartitionInfo
->RewritePartition
= TRUE
;
2666 /* Wipe unused logical partition entries */
2667 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2671 DPRINT1("Logical partition entry %lu\n", Index
);
2673 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2675 if (!IsEmptyLayoutEntry(PartitionInfo
))
2677 DPRINT1("Wiping partition entry %lu\n", Index
);
2679 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2680 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2681 PartitionInfo
->HiddenSectors
= 0;
2682 PartitionInfo
->PartitionNumber
= 0;
2683 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2684 PartitionInfo
->BootIndicator
= FALSE
;
2685 PartitionInfo
->RecognizedPartition
= FALSE
;
2686 PartitionInfo
->RewritePartition
= TRUE
;
2691 DiskEntry
->Dirty
= TRUE
;
2693 #ifdef DUMP_PARTITION_TABLE
2694 DumpPartitionTable(DiskEntry
);
2700 GetPrevUnpartitionedEntry(
2701 IN PPARTENTRY PartEntry
)
2703 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
2704 PPARTENTRY PrevPartEntry
;
2705 PLIST_ENTRY ListHead
;
2707 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2709 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2713 if (PartEntry
->LogicalPartition
)
2714 ListHead
= &DiskEntry
->LogicalPartListHead
;
2716 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2718 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2720 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2723 if (!PrevPartEntry
->IsPartitioned
)
2725 ASSERT(PrevPartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
2726 return PrevPartEntry
;
2735 GetNextUnpartitionedEntry(
2736 IN PPARTENTRY PartEntry
)
2738 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
2739 PPARTENTRY NextPartEntry
;
2740 PLIST_ENTRY ListHead
;
2742 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2744 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2748 if (PartEntry
->LogicalPartition
)
2749 ListHead
= &DiskEntry
->LogicalPartListHead
;
2751 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2753 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2755 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2758 if (!NextPartEntry
->IsPartitioned
)
2760 ASSERT(NextPartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
2761 return NextPartEntry
;
2769 CreatePrimaryPartition(
2771 IN PPARTENTRY SelectedEntry
,
2772 IN ULONGLONG SectorCount
,
2773 IN BOOLEAN AutoCreate
)
2776 PPARTENTRY PartEntry
;
2778 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount
);
2781 SelectedEntry
== NULL
||
2782 SelectedEntry
->DiskEntry
== NULL
||
2783 SelectedEntry
->IsPartitioned
)
2788 Error
= PrimaryPartitionCreationChecks(SelectedEntry
);
2789 if (Error
!= NOT_AN_ERROR
)
2791 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error
);
2795 /* Convert the current entry, or insert and initialize a new partition entry */
2796 PartEntry
= InitializePartitionEntry(SelectedEntry
->DiskEntry
, SelectedEntry
, SectorCount
, AutoCreate
);
2797 if (PartEntry
== NULL
)
2800 UpdateDiskLayout(PartEntry
->DiskEntry
);
2802 AssignDriveLetters(List
);
2809 AddLogicalDiskSpace(
2810 IN PDISKENTRY DiskEntry
)
2812 ULONGLONG StartSector
;
2813 ULONGLONG SectorCount
;
2814 PPARTENTRY NewPartEntry
;
2816 DPRINT1("AddLogicalDiskSpace()\n");
2818 /* Create a partition entry that represents the empty space in the container partition */
2820 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2821 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2823 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
2824 &DiskEntry
->LogicalPartListHead
,
2828 if (NewPartEntry
== NULL
)
2830 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2833 NewPartEntry
->LogicalPartition
= TRUE
;
2837 CreateExtendedPartition(
2839 IN PPARTENTRY SelectedEntry
,
2840 IN ULONGLONG SectorCount
)
2843 PPARTENTRY PartEntry
;
2845 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount
);
2848 SelectedEntry
== NULL
||
2849 SelectedEntry
->DiskEntry
== NULL
||
2850 SelectedEntry
->IsPartitioned
)
2855 Error
= ExtendedPartitionCreationChecks(SelectedEntry
);
2856 if (Error
!= NOT_AN_ERROR
)
2858 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error
);
2862 /* Convert the current entry, or insert and initialize a new partition entry */
2863 PartEntry
= InitializePartitionEntry(SelectedEntry
->DiskEntry
, SelectedEntry
, SectorCount
, FALSE
);
2864 if (PartEntry
== NULL
)
2867 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2869 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2870 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2874 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2875 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2878 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2879 PartEntry
->New
= FALSE
;
2880 PartEntry
->FormatState
= Formatted
;
2882 PartEntry
->DiskEntry
->ExtendedPartition
= PartEntry
;
2884 AddLogicalDiskSpace(PartEntry
->DiskEntry
);
2886 UpdateDiskLayout(PartEntry
->DiskEntry
);
2888 AssignDriveLetters(List
);
2894 CreateLogicalPartition(
2896 IN PPARTENTRY SelectedEntry
,
2897 IN ULONGLONG SectorCount
,
2898 IN BOOLEAN AutoCreate
)
2901 PPARTENTRY PartEntry
;
2903 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount
);
2906 SelectedEntry
== NULL
||
2907 SelectedEntry
->DiskEntry
== NULL
||
2908 SelectedEntry
->IsPartitioned
)
2913 Error
= LogicalPartitionCreationChecks(SelectedEntry
);
2914 if (Error
!= NOT_AN_ERROR
)
2916 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error
);
2920 /* Convert the current entry, or insert and initialize a new partition entry */
2921 PartEntry
= InitializePartitionEntry(SelectedEntry
->DiskEntry
, SelectedEntry
, SectorCount
, AutoCreate
);
2922 if (PartEntry
== NULL
)
2925 PartEntry
->LogicalPartition
= TRUE
;
2927 UpdateDiskLayout(PartEntry
->DiskEntry
);
2929 AssignDriveLetters(List
);
2937 IN PPARTENTRY PartEntry
)
2940 NTSTATUS LockStatus
;
2941 UNICODE_STRING Name
;
2942 OBJECT_ATTRIBUTES ObjectAttributes
;
2943 IO_STATUS_BLOCK IoStatusBlock
;
2944 HANDLE PartitionHandle
;
2945 WCHAR Buffer
[MAX_PATH
];
2947 /* Check whether the partition is valid and was mounted by the system */
2948 if (!PartEntry
->IsPartitioned
||
2949 IsContainerPartition(PartEntry
->PartitionType
) ||
2950 !IsRecognizedPartition(PartEntry
->PartitionType
) ||
2951 PartEntry
->FormatState
== Unformatted
/* || PartEntry->FormatState == UnknownFormat */ ||
2952 !*PartEntry
->FileSystem
||
2953 PartEntry
->PartitionNumber
== 0)
2955 /* The partition is not mounted, so just return success */
2956 return STATUS_SUCCESS
;
2959 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2961 /* Open the volume */
2962 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
2963 L
"\\Device\\Harddisk%lu\\Partition%lu",
2964 PartEntry
->DiskEntry
->DiskNumber
,
2965 PartEntry
->PartitionNumber
);
2966 RtlInitUnicodeString(&Name
, Buffer
);
2968 InitializeObjectAttributes(&ObjectAttributes
,
2970 OBJ_CASE_INSENSITIVE
,
2974 Status
= NtOpenFile(&PartitionHandle
,
2975 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
2978 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2979 FILE_SYNCHRONOUS_IO_NONALERT
);
2980 if (!NT_SUCCESS(Status
))
2982 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name
, Status
);
2986 /* Lock the volume */
2987 LockStatus
= NtFsControlFile(PartitionHandle
,
2997 if (!NT_SUCCESS(LockStatus
))
2999 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus
);
3002 /* Dismount the volume */
3003 Status
= NtFsControlFile(PartitionHandle
,
3008 FSCTL_DISMOUNT_VOLUME
,
3013 if (!NT_SUCCESS(Status
))
3015 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status
);
3018 /* Unlock the volume */
3019 LockStatus
= NtFsControlFile(PartitionHandle
,
3024 FSCTL_UNLOCK_VOLUME
,
3029 if (!NT_SUCCESS(LockStatus
))
3031 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus
);
3034 /* Close the volume */
3035 NtClose(PartitionHandle
);
3043 IN PPARTENTRY PartEntry
,
3044 OUT PPARTENTRY
* FreeRegion OPTIONAL
)
3046 PDISKENTRY DiskEntry
;
3047 PPARTENTRY PrevPartEntry
;
3048 PPARTENTRY NextPartEntry
;
3049 PPARTENTRY LogicalPartEntry
;
3053 PartEntry
== NULL
||
3054 PartEntry
->DiskEntry
== NULL
||
3055 PartEntry
->IsPartitioned
== FALSE
)
3060 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3062 /* Clear the system partition pointers if it is being deleted */
3063 if (List
->SystemPartition
== PartEntry
)
3065 ASSERT(List
->SystemPartition
);
3066 ASSERT(List
->SystemPartition
->DiskEntry
->MediaType
!= RemovableMedia
);
3068 if (List
->SystemPartition
== List
->OriginalSystemPartition
)
3069 List
->OriginalSystemPartition
= NULL
;
3070 List
->SystemPartition
= NULL
;
3073 DiskEntry
= PartEntry
->DiskEntry
;
3075 /* Check which type of partition (primary/logical or extended) is being deleted */
3076 if (DiskEntry
->ExtendedPartition
== PartEntry
)
3078 /* An extended partition is being deleted: delete all logical partition entries */
3079 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
3081 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
3082 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
3084 /* Dismount the logical partition */
3085 DismountVolume(LogicalPartEntry
);
3088 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
3091 DiskEntry
->ExtendedPartition
= NULL
;
3095 /* A primary partition is being deleted: dismount it */
3096 DismountVolume(PartEntry
);
3099 /* Adjust the unpartitioned disk space entries */
3101 /* Get pointer to previous and next unpartitioned entries */
3102 PrevPartEntry
= GetPrevUnpartitionedEntry(PartEntry
);
3103 NextPartEntry
= GetNextUnpartitionedEntry(PartEntry
);
3105 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
3107 /* Merge the previous, current and next unpartitioned entries */
3109 /* Adjust the previous entry length */
3110 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
3112 /* Remove the current and next entries */
3113 RemoveEntryList(&PartEntry
->ListEntry
);
3114 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3115 RemoveEntryList(&NextPartEntry
->ListEntry
);
3116 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
3118 /* Optionally return the freed region */
3120 *FreeRegion
= PrevPartEntry
;
3122 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
3124 /* Merge the current and the previous unpartitioned entries */
3126 /* Adjust the previous entry length */
3127 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3129 /* Remove the current entry */
3130 RemoveEntryList(&PartEntry
->ListEntry
);
3131 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3133 /* Optionally return the freed region */
3135 *FreeRegion
= PrevPartEntry
;
3137 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
3139 /* Merge the current and the next unpartitioned entries */
3141 /* Adjust the next entry offset and length */
3142 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
3143 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3145 /* Remove the current entry */
3146 RemoveEntryList(&PartEntry
->ListEntry
);
3147 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3149 /* Optionally return the freed region */
3151 *FreeRegion
= NextPartEntry
;
3155 /* Nothing to merge but change the current entry */
3156 PartEntry
->IsPartitioned
= FALSE
;
3157 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
3158 PartEntry
->FormatState
= Unformatted
;
3159 PartEntry
->FileSystem
[0] = L
'\0';
3160 PartEntry
->DriveLetter
= 0;
3161 PartEntry
->OnDiskPartitionNumber
= 0;
3162 PartEntry
->PartitionNumber
= 0;
3163 // PartEntry->PartitionIndex = 0;
3165 /* Optionally return the freed region */
3167 *FreeRegion
= PartEntry
;
3170 UpdateDiskLayout(DiskEntry
);
3172 AssignDriveLetters(List
);
3178 * Retrieve the actual "active" partition of the given disk.
3179 * On MBR disks, partition with the Active/Boot flag set;
3180 * on GPT disks, partition with the correct GUID.
3184 GetActiveDiskPartition(
3185 IN PDISKENTRY DiskEntry
)
3187 PLIST_ENTRY ListEntry
;
3188 PPARTENTRY PartEntry
;
3189 PPARTENTRY ActivePartition
= NULL
;
3191 /* Check for empty disk list */
3192 // ASSERT(DiskEntry);
3196 /* Check for empty partition list */
3197 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
3200 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3202 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3206 /* Scan all (primary) partitions to find the active disk partition */
3207 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3208 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3209 ListEntry
= ListEntry
->Flink
)
3211 /* Retrieve the partition */
3212 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3214 // TODO: Support for GPT disks!
3216 /* Check if the partition is partitioned, used and active */
3217 if (PartEntry
->IsPartitioned
&&
3218 // !IsContainerPartition(PartEntry->PartitionType) &&
3219 PartEntry
->BootIndicator
)
3221 /* Yes, we found it */
3222 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3223 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3225 ActivePartition
= PartEntry
;
3227 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3228 PartEntry
->PartitionNumber
, DiskEntry
->DiskNumber
,
3229 (PartEntry
->DriveLetter
== 0) ? L
'-' : PartEntry
->DriveLetter
);
3234 /* Check if the disk is new and if so, use its first partition as the active system partition */
3235 if (DiskEntry
->NewDisk
&& ActivePartition
!= NULL
)
3237 // FIXME: What to do??
3238 DPRINT1("NewDisk TRUE but already existing active partition?\n");
3241 /* Return the active partition found (or none) */
3242 return ActivePartition
;
3247 IsSupportedActivePartition(
3248 IN PPARTENTRY PartEntry
)
3250 /* Check the type and the filesystem of this partition */
3253 * We do not support extended partition containers (on MBR disks) marked
3254 * as active, and containing code inside their extended boot records.
3256 if (IsContainerPartition(PartEntry
->PartitionType
))
3258 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3259 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3264 * ADDITIONAL CHECKS / BIG HACK:
3266 * Retrieve its file system and check whether we have
3267 * write support for it. If that is the case we are fine
3268 * and we can use it directly. However if we don't have
3269 * write support we will need to change the active system
3272 * NOTE that this is completely useless on architectures
3273 * where a real system partition is required, as on these
3274 * architectures the partition uses the FAT FS, for which
3275 * we do have write support.
3276 * NOTE also that for those architectures looking for a
3277 * partition boot indicator is insufficient.
3279 if ((PartEntry
->FormatState
== Unformatted
) ||
3280 (PartEntry
->FormatState
== Preformatted
) ||
3281 (PartEntry
->FormatState
== Formatted
))
3283 ASSERT(*PartEntry
->FileSystem
);
3285 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3286 if (wcsicmp(PartEntry
->FileSystem
, L
"FAT") == 0 ||
3287 wcsicmp(PartEntry
->FileSystem
, L
"FAT32") == 0 ||
3288 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3289 wcsicmp(PartEntry
->FileSystem
, L
"BTRFS") == 0 ||
3290 wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
3296 // WARNING: We cannot write on this FS yet!
3297 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3298 PartEntry
->FileSystem
);
3302 else // if (PartEntry->FormatState == UnknownFormat)
3304 ASSERT(!*PartEntry
->FileSystem
);
3306 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3307 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3311 // HACK: WARNING: We cannot write on this FS yet!
3312 // See fsutil.c:InferFileSystem()
3313 if (PartEntry
->PartitionType
== PARTITION_IFS
)
3315 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3316 PartEntry
->FileSystem
);
3324 CheckActiveSystemPartition(
3326 IN BOOLEAN ForceSelect
,
3327 IN PDISKENTRY AlternateDisk OPTIONAL
,
3328 IN PPARTENTRY AlternatePart OPTIONAL
)
3330 PLIST_ENTRY ListEntry
;
3331 PDISKENTRY DiskEntry
;
3332 PPARTENTRY PartEntry
;
3333 PPARTENTRY ActivePartition
;
3334 PPARTENTRY CandidatePartition
= NULL
;
3336 /* Check for empty disk list */
3337 if (IsListEmpty(&List
->DiskListHead
))
3339 /* No system partition! */
3340 List
->SystemPartition
= NULL
;
3341 List
->OriginalSystemPartition
= NULL
;
3342 goto NoSystemPartition
;
3345 if (List
->SystemPartition
!= NULL
)
3347 /* We already have an active system partition */
3348 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3349 List
->SystemPartition
->PartitionNumber
,
3350 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3351 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3356 List
->SystemPartition
= NULL
;
3357 List
->OriginalSystemPartition
= NULL
;
3359 /* Adjust the optional alternate disk if needed */
3360 if (!AlternateDisk
&& AlternatePart
)
3361 AlternateDisk
= AlternatePart
->DiskEntry
;
3363 /* Ensure that the alternate partition is on the alternate disk */
3365 ASSERT(AlternateDisk
&& (AlternatePart
->DiskEntry
== AlternateDisk
));
3367 /* Ensure that the alternate disk is in the list */
3369 ASSERT(AlternateDisk
->PartList
== List
);
3372 // Pass == 1 : Check the first (system) disk.
3376 * First, check whether the first disk (the one that will be booted
3377 * by default by the hardware) contains an active partition. If so
3378 * this should be our system partition.
3380 DiskEntry
= CONTAINING_RECORD(List
->DiskListHead
.Flink
,
3381 DISKENTRY
, ListEntry
);
3383 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3385 DPRINT1("First (system) disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3386 goto UseAlternateDisk
;
3389 ActivePartition
= GetActiveDiskPartition(DiskEntry
);
3390 if (ActivePartition
)
3392 /* Save the actual system partition */
3393 List
->OriginalSystemPartition
= ActivePartition
;
3395 /* If we get a candidate active partition in the first disk, validate it */
3396 if (IsSupportedActivePartition(ActivePartition
))
3398 CandidatePartition
= ActivePartition
;
3399 goto SystemPartitionFound
;
3403 /* If this first disk is not the optional alternate disk, perform the minimal checks */
3404 if (DiskEntry
!= AlternateDisk
)
3407 * No active partition has been recognized. Enumerate all the (primary)
3408 * partitions in the first disk, excluding the possible current active
3409 * partition, to find a new candidate.
3411 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3412 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3413 ListEntry
= ListEntry
->Flink
)
3415 /* Retrieve the partition */
3416 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3418 /* Skip the current active partition */
3419 if (/* ActivePartition != NULL && */ PartEntry
== ActivePartition
)
3422 /* Check if the partition is partitioned and used */
3423 if (PartEntry
->IsPartitioned
&&
3424 !IsContainerPartition(PartEntry
->PartitionType
))
3426 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3428 /* If we get a candidate active partition in the first disk, validate it */
3429 if (IsSupportedActivePartition(PartEntry
))
3431 CandidatePartition
= PartEntry
;
3432 goto FindAndUseAlternativeSystemPartition
;
3437 /* Check if the partition is partitioned and used */
3438 if (!PartEntry
->IsPartitioned
)
3440 ASSERT(PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
3442 // TODO: Check for minimal size!!
3443 CandidatePartition
= PartEntry
;
3444 goto FindAndUseAlternativeSystemPartition
;
3450 * Still nothing, look whether there is some free space that we can use
3451 * for the new system partition. We must be sure that the total number
3452 * of partition is less than the maximum allowed, and that the minimal
3456 // TODO: Fix the handling of system partition being created in unpartitioned space!!
3457 // --> When to partition it? etc...
3459 if (GetPrimaryPartitionCount(DiskEntry
) < 4)
3461 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3462 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3463 ListEntry
= ListEntry
->Flink
)
3465 /* Retrieve the partition */
3466 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3468 /* Skip the current active partition */
3469 if (/* ActivePartition != NULL && */ PartEntry
== ActivePartition
)
3472 /* Check for unpartitioned space */
3473 if (!PartEntry
->IsPartitioned
)
3475 ASSERT(PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
3477 // TODO: Check for minimal size!!
3478 CandidatePartition
= PartEntry
;
3479 goto FindAndUseAlternativeSystemPartition
;
3487 // Pass == 2 : No active partition found: Check the alternate disk if specified.
3491 if (!AlternateDisk
|| (!ForceSelect
&& (DiskEntry
!= AlternateDisk
)))
3492 goto NoSystemPartition
;
3494 if (AlternateDisk
->DiskStyle
== PARTITION_STYLE_GPT
)
3496 DPRINT1("Alternate disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3497 goto NoSystemPartition
;
3500 if (DiskEntry
!= AlternateDisk
)
3502 /* Choose the alternate disk */
3503 DiskEntry
= AlternateDisk
;
3505 ActivePartition
= GetActiveDiskPartition(DiskEntry
);
3506 if (ActivePartition
)
3508 /* If we get a candidate active partition, validate it */
3509 if (IsSupportedActivePartition(ActivePartition
))
3511 CandidatePartition
= ActivePartition
;
3512 goto FindAndUseAlternativeSystemPartition
;
3517 /* We now may have an unsupported active partition, or none */
3520 *** TODO: Improve the selection:
3521 *** - If we want a really separate system partition from the partition where
3522 *** we install, do something similar to what's done below in the code.
3523 *** - Otherwise if we allow for the system partition to be also the partition
3524 *** where we install, just directly fall down to using AlternatePart.
3527 /* Retrieve the first partition of the disk */
3528 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
3529 PARTENTRY
, ListEntry
);
3530 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3532 CandidatePartition
= PartEntry
;
3535 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3538 /* Check if the disk is new and if so, use its first partition as the active system partition */
3539 if (DiskEntry
->NewDisk
)
3541 // !IsContainerPartition(PartEntry->PartitionType);
3542 if (!CandidatePartition
->IsPartitioned
|| !CandidatePartition
->BootIndicator
) /* CandidatePartition != ActivePartition */
3544 ASSERT(DiskEntry
== CandidatePartition
->DiskEntry
);
3546 List
->SystemPartition
= CandidatePartition
;
3547 List
->OriginalSystemPartition
= List
->SystemPartition
;
3549 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3550 List
->SystemPartition
->PartitionNumber
,
3551 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3552 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3554 goto SetSystemPartition
;
3557 // FIXME: What to do??
3558 DPRINT1("NewDisk TRUE but first partition is used?\n");
3562 * The disk is not new, check if any partition is initialized;
3563 * if not, the first one becomes the system partition.
3565 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3566 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3567 ListEntry
= ListEntry
->Flink
)
3569 /* Retrieve the partition */
3570 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3572 /* Check if the partition is partitioned and is used */
3573 // !IsContainerPartition(PartEntry->PartitionType);
3574 if (/* PartEntry->IsPartitioned && */
3575 PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
)
3580 if (ListEntry
== &DiskEntry
->PrimaryPartListHead
)
3583 * OK we haven't encountered any used and active partition,
3584 * so use the first one as the system partition.
3586 ASSERT(DiskEntry
== CandidatePartition
->DiskEntry
);
3587 List
->SystemPartition
= CandidatePartition
; // The first PartEntry
3588 List
->OriginalSystemPartition
= List
->SystemPartition
;
3590 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3591 List
->SystemPartition
->PartitionNumber
,
3592 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3593 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3595 goto SetSystemPartition
;
3599 * The disk is not new, we did not find any actual active partition,
3600 * or the one we found was not supported, or any possible other canditate
3601 * is not supported. We then use the alternate partition if specified.
3605 DPRINT1("No system partition found, use the alternative partition!\n");
3606 CandidatePartition
= AlternatePart
;
3607 goto UseAlternativeSystemPartition
;
3612 DPRINT1("No valid or supported system partition has been found on this system!\n");
3617 SystemPartitionFound
:
3618 ASSERT(CandidatePartition
);
3619 List
->SystemPartition
= CandidatePartition
;
3621 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3622 List
->SystemPartition
->PartitionNumber
,
3623 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3624 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3628 FindAndUseAlternativeSystemPartition
:
3630 * We are here because we have not found any (active) candidate
3631 * system partition that we know how to support. What we are going
3632 * to do is to change the existing system partition and use the
3633 * partition on which we install ReactOS as the new system partition,
3634 * and then we will need to add in FreeLdr's entry a boot entry to boot
3635 * from the original system partition.
3638 /* Unset the old system partition */
3639 if (List
->OriginalSystemPartition
)
3641 List
->OriginalSystemPartition
->BootIndicator
= FALSE
;
3642 List
->OriginalSystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->OriginalSystemPartition
->PartitionIndex
].BootIndicator
= FALSE
;
3643 List
->OriginalSystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->OriginalSystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3644 List
->OriginalSystemPartition
->DiskEntry
->Dirty
= TRUE
;
3647 UseAlternativeSystemPartition
:
3648 ASSERT(CandidatePartition
);
3649 List
->SystemPartition
= CandidatePartition
;
3651 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3652 List
->SystemPartition
->PartitionNumber
,
3653 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3654 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3657 /* Set the new active system partition */
3658 List
->SystemPartition
->BootIndicator
= TRUE
;
3659 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= TRUE
;
3660 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3661 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3666 IN PDISKENTRY DiskEntry
)
3669 OBJECT_ATTRIBUTES ObjectAttributes
;
3670 UNICODE_STRING Name
;
3672 IO_STATUS_BLOCK Iosb
;
3674 PPARTITION_INFORMATION PartitionInfo
;
3675 ULONG PartitionCount
;
3676 PLIST_ENTRY ListEntry
;
3677 PPARTENTRY PartEntry
;
3678 WCHAR DstPath
[MAX_PATH
];
3680 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3682 /* If the disk is not dirty, there is nothing to do */
3683 if (!DiskEntry
->Dirty
)
3684 return STATUS_SUCCESS
;
3686 RtlStringCchPrintfW(DstPath
, ARRAYSIZE(DstPath
),
3687 L
"\\Device\\Harddisk%lu\\Partition0",
3688 DiskEntry
->DiskNumber
);
3689 RtlInitUnicodeString(&Name
, DstPath
);
3691 InitializeObjectAttributes(&ObjectAttributes
,
3693 OBJ_CASE_INSENSITIVE
,
3697 Status
= NtOpenFile(&FileHandle
,
3698 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3702 FILE_SYNCHRONOUS_IO_NONALERT
);
3703 if (!NT_SUCCESS(Status
))
3705 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3709 #ifdef DUMP_PARTITION_TABLE
3710 DumpPartitionTable(DiskEntry
);
3714 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3715 // the disk in MBR or GPT format in case the disk was not initialized!!
3716 // For this we must ask the user which format to use.
3719 /* Save the original partition count to be restored later (see comment below) */
3720 PartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
3722 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3723 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3724 ((PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3725 Status
= NtDeviceIoControlFile(FileHandle
,
3730 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3731 DiskEntry
->LayoutBuffer
,
3733 DiskEntry
->LayoutBuffer
,
3735 NtClose(FileHandle
);
3738 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3739 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3740 * where such a table is expected to enumerate up to 4 partitions:
3741 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3742 * Due to this we need to restore the original PartitionCount number.
3744 DiskEntry
->LayoutBuffer
->PartitionCount
= PartitionCount
;
3746 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3747 if (!NT_SUCCESS(Status
))
3749 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3753 #ifdef DUMP_PARTITION_TABLE
3754 DumpPartitionTable(DiskEntry
);
3757 /* Update the partition numbers */
3759 /* Update the primary partition table */
3760 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3761 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3762 ListEntry
= ListEntry
->Flink
)
3764 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3766 if (PartEntry
->IsPartitioned
)
3768 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3769 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3770 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3774 /* Update the logical partition table */
3775 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
3776 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
3777 ListEntry
= ListEntry
->Flink
)
3779 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3781 if (PartEntry
->IsPartitioned
)
3783 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3784 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3785 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3790 // NOTE: Originally (see r40437), we used to install here also a new MBR
3791 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3792 // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0.
3793 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3794 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3795 // was called too, the installation test was modified by checking whether
3796 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3799 /* The layout has been successfully updated, the disk is not dirty anymore */
3800 DiskEntry
->Dirty
= FALSE
;
3806 WritePartitionsToDisk(
3811 PDISKENTRY DiskEntry
;
3816 for (Entry
= List
->DiskListHead
.Flink
;
3817 Entry
!= &List
->DiskListHead
;
3818 Entry
= Entry
->Flink
)
3820 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3822 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3824 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3828 if (DiskEntry
->Dirty
!= FALSE
)
3830 Status
= WritePartitions(DiskEntry
);
3831 if (!NT_SUCCESS(Status
))
3833 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
3834 DiskEntry
->DiskNumber
, Status
);
3843 SetMountedDeviceValue(
3846 IN LARGE_INTEGER StartingOffset
)
3848 OBJECT_ATTRIBUTES ObjectAttributes
;
3849 WCHAR ValueNameBuffer
[16];
3850 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3851 UNICODE_STRING ValueName
;
3852 REG_DISK_MOUNT_INFO MountInfo
;
3856 RtlStringCchPrintfW(ValueNameBuffer
, ARRAYSIZE(ValueNameBuffer
),
3857 L
"\\DosDevices\\%c:", Letter
);
3858 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
3860 InitializeObjectAttributes(&ObjectAttributes
,
3862 OBJ_CASE_INSENSITIVE
,
3866 Status
= NtOpenKey(&KeyHandle
,
3869 if (!NT_SUCCESS(Status
))
3871 Status
= NtCreateKey(&KeyHandle
,
3876 REG_OPTION_NON_VOLATILE
,
3880 if (!NT_SUCCESS(Status
))
3882 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
3886 MountInfo
.Signature
= Signature
;
3887 MountInfo
.StartingOffset
= StartingOffset
;
3888 Status
= NtSetValueKey(KeyHandle
,
3895 if (!NT_SUCCESS(Status
))
3897 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
3905 SetMountedDeviceValues(
3908 PLIST_ENTRY Entry1
, Entry2
;
3909 PDISKENTRY DiskEntry
;
3910 PPARTENTRY PartEntry
;
3911 LARGE_INTEGER StartingOffset
;
3916 for (Entry1
= List
->DiskListHead
.Flink
;
3917 Entry1
!= &List
->DiskListHead
;
3918 Entry1
= Entry1
->Flink
)
3920 DiskEntry
= CONTAINING_RECORD(Entry1
,
3924 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3926 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3930 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3931 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3932 Entry2
= Entry2
->Flink
)
3934 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3935 if (PartEntry
->IsPartitioned
) // && !IsContainerPartition(PartEntry->PartitionType)
3937 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3939 /* Assign a "\DosDevices\#:" mount point to this partition */
3940 if (PartEntry
->DriveLetter
)
3942 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3943 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3944 DiskEntry
->LayoutBuffer
->Signature
,
3953 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3954 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3955 Entry2
= Entry2
->Flink
)
3957 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3958 if (PartEntry
->IsPartitioned
) // && !IsContainerPartition(PartEntry->PartitionType)
3960 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3962 /* Assign a "\DosDevices\#:" mount point to this partition */
3963 if (PartEntry
->DriveLetter
)
3965 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3966 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3967 DiskEntry
->LayoutBuffer
->Signature
,
3982 IN PPARTENTRY PartEntry
,
3983 IN UCHAR PartitionType
)
3985 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3987 PartEntry
->PartitionType
= PartitionType
;
3989 DiskEntry
->Dirty
= TRUE
;
3990 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].PartitionType
= PartitionType
;
3991 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RecognizedPartition
= IsRecognizedPartition(PartitionType
);
3992 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3996 PrimaryPartitionCreationChecks(
3997 IN PPARTENTRY PartEntry
)
3999 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
4001 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4003 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4004 return ERROR_WARN_PARTITION
;
4007 /* Fail if the partition is already in use */
4008 if (PartEntry
->IsPartitioned
)
4009 return ERROR_NEW_PARTITION
;
4011 /* Only one primary partition is allowed on super-floppy */
4012 if (IsSuperFloppy(DiskEntry
))
4013 return ERROR_PARTITION_TABLE_FULL
;
4015 /* Fail if there are already 4 primary partitions in the list */
4016 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
4017 return ERROR_PARTITION_TABLE_FULL
;
4019 return ERROR_SUCCESS
;
4023 ExtendedPartitionCreationChecks(
4024 IN PPARTENTRY PartEntry
)
4026 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
4028 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4030 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4031 return ERROR_WARN_PARTITION
;
4034 /* Fail if the partition is already in use */
4035 if (PartEntry
->IsPartitioned
)
4036 return ERROR_NEW_PARTITION
;
4038 /* Only one primary partition is allowed on super-floppy */
4039 if (IsSuperFloppy(DiskEntry
))
4040 return ERROR_PARTITION_TABLE_FULL
;
4042 /* Fail if there are already 4 primary partitions in the list */
4043 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
4044 return ERROR_PARTITION_TABLE_FULL
;
4046 /* Fail if there is another extended partition in the list */
4047 if (DiskEntry
->ExtendedPartition
!= NULL
)
4048 return ERROR_ONLY_ONE_EXTENDED
;
4050 return ERROR_SUCCESS
;
4054 LogicalPartitionCreationChecks(
4055 IN PPARTENTRY PartEntry
)
4057 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
4059 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4061 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4062 return ERROR_WARN_PARTITION
;
4065 /* Fail if the partition is already in use */
4066 if (PartEntry
->IsPartitioned
)
4067 return ERROR_NEW_PARTITION
;
4069 /* Only one primary partition is allowed on super-floppy */
4070 if (IsSuperFloppy(DiskEntry
))
4071 return ERROR_PARTITION_TABLE_FULL
;
4073 return ERROR_SUCCESS
;
4077 GetNextUnformattedPartition(
4079 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
4080 OUT PPARTENTRY
*pPartEntry
)
4082 PLIST_ENTRY Entry1
, Entry2
;
4083 PDISKENTRY DiskEntry
;
4084 PPARTENTRY PartEntry
;
4086 for (Entry1
= List
->DiskListHead
.Flink
;
4087 Entry1
!= &List
->DiskListHead
;
4088 Entry1
= Entry1
->Flink
)
4090 DiskEntry
= CONTAINING_RECORD(Entry1
,
4094 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4096 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4100 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
4101 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
4102 Entry2
= Entry2
->Flink
)
4104 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4105 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
4107 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4108 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4109 *pPartEntry
= PartEntry
;
4114 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
4115 Entry2
!= &DiskEntry
->LogicalPartListHead
;
4116 Entry2
= Entry2
->Flink
)
4118 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4119 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
4121 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4122 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4123 *pPartEntry
= PartEntry
;
4129 if (pDiskEntry
) *pDiskEntry
= NULL
;
4136 GetNextUncheckedPartition(
4138 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
4139 OUT PPARTENTRY
*pPartEntry
)
4141 PLIST_ENTRY Entry1
, Entry2
;
4142 PDISKENTRY DiskEntry
;
4143 PPARTENTRY PartEntry
;
4145 for (Entry1
= List
->DiskListHead
.Flink
;
4146 Entry1
!= &List
->DiskListHead
;
4147 Entry1
= Entry1
->Flink
)
4149 DiskEntry
= CONTAINING_RECORD(Entry1
,
4153 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4155 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4159 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
4160 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
4161 Entry2
= Entry2
->Flink
)
4163 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4164 if (PartEntry
->IsPartitioned
&& PartEntry
->NeedsCheck
)
4166 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4167 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4168 *pPartEntry
= PartEntry
;
4173 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
4174 Entry2
!= &DiskEntry
->LogicalPartListHead
;
4175 Entry2
= Entry2
->Flink
)
4177 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4178 if (PartEntry
->IsPartitioned
&& PartEntry
->NeedsCheck
)
4180 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4181 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4182 *pPartEntry
= PartEntry
;
4188 if (pDiskEntry
) *pDiskEntry
= NULL
;