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-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
17 //#define DUMP_PARTITION_TABLE
21 typedef struct _REG_DISK_MOUNT_INFO
24 LARGE_INTEGER StartingOffset
;
25 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
30 /* HELPERS FOR PARTITION TYPES **********************************************/
33 * This partition type list was ripped from the kernelDisk.c module of
34 * the Visopsys Operating System (see license below), and completed with
35 * information from Paragon Hard-Disk Manager, and the following websites:
36 * http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
37 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
42 * Visopsys Operating System
43 * Copyright (C) 1998-2015 J. Andrew McLaughlin
45 * This program is free software; you can redistribute it and/or modify it
46 * under the terms of the GNU General Public License as published by the Free
47 * Software Foundation; either version 2 of the License, or (at your option)
50 * This program is distributed in the hope that it will be useful, but
51 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
52 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
55 * You should have received a copy of the GNU General Public License along
56 * with this program; if not, write to the Free Software Foundation, Inc.,
57 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
60 /* This is a table for keeping known partition type codes and descriptions */
61 PARTITION_TYPE PartitionTypes
[NUM_PARTITION_TYPE_ENTRIES
] =
65 { 0x02, "XENIX root" },
66 { 0x03, "XENIX usr" },
67 { 0x04, "FAT16 (< 32 MB)" },
70 { 0x07, "NTFS/HPFS/exFAT" },
71 { 0x08, "OS/2 or AIX boot" },
73 { 0x0A, "OS/2 Boot Manager" },
75 { 0x0C, "FAT32 (LBA)" },
76 { 0x0E, "FAT16 (LBA)" },
77 { 0x0F, "Extended (LBA)" },
79 { 0x11, "Hidden FAT12" },
80 { 0x12, "FAT diagnostic (Compaq)" },
82 { 0x14, "Hidden FAT16 (< 32 MB)" },
83 { 0x16, "Hidden FAT16" },
84 { 0x17, "Hidden HPFS or NTFS" },
85 { 0x18, "AST SmartSleep" },
86 { 0x1B, "Hidden FAT32" },
87 { 0x1C, "Hidden FAT32 (LBA)" },
88 { 0x1E, "Hidden FAT16 (LBA)" },
89 { 0x24, "NEC DOS 3.x" },
90 { 0x27, "Hidden WinRE NTFS" },
91 { 0x2A, "AtheOS File System (AFS)" },
92 { 0x2B, "SyllableSecure (SylStor)" },
94 { 0x35, "JFS on OS/2 or eCS" },
95 { 0x38, "THEOS v3.2 2GB partition" },
97 { 0x3A, "THEOS v4 4GB partition" },
98 { 0x3B, "THEOS v4 extended partition" },
99 { 0x3C, "PartitionMagic recovery partition" },
100 { 0x3D, "Hidden NetWare" },
102 { 0x41, "PowerPC PReP boot" },
103 { 0x42, "Win2K Dynamic Volume extended" },
104 { 0x43, "Old Linux" },
106 { 0x45, "Priam or Boot-US Boot Manager" },
108 { 0x4E, "QNX4.x 2nd partition" },
109 { 0x4F, "QNX4.x 3rd partition" },
110 { 0x50, "OnTrack Disk Manager R/O" },
111 { 0x51, "OnTrack Disk Manager R/W or Novell" },
113 { 0x53, "OnTrack DM6 Aux3" },
114 { 0x54, "OnTrack DM6 Dynamic Drive Overlay" },
115 { 0x55, "EZ-Drive" },
116 { 0x56, "Golden Bow VFeature Partitioned Volume" },
117 { 0x5C, "Priam EDisk" },
118 { 0x61, "SpeedStor" },
120 { 0x63, "GNU HURD or Unix System V (SCO, ISC Unix, UnixWare)" },
121 { 0x64, "Novell NetWare 286, 2.xx" },
122 { 0x65, "Novell NetWare 386, 3.xx or 4.xx" },
123 { 0x66, "Novell NetWare SMS Partition" },
126 { 0x69, "Novell NetWare 5+" },
127 { 0x70, "DiskSecure Multi-Boot" },
128 { 0x75, "IBM PC/IX" },
129 { 0x7E, "Veritas VxVM public" },
130 { 0x7F, "Veritas VxVM private" },
131 { 0x80, "Old MINIX" },
132 { 0x81, "Linux or MINIX" },
133 { 0x82, "Linux swap or Solaris" },
134 { 0x83, "Linux Native" },
135 { 0x84, "Hibernate" },
136 { 0x85, "Extended Linux" },
137 { 0x86, "FAT16 mirrored" },
138 { 0x87, "HPFS or NTFS mirrored" },
139 { 0x88, "Linux plaintext partition table" },
140 { 0x8B, "FAT32 mirrored" },
141 { 0x8C, "FAT32 (LBA) mirrored" },
142 { 0x8E, "Linux LVM" },
143 { 0x93, "Hidden Linux" },
144 { 0x94, "Amoeba BBT" },
145 { 0x96, "CDFS/ISO-9660" },
147 { 0xA0, "Laptop Hibernate" },
148 { 0xA1, "Laptop Hibernate (NEC 6000H)" },
149 { 0xA5, "BSD, NetBSD, FreeBSD" },
151 { 0xA7, "NeXTStep" },
152 { 0xA8, "Darwin UFS" }, // Also known as "OS-X"
154 { 0xAB, "Darwin boot" },
155 { 0xAF, "Apple HFS" },
156 { 0xB6, "NT FAT16 corrupt mirror" },
157 { 0xB7, "BSDI BSD/386 FS" }, // Alternatively, "NT NTFS corrupt mirror"
158 { 0xB8, "BSDI BSD/386 swap" },
159 { 0xBB, "Boot Wizard hidden" },
160 { 0xBC, "Paragon Backup capsule" },
161 { 0xBE, "Solaris 8 boot partition" },
162 { 0xBF, "Solaris 10 x86" },
163 { 0xC0, "NTFT" }, // Alternatively, "CTOS" or "REAL/32 or DR-DOS or Novell-DOS secure partition"
164 { 0xC1, "DR-DOS FAT12" },
165 { 0xC2, "Hidden Linux" },
166 { 0xC3, "Hidden Linux swap" },
167 { 0xC4, "DR-DOS FAT16 (< 32 MB)" },
168 { 0xC5, "DR-DOS Extended" },
169 { 0xC6, "DR-DOS FAT16" },
170 { 0xC7, "HPFS mirrored" }, // Alternatively, "Syrinx boot"
171 { 0xCB, "DR-DOS FAT32" },
172 { 0xCC, "DR-DOS FAT32 (LBA)" },
173 { 0xCE, "DR-DOS FAT16 (LBA)" },
175 { 0xD1, "MDOS FAT12" },
176 { 0xD4, "MDOS FAT16 (< 32 MB)" },
177 { 0xD5, "MDOS Extended" },
178 { 0xD6, "MDOS FAT16" },
180 { 0xDB, "Digital Research CP/M" },
181 { 0xDE, "Dell OEM" },
182 { 0xDF, "BootIt EMBRM (FAT16/32)" },
183 { 0xE1, "SpeedStor FAT12" },
184 { 0xE3, "SpeedStor (0xE3)" },
185 { 0xE4, "SpeedStor FAT16" },
186 { 0xE5, "Tandy MSDOS" },
187 { 0xE6, "SpeedStor (0xE6)" },
188 { 0xE8, "Linux Unified Key Setup partition" },
189 { 0xEA, "Rufus private partition" },
190 { 0xEB, "BeOS BFS" },
191 { 0xEC, "SkyOS SkyFS" },
192 { 0xEE, "EFI GPT protective" },
193 { 0xEF, "EFI System partition" },
194 { 0xF0, "Linux/PA-RISC boot loader" },
195 { 0xF1, "SpeedStor (0xF1)" },
196 { 0xF2, "DOS 3.3+ second" },
197 { 0xF4, "SpeedStor (0xF4)" },
198 { 0xF5, "SpeedStor (0xF5)" },
199 { 0xF6, "SpeedStor (0xF6)" },
201 { 0xFB, "VMware FS" },
202 { 0xFC, "VMware swap" },
203 { 0xFD, "Linux RAID auto" },
204 { 0xFE, "NT hidden partition" },
205 { 0xFF, "XENIX Bad Block Table" },
209 /* FUNCTIONS ****************************************************************/
211 #ifdef DUMP_PARTITION_TABLE
215 PDISKENTRY DiskEntry
)
217 PPARTITION_INFORMATION PartitionInfo
;
221 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
222 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
224 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
226 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
227 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
229 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
230 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
231 PartitionInfo
->HiddenSectors
,
232 PartitionInfo
->PartitionNumber
,
233 PartitionInfo
->PartitionType
,
234 PartitionInfo
->BootIndicator
? '*': ' ',
235 PartitionInfo
->RewritePartition
? 'Y': 'N');
250 Temp
= Value
/ Alignment
;
252 return Temp
* Alignment
;
260 ULONGLONG Temp
, Result
;
262 Temp
= Value
/ Alignment
;
264 Result
= Temp
* Alignment
;
265 if (Value
% Alignment
)
273 IN ULONGLONG Dividend
,
274 IN ULONGLONG Divisor
)
276 return (Dividend
+ Divisor
/ 2) / Divisor
;
283 IN PDISKENTRY DiskEntry
)
285 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
289 RtlInitUnicodeString(&DiskEntry
->DriverName
, NULL
);
291 RtlStringCchPrintfW(KeyName
, ARRAYSIZE(KeyName
),
292 L
"\\Scsi\\Scsi Port %hu",
295 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
297 QueryTable
[0].Name
= L
"Driver";
298 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
299 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
301 /* This will allocate DiskEntry->DriverName if needed */
302 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
307 if (!NT_SUCCESS(Status
))
309 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
318 PDISKENTRY DiskEntry
;
319 PPARTENTRY PartEntry
;
326 /* Assign drive letters to primary partitions */
327 Entry1
= List
->DiskListHead
.Flink
;
328 while (Entry1
!= &List
->DiskListHead
)
330 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
332 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
333 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
335 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
337 PartEntry
->DriveLetter
= 0;
339 if (PartEntry
->IsPartitioned
&&
340 !IsContainerPartition(PartEntry
->PartitionType
))
342 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
343 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
344 PartEntry
->SectorCount
.QuadPart
!= 0LL))
348 PartEntry
->DriveLetter
= Letter
;
354 Entry2
= Entry2
->Flink
;
357 Entry1
= Entry1
->Flink
;
360 /* Assign drive letters to logical drives */
361 Entry1
= List
->DiskListHead
.Flink
;
362 while (Entry1
!= &List
->DiskListHead
)
364 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
366 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
367 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
369 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
371 PartEntry
->DriveLetter
= 0;
373 if (PartEntry
->IsPartitioned
)
375 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
376 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
377 PartEntry
->SectorCount
.QuadPart
!= 0LL))
381 PartEntry
->DriveLetter
= Letter
;
387 Entry2
= Entry2
->Flink
;
390 Entry1
= Entry1
->Flink
;
396 DiskIdentifierQueryRoutine(
404 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
405 UNICODE_STRING NameU
;
407 if (ValueType
== REG_SZ
&&
408 ValueLength
== 20 * sizeof(WCHAR
))
410 NameU
.Buffer
= (PWCHAR
)ValueData
;
411 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
412 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
414 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
415 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
417 return STATUS_SUCCESS
;
420 return STATUS_UNSUCCESSFUL
;
425 DiskConfigurationDataQueryRoutine(
433 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
434 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
435 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
438 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
439 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
440 return STATUS_UNSUCCESSFUL
;
442 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
444 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
446 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
447 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
448 return STATUS_UNSUCCESSFUL
;
451 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
453 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
454 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
457 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
458 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
460 return STATUS_SUCCESS
;
463 return STATUS_UNSUCCESSFUL
;
468 SystemConfigurationDataQueryRoutine(
476 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
477 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
480 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
481 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
482 return STATUS_UNSUCCESSFUL
;
484 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
486 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
488 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
489 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
490 return STATUS_UNSUCCESSFUL
;
493 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
495 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
496 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
499 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(ProcessHeap
, 0,
500 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
501 if (*Int13Drives
== NULL
)
502 return STATUS_NO_MEMORY
;
505 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
506 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
507 return STATUS_SUCCESS
;
510 return STATUS_UNSUCCESSFUL
;
515 EnumerateBiosDiskEntries(
516 IN PPARTLIST PartList
)
518 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
523 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
524 PBIOSDISKENTRY BiosDiskEntry
;
526 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
528 memset(QueryTable
, 0, sizeof(QueryTable
));
530 QueryTable
[1].Name
= L
"Configuration Data";
531 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
533 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
534 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
538 if (!NT_SUCCESS(Status
))
540 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
547 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
549 ROOT_NAME
, AdapterCount
);
550 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
555 if (!NT_SUCCESS(Status
))
560 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
561 L
"%s\\%lu\\DiskController",
562 ROOT_NAME
, AdapterCount
);
563 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
568 if (NT_SUCCESS(Status
))
572 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
573 L
"%s\\%lu\\DiskController\\0",
574 ROOT_NAME
, AdapterCount
);
575 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
580 if (!NT_SUCCESS(Status
))
582 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
586 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
587 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral",
588 ROOT_NAME
, AdapterCount
);
589 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
594 if (NT_SUCCESS(Status
))
596 QueryTable
[0].Name
= L
"Identifier";
597 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
598 QueryTable
[1].Name
= L
"Configuration Data";
599 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
604 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
605 if (BiosDiskEntry
== NULL
)
610 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
611 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
612 ROOT_NAME
, AdapterCount
, DiskCount
);
613 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
616 (PVOID
)BiosDiskEntry
,
618 if (!NT_SUCCESS(Status
))
620 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
624 BiosDiskEntry
->DiskNumber
= DiskCount
;
625 BiosDiskEntry
->Recognized
= FALSE
;
627 if (DiskCount
< Int13Drives
[0].NumberDrives
)
629 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
633 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount
);
636 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
638 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
639 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
640 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
641 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
642 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
643 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
644 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
645 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
646 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
647 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
648 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
654 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
662 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
670 * Inserts the disk region represented by PartEntry into either the primary
671 * or the logical partition list of the given disk.
672 * The lists are kept sorted by increasing order of start sectors.
673 * Of course no disk region should overlap at all with one another.
678 IN PDISKENTRY DiskEntry
,
679 IN PPARTENTRY PartEntry
,
680 IN BOOLEAN LogicalPartition
)
684 PPARTENTRY PartEntry2
;
686 /* Use the correct partition list */
687 if (LogicalPartition
)
688 List
= &DiskEntry
->LogicalPartListHead
;
690 List
= &DiskEntry
->PrimaryPartListHead
;
692 /* Find the first disk region before which we need to insert the new one */
693 for (Entry
= List
->Flink
; Entry
!= List
; Entry
= Entry
->Flink
)
695 PartEntry2
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
697 /* Ignore any unused empty region */
698 if ((PartEntry2
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
699 PartEntry2
->StartSector
.QuadPart
== 0) || PartEntry2
->SectorCount
.QuadPart
== 0)
704 /* If the current region ends before the one to be inserted, try again */
705 if (PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1 < PartEntry
->StartSector
.QuadPart
)
709 * One of the disk region boundaries crosses the desired region
710 * (it starts after the desired region, or ends before the end
711 * of the desired region): this is an impossible situation because
712 * disk regions (partitions) cannot overlap!
713 * Throw an error and bail out.
715 if (max(PartEntry
->StartSector
.QuadPart
, PartEntry2
->StartSector
.QuadPart
)
717 min( PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
718 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1))
720 DPRINT1("Disk region overlap problem, stopping there!\n"
721 "Partition to be inserted:\n"
722 " StartSector = %I64u ; EndSector = %I64u\n"
723 "Existing disk region:\n"
724 " StartSector = %I64u ; EndSector = %I64u\n",
725 PartEntry
->StartSector
.QuadPart
,
726 PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
727 PartEntry2
->StartSector
.QuadPart
,
728 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1);
732 /* We have found the first region before which the new one has to be inserted */
736 /* Insert the disk region */
737 InsertTailList(Entry
, &PartEntry
->ListEntry
);
742 CreateInsertBlankRegion(
743 IN PDISKENTRY DiskEntry
,
744 IN OUT PLIST_ENTRY ListHead
,
745 IN ULONGLONG StartSector
,
746 IN ULONGLONG SectorCount
,
747 IN BOOLEAN LogicalSpace
)
749 PPARTENTRY NewPartEntry
;
751 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
754 if (NewPartEntry
== NULL
)
757 NewPartEntry
->DiskEntry
= DiskEntry
;
759 NewPartEntry
->IsPartitioned
= FALSE
;
760 NewPartEntry
->FormatState
= Unformatted
;
761 NewPartEntry
->FileSystem
= NULL
;
763 NewPartEntry
->StartSector
.QuadPart
= StartSector
;
764 NewPartEntry
->SectorCount
.QuadPart
= SectorCount
;
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 table 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 /* Convert current entry to 'new (unformatted)' */
796 PartEntry
->IsPartitioned
= TRUE
;
797 PartEntry
->New
= TRUE
;
798 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
799 PartEntry
->FormatState
= Unformatted
;
800 PartEntry
->FileSystem
= NULL
;
801 PartEntry
->AutoCreate
= AutoCreate
;
802 PartEntry
->BootIndicator
= FALSE
;
803 PartEntry
->LogicalPartition
= FALSE
;
805 NewPartEntry
= PartEntry
;
809 DPRINT1("Add new partition entry\n");
811 /* Insert and initialize a new partition entry */
812 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
815 if (NewPartEntry
== NULL
)
818 /* Insert the new entry into the list */
819 InsertTailList(&PartEntry
->ListEntry
,
820 &NewPartEntry
->ListEntry
);
822 NewPartEntry
->DiskEntry
= DiskEntry
;
824 NewPartEntry
->IsPartitioned
= TRUE
;
825 NewPartEntry
->New
= TRUE
;
826 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
827 NewPartEntry
->FormatState
= Unformatted
;
828 NewPartEntry
->FileSystem
= NULL
;
829 NewPartEntry
->BootIndicator
= FALSE
;
830 NewPartEntry
->LogicalPartition
= FALSE
;
832 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
833 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
834 NewPartEntry
->StartSector
.QuadPart
;
836 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
837 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
840 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
841 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
842 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
852 IN PDISKENTRY DiskEntry
,
853 IN ULONG PartitionIndex
,
854 IN BOOLEAN LogicalPartition
)
857 PPARTITION_INFORMATION PartitionInfo
;
858 PPARTENTRY PartEntry
;
860 OBJECT_ATTRIBUTES ObjectAttributes
;
861 IO_STATUS_BLOCK IoStatusBlock
;
862 WCHAR Buffer
[MAX_PATH
];
864 UCHAR LabelBuffer
[sizeof(FILE_FS_VOLUME_INFORMATION
) + 256 * sizeof(WCHAR
)];
865 PFILE_FS_VOLUME_INFORMATION LabelInfo
= (PFILE_FS_VOLUME_INFORMATION
)LabelBuffer
;
867 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
869 if (PartitionInfo
->PartitionType
== PARTITION_ENTRY_UNUSED
||
870 ((LogicalPartition
!= FALSE
) && IsContainerPartition(PartitionInfo
->PartitionType
)))
875 PartEntry
= RtlAllocateHeap(ProcessHeap
,
878 if (PartEntry
== NULL
)
881 PartEntry
->DiskEntry
= DiskEntry
;
883 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
884 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
886 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
887 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
888 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
890 PartEntry
->LogicalPartition
= LogicalPartition
;
891 PartEntry
->IsPartitioned
= TRUE
;
892 PartEntry
->OnDiskPartitionNumber
= PartitionInfo
->PartitionNumber
;
893 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
894 PartEntry
->PartitionIndex
= PartitionIndex
;
896 if (IsContainerPartition(PartEntry
->PartitionType
))
898 PartEntry
->FormatState
= Unformatted
;
899 PartEntry
->FileSystem
= NULL
;
901 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
902 DiskEntry
->ExtendedPartition
= PartEntry
;
904 else if (IsRecognizedPartition(PartEntry
->PartitionType
))
906 ASSERT(PartitionInfo
->RecognizedPartition
);
908 PartEntry
->FileSystem
= GetFileSystem(PartEntry
);
909 if (PartEntry
->FileSystem
)
910 PartEntry
->FormatState
= Preformatted
;
912 PartEntry
->FormatState
= Unformatted
;
913 // PartEntry->FormatState = UnknownFormat;
917 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
918 PartEntry
->FormatState
= UnknownFormat
;
921 /* Initialize the partition volume label */
922 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
924 /* Open the volume, ignore any errors */
925 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
926 L
"\\Device\\Harddisk%lu\\Partition%lu",
927 DiskEntry
->DiskNumber
,
928 PartEntry
->PartitionNumber
);
929 RtlInitUnicodeString(&Name
, Buffer
);
931 InitializeObjectAttributes(&ObjectAttributes
,
933 OBJ_CASE_INSENSITIVE
,
937 Status
= NtOpenFile(&FileHandle
,
938 FILE_READ_DATA
| SYNCHRONIZE
,
941 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
942 FILE_SYNCHRONOUS_IO_NONALERT
);
943 if (NT_SUCCESS(Status
))
945 /* Retrieve the partition volume label */
946 Status
= NtQueryVolumeInformationFile(FileHandle
,
950 FileFsVolumeInformation
);
951 /* Close the handle */
954 /* Check for success */
955 if (NT_SUCCESS(Status
))
957 /* Copy the (possibly truncated) volume label and NULL-terminate it */
958 RtlStringCbCopyNW(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
),
959 LabelInfo
->VolumeLabel
, LabelInfo
->VolumeLabelLength
);
963 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status
);
968 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status
);
971 InsertDiskRegion(DiskEntry
, PartEntry
, LogicalPartition
);
976 ScanForUnpartitionedDiskSpace(
977 IN PDISKENTRY DiskEntry
)
979 ULONGLONG StartSector
;
980 ULONGLONG SectorCount
;
981 ULONGLONG LastStartSector
;
982 ULONGLONG LastSectorCount
;
983 ULONGLONG LastUnusedSectorCount
;
984 PPARTENTRY PartEntry
;
985 PPARTENTRY NewPartEntry
;
988 DPRINT("ScanForUnpartitionedDiskSpace()\n");
990 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
992 DPRINT1("No primary partition!\n");
994 /* Create a partition entry that represents the empty disk */
996 if (DiskEntry
->SectorAlignment
< 2048)
997 StartSector
= 2048ULL;
999 StartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1000 SectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) - StartSector
;
1002 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1003 &DiskEntry
->PrimaryPartListHead
,
1007 if (NewPartEntry
== NULL
)
1008 DPRINT1("Failed to create a new empty region for full disk space!\n");
1013 /* Start partition at head 1, cylinder 0 */
1014 if (DiskEntry
->SectorAlignment
< 2048)
1015 LastStartSector
= 2048ULL;
1017 LastStartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1018 LastSectorCount
= 0ULL;
1019 LastUnusedSectorCount
= 0ULL;
1021 Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1022 while (Entry
!= &DiskEntry
->PrimaryPartListHead
)
1024 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1026 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1027 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1029 LastUnusedSectorCount
=
1030 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
1032 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
1033 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1035 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1037 StartSector
= LastStartSector
+ LastSectorCount
;
1038 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1040 /* Insert the table into the list */
1041 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1042 &PartEntry
->ListEntry
,
1046 if (NewPartEntry
== NULL
)
1048 DPRINT1("Failed to create a new empty region for disk space!\n");
1053 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1054 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1057 Entry
= Entry
->Flink
;
1060 /* Check for trailing unpartitioned disk space */
1061 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
1063 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
1065 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1067 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1069 StartSector
= LastStartSector
+ LastSectorCount
;
1070 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1072 /* Append the table to the list */
1073 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1074 &DiskEntry
->PrimaryPartListHead
,
1078 if (NewPartEntry
== NULL
)
1080 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1086 if (DiskEntry
->ExtendedPartition
!= NULL
)
1088 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1090 DPRINT1("No logical partition!\n");
1092 /* Create a partition entry that represents the empty extended partition */
1094 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1095 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
1097 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1098 &DiskEntry
->LogicalPartListHead
,
1102 if (NewPartEntry
== NULL
)
1104 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1107 NewPartEntry
->LogicalPartition
= TRUE
;
1112 /* Start partition at head 1, cylinder 0 */
1113 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1114 LastSectorCount
= 0ULL;
1115 LastUnusedSectorCount
= 0ULL;
1117 Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1118 while (Entry
!= &DiskEntry
->LogicalPartListHead
)
1120 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1122 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1123 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1125 LastUnusedSectorCount
=
1126 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
1128 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
1129 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1131 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1133 StartSector
= LastStartSector
+ LastSectorCount
;
1134 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1136 /* Insert the table into the list */
1137 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1138 &PartEntry
->ListEntry
,
1142 if (NewPartEntry
== NULL
)
1144 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1147 NewPartEntry
->LogicalPartition
= TRUE
;
1150 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1151 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1154 Entry
= Entry
->Flink
;
1157 /* Check for trailing unpartitioned disk space */
1158 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
1160 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+
1161 DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
1162 DiskEntry
->SectorAlignment
);
1164 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1166 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1168 StartSector
= LastStartSector
+ LastSectorCount
;
1169 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1171 /* Append the table to the list */
1172 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1173 &DiskEntry
->LogicalPartListHead
,
1177 if (NewPartEntry
== NULL
)
1179 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1182 NewPartEntry
->LogicalPartition
= TRUE
;
1187 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1194 IN PDISKENTRY DiskEntry
)
1196 LARGE_INTEGER SystemTime
;
1197 TIME_FIELDS TimeFields
;
1199 PDISKENTRY DiskEntry2
;
1202 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1206 NtQuerySystemTime(&SystemTime
);
1207 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1209 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1210 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1211 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1212 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1214 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1219 /* Check if the signature already exist */
1221 * Check also signatures from disks, which are
1222 * not visible (bootable) by the bios.
1224 Entry2
= List
->DiskListHead
.Flink
;
1225 while (Entry2
!= &List
->DiskListHead
)
1227 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1229 if (DiskEntry
!= DiskEntry2
&&
1230 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1233 Entry2
= Entry2
->Flink
;
1236 if (Entry2
== &List
->DiskListHead
)
1243 UpdateDiskSignatures(
1247 PDISKENTRY DiskEntry
;
1249 /* Print partition lines */
1250 Entry
= List
->DiskListHead
.Flink
;
1251 while (Entry
!= &List
->DiskListHead
)
1253 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1255 if (DiskEntry
->LayoutBuffer
&&
1256 DiskEntry
->LayoutBuffer
->Signature
== 0)
1258 SetDiskSignature(List
, DiskEntry
);
1259 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1262 Entry
= Entry
->Flink
;
1269 IN HANDLE FileHandle
,
1270 IN ULONG DiskNumber
,
1273 DISK_GEOMETRY DiskGeometry
;
1274 SCSI_ADDRESS ScsiAddress
;
1275 PDISKENTRY DiskEntry
;
1276 IO_STATUS_BLOCK Iosb
;
1278 PPARTITION_SECTOR Mbr
;
1280 LARGE_INTEGER FileOffset
;
1281 WCHAR Identifier
[20];
1285 PLIST_ENTRY ListEntry
;
1286 PBIOSDISKENTRY BiosDiskEntry
;
1287 ULONG LayoutBufferSize
;
1288 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1290 /* Retrieve the drive geometry */
1291 Status
= NtDeviceIoControlFile(FileHandle
,
1296 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1300 sizeof(DiskGeometry
));
1301 if (!NT_SUCCESS(Status
))
1304 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1305 DiskGeometry
.MediaType
!= RemovableMedia
)
1311 * FIXME: Here we suppose the disk is always SCSI. What if it is
1312 * of another type? To check this we need to retrieve the name of
1313 * the driver the disk device belongs to.
1315 Status
= NtDeviceIoControlFile(FileHandle
,
1320 IOCTL_SCSI_GET_ADDRESS
,
1324 sizeof(ScsiAddress
));
1325 if (!NT_SUCCESS(Status
))
1329 * Check whether the disk is initialized, by looking at its MBR.
1330 * NOTE that this must be generalized to GPT disks as well!
1333 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1335 DiskGeometry
.BytesPerSector
);
1339 FileOffset
.QuadPart
= 0;
1340 Status
= NtReadFile(FileHandle
,
1346 DiskGeometry
.BytesPerSector
,
1349 if (!NT_SUCCESS(Status
))
1351 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1352 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1355 Signature
= Mbr
->Signature
;
1357 /* Calculate the MBR checksum */
1359 Buffer
= (PULONG
)Mbr
;
1360 for (i
= 0; i
< 128; i
++)
1362 Checksum
+= Buffer
[i
];
1364 Checksum
= ~Checksum
+ 1;
1366 RtlStringCchPrintfW(Identifier
, ARRAYSIZE(Identifier
),
1367 L
"%08x-%08x-A", Checksum
, Signature
);
1368 DPRINT("Identifier: %S\n", Identifier
);
1370 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1373 if (DiskEntry
== NULL
)
1375 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1376 DPRINT1("Failed to allocate a new disk entry.\n");
1380 // DiskEntry->Checksum = Checksum;
1381 // DiskEntry->Signature = Signature;
1382 DiskEntry
->BiosFound
= FALSE
;
1385 * Check if this disk has a valid MBR: verify its signature,
1386 * and whether its two first bytes are a valid instruction
1387 * (related to this, see IsThereAValidBootSector() in partlist.c).
1389 if (Mbr
->Magic
!= 0xaa55 || (*(PUSHORT
)Mbr
->BootCode
) == 0x0000)
1390 DiskEntry
->NoMbr
= TRUE
;
1392 DiskEntry
->NoMbr
= FALSE
;
1394 /* Free the MBR sector buffer */
1395 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1398 ListEntry
= List
->BiosDiskListHead
.Flink
;
1399 while (ListEntry
!= &List
->BiosDiskListHead
)
1401 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1403 * Compare the size from bios and the reported size from driver.
1404 * If we have more than one disk with a zero or with the same signature
1405 * we must create new signatures and reboot. After the reboot,
1406 * it is possible to identify the disks.
1408 if (BiosDiskEntry
->Signature
== Signature
&&
1409 BiosDiskEntry
->Checksum
== Checksum
&&
1410 !BiosDiskEntry
->Recognized
)
1412 if (!DiskEntry
->BiosFound
)
1414 DiskEntry
->BiosDiskNumber
= BiosDiskEntry
->DiskNumber
;
1415 DiskEntry
->BiosFound
= TRUE
;
1416 BiosDiskEntry
->Recognized
= TRUE
;
1420 // FIXME: What to do?
1423 ListEntry
= ListEntry
->Flink
;
1426 if (!DiskEntry
->BiosFound
)
1429 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1432 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber
);
1436 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1437 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1439 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1440 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1441 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1442 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1444 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1445 DPRINT("TracksPerCylinder %lu\n", DiskEntry
->TracksPerCylinder
);
1446 DPRINT("SectorsPerTrack %lu\n", DiskEntry
->SectorsPerTrack
);
1447 DPRINT("BytesPerSector %lu\n", DiskEntry
->BytesPerSector
);
1449 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1450 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1451 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1453 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1454 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1455 DiskGeometry
.SectorsPerTrack
;
1457 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
.QuadPart
);
1458 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1460 DiskEntry
->DiskNumber
= DiskNumber
;
1461 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1462 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1463 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1465 GetDriverName(DiskEntry
);
1467 * Actually it would be more correct somehow to use:
1469 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1470 * ULONG ReturnedLength;
1472 * Status = NtQueryObject(SomeHandleToTheDisk,
1473 * ObjectNameInformation,
1479 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1482 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1486 * We now retrieve the disk partition layout
1489 /* Allocate a layout buffer with 4 partition entries first */
1490 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1491 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1492 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1495 if (DiskEntry
->LayoutBuffer
== NULL
)
1497 DPRINT1("Failed to allocate the disk layout buffer!\n");
1501 /* Keep looping while the drive layout buffer is too small */
1504 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1505 Status
= NtDeviceIoControlFile(FileHandle
,
1510 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1513 DiskEntry
->LayoutBuffer
,
1515 if (NT_SUCCESS(Status
))
1518 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1520 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1524 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1525 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1527 DiskEntry
->LayoutBuffer
,
1529 if (NewLayoutBuffer
== NULL
)
1531 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1535 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1538 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1540 #ifdef DUMP_PARTITION_TABLE
1541 DumpPartitionTable(DiskEntry
);
1544 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1545 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1546 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= PARTITION_ENTRY_UNUSED
)
1548 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1550 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1552 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1554 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1558 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1563 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1566 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1568 DiskEntry
->NewDisk
= TRUE
;
1569 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1571 for (i
= 0; i
< 4; i
++)
1573 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1578 /* Enumerate and add the first four primary partitions */
1579 for (i
= 0; i
< 4; i
++)
1581 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, FALSE
);
1584 /* Enumerate and add the remaining partitions as logical ones */
1585 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1587 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, TRUE
);
1591 ScanForUnpartitionedDiskSpace(DiskEntry
);
1595 CreatePartitionList(VOID
)
1598 OBJECT_ATTRIBUTES ObjectAttributes
;
1599 SYSTEM_DEVICE_INFORMATION Sdi
;
1600 IO_STATUS_BLOCK Iosb
;
1604 WCHAR Buffer
[MAX_PATH
];
1605 UNICODE_STRING Name
;
1608 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1614 List
->CurrentDisk
= NULL
;
1615 List
->CurrentPartition
= NULL
;
1617 List
->SystemPartition
= NULL
;
1618 List
->OriginalSystemPartition
= NULL
;
1620 InitializeListHead(&List
->DiskListHead
);
1621 InitializeListHead(&List
->BiosDiskListHead
);
1624 * Enumerate the disks seen by the BIOS; this will be used later
1625 * to map drives seen by NTOS with their corresponding BIOS names.
1627 EnumerateBiosDiskEntries(List
);
1629 /* Enumerate disks seen by NTOS */
1630 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1634 if (!NT_SUCCESS(Status
))
1636 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status
);
1637 RtlFreeHeap(ProcessHeap
, 0, List
);
1641 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1643 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
1644 L
"\\Device\\Harddisk%lu\\Partition0",
1646 RtlInitUnicodeString(&Name
, Buffer
);
1648 InitializeObjectAttributes(&ObjectAttributes
,
1650 OBJ_CASE_INSENSITIVE
,
1654 Status
= NtOpenFile(&FileHandle
,
1655 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1658 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1659 FILE_SYNCHRONOUS_IO_NONALERT
);
1660 if (NT_SUCCESS(Status
))
1662 AddDiskToList(FileHandle
, DiskNumber
, List
);
1663 NtClose(FileHandle
);
1667 UpdateDiskSignatures(List
);
1669 AssignDriveLetters(List
);
1671 /* Search for first usable disk and partition */
1672 if (IsListEmpty(&List
->DiskListHead
))
1674 List
->CurrentDisk
= NULL
;
1675 List
->CurrentPartition
= NULL
;
1679 List
->CurrentDisk
= CONTAINING_RECORD(List
->DiskListHead
.Flink
,
1683 if (IsListEmpty(&List
->CurrentDisk
->PrimaryPartListHead
))
1685 List
->CurrentPartition
= NULL
;
1689 List
->CurrentPartition
= CONTAINING_RECORD(List
->CurrentDisk
->PrimaryPartListHead
.Flink
,
1699 DestroyPartitionList(
1702 PDISKENTRY DiskEntry
;
1703 PBIOSDISKENTRY BiosDiskEntry
;
1704 PPARTENTRY PartEntry
;
1707 /* Release disk and partition info */
1708 while (!IsListEmpty(&List
->DiskListHead
))
1710 Entry
= RemoveHeadList(&List
->DiskListHead
);
1711 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1713 /* Release driver name */
1714 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1716 /* Release primary partition list */
1717 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1719 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1720 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1722 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1725 /* Release logical partition list */
1726 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1728 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1729 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1731 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1734 /* Release layout buffer */
1735 if (DiskEntry
->LayoutBuffer
!= NULL
)
1736 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1738 /* Release disk entry */
1739 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1742 /* Release the bios disk info */
1743 while (!IsListEmpty(&List
->BiosDiskListHead
))
1745 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1746 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1748 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
1751 /* Release list head */
1752 RtlFreeHeap(ProcessHeap
, 0, List
);
1756 GetDiskByBiosNumber(
1758 IN ULONG BiosDiskNumber
)
1760 PDISKENTRY DiskEntry
;
1763 /* Loop over the disks and find the correct one */
1764 Entry
= List
->DiskListHead
.Flink
;
1765 while (Entry
!= &List
->DiskListHead
)
1767 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1768 Entry
= Entry
->Flink
;
1770 if (DiskEntry
->BiosDiskNumber
== BiosDiskNumber
)
1777 /* Disk not found, stop there */
1784 IN ULONG DiskNumber
)
1786 PDISKENTRY DiskEntry
;
1789 /* Loop over the disks and find the correct one */
1790 Entry
= List
->DiskListHead
.Flink
;
1791 while (Entry
!= &List
->DiskListHead
)
1793 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1794 Entry
= Entry
->Flink
;
1796 if (DiskEntry
->DiskNumber
== DiskNumber
)
1803 /* Disk not found, stop there */
1814 PDISKENTRY DiskEntry
;
1817 /* Loop over the disks and find the correct one */
1818 Entry
= List
->DiskListHead
.Flink
;
1819 while (Entry
!= &List
->DiskListHead
)
1821 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1822 Entry
= Entry
->Flink
;
1824 if (DiskEntry
->Port
== Port
&&
1825 DiskEntry
->Bus
== Bus
&&
1826 DiskEntry
->Id
== Id
)
1833 /* Disk not found, stop there */
1842 PDISKENTRY DiskEntry
;
1845 /* Loop over the disks and find the correct one */
1846 Entry
= List
->DiskListHead
.Flink
;
1847 while (Entry
!= &List
->DiskListHead
)
1849 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1850 Entry
= Entry
->Flink
;
1852 if (DiskEntry
->LayoutBuffer
->Signature
== Signature
)
1859 /* Disk not found, stop there */
1865 // IN PPARTLIST List,
1866 IN PDISKENTRY DiskEntry
,
1867 IN ULONG PartitionNumber
)
1869 PPARTENTRY PartEntry
;
1872 /* Disk found, loop over the primary partitions first... */
1873 Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1874 while (Entry
!= &DiskEntry
->PrimaryPartListHead
)
1876 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1877 Entry
= Entry
->Flink
;
1879 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1881 /* Partition found */
1886 /* ... then over the logical partitions if needed */
1887 Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1888 while (Entry
!= &DiskEntry
->LogicalPartListHead
)
1890 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1891 Entry
= Entry
->Flink
;
1893 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1895 /* Partition found */
1900 /* The partition was not found on the disk, stop there */
1907 IN ULONG DiskNumber
,
1908 IN ULONG PartitionNumber OPTIONAL
,
1909 OUT PDISKENTRY
* pDiskEntry
,
1910 OUT PPARTENTRY
* pPartEntry OPTIONAL
)
1912 PDISKENTRY DiskEntry
;
1913 PPARTENTRY PartEntry
= NULL
;
1916 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
1920 /* If we have a partition (PartitionNumber != 0), find it */
1921 if (PartitionNumber
!= 0)
1923 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
1926 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
1929 /* Return the disk (and optionally the partition) */
1930 *pDiskEntry
= DiskEntry
;
1931 if (pPartEntry
) *pPartEntry
= PartEntry
;
1936 // NOTE: Was introduced broken in r6258 by Casper
1941 IN ULONG DiskNumber
,
1942 IN ULONG PartitionNumber
)
1944 PDISKENTRY DiskEntry
;
1945 PPARTENTRY PartEntry
;
1947 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
1951 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
1955 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
1956 ASSERT(DiskEntry
->DiskNumber
== DiskNumber
);
1957 ASSERT(PartEntry
->PartitionNumber
== PartitionNumber
);
1959 List
->CurrentDisk
= DiskEntry
;
1960 List
->CurrentPartition
= PartEntry
;
1968 PLIST_ENTRY DiskListEntry
;
1969 PLIST_ENTRY PartListEntry
;
1970 PDISKENTRY DiskEntry
;
1971 PPARTENTRY PartEntry
;
1973 /* Fail if no disks are available */
1974 if (IsListEmpty(&List
->DiskListHead
))
1977 /* Check for next usable entry on current disk */
1978 if (List
->CurrentPartition
!= NULL
)
1980 if (List
->CurrentPartition
->LogicalPartition
)
1982 /* Logical partition */
1984 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
1985 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
1987 /* Next logical partition */
1988 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
1990 List
->CurrentPartition
= PartEntry
;
1991 return List
->CurrentPartition
;
1995 PartListEntry
= List
->CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
1996 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
1998 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2000 List
->CurrentPartition
= PartEntry
;
2001 return List
->CurrentPartition
;
2007 /* Primary or extended partition */
2009 if (List
->CurrentPartition
->IsPartitioned
&&
2010 IsContainerPartition(List
->CurrentPartition
->PartitionType
))
2012 /* First logical partition */
2013 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Flink
;
2014 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2016 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2018 List
->CurrentPartition
= PartEntry
;
2019 return List
->CurrentPartition
;
2024 /* Next primary partition */
2025 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2026 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2028 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2030 List
->CurrentPartition
= PartEntry
;
2031 return List
->CurrentPartition
;
2037 /* Search for the first partition entry on the next disk */
2038 DiskListEntry
= List
->CurrentDisk
->ListEntry
.Flink
;
2039 while (DiskListEntry
!= &List
->DiskListHead
)
2041 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2043 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2044 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2046 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2048 List
->CurrentDisk
= DiskEntry
;
2049 List
->CurrentPartition
= PartEntry
;
2050 return List
->CurrentPartition
;
2053 DiskListEntry
= DiskListEntry
->Flink
;
2063 PLIST_ENTRY DiskListEntry
;
2064 PLIST_ENTRY PartListEntry
;
2065 PDISKENTRY DiskEntry
;
2066 PPARTENTRY PartEntry
;
2068 /* Fail if no disks are available */
2069 if (IsListEmpty(&List
->DiskListHead
))
2072 /* Check for previous usable entry on current disk */
2073 if (List
->CurrentPartition
!= NULL
)
2075 if (List
->CurrentPartition
->LogicalPartition
)
2077 /* Logical partition */
2078 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2079 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2081 /* Previous logical partition */
2082 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2086 /* Extended partition */
2087 PartEntry
= List
->CurrentDisk
->ExtendedPartition
;
2090 List
->CurrentPartition
= PartEntry
;
2091 return List
->CurrentPartition
;
2095 /* Primary or extended partition */
2097 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2098 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2100 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2102 if (PartEntry
->IsPartitioned
&&
2103 IsContainerPartition(PartEntry
->PartitionType
))
2105 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Blink
;
2106 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2109 List
->CurrentPartition
= PartEntry
;
2110 return List
->CurrentPartition
;
2115 /* Search for the last partition entry on the previous disk */
2116 DiskListEntry
= List
->CurrentDisk
->ListEntry
.Blink
;
2117 while (DiskListEntry
!= &List
->DiskListHead
)
2119 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2121 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Blink
;
2122 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2124 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2126 if (PartEntry
->IsPartitioned
&&
2127 IsContainerPartition(PartEntry
->PartitionType
))
2129 PartListEntry
= DiskEntry
->LogicalPartListHead
.Blink
;
2130 if (PartListEntry
!= &DiskEntry
->LogicalPartListHead
)
2132 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2134 List
->CurrentDisk
= DiskEntry
;
2135 List
->CurrentPartition
= PartEntry
;
2136 return List
->CurrentPartition
;
2141 List
->CurrentDisk
= DiskEntry
;
2142 List
->CurrentPartition
= PartEntry
;
2143 return List
->CurrentPartition
;
2147 DiskListEntry
= DiskListEntry
->Blink
;
2157 IN PPARTITION_INFORMATION PartitionInfo
)
2159 if (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2160 PartitionInfo
->PartitionLength
.QuadPart
== 0)
2171 IsSamePrimaryLayoutEntry(
2172 IN PPARTITION_INFORMATION PartitionInfo
,
2173 IN PDISKENTRY DiskEntry
,
2174 IN PPARTENTRY PartEntry
)
2176 if (PartitionInfo
->StartingOffset
.QuadPart
== PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
&&
2177 PartitionInfo
->PartitionLength
.QuadPart
== PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
)
2178 // PartitionInfo->PartitionType == PartEntry->PartitionType
2188 GetPrimaryPartitionCount(
2189 IN PDISKENTRY DiskEntry
)
2192 PPARTENTRY PartEntry
;
2195 Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2196 while (Entry
!= &DiskEntry
->PrimaryPartListHead
)
2198 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2199 if (PartEntry
->IsPartitioned
)
2202 Entry
= Entry
->Flink
;
2210 GetLogicalPartitionCount(
2211 IN PDISKENTRY DiskEntry
)
2213 PLIST_ENTRY ListEntry
;
2214 PPARTENTRY PartEntry
;
2217 ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2218 while (ListEntry
!= &DiskEntry
->LogicalPartListHead
)
2220 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2221 if (PartEntry
->IsPartitioned
)
2224 ListEntry
= ListEntry
->Flink
;
2232 ReAllocateLayoutBuffer(
2233 IN PDISKENTRY DiskEntry
)
2235 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2236 ULONG NewPartitionCount
;
2237 ULONG CurrentPartitionCount
= 0;
2238 ULONG LayoutBufferSize
;
2241 DPRINT1("ReAllocateLayoutBuffer()\n");
2243 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2245 if (DiskEntry
->LayoutBuffer
)
2246 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2248 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2249 CurrentPartitionCount
, NewPartitionCount
);
2251 if (CurrentPartitionCount
== NewPartitionCount
)
2254 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2255 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2256 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2258 DiskEntry
->LayoutBuffer
,
2260 if (NewLayoutBuffer
== NULL
)
2262 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2266 NewLayoutBuffer
->PartitionCount
= NewPartitionCount
;
2268 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2269 if (NewPartitionCount
> CurrentPartitionCount
)
2271 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2273 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2277 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2285 IN PDISKENTRY DiskEntry
)
2287 PPARTITION_INFORMATION PartitionInfo
;
2288 PPARTITION_INFORMATION LinkInfo
= NULL
;
2289 PLIST_ENTRY ListEntry
;
2290 PPARTENTRY PartEntry
;
2291 LARGE_INTEGER HiddenSectors64
;
2293 ULONG PartitionNumber
= 1;
2295 DPRINT1("UpdateDiskLayout()\n");
2297 /* Resize the layout buffer if necessary */
2298 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2300 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2304 /* Update the primary partition table */
2306 ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2307 while (ListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2309 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2311 if (PartEntry
->IsPartitioned
)
2313 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2314 PartEntry
->PartitionIndex
= Index
;
2316 /* Reset the current partition number only for newly-created partitions */
2318 PartEntry
->PartitionNumber
= 0;
2320 PartEntry
->OnDiskPartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
)) ? PartitionNumber
: 0;
2322 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, DiskEntry
, PartEntry
))
2324 DPRINT1("Updating primary partition entry %lu\n", Index
);
2326 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2327 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2328 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2329 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2330 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2331 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2332 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2333 PartitionInfo
->RewritePartition
= TRUE
;
2336 if (!IsContainerPartition(PartEntry
->PartitionType
))
2342 ListEntry
= ListEntry
->Flink
;
2347 /* Update the logical partition table */
2349 ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2350 while (ListEntry
!= &DiskEntry
->LogicalPartListHead
)
2352 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2354 if (PartEntry
->IsPartitioned
)
2356 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2357 PartEntry
->PartitionIndex
= Index
;
2359 DPRINT1("Updating logical partition entry %lu\n", Index
);
2361 /* Reset the current partition number only for newly-created partitions */
2363 PartEntry
->PartitionNumber
= 0;
2365 PartEntry
->OnDiskPartitionNumber
= PartitionNumber
;
2367 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2368 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2369 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2370 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2371 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2372 PartitionInfo
->BootIndicator
= FALSE
;
2373 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2374 PartitionInfo
->RewritePartition
= TRUE
;
2376 /* Fill the link entry of the previous partition entry */
2377 if (LinkInfo
!= NULL
)
2379 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2380 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2381 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2382 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2383 LinkInfo
->PartitionNumber
= 0;
2384 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2385 LinkInfo
->BootIndicator
= FALSE
;
2386 LinkInfo
->RecognizedPartition
= FALSE
;
2387 LinkInfo
->RewritePartition
= TRUE
;
2390 /* Save a pointer to the link entry of the current partition entry */
2391 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2397 ListEntry
= ListEntry
->Flink
;
2400 /* Wipe unused primary partition entries */
2401 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2403 DPRINT1("Primary partition entry %lu\n", Index
);
2405 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2407 if (!IsEmptyLayoutEntry(PartitionInfo
))
2409 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2411 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2412 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2413 PartitionInfo
->HiddenSectors
= 0;
2414 PartitionInfo
->PartitionNumber
= 0;
2415 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2416 PartitionInfo
->BootIndicator
= FALSE
;
2417 PartitionInfo
->RecognizedPartition
= FALSE
;
2418 PartitionInfo
->RewritePartition
= TRUE
;
2422 /* Wipe unused logical partition entries */
2423 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2427 DPRINT1("Logical partition entry %lu\n", Index
);
2429 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2431 if (!IsEmptyLayoutEntry(PartitionInfo
))
2433 DPRINT1("Wiping partition entry %lu\n", Index
);
2435 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2436 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2437 PartitionInfo
->HiddenSectors
= 0;
2438 PartitionInfo
->PartitionNumber
= 0;
2439 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2440 PartitionInfo
->BootIndicator
= FALSE
;
2441 PartitionInfo
->RecognizedPartition
= FALSE
;
2442 PartitionInfo
->RewritePartition
= TRUE
;
2447 DiskEntry
->Dirty
= TRUE
;
2449 #ifdef DUMP_PARTITION_TABLE
2450 DumpPartitionTable(DiskEntry
);
2456 GetPrevUnpartitionedEntry(
2457 IN PDISKENTRY DiskEntry
,
2458 IN PPARTENTRY PartEntry
)
2460 PPARTENTRY PrevPartEntry
;
2461 PLIST_ENTRY ListHead
;
2463 if (PartEntry
->LogicalPartition
)
2464 ListHead
= &DiskEntry
->LogicalPartListHead
;
2466 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2468 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2470 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2473 if (PrevPartEntry
->IsPartitioned
== FALSE
)
2474 return PrevPartEntry
;
2482 GetNextUnpartitionedEntry(
2483 IN PDISKENTRY DiskEntry
,
2484 IN PPARTENTRY PartEntry
)
2486 PPARTENTRY NextPartEntry
;
2487 PLIST_ENTRY ListHead
;
2489 if (PartEntry
->LogicalPartition
)
2490 ListHead
= &DiskEntry
->LogicalPartListHead
;
2492 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2494 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2496 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2499 if (NextPartEntry
->IsPartitioned
== FALSE
)
2500 return NextPartEntry
;
2507 CreatePrimaryPartition(
2509 IN ULONGLONG SectorCount
,
2510 IN BOOLEAN AutoCreate
)
2513 PDISKENTRY DiskEntry
;
2514 PPARTENTRY PartEntry
;
2516 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount
);
2519 List
->CurrentDisk
== NULL
||
2520 List
->CurrentPartition
== NULL
||
2521 List
->CurrentPartition
->IsPartitioned
)
2526 Error
= PrimaryPartitionCreationChecks(List
);
2527 if (Error
!= NOT_AN_ERROR
)
2529 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error
);
2533 DiskEntry
= List
->CurrentDisk
;
2534 PartEntry
= List
->CurrentPartition
;
2536 /* Convert the current entry, or insert and initialize a new partition entry */
2537 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, AutoCreate
);
2538 if (PartEntry
== NULL
)
2541 UpdateDiskLayout(DiskEntry
);
2543 AssignDriveLetters(List
);
2550 AddLogicalDiskSpace(
2551 IN PDISKENTRY DiskEntry
)
2553 ULONGLONG StartSector
;
2554 ULONGLONG SectorCount
;
2555 PPARTENTRY NewPartEntry
;
2557 DPRINT1("AddLogicalDiskSpace()\n");
2559 /* Create a partition entry that represents the empty space in the container partition */
2561 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2562 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2564 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
2565 &DiskEntry
->LogicalPartListHead
,
2569 if (NewPartEntry
== NULL
)
2571 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2574 NewPartEntry
->LogicalPartition
= TRUE
;
2578 CreateExtendedPartition(
2580 IN ULONGLONG SectorCount
)
2583 PDISKENTRY DiskEntry
;
2584 PPARTENTRY PartEntry
;
2586 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount
);
2589 List
->CurrentDisk
== NULL
||
2590 List
->CurrentPartition
== NULL
||
2591 List
->CurrentPartition
->IsPartitioned
)
2596 Error
= ExtendedPartitionCreationChecks(List
);
2597 if (Error
!= NOT_AN_ERROR
)
2599 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error
);
2603 DiskEntry
= List
->CurrentDisk
;
2604 PartEntry
= List
->CurrentPartition
;
2606 /* Convert the current entry, or insert and initialize a new partition entry */
2607 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, FALSE
);
2608 if (PartEntry
== NULL
)
2611 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2613 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2614 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2618 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2619 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2622 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2623 PartEntry
->New
= FALSE
;
2624 PartEntry
->FormatState
= Formatted
;
2626 DiskEntry
->ExtendedPartition
= PartEntry
;
2628 AddLogicalDiskSpace(DiskEntry
);
2630 UpdateDiskLayout(DiskEntry
);
2632 AssignDriveLetters(List
);
2638 CreateLogicalPartition(
2640 IN ULONGLONG SectorCount
,
2641 IN BOOLEAN AutoCreate
)
2644 PDISKENTRY DiskEntry
;
2645 PPARTENTRY PartEntry
;
2647 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount
);
2650 List
->CurrentDisk
== NULL
||
2651 List
->CurrentPartition
== NULL
||
2652 List
->CurrentPartition
->IsPartitioned
)
2657 Error
= LogicalPartitionCreationChecks(List
);
2658 if (Error
!= NOT_AN_ERROR
)
2660 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error
);
2664 DiskEntry
= List
->CurrentDisk
;
2665 PartEntry
= List
->CurrentPartition
;
2667 /* Convert the current entry, or insert and initialize a new partition entry */
2668 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, AutoCreate
);
2669 if (PartEntry
== NULL
)
2672 PartEntry
->LogicalPartition
= TRUE
;
2674 UpdateDiskLayout(DiskEntry
);
2676 AssignDriveLetters(List
);
2684 IN PPARTENTRY PartEntry
)
2687 NTSTATUS LockStatus
;
2688 UNICODE_STRING Name
;
2689 OBJECT_ATTRIBUTES ObjectAttributes
;
2690 IO_STATUS_BLOCK IoStatusBlock
;
2691 HANDLE PartitionHandle
;
2692 WCHAR Buffer
[MAX_PATH
];
2694 /* Check whether the partition is valid and may have been mounted in the system */
2695 if (!PartEntry
->IsPartitioned
||
2696 PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2697 IsContainerPartition(PartEntry
->PartitionType
) ||
2698 !IsRecognizedPartition(PartEntry
->PartitionType
) ||
2699 PartEntry
->FormatState
== Unformatted
/* || PartEntry->FormatState == UnknownFormat */ ||
2700 PartEntry
->FileSystem
== NULL
||
2701 PartEntry
->PartitionNumber
== 0)
2703 /* The partition is not mounted, so just return success */
2704 return STATUS_SUCCESS
;
2707 /* Open the volume */
2708 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
2709 L
"\\Device\\Harddisk%lu\\Partition%lu",
2710 PartEntry
->DiskEntry
->DiskNumber
,
2711 PartEntry
->PartitionNumber
);
2712 RtlInitUnicodeString(&Name
, Buffer
);
2714 InitializeObjectAttributes(&ObjectAttributes
,
2716 OBJ_CASE_INSENSITIVE
,
2720 Status
= NtOpenFile(&PartitionHandle
,
2721 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
2724 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2725 FILE_SYNCHRONOUS_IO_NONALERT
);
2726 if (!NT_SUCCESS(Status
))
2728 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name
, Status
);
2732 /* Lock the volume */
2733 LockStatus
= NtFsControlFile(PartitionHandle
,
2743 if (!NT_SUCCESS(LockStatus
))
2745 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus
);
2748 /* Dismount the volume */
2749 Status
= NtFsControlFile(PartitionHandle
,
2754 FSCTL_DISMOUNT_VOLUME
,
2759 if (!NT_SUCCESS(Status
))
2761 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status
);
2764 /* Unlock the volume */
2765 LockStatus
= NtFsControlFile(PartitionHandle
,
2770 FSCTL_UNLOCK_VOLUME
,
2775 if (!NT_SUCCESS(LockStatus
))
2777 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus
);
2780 /* Close the volume */
2781 NtClose(PartitionHandle
);
2787 DeleteCurrentPartition(
2790 PDISKENTRY DiskEntry
;
2791 PPARTENTRY PartEntry
;
2792 PPARTENTRY PrevPartEntry
;
2793 PPARTENTRY NextPartEntry
;
2794 PPARTENTRY LogicalPartEntry
;
2798 List
->CurrentDisk
== NULL
||
2799 List
->CurrentPartition
== NULL
||
2800 List
->CurrentPartition
->IsPartitioned
== FALSE
)
2805 /* Clear the system disk and partition pointers if the system partition is being deleted */
2806 if (List
->SystemPartition
== List
->CurrentPartition
)
2808 List
->SystemPartition
= NULL
;
2811 DiskEntry
= List
->CurrentDisk
;
2812 PartEntry
= List
->CurrentPartition
;
2814 /* Check which type of partition (primary/logical or extended) is being deleted */
2815 if (DiskEntry
->ExtendedPartition
== PartEntry
)
2817 /* An extended partition is being deleted: delete all logical partition entries */
2818 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
2820 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
2821 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2823 /* Dismount the logical partition */
2824 DismountVolume(LogicalPartEntry
);
2827 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
2830 DiskEntry
->ExtendedPartition
= NULL
;
2834 /* A primary partition is being deleted: dismount it */
2835 DismountVolume(PartEntry
);
2838 /* Adjust unpartitioned disk space entries */
2840 /* Get pointer to previous and next unpartitioned entries */
2841 PrevPartEntry
= GetPrevUnpartitionedEntry(DiskEntry
, PartEntry
);
2842 NextPartEntry
= GetNextUnpartitionedEntry(DiskEntry
, PartEntry
);
2844 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
2846 /* Merge previous, current and next unpartitioned entry */
2848 /* Adjust the previous entries length */
2849 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
2851 /* Remove the current entry */
2852 RemoveEntryList(&PartEntry
->ListEntry
);
2853 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2855 /* Remove the next entry */
2856 RemoveEntryList(&NextPartEntry
->ListEntry
);
2857 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
2859 /* Update current partition */
2860 List
->CurrentPartition
= PrevPartEntry
;
2862 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
2864 /* Merge current and previous unpartitioned entry */
2866 /* Adjust the previous entries length */
2867 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2869 /* Remove the current entry */
2870 RemoveEntryList(&PartEntry
->ListEntry
);
2871 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2873 /* Update current partition */
2874 List
->CurrentPartition
= PrevPartEntry
;
2876 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
2878 /* Merge current and next unpartitioned entry */
2880 /* Adjust the next entries offset and length */
2881 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
2882 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2884 /* Remove the current entry */
2885 RemoveEntryList(&PartEntry
->ListEntry
);
2886 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2888 /* Update current partition */
2889 List
->CurrentPartition
= NextPartEntry
;
2893 /* Nothing to merge but change current entry */
2894 PartEntry
->IsPartitioned
= FALSE
;
2895 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2896 PartEntry
->FormatState
= Unformatted
;
2897 PartEntry
->FileSystem
= NULL
;
2898 PartEntry
->DriveLetter
= 0;
2899 PartEntry
->OnDiskPartitionNumber
= 0;
2900 PartEntry
->PartitionNumber
= 0;
2901 // PartEntry->PartitionIndex = 0;
2904 UpdateDiskLayout(DiskEntry
);
2906 AssignDriveLetters(List
);
2910 CheckActiveSystemPartition(
2913 PDISKENTRY DiskEntry
;
2914 PPARTENTRY PartEntry
;
2915 PLIST_ENTRY ListEntry
;
2917 PFILE_SYSTEM FileSystem
;
2919 /* Check for empty disk list */
2920 if (IsListEmpty(&List
->DiskListHead
))
2922 List
->SystemPartition
= NULL
;
2923 List
->OriginalSystemPartition
= NULL
;
2927 /* Choose the currently selected disk */
2928 DiskEntry
= List
->CurrentDisk
;
2930 /* Check for empty partition list */
2931 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
2933 List
->SystemPartition
= NULL
;
2934 List
->OriginalSystemPartition
= NULL
;
2938 if (List
->SystemPartition
!= NULL
)
2940 /* We already have an active system partition */
2941 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
2942 List
->SystemPartition
->PartitionNumber
,
2943 List
->SystemPartition
->DiskEntry
->DiskNumber
,
2944 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
2948 DPRINT1("We are here (1)!\n");
2950 List
->SystemPartition
= NULL
;
2951 List
->OriginalSystemPartition
= NULL
;
2953 /* Retrieve the first partition of the disk */
2954 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
2957 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
2958 List
->SystemPartition
= PartEntry
;
2961 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
2964 /* Check if the disk is new and if so, use its first partition as the active system partition */
2965 if (DiskEntry
->NewDisk
)
2967 if (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
== FALSE
)
2969 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
2970 List
->SystemPartition
= PartEntry
;
2972 List
->OriginalSystemPartition
= List
->SystemPartition
;
2974 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
2975 List
->SystemPartition
->PartitionNumber
,
2976 List
->SystemPartition
->DiskEntry
->DiskNumber
,
2977 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
2979 goto SetSystemPartition
;
2982 // FIXME: What to do??
2983 DPRINT1("NewDisk TRUE but first partition is used?\n");
2986 DPRINT1("We are here (2)!\n");
2989 * The disk is not new, check if any partition is initialized;
2990 * if not, the first one becomes the system partition.
2992 ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2993 while (ListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2995 /* Retrieve the partition and go to the next one */
2996 PartEntry
= CONTAINING_RECORD(ListEntry
,
3000 /* Check if the partition is partitioned and is used */
3001 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
!= FALSE
)
3006 /* Go to the next one */
3007 ListEntry
= ListEntry
->Flink
;
3009 if (ListEntry
== &DiskEntry
->PrimaryPartListHead
)
3012 * OK we haven't encountered any used and active partition,
3013 * so use the first one as the system partition.
3015 ASSERT(DiskEntry
== List
->SystemPartition
->DiskEntry
);
3016 List
->OriginalSystemPartition
= List
->SystemPartition
; // First PartEntry
3018 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3019 List
->SystemPartition
->PartitionNumber
,
3020 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3021 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3023 goto SetSystemPartition
;
3026 List
->SystemPartition
= NULL
;
3027 List
->OriginalSystemPartition
= NULL
;
3029 DPRINT1("We are here (3)!\n");
3031 /* The disk is not new, scan all partitions to find the (active) system partition */
3032 ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3033 while (ListEntry
!= &DiskEntry
->PrimaryPartListHead
)
3035 /* Retrieve the partition and go to the next one */
3036 PartEntry
= CONTAINING_RECORD(ListEntry
,
3039 ListEntry
= ListEntry
->Flink
;
3041 /* Check if the partition is partitioned and used */
3042 if (PartEntry
->IsPartitioned
&&
3043 PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
)
3045 /* Check if the partition is active */
3046 if (PartEntry
->BootIndicator
)
3048 /* Yes, we found it */
3049 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3050 List
->SystemPartition
= PartEntry
;
3052 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3053 PartEntry
->PartitionNumber
,
3054 DiskEntry
->DiskNumber
,
3055 (PartEntry
->DriveLetter
== 0) ? L
'-' : PartEntry
->DriveLetter
);
3061 /* Check if we have found the system partition */
3062 if (List
->SystemPartition
== NULL
)
3064 /* Nothing, use the alternative system partition */
3065 DPRINT1("No system partition found, use the alternative partition!\n");
3066 goto UseAlternativeSystemPartition
;
3070 List
->OriginalSystemPartition
= List
->SystemPartition
;
3073 * ADDITIONAL CHECKS / BIG HACK:
3075 * Retrieve its file system and check whether we have
3076 * write support for it. If that is the case we are fine
3077 * and we can use it directly. However if we don't have
3078 * write support we will need to change the active system
3081 * NOTE that this is completely useless on architectures
3082 * where a real system partition is required, as on these
3083 * architectures the partition uses the FAT FS, for which
3084 * we do have write support.
3085 * NOTE also that for those architectures looking for a
3086 * partition boot indicator is insufficient.
3088 FileSystem
= GetFileSystem(List
->OriginalSystemPartition
);
3089 if (FileSystem
== NULL
)
3091 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
3092 List
->OriginalSystemPartition
->PartitionNumber
,
3093 List
->OriginalSystemPartition
->DiskEntry
->DiskNumber
);
3094 goto FindAndUseAlternativeSystemPartition
;
3096 // HACK: WARNING: We cannot write on this FS yet!
3097 // See fsutil.c:GetFileSystem()
3098 if (List
->OriginalSystemPartition
->PartitionType
== PARTITION_IFS
)
3100 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
3101 FileSystem
->FileSystemName
);
3102 goto FindAndUseAlternativeSystemPartition
;
3105 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3106 List
->SystemPartition
->PartitionNumber
,
3107 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3108 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3112 FindAndUseAlternativeSystemPartition
:
3114 * We are here because we have not found any (active) candidate
3115 * system partition that we know how to support. What we are going
3116 * to do is to change the existing system partition and use the
3117 * partition on which we install ReactOS as the new system partition,
3118 * and then we will need to add in FreeLdr's entry a boot entry to boot
3119 * from the original system partition.
3122 /* Unset the old system partition */
3123 List
->SystemPartition
->BootIndicator
= FALSE
;
3124 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= FALSE
;
3125 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3126 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3128 UseAlternativeSystemPartition
:
3129 List
->SystemPartition
= List
->CurrentPartition
;
3131 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3132 List
->SystemPartition
->PartitionNumber
,
3133 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3134 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3137 /* Set the new active system partition */
3138 List
->SystemPartition
->BootIndicator
= TRUE
;
3139 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= TRUE
;
3140 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3141 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3148 IN PDISKENTRY DiskEntry
)
3151 OBJECT_ATTRIBUTES ObjectAttributes
;
3152 UNICODE_STRING Name
;
3154 IO_STATUS_BLOCK Iosb
;
3156 PPARTITION_INFORMATION PartitionInfo
;
3157 ULONG PartitionCount
;
3158 PLIST_ENTRY ListEntry
;
3159 PPARTENTRY PartEntry
;
3160 WCHAR DstPath
[MAX_PATH
];
3162 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3164 RtlStringCchPrintfW(DstPath
, ARRAYSIZE(DstPath
),
3165 L
"\\Device\\Harddisk%lu\\Partition0",
3166 DiskEntry
->DiskNumber
);
3167 RtlInitUnicodeString(&Name
, DstPath
);
3169 InitializeObjectAttributes(&ObjectAttributes
,
3171 OBJ_CASE_INSENSITIVE
,
3175 Status
= NtOpenFile(&FileHandle
,
3176 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3180 FILE_SYNCHRONOUS_IO_NONALERT
);
3181 if (!NT_SUCCESS(Status
))
3183 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3187 #ifdef DUMP_PARTITION_TABLE
3188 DumpPartitionTable(DiskEntry
);
3192 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3193 // the disk in MBR or GPT format in case the disk was not initialized!!
3194 // For this we must ask the user which format to use.
3197 /* Save the original partition count to be restored later (see comment below) */
3198 PartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
3200 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3201 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3202 ((PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3203 Status
= NtDeviceIoControlFile(FileHandle
,
3208 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3209 DiskEntry
->LayoutBuffer
,
3211 DiskEntry
->LayoutBuffer
,
3213 NtClose(FileHandle
);
3216 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3217 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3218 * where such a table is expected to enumerate up to 4 partitions:
3219 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3220 * Due to this we need to restore the original PartitionCount number.
3222 DiskEntry
->LayoutBuffer
->PartitionCount
= PartitionCount
;
3224 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3225 if (!NT_SUCCESS(Status
))
3227 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3231 #ifdef DUMP_PARTITION_TABLE
3232 DumpPartitionTable(DiskEntry
);
3235 /* Update the partition numbers */
3237 /* Update the primary partition table */
3238 ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3239 while (ListEntry
!= &DiskEntry
->PrimaryPartListHead
)
3241 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3243 if (PartEntry
->IsPartitioned
)
3245 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3246 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3249 ListEntry
= ListEntry
->Flink
;
3252 /* Update the logical partition table */
3253 ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
3254 while (ListEntry
!= &DiskEntry
->LogicalPartListHead
)
3256 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3258 if (PartEntry
->IsPartitioned
)
3260 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3261 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3264 ListEntry
= ListEntry
->Flink
;
3268 // NOTE: Originally (see r40437), we used to install here also a new MBR
3269 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3270 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3271 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3272 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3273 // was called too, the installation test was modified by checking whether
3274 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3277 // DiskEntry->Dirty = FALSE;
3283 WritePartitionsToDisk(
3287 PDISKENTRY DiskEntry
;
3292 Entry
= List
->DiskListHead
.Flink
;
3293 while (Entry
!= &List
->DiskListHead
)
3295 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3297 if (DiskEntry
->Dirty
!= FALSE
)
3299 WritePartitions(List
, DiskEntry
);
3300 DiskEntry
->Dirty
= FALSE
;
3303 Entry
= Entry
->Flink
;
3310 SetMountedDeviceValue(
3313 IN LARGE_INTEGER StartingOffset
)
3315 OBJECT_ATTRIBUTES ObjectAttributes
;
3316 WCHAR ValueNameBuffer
[16];
3317 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3318 UNICODE_STRING ValueName
;
3319 REG_DISK_MOUNT_INFO MountInfo
;
3323 RtlStringCchPrintfW(ValueNameBuffer
, ARRAYSIZE(ValueNameBuffer
),
3324 L
"\\DosDevices\\%c:", Letter
);
3325 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
3327 InitializeObjectAttributes(&ObjectAttributes
,
3329 OBJ_CASE_INSENSITIVE
,
3333 Status
= NtOpenKey(&KeyHandle
,
3336 if (!NT_SUCCESS(Status
))
3338 Status
= NtCreateKey(&KeyHandle
,
3343 REG_OPTION_NON_VOLATILE
,
3347 if (!NT_SUCCESS(Status
))
3349 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
3353 MountInfo
.Signature
= Signature
;
3354 MountInfo
.StartingOffset
= StartingOffset
;
3355 Status
= NtSetValueKey(KeyHandle
,
3362 if (!NT_SUCCESS(Status
))
3364 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
3372 SetMountedDeviceValues(
3375 PLIST_ENTRY Entry1
, Entry2
;
3376 PDISKENTRY DiskEntry
;
3377 PPARTENTRY PartEntry
;
3378 LARGE_INTEGER StartingOffset
;
3383 Entry1
= List
->DiskListHead
.Flink
;
3384 while (Entry1
!= &List
->DiskListHead
)
3386 DiskEntry
= CONTAINING_RECORD(Entry1
,
3390 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3391 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
3393 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3394 if (PartEntry
->IsPartitioned
)
3396 /* Assign a "\DosDevices\#:" mount point to this partition */
3397 if (PartEntry
->DriveLetter
)
3399 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3400 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3401 DiskEntry
->LayoutBuffer
->Signature
,
3409 Entry2
= Entry2
->Flink
;
3412 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3413 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
3415 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3416 if (PartEntry
->IsPartitioned
)
3418 /* Assign a "\DosDevices\#:" mount point to this partition */
3419 if (PartEntry
->DriveLetter
)
3421 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3422 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3423 DiskEntry
->LayoutBuffer
->Signature
,
3431 Entry2
= Entry2
->Flink
;
3434 Entry1
= Entry1
->Flink
;
3442 IN PPARTENTRY PartEntry
,
3443 IN UCHAR PartitionType
)
3445 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3447 PartEntry
->PartitionType
= PartitionType
;
3449 DiskEntry
->Dirty
= TRUE
;
3450 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].PartitionType
= PartitionType
;
3451 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RecognizedPartition
= IsRecognizedPartition(PartitionType
);
3452 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3456 PrimaryPartitionCreationChecks(
3459 PDISKENTRY DiskEntry
;
3460 PPARTENTRY PartEntry
;
3462 DiskEntry
= List
->CurrentDisk
;
3463 PartEntry
= List
->CurrentPartition
;
3465 /* Fail if the partition is already in use */
3466 if (PartEntry
->IsPartitioned
)
3467 return ERROR_NEW_PARTITION
;
3469 /* Fail if there are already 4 primary partitions in the list */
3470 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3471 return ERROR_PARTITION_TABLE_FULL
;
3473 return ERROR_SUCCESS
;
3477 ExtendedPartitionCreationChecks(
3480 PDISKENTRY DiskEntry
;
3481 PPARTENTRY PartEntry
;
3483 DiskEntry
= List
->CurrentDisk
;
3484 PartEntry
= List
->CurrentPartition
;
3486 /* Fail if the partition is already in use */
3487 if (PartEntry
->IsPartitioned
)
3488 return ERROR_NEW_PARTITION
;
3490 /* Fail if there are already 4 primary partitions in the list */
3491 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3492 return ERROR_PARTITION_TABLE_FULL
;
3494 /* Fail if there is another extended partition in the list */
3495 if (DiskEntry
->ExtendedPartition
!= NULL
)
3496 return ERROR_ONLY_ONE_EXTENDED
;
3498 return ERROR_SUCCESS
;
3502 LogicalPartitionCreationChecks(
3505 // PDISKENTRY DiskEntry;
3506 PPARTENTRY PartEntry
;
3508 // DiskEntry = List->CurrentDisk;
3509 PartEntry
= List
->CurrentPartition
;
3511 /* Fail if the partition is already in use */
3512 if (PartEntry
->IsPartitioned
)
3513 return ERROR_NEW_PARTITION
;
3515 return ERROR_SUCCESS
;
3519 GetNextUnformattedPartition(
3521 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3522 OUT PPARTENTRY
*pPartEntry
)
3524 PLIST_ENTRY Entry1
, Entry2
;
3525 PDISKENTRY DiskEntry
;
3526 PPARTENTRY PartEntry
;
3528 Entry1
= List
->DiskListHead
.Flink
;
3529 while (Entry1
!= &List
->DiskListHead
)
3531 DiskEntry
= CONTAINING_RECORD(Entry1
,
3535 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3536 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
3538 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3539 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3541 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3542 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3543 *pPartEntry
= PartEntry
;
3547 Entry2
= Entry2
->Flink
;
3550 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3551 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
3553 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3554 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3556 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3557 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3558 *pPartEntry
= PartEntry
;
3562 Entry2
= Entry2
->Flink
;
3565 Entry1
= Entry1
->Flink
;
3568 if (pDiskEntry
) *pDiskEntry
= NULL
;
3575 GetNextUncheckedPartition(
3577 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3578 OUT PPARTENTRY
*pPartEntry
)
3580 PLIST_ENTRY Entry1
, Entry2
;
3581 PDISKENTRY DiskEntry
;
3582 PPARTENTRY PartEntry
;
3584 Entry1
= List
->DiskListHead
.Flink
;
3585 while (Entry1
!= &List
->DiskListHead
)
3587 DiskEntry
= CONTAINING_RECORD(Entry1
,
3591 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3592 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
3594 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3595 if (PartEntry
->NeedsCheck
== TRUE
)
3597 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3598 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3599 *pPartEntry
= PartEntry
;
3603 Entry2
= Entry2
->Flink
;
3606 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3607 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
3609 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3610 if (PartEntry
->NeedsCheck
== TRUE
)
3612 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3613 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3614 *pPartEntry
= PartEntry
;
3618 Entry2
= Entry2
->Flink
;
3621 Entry1
= Entry1
->Flink
;
3624 if (pDiskEntry
) *pDiskEntry
= NULL
;