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 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
346 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
347 PartEntry
->SectorCount
.QuadPart
!= 0LL))
351 PartEntry
->DriveLetter
= Letter
;
359 /* Assign drive letters to logical drives */
360 for (Entry1
= List
->DiskListHead
.Flink
;
361 Entry1
!= &List
->DiskListHead
;
362 Entry1
= Entry1
->Flink
)
364 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
366 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
367 Entry2
!= &DiskEntry
->LogicalPartListHead
;
368 Entry2
= Entry2
->Flink
)
370 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
372 PartEntry
->DriveLetter
= 0;
374 if (PartEntry
->IsPartitioned
)
376 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
377 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
378 PartEntry
->SectorCount
.QuadPart
!= 0LL))
382 PartEntry
->DriveLetter
= Letter
;
393 DiskIdentifierQueryRoutine(
401 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
402 UNICODE_STRING NameU
;
404 if (ValueType
== REG_SZ
&&
405 ValueLength
== 20 * sizeof(WCHAR
))
407 NameU
.Buffer
= (PWCHAR
)ValueData
;
408 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
409 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
411 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
412 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
414 return STATUS_SUCCESS
;
417 return STATUS_UNSUCCESSFUL
;
422 DiskConfigurationDataQueryRoutine(
430 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
431 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
432 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
435 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
436 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
437 return STATUS_UNSUCCESSFUL
;
439 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
441 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
443 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
444 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
445 return STATUS_UNSUCCESSFUL
;
448 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
450 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
451 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
454 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
455 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
457 return STATUS_SUCCESS
;
460 return STATUS_UNSUCCESSFUL
;
465 SystemConfigurationDataQueryRoutine(
473 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
474 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
477 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
478 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
479 return STATUS_UNSUCCESSFUL
;
481 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
483 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
485 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
486 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
487 return STATUS_UNSUCCESSFUL
;
490 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
492 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
493 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
496 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(ProcessHeap
, 0,
497 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
498 if (*Int13Drives
== NULL
)
499 return STATUS_NO_MEMORY
;
502 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
503 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
504 return STATUS_SUCCESS
;
507 return STATUS_UNSUCCESSFUL
;
512 EnumerateBiosDiskEntries(
513 IN PPARTLIST PartList
)
515 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
520 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
521 PBIOSDISKENTRY BiosDiskEntry
;
523 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
525 memset(QueryTable
, 0, sizeof(QueryTable
));
527 QueryTable
[1].Name
= L
"Configuration Data";
528 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
530 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
531 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
535 if (!NT_SUCCESS(Status
))
537 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
544 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
546 ROOT_NAME
, AdapterCount
);
547 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
552 if (!NT_SUCCESS(Status
))
557 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
558 L
"%s\\%lu\\DiskController",
559 ROOT_NAME
, AdapterCount
);
560 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
565 if (NT_SUCCESS(Status
))
569 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
570 L
"%s\\%lu\\DiskController\\0",
571 ROOT_NAME
, AdapterCount
);
572 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
577 if (!NT_SUCCESS(Status
))
579 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
583 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
584 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral",
585 ROOT_NAME
, AdapterCount
);
586 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
591 if (NT_SUCCESS(Status
))
593 QueryTable
[0].Name
= L
"Identifier";
594 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
595 QueryTable
[1].Name
= L
"Configuration Data";
596 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
601 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
602 if (BiosDiskEntry
== NULL
)
607 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
608 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
609 ROOT_NAME
, AdapterCount
, DiskCount
);
610 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
613 (PVOID
)BiosDiskEntry
,
615 if (!NT_SUCCESS(Status
))
617 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
621 BiosDiskEntry
->DiskNumber
= DiskCount
;
622 BiosDiskEntry
->Recognized
= FALSE
;
624 if (DiskCount
< Int13Drives
[0].NumberDrives
)
626 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
630 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount
);
633 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
635 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
636 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
637 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
638 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
639 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
640 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
641 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
642 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
643 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
644 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
645 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
651 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
659 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
667 * Inserts the disk region represented by PartEntry into either the primary
668 * or the logical partition list of the given disk.
669 * The lists are kept sorted by increasing order of start sectors.
670 * Of course no disk region should overlap at all with one another.
675 IN PDISKENTRY DiskEntry
,
676 IN PPARTENTRY PartEntry
,
677 IN BOOLEAN LogicalPartition
)
681 PPARTENTRY PartEntry2
;
683 /* Use the correct partition list */
684 if (LogicalPartition
)
685 List
= &DiskEntry
->LogicalPartListHead
;
687 List
= &DiskEntry
->PrimaryPartListHead
;
689 /* Find the first disk region before which we need to insert the new one */
690 for (Entry
= List
->Flink
; Entry
!= List
; Entry
= Entry
->Flink
)
692 PartEntry2
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
694 /* Ignore any unused empty region */
695 if ((PartEntry2
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
696 PartEntry2
->StartSector
.QuadPart
== 0) || PartEntry2
->SectorCount
.QuadPart
== 0)
701 /* If the current region ends before the one to be inserted, try again */
702 if (PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1 < PartEntry
->StartSector
.QuadPart
)
706 * One of the disk region boundaries crosses the desired region
707 * (it starts after the desired region, or ends before the end
708 * of the desired region): this is an impossible situation because
709 * disk regions (partitions) cannot overlap!
710 * Throw an error and bail out.
712 if (max(PartEntry
->StartSector
.QuadPart
, PartEntry2
->StartSector
.QuadPart
)
714 min( PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
715 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1))
717 DPRINT1("Disk region overlap problem, stopping there!\n"
718 "Partition to be inserted:\n"
719 " StartSector = %I64u ; EndSector = %I64u\n"
720 "Existing disk region:\n"
721 " StartSector = %I64u ; EndSector = %I64u\n",
722 PartEntry
->StartSector
.QuadPart
,
723 PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
724 PartEntry2
->StartSector
.QuadPart
,
725 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1);
729 /* We have found the first region before which the new one has to be inserted */
733 /* Insert the disk region */
734 InsertTailList(Entry
, &PartEntry
->ListEntry
);
739 CreateInsertBlankRegion(
740 IN PDISKENTRY DiskEntry
,
741 IN OUT PLIST_ENTRY ListHead
,
742 IN ULONGLONG StartSector
,
743 IN ULONGLONG SectorCount
,
744 IN BOOLEAN LogicalSpace
)
746 PPARTENTRY NewPartEntry
;
748 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
751 if (NewPartEntry
== NULL
)
754 NewPartEntry
->DiskEntry
= DiskEntry
;
756 NewPartEntry
->StartSector
.QuadPart
= StartSector
;
757 NewPartEntry
->SectorCount
.QuadPart
= SectorCount
;
759 NewPartEntry
->IsPartitioned
= FALSE
;
760 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
761 NewPartEntry
->FormatState
= Unformatted
;
762 NewPartEntry
->FileSystem
[0] = L
'\0';
764 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
765 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
766 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
768 /* Insert the new entry into the list */
769 InsertTailList(ListHead
, &NewPartEntry
->ListEntry
);
777 InitializePartitionEntry(
778 IN PDISKENTRY DiskEntry
,
779 IN PPARTENTRY PartEntry
,
780 IN ULONGLONG SectorCount
,
781 IN BOOLEAN AutoCreate
)
783 PPARTENTRY NewPartEntry
;
785 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
787 if ((AutoCreate
!= FALSE
) ||
788 (AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
789 PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
))
791 DPRINT1("Convert existing partition entry\n");
793 NewPartEntry
= PartEntry
;
794 NewPartEntry
->AutoCreate
= AutoCreate
;
798 DPRINT1("Add new partition entry\n");
800 /* Insert and initialize a new partition entry */
801 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
804 if (NewPartEntry
== NULL
)
807 NewPartEntry
->DiskEntry
= DiskEntry
;
809 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
810 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
811 NewPartEntry
->StartSector
.QuadPart
;
813 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
814 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
816 /* Insert the new entry into the list */
817 InsertTailList(&PartEntry
->ListEntry
, &NewPartEntry
->ListEntry
);
820 /* Create entry as 'New (Unformatted)' */
821 NewPartEntry
->New
= TRUE
;
822 NewPartEntry
->IsPartitioned
= TRUE
;
824 NewPartEntry
->PartitionType
= FileSystemToPartitionType(L
"RAW", &NewPartEntry
->StartSector
, &NewPartEntry
->SectorCount
);
825 ASSERT(NewPartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
827 NewPartEntry
->FormatState
= Unformatted
;
828 NewPartEntry
->FileSystem
[0] = L
'\0';
829 // NewPartEntry->AutoCreate = AutoCreate;
830 NewPartEntry
->BootIndicator
= FALSE
;
831 NewPartEntry
->LogicalPartition
= FALSE
;
833 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
834 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
835 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
845 IN PDISKENTRY DiskEntry
,
846 IN ULONG PartitionIndex
,
847 IN BOOLEAN LogicalPartition
)
850 PPARTITION_INFORMATION PartitionInfo
;
851 PPARTENTRY PartEntry
;
852 HANDLE PartitionHandle
;
853 OBJECT_ATTRIBUTES ObjectAttributes
;
854 IO_STATUS_BLOCK IoStatusBlock
;
855 WCHAR PathBuffer
[MAX_PATH
];
857 UCHAR LabelBuffer
[sizeof(FILE_FS_VOLUME_INFORMATION
) + 256 * sizeof(WCHAR
)];
858 PFILE_FS_VOLUME_INFORMATION LabelInfo
= (PFILE_FS_VOLUME_INFORMATION
)LabelBuffer
;
860 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
862 if (PartitionInfo
->PartitionType
== PARTITION_ENTRY_UNUSED
||
863 ((LogicalPartition
!= FALSE
) && IsContainerPartition(PartitionInfo
->PartitionType
)))
868 PartEntry
= RtlAllocateHeap(ProcessHeap
,
871 if (PartEntry
== NULL
)
874 PartEntry
->DiskEntry
= DiskEntry
;
876 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
877 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
879 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
880 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
881 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
883 PartEntry
->LogicalPartition
= LogicalPartition
;
884 PartEntry
->IsPartitioned
= TRUE
;
885 PartEntry
->OnDiskPartitionNumber
= PartitionInfo
->PartitionNumber
;
886 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
887 PartEntry
->PartitionIndex
= PartitionIndex
;
889 /* Specify the partition as initially unformatted */
890 PartEntry
->FormatState
= Unformatted
;
891 PartEntry
->FileSystem
[0] = L
'\0';
893 /* Initialize the partition volume label */
894 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
896 if (IsContainerPartition(PartEntry
->PartitionType
))
898 PartEntry
->FormatState
= Unformatted
;
900 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
901 DiskEntry
->ExtendedPartition
= PartEntry
;
903 else if (IsRecognizedPartition(PartEntry
->PartitionType
))
905 ASSERT(PartitionInfo
->RecognizedPartition
);
907 /* Open the volume, ignore any errors */
908 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
909 L
"\\Device\\Harddisk%lu\\Partition%lu",
910 DiskEntry
->DiskNumber
,
911 PartEntry
->PartitionNumber
);
912 RtlInitUnicodeString(&Name
, PathBuffer
);
914 InitializeObjectAttributes(&ObjectAttributes
,
916 OBJ_CASE_INSENSITIVE
,
920 PartitionHandle
= NULL
;
921 Status
= NtOpenFile(&PartitionHandle
,
922 FILE_READ_DATA
| SYNCHRONIZE
,
925 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
926 FILE_SYNCHRONOUS_IO_NONALERT
);
927 if (!NT_SUCCESS(Status
))
929 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status
);
932 if (/* NT_SUCCESS(Status) && */ PartitionHandle
)
934 /* We don't have a FS, try to guess one */
935 Status
= InferFileSystemByHandle(PartitionHandle
,
936 PartEntry
->PartitionType
,
937 PartEntry
->FileSystem
,
938 sizeof(PartEntry
->FileSystem
));
939 if (!NT_SUCCESS(Status
))
940 DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status
);
942 if (*PartEntry
->FileSystem
)
944 if (wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
945 PartEntry
->FormatState
= Unformatted
;
947 PartEntry
->FormatState
= Preformatted
;
951 PartEntry
->FormatState
= UnknownFormat
;
954 /* Retrieve the partition volume label */
957 Status
= NtQueryVolumeInformationFile(PartitionHandle
,
961 FileFsVolumeInformation
);
962 if (NT_SUCCESS(Status
))
964 /* Copy the (possibly truncated) volume label and NULL-terminate it */
965 RtlStringCbCopyNW(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
),
966 LabelInfo
->VolumeLabel
, LabelInfo
->VolumeLabelLength
);
970 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status
);
974 /* Close the partition */
976 NtClose(PartitionHandle
);
980 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
981 PartEntry
->FormatState
= UnknownFormat
;
984 InsertDiskRegion(DiskEntry
, PartEntry
, LogicalPartition
);
989 ScanForUnpartitionedDiskSpace(
990 IN PDISKENTRY DiskEntry
)
992 ULONGLONG StartSector
;
993 ULONGLONG SectorCount
;
994 ULONGLONG LastStartSector
;
995 ULONGLONG LastSectorCount
;
996 ULONGLONG LastUnusedSectorCount
;
997 PPARTENTRY PartEntry
;
998 PPARTENTRY NewPartEntry
;
1001 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1003 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1005 DPRINT1("No primary partition!\n");
1007 /* Create a partition entry that represents the empty disk */
1009 if (DiskEntry
->SectorAlignment
< 2048)
1010 StartSector
= 2048ULL;
1012 StartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1013 SectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) - StartSector
;
1015 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1016 &DiskEntry
->PrimaryPartListHead
,
1020 if (NewPartEntry
== NULL
)
1021 DPRINT1("Failed to create a new empty region for full disk space!\n");
1026 /* Start partition at head 1, cylinder 0 */
1027 if (DiskEntry
->SectorAlignment
< 2048)
1028 LastStartSector
= 2048ULL;
1030 LastStartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1031 LastSectorCount
= 0ULL;
1032 LastUnusedSectorCount
= 0ULL;
1034 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1035 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1036 Entry
= Entry
->Flink
)
1038 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1040 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1041 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1043 LastUnusedSectorCount
=
1044 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
1046 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
1047 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1049 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1051 StartSector
= LastStartSector
+ LastSectorCount
;
1052 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1054 /* Insert the table into the list */
1055 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1056 &PartEntry
->ListEntry
,
1060 if (NewPartEntry
== NULL
)
1062 DPRINT1("Failed to create a new empty region for disk space!\n");
1067 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1068 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1072 /* Check for trailing unpartitioned disk space */
1073 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
1075 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
1077 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1079 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1081 StartSector
= LastStartSector
+ LastSectorCount
;
1082 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1084 /* Append the table to the list */
1085 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1086 &DiskEntry
->PrimaryPartListHead
,
1090 if (NewPartEntry
== NULL
)
1092 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1098 if (DiskEntry
->ExtendedPartition
!= NULL
)
1100 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1102 DPRINT1("No logical partition!\n");
1104 /* Create a partition entry that represents the empty extended partition */
1106 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1107 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
1109 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1110 &DiskEntry
->LogicalPartListHead
,
1114 if (NewPartEntry
== NULL
)
1116 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1119 NewPartEntry
->LogicalPartition
= TRUE
;
1124 /* Start partition at head 1, cylinder 0 */
1125 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1126 LastSectorCount
= 0ULL;
1127 LastUnusedSectorCount
= 0ULL;
1129 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1130 Entry
!= &DiskEntry
->LogicalPartListHead
;
1131 Entry
= Entry
->Flink
)
1133 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1135 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1136 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1138 LastUnusedSectorCount
=
1139 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
1141 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
1142 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1144 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1146 StartSector
= LastStartSector
+ LastSectorCount
;
1147 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1149 /* Insert the table into the list */
1150 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1151 &PartEntry
->ListEntry
,
1155 if (NewPartEntry
== NULL
)
1157 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1160 NewPartEntry
->LogicalPartition
= TRUE
;
1163 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1164 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1168 /* Check for trailing unpartitioned disk space */
1169 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
1171 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+
1172 DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
1173 DiskEntry
->SectorAlignment
);
1175 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1177 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1179 StartSector
= LastStartSector
+ LastSectorCount
;
1180 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1182 /* Append the table to the list */
1183 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1184 &DiskEntry
->LogicalPartListHead
,
1188 if (NewPartEntry
== NULL
)
1190 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1193 NewPartEntry
->LogicalPartition
= TRUE
;
1198 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1205 IN PDISKENTRY DiskEntry
)
1207 LARGE_INTEGER SystemTime
;
1208 TIME_FIELDS TimeFields
;
1210 PDISKENTRY DiskEntry2
;
1213 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1215 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1219 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1223 NtQuerySystemTime(&SystemTime
);
1224 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1226 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1227 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1228 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1229 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1231 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1236 /* Check if the signature already exist */
1238 * Check also signatures from disks, which are
1239 * not visible (bootable) by the bios.
1241 for (Entry2
= List
->DiskListHead
.Flink
;
1242 Entry2
!= &List
->DiskListHead
;
1243 Entry2
= Entry2
->Flink
)
1245 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1247 if (DiskEntry2
->DiskStyle
== PARTITION_STYLE_GPT
)
1249 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1253 if (DiskEntry
!= DiskEntry2
&&
1254 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1258 if (Entry2
== &List
->DiskListHead
)
1265 UpdateDiskSignatures(
1269 PDISKENTRY DiskEntry
;
1271 /* Update each disk */
1272 for (Entry
= List
->DiskListHead
.Flink
;
1273 Entry
!= &List
->DiskListHead
;
1274 Entry
= Entry
->Flink
)
1276 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1278 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1280 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1284 if (DiskEntry
->LayoutBuffer
&&
1285 DiskEntry
->LayoutBuffer
->Signature
== 0)
1287 SetDiskSignature(List
, DiskEntry
);
1288 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1296 IN HANDLE FileHandle
,
1297 IN ULONG DiskNumber
,
1300 DISK_GEOMETRY DiskGeometry
;
1301 SCSI_ADDRESS ScsiAddress
;
1302 PDISKENTRY DiskEntry
;
1303 IO_STATUS_BLOCK Iosb
;
1305 PPARTITION_SECTOR Mbr
;
1307 LARGE_INTEGER FileOffset
;
1308 WCHAR Identifier
[20];
1312 PLIST_ENTRY ListEntry
;
1313 PBIOSDISKENTRY BiosDiskEntry
;
1314 ULONG LayoutBufferSize
;
1315 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1317 /* Retrieve the drive geometry */
1318 Status
= NtDeviceIoControlFile(FileHandle
,
1323 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1327 sizeof(DiskGeometry
));
1328 if (!NT_SUCCESS(Status
))
1331 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1332 DiskGeometry
.MediaType
!= RemovableMedia
)
1338 * FIXME: Here we suppose the disk is always SCSI. What if it is
1339 * of another type? To check this we need to retrieve the name of
1340 * the driver the disk device belongs to.
1342 Status
= NtDeviceIoControlFile(FileHandle
,
1347 IOCTL_SCSI_GET_ADDRESS
,
1351 sizeof(ScsiAddress
));
1352 if (!NT_SUCCESS(Status
))
1356 * Check whether the disk is initialized, by looking at its MBR.
1357 * NOTE that this must be generalized to GPT disks as well!
1360 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1362 DiskGeometry
.BytesPerSector
);
1366 FileOffset
.QuadPart
= 0;
1367 Status
= NtReadFile(FileHandle
,
1373 DiskGeometry
.BytesPerSector
,
1376 if (!NT_SUCCESS(Status
))
1378 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1379 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1382 Signature
= Mbr
->Signature
;
1384 /* Calculate the MBR checksum */
1386 Buffer
= (PULONG
)Mbr
;
1387 for (i
= 0; i
< 128; i
++)
1389 Checksum
+= Buffer
[i
];
1391 Checksum
= ~Checksum
+ 1;
1393 RtlStringCchPrintfW(Identifier
, ARRAYSIZE(Identifier
),
1394 L
"%08x-%08x-A", Checksum
, Signature
);
1395 DPRINT("Identifier: %S\n", Identifier
);
1397 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1400 if (DiskEntry
== NULL
)
1402 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1403 DPRINT1("Failed to allocate a new disk entry.\n");
1407 // DiskEntry->Checksum = Checksum;
1408 // DiskEntry->Signature = Signature;
1409 DiskEntry
->BiosFound
= FALSE
;
1412 * Check if this disk has a valid MBR: verify its signature,
1413 * and whether its two first bytes are a valid instruction
1414 * (related to this, see IsThereAValidBootSector() in partlist.c).
1416 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1419 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1421 /* If we have not the 0xAA55 then it's raw partition */
1422 if (Mbr
->Magic
!= PARTITION_MAGIC
)
1424 DiskEntry
->DiskStyle
= PARTITION_STYLE_RAW
;
1426 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1427 else if (Mbr
->Partition
[0].PartitionType
== EFI_PMBR_OSTYPE_EFI
&&
1428 Mbr
->Partition
[1].PartitionType
== 0 &&
1429 Mbr
->Partition
[2].PartitionType
== 0 &&
1430 Mbr
->Partition
[3].PartitionType
== 0)
1432 DiskEntry
->DiskStyle
= PARTITION_STYLE_GPT
;
1434 /* Otherwise, partition table is in MBR */
1437 DiskEntry
->DiskStyle
= PARTITION_STYLE_MBR
;
1440 /* Free the MBR sector buffer */
1441 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1444 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1445 ListEntry
!= &List
->BiosDiskListHead
;
1446 ListEntry
= ListEntry
->Flink
)
1448 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1450 * Compare the size from bios and the reported size from driver.
1451 * If we have more than one disk with a zero or with the same signature
1452 * we must create new signatures and reboot. After the reboot,
1453 * it is possible to identify the disks.
1455 if (BiosDiskEntry
->Signature
== Signature
&&
1456 BiosDiskEntry
->Checksum
== Checksum
&&
1457 !BiosDiskEntry
->Recognized
)
1459 if (!DiskEntry
->BiosFound
)
1461 DiskEntry
->BiosDiskNumber
= BiosDiskEntry
->DiskNumber
;
1462 DiskEntry
->BiosFound
= TRUE
;
1463 BiosDiskEntry
->Recognized
= TRUE
;
1467 // FIXME: What to do?
1472 if (!DiskEntry
->BiosFound
)
1475 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1478 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber
);
1482 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1483 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1485 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1486 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1487 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1488 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1490 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1491 DPRINT("TracksPerCylinder %lu\n", DiskEntry
->TracksPerCylinder
);
1492 DPRINT("SectorsPerTrack %lu\n", DiskEntry
->SectorsPerTrack
);
1493 DPRINT("BytesPerSector %lu\n", DiskEntry
->BytesPerSector
);
1495 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1496 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1497 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1499 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1500 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1501 DiskGeometry
.SectorsPerTrack
;
1503 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
.QuadPart
);
1504 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1506 DiskEntry
->DiskNumber
= DiskNumber
;
1507 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1508 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1509 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1511 GetDriverName(DiskEntry
);
1513 * Actually it would be more correct somehow to use:
1515 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1516 * ULONG ReturnedLength;
1518 * Status = NtQueryObject(SomeHandleToTheDisk,
1519 * ObjectNameInformation,
1525 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1528 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1532 * We now retrieve the disk partition layout
1536 * Stop there now if the disk is GPT-partitioned,
1537 * since we currently do not support such disks.
1539 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1541 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1545 /* Allocate a layout buffer with 4 partition entries first */
1546 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1547 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1548 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1551 if (DiskEntry
->LayoutBuffer
== NULL
)
1553 DPRINT1("Failed to allocate the disk layout buffer!\n");
1557 /* Keep looping while the drive layout buffer is too small */
1560 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1561 Status
= NtDeviceIoControlFile(FileHandle
,
1566 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1569 DiskEntry
->LayoutBuffer
,
1571 if (NT_SUCCESS(Status
))
1574 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1576 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1580 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1581 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1583 DiskEntry
->LayoutBuffer
,
1585 if (NewLayoutBuffer
== NULL
)
1587 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1591 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1594 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1596 #ifdef DUMP_PARTITION_TABLE
1597 DumpPartitionTable(DiskEntry
);
1600 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1601 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1602 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= PARTITION_ENTRY_UNUSED
)
1604 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1606 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1608 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1610 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1614 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1619 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1622 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1624 DiskEntry
->NewDisk
= TRUE
;
1625 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1627 for (i
= 0; i
< 4; i
++)
1629 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1634 /* Enumerate and add the first four primary partitions */
1635 for (i
= 0; i
< 4; i
++)
1637 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, FALSE
);
1640 /* Enumerate and add the remaining partitions as logical ones */
1641 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1643 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, TRUE
);
1647 ScanForUnpartitionedDiskSpace(DiskEntry
);
1651 CreatePartitionList(VOID
)
1654 OBJECT_ATTRIBUTES ObjectAttributes
;
1655 SYSTEM_DEVICE_INFORMATION Sdi
;
1656 IO_STATUS_BLOCK Iosb
;
1660 WCHAR Buffer
[MAX_PATH
];
1661 UNICODE_STRING Name
;
1664 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1670 List
->CurrentDisk
= NULL
;
1671 List
->CurrentPartition
= NULL
;
1673 List
->SystemPartition
= NULL
;
1674 List
->OriginalSystemPartition
= NULL
;
1676 InitializeListHead(&List
->DiskListHead
);
1677 InitializeListHead(&List
->BiosDiskListHead
);
1680 * Enumerate the disks seen by the BIOS; this will be used later
1681 * to map drives seen by NTOS with their corresponding BIOS names.
1683 EnumerateBiosDiskEntries(List
);
1685 /* Enumerate disks seen by NTOS */
1686 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1690 if (!NT_SUCCESS(Status
))
1692 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status
);
1693 RtlFreeHeap(ProcessHeap
, 0, List
);
1697 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1699 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
1700 L
"\\Device\\Harddisk%lu\\Partition0",
1702 RtlInitUnicodeString(&Name
, Buffer
);
1704 InitializeObjectAttributes(&ObjectAttributes
,
1706 OBJ_CASE_INSENSITIVE
,
1710 Status
= NtOpenFile(&FileHandle
,
1711 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1714 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1715 FILE_SYNCHRONOUS_IO_NONALERT
);
1716 if (NT_SUCCESS(Status
))
1718 AddDiskToList(FileHandle
, DiskNumber
, List
);
1719 NtClose(FileHandle
);
1723 UpdateDiskSignatures(List
);
1725 AssignDriveLetters(List
);
1727 /* Search for first usable disk and partition */
1728 if (IsListEmpty(&List
->DiskListHead
))
1730 List
->CurrentDisk
= NULL
;
1731 List
->CurrentPartition
= NULL
;
1735 List
->CurrentDisk
= CONTAINING_RECORD(List
->DiskListHead
.Flink
,
1739 if (IsListEmpty(&List
->CurrentDisk
->PrimaryPartListHead
))
1741 List
->CurrentPartition
= NULL
;
1745 List
->CurrentPartition
= CONTAINING_RECORD(List
->CurrentDisk
->PrimaryPartListHead
.Flink
,
1755 DestroyPartitionList(
1758 PDISKENTRY DiskEntry
;
1759 PBIOSDISKENTRY BiosDiskEntry
;
1760 PPARTENTRY PartEntry
;
1763 /* Release disk and partition info */
1764 while (!IsListEmpty(&List
->DiskListHead
))
1766 Entry
= RemoveHeadList(&List
->DiskListHead
);
1767 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1769 /* Release driver name */
1770 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1772 /* Release primary partition list */
1773 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1775 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1776 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1778 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1781 /* Release logical partition list */
1782 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1784 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1785 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1787 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1790 /* Release layout buffer */
1791 if (DiskEntry
->LayoutBuffer
!= NULL
)
1792 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1794 /* Release disk entry */
1795 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1798 /* Release the bios disk info */
1799 while (!IsListEmpty(&List
->BiosDiskListHead
))
1801 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1802 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1804 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
1807 /* Release list head */
1808 RtlFreeHeap(ProcessHeap
, 0, List
);
1812 GetDiskByBiosNumber(
1814 IN ULONG BiosDiskNumber
)
1816 PDISKENTRY DiskEntry
;
1819 /* Loop over the disks and find the correct one */
1820 for (Entry
= List
->DiskListHead
.Flink
;
1821 Entry
!= &List
->DiskListHead
;
1822 Entry
= Entry
->Flink
)
1824 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1826 if (DiskEntry
->BiosDiskNumber
== BiosDiskNumber
)
1833 /* Disk not found, stop there */
1840 IN ULONG DiskNumber
)
1842 PDISKENTRY DiskEntry
;
1845 /* Loop over the disks and find the correct one */
1846 for (Entry
= List
->DiskListHead
.Flink
;
1847 Entry
!= &List
->DiskListHead
;
1848 Entry
= Entry
->Flink
)
1850 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1852 if (DiskEntry
->DiskNumber
== DiskNumber
)
1859 /* Disk not found, stop there */
1870 PDISKENTRY DiskEntry
;
1873 /* Loop over the disks and find the correct one */
1874 for (Entry
= List
->DiskListHead
.Flink
;
1875 Entry
!= &List
->DiskListHead
;
1876 Entry
= Entry
->Flink
)
1878 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1880 if (DiskEntry
->Port
== Port
&&
1881 DiskEntry
->Bus
== Bus
&&
1882 DiskEntry
->Id
== Id
)
1889 /* Disk not found, stop there */
1898 PDISKENTRY DiskEntry
;
1901 /* Loop over the disks and find the correct one */
1902 for (Entry
= List
->DiskListHead
.Flink
;
1903 Entry
!= &List
->DiskListHead
;
1904 Entry
= Entry
->Flink
)
1906 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1908 if (DiskEntry
->LayoutBuffer
->Signature
== Signature
)
1915 /* Disk not found, stop there */
1921 // IN PPARTLIST List,
1922 IN PDISKENTRY DiskEntry
,
1923 IN ULONG PartitionNumber
)
1925 PPARTENTRY PartEntry
;
1928 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1930 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1934 /* Disk found, loop over the primary partitions first... */
1935 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1936 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1937 Entry
= Entry
->Flink
)
1939 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1941 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1943 /* Partition found */
1948 /* ... then over the logical partitions if needed */
1949 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1950 Entry
!= &DiskEntry
->LogicalPartListHead
;
1951 Entry
= Entry
->Flink
)
1953 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1955 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1957 /* Partition found */
1962 /* The partition was not found on the disk, stop there */
1969 IN ULONG DiskNumber
,
1970 IN ULONG PartitionNumber OPTIONAL
,
1971 OUT PDISKENTRY
* pDiskEntry
,
1972 OUT PPARTENTRY
* pPartEntry OPTIONAL
)
1974 PDISKENTRY DiskEntry
;
1975 PPARTENTRY PartEntry
= NULL
;
1978 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
1982 /* If we have a partition (PartitionNumber != 0), find it */
1983 if (PartitionNumber
!= 0)
1985 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1987 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1991 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
1994 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
1997 /* Return the disk (and optionally the partition) */
1998 *pDiskEntry
= DiskEntry
;
1999 if (pPartEntry
) *pPartEntry
= PartEntry
;
2004 // NOTE: Was introduced broken in r6258 by Casper
2009 IN ULONG DiskNumber
,
2010 IN ULONG PartitionNumber
)
2012 PDISKENTRY DiskEntry
;
2013 PPARTENTRY PartEntry
;
2015 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
2019 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
2023 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2024 ASSERT(DiskEntry
->DiskNumber
== DiskNumber
);
2025 ASSERT(PartEntry
->PartitionNumber
== PartitionNumber
);
2027 List
->CurrentDisk
= DiskEntry
;
2028 List
->CurrentPartition
= PartEntry
;
2036 PLIST_ENTRY DiskListEntry
;
2037 PLIST_ENTRY PartListEntry
;
2038 PDISKENTRY DiskEntry
;
2039 PPARTENTRY PartEntry
;
2041 /* Fail if no disks are available */
2042 if (IsListEmpty(&List
->DiskListHead
))
2045 /* Check for next usable entry on current disk */
2046 if (List
->CurrentPartition
!= NULL
)
2048 if (List
->CurrentPartition
->LogicalPartition
)
2050 /* Logical partition */
2052 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2053 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2055 /* Next logical partition */
2056 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2058 List
->CurrentPartition
= PartEntry
;
2059 return List
->CurrentPartition
;
2063 PartListEntry
= List
->CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
2064 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2066 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2068 List
->CurrentPartition
= PartEntry
;
2069 return List
->CurrentPartition
;
2075 /* Primary or extended partition */
2077 if (List
->CurrentPartition
->IsPartitioned
&&
2078 IsContainerPartition(List
->CurrentPartition
->PartitionType
))
2080 /* First logical partition */
2081 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Flink
;
2082 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2084 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2086 List
->CurrentPartition
= PartEntry
;
2087 return List
->CurrentPartition
;
2092 /* Next primary partition */
2093 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2094 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2096 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2098 List
->CurrentPartition
= PartEntry
;
2099 return List
->CurrentPartition
;
2105 /* Search for the first partition entry on the next disk */
2106 for (DiskListEntry
= List
->CurrentDisk
->ListEntry
.Flink
;
2107 DiskListEntry
!= &List
->DiskListHead
;
2108 DiskListEntry
= DiskListEntry
->Flink
)
2110 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2112 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2114 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2118 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2119 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2121 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2123 List
->CurrentDisk
= DiskEntry
;
2124 List
->CurrentPartition
= PartEntry
;
2125 return List
->CurrentPartition
;
2136 PLIST_ENTRY DiskListEntry
;
2137 PLIST_ENTRY PartListEntry
;
2138 PDISKENTRY DiskEntry
;
2139 PPARTENTRY PartEntry
;
2141 /* Fail if no disks are available */
2142 if (IsListEmpty(&List
->DiskListHead
))
2145 /* Check for previous usable entry on current disk */
2146 if (List
->CurrentPartition
!= NULL
)
2148 if (List
->CurrentPartition
->LogicalPartition
)
2150 /* Logical partition */
2151 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2152 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2154 /* Previous logical partition */
2155 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2159 /* Extended partition */
2160 PartEntry
= List
->CurrentDisk
->ExtendedPartition
;
2163 List
->CurrentPartition
= PartEntry
;
2164 return List
->CurrentPartition
;
2168 /* Primary or extended partition */
2170 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2171 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2173 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2175 if (PartEntry
->IsPartitioned
&&
2176 IsContainerPartition(PartEntry
->PartitionType
))
2178 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Blink
;
2179 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2182 List
->CurrentPartition
= PartEntry
;
2183 return List
->CurrentPartition
;
2188 /* Search for the last partition entry on the previous disk */
2189 for (DiskListEntry
= List
->CurrentDisk
->ListEntry
.Blink
;
2190 DiskListEntry
!= &List
->DiskListHead
;
2191 DiskListEntry
= DiskListEntry
->Blink
)
2193 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2195 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2197 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2201 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Blink
;
2202 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2204 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2206 if (PartEntry
->IsPartitioned
&&
2207 IsContainerPartition(PartEntry
->PartitionType
))
2209 PartListEntry
= DiskEntry
->LogicalPartListHead
.Blink
;
2210 if (PartListEntry
!= &DiskEntry
->LogicalPartListHead
)
2212 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2214 List
->CurrentDisk
= DiskEntry
;
2215 List
->CurrentPartition
= PartEntry
;
2216 return List
->CurrentPartition
;
2221 List
->CurrentDisk
= DiskEntry
;
2222 List
->CurrentPartition
= PartEntry
;
2223 return List
->CurrentPartition
;
2235 IN PPARTITION_INFORMATION PartitionInfo
)
2237 if (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2238 PartitionInfo
->PartitionLength
.QuadPart
== 0)
2249 IsSamePrimaryLayoutEntry(
2250 IN PPARTITION_INFORMATION PartitionInfo
,
2251 IN PDISKENTRY DiskEntry
,
2252 IN PPARTENTRY PartEntry
)
2254 if (PartitionInfo
->StartingOffset
.QuadPart
== PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
&&
2255 PartitionInfo
->PartitionLength
.QuadPart
== PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
)
2256 // PartitionInfo->PartitionType == PartEntry->PartitionType
2266 GetPrimaryPartitionCount(
2267 IN PDISKENTRY DiskEntry
)
2270 PPARTENTRY PartEntry
;
2273 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2275 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2279 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2280 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2281 Entry
= Entry
->Flink
)
2283 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2284 if (PartEntry
->IsPartitioned
)
2293 GetLogicalPartitionCount(
2294 IN PDISKENTRY DiskEntry
)
2296 PLIST_ENTRY ListEntry
;
2297 PPARTENTRY PartEntry
;
2300 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2302 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2306 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2307 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2308 ListEntry
= ListEntry
->Flink
)
2310 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2311 if (PartEntry
->IsPartitioned
)
2320 ReAllocateLayoutBuffer(
2321 IN PDISKENTRY DiskEntry
)
2323 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2324 ULONG NewPartitionCount
;
2325 ULONG CurrentPartitionCount
= 0;
2326 ULONG LayoutBufferSize
;
2329 DPRINT1("ReAllocateLayoutBuffer()\n");
2331 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2333 if (DiskEntry
->LayoutBuffer
)
2334 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2336 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2337 CurrentPartitionCount
, NewPartitionCount
);
2339 if (CurrentPartitionCount
== NewPartitionCount
)
2342 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2343 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2344 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2346 DiskEntry
->LayoutBuffer
,
2348 if (NewLayoutBuffer
== NULL
)
2350 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2354 NewLayoutBuffer
->PartitionCount
= NewPartitionCount
;
2356 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2357 if (NewPartitionCount
> CurrentPartitionCount
)
2359 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2361 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2365 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2373 IN PDISKENTRY DiskEntry
)
2375 PPARTITION_INFORMATION PartitionInfo
;
2376 PPARTITION_INFORMATION LinkInfo
= NULL
;
2377 PLIST_ENTRY ListEntry
;
2378 PPARTENTRY PartEntry
;
2379 LARGE_INTEGER HiddenSectors64
;
2381 ULONG PartitionNumber
= 1;
2383 DPRINT1("UpdateDiskLayout()\n");
2385 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2387 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2391 /* Resize the layout buffer if necessary */
2392 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2394 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2398 /* Update the primary partition table */
2400 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2401 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
2402 ListEntry
= ListEntry
->Flink
)
2404 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2406 if (PartEntry
->IsPartitioned
)
2408 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2409 PartEntry
->PartitionIndex
= Index
;
2411 /* Reset the current partition number only for newly-created partitions */
2413 PartEntry
->PartitionNumber
= 0;
2415 PartEntry
->OnDiskPartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
)) ? PartitionNumber
: 0;
2417 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, DiskEntry
, PartEntry
))
2419 DPRINT1("Updating primary partition entry %lu\n", Index
);
2421 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2422 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2423 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2424 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2425 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2426 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2427 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2428 PartitionInfo
->RewritePartition
= TRUE
;
2431 if (!IsContainerPartition(PartEntry
->PartitionType
))
2440 /* Update the logical partition table */
2442 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2443 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2444 ListEntry
= ListEntry
->Flink
)
2446 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2448 if (PartEntry
->IsPartitioned
)
2450 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2451 PartEntry
->PartitionIndex
= Index
;
2453 DPRINT1("Updating logical partition entry %lu\n", Index
);
2455 /* Reset the current partition number only for newly-created partitions */
2457 PartEntry
->PartitionNumber
= 0;
2459 PartEntry
->OnDiskPartitionNumber
= PartitionNumber
;
2461 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2462 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2463 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2464 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2465 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2466 PartitionInfo
->BootIndicator
= FALSE
;
2467 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2468 PartitionInfo
->RewritePartition
= TRUE
;
2470 /* Fill the link entry of the previous partition entry */
2471 if (LinkInfo
!= NULL
)
2473 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2474 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2475 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2476 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2477 LinkInfo
->PartitionNumber
= 0;
2478 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2479 LinkInfo
->BootIndicator
= FALSE
;
2480 LinkInfo
->RecognizedPartition
= FALSE
;
2481 LinkInfo
->RewritePartition
= TRUE
;
2484 /* Save a pointer to the link entry of the current partition entry */
2485 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2492 /* Wipe unused primary partition entries */
2493 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2495 DPRINT1("Primary partition entry %lu\n", Index
);
2497 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2499 if (!IsEmptyLayoutEntry(PartitionInfo
))
2501 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2503 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2504 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2505 PartitionInfo
->HiddenSectors
= 0;
2506 PartitionInfo
->PartitionNumber
= 0;
2507 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2508 PartitionInfo
->BootIndicator
= FALSE
;
2509 PartitionInfo
->RecognizedPartition
= FALSE
;
2510 PartitionInfo
->RewritePartition
= TRUE
;
2514 /* Wipe unused logical partition entries */
2515 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2519 DPRINT1("Logical partition entry %lu\n", Index
);
2521 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2523 if (!IsEmptyLayoutEntry(PartitionInfo
))
2525 DPRINT1("Wiping partition entry %lu\n", Index
);
2527 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2528 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2529 PartitionInfo
->HiddenSectors
= 0;
2530 PartitionInfo
->PartitionNumber
= 0;
2531 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2532 PartitionInfo
->BootIndicator
= FALSE
;
2533 PartitionInfo
->RecognizedPartition
= FALSE
;
2534 PartitionInfo
->RewritePartition
= TRUE
;
2539 DiskEntry
->Dirty
= TRUE
;
2541 #ifdef DUMP_PARTITION_TABLE
2542 DumpPartitionTable(DiskEntry
);
2548 GetPrevUnpartitionedEntry(
2549 IN PDISKENTRY DiskEntry
,
2550 IN PPARTENTRY PartEntry
)
2552 PPARTENTRY PrevPartEntry
;
2553 PLIST_ENTRY ListHead
;
2555 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2557 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2561 if (PartEntry
->LogicalPartition
)
2562 ListHead
= &DiskEntry
->LogicalPartListHead
;
2564 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2566 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2568 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2571 if (PrevPartEntry
->IsPartitioned
== FALSE
)
2572 return PrevPartEntry
;
2580 GetNextUnpartitionedEntry(
2581 IN PDISKENTRY DiskEntry
,
2582 IN PPARTENTRY PartEntry
)
2584 PPARTENTRY NextPartEntry
;
2585 PLIST_ENTRY ListHead
;
2587 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2589 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2593 if (PartEntry
->LogicalPartition
)
2594 ListHead
= &DiskEntry
->LogicalPartListHead
;
2596 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2598 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2600 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2603 if (NextPartEntry
->IsPartitioned
== FALSE
)
2604 return NextPartEntry
;
2611 CreatePrimaryPartition(
2613 IN ULONGLONG SectorCount
,
2614 IN BOOLEAN AutoCreate
)
2617 PDISKENTRY DiskEntry
;
2618 PPARTENTRY PartEntry
;
2620 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount
);
2623 List
->CurrentDisk
== NULL
||
2624 List
->CurrentPartition
== NULL
||
2625 List
->CurrentPartition
->IsPartitioned
)
2630 Error
= PrimaryPartitionCreationChecks(List
);
2631 if (Error
!= NOT_AN_ERROR
)
2633 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error
);
2637 DiskEntry
= List
->CurrentDisk
;
2638 PartEntry
= List
->CurrentPartition
;
2640 /* Convert the current entry, or insert and initialize a new partition entry */
2641 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, AutoCreate
);
2642 if (PartEntry
== NULL
)
2645 UpdateDiskLayout(DiskEntry
);
2647 AssignDriveLetters(List
);
2654 AddLogicalDiskSpace(
2655 IN PDISKENTRY DiskEntry
)
2657 ULONGLONG StartSector
;
2658 ULONGLONG SectorCount
;
2659 PPARTENTRY NewPartEntry
;
2661 DPRINT1("AddLogicalDiskSpace()\n");
2663 /* Create a partition entry that represents the empty space in the container partition */
2665 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2666 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2668 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
2669 &DiskEntry
->LogicalPartListHead
,
2673 if (NewPartEntry
== NULL
)
2675 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2678 NewPartEntry
->LogicalPartition
= TRUE
;
2682 CreateExtendedPartition(
2684 IN ULONGLONG SectorCount
)
2687 PDISKENTRY DiskEntry
;
2688 PPARTENTRY PartEntry
;
2690 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount
);
2693 List
->CurrentDisk
== NULL
||
2694 List
->CurrentPartition
== NULL
||
2695 List
->CurrentPartition
->IsPartitioned
)
2700 Error
= ExtendedPartitionCreationChecks(List
);
2701 if (Error
!= NOT_AN_ERROR
)
2703 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error
);
2707 DiskEntry
= List
->CurrentDisk
;
2708 PartEntry
= List
->CurrentPartition
;
2710 /* Convert the current entry, or insert and initialize a new partition entry */
2711 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, FALSE
);
2712 if (PartEntry
== NULL
)
2715 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2717 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2718 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2722 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2723 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2726 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2727 PartEntry
->New
= FALSE
;
2728 PartEntry
->FormatState
= Formatted
;
2730 DiskEntry
->ExtendedPartition
= PartEntry
;
2732 AddLogicalDiskSpace(DiskEntry
);
2734 UpdateDiskLayout(DiskEntry
);
2736 AssignDriveLetters(List
);
2742 CreateLogicalPartition(
2744 IN ULONGLONG SectorCount
,
2745 IN BOOLEAN AutoCreate
)
2748 PDISKENTRY DiskEntry
;
2749 PPARTENTRY PartEntry
;
2751 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount
);
2754 List
->CurrentDisk
== NULL
||
2755 List
->CurrentPartition
== NULL
||
2756 List
->CurrentPartition
->IsPartitioned
)
2761 Error
= LogicalPartitionCreationChecks(List
);
2762 if (Error
!= NOT_AN_ERROR
)
2764 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error
);
2768 DiskEntry
= List
->CurrentDisk
;
2769 PartEntry
= List
->CurrentPartition
;
2771 /* Convert the current entry, or insert and initialize a new partition entry */
2772 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, AutoCreate
);
2773 if (PartEntry
== NULL
)
2776 PartEntry
->LogicalPartition
= TRUE
;
2778 UpdateDiskLayout(DiskEntry
);
2780 AssignDriveLetters(List
);
2788 IN PPARTENTRY PartEntry
)
2791 NTSTATUS LockStatus
;
2792 UNICODE_STRING Name
;
2793 OBJECT_ATTRIBUTES ObjectAttributes
;
2794 IO_STATUS_BLOCK IoStatusBlock
;
2795 HANDLE PartitionHandle
;
2796 WCHAR Buffer
[MAX_PATH
];
2798 /* Check whether the partition is valid and may have been mounted in the system */
2799 if (!PartEntry
->IsPartitioned
||
2800 PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2801 IsContainerPartition(PartEntry
->PartitionType
) ||
2802 !IsRecognizedPartition(PartEntry
->PartitionType
) ||
2803 PartEntry
->FormatState
== Unformatted
/* || PartEntry->FormatState == UnknownFormat */ ||
2804 !*PartEntry
->FileSystem
||
2805 PartEntry
->PartitionNumber
== 0)
2807 /* The partition is not mounted, so just return success */
2808 return STATUS_SUCCESS
;
2811 /* Open the volume */
2812 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
2813 L
"\\Device\\Harddisk%lu\\Partition%lu",
2814 PartEntry
->DiskEntry
->DiskNumber
,
2815 PartEntry
->PartitionNumber
);
2816 RtlInitUnicodeString(&Name
, Buffer
);
2818 InitializeObjectAttributes(&ObjectAttributes
,
2820 OBJ_CASE_INSENSITIVE
,
2824 Status
= NtOpenFile(&PartitionHandle
,
2825 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
2828 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2829 FILE_SYNCHRONOUS_IO_NONALERT
);
2830 if (!NT_SUCCESS(Status
))
2832 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name
, Status
);
2836 /* Lock the volume */
2837 LockStatus
= NtFsControlFile(PartitionHandle
,
2847 if (!NT_SUCCESS(LockStatus
))
2849 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus
);
2852 /* Dismount the volume */
2853 Status
= NtFsControlFile(PartitionHandle
,
2858 FSCTL_DISMOUNT_VOLUME
,
2863 if (!NT_SUCCESS(Status
))
2865 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status
);
2868 /* Unlock the volume */
2869 LockStatus
= NtFsControlFile(PartitionHandle
,
2874 FSCTL_UNLOCK_VOLUME
,
2879 if (!NT_SUCCESS(LockStatus
))
2881 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus
);
2884 /* Close the volume */
2885 NtClose(PartitionHandle
);
2891 DeleteCurrentPartition(
2894 PDISKENTRY DiskEntry
;
2895 PPARTENTRY PartEntry
;
2896 PPARTENTRY PrevPartEntry
;
2897 PPARTENTRY NextPartEntry
;
2898 PPARTENTRY LogicalPartEntry
;
2902 List
->CurrentDisk
== NULL
||
2903 List
->CurrentPartition
== NULL
||
2904 List
->CurrentPartition
->IsPartitioned
== FALSE
)
2909 /* Clear the system disk and partition pointers if the system partition is being deleted */
2910 if (List
->SystemPartition
== List
->CurrentPartition
)
2912 List
->SystemPartition
= NULL
;
2915 DiskEntry
= List
->CurrentDisk
;
2916 PartEntry
= List
->CurrentPartition
;
2918 /* Check which type of partition (primary/logical or extended) is being deleted */
2919 if (DiskEntry
->ExtendedPartition
== PartEntry
)
2921 /* An extended partition is being deleted: delete all logical partition entries */
2922 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
2924 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
2925 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2927 /* Dismount the logical partition */
2928 DismountVolume(LogicalPartEntry
);
2931 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
2934 DiskEntry
->ExtendedPartition
= NULL
;
2938 /* A primary partition is being deleted: dismount it */
2939 DismountVolume(PartEntry
);
2942 /* Adjust unpartitioned disk space entries */
2944 /* Get pointer to previous and next unpartitioned entries */
2945 PrevPartEntry
= GetPrevUnpartitionedEntry(DiskEntry
, PartEntry
);
2946 NextPartEntry
= GetNextUnpartitionedEntry(DiskEntry
, PartEntry
);
2948 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
2950 /* Merge previous, current and next unpartitioned entry */
2952 /* Adjust the previous entries length */
2953 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
2955 /* Remove the current entry */
2956 RemoveEntryList(&PartEntry
->ListEntry
);
2957 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2959 /* Remove the next entry */
2960 RemoveEntryList(&NextPartEntry
->ListEntry
);
2961 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
2963 /* Update current partition */
2964 List
->CurrentPartition
= PrevPartEntry
;
2966 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
2968 /* Merge current and previous unpartitioned entry */
2970 /* Adjust the previous entries length */
2971 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2973 /* Remove the current entry */
2974 RemoveEntryList(&PartEntry
->ListEntry
);
2975 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2977 /* Update current partition */
2978 List
->CurrentPartition
= PrevPartEntry
;
2980 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
2982 /* Merge current and next unpartitioned entry */
2984 /* Adjust the next entries offset and length */
2985 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
2986 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2988 /* Remove the current entry */
2989 RemoveEntryList(&PartEntry
->ListEntry
);
2990 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2992 /* Update current partition */
2993 List
->CurrentPartition
= NextPartEntry
;
2997 /* Nothing to merge but change current entry */
2998 PartEntry
->IsPartitioned
= FALSE
;
2999 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
3000 PartEntry
->FormatState
= Unformatted
;
3001 PartEntry
->FileSystem
[0] = L
'\0';
3002 PartEntry
->DriveLetter
= 0;
3003 PartEntry
->OnDiskPartitionNumber
= 0;
3004 PartEntry
->PartitionNumber
= 0;
3005 // PartEntry->PartitionIndex = 0;
3008 UpdateDiskLayout(DiskEntry
);
3010 AssignDriveLetters(List
);
3015 IsSupportedActivePartition(
3016 IN PPARTENTRY PartEntry
)
3018 /* Check the type and the filesystem of this partition */
3021 * We do not support extended partition containers (on MBR disks) marked
3022 * as active, and containing code inside their extended boot records.
3024 if (IsContainerPartition(PartEntry
->PartitionType
))
3026 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3027 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3032 * ADDITIONAL CHECKS / BIG HACK:
3034 * Retrieve its file system and check whether we have
3035 * write support for it. If that is the case we are fine
3036 * and we can use it directly. However if we don't have
3037 * write support we will need to change the active system
3040 * NOTE that this is completely useless on architectures
3041 * where a real system partition is required, as on these
3042 * architectures the partition uses the FAT FS, for which
3043 * we do have write support.
3044 * NOTE also that for those architectures looking for a
3045 * partition boot indicator is insufficient.
3047 if ((PartEntry
->FormatState
== Unformatted
) ||
3048 (PartEntry
->FormatState
== Preformatted
) ||
3049 (PartEntry
->FormatState
== Formatted
))
3051 ASSERT(*PartEntry
->FileSystem
);
3053 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3054 if (wcsicmp(PartEntry
->FileSystem
, L
"FAT") == 0 ||
3055 wcsicmp(PartEntry
->FileSystem
, L
"FAT32") == 0 ||
3056 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3057 wcsicmp(PartEntry
->FileSystem
, L
"BTRFS") == 0 ||
3058 wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
3064 // WARNING: We cannot write on this FS yet!
3065 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3066 PartEntry
->FileSystem
);
3070 else // if (PartEntry->FormatState == UnknownFormat)
3072 ASSERT(!*PartEntry
->FileSystem
);
3074 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3075 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3079 // HACK: WARNING: We cannot write on this FS yet!
3080 // See fsutil.c:InferFileSystem()
3081 if (PartEntry
->PartitionType
== PARTITION_IFS
)
3083 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3084 PartEntry
->FileSystem
);
3092 CheckActiveSystemPartition(
3095 PDISKENTRY DiskEntry
;
3096 PPARTENTRY PartEntry
;
3097 PLIST_ENTRY ListEntry
;
3099 /* Check for empty disk list */
3100 if (IsListEmpty(&List
->DiskListHead
))
3102 List
->SystemPartition
= NULL
;
3103 List
->OriginalSystemPartition
= NULL
;
3107 /* Choose the currently selected disk */
3108 DiskEntry
= List
->CurrentDisk
;
3110 /* Check for empty partition list */
3111 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
3113 List
->SystemPartition
= NULL
;
3114 List
->OriginalSystemPartition
= NULL
;
3118 if (List
->SystemPartition
!= NULL
)
3120 /* We already have an active system partition */
3121 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3122 List
->SystemPartition
->PartitionNumber
,
3123 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3124 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3128 DPRINT("We are here (1)!\n");
3130 List
->SystemPartition
= NULL
;
3131 List
->OriginalSystemPartition
= NULL
;
3133 /* Retrieve the first partition of the disk */
3134 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
3137 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3138 List
->SystemPartition
= PartEntry
;
3141 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3144 /* Check if the disk is new and if so, use its first partition as the active system partition */
3145 if (DiskEntry
->NewDisk
)
3147 if (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
== FALSE
)
3149 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3150 List
->SystemPartition
= PartEntry
;
3152 List
->OriginalSystemPartition
= List
->SystemPartition
;
3154 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3155 List
->SystemPartition
->PartitionNumber
,
3156 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3157 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3159 goto SetSystemPartition
;
3162 // FIXME: What to do??
3163 DPRINT1("NewDisk TRUE but first partition is used?\n");
3166 DPRINT("We are here (2)!\n");
3169 * The disk is not new, check if any partition is initialized;
3170 * if not, the first one becomes the system partition.
3172 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3173 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3174 ListEntry
= ListEntry
->Flink
)
3176 /* Retrieve the partition */
3177 PartEntry
= CONTAINING_RECORD(ListEntry
,
3181 /* Check if the partition is partitioned and is used */
3182 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
!= FALSE
)
3187 if (ListEntry
== &DiskEntry
->PrimaryPartListHead
)
3190 * OK we haven't encountered any used and active partition,
3191 * so use the first one as the system partition.
3193 ASSERT(DiskEntry
== List
->SystemPartition
->DiskEntry
);
3194 List
->OriginalSystemPartition
= List
->SystemPartition
; // First PartEntry
3196 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3197 List
->SystemPartition
->PartitionNumber
,
3198 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3199 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3201 goto SetSystemPartition
;
3204 List
->SystemPartition
= NULL
;
3205 List
->OriginalSystemPartition
= NULL
;
3207 DPRINT("We are here (3)!\n");
3209 /* The disk is not new, scan all partitions to find the (active) system partition */
3210 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3211 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3212 ListEntry
= ListEntry
->Flink
)
3214 /* Retrieve the partition */
3215 PartEntry
= CONTAINING_RECORD(ListEntry
,
3219 /* Check if the partition is partitioned and used */
3220 if (PartEntry
->IsPartitioned
&&
3221 PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
)
3223 /* Check if the partition is active */
3224 if (PartEntry
->BootIndicator
)
3226 /* Yes, we found it */
3227 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3228 List
->SystemPartition
= PartEntry
;
3230 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3231 PartEntry
->PartitionNumber
,
3232 DiskEntry
->DiskNumber
,
3233 (PartEntry
->DriveLetter
== 0) ? L
'-' : PartEntry
->DriveLetter
);
3239 /* Check if we have found the system partition */
3240 if (List
->SystemPartition
== NULL
)
3242 /* Nothing, use the alternative system partition */
3243 DPRINT1("No system partition found, use the alternative partition!\n");
3244 goto UseAlternativeSystemPartition
;
3248 List
->OriginalSystemPartition
= List
->SystemPartition
;
3250 /* If we get a candidate active partition, validate it */
3251 if (!IsSupportedActivePartition(List
->OriginalSystemPartition
))
3253 goto FindAndUseAlternativeSystemPartition
;
3256 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3257 List
->SystemPartition
->PartitionNumber
,
3258 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3259 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3263 FindAndUseAlternativeSystemPartition
:
3265 * We are here because we have not found any (active) candidate
3266 * system partition that we know how to support. What we are going
3267 * to do is to change the existing system partition and use the
3268 * partition on which we install ReactOS as the new system partition,
3269 * and then we will need to add in FreeLdr's entry a boot entry to boot
3270 * from the original system partition.
3273 /* Unset the old system partition */
3274 List
->SystemPartition
->BootIndicator
= FALSE
;
3275 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= FALSE
;
3276 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3277 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3279 UseAlternativeSystemPartition
:
3280 List
->SystemPartition
= List
->CurrentPartition
;
3282 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3283 List
->SystemPartition
->PartitionNumber
,
3284 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3285 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3288 /* Set the new active system partition */
3289 List
->SystemPartition
->BootIndicator
= TRUE
;
3290 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= TRUE
;
3291 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3292 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3299 IN PDISKENTRY DiskEntry
)
3302 OBJECT_ATTRIBUTES ObjectAttributes
;
3303 UNICODE_STRING Name
;
3305 IO_STATUS_BLOCK Iosb
;
3307 PPARTITION_INFORMATION PartitionInfo
;
3308 ULONG PartitionCount
;
3309 PLIST_ENTRY ListEntry
;
3310 PPARTENTRY PartEntry
;
3311 WCHAR DstPath
[MAX_PATH
];
3313 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3315 RtlStringCchPrintfW(DstPath
, ARRAYSIZE(DstPath
),
3316 L
"\\Device\\Harddisk%lu\\Partition0",
3317 DiskEntry
->DiskNumber
);
3318 RtlInitUnicodeString(&Name
, DstPath
);
3320 InitializeObjectAttributes(&ObjectAttributes
,
3322 OBJ_CASE_INSENSITIVE
,
3326 Status
= NtOpenFile(&FileHandle
,
3327 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3331 FILE_SYNCHRONOUS_IO_NONALERT
);
3332 if (!NT_SUCCESS(Status
))
3334 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3338 #ifdef DUMP_PARTITION_TABLE
3339 DumpPartitionTable(DiskEntry
);
3343 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3344 // the disk in MBR or GPT format in case the disk was not initialized!!
3345 // For this we must ask the user which format to use.
3348 /* Save the original partition count to be restored later (see comment below) */
3349 PartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
3351 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3352 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3353 ((PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3354 Status
= NtDeviceIoControlFile(FileHandle
,
3359 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3360 DiskEntry
->LayoutBuffer
,
3362 DiskEntry
->LayoutBuffer
,
3364 NtClose(FileHandle
);
3367 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3368 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3369 * where such a table is expected to enumerate up to 4 partitions:
3370 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3371 * Due to this we need to restore the original PartitionCount number.
3373 DiskEntry
->LayoutBuffer
->PartitionCount
= PartitionCount
;
3375 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3376 if (!NT_SUCCESS(Status
))
3378 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3382 #ifdef DUMP_PARTITION_TABLE
3383 DumpPartitionTable(DiskEntry
);
3386 /* Update the partition numbers */
3388 /* Update the primary partition table */
3389 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3390 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3391 ListEntry
= ListEntry
->Flink
)
3393 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3395 if (PartEntry
->IsPartitioned
)
3397 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3398 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3402 /* Update the logical partition table */
3403 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
3404 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
3405 ListEntry
= ListEntry
->Flink
)
3407 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3409 if (PartEntry
->IsPartitioned
)
3411 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3412 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3417 // NOTE: Originally (see r40437), we used to install here also a new MBR
3418 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3419 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3420 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3421 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3422 // was called too, the installation test was modified by checking whether
3423 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3426 // DiskEntry->Dirty = FALSE;
3432 WritePartitionsToDisk(
3436 PDISKENTRY DiskEntry
;
3441 for (Entry
= List
->DiskListHead
.Flink
;
3442 Entry
!= &List
->DiskListHead
;
3443 Entry
= Entry
->Flink
)
3445 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3447 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3449 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3453 if (DiskEntry
->Dirty
!= FALSE
)
3455 WritePartitions(List
, DiskEntry
);
3456 DiskEntry
->Dirty
= FALSE
;
3464 SetMountedDeviceValue(
3467 IN LARGE_INTEGER StartingOffset
)
3469 OBJECT_ATTRIBUTES ObjectAttributes
;
3470 WCHAR ValueNameBuffer
[16];
3471 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3472 UNICODE_STRING ValueName
;
3473 REG_DISK_MOUNT_INFO MountInfo
;
3477 RtlStringCchPrintfW(ValueNameBuffer
, ARRAYSIZE(ValueNameBuffer
),
3478 L
"\\DosDevices\\%c:", Letter
);
3479 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
3481 InitializeObjectAttributes(&ObjectAttributes
,
3483 OBJ_CASE_INSENSITIVE
,
3487 Status
= NtOpenKey(&KeyHandle
,
3490 if (!NT_SUCCESS(Status
))
3492 Status
= NtCreateKey(&KeyHandle
,
3497 REG_OPTION_NON_VOLATILE
,
3501 if (!NT_SUCCESS(Status
))
3503 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
3507 MountInfo
.Signature
= Signature
;
3508 MountInfo
.StartingOffset
= StartingOffset
;
3509 Status
= NtSetValueKey(KeyHandle
,
3516 if (!NT_SUCCESS(Status
))
3518 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
3526 SetMountedDeviceValues(
3529 PLIST_ENTRY Entry1
, Entry2
;
3530 PDISKENTRY DiskEntry
;
3531 PPARTENTRY PartEntry
;
3532 LARGE_INTEGER StartingOffset
;
3537 for (Entry1
= List
->DiskListHead
.Flink
;
3538 Entry1
!= &List
->DiskListHead
;
3539 Entry1
= Entry1
->Flink
)
3541 DiskEntry
= CONTAINING_RECORD(Entry1
,
3545 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3547 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3551 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3552 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3553 Entry2
= Entry2
->Flink
)
3555 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3556 if (PartEntry
->IsPartitioned
)
3558 /* Assign a "\DosDevices\#:" mount point to this partition */
3559 if (PartEntry
->DriveLetter
)
3561 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3562 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3563 DiskEntry
->LayoutBuffer
->Signature
,
3572 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3573 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3574 Entry2
= Entry2
->Flink
)
3576 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3577 if (PartEntry
->IsPartitioned
)
3579 /* Assign a "\DosDevices\#:" mount point to this partition */
3580 if (PartEntry
->DriveLetter
)
3582 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3583 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3584 DiskEntry
->LayoutBuffer
->Signature
,
3599 IN PPARTENTRY PartEntry
,
3600 IN UCHAR PartitionType
)
3602 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3604 PartEntry
->PartitionType
= PartitionType
;
3606 DiskEntry
->Dirty
= TRUE
;
3607 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].PartitionType
= PartitionType
;
3608 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RecognizedPartition
= IsRecognizedPartition(PartitionType
);
3609 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3613 PrimaryPartitionCreationChecks(
3616 PDISKENTRY DiskEntry
;
3617 PPARTENTRY PartEntry
;
3619 DiskEntry
= List
->CurrentDisk
;
3620 PartEntry
= List
->CurrentPartition
;
3622 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3624 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3625 return ERROR_WARN_PARTITION
;
3628 /* Fail if the partition is already in use */
3629 if (PartEntry
->IsPartitioned
)
3630 return ERROR_NEW_PARTITION
;
3632 /* Fail if there are already 4 primary partitions in the list */
3633 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3634 return ERROR_PARTITION_TABLE_FULL
;
3636 return ERROR_SUCCESS
;
3640 ExtendedPartitionCreationChecks(
3643 PDISKENTRY DiskEntry
;
3644 PPARTENTRY PartEntry
;
3646 DiskEntry
= List
->CurrentDisk
;
3647 PartEntry
= List
->CurrentPartition
;
3649 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3651 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3652 return ERROR_WARN_PARTITION
;
3655 /* Fail if the partition is already in use */
3656 if (PartEntry
->IsPartitioned
)
3657 return ERROR_NEW_PARTITION
;
3659 /* Fail if there are already 4 primary partitions in the list */
3660 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3661 return ERROR_PARTITION_TABLE_FULL
;
3663 /* Fail if there is another extended partition in the list */
3664 if (DiskEntry
->ExtendedPartition
!= NULL
)
3665 return ERROR_ONLY_ONE_EXTENDED
;
3667 return ERROR_SUCCESS
;
3671 LogicalPartitionCreationChecks(
3674 PDISKENTRY DiskEntry
;
3675 PPARTENTRY PartEntry
;
3677 DiskEntry
= List
->CurrentDisk
;
3678 PartEntry
= List
->CurrentPartition
;
3680 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3682 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3683 return ERROR_WARN_PARTITION
;
3686 /* Fail if the partition is already in use */
3687 if (PartEntry
->IsPartitioned
)
3688 return ERROR_NEW_PARTITION
;
3690 return ERROR_SUCCESS
;
3694 GetNextUnformattedPartition(
3696 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3697 OUT PPARTENTRY
*pPartEntry
)
3699 PLIST_ENTRY Entry1
, Entry2
;
3700 PDISKENTRY DiskEntry
;
3701 PPARTENTRY PartEntry
;
3703 for (Entry1
= List
->DiskListHead
.Flink
;
3704 Entry1
!= &List
->DiskListHead
;
3705 Entry1
= Entry1
->Flink
)
3707 DiskEntry
= CONTAINING_RECORD(Entry1
,
3711 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3713 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3717 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3718 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3719 Entry2
= Entry2
->Flink
)
3721 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3722 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3724 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3725 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3726 *pPartEntry
= PartEntry
;
3731 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3732 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3733 Entry2
= Entry2
->Flink
)
3735 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3736 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3738 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3739 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3740 *pPartEntry
= PartEntry
;
3746 if (pDiskEntry
) *pDiskEntry
= NULL
;
3753 GetNextUncheckedPartition(
3755 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3756 OUT PPARTENTRY
*pPartEntry
)
3758 PLIST_ENTRY Entry1
, Entry2
;
3759 PDISKENTRY DiskEntry
;
3760 PPARTENTRY PartEntry
;
3762 for (Entry1
= List
->DiskListHead
.Flink
;
3763 Entry1
!= &List
->DiskListHead
;
3764 Entry1
= Entry1
->Flink
)
3766 DiskEntry
= CONTAINING_RECORD(Entry1
,
3770 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3772 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3776 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3777 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3778 Entry2
= Entry2
->Flink
)
3780 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3781 if (PartEntry
->NeedsCheck
== TRUE
)
3783 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3784 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3785 *pPartEntry
= PartEntry
;
3790 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3791 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3792 Entry2
= Entry2
->Flink
)
3794 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3795 if (PartEntry
->NeedsCheck
== TRUE
)
3797 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3798 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3799 *pPartEntry
= PartEntry
;
3805 if (pDiskEntry
) *pDiskEntry
= NULL
;