2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Partition list functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2018-2019 Hermes Belusca-Maito
18 //#define DUMP_PARTITION_TABLE
22 typedef struct _REG_DISK_MOUNT_INFO
25 LARGE_INTEGER StartingOffset
;
26 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
31 /* HELPERS FOR PARTITION TYPES **********************************************/
34 * This partition type list was ripped from the kernelDisk.c module of
35 * the Visopsys Operating System (see license below), and completed with
36 * information from Paragon Hard-Disk Manager, and the following websites:
37 * http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
38 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
43 * Visopsys Operating System
44 * Copyright (C) 1998-2015 J. Andrew McLaughlin
46 * This program is free software; you can redistribute it and/or modify it
47 * under the terms of the GNU General Public License as published by the Free
48 * Software Foundation; either version 2 of the License, or (at your option)
51 * This program is distributed in the hope that it will be useful, but
52 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
53 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
56 * You should have received a copy of the GNU General Public License along
57 * with this program; if not, write to the Free Software Foundation, Inc.,
58 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
61 /* This is a table for keeping known partition type codes and descriptions */
62 PARTITION_TYPE PartitionTypes
[NUM_PARTITION_TYPE_ENTRIES
] =
66 { 0x02, "XENIX root" },
67 { 0x03, "XENIX usr" },
68 { 0x04, "FAT16 (< 32 MB)" },
71 { 0x07, "NTFS/HPFS/exFAT" },
72 { 0x08, "OS/2 or AIX boot" },
74 { 0x0A, "OS/2 Boot Manager" },
76 { 0x0C, "FAT32 (LBA)" },
77 { 0x0E, "FAT16 (LBA)" },
78 { 0x0F, "Extended (LBA)" },
80 { 0x11, "Hidden FAT12" },
81 { 0x12, "FAT diagnostic (Compaq)" },
83 { 0x14, "Hidden FAT16 (< 32 MB)" },
84 { 0x16, "Hidden FAT16" },
85 { 0x17, "Hidden HPFS or NTFS" },
86 { 0x18, "AST SmartSleep" },
87 { 0x1B, "Hidden FAT32" },
88 { 0x1C, "Hidden FAT32 (LBA)" },
89 { 0x1E, "Hidden FAT16 (LBA)" },
90 { 0x24, "NEC DOS 3.x" },
91 { 0x27, "Hidden WinRE NTFS" },
92 { 0x2A, "AtheOS File System (AFS)" },
93 { 0x2B, "SyllableSecure (SylStor)" },
95 { 0x35, "JFS on OS/2 or eCS" },
96 { 0x38, "THEOS v3.2 2GB partition" },
98 { 0x3A, "THEOS v4 4GB partition" },
99 { 0x3B, "THEOS v4 extended partition" },
100 { 0x3C, "PartitionMagic recovery partition" },
101 { 0x3D, "Hidden NetWare" },
103 { 0x41, "PowerPC PReP boot" },
104 { 0x42, "Win2K Dynamic Volume extended" },
105 { 0x43, "Old Linux" },
107 { 0x45, "Priam or Boot-US Boot Manager" },
109 { 0x4E, "QNX4.x 2nd partition" },
110 { 0x4F, "QNX4.x 3rd partition" },
111 { 0x50, "OnTrack Disk Manager R/O" },
112 { 0x51, "OnTrack Disk Manager R/W or Novell" },
114 { 0x53, "OnTrack DM6 Aux3" },
115 { 0x54, "OnTrack DM6 Dynamic Drive Overlay" },
116 { 0x55, "EZ-Drive" },
117 { 0x56, "Golden Bow VFeature Partitioned Volume" },
118 { 0x5C, "Priam EDisk" },
119 { 0x61, "SpeedStor" },
121 { 0x63, "GNU HURD or Unix System V (SCO, ISC Unix, UnixWare)" },
122 { 0x64, "Novell NetWare 286, 2.xx" },
123 { 0x65, "Novell NetWare 386, 3.xx or 4.xx" },
124 { 0x66, "Novell NetWare SMS Partition" },
127 { 0x69, "Novell NetWare 5+" },
128 { 0x70, "DiskSecure Multi-Boot" },
129 { 0x75, "IBM PC/IX" },
130 { 0x7E, "Veritas VxVM public" },
131 { 0x7F, "Veritas VxVM private" },
132 { 0x80, "Old MINIX" },
133 { 0x81, "Linux or MINIX" },
134 { 0x82, "Linux swap or Solaris" },
135 { 0x83, "Linux Native" },
136 { 0x84, "Hibernate" },
137 { 0x85, "Extended Linux" },
138 { 0x86, "FAT16 mirrored" },
139 { 0x87, "HPFS or NTFS mirrored" },
140 { 0x88, "Linux plaintext partition table" },
141 { 0x8B, "FAT32 mirrored" },
142 { 0x8C, "FAT32 (LBA) mirrored" },
143 { 0x8E, "Linux LVM" },
144 { 0x93, "Hidden Linux" },
145 { 0x94, "Amoeba BBT" },
146 { 0x96, "CDFS/ISO-9660" },
148 { 0xA0, "Laptop Hibernate" },
149 { 0xA1, "Laptop Hibernate (NEC 6000H)" },
150 { 0xA5, "BSD, NetBSD, FreeBSD" },
152 { 0xA7, "NeXTStep" },
153 { 0xA8, "Darwin UFS" }, // Also known as "OS-X"
155 { 0xAB, "Darwin boot" },
156 { 0xAF, "Apple HFS" },
157 { 0xB6, "NT FAT16 corrupt mirror" },
158 { 0xB7, "BSDI BSD/386 FS" }, // Alternatively, "NT NTFS corrupt mirror"
159 { 0xB8, "BSDI BSD/386 swap" },
160 { 0xBB, "Boot Wizard hidden" },
161 { 0xBC, "Paragon Backup capsule" },
162 { 0xBE, "Solaris 8 boot partition" },
163 { 0xBF, "Solaris 10 x86" },
164 { 0xC0, "NTFT" }, // Alternatively, "CTOS" or "REAL/32 or DR-DOS or Novell-DOS secure partition"
165 { 0xC1, "DR-DOS FAT12" },
166 { 0xC2, "Hidden Linux" },
167 { 0xC3, "Hidden Linux swap" },
168 { 0xC4, "DR-DOS FAT16 (< 32 MB)" },
169 { 0xC5, "DR-DOS Extended" },
170 { 0xC6, "DR-DOS FAT16" },
171 { 0xC7, "HPFS mirrored" }, // Alternatively, "Syrinx boot"
172 { 0xCB, "DR-DOS FAT32" },
173 { 0xCC, "DR-DOS FAT32 (LBA)" },
174 { 0xCE, "DR-DOS FAT16 (LBA)" },
176 { 0xD1, "MDOS FAT12" },
177 { 0xD4, "MDOS FAT16 (< 32 MB)" },
178 { 0xD5, "MDOS Extended" },
179 { 0xD6, "MDOS FAT16" },
181 { 0xDB, "Digital Research CP/M" },
182 { 0xDE, "Dell OEM" },
183 { 0xDF, "BootIt EMBRM (FAT16/32)" },
184 { 0xE1, "SpeedStor FAT12" },
185 { 0xE3, "SpeedStor (0xE3)" },
186 { 0xE4, "SpeedStor FAT16" },
187 { 0xE5, "Tandy MSDOS" },
188 { 0xE6, "SpeedStor (0xE6)" },
189 { 0xE8, "Linux Unified Key Setup partition" },
190 { 0xEA, "Rufus private partition" },
191 { 0xEB, "BeOS BFS" },
192 { 0xEC, "SkyOS SkyFS" },
193 { 0xEE, "EFI GPT protective" },
194 { 0xEF, "EFI System partition" },
195 { 0xF0, "Linux/PA-RISC boot loader" },
196 { 0xF1, "SpeedStor (0xF1)" },
197 { 0xF2, "DOS 3.3+ second" },
198 { 0xF4, "SpeedStor (0xF4)" },
199 { 0xF5, "SpeedStor (0xF5)" },
200 { 0xF6, "SpeedStor (0xF6)" },
202 { 0xFB, "VMware FS" },
203 { 0xFC, "VMware swap" },
204 { 0xFD, "Linux RAID auto" },
205 { 0xFE, "NT hidden partition" },
206 { 0xFF, "XENIX Bad Block Table" },
210 /* FUNCTIONS ****************************************************************/
212 #ifdef DUMP_PARTITION_TABLE
216 PDISKENTRY DiskEntry
)
218 PPARTITION_INFORMATION PartitionInfo
;
222 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
223 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
225 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
227 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
228 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
230 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
231 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
232 PartitionInfo
->HiddenSectors
,
233 PartitionInfo
->PartitionNumber
,
234 PartitionInfo
->PartitionType
,
235 PartitionInfo
->BootIndicator
? '*': ' ',
236 PartitionInfo
->RewritePartition
? 'Y': 'N');
251 Temp
= Value
/ Alignment
;
253 return Temp
* Alignment
;
261 ULONGLONG Temp
, Result
;
263 Temp
= Value
/ Alignment
;
265 Result
= Temp
* Alignment
;
266 if (Value
% Alignment
)
274 IN ULONGLONG Dividend
,
275 IN ULONGLONG Divisor
)
277 return (Dividend
+ Divisor
/ 2) / Divisor
;
284 IN PDISKENTRY DiskEntry
)
286 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
290 RtlInitUnicodeString(&DiskEntry
->DriverName
, NULL
);
292 RtlStringCchPrintfW(KeyName
, ARRAYSIZE(KeyName
),
293 L
"\\Scsi\\Scsi Port %hu",
296 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
298 QueryTable
[0].Name
= L
"Driver";
299 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
300 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
302 /* This will allocate DiskEntry->DriverName if needed */
303 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
308 if (!NT_SUCCESS(Status
))
310 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
319 PDISKENTRY DiskEntry
;
320 PPARTENTRY PartEntry
;
327 /* Assign drive letters to primary partitions */
328 for (Entry1
= List
->DiskListHead
.Flink
;
329 Entry1
!= &List
->DiskListHead
;
330 Entry1
= Entry1
->Flink
)
332 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
334 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
335 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
336 Entry2
= Entry2
->Flink
)
338 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
340 PartEntry
->DriveLetter
= 0;
342 if (PartEntry
->IsPartitioned
&&
343 !IsContainerPartition(PartEntry
->PartitionType
))
345 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
347 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
348 PartEntry
->SectorCount
.QuadPart
!= 0LL)
352 PartEntry
->DriveLetter
= Letter
;
360 /* Assign drive letters to logical drives */
361 for (Entry1
= List
->DiskListHead
.Flink
;
362 Entry1
!= &List
->DiskListHead
;
363 Entry1
= Entry1
->Flink
)
365 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
367 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
368 Entry2
!= &DiskEntry
->LogicalPartListHead
;
369 Entry2
= Entry2
->Flink
)
371 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
373 PartEntry
->DriveLetter
= 0;
375 if (PartEntry
->IsPartitioned
)
377 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
379 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
380 PartEntry
->SectorCount
.QuadPart
!= 0LL)
384 PartEntry
->DriveLetter
= Letter
;
395 DiskIdentifierQueryRoutine(
403 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
404 UNICODE_STRING NameU
;
406 if (ValueType
== REG_SZ
&&
407 ValueLength
== 20 * sizeof(WCHAR
))
409 NameU
.Buffer
= (PWCHAR
)ValueData
;
410 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
411 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
413 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
414 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
416 return STATUS_SUCCESS
;
419 return STATUS_UNSUCCESSFUL
;
424 DiskConfigurationDataQueryRoutine(
432 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
433 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
434 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
437 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
438 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
439 return STATUS_UNSUCCESSFUL
;
441 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
443 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
445 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
446 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
447 return STATUS_UNSUCCESSFUL
;
450 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
452 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
453 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
456 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
457 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
459 return STATUS_SUCCESS
;
462 return STATUS_UNSUCCESSFUL
;
467 SystemConfigurationDataQueryRoutine(
475 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
476 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
479 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
480 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
481 return STATUS_UNSUCCESSFUL
;
483 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
485 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
487 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
488 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
489 return STATUS_UNSUCCESSFUL
;
492 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
494 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
495 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
498 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(ProcessHeap
, 0,
499 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
500 if (*Int13Drives
== NULL
)
501 return STATUS_NO_MEMORY
;
504 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
505 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
506 return STATUS_SUCCESS
;
509 return STATUS_UNSUCCESSFUL
;
514 EnumerateBiosDiskEntries(
515 IN PPARTLIST PartList
)
517 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
522 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
523 PBIOSDISKENTRY BiosDiskEntry
;
525 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
527 memset(QueryTable
, 0, sizeof(QueryTable
));
529 QueryTable
[1].Name
= L
"Configuration Data";
530 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
532 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
533 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
537 if (!NT_SUCCESS(Status
))
539 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
546 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
548 ROOT_NAME
, AdapterCount
);
549 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
554 if (!NT_SUCCESS(Status
))
559 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
560 L
"%s\\%lu\\DiskController",
561 ROOT_NAME
, AdapterCount
);
562 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
567 if (NT_SUCCESS(Status
))
571 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
572 L
"%s\\%lu\\DiskController\\0",
573 ROOT_NAME
, AdapterCount
);
574 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
579 if (!NT_SUCCESS(Status
))
581 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
585 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
586 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral",
587 ROOT_NAME
, AdapterCount
);
588 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
593 if (NT_SUCCESS(Status
))
595 QueryTable
[0].Name
= L
"Identifier";
596 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
597 QueryTable
[1].Name
= L
"Configuration Data";
598 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
603 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
604 if (BiosDiskEntry
== NULL
)
609 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
610 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
611 ROOT_NAME
, AdapterCount
, DiskCount
);
612 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
615 (PVOID
)BiosDiskEntry
,
617 if (!NT_SUCCESS(Status
))
619 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
623 BiosDiskEntry
->DiskNumber
= DiskCount
;
624 BiosDiskEntry
->Recognized
= FALSE
;
626 if (DiskCount
< Int13Drives
[0].NumberDrives
)
628 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
632 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount
);
635 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
637 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
638 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
639 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
640 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
641 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
642 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
643 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
644 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
645 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
646 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
647 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
653 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
661 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
669 * Inserts the disk region represented by PartEntry into either the primary
670 * or the logical partition list of the given disk.
671 * The lists are kept sorted by increasing order of start sectors.
672 * Of course no disk region should overlap at all with one another.
677 IN PDISKENTRY DiskEntry
,
678 IN PPARTENTRY PartEntry
,
679 IN BOOLEAN LogicalPartition
)
683 PPARTENTRY PartEntry2
;
685 /* Use the correct partition list */
686 if (LogicalPartition
)
687 List
= &DiskEntry
->LogicalPartListHead
;
689 List
= &DiskEntry
->PrimaryPartListHead
;
691 /* Find the first disk region before which we need to insert the new one */
692 for (Entry
= List
->Flink
; Entry
!= List
; Entry
= Entry
->Flink
)
694 PartEntry2
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
696 /* Ignore any unused empty region */
697 if ((PartEntry2
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
698 PartEntry2
->StartSector
.QuadPart
== 0) || PartEntry2
->SectorCount
.QuadPart
== 0)
703 /* If the current region ends before the one to be inserted, try again */
704 if (PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1 < PartEntry
->StartSector
.QuadPart
)
708 * One of the disk region boundaries crosses the desired region
709 * (it starts after the desired region, or ends before the end
710 * of the desired region): this is an impossible situation because
711 * disk regions (partitions) cannot overlap!
712 * Throw an error and bail out.
714 if (max(PartEntry
->StartSector
.QuadPart
, PartEntry2
->StartSector
.QuadPart
)
716 min( PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
717 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1))
719 DPRINT1("Disk region overlap problem, stopping there!\n"
720 "Partition to be inserted:\n"
721 " StartSector = %I64u ; EndSector = %I64u\n"
722 "Existing disk region:\n"
723 " StartSector = %I64u ; EndSector = %I64u\n",
724 PartEntry
->StartSector
.QuadPart
,
725 PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
726 PartEntry2
->StartSector
.QuadPart
,
727 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1);
731 /* We have found the first region before which the new one has to be inserted */
735 /* Insert the disk region */
736 InsertTailList(Entry
, &PartEntry
->ListEntry
);
741 CreateInsertBlankRegion(
742 IN PDISKENTRY DiskEntry
,
743 IN OUT PLIST_ENTRY ListHead
,
744 IN ULONGLONG StartSector
,
745 IN ULONGLONG SectorCount
,
746 IN BOOLEAN LogicalSpace
)
748 PPARTENTRY NewPartEntry
;
750 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
753 if (NewPartEntry
== NULL
)
756 NewPartEntry
->DiskEntry
= DiskEntry
;
758 NewPartEntry
->StartSector
.QuadPart
= StartSector
;
759 NewPartEntry
->SectorCount
.QuadPart
= SectorCount
;
761 NewPartEntry
->IsPartitioned
= FALSE
;
762 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
763 NewPartEntry
->FormatState
= Unformatted
;
764 NewPartEntry
->FileSystem
[0] = L
'\0';
766 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
767 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
768 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
770 /* Insert the new entry into the list */
771 InsertTailList(ListHead
, &NewPartEntry
->ListEntry
);
779 InitializePartitionEntry(
780 IN PDISKENTRY DiskEntry
,
781 IN PPARTENTRY PartEntry
,
782 IN ULONGLONG SectorCount
,
783 IN BOOLEAN AutoCreate
)
785 PPARTENTRY NewPartEntry
;
787 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
789 if ((AutoCreate
!= FALSE
) ||
790 (AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
791 PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
))
793 DPRINT1("Convert existing partition entry\n");
795 NewPartEntry
= PartEntry
;
796 NewPartEntry
->AutoCreate
= AutoCreate
;
800 DPRINT1("Add new partition entry\n");
802 /* Insert and initialize a new partition entry */
803 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
806 if (NewPartEntry
== NULL
)
809 NewPartEntry
->DiskEntry
= DiskEntry
;
811 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
812 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
813 NewPartEntry
->StartSector
.QuadPart
;
815 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
816 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
818 /* Insert the new entry into the list */
819 InsertTailList(&PartEntry
->ListEntry
, &NewPartEntry
->ListEntry
);
822 /* Create entry as 'New (Unformatted)' */
823 NewPartEntry
->New
= TRUE
;
824 NewPartEntry
->IsPartitioned
= TRUE
;
826 NewPartEntry
->PartitionType
= FileSystemToPartitionType(L
"RAW", &NewPartEntry
->StartSector
, &NewPartEntry
->SectorCount
);
827 ASSERT(NewPartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
829 NewPartEntry
->FormatState
= Unformatted
;
830 NewPartEntry
->FileSystem
[0] = L
'\0';
831 // NewPartEntry->AutoCreate = AutoCreate;
832 NewPartEntry
->BootIndicator
= FALSE
;
833 NewPartEntry
->LogicalPartition
= FALSE
;
835 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
836 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
837 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
847 IN PDISKENTRY DiskEntry
,
848 IN ULONG PartitionIndex
,
849 IN BOOLEAN LogicalPartition
)
852 PPARTITION_INFORMATION PartitionInfo
;
853 PPARTENTRY PartEntry
;
854 HANDLE PartitionHandle
;
855 OBJECT_ATTRIBUTES ObjectAttributes
;
856 IO_STATUS_BLOCK IoStatusBlock
;
857 WCHAR PathBuffer
[MAX_PATH
];
859 UCHAR LabelBuffer
[sizeof(FILE_FS_VOLUME_INFORMATION
) + 256 * sizeof(WCHAR
)];
860 PFILE_FS_VOLUME_INFORMATION LabelInfo
= (PFILE_FS_VOLUME_INFORMATION
)LabelBuffer
;
862 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
864 if (PartitionInfo
->PartitionType
== PARTITION_ENTRY_UNUSED
||
865 ((LogicalPartition
!= FALSE
) && IsContainerPartition(PartitionInfo
->PartitionType
)))
870 PartEntry
= RtlAllocateHeap(ProcessHeap
,
873 if (PartEntry
== NULL
)
876 PartEntry
->DiskEntry
= DiskEntry
;
878 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
879 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
881 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
882 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
883 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
885 PartEntry
->LogicalPartition
= LogicalPartition
;
886 PartEntry
->IsPartitioned
= TRUE
;
887 PartEntry
->OnDiskPartitionNumber
= PartitionInfo
->PartitionNumber
;
888 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
889 PartEntry
->PartitionIndex
= PartitionIndex
;
891 /* Specify the partition as initially unformatted */
892 PartEntry
->FormatState
= Unformatted
;
893 PartEntry
->FileSystem
[0] = L
'\0';
895 /* Initialize the partition volume label */
896 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
898 if (IsContainerPartition(PartEntry
->PartitionType
))
900 PartEntry
->FormatState
= Unformatted
;
902 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
903 DiskEntry
->ExtendedPartition
= PartEntry
;
905 else if (IsRecognizedPartition(PartEntry
->PartitionType
))
907 ASSERT(PartitionInfo
->RecognizedPartition
);
908 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
910 /* Open the volume, ignore any errors */
911 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
912 L
"\\Device\\Harddisk%lu\\Partition%lu",
913 DiskEntry
->DiskNumber
,
914 PartEntry
->PartitionNumber
);
915 RtlInitUnicodeString(&Name
, PathBuffer
);
917 InitializeObjectAttributes(&ObjectAttributes
,
919 OBJ_CASE_INSENSITIVE
,
923 PartitionHandle
= NULL
;
924 Status
= NtOpenFile(&PartitionHandle
,
925 FILE_READ_DATA
| SYNCHRONIZE
,
928 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
929 FILE_SYNCHRONOUS_IO_NONALERT
);
930 if (!NT_SUCCESS(Status
))
932 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status
);
935 if (/* NT_SUCCESS(Status) && */ PartitionHandle
)
937 /* We don't have a FS, try to guess one */
938 Status
= InferFileSystemByHandle(PartitionHandle
,
939 PartEntry
->PartitionType
,
940 PartEntry
->FileSystem
,
941 sizeof(PartEntry
->FileSystem
));
942 if (!NT_SUCCESS(Status
))
943 DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status
);
945 if (*PartEntry
->FileSystem
)
947 if (wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
948 PartEntry
->FormatState
= Unformatted
;
950 PartEntry
->FormatState
= Preformatted
;
954 PartEntry
->FormatState
= UnknownFormat
;
957 /* Retrieve the partition volume label */
960 Status
= NtQueryVolumeInformationFile(PartitionHandle
,
964 FileFsVolumeInformation
);
965 if (NT_SUCCESS(Status
))
967 /* Copy the (possibly truncated) volume label and NULL-terminate it */
968 RtlStringCbCopyNW(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
),
969 LabelInfo
->VolumeLabel
, LabelInfo
->VolumeLabelLength
);
973 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status
);
977 /* Close the partition */
979 NtClose(PartitionHandle
);
983 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
984 PartEntry
->FormatState
= UnknownFormat
;
987 InsertDiskRegion(DiskEntry
, PartEntry
, LogicalPartition
);
992 ScanForUnpartitionedDiskSpace(
993 IN PDISKENTRY DiskEntry
)
995 ULONGLONG StartSector
;
996 ULONGLONG SectorCount
;
997 ULONGLONG LastStartSector
;
998 ULONGLONG LastSectorCount
;
999 ULONGLONG LastUnusedSectorCount
;
1000 PPARTENTRY PartEntry
;
1001 PPARTENTRY NewPartEntry
;
1004 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1006 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1008 DPRINT1("No primary partition!\n");
1010 /* Create a partition entry that represents the empty disk */
1012 if (DiskEntry
->SectorAlignment
< 2048)
1013 StartSector
= 2048ULL;
1015 StartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1016 SectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) - StartSector
;
1018 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1019 &DiskEntry
->PrimaryPartListHead
,
1023 if (NewPartEntry
== NULL
)
1024 DPRINT1("Failed to create a new empty region for full disk space!\n");
1029 /* Start partition at head 1, cylinder 0 */
1030 if (DiskEntry
->SectorAlignment
< 2048)
1031 LastStartSector
= 2048ULL;
1033 LastStartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1034 LastSectorCount
= 0ULL;
1035 LastUnusedSectorCount
= 0ULL;
1037 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1038 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1039 Entry
= Entry
->Flink
)
1041 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1043 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1044 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1046 LastUnusedSectorCount
=
1047 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
1049 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
1050 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1052 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1054 StartSector
= LastStartSector
+ LastSectorCount
;
1055 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1057 /* Insert the table into the list */
1058 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1059 &PartEntry
->ListEntry
,
1063 if (NewPartEntry
== NULL
)
1065 DPRINT1("Failed to create a new empty region for disk space!\n");
1070 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1071 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1075 /* Check for trailing unpartitioned disk space */
1076 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
1078 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
1080 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1082 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1084 StartSector
= LastStartSector
+ LastSectorCount
;
1085 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1087 /* Append the table to the list */
1088 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1089 &DiskEntry
->PrimaryPartListHead
,
1093 if (NewPartEntry
== NULL
)
1095 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1101 if (DiskEntry
->ExtendedPartition
!= NULL
)
1103 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1105 DPRINT1("No logical partition!\n");
1107 /* Create a partition entry that represents the empty extended partition */
1109 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1110 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
1112 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1113 &DiskEntry
->LogicalPartListHead
,
1117 if (NewPartEntry
== NULL
)
1119 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1122 NewPartEntry
->LogicalPartition
= TRUE
;
1127 /* Start partition at head 1, cylinder 0 */
1128 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1129 LastSectorCount
= 0ULL;
1130 LastUnusedSectorCount
= 0ULL;
1132 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1133 Entry
!= &DiskEntry
->LogicalPartListHead
;
1134 Entry
= Entry
->Flink
)
1136 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1138 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1139 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1141 LastUnusedSectorCount
=
1142 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
1144 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
1145 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1147 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1149 StartSector
= LastStartSector
+ LastSectorCount
;
1150 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1152 /* Insert the table into the list */
1153 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1154 &PartEntry
->ListEntry
,
1158 if (NewPartEntry
== NULL
)
1160 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1163 NewPartEntry
->LogicalPartition
= TRUE
;
1166 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1167 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1171 /* Check for trailing unpartitioned disk space */
1172 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
1174 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+
1175 DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
1176 DiskEntry
->SectorAlignment
);
1178 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1180 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1182 StartSector
= LastStartSector
+ LastSectorCount
;
1183 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1185 /* Append the table to the list */
1186 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1187 &DiskEntry
->LogicalPartListHead
,
1191 if (NewPartEntry
== NULL
)
1193 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1196 NewPartEntry
->LogicalPartition
= TRUE
;
1201 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1208 IN PDISKENTRY DiskEntry
)
1210 LARGE_INTEGER SystemTime
;
1211 TIME_FIELDS TimeFields
;
1213 PDISKENTRY DiskEntry2
;
1216 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1218 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1222 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1226 NtQuerySystemTime(&SystemTime
);
1227 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1229 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1230 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1231 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1232 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1234 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1239 /* Check if the signature already exist */
1241 * Check also signatures from disks, which are
1242 * not visible (bootable) by the bios.
1244 for (Entry2
= List
->DiskListHead
.Flink
;
1245 Entry2
!= &List
->DiskListHead
;
1246 Entry2
= Entry2
->Flink
)
1248 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1250 if (DiskEntry2
->DiskStyle
== PARTITION_STYLE_GPT
)
1252 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1256 if (DiskEntry
!= DiskEntry2
&&
1257 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1261 if (Entry2
== &List
->DiskListHead
)
1268 UpdateDiskSignatures(
1272 PDISKENTRY DiskEntry
;
1274 /* Update each disk */
1275 for (Entry
= List
->DiskListHead
.Flink
;
1276 Entry
!= &List
->DiskListHead
;
1277 Entry
= Entry
->Flink
)
1279 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1281 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1283 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1287 if (DiskEntry
->LayoutBuffer
&&
1288 DiskEntry
->LayoutBuffer
->Signature
== 0)
1290 SetDiskSignature(List
, DiskEntry
);
1291 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1299 IN HANDLE FileHandle
,
1300 IN ULONG DiskNumber
,
1303 DISK_GEOMETRY DiskGeometry
;
1304 SCSI_ADDRESS ScsiAddress
;
1305 PDISKENTRY DiskEntry
;
1306 IO_STATUS_BLOCK Iosb
;
1308 PPARTITION_SECTOR Mbr
;
1310 LARGE_INTEGER FileOffset
;
1311 WCHAR Identifier
[20];
1315 PLIST_ENTRY ListEntry
;
1316 PBIOSDISKENTRY BiosDiskEntry
;
1317 ULONG LayoutBufferSize
;
1318 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1320 /* Retrieve the drive geometry */
1321 Status
= NtDeviceIoControlFile(FileHandle
,
1326 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1330 sizeof(DiskGeometry
));
1331 if (!NT_SUCCESS(Status
))
1334 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1335 DiskGeometry
.MediaType
!= RemovableMedia
)
1341 * FIXME: Here we suppose the disk is always SCSI. What if it is
1342 * of another type? To check this we need to retrieve the name of
1343 * the driver the disk device belongs to.
1345 Status
= NtDeviceIoControlFile(FileHandle
,
1350 IOCTL_SCSI_GET_ADDRESS
,
1354 sizeof(ScsiAddress
));
1355 if (!NT_SUCCESS(Status
))
1359 * Check whether the disk is initialized, by looking at its MBR.
1360 * NOTE that this must be generalized to GPT disks as well!
1363 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1365 DiskGeometry
.BytesPerSector
);
1369 FileOffset
.QuadPart
= 0;
1370 Status
= NtReadFile(FileHandle
,
1376 DiskGeometry
.BytesPerSector
,
1379 if (!NT_SUCCESS(Status
))
1381 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1382 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1385 Signature
= Mbr
->Signature
;
1387 /* Calculate the MBR checksum */
1389 Buffer
= (PULONG
)Mbr
;
1390 for (i
= 0; i
< 128; i
++)
1392 Checksum
+= Buffer
[i
];
1394 Checksum
= ~Checksum
+ 1;
1396 RtlStringCchPrintfW(Identifier
, ARRAYSIZE(Identifier
),
1397 L
"%08x-%08x-A", Checksum
, Signature
);
1398 DPRINT("Identifier: %S\n", Identifier
);
1400 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1403 if (DiskEntry
== NULL
)
1405 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1406 DPRINT1("Failed to allocate a new disk entry.\n");
1410 // DiskEntry->Checksum = Checksum;
1411 // DiskEntry->Signature = Signature;
1412 DiskEntry
->BiosFound
= FALSE
;
1415 * Check if this disk has a valid MBR: verify its signature,
1416 * and whether its two first bytes are a valid instruction
1417 * (related to this, see IsThereAValidBootSector() in partlist.c).
1419 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1422 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1424 /* If we have not the 0xAA55 then it's raw partition */
1425 if (Mbr
->Magic
!= PARTITION_MAGIC
)
1427 DiskEntry
->DiskStyle
= PARTITION_STYLE_RAW
;
1429 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1430 else if (Mbr
->Partition
[0].PartitionType
== EFI_PMBR_OSTYPE_EFI
&&
1431 Mbr
->Partition
[1].PartitionType
== 0 &&
1432 Mbr
->Partition
[2].PartitionType
== 0 &&
1433 Mbr
->Partition
[3].PartitionType
== 0)
1435 DiskEntry
->DiskStyle
= PARTITION_STYLE_GPT
;
1437 /* Otherwise, partition table is in MBR */
1440 DiskEntry
->DiskStyle
= PARTITION_STYLE_MBR
;
1443 /* Free the MBR sector buffer */
1444 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1447 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1448 ListEntry
!= &List
->BiosDiskListHead
;
1449 ListEntry
= ListEntry
->Flink
)
1451 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1453 * Compare the size from bios and the reported size from driver.
1454 * If we have more than one disk with a zero or with the same signature
1455 * we must create new signatures and reboot. After the reboot,
1456 * it is possible to identify the disks.
1458 if (BiosDiskEntry
->Signature
== Signature
&&
1459 BiosDiskEntry
->Checksum
== Checksum
&&
1460 !BiosDiskEntry
->Recognized
)
1462 if (!DiskEntry
->BiosFound
)
1464 DiskEntry
->BiosDiskNumber
= BiosDiskEntry
->DiskNumber
;
1465 DiskEntry
->BiosFound
= TRUE
;
1466 BiosDiskEntry
->Recognized
= TRUE
;
1470 // FIXME: What to do?
1475 if (!DiskEntry
->BiosFound
)
1478 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1481 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber
);
1485 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1486 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1488 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1489 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1490 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1491 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1493 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1494 DPRINT("TracksPerCylinder %lu\n", DiskEntry
->TracksPerCylinder
);
1495 DPRINT("SectorsPerTrack %lu\n", DiskEntry
->SectorsPerTrack
);
1496 DPRINT("BytesPerSector %lu\n", DiskEntry
->BytesPerSector
);
1498 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1499 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1500 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1502 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1503 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1504 DiskGeometry
.SectorsPerTrack
;
1506 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
.QuadPart
);
1507 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1509 DiskEntry
->DiskNumber
= DiskNumber
;
1510 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1511 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1512 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1514 GetDriverName(DiskEntry
);
1516 * Actually it would be more correct somehow to use:
1518 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1519 * ULONG ReturnedLength;
1521 * Status = NtQueryObject(SomeHandleToTheDisk,
1522 * ObjectNameInformation,
1528 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1531 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1535 * We now retrieve the disk partition layout
1539 * Stop there now if the disk is GPT-partitioned,
1540 * since we currently do not support such disks.
1542 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1544 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1548 /* Allocate a layout buffer with 4 partition entries first */
1549 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1550 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1551 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1554 if (DiskEntry
->LayoutBuffer
== NULL
)
1556 DPRINT1("Failed to allocate the disk layout buffer!\n");
1560 /* Keep looping while the drive layout buffer is too small */
1563 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1564 Status
= NtDeviceIoControlFile(FileHandle
,
1569 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1572 DiskEntry
->LayoutBuffer
,
1574 if (NT_SUCCESS(Status
))
1577 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1579 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1583 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1584 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1586 DiskEntry
->LayoutBuffer
,
1588 if (NewLayoutBuffer
== NULL
)
1590 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1594 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1597 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1599 #ifdef DUMP_PARTITION_TABLE
1600 DumpPartitionTable(DiskEntry
);
1603 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1604 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1605 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= PARTITION_ENTRY_UNUSED
)
1607 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1609 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1611 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1613 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1617 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1622 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1625 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1627 DiskEntry
->NewDisk
= TRUE
;
1628 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1630 for (i
= 0; i
< 4; i
++)
1632 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1637 /* Enumerate and add the first four primary partitions */
1638 for (i
= 0; i
< 4; i
++)
1640 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, FALSE
);
1643 /* Enumerate and add the remaining partitions as logical ones */
1644 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1646 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, TRUE
);
1650 ScanForUnpartitionedDiskSpace(DiskEntry
);
1654 CreatePartitionList(VOID
)
1657 OBJECT_ATTRIBUTES ObjectAttributes
;
1658 SYSTEM_DEVICE_INFORMATION Sdi
;
1659 IO_STATUS_BLOCK Iosb
;
1663 WCHAR Buffer
[MAX_PATH
];
1664 UNICODE_STRING Name
;
1667 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1673 List
->CurrentDisk
= NULL
;
1674 List
->CurrentPartition
= NULL
;
1676 List
->SystemPartition
= NULL
;
1677 List
->OriginalSystemPartition
= NULL
;
1679 InitializeListHead(&List
->DiskListHead
);
1680 InitializeListHead(&List
->BiosDiskListHead
);
1683 * Enumerate the disks seen by the BIOS; this will be used later
1684 * to map drives seen by NTOS with their corresponding BIOS names.
1686 EnumerateBiosDiskEntries(List
);
1688 /* Enumerate disks seen by NTOS */
1689 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1693 if (!NT_SUCCESS(Status
))
1695 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status
);
1696 RtlFreeHeap(ProcessHeap
, 0, List
);
1700 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1702 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
1703 L
"\\Device\\Harddisk%lu\\Partition0",
1705 RtlInitUnicodeString(&Name
, Buffer
);
1707 InitializeObjectAttributes(&ObjectAttributes
,
1709 OBJ_CASE_INSENSITIVE
,
1713 Status
= NtOpenFile(&FileHandle
,
1714 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1717 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1718 FILE_SYNCHRONOUS_IO_NONALERT
);
1719 if (NT_SUCCESS(Status
))
1721 AddDiskToList(FileHandle
, DiskNumber
, List
);
1722 NtClose(FileHandle
);
1726 UpdateDiskSignatures(List
);
1728 AssignDriveLetters(List
);
1730 /* Search for first usable disk and partition */
1731 if (IsListEmpty(&List
->DiskListHead
))
1733 List
->CurrentDisk
= NULL
;
1734 List
->CurrentPartition
= NULL
;
1738 List
->CurrentDisk
= CONTAINING_RECORD(List
->DiskListHead
.Flink
,
1742 if (IsListEmpty(&List
->CurrentDisk
->PrimaryPartListHead
))
1744 List
->CurrentPartition
= NULL
;
1748 List
->CurrentPartition
= CONTAINING_RECORD(List
->CurrentDisk
->PrimaryPartListHead
.Flink
,
1758 DestroyPartitionList(
1761 PDISKENTRY DiskEntry
;
1762 PBIOSDISKENTRY BiosDiskEntry
;
1763 PPARTENTRY PartEntry
;
1766 /* Release disk and partition info */
1767 while (!IsListEmpty(&List
->DiskListHead
))
1769 Entry
= RemoveHeadList(&List
->DiskListHead
);
1770 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1772 /* Release driver name */
1773 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1775 /* Release primary partition list */
1776 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1778 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1779 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1781 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1784 /* Release logical partition list */
1785 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1787 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1788 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1790 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1793 /* Release layout buffer */
1794 if (DiskEntry
->LayoutBuffer
!= NULL
)
1795 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1797 /* Release disk entry */
1798 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1801 /* Release the bios disk info */
1802 while (!IsListEmpty(&List
->BiosDiskListHead
))
1804 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1805 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1807 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
1810 /* Release list head */
1811 RtlFreeHeap(ProcessHeap
, 0, List
);
1815 GetDiskByBiosNumber(
1817 IN ULONG BiosDiskNumber
)
1819 PDISKENTRY DiskEntry
;
1822 /* Loop over the disks and find the correct one */
1823 for (Entry
= List
->DiskListHead
.Flink
;
1824 Entry
!= &List
->DiskListHead
;
1825 Entry
= Entry
->Flink
)
1827 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1829 if (DiskEntry
->BiosDiskNumber
== BiosDiskNumber
)
1836 /* Disk not found, stop there */
1843 IN ULONG DiskNumber
)
1845 PDISKENTRY DiskEntry
;
1848 /* Loop over the disks and find the correct one */
1849 for (Entry
= List
->DiskListHead
.Flink
;
1850 Entry
!= &List
->DiskListHead
;
1851 Entry
= Entry
->Flink
)
1853 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1855 if (DiskEntry
->DiskNumber
== DiskNumber
)
1862 /* Disk not found, stop there */
1873 PDISKENTRY DiskEntry
;
1876 /* Loop over the disks and find the correct one */
1877 for (Entry
= List
->DiskListHead
.Flink
;
1878 Entry
!= &List
->DiskListHead
;
1879 Entry
= Entry
->Flink
)
1881 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1883 if (DiskEntry
->Port
== Port
&&
1884 DiskEntry
->Bus
== Bus
&&
1885 DiskEntry
->Id
== Id
)
1892 /* Disk not found, stop there */
1901 PDISKENTRY DiskEntry
;
1904 /* Loop over the disks and find the correct one */
1905 for (Entry
= List
->DiskListHead
.Flink
;
1906 Entry
!= &List
->DiskListHead
;
1907 Entry
= Entry
->Flink
)
1909 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1911 if (DiskEntry
->LayoutBuffer
->Signature
== Signature
)
1918 /* Disk not found, stop there */
1924 // IN PPARTLIST List,
1925 IN PDISKENTRY DiskEntry
,
1926 IN ULONG PartitionNumber
)
1928 PPARTENTRY PartEntry
;
1931 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1933 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1937 /* Disk found, loop over the primary partitions first... */
1938 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1939 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1940 Entry
= Entry
->Flink
)
1942 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1944 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1946 /* Partition found */
1951 /* ... then over the logical partitions if needed */
1952 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1953 Entry
!= &DiskEntry
->LogicalPartListHead
;
1954 Entry
= Entry
->Flink
)
1956 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1958 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1960 /* Partition found */
1965 /* The partition was not found on the disk, stop there */
1972 IN ULONG DiskNumber
,
1973 IN ULONG PartitionNumber OPTIONAL
,
1974 OUT PDISKENTRY
* pDiskEntry
,
1975 OUT PPARTENTRY
* pPartEntry OPTIONAL
)
1977 PDISKENTRY DiskEntry
;
1978 PPARTENTRY PartEntry
= NULL
;
1981 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
1985 /* If we have a partition (PartitionNumber != 0), find it */
1986 if (PartitionNumber
!= 0)
1988 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1990 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1994 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
1997 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2000 /* Return the disk (and optionally the partition) */
2001 *pDiskEntry
= DiskEntry
;
2002 if (pPartEntry
) *pPartEntry
= PartEntry
;
2007 // NOTE: Was introduced broken in r6258 by Casper
2012 IN ULONG DiskNumber
,
2013 IN ULONG PartitionNumber
)
2015 PDISKENTRY DiskEntry
;
2016 PPARTENTRY PartEntry
;
2018 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
2022 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
2026 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2027 ASSERT(DiskEntry
->DiskNumber
== DiskNumber
);
2028 ASSERT(PartEntry
->PartitionNumber
== PartitionNumber
);
2030 List
->CurrentDisk
= DiskEntry
;
2031 List
->CurrentPartition
= PartEntry
;
2039 PLIST_ENTRY DiskListEntry
;
2040 PLIST_ENTRY PartListEntry
;
2041 PDISKENTRY DiskEntry
;
2042 PPARTENTRY PartEntry
;
2044 /* Fail if no disks are available */
2045 if (IsListEmpty(&List
->DiskListHead
))
2048 /* Check for next usable entry on current disk */
2049 if (List
->CurrentPartition
!= NULL
)
2051 if (List
->CurrentPartition
->LogicalPartition
)
2053 /* Logical partition */
2055 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2056 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2058 /* Next logical partition */
2059 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2061 List
->CurrentPartition
= PartEntry
;
2062 return List
->CurrentPartition
;
2066 PartListEntry
= List
->CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
2067 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2069 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2071 List
->CurrentPartition
= PartEntry
;
2072 return List
->CurrentPartition
;
2078 /* Primary or extended partition */
2080 if (List
->CurrentPartition
->IsPartitioned
&&
2081 IsContainerPartition(List
->CurrentPartition
->PartitionType
))
2083 /* First logical partition */
2084 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Flink
;
2085 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2087 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2089 List
->CurrentPartition
= PartEntry
;
2090 return List
->CurrentPartition
;
2095 /* Next primary partition */
2096 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2097 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2099 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2101 List
->CurrentPartition
= PartEntry
;
2102 return List
->CurrentPartition
;
2108 /* Search for the first partition entry on the next disk */
2109 for (DiskListEntry
= List
->CurrentDisk
->ListEntry
.Flink
;
2110 DiskListEntry
!= &List
->DiskListHead
;
2111 DiskListEntry
= DiskListEntry
->Flink
)
2113 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2115 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2117 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2121 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2122 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2124 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2126 List
->CurrentDisk
= DiskEntry
;
2127 List
->CurrentPartition
= PartEntry
;
2128 return List
->CurrentPartition
;
2139 PLIST_ENTRY DiskListEntry
;
2140 PLIST_ENTRY PartListEntry
;
2141 PDISKENTRY DiskEntry
;
2142 PPARTENTRY PartEntry
;
2144 /* Fail if no disks are available */
2145 if (IsListEmpty(&List
->DiskListHead
))
2148 /* Check for previous usable entry on current disk */
2149 if (List
->CurrentPartition
!= NULL
)
2151 if (List
->CurrentPartition
->LogicalPartition
)
2153 /* Logical partition */
2154 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2155 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2157 /* Previous logical partition */
2158 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2162 /* Extended partition */
2163 PartEntry
= List
->CurrentDisk
->ExtendedPartition
;
2166 List
->CurrentPartition
= PartEntry
;
2167 return List
->CurrentPartition
;
2171 /* Primary or extended partition */
2173 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2174 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2176 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2178 if (PartEntry
->IsPartitioned
&&
2179 IsContainerPartition(PartEntry
->PartitionType
))
2181 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Blink
;
2182 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2185 List
->CurrentPartition
= PartEntry
;
2186 return List
->CurrentPartition
;
2191 /* Search for the last partition entry on the previous disk */
2192 for (DiskListEntry
= List
->CurrentDisk
->ListEntry
.Blink
;
2193 DiskListEntry
!= &List
->DiskListHead
;
2194 DiskListEntry
= DiskListEntry
->Blink
)
2196 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2198 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2200 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2204 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Blink
;
2205 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2207 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2209 if (PartEntry
->IsPartitioned
&&
2210 IsContainerPartition(PartEntry
->PartitionType
))
2212 PartListEntry
= DiskEntry
->LogicalPartListHead
.Blink
;
2213 if (PartListEntry
!= &DiskEntry
->LogicalPartListHead
)
2215 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2217 List
->CurrentDisk
= DiskEntry
;
2218 List
->CurrentPartition
= PartEntry
;
2219 return List
->CurrentPartition
;
2224 List
->CurrentDisk
= DiskEntry
;
2225 List
->CurrentPartition
= PartEntry
;
2226 return List
->CurrentPartition
;
2238 IN PPARTITION_INFORMATION PartitionInfo
)
2240 if (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2241 PartitionInfo
->PartitionLength
.QuadPart
== 0)
2252 IsSamePrimaryLayoutEntry(
2253 IN PPARTITION_INFORMATION PartitionInfo
,
2254 IN PDISKENTRY DiskEntry
,
2255 IN PPARTENTRY PartEntry
)
2257 if (PartitionInfo
->StartingOffset
.QuadPart
== PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
&&
2258 PartitionInfo
->PartitionLength
.QuadPart
== PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
)
2259 // PartitionInfo->PartitionType == PartEntry->PartitionType
2269 GetPrimaryPartitionCount(
2270 IN PDISKENTRY DiskEntry
)
2273 PPARTENTRY PartEntry
;
2276 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2278 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2282 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2283 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2284 Entry
= Entry
->Flink
)
2286 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2287 if (PartEntry
->IsPartitioned
)
2296 GetLogicalPartitionCount(
2297 IN PDISKENTRY DiskEntry
)
2299 PLIST_ENTRY ListEntry
;
2300 PPARTENTRY PartEntry
;
2303 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2305 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2309 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2310 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2311 ListEntry
= ListEntry
->Flink
)
2313 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2314 if (PartEntry
->IsPartitioned
)
2323 ReAllocateLayoutBuffer(
2324 IN PDISKENTRY DiskEntry
)
2326 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2327 ULONG NewPartitionCount
;
2328 ULONG CurrentPartitionCount
= 0;
2329 ULONG LayoutBufferSize
;
2332 DPRINT1("ReAllocateLayoutBuffer()\n");
2334 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2336 if (DiskEntry
->LayoutBuffer
)
2337 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2339 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2340 CurrentPartitionCount
, NewPartitionCount
);
2342 if (CurrentPartitionCount
== NewPartitionCount
)
2345 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2346 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2347 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2349 DiskEntry
->LayoutBuffer
,
2351 if (NewLayoutBuffer
== NULL
)
2353 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2357 NewLayoutBuffer
->PartitionCount
= NewPartitionCount
;
2359 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2360 if (NewPartitionCount
> CurrentPartitionCount
)
2362 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2364 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2368 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2376 IN PDISKENTRY DiskEntry
)
2378 PPARTITION_INFORMATION PartitionInfo
;
2379 PPARTITION_INFORMATION LinkInfo
= NULL
;
2380 PLIST_ENTRY ListEntry
;
2381 PPARTENTRY PartEntry
;
2382 LARGE_INTEGER HiddenSectors64
;
2384 ULONG PartitionNumber
= 1;
2386 DPRINT1("UpdateDiskLayout()\n");
2388 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2390 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2394 /* Resize the layout buffer if necessary */
2395 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2397 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2401 /* Update the primary partition table */
2403 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2404 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
2405 ListEntry
= ListEntry
->Flink
)
2407 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2409 if (PartEntry
->IsPartitioned
)
2411 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2413 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2414 PartEntry
->PartitionIndex
= Index
;
2416 /* Reset the current partition number only for newly-created (unmounted) partitions */
2418 PartEntry
->PartitionNumber
= 0;
2420 PartEntry
->OnDiskPartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
) ? PartitionNumber
: 0);
2422 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, DiskEntry
, PartEntry
))
2424 DPRINT1("Updating primary partition entry %lu\n", Index
);
2426 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2427 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2428 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2429 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2430 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2431 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2432 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2433 PartitionInfo
->RewritePartition
= TRUE
;
2436 if (!IsContainerPartition(PartEntry
->PartitionType
))
2445 /* Update the logical partition table */
2447 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2448 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2449 ListEntry
= ListEntry
->Flink
)
2451 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2453 if (PartEntry
->IsPartitioned
)
2455 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2457 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2458 PartEntry
->PartitionIndex
= Index
;
2460 /* Reset the current partition number only for newly-created (unmounted) partitions */
2462 PartEntry
->PartitionNumber
= 0;
2464 PartEntry
->OnDiskPartitionNumber
= PartitionNumber
;
2466 DPRINT1("Updating logical partition entry %lu\n", Index
);
2468 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2469 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2470 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2471 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2472 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2473 PartitionInfo
->BootIndicator
= FALSE
;
2474 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2475 PartitionInfo
->RewritePartition
= TRUE
;
2477 /* Fill the link entry of the previous partition entry */
2478 if (LinkInfo
!= NULL
)
2480 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2481 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2482 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2483 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2484 LinkInfo
->PartitionNumber
= 0;
2485 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2486 LinkInfo
->BootIndicator
= FALSE
;
2487 LinkInfo
->RecognizedPartition
= FALSE
;
2488 LinkInfo
->RewritePartition
= TRUE
;
2491 /* Save a pointer to the link entry of the current partition entry */
2492 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2499 /* Wipe unused primary partition entries */
2500 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2502 DPRINT1("Primary partition entry %lu\n", Index
);
2504 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2506 if (!IsEmptyLayoutEntry(PartitionInfo
))
2508 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2510 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2511 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2512 PartitionInfo
->HiddenSectors
= 0;
2513 PartitionInfo
->PartitionNumber
= 0;
2514 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2515 PartitionInfo
->BootIndicator
= FALSE
;
2516 PartitionInfo
->RecognizedPartition
= FALSE
;
2517 PartitionInfo
->RewritePartition
= TRUE
;
2521 /* Wipe unused logical partition entries */
2522 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2526 DPRINT1("Logical partition entry %lu\n", Index
);
2528 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2530 if (!IsEmptyLayoutEntry(PartitionInfo
))
2532 DPRINT1("Wiping partition entry %lu\n", Index
);
2534 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2535 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2536 PartitionInfo
->HiddenSectors
= 0;
2537 PartitionInfo
->PartitionNumber
= 0;
2538 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2539 PartitionInfo
->BootIndicator
= FALSE
;
2540 PartitionInfo
->RecognizedPartition
= FALSE
;
2541 PartitionInfo
->RewritePartition
= TRUE
;
2546 DiskEntry
->Dirty
= TRUE
;
2548 #ifdef DUMP_PARTITION_TABLE
2549 DumpPartitionTable(DiskEntry
);
2555 GetPrevUnpartitionedEntry(
2556 IN PDISKENTRY DiskEntry
,
2557 IN PPARTENTRY PartEntry
)
2559 PPARTENTRY PrevPartEntry
;
2560 PLIST_ENTRY ListHead
;
2562 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2564 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2568 if (PartEntry
->LogicalPartition
)
2569 ListHead
= &DiskEntry
->LogicalPartListHead
;
2571 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2573 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2575 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2578 if (PrevPartEntry
->IsPartitioned
== FALSE
)
2580 ASSERT(PrevPartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
2581 return PrevPartEntry
;
2590 GetNextUnpartitionedEntry(
2591 IN PDISKENTRY DiskEntry
,
2592 IN PPARTENTRY PartEntry
)
2594 PPARTENTRY NextPartEntry
;
2595 PLIST_ENTRY ListHead
;
2597 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2599 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2603 if (PartEntry
->LogicalPartition
)
2604 ListHead
= &DiskEntry
->LogicalPartListHead
;
2606 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2608 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2610 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2613 if (NextPartEntry
->IsPartitioned
== FALSE
)
2615 ASSERT(NextPartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
2616 return NextPartEntry
;
2624 CreatePrimaryPartition(
2626 IN PPARTENTRY SelectedEntry
,
2627 IN ULONGLONG SectorCount
,
2628 IN BOOLEAN AutoCreate
)
2631 PPARTENTRY PartEntry
;
2633 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount
);
2636 SelectedEntry
== NULL
||
2637 SelectedEntry
->DiskEntry
== NULL
||
2638 SelectedEntry
->IsPartitioned
)
2643 Error
= PrimaryPartitionCreationChecks(SelectedEntry
);
2644 if (Error
!= NOT_AN_ERROR
)
2646 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error
);
2650 /* Convert the current entry, or insert and initialize a new partition entry */
2651 PartEntry
= InitializePartitionEntry(SelectedEntry
->DiskEntry
, SelectedEntry
, SectorCount
, AutoCreate
);
2652 if (PartEntry
== NULL
)
2655 UpdateDiskLayout(PartEntry
->DiskEntry
);
2657 AssignDriveLetters(List
);
2664 AddLogicalDiskSpace(
2665 IN PDISKENTRY DiskEntry
)
2667 ULONGLONG StartSector
;
2668 ULONGLONG SectorCount
;
2669 PPARTENTRY NewPartEntry
;
2671 DPRINT1("AddLogicalDiskSpace()\n");
2673 /* Create a partition entry that represents the empty space in the container partition */
2675 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2676 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2678 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
2679 &DiskEntry
->LogicalPartListHead
,
2683 if (NewPartEntry
== NULL
)
2685 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2688 NewPartEntry
->LogicalPartition
= TRUE
;
2692 CreateExtendedPartition(
2694 IN PPARTENTRY SelectedEntry
,
2695 IN ULONGLONG SectorCount
)
2698 PPARTENTRY PartEntry
;
2700 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount
);
2703 SelectedEntry
== NULL
||
2704 SelectedEntry
->DiskEntry
== NULL
||
2705 SelectedEntry
->IsPartitioned
)
2710 Error
= ExtendedPartitionCreationChecks(SelectedEntry
);
2711 if (Error
!= NOT_AN_ERROR
)
2713 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error
);
2717 /* Convert the current entry, or insert and initialize a new partition entry */
2718 PartEntry
= InitializePartitionEntry(SelectedEntry
->DiskEntry
, SelectedEntry
, SectorCount
, FALSE
);
2719 if (PartEntry
== NULL
)
2722 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2724 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2725 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2729 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2730 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2733 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2734 PartEntry
->New
= FALSE
;
2735 PartEntry
->FormatState
= Formatted
;
2737 PartEntry
->DiskEntry
->ExtendedPartition
= PartEntry
;
2739 AddLogicalDiskSpace(PartEntry
->DiskEntry
);
2741 UpdateDiskLayout(PartEntry
->DiskEntry
);
2743 AssignDriveLetters(List
);
2749 CreateLogicalPartition(
2751 IN PPARTENTRY SelectedEntry
,
2752 IN ULONGLONG SectorCount
,
2753 IN BOOLEAN AutoCreate
)
2756 PPARTENTRY PartEntry
;
2758 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount
);
2761 SelectedEntry
== NULL
||
2762 SelectedEntry
->DiskEntry
== NULL
||
2763 SelectedEntry
->IsPartitioned
)
2768 Error
= LogicalPartitionCreationChecks(SelectedEntry
);
2769 if (Error
!= NOT_AN_ERROR
)
2771 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error
);
2775 /* Convert the current entry, or insert and initialize a new partition entry */
2776 PartEntry
= InitializePartitionEntry(SelectedEntry
->DiskEntry
, SelectedEntry
, SectorCount
, AutoCreate
);
2777 if (PartEntry
== NULL
)
2780 PartEntry
->LogicalPartition
= TRUE
;
2782 UpdateDiskLayout(PartEntry
->DiskEntry
);
2784 AssignDriveLetters(List
);
2792 IN PPARTENTRY PartEntry
)
2795 NTSTATUS LockStatus
;
2796 UNICODE_STRING Name
;
2797 OBJECT_ATTRIBUTES ObjectAttributes
;
2798 IO_STATUS_BLOCK IoStatusBlock
;
2799 HANDLE PartitionHandle
;
2800 WCHAR Buffer
[MAX_PATH
];
2802 /* Check whether the partition is valid and was mounted by the system */
2803 if (!PartEntry
->IsPartitioned
||
2804 IsContainerPartition(PartEntry
->PartitionType
) ||
2805 !IsRecognizedPartition(PartEntry
->PartitionType
) ||
2806 PartEntry
->FormatState
== Unformatted
/* || PartEntry->FormatState == UnknownFormat */ ||
2807 !*PartEntry
->FileSystem
||
2808 PartEntry
->PartitionNumber
== 0)
2810 /* The partition is not mounted, so just return success */
2811 return STATUS_SUCCESS
;
2814 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2816 /* Open the volume */
2817 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
2818 L
"\\Device\\Harddisk%lu\\Partition%lu",
2819 PartEntry
->DiskEntry
->DiskNumber
,
2820 PartEntry
->PartitionNumber
);
2821 RtlInitUnicodeString(&Name
, Buffer
);
2823 InitializeObjectAttributes(&ObjectAttributes
,
2825 OBJ_CASE_INSENSITIVE
,
2829 Status
= NtOpenFile(&PartitionHandle
,
2830 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
2833 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2834 FILE_SYNCHRONOUS_IO_NONALERT
);
2835 if (!NT_SUCCESS(Status
))
2837 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name
, Status
);
2841 /* Lock the volume */
2842 LockStatus
= NtFsControlFile(PartitionHandle
,
2852 if (!NT_SUCCESS(LockStatus
))
2854 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus
);
2857 /* Dismount the volume */
2858 Status
= NtFsControlFile(PartitionHandle
,
2863 FSCTL_DISMOUNT_VOLUME
,
2868 if (!NT_SUCCESS(Status
))
2870 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status
);
2873 /* Unlock the volume */
2874 LockStatus
= NtFsControlFile(PartitionHandle
,
2879 FSCTL_UNLOCK_VOLUME
,
2884 if (!NT_SUCCESS(LockStatus
))
2886 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus
);
2889 /* Close the volume */
2890 NtClose(PartitionHandle
);
2898 IN PPARTENTRY PartEntry
)
2900 PDISKENTRY DiskEntry
;
2901 PPARTENTRY PrevPartEntry
;
2902 PPARTENTRY NextPartEntry
;
2903 PPARTENTRY LogicalPartEntry
;
2907 PartEntry
== NULL
||
2908 PartEntry
->DiskEntry
== NULL
||
2909 PartEntry
->IsPartitioned
== FALSE
)
2914 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2916 /* Clear the system partition pointers if it is being deleted */
2917 if (List
->SystemPartition
== PartEntry
)
2919 ASSERT(List
->SystemPartition
);
2921 if (List
->SystemPartition
== List
->OriginalSystemPartition
)
2922 List
->OriginalSystemPartition
= NULL
;
2923 List
->SystemPartition
= NULL
;
2926 DiskEntry
= PartEntry
->DiskEntry
;
2928 /* Check which type of partition (primary/logical or extended) is being deleted */
2929 if (DiskEntry
->ExtendedPartition
== PartEntry
)
2931 /* An extended partition is being deleted: delete all logical partition entries */
2932 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
2934 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
2935 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2937 /* Dismount the logical partition */
2938 DismountVolume(LogicalPartEntry
);
2941 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
2944 DiskEntry
->ExtendedPartition
= NULL
;
2948 /* A primary partition is being deleted: dismount it */
2949 DismountVolume(PartEntry
);
2952 /* Adjust unpartitioned disk space entries */
2954 /* Get pointer to previous and next unpartitioned entries */
2955 PrevPartEntry
= GetPrevUnpartitionedEntry(DiskEntry
, PartEntry
);
2956 NextPartEntry
= GetNextUnpartitionedEntry(DiskEntry
, PartEntry
);
2958 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
2960 /* Merge previous, current and next unpartitioned entry */
2962 /* Adjust the previous entries length */
2963 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
2965 /* Remove the current entry */
2966 RemoveEntryList(&PartEntry
->ListEntry
);
2967 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2969 /* Remove the next entry */
2970 RemoveEntryList(&NextPartEntry
->ListEntry
);
2971 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
2973 /* Update current partition */
2974 if (List
->CurrentPartition
== PartEntry
||
2975 List
->CurrentPartition
== NextPartEntry
)
2977 List
->CurrentPartition
= PrevPartEntry
;
2980 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
2982 /* Merge current and previous unpartitioned entry */
2984 /* Adjust the previous entries length */
2985 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2987 /* Remove the current entry */
2988 RemoveEntryList(&PartEntry
->ListEntry
);
2989 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2991 /* Update current partition */
2992 if (List
->CurrentPartition
== PartEntry
)
2994 List
->CurrentPartition
= PrevPartEntry
;
2997 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
2999 /* Merge current and next unpartitioned entry */
3001 /* Adjust the next entries offset and length */
3002 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
3003 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3005 /* Remove the current entry */
3006 RemoveEntryList(&PartEntry
->ListEntry
);
3007 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3009 /* Update current partition */
3010 if (List
->CurrentPartition
== PartEntry
)
3012 List
->CurrentPartition
= NextPartEntry
;
3017 /* Nothing to merge but change current entry */
3018 PartEntry
->IsPartitioned
= FALSE
;
3019 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
3020 PartEntry
->FormatState
= Unformatted
;
3021 PartEntry
->FileSystem
[0] = L
'\0';
3022 PartEntry
->DriveLetter
= 0;
3023 PartEntry
->OnDiskPartitionNumber
= 0;
3024 PartEntry
->PartitionNumber
= 0;
3025 // PartEntry->PartitionIndex = 0;
3028 UpdateDiskLayout(DiskEntry
);
3030 AssignDriveLetters(List
);
3034 DeleteCurrentPartition(
3037 DeletePartition(List
, List
->CurrentPartition
);
3042 IsSupportedActivePartition(
3043 IN PPARTENTRY PartEntry
)
3045 /* Check the type and the filesystem of this partition */
3048 * We do not support extended partition containers (on MBR disks) marked
3049 * as active, and containing code inside their extended boot records.
3051 if (IsContainerPartition(PartEntry
->PartitionType
))
3053 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3054 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3059 * ADDITIONAL CHECKS / BIG HACK:
3061 * Retrieve its file system and check whether we have
3062 * write support for it. If that is the case we are fine
3063 * and we can use it directly. However if we don't have
3064 * write support we will need to change the active system
3067 * NOTE that this is completely useless on architectures
3068 * where a real system partition is required, as on these
3069 * architectures the partition uses the FAT FS, for which
3070 * we do have write support.
3071 * NOTE also that for those architectures looking for a
3072 * partition boot indicator is insufficient.
3074 if ((PartEntry
->FormatState
== Unformatted
) ||
3075 (PartEntry
->FormatState
== Preformatted
) ||
3076 (PartEntry
->FormatState
== Formatted
))
3078 ASSERT(*PartEntry
->FileSystem
);
3080 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3081 if (wcsicmp(PartEntry
->FileSystem
, L
"FAT") == 0 ||
3082 wcsicmp(PartEntry
->FileSystem
, L
"FAT32") == 0 ||
3083 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3084 wcsicmp(PartEntry
->FileSystem
, L
"BTRFS") == 0 ||
3085 wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
3091 // WARNING: We cannot write on this FS yet!
3092 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3093 PartEntry
->FileSystem
);
3097 else // if (PartEntry->FormatState == UnknownFormat)
3099 ASSERT(!*PartEntry
->FileSystem
);
3101 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3102 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3106 // HACK: WARNING: We cannot write on this FS yet!
3107 // See fsutil.c:InferFileSystem()
3108 if (PartEntry
->PartitionType
== PARTITION_IFS
)
3110 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3111 PartEntry
->FileSystem
);
3119 CheckActiveSystemPartition(
3122 PDISKENTRY DiskEntry
;
3123 PPARTENTRY PartEntry
;
3124 PLIST_ENTRY ListEntry
;
3126 /* Check for empty disk list */
3127 if (IsListEmpty(&List
->DiskListHead
))
3129 List
->SystemPartition
= NULL
;
3130 List
->OriginalSystemPartition
= NULL
;
3134 /* Choose the currently selected disk */
3135 DiskEntry
= List
->CurrentDisk
;
3137 /* Check for empty partition list */
3138 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
3140 List
->SystemPartition
= NULL
;
3141 List
->OriginalSystemPartition
= NULL
;
3145 if (List
->SystemPartition
!= NULL
)
3147 /* We already have an active system partition */
3148 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3149 List
->SystemPartition
->PartitionNumber
,
3150 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3151 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3155 DPRINT("We are here (1)!\n");
3157 List
->SystemPartition
= NULL
;
3158 List
->OriginalSystemPartition
= NULL
;
3160 /* Retrieve the first partition of the disk */
3161 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
3164 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3165 List
->SystemPartition
= PartEntry
;
3168 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3171 /* Check if the disk is new and if so, use its first partition as the active system partition */
3172 if (DiskEntry
->NewDisk
)
3174 if (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
== FALSE
)
3176 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3177 List
->SystemPartition
= PartEntry
;
3179 List
->OriginalSystemPartition
= List
->SystemPartition
;
3181 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3182 List
->SystemPartition
->PartitionNumber
,
3183 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3184 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3186 goto SetSystemPartition
;
3189 // FIXME: What to do??
3190 DPRINT1("NewDisk TRUE but first partition is used?\n");
3193 DPRINT("We are here (2)!\n");
3196 * The disk is not new, check if any partition is initialized;
3197 * if not, the first one becomes the system partition.
3199 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3200 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3201 ListEntry
= ListEntry
->Flink
)
3203 /* Retrieve the partition */
3204 PartEntry
= CONTAINING_RECORD(ListEntry
,
3208 /* Check if the partition is partitioned and is used */
3209 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
!= FALSE
)
3214 if (ListEntry
== &DiskEntry
->PrimaryPartListHead
)
3217 * OK we haven't encountered any used and active partition,
3218 * so use the first one as the system partition.
3220 ASSERT(DiskEntry
== List
->SystemPartition
->DiskEntry
);
3221 List
->OriginalSystemPartition
= List
->SystemPartition
; // First PartEntry
3223 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3224 List
->SystemPartition
->PartitionNumber
,
3225 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3226 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3228 goto SetSystemPartition
;
3231 List
->SystemPartition
= NULL
;
3232 List
->OriginalSystemPartition
= NULL
;
3234 DPRINT("We are here (3)!\n");
3236 /* The disk is not new, scan all partitions to find the (active) system partition */
3237 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3238 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3239 ListEntry
= ListEntry
->Flink
)
3241 /* Retrieve the partition */
3242 PartEntry
= CONTAINING_RECORD(ListEntry
,
3246 /* Check if the partition is partitioned and used */
3247 if (PartEntry
->IsPartitioned
&&
3248 PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
)
3250 /* Check if the partition is active */
3251 if (PartEntry
->BootIndicator
)
3253 /* Yes, we found it */
3254 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3255 List
->SystemPartition
= PartEntry
;
3257 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3258 PartEntry
->PartitionNumber
,
3259 DiskEntry
->DiskNumber
,
3260 (PartEntry
->DriveLetter
== 0) ? L
'-' : PartEntry
->DriveLetter
);
3266 /* Check if we have found the system partition */
3267 if (List
->SystemPartition
== NULL
)
3269 /* Nothing, use the alternative system partition */
3270 DPRINT1("No system partition found, use the alternative partition!\n");
3271 goto UseAlternativeSystemPartition
;
3275 List
->OriginalSystemPartition
= List
->SystemPartition
;
3277 /* If we get a candidate active partition, validate it */
3278 if (!IsSupportedActivePartition(List
->OriginalSystemPartition
))
3280 goto FindAndUseAlternativeSystemPartition
;
3283 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3284 List
->SystemPartition
->PartitionNumber
,
3285 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3286 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3290 FindAndUseAlternativeSystemPartition
:
3292 * We are here because we have not found any (active) candidate
3293 * system partition that we know how to support. What we are going
3294 * to do is to change the existing system partition and use the
3295 * partition on which we install ReactOS as the new system partition,
3296 * and then we will need to add in FreeLdr's entry a boot entry to boot
3297 * from the original system partition.
3300 /* Unset the old system partition */
3301 List
->SystemPartition
->BootIndicator
= FALSE
;
3302 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= FALSE
;
3303 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3304 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3306 UseAlternativeSystemPartition
:
3307 List
->SystemPartition
= List
->CurrentPartition
;
3309 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3310 List
->SystemPartition
->PartitionNumber
,
3311 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3312 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3315 /* Set the new active system partition */
3316 List
->SystemPartition
->BootIndicator
= TRUE
;
3317 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= TRUE
;
3318 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3319 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3324 IN PDISKENTRY DiskEntry
)
3327 OBJECT_ATTRIBUTES ObjectAttributes
;
3328 UNICODE_STRING Name
;
3330 IO_STATUS_BLOCK Iosb
;
3332 PPARTITION_INFORMATION PartitionInfo
;
3333 ULONG PartitionCount
;
3334 PLIST_ENTRY ListEntry
;
3335 PPARTENTRY PartEntry
;
3336 WCHAR DstPath
[MAX_PATH
];
3338 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3340 /* If the disk is not dirty, there is nothing to do */
3341 if (!DiskEntry
->Dirty
)
3342 return STATUS_SUCCESS
;
3344 RtlStringCchPrintfW(DstPath
, ARRAYSIZE(DstPath
),
3345 L
"\\Device\\Harddisk%lu\\Partition0",
3346 DiskEntry
->DiskNumber
);
3347 RtlInitUnicodeString(&Name
, DstPath
);
3349 InitializeObjectAttributes(&ObjectAttributes
,
3351 OBJ_CASE_INSENSITIVE
,
3355 Status
= NtOpenFile(&FileHandle
,
3356 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3360 FILE_SYNCHRONOUS_IO_NONALERT
);
3361 if (!NT_SUCCESS(Status
))
3363 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3367 #ifdef DUMP_PARTITION_TABLE
3368 DumpPartitionTable(DiskEntry
);
3372 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3373 // the disk in MBR or GPT format in case the disk was not initialized!!
3374 // For this we must ask the user which format to use.
3377 /* Save the original partition count to be restored later (see comment below) */
3378 PartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
3380 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3381 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3382 ((PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3383 Status
= NtDeviceIoControlFile(FileHandle
,
3388 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3389 DiskEntry
->LayoutBuffer
,
3391 DiskEntry
->LayoutBuffer
,
3393 NtClose(FileHandle
);
3396 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3397 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3398 * where such a table is expected to enumerate up to 4 partitions:
3399 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3400 * Due to this we need to restore the original PartitionCount number.
3402 DiskEntry
->LayoutBuffer
->PartitionCount
= PartitionCount
;
3404 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3405 if (!NT_SUCCESS(Status
))
3407 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3411 #ifdef DUMP_PARTITION_TABLE
3412 DumpPartitionTable(DiskEntry
);
3415 /* Update the partition numbers */
3417 /* Update the primary partition table */
3418 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3419 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3420 ListEntry
= ListEntry
->Flink
)
3422 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3424 if (PartEntry
->IsPartitioned
)
3426 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3427 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3428 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3432 /* Update the logical partition table */
3433 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
3434 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
3435 ListEntry
= ListEntry
->Flink
)
3437 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3439 if (PartEntry
->IsPartitioned
)
3441 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3442 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3443 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3448 // NOTE: Originally (see r40437), we used to install here also a new MBR
3449 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3450 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3451 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3452 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3453 // was called too, the installation test was modified by checking whether
3454 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3457 /* The layout has been successfully updated, the disk is not dirty anymore */
3458 DiskEntry
->Dirty
= FALSE
;
3464 WritePartitionsToDisk(
3469 PDISKENTRY DiskEntry
;
3474 for (Entry
= List
->DiskListHead
.Flink
;
3475 Entry
!= &List
->DiskListHead
;
3476 Entry
= Entry
->Flink
)
3478 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3480 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3482 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3486 if (DiskEntry
->Dirty
!= FALSE
)
3488 Status
= WritePartitions(DiskEntry
);
3489 if (!NT_SUCCESS(Status
))
3491 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
3492 DiskEntry
->DiskNumber
, Status
);
3501 SetMountedDeviceValue(
3504 IN LARGE_INTEGER StartingOffset
)
3506 OBJECT_ATTRIBUTES ObjectAttributes
;
3507 WCHAR ValueNameBuffer
[16];
3508 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3509 UNICODE_STRING ValueName
;
3510 REG_DISK_MOUNT_INFO MountInfo
;
3514 RtlStringCchPrintfW(ValueNameBuffer
, ARRAYSIZE(ValueNameBuffer
),
3515 L
"\\DosDevices\\%c:", Letter
);
3516 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
3518 InitializeObjectAttributes(&ObjectAttributes
,
3520 OBJ_CASE_INSENSITIVE
,
3524 Status
= NtOpenKey(&KeyHandle
,
3527 if (!NT_SUCCESS(Status
))
3529 Status
= NtCreateKey(&KeyHandle
,
3534 REG_OPTION_NON_VOLATILE
,
3538 if (!NT_SUCCESS(Status
))
3540 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
3544 MountInfo
.Signature
= Signature
;
3545 MountInfo
.StartingOffset
= StartingOffset
;
3546 Status
= NtSetValueKey(KeyHandle
,
3553 if (!NT_SUCCESS(Status
))
3555 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
3563 SetMountedDeviceValues(
3566 PLIST_ENTRY Entry1
, Entry2
;
3567 PDISKENTRY DiskEntry
;
3568 PPARTENTRY PartEntry
;
3569 LARGE_INTEGER StartingOffset
;
3574 for (Entry1
= List
->DiskListHead
.Flink
;
3575 Entry1
!= &List
->DiskListHead
;
3576 Entry1
= Entry1
->Flink
)
3578 DiskEntry
= CONTAINING_RECORD(Entry1
,
3582 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3584 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3588 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3589 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3590 Entry2
= Entry2
->Flink
)
3592 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3593 if (PartEntry
->IsPartitioned
) // && !IsContainerPartition(PartEntry->PartitionType)
3595 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3597 /* Assign a "\DosDevices\#:" mount point to this partition */
3598 if (PartEntry
->DriveLetter
)
3600 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3601 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3602 DiskEntry
->LayoutBuffer
->Signature
,
3611 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3612 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3613 Entry2
= Entry2
->Flink
)
3615 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3616 if (PartEntry
->IsPartitioned
) // && !IsContainerPartition(PartEntry->PartitionType)
3618 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3620 /* Assign a "\DosDevices\#:" mount point to this partition */
3621 if (PartEntry
->DriveLetter
)
3623 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3624 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3625 DiskEntry
->LayoutBuffer
->Signature
,
3640 IN PPARTENTRY PartEntry
,
3641 IN UCHAR PartitionType
)
3643 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3645 PartEntry
->PartitionType
= PartitionType
;
3647 DiskEntry
->Dirty
= TRUE
;
3648 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].PartitionType
= PartitionType
;
3649 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RecognizedPartition
= IsRecognizedPartition(PartitionType
);
3650 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3654 PrimaryPartitionCreationChecks(
3655 IN PPARTENTRY PartEntry
)
3657 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3659 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3661 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3662 return ERROR_WARN_PARTITION
;
3665 /* Fail if the partition is already in use */
3666 if (PartEntry
->IsPartitioned
)
3667 return ERROR_NEW_PARTITION
;
3669 /* Fail if there are already 4 primary partitions in the list */
3670 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3671 return ERROR_PARTITION_TABLE_FULL
;
3673 return ERROR_SUCCESS
;
3677 ExtendedPartitionCreationChecks(
3678 IN PPARTENTRY PartEntry
)
3680 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3682 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3684 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3685 return ERROR_WARN_PARTITION
;
3688 /* Fail if the partition is already in use */
3689 if (PartEntry
->IsPartitioned
)
3690 return ERROR_NEW_PARTITION
;
3692 /* Fail if there are already 4 primary partitions in the list */
3693 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3694 return ERROR_PARTITION_TABLE_FULL
;
3696 /* Fail if there is another extended partition in the list */
3697 if (DiskEntry
->ExtendedPartition
!= NULL
)
3698 return ERROR_ONLY_ONE_EXTENDED
;
3700 return ERROR_SUCCESS
;
3704 LogicalPartitionCreationChecks(
3705 IN PPARTENTRY PartEntry
)
3707 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3709 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3711 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3712 return ERROR_WARN_PARTITION
;
3715 /* Fail if the partition is already in use */
3716 if (PartEntry
->IsPartitioned
)
3717 return ERROR_NEW_PARTITION
;
3719 return ERROR_SUCCESS
;
3723 GetNextUnformattedPartition(
3725 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3726 OUT PPARTENTRY
*pPartEntry
)
3728 PLIST_ENTRY Entry1
, Entry2
;
3729 PDISKENTRY DiskEntry
;
3730 PPARTENTRY PartEntry
;
3732 for (Entry1
= List
->DiskListHead
.Flink
;
3733 Entry1
!= &List
->DiskListHead
;
3734 Entry1
= Entry1
->Flink
)
3736 DiskEntry
= CONTAINING_RECORD(Entry1
,
3740 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3742 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3746 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3747 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3748 Entry2
= Entry2
->Flink
)
3750 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3751 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3753 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3754 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3755 *pPartEntry
= PartEntry
;
3760 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3761 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3762 Entry2
= Entry2
->Flink
)
3764 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3765 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3767 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3768 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3769 *pPartEntry
= PartEntry
;
3775 if (pDiskEntry
) *pDiskEntry
= NULL
;
3782 GetNextUncheckedPartition(
3784 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3785 OUT PPARTENTRY
*pPartEntry
)
3787 PLIST_ENTRY Entry1
, Entry2
;
3788 PDISKENTRY DiskEntry
;
3789 PPARTENTRY PartEntry
;
3791 for (Entry1
= List
->DiskListHead
.Flink
;
3792 Entry1
!= &List
->DiskListHead
;
3793 Entry1
= Entry1
->Flink
)
3795 DiskEntry
= CONTAINING_RECORD(Entry1
,
3799 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3801 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3805 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3806 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3807 Entry2
= Entry2
->Flink
)
3809 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3810 if (PartEntry
->IsPartitioned
&& PartEntry
->NeedsCheck
)
3812 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3813 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3814 *pPartEntry
= PartEntry
;
3819 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3820 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3821 Entry2
= Entry2
->Flink
)
3823 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3824 if (PartEntry
->IsPartitioned
&& PartEntry
->NeedsCheck
)
3826 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3827 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3828 *pPartEntry
= PartEntry
;
3834 if (pDiskEntry
) *pDiskEntry
= NULL
;