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 for (Entry1
= List
->DiskListHead
.Flink
;
328 Entry1
!= &List
->DiskListHead
;
329 Entry1
= Entry1
->Flink
)
331 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
333 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
334 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
335 Entry2
= Entry2
->Flink
)
337 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
339 PartEntry
->DriveLetter
= 0;
341 if (PartEntry
->IsPartitioned
&&
342 !IsContainerPartition(PartEntry
->PartitionType
))
344 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
345 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
346 PartEntry
->SectorCount
.QuadPart
!= 0LL))
350 PartEntry
->DriveLetter
= Letter
;
358 /* Assign drive letters to logical drives */
359 for (Entry1
= List
->DiskListHead
.Flink
;
360 Entry1
!= &List
->DiskListHead
;
361 Entry1
= Entry1
->Flink
)
363 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
365 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
366 Entry2
!= &DiskEntry
->LogicalPartListHead
;
367 Entry2
= Entry2
->Flink
)
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
;
392 DiskIdentifierQueryRoutine(
400 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
401 UNICODE_STRING NameU
;
403 if (ValueType
== REG_SZ
&&
404 ValueLength
== 20 * sizeof(WCHAR
))
406 NameU
.Buffer
= (PWCHAR
)ValueData
;
407 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
408 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
410 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
411 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
413 return STATUS_SUCCESS
;
416 return STATUS_UNSUCCESSFUL
;
421 DiskConfigurationDataQueryRoutine(
429 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
430 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
431 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
434 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
435 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
436 return STATUS_UNSUCCESSFUL
;
438 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
440 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
442 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
443 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
444 return STATUS_UNSUCCESSFUL
;
447 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
449 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
450 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
453 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
454 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
456 return STATUS_SUCCESS
;
459 return STATUS_UNSUCCESSFUL
;
464 SystemConfigurationDataQueryRoutine(
472 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
473 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
476 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
477 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
478 return STATUS_UNSUCCESSFUL
;
480 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
482 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
484 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
485 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
486 return STATUS_UNSUCCESSFUL
;
489 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
491 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
492 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
495 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(ProcessHeap
, 0,
496 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
497 if (*Int13Drives
== NULL
)
498 return STATUS_NO_MEMORY
;
501 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
502 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
503 return STATUS_SUCCESS
;
506 return STATUS_UNSUCCESSFUL
;
511 EnumerateBiosDiskEntries(
512 IN PPARTLIST PartList
)
514 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
519 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
520 PBIOSDISKENTRY BiosDiskEntry
;
522 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
524 memset(QueryTable
, 0, sizeof(QueryTable
));
526 QueryTable
[1].Name
= L
"Configuration Data";
527 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
529 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
530 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
543 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
545 ROOT_NAME
, AdapterCount
);
546 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
551 if (!NT_SUCCESS(Status
))
556 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
557 L
"%s\\%lu\\DiskController",
558 ROOT_NAME
, AdapterCount
);
559 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
564 if (NT_SUCCESS(Status
))
568 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
569 L
"%s\\%lu\\DiskController\\0",
570 ROOT_NAME
, AdapterCount
);
571 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
576 if (!NT_SUCCESS(Status
))
578 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
582 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
583 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral",
584 ROOT_NAME
, AdapterCount
);
585 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
590 if (NT_SUCCESS(Status
))
592 QueryTable
[0].Name
= L
"Identifier";
593 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
594 QueryTable
[1].Name
= L
"Configuration Data";
595 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
600 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
601 if (BiosDiskEntry
== NULL
)
606 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
607 L
"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
608 ROOT_NAME
, AdapterCount
, DiskCount
);
609 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
612 (PVOID
)BiosDiskEntry
,
614 if (!NT_SUCCESS(Status
))
616 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
620 BiosDiskEntry
->DiskNumber
= DiskCount
;
621 BiosDiskEntry
->Recognized
= FALSE
;
623 if (DiskCount
< Int13Drives
[0].NumberDrives
)
625 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
629 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount
);
632 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
634 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
635 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
636 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
637 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
638 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
639 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
640 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
641 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
642 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
643 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
644 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
650 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
658 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
666 * Inserts the disk region represented by PartEntry into either the primary
667 * or the logical partition list of the given disk.
668 * The lists are kept sorted by increasing order of start sectors.
669 * Of course no disk region should overlap at all with one another.
674 IN PDISKENTRY DiskEntry
,
675 IN PPARTENTRY PartEntry
,
676 IN BOOLEAN LogicalPartition
)
680 PPARTENTRY PartEntry2
;
682 /* Use the correct partition list */
683 if (LogicalPartition
)
684 List
= &DiskEntry
->LogicalPartListHead
;
686 List
= &DiskEntry
->PrimaryPartListHead
;
688 /* Find the first disk region before which we need to insert the new one */
689 for (Entry
= List
->Flink
; Entry
!= List
; Entry
= Entry
->Flink
)
691 PartEntry2
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
693 /* Ignore any unused empty region */
694 if ((PartEntry2
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
695 PartEntry2
->StartSector
.QuadPart
== 0) || PartEntry2
->SectorCount
.QuadPart
== 0)
700 /* If the current region ends before the one to be inserted, try again */
701 if (PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1 < PartEntry
->StartSector
.QuadPart
)
705 * One of the disk region boundaries crosses the desired region
706 * (it starts after the desired region, or ends before the end
707 * of the desired region): this is an impossible situation because
708 * disk regions (partitions) cannot overlap!
709 * Throw an error and bail out.
711 if (max(PartEntry
->StartSector
.QuadPart
, PartEntry2
->StartSector
.QuadPart
)
713 min( PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
714 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1))
716 DPRINT1("Disk region overlap problem, stopping there!\n"
717 "Partition to be inserted:\n"
718 " StartSector = %I64u ; EndSector = %I64u\n"
719 "Existing disk region:\n"
720 " StartSector = %I64u ; EndSector = %I64u\n",
721 PartEntry
->StartSector
.QuadPart
,
722 PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
723 PartEntry2
->StartSector
.QuadPart
,
724 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1);
728 /* We have found the first region before which the new one has to be inserted */
732 /* Insert the disk region */
733 InsertTailList(Entry
, &PartEntry
->ListEntry
);
738 CreateInsertBlankRegion(
739 IN PDISKENTRY DiskEntry
,
740 IN OUT PLIST_ENTRY ListHead
,
741 IN ULONGLONG StartSector
,
742 IN ULONGLONG SectorCount
,
743 IN BOOLEAN LogicalSpace
)
745 PPARTENTRY NewPartEntry
;
747 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
750 if (NewPartEntry
== NULL
)
753 NewPartEntry
->DiskEntry
= DiskEntry
;
755 NewPartEntry
->IsPartitioned
= FALSE
;
756 NewPartEntry
->FormatState
= Unformatted
;
757 NewPartEntry
->FileSystem
= NULL
;
759 NewPartEntry
->StartSector
.QuadPart
= StartSector
;
760 NewPartEntry
->SectorCount
.QuadPart
= SectorCount
;
762 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
763 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
764 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
766 /* Insert the table into the list */
767 InsertTailList(ListHead
, &NewPartEntry
->ListEntry
);
775 InitializePartitionEntry(
776 IN PDISKENTRY DiskEntry
,
777 IN PPARTENTRY PartEntry
,
778 IN ULONGLONG SectorCount
,
779 IN BOOLEAN AutoCreate
)
781 PPARTENTRY NewPartEntry
;
783 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
785 if ((AutoCreate
!= FALSE
) ||
786 (AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
787 PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
))
789 DPRINT1("Convert existing partition entry\n");
791 /* Convert current entry to 'new (unformatted)' */
792 PartEntry
->IsPartitioned
= TRUE
;
793 PartEntry
->New
= TRUE
;
794 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
795 PartEntry
->FormatState
= Unformatted
;
796 PartEntry
->FileSystem
= NULL
;
797 PartEntry
->AutoCreate
= AutoCreate
;
798 PartEntry
->BootIndicator
= FALSE
;
799 PartEntry
->LogicalPartition
= FALSE
;
801 NewPartEntry
= PartEntry
;
805 DPRINT1("Add new partition entry\n");
807 /* Insert and initialize a new partition entry */
808 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
811 if (NewPartEntry
== NULL
)
814 /* Insert the new entry into the list */
815 InsertTailList(&PartEntry
->ListEntry
,
816 &NewPartEntry
->ListEntry
);
818 NewPartEntry
->DiskEntry
= DiskEntry
;
820 NewPartEntry
->IsPartitioned
= TRUE
;
821 NewPartEntry
->New
= TRUE
;
822 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
823 NewPartEntry
->FormatState
= Unformatted
;
824 NewPartEntry
->FileSystem
= NULL
;
825 NewPartEntry
->BootIndicator
= FALSE
;
826 NewPartEntry
->LogicalPartition
= FALSE
;
828 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
829 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
830 NewPartEntry
->StartSector
.QuadPart
;
832 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
833 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
836 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
837 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
838 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
848 IN PDISKENTRY DiskEntry
,
849 IN ULONG PartitionIndex
,
850 IN BOOLEAN LogicalPartition
)
853 PPARTITION_INFORMATION PartitionInfo
;
854 PPARTENTRY PartEntry
;
856 OBJECT_ATTRIBUTES ObjectAttributes
;
857 IO_STATUS_BLOCK IoStatusBlock
;
858 WCHAR Buffer
[MAX_PATH
];
860 UCHAR LabelBuffer
[sizeof(FILE_FS_VOLUME_INFORMATION
) + 256 * sizeof(WCHAR
)];
861 PFILE_FS_VOLUME_INFORMATION LabelInfo
= (PFILE_FS_VOLUME_INFORMATION
)LabelBuffer
;
863 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
865 if (PartitionInfo
->PartitionType
== PARTITION_ENTRY_UNUSED
||
866 ((LogicalPartition
!= FALSE
) && IsContainerPartition(PartitionInfo
->PartitionType
)))
871 PartEntry
= RtlAllocateHeap(ProcessHeap
,
874 if (PartEntry
== NULL
)
877 PartEntry
->DiskEntry
= DiskEntry
;
879 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
880 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
882 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
883 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
884 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
886 PartEntry
->LogicalPartition
= LogicalPartition
;
887 PartEntry
->IsPartitioned
= TRUE
;
888 PartEntry
->OnDiskPartitionNumber
= PartitionInfo
->PartitionNumber
;
889 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
890 PartEntry
->PartitionIndex
= PartitionIndex
;
892 if (IsContainerPartition(PartEntry
->PartitionType
))
894 PartEntry
->FormatState
= Unformatted
;
895 PartEntry
->FileSystem
= NULL
;
897 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
898 DiskEntry
->ExtendedPartition
= PartEntry
;
900 else if (IsRecognizedPartition(PartEntry
->PartitionType
))
902 ASSERT(PartitionInfo
->RecognizedPartition
);
904 PartEntry
->FileSystem
= GetFileSystem(PartEntry
);
905 if (PartEntry
->FileSystem
)
906 PartEntry
->FormatState
= Preformatted
;
908 PartEntry
->FormatState
= Unformatted
;
909 // PartEntry->FormatState = UnknownFormat;
913 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
914 PartEntry
->FormatState
= UnknownFormat
;
917 /* Initialize the partition volume label */
918 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
920 /* Open the volume, ignore any errors */
921 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
922 L
"\\Device\\Harddisk%lu\\Partition%lu",
923 DiskEntry
->DiskNumber
,
924 PartEntry
->PartitionNumber
);
925 RtlInitUnicodeString(&Name
, Buffer
);
927 InitializeObjectAttributes(&ObjectAttributes
,
929 OBJ_CASE_INSENSITIVE
,
933 Status
= NtOpenFile(&FileHandle
,
934 FILE_READ_DATA
| SYNCHRONIZE
,
937 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
938 FILE_SYNCHRONOUS_IO_NONALERT
);
939 if (NT_SUCCESS(Status
))
941 /* Retrieve the partition volume label */
942 Status
= NtQueryVolumeInformationFile(FileHandle
,
946 FileFsVolumeInformation
);
947 /* Close the handle */
950 /* Check for success */
951 if (NT_SUCCESS(Status
))
953 /* Copy the (possibly truncated) volume label and NULL-terminate it */
954 RtlStringCbCopyNW(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
),
955 LabelInfo
->VolumeLabel
, LabelInfo
->VolumeLabelLength
);
959 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status
);
964 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status
);
967 InsertDiskRegion(DiskEntry
, PartEntry
, LogicalPartition
);
972 ScanForUnpartitionedDiskSpace(
973 IN PDISKENTRY DiskEntry
)
975 ULONGLONG StartSector
;
976 ULONGLONG SectorCount
;
977 ULONGLONG LastStartSector
;
978 ULONGLONG LastSectorCount
;
979 ULONGLONG LastUnusedSectorCount
;
980 PPARTENTRY PartEntry
;
981 PPARTENTRY NewPartEntry
;
984 DPRINT("ScanForUnpartitionedDiskSpace()\n");
986 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
988 DPRINT1("No primary partition!\n");
990 /* Create a partition entry that represents the empty disk */
992 if (DiskEntry
->SectorAlignment
< 2048)
993 StartSector
= 2048ULL;
995 StartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
996 SectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) - StartSector
;
998 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
999 &DiskEntry
->PrimaryPartListHead
,
1003 if (NewPartEntry
== NULL
)
1004 DPRINT1("Failed to create a new empty region for full disk space!\n");
1009 /* Start partition at head 1, cylinder 0 */
1010 if (DiskEntry
->SectorAlignment
< 2048)
1011 LastStartSector
= 2048ULL;
1013 LastStartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1014 LastSectorCount
= 0ULL;
1015 LastUnusedSectorCount
= 0ULL;
1017 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1018 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1019 Entry
= Entry
->Flink
)
1021 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1023 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1024 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1026 LastUnusedSectorCount
=
1027 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
1029 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
1030 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1032 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1034 StartSector
= LastStartSector
+ LastSectorCount
;
1035 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1037 /* Insert the table into the list */
1038 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1039 &PartEntry
->ListEntry
,
1043 if (NewPartEntry
== NULL
)
1045 DPRINT1("Failed to create a new empty region for disk space!\n");
1050 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1051 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1055 /* Check for trailing unpartitioned disk space */
1056 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
1058 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
1060 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1062 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1064 StartSector
= LastStartSector
+ LastSectorCount
;
1065 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1067 /* Append the table to the list */
1068 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1069 &DiskEntry
->PrimaryPartListHead
,
1073 if (NewPartEntry
== NULL
)
1075 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1081 if (DiskEntry
->ExtendedPartition
!= NULL
)
1083 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1085 DPRINT1("No logical partition!\n");
1087 /* Create a partition entry that represents the empty extended partition */
1089 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1090 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
1092 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1093 &DiskEntry
->LogicalPartListHead
,
1097 if (NewPartEntry
== NULL
)
1099 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1102 NewPartEntry
->LogicalPartition
= TRUE
;
1107 /* Start partition at head 1, cylinder 0 */
1108 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1109 LastSectorCount
= 0ULL;
1110 LastUnusedSectorCount
= 0ULL;
1112 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1113 Entry
!= &DiskEntry
->LogicalPartListHead
;
1114 Entry
= Entry
->Flink
)
1116 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1118 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1119 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1121 LastUnusedSectorCount
=
1122 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
1124 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
1125 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1127 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1129 StartSector
= LastStartSector
+ LastSectorCount
;
1130 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1132 /* Insert the table into the list */
1133 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1134 &PartEntry
->ListEntry
,
1138 if (NewPartEntry
== NULL
)
1140 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1143 NewPartEntry
->LogicalPartition
= TRUE
;
1146 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1147 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1151 /* Check for trailing unpartitioned disk space */
1152 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
1154 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+
1155 DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
1156 DiskEntry
->SectorAlignment
);
1158 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1160 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1162 StartSector
= LastStartSector
+ LastSectorCount
;
1163 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1165 /* Append the table to the list */
1166 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1167 &DiskEntry
->LogicalPartListHead
,
1171 if (NewPartEntry
== NULL
)
1173 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1176 NewPartEntry
->LogicalPartition
= TRUE
;
1181 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1188 IN PDISKENTRY DiskEntry
)
1190 LARGE_INTEGER SystemTime
;
1191 TIME_FIELDS TimeFields
;
1193 PDISKENTRY DiskEntry2
;
1196 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1200 NtQuerySystemTime(&SystemTime
);
1201 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1203 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1204 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1205 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1206 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1208 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1213 /* Check if the signature already exist */
1215 * Check also signatures from disks, which are
1216 * not visible (bootable) by the bios.
1218 for (Entry2
= List
->DiskListHead
.Flink
;
1219 Entry2
!= &List
->DiskListHead
;
1220 Entry2
= Entry2
->Flink
)
1222 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1224 if (DiskEntry
!= DiskEntry2
&&
1225 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1229 if (Entry2
== &List
->DiskListHead
)
1236 UpdateDiskSignatures(
1240 PDISKENTRY DiskEntry
;
1242 /* Print partition lines */
1243 for (Entry
= List
->DiskListHead
.Flink
;
1244 Entry
!= &List
->DiskListHead
;
1245 Entry
= Entry
->Flink
)
1247 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1249 if (DiskEntry
->LayoutBuffer
&&
1250 DiskEntry
->LayoutBuffer
->Signature
== 0)
1252 SetDiskSignature(List
, DiskEntry
);
1253 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1261 IN HANDLE FileHandle
,
1262 IN ULONG DiskNumber
,
1265 DISK_GEOMETRY DiskGeometry
;
1266 SCSI_ADDRESS ScsiAddress
;
1267 PDISKENTRY DiskEntry
;
1268 IO_STATUS_BLOCK Iosb
;
1270 PPARTITION_SECTOR Mbr
;
1272 LARGE_INTEGER FileOffset
;
1273 WCHAR Identifier
[20];
1277 PLIST_ENTRY ListEntry
;
1278 PBIOSDISKENTRY BiosDiskEntry
;
1279 ULONG LayoutBufferSize
;
1280 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1282 /* Retrieve the drive geometry */
1283 Status
= NtDeviceIoControlFile(FileHandle
,
1288 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1292 sizeof(DiskGeometry
));
1293 if (!NT_SUCCESS(Status
))
1296 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1297 DiskGeometry
.MediaType
!= RemovableMedia
)
1303 * FIXME: Here we suppose the disk is always SCSI. What if it is
1304 * of another type? To check this we need to retrieve the name of
1305 * the driver the disk device belongs to.
1307 Status
= NtDeviceIoControlFile(FileHandle
,
1312 IOCTL_SCSI_GET_ADDRESS
,
1316 sizeof(ScsiAddress
));
1317 if (!NT_SUCCESS(Status
))
1321 * Check whether the disk is initialized, by looking at its MBR.
1322 * NOTE that this must be generalized to GPT disks as well!
1325 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1327 DiskGeometry
.BytesPerSector
);
1331 FileOffset
.QuadPart
= 0;
1332 Status
= NtReadFile(FileHandle
,
1338 DiskGeometry
.BytesPerSector
,
1341 if (!NT_SUCCESS(Status
))
1343 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1344 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1347 Signature
= Mbr
->Signature
;
1349 /* Calculate the MBR checksum */
1351 Buffer
= (PULONG
)Mbr
;
1352 for (i
= 0; i
< 128; i
++)
1354 Checksum
+= Buffer
[i
];
1356 Checksum
= ~Checksum
+ 1;
1358 RtlStringCchPrintfW(Identifier
, ARRAYSIZE(Identifier
),
1359 L
"%08x-%08x-A", Checksum
, Signature
);
1360 DPRINT("Identifier: %S\n", Identifier
);
1362 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1365 if (DiskEntry
== NULL
)
1367 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1368 DPRINT1("Failed to allocate a new disk entry.\n");
1372 // DiskEntry->Checksum = Checksum;
1373 // DiskEntry->Signature = Signature;
1374 DiskEntry
->BiosFound
= FALSE
;
1377 * Check if this disk has a valid MBR: verify its signature,
1378 * and whether its two first bytes are a valid instruction
1379 * (related to this, see IsThereAValidBootSector() in partlist.c).
1381 if (Mbr
->Magic
!= 0xaa55 || (*(PUSHORT
)Mbr
->BootCode
) == 0x0000)
1382 DiskEntry
->NoMbr
= TRUE
;
1384 DiskEntry
->NoMbr
= FALSE
;
1386 /* Free the MBR sector buffer */
1387 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1390 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1391 ListEntry
!= &List
->BiosDiskListHead
;
1392 ListEntry
= ListEntry
->Flink
)
1394 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1396 * Compare the size from bios and the reported size from driver.
1397 * If we have more than one disk with a zero or with the same signature
1398 * we must create new signatures and reboot. After the reboot,
1399 * it is possible to identify the disks.
1401 if (BiosDiskEntry
->Signature
== Signature
&&
1402 BiosDiskEntry
->Checksum
== Checksum
&&
1403 !BiosDiskEntry
->Recognized
)
1405 if (!DiskEntry
->BiosFound
)
1407 DiskEntry
->BiosDiskNumber
= BiosDiskEntry
->DiskNumber
;
1408 DiskEntry
->BiosFound
= TRUE
;
1409 BiosDiskEntry
->Recognized
= TRUE
;
1413 // FIXME: What to do?
1418 if (!DiskEntry
->BiosFound
)
1421 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1424 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber
);
1428 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1429 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1431 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1432 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1433 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1434 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1436 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1437 DPRINT("TracksPerCylinder %lu\n", DiskEntry
->TracksPerCylinder
);
1438 DPRINT("SectorsPerTrack %lu\n", DiskEntry
->SectorsPerTrack
);
1439 DPRINT("BytesPerSector %lu\n", DiskEntry
->BytesPerSector
);
1441 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1442 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1443 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1445 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1446 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1447 DiskGeometry
.SectorsPerTrack
;
1449 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
.QuadPart
);
1450 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1452 DiskEntry
->DiskNumber
= DiskNumber
;
1453 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1454 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1455 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1457 GetDriverName(DiskEntry
);
1459 * Actually it would be more correct somehow to use:
1461 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1462 * ULONG ReturnedLength;
1464 * Status = NtQueryObject(SomeHandleToTheDisk,
1465 * ObjectNameInformation,
1471 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1474 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1478 * We now retrieve the disk partition layout
1481 /* Allocate a layout buffer with 4 partition entries first */
1482 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1483 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1484 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1487 if (DiskEntry
->LayoutBuffer
== NULL
)
1489 DPRINT1("Failed to allocate the disk layout buffer!\n");
1493 /* Keep looping while the drive layout buffer is too small */
1496 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1497 Status
= NtDeviceIoControlFile(FileHandle
,
1502 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1505 DiskEntry
->LayoutBuffer
,
1507 if (NT_SUCCESS(Status
))
1510 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1512 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1516 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1517 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1519 DiskEntry
->LayoutBuffer
,
1521 if (NewLayoutBuffer
== NULL
)
1523 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1527 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1530 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1532 #ifdef DUMP_PARTITION_TABLE
1533 DumpPartitionTable(DiskEntry
);
1536 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1537 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1538 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= PARTITION_ENTRY_UNUSED
)
1540 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1542 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1544 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1546 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1550 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1555 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1558 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1560 DiskEntry
->NewDisk
= TRUE
;
1561 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1563 for (i
= 0; i
< 4; i
++)
1565 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1570 /* Enumerate and add the first four primary partitions */
1571 for (i
= 0; i
< 4; i
++)
1573 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, FALSE
);
1576 /* Enumerate and add the remaining partitions as logical ones */
1577 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1579 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, TRUE
);
1583 ScanForUnpartitionedDiskSpace(DiskEntry
);
1587 CreatePartitionList(VOID
)
1590 OBJECT_ATTRIBUTES ObjectAttributes
;
1591 SYSTEM_DEVICE_INFORMATION Sdi
;
1592 IO_STATUS_BLOCK Iosb
;
1596 WCHAR Buffer
[MAX_PATH
];
1597 UNICODE_STRING Name
;
1600 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1606 List
->CurrentDisk
= NULL
;
1607 List
->CurrentPartition
= NULL
;
1609 List
->SystemPartition
= NULL
;
1610 List
->OriginalSystemPartition
= NULL
;
1612 InitializeListHead(&List
->DiskListHead
);
1613 InitializeListHead(&List
->BiosDiskListHead
);
1616 * Enumerate the disks seen by the BIOS; this will be used later
1617 * to map drives seen by NTOS with their corresponding BIOS names.
1619 EnumerateBiosDiskEntries(List
);
1621 /* Enumerate disks seen by NTOS */
1622 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1626 if (!NT_SUCCESS(Status
))
1628 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status
);
1629 RtlFreeHeap(ProcessHeap
, 0, List
);
1633 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1635 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
1636 L
"\\Device\\Harddisk%lu\\Partition0",
1638 RtlInitUnicodeString(&Name
, Buffer
);
1640 InitializeObjectAttributes(&ObjectAttributes
,
1642 OBJ_CASE_INSENSITIVE
,
1646 Status
= NtOpenFile(&FileHandle
,
1647 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1650 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1651 FILE_SYNCHRONOUS_IO_NONALERT
);
1652 if (NT_SUCCESS(Status
))
1654 AddDiskToList(FileHandle
, DiskNumber
, List
);
1655 NtClose(FileHandle
);
1659 UpdateDiskSignatures(List
);
1661 AssignDriveLetters(List
);
1663 /* Search for first usable disk and partition */
1664 if (IsListEmpty(&List
->DiskListHead
))
1666 List
->CurrentDisk
= NULL
;
1667 List
->CurrentPartition
= NULL
;
1671 List
->CurrentDisk
= CONTAINING_RECORD(List
->DiskListHead
.Flink
,
1675 if (IsListEmpty(&List
->CurrentDisk
->PrimaryPartListHead
))
1677 List
->CurrentPartition
= NULL
;
1681 List
->CurrentPartition
= CONTAINING_RECORD(List
->CurrentDisk
->PrimaryPartListHead
.Flink
,
1691 DestroyPartitionList(
1694 PDISKENTRY DiskEntry
;
1695 PBIOSDISKENTRY BiosDiskEntry
;
1696 PPARTENTRY PartEntry
;
1699 /* Release disk and partition info */
1700 while (!IsListEmpty(&List
->DiskListHead
))
1702 Entry
= RemoveHeadList(&List
->DiskListHead
);
1703 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1705 /* Release driver name */
1706 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1708 /* Release primary partition list */
1709 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1711 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1712 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1714 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1717 /* Release logical partition list */
1718 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1720 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1721 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1723 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1726 /* Release layout buffer */
1727 if (DiskEntry
->LayoutBuffer
!= NULL
)
1728 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1730 /* Release disk entry */
1731 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1734 /* Release the bios disk info */
1735 while (!IsListEmpty(&List
->BiosDiskListHead
))
1737 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1738 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1740 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
1743 /* Release list head */
1744 RtlFreeHeap(ProcessHeap
, 0, List
);
1748 GetDiskByBiosNumber(
1750 IN ULONG BiosDiskNumber
)
1752 PDISKENTRY DiskEntry
;
1755 /* Loop over the disks and find the correct one */
1756 for (Entry
= List
->DiskListHead
.Flink
;
1757 Entry
!= &List
->DiskListHead
;
1758 Entry
= Entry
->Flink
)
1760 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1762 if (DiskEntry
->BiosDiskNumber
== BiosDiskNumber
)
1769 /* Disk not found, stop there */
1776 IN ULONG DiskNumber
)
1778 PDISKENTRY DiskEntry
;
1781 /* Loop over the disks and find the correct one */
1782 for (Entry
= List
->DiskListHead
.Flink
;
1783 Entry
!= &List
->DiskListHead
;
1784 Entry
= Entry
->Flink
)
1786 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1788 if (DiskEntry
->DiskNumber
== DiskNumber
)
1795 /* Disk not found, stop there */
1806 PDISKENTRY DiskEntry
;
1809 /* Loop over the disks and find the correct one */
1810 for (Entry
= List
->DiskListHead
.Flink
;
1811 Entry
!= &List
->DiskListHead
;
1812 Entry
= Entry
->Flink
)
1814 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1816 if (DiskEntry
->Port
== Port
&&
1817 DiskEntry
->Bus
== Bus
&&
1818 DiskEntry
->Id
== Id
)
1825 /* Disk not found, stop there */
1834 PDISKENTRY DiskEntry
;
1837 /* Loop over the disks and find the correct one */
1838 for (Entry
= List
->DiskListHead
.Flink
;
1839 Entry
!= &List
->DiskListHead
;
1840 Entry
= Entry
->Flink
)
1842 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1844 if (DiskEntry
->LayoutBuffer
->Signature
== Signature
)
1851 /* Disk not found, stop there */
1857 // IN PPARTLIST List,
1858 IN PDISKENTRY DiskEntry
,
1859 IN ULONG PartitionNumber
)
1861 PPARTENTRY PartEntry
;
1864 /* Disk found, loop over the primary partitions first... */
1865 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1866 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1867 Entry
= Entry
->Flink
)
1869 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1871 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1873 /* Partition found */
1878 /* ... then over the logical partitions if needed */
1879 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1880 Entry
!= &DiskEntry
->LogicalPartListHead
;
1881 Entry
= Entry
->Flink
)
1883 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1885 if (PartEntry
->PartitionNumber
== PartitionNumber
)
1887 /* Partition found */
1892 /* The partition was not found on the disk, stop there */
1899 IN ULONG DiskNumber
,
1900 IN ULONG PartitionNumber OPTIONAL
,
1901 OUT PDISKENTRY
* pDiskEntry
,
1902 OUT PPARTENTRY
* pPartEntry OPTIONAL
)
1904 PDISKENTRY DiskEntry
;
1905 PPARTENTRY PartEntry
= NULL
;
1908 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
1912 /* If we have a partition (PartitionNumber != 0), find it */
1913 if (PartitionNumber
!= 0)
1915 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
1918 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
1921 /* Return the disk (and optionally the partition) */
1922 *pDiskEntry
= DiskEntry
;
1923 if (pPartEntry
) *pPartEntry
= PartEntry
;
1928 // NOTE: Was introduced broken in r6258 by Casper
1933 IN ULONG DiskNumber
,
1934 IN ULONG PartitionNumber
)
1936 PDISKENTRY DiskEntry
;
1937 PPARTENTRY PartEntry
;
1939 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
1943 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
1947 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
1948 ASSERT(DiskEntry
->DiskNumber
== DiskNumber
);
1949 ASSERT(PartEntry
->PartitionNumber
== PartitionNumber
);
1951 List
->CurrentDisk
= DiskEntry
;
1952 List
->CurrentPartition
= PartEntry
;
1960 PLIST_ENTRY DiskListEntry
;
1961 PLIST_ENTRY PartListEntry
;
1962 PDISKENTRY DiskEntry
;
1963 PPARTENTRY PartEntry
;
1965 /* Fail if no disks are available */
1966 if (IsListEmpty(&List
->DiskListHead
))
1969 /* Check for next usable entry on current disk */
1970 if (List
->CurrentPartition
!= NULL
)
1972 if (List
->CurrentPartition
->LogicalPartition
)
1974 /* Logical partition */
1976 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
1977 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
1979 /* Next logical partition */
1980 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
1982 List
->CurrentPartition
= PartEntry
;
1983 return List
->CurrentPartition
;
1987 PartListEntry
= List
->CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
1988 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
1990 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
1992 List
->CurrentPartition
= PartEntry
;
1993 return List
->CurrentPartition
;
1999 /* Primary or extended partition */
2001 if (List
->CurrentPartition
->IsPartitioned
&&
2002 IsContainerPartition(List
->CurrentPartition
->PartitionType
))
2004 /* First logical partition */
2005 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Flink
;
2006 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2008 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2010 List
->CurrentPartition
= PartEntry
;
2011 return List
->CurrentPartition
;
2016 /* Next primary partition */
2017 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2018 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2020 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2022 List
->CurrentPartition
= PartEntry
;
2023 return List
->CurrentPartition
;
2029 /* Search for the first partition entry on the next disk */
2030 for (DiskListEntry
= List
->CurrentDisk
->ListEntry
.Flink
;
2031 DiskListEntry
!= &List
->DiskListHead
;
2032 DiskListEntry
= DiskListEntry
->Flink
)
2034 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2036 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2037 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2039 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2041 List
->CurrentDisk
= DiskEntry
;
2042 List
->CurrentPartition
= PartEntry
;
2043 return List
->CurrentPartition
;
2054 PLIST_ENTRY DiskListEntry
;
2055 PLIST_ENTRY PartListEntry
;
2056 PDISKENTRY DiskEntry
;
2057 PPARTENTRY PartEntry
;
2059 /* Fail if no disks are available */
2060 if (IsListEmpty(&List
->DiskListHead
))
2063 /* Check for previous usable entry on current disk */
2064 if (List
->CurrentPartition
!= NULL
)
2066 if (List
->CurrentPartition
->LogicalPartition
)
2068 /* Logical partition */
2069 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2070 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2072 /* Previous logical partition */
2073 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2077 /* Extended partition */
2078 PartEntry
= List
->CurrentDisk
->ExtendedPartition
;
2081 List
->CurrentPartition
= PartEntry
;
2082 return List
->CurrentPartition
;
2086 /* Primary or extended partition */
2088 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2089 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2091 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2093 if (PartEntry
->IsPartitioned
&&
2094 IsContainerPartition(PartEntry
->PartitionType
))
2096 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Blink
;
2097 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2100 List
->CurrentPartition
= PartEntry
;
2101 return List
->CurrentPartition
;
2106 /* Search for the last partition entry on the previous disk */
2107 for (DiskListEntry
= List
->CurrentDisk
->ListEntry
.Blink
;
2108 DiskListEntry
!= &List
->DiskListHead
;
2109 DiskListEntry
= DiskListEntry
->Blink
)
2111 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2113 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Blink
;
2114 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2116 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2118 if (PartEntry
->IsPartitioned
&&
2119 IsContainerPartition(PartEntry
->PartitionType
))
2121 PartListEntry
= DiskEntry
->LogicalPartListHead
.Blink
;
2122 if (PartListEntry
!= &DiskEntry
->LogicalPartListHead
)
2124 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2126 List
->CurrentDisk
= DiskEntry
;
2127 List
->CurrentPartition
= PartEntry
;
2128 return List
->CurrentPartition
;
2133 List
->CurrentDisk
= DiskEntry
;
2134 List
->CurrentPartition
= PartEntry
;
2135 return List
->CurrentPartition
;
2147 IN PPARTITION_INFORMATION PartitionInfo
)
2149 if (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2150 PartitionInfo
->PartitionLength
.QuadPart
== 0)
2161 IsSamePrimaryLayoutEntry(
2162 IN PPARTITION_INFORMATION PartitionInfo
,
2163 IN PDISKENTRY DiskEntry
,
2164 IN PPARTENTRY PartEntry
)
2166 if (PartitionInfo
->StartingOffset
.QuadPart
== PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
&&
2167 PartitionInfo
->PartitionLength
.QuadPart
== PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
)
2168 // PartitionInfo->PartitionType == PartEntry->PartitionType
2178 GetPrimaryPartitionCount(
2179 IN PDISKENTRY DiskEntry
)
2182 PPARTENTRY PartEntry
;
2185 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2186 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2187 Entry
= Entry
->Flink
)
2189 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2190 if (PartEntry
->IsPartitioned
)
2199 GetLogicalPartitionCount(
2200 IN PDISKENTRY DiskEntry
)
2202 PLIST_ENTRY ListEntry
;
2203 PPARTENTRY PartEntry
;
2206 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2207 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2208 ListEntry
= ListEntry
->Flink
)
2210 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2211 if (PartEntry
->IsPartitioned
)
2220 ReAllocateLayoutBuffer(
2221 IN PDISKENTRY DiskEntry
)
2223 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2224 ULONG NewPartitionCount
;
2225 ULONG CurrentPartitionCount
= 0;
2226 ULONG LayoutBufferSize
;
2229 DPRINT1("ReAllocateLayoutBuffer()\n");
2231 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2233 if (DiskEntry
->LayoutBuffer
)
2234 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2236 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2237 CurrentPartitionCount
, NewPartitionCount
);
2239 if (CurrentPartitionCount
== NewPartitionCount
)
2242 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2243 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2244 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2246 DiskEntry
->LayoutBuffer
,
2248 if (NewLayoutBuffer
== NULL
)
2250 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2254 NewLayoutBuffer
->PartitionCount
= NewPartitionCount
;
2256 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2257 if (NewPartitionCount
> CurrentPartitionCount
)
2259 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2261 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2265 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2273 IN PDISKENTRY DiskEntry
)
2275 PPARTITION_INFORMATION PartitionInfo
;
2276 PPARTITION_INFORMATION LinkInfo
= NULL
;
2277 PLIST_ENTRY ListEntry
;
2278 PPARTENTRY PartEntry
;
2279 LARGE_INTEGER HiddenSectors64
;
2281 ULONG PartitionNumber
= 1;
2283 DPRINT1("UpdateDiskLayout()\n");
2285 /* Resize the layout buffer if necessary */
2286 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2288 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2292 /* Update the primary partition table */
2294 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2295 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
2296 ListEntry
= ListEntry
->Flink
)
2298 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2300 if (PartEntry
->IsPartitioned
)
2302 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2303 PartEntry
->PartitionIndex
= Index
;
2305 /* Reset the current partition number only for newly-created partitions */
2307 PartEntry
->PartitionNumber
= 0;
2309 PartEntry
->OnDiskPartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
)) ? PartitionNumber
: 0;
2311 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, DiskEntry
, PartEntry
))
2313 DPRINT1("Updating primary partition entry %lu\n", Index
);
2315 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2316 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2317 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2318 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2319 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2320 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2321 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2322 PartitionInfo
->RewritePartition
= TRUE
;
2325 if (!IsContainerPartition(PartEntry
->PartitionType
))
2334 /* Update the logical partition table */
2336 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2337 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2338 ListEntry
= ListEntry
->Flink
)
2340 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2342 if (PartEntry
->IsPartitioned
)
2344 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2345 PartEntry
->PartitionIndex
= Index
;
2347 DPRINT1("Updating logical partition entry %lu\n", Index
);
2349 /* Reset the current partition number only for newly-created partitions */
2351 PartEntry
->PartitionNumber
= 0;
2353 PartEntry
->OnDiskPartitionNumber
= PartitionNumber
;
2355 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2356 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2357 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2358 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2359 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2360 PartitionInfo
->BootIndicator
= FALSE
;
2361 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2362 PartitionInfo
->RewritePartition
= TRUE
;
2364 /* Fill the link entry of the previous partition entry */
2365 if (LinkInfo
!= NULL
)
2367 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2368 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2369 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2370 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2371 LinkInfo
->PartitionNumber
= 0;
2372 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2373 LinkInfo
->BootIndicator
= FALSE
;
2374 LinkInfo
->RecognizedPartition
= FALSE
;
2375 LinkInfo
->RewritePartition
= TRUE
;
2378 /* Save a pointer to the link entry of the current partition entry */
2379 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2386 /* Wipe unused primary partition entries */
2387 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2389 DPRINT1("Primary partition entry %lu\n", Index
);
2391 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2393 if (!IsEmptyLayoutEntry(PartitionInfo
))
2395 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2397 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2398 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2399 PartitionInfo
->HiddenSectors
= 0;
2400 PartitionInfo
->PartitionNumber
= 0;
2401 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2402 PartitionInfo
->BootIndicator
= FALSE
;
2403 PartitionInfo
->RecognizedPartition
= FALSE
;
2404 PartitionInfo
->RewritePartition
= TRUE
;
2408 /* Wipe unused logical partition entries */
2409 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2413 DPRINT1("Logical partition entry %lu\n", Index
);
2415 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2417 if (!IsEmptyLayoutEntry(PartitionInfo
))
2419 DPRINT1("Wiping partition entry %lu\n", Index
);
2421 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2422 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2423 PartitionInfo
->HiddenSectors
= 0;
2424 PartitionInfo
->PartitionNumber
= 0;
2425 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2426 PartitionInfo
->BootIndicator
= FALSE
;
2427 PartitionInfo
->RecognizedPartition
= FALSE
;
2428 PartitionInfo
->RewritePartition
= TRUE
;
2433 DiskEntry
->Dirty
= TRUE
;
2435 #ifdef DUMP_PARTITION_TABLE
2436 DumpPartitionTable(DiskEntry
);
2442 GetPrevUnpartitionedEntry(
2443 IN PDISKENTRY DiskEntry
,
2444 IN PPARTENTRY PartEntry
)
2446 PPARTENTRY PrevPartEntry
;
2447 PLIST_ENTRY ListHead
;
2449 if (PartEntry
->LogicalPartition
)
2450 ListHead
= &DiskEntry
->LogicalPartListHead
;
2452 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2454 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2456 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2459 if (PrevPartEntry
->IsPartitioned
== FALSE
)
2460 return PrevPartEntry
;
2468 GetNextUnpartitionedEntry(
2469 IN PDISKENTRY DiskEntry
,
2470 IN PPARTENTRY PartEntry
)
2472 PPARTENTRY NextPartEntry
;
2473 PLIST_ENTRY ListHead
;
2475 if (PartEntry
->LogicalPartition
)
2476 ListHead
= &DiskEntry
->LogicalPartListHead
;
2478 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2480 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2482 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2485 if (NextPartEntry
->IsPartitioned
== FALSE
)
2486 return NextPartEntry
;
2493 CreatePrimaryPartition(
2495 IN ULONGLONG SectorCount
,
2496 IN BOOLEAN AutoCreate
)
2499 PDISKENTRY DiskEntry
;
2500 PPARTENTRY PartEntry
;
2502 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount
);
2505 List
->CurrentDisk
== NULL
||
2506 List
->CurrentPartition
== NULL
||
2507 List
->CurrentPartition
->IsPartitioned
)
2512 Error
= PrimaryPartitionCreationChecks(List
);
2513 if (Error
!= NOT_AN_ERROR
)
2515 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error
);
2519 DiskEntry
= List
->CurrentDisk
;
2520 PartEntry
= List
->CurrentPartition
;
2522 /* Convert the current entry, or insert and initialize a new partition entry */
2523 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, AutoCreate
);
2524 if (PartEntry
== NULL
)
2527 UpdateDiskLayout(DiskEntry
);
2529 AssignDriveLetters(List
);
2536 AddLogicalDiskSpace(
2537 IN PDISKENTRY DiskEntry
)
2539 ULONGLONG StartSector
;
2540 ULONGLONG SectorCount
;
2541 PPARTENTRY NewPartEntry
;
2543 DPRINT1("AddLogicalDiskSpace()\n");
2545 /* Create a partition entry that represents the empty space in the container partition */
2547 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2548 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2550 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
2551 &DiskEntry
->LogicalPartListHead
,
2555 if (NewPartEntry
== NULL
)
2557 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2560 NewPartEntry
->LogicalPartition
= TRUE
;
2564 CreateExtendedPartition(
2566 IN ULONGLONG SectorCount
)
2569 PDISKENTRY DiskEntry
;
2570 PPARTENTRY PartEntry
;
2572 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount
);
2575 List
->CurrentDisk
== NULL
||
2576 List
->CurrentPartition
== NULL
||
2577 List
->CurrentPartition
->IsPartitioned
)
2582 Error
= ExtendedPartitionCreationChecks(List
);
2583 if (Error
!= NOT_AN_ERROR
)
2585 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error
);
2589 DiskEntry
= List
->CurrentDisk
;
2590 PartEntry
= List
->CurrentPartition
;
2592 /* Convert the current entry, or insert and initialize a new partition entry */
2593 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, FALSE
);
2594 if (PartEntry
== NULL
)
2597 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2599 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2600 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2604 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2605 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2608 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2609 PartEntry
->New
= FALSE
;
2610 PartEntry
->FormatState
= Formatted
;
2612 DiskEntry
->ExtendedPartition
= PartEntry
;
2614 AddLogicalDiskSpace(DiskEntry
);
2616 UpdateDiskLayout(DiskEntry
);
2618 AssignDriveLetters(List
);
2624 CreateLogicalPartition(
2626 IN ULONGLONG SectorCount
,
2627 IN BOOLEAN AutoCreate
)
2630 PDISKENTRY DiskEntry
;
2631 PPARTENTRY PartEntry
;
2633 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount
);
2636 List
->CurrentDisk
== NULL
||
2637 List
->CurrentPartition
== NULL
||
2638 List
->CurrentPartition
->IsPartitioned
)
2643 Error
= LogicalPartitionCreationChecks(List
);
2644 if (Error
!= NOT_AN_ERROR
)
2646 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error
);
2650 DiskEntry
= List
->CurrentDisk
;
2651 PartEntry
= List
->CurrentPartition
;
2653 /* Convert the current entry, or insert and initialize a new partition entry */
2654 PartEntry
= InitializePartitionEntry(DiskEntry
, PartEntry
, SectorCount
, AutoCreate
);
2655 if (PartEntry
== NULL
)
2658 PartEntry
->LogicalPartition
= TRUE
;
2660 UpdateDiskLayout(DiskEntry
);
2662 AssignDriveLetters(List
);
2670 IN PPARTENTRY PartEntry
)
2673 NTSTATUS LockStatus
;
2674 UNICODE_STRING Name
;
2675 OBJECT_ATTRIBUTES ObjectAttributes
;
2676 IO_STATUS_BLOCK IoStatusBlock
;
2677 HANDLE PartitionHandle
;
2678 WCHAR Buffer
[MAX_PATH
];
2680 /* Check whether the partition is valid and may have been mounted in the system */
2681 if (!PartEntry
->IsPartitioned
||
2682 PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
||
2683 IsContainerPartition(PartEntry
->PartitionType
) ||
2684 !IsRecognizedPartition(PartEntry
->PartitionType
) ||
2685 PartEntry
->FormatState
== Unformatted
/* || PartEntry->FormatState == UnknownFormat */ ||
2686 PartEntry
->FileSystem
== NULL
||
2687 PartEntry
->PartitionNumber
== 0)
2689 /* The partition is not mounted, so just return success */
2690 return STATUS_SUCCESS
;
2693 /* Open the volume */
2694 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
2695 L
"\\Device\\Harddisk%lu\\Partition%lu",
2696 PartEntry
->DiskEntry
->DiskNumber
,
2697 PartEntry
->PartitionNumber
);
2698 RtlInitUnicodeString(&Name
, Buffer
);
2700 InitializeObjectAttributes(&ObjectAttributes
,
2702 OBJ_CASE_INSENSITIVE
,
2706 Status
= NtOpenFile(&PartitionHandle
,
2707 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
2710 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2711 FILE_SYNCHRONOUS_IO_NONALERT
);
2712 if (!NT_SUCCESS(Status
))
2714 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name
, Status
);
2718 /* Lock the volume */
2719 LockStatus
= NtFsControlFile(PartitionHandle
,
2729 if (!NT_SUCCESS(LockStatus
))
2731 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus
);
2734 /* Dismount the volume */
2735 Status
= NtFsControlFile(PartitionHandle
,
2740 FSCTL_DISMOUNT_VOLUME
,
2745 if (!NT_SUCCESS(Status
))
2747 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status
);
2750 /* Unlock the volume */
2751 LockStatus
= NtFsControlFile(PartitionHandle
,
2756 FSCTL_UNLOCK_VOLUME
,
2761 if (!NT_SUCCESS(LockStatus
))
2763 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus
);
2766 /* Close the volume */
2767 NtClose(PartitionHandle
);
2773 DeleteCurrentPartition(
2776 PDISKENTRY DiskEntry
;
2777 PPARTENTRY PartEntry
;
2778 PPARTENTRY PrevPartEntry
;
2779 PPARTENTRY NextPartEntry
;
2780 PPARTENTRY LogicalPartEntry
;
2784 List
->CurrentDisk
== NULL
||
2785 List
->CurrentPartition
== NULL
||
2786 List
->CurrentPartition
->IsPartitioned
== FALSE
)
2791 /* Clear the system disk and partition pointers if the system partition is being deleted */
2792 if (List
->SystemPartition
== List
->CurrentPartition
)
2794 List
->SystemPartition
= NULL
;
2797 DiskEntry
= List
->CurrentDisk
;
2798 PartEntry
= List
->CurrentPartition
;
2800 /* Check which type of partition (primary/logical or extended) is being deleted */
2801 if (DiskEntry
->ExtendedPartition
== PartEntry
)
2803 /* An extended partition is being deleted: delete all logical partition entries */
2804 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
2806 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
2807 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2809 /* Dismount the logical partition */
2810 DismountVolume(LogicalPartEntry
);
2813 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
2816 DiskEntry
->ExtendedPartition
= NULL
;
2820 /* A primary partition is being deleted: dismount it */
2821 DismountVolume(PartEntry
);
2824 /* Adjust unpartitioned disk space entries */
2826 /* Get pointer to previous and next unpartitioned entries */
2827 PrevPartEntry
= GetPrevUnpartitionedEntry(DiskEntry
, PartEntry
);
2828 NextPartEntry
= GetNextUnpartitionedEntry(DiskEntry
, PartEntry
);
2830 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
2832 /* Merge previous, current and next unpartitioned entry */
2834 /* Adjust the previous entries length */
2835 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
2837 /* Remove the current entry */
2838 RemoveEntryList(&PartEntry
->ListEntry
);
2839 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2841 /* Remove the next entry */
2842 RemoveEntryList(&NextPartEntry
->ListEntry
);
2843 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
2845 /* Update current partition */
2846 List
->CurrentPartition
= PrevPartEntry
;
2848 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
2850 /* Merge current and previous unpartitioned entry */
2852 /* Adjust the previous entries length */
2853 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2855 /* Remove the current entry */
2856 RemoveEntryList(&PartEntry
->ListEntry
);
2857 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2859 /* Update current partition */
2860 List
->CurrentPartition
= PrevPartEntry
;
2862 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
2864 /* Merge current and next unpartitioned entry */
2866 /* Adjust the next entries offset and length */
2867 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
2868 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
2870 /* Remove the current entry */
2871 RemoveEntryList(&PartEntry
->ListEntry
);
2872 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
2874 /* Update current partition */
2875 List
->CurrentPartition
= NextPartEntry
;
2879 /* Nothing to merge but change current entry */
2880 PartEntry
->IsPartitioned
= FALSE
;
2881 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2882 PartEntry
->FormatState
= Unformatted
;
2883 PartEntry
->FileSystem
= NULL
;
2884 PartEntry
->DriveLetter
= 0;
2885 PartEntry
->OnDiskPartitionNumber
= 0;
2886 PartEntry
->PartitionNumber
= 0;
2887 // PartEntry->PartitionIndex = 0;
2890 UpdateDiskLayout(DiskEntry
);
2892 AssignDriveLetters(List
);
2896 CheckActiveSystemPartition(
2899 PDISKENTRY DiskEntry
;
2900 PPARTENTRY PartEntry
;
2901 PLIST_ENTRY ListEntry
;
2903 PFILE_SYSTEM FileSystem
;
2905 /* Check for empty disk list */
2906 if (IsListEmpty(&List
->DiskListHead
))
2908 List
->SystemPartition
= NULL
;
2909 List
->OriginalSystemPartition
= NULL
;
2913 /* Choose the currently selected disk */
2914 DiskEntry
= List
->CurrentDisk
;
2916 /* Check for empty partition list */
2917 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
2919 List
->SystemPartition
= NULL
;
2920 List
->OriginalSystemPartition
= NULL
;
2924 if (List
->SystemPartition
!= NULL
)
2926 /* We already have an active system partition */
2927 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
2928 List
->SystemPartition
->PartitionNumber
,
2929 List
->SystemPartition
->DiskEntry
->DiskNumber
,
2930 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
2934 DPRINT1("We are here (1)!\n");
2936 List
->SystemPartition
= NULL
;
2937 List
->OriginalSystemPartition
= NULL
;
2939 /* Retrieve the first partition of the disk */
2940 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
2943 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
2944 List
->SystemPartition
= PartEntry
;
2947 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
2950 /* Check if the disk is new and if so, use its first partition as the active system partition */
2951 if (DiskEntry
->NewDisk
)
2953 if (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
== FALSE
)
2955 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
2956 List
->SystemPartition
= PartEntry
;
2958 List
->OriginalSystemPartition
= List
->SystemPartition
;
2960 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
2961 List
->SystemPartition
->PartitionNumber
,
2962 List
->SystemPartition
->DiskEntry
->DiskNumber
,
2963 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
2965 goto SetSystemPartition
;
2968 // FIXME: What to do??
2969 DPRINT1("NewDisk TRUE but first partition is used?\n");
2972 DPRINT1("We are here (2)!\n");
2975 * The disk is not new, check if any partition is initialized;
2976 * if not, the first one becomes the system partition.
2978 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2979 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
2980 ListEntry
= ListEntry
->Flink
)
2982 /* Retrieve the partition */
2983 PartEntry
= CONTAINING_RECORD(ListEntry
,
2987 /* Check if the partition is partitioned and is used */
2988 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
!= FALSE
)
2993 if (ListEntry
== &DiskEntry
->PrimaryPartListHead
)
2996 * OK we haven't encountered any used and active partition,
2997 * so use the first one as the system partition.
2999 ASSERT(DiskEntry
== List
->SystemPartition
->DiskEntry
);
3000 List
->OriginalSystemPartition
= List
->SystemPartition
; // First PartEntry
3002 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3003 List
->SystemPartition
->PartitionNumber
,
3004 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3005 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3007 goto SetSystemPartition
;
3010 List
->SystemPartition
= NULL
;
3011 List
->OriginalSystemPartition
= NULL
;
3013 DPRINT1("We are here (3)!\n");
3015 /* The disk is not new, scan all partitions to find the (active) system partition */
3016 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3017 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3018 ListEntry
= ListEntry
->Flink
)
3020 /* Retrieve the partition */
3021 PartEntry
= CONTAINING_RECORD(ListEntry
,
3025 /* Check if the partition is partitioned and used */
3026 if (PartEntry
->IsPartitioned
&&
3027 PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
)
3029 /* Check if the partition is active */
3030 if (PartEntry
->BootIndicator
)
3032 /* Yes, we found it */
3033 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3034 List
->SystemPartition
= PartEntry
;
3036 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3037 PartEntry
->PartitionNumber
,
3038 DiskEntry
->DiskNumber
,
3039 (PartEntry
->DriveLetter
== 0) ? L
'-' : PartEntry
->DriveLetter
);
3045 /* Check if we have found the system partition */
3046 if (List
->SystemPartition
== NULL
)
3048 /* Nothing, use the alternative system partition */
3049 DPRINT1("No system partition found, use the alternative partition!\n");
3050 goto UseAlternativeSystemPartition
;
3054 List
->OriginalSystemPartition
= List
->SystemPartition
;
3057 * ADDITIONAL CHECKS / BIG HACK:
3059 * Retrieve its file system and check whether we have
3060 * write support for it. If that is the case we are fine
3061 * and we can use it directly. However if we don't have
3062 * write support we will need to change the active system
3065 * NOTE that this is completely useless on architectures
3066 * where a real system partition is required, as on these
3067 * architectures the partition uses the FAT FS, for which
3068 * we do have write support.
3069 * NOTE also that for those architectures looking for a
3070 * partition boot indicator is insufficient.
3072 FileSystem
= GetFileSystem(List
->OriginalSystemPartition
);
3073 if (FileSystem
== NULL
)
3075 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
3076 List
->OriginalSystemPartition
->PartitionNumber
,
3077 List
->OriginalSystemPartition
->DiskEntry
->DiskNumber
);
3078 goto FindAndUseAlternativeSystemPartition
;
3080 // HACK: WARNING: We cannot write on this FS yet!
3081 // See fsutil.c:GetFileSystem()
3082 if (List
->OriginalSystemPartition
->PartitionType
== PARTITION_IFS
)
3084 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
3085 FileSystem
->FileSystemName
);
3086 goto FindAndUseAlternativeSystemPartition
;
3089 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3090 List
->SystemPartition
->PartitionNumber
,
3091 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3092 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3096 FindAndUseAlternativeSystemPartition
:
3098 * We are here because we have not found any (active) candidate
3099 * system partition that we know how to support. What we are going
3100 * to do is to change the existing system partition and use the
3101 * partition on which we install ReactOS as the new system partition,
3102 * and then we will need to add in FreeLdr's entry a boot entry to boot
3103 * from the original system partition.
3106 /* Unset the old system partition */
3107 List
->SystemPartition
->BootIndicator
= FALSE
;
3108 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= FALSE
;
3109 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3110 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3112 UseAlternativeSystemPartition
:
3113 List
->SystemPartition
= List
->CurrentPartition
;
3115 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3116 List
->SystemPartition
->PartitionNumber
,
3117 List
->SystemPartition
->DiskEntry
->DiskNumber
,
3118 (List
->SystemPartition
->DriveLetter
== 0) ? L
'-' : List
->SystemPartition
->DriveLetter
);
3121 /* Set the new active system partition */
3122 List
->SystemPartition
->BootIndicator
= TRUE
;
3123 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].BootIndicator
= TRUE
;
3124 List
->SystemPartition
->DiskEntry
->LayoutBuffer
->PartitionEntry
[List
->SystemPartition
->PartitionIndex
].RewritePartition
= TRUE
;
3125 List
->SystemPartition
->DiskEntry
->Dirty
= TRUE
;
3132 IN PDISKENTRY DiskEntry
)
3135 OBJECT_ATTRIBUTES ObjectAttributes
;
3136 UNICODE_STRING Name
;
3138 IO_STATUS_BLOCK Iosb
;
3140 PPARTITION_INFORMATION PartitionInfo
;
3141 ULONG PartitionCount
;
3142 PLIST_ENTRY ListEntry
;
3143 PPARTENTRY PartEntry
;
3144 WCHAR DstPath
[MAX_PATH
];
3146 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3148 RtlStringCchPrintfW(DstPath
, ARRAYSIZE(DstPath
),
3149 L
"\\Device\\Harddisk%lu\\Partition0",
3150 DiskEntry
->DiskNumber
);
3151 RtlInitUnicodeString(&Name
, DstPath
);
3153 InitializeObjectAttributes(&ObjectAttributes
,
3155 OBJ_CASE_INSENSITIVE
,
3159 Status
= NtOpenFile(&FileHandle
,
3160 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3164 FILE_SYNCHRONOUS_IO_NONALERT
);
3165 if (!NT_SUCCESS(Status
))
3167 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3171 #ifdef DUMP_PARTITION_TABLE
3172 DumpPartitionTable(DiskEntry
);
3176 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3177 // the disk in MBR or GPT format in case the disk was not initialized!!
3178 // For this we must ask the user which format to use.
3181 /* Save the original partition count to be restored later (see comment below) */
3182 PartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
3184 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3185 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3186 ((PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3187 Status
= NtDeviceIoControlFile(FileHandle
,
3192 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3193 DiskEntry
->LayoutBuffer
,
3195 DiskEntry
->LayoutBuffer
,
3197 NtClose(FileHandle
);
3200 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3201 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3202 * where such a table is expected to enumerate up to 4 partitions:
3203 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3204 * Due to this we need to restore the original PartitionCount number.
3206 DiskEntry
->LayoutBuffer
->PartitionCount
= PartitionCount
;
3208 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3209 if (!NT_SUCCESS(Status
))
3211 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3215 #ifdef DUMP_PARTITION_TABLE
3216 DumpPartitionTable(DiskEntry
);
3219 /* Update the partition numbers */
3221 /* Update the primary partition table */
3222 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3223 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3224 ListEntry
= ListEntry
->Flink
)
3226 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3228 if (PartEntry
->IsPartitioned
)
3230 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3231 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3235 /* Update the logical partition table */
3236 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
3237 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
3238 ListEntry
= ListEntry
->Flink
)
3240 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3242 if (PartEntry
->IsPartitioned
)
3244 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3245 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3250 // NOTE: Originally (see r40437), we used to install here also a new MBR
3251 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3252 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3253 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3254 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3255 // was called too, the installation test was modified by checking whether
3256 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3259 // DiskEntry->Dirty = FALSE;
3265 WritePartitionsToDisk(
3269 PDISKENTRY DiskEntry
;
3274 for (Entry
= List
->DiskListHead
.Flink
;
3275 Entry
!= &List
->DiskListHead
;
3276 Entry
= Entry
->Flink
)
3278 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3280 if (DiskEntry
->Dirty
!= FALSE
)
3282 WritePartitions(List
, DiskEntry
);
3283 DiskEntry
->Dirty
= FALSE
;
3291 SetMountedDeviceValue(
3294 IN LARGE_INTEGER StartingOffset
)
3296 OBJECT_ATTRIBUTES ObjectAttributes
;
3297 WCHAR ValueNameBuffer
[16];
3298 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3299 UNICODE_STRING ValueName
;
3300 REG_DISK_MOUNT_INFO MountInfo
;
3304 RtlStringCchPrintfW(ValueNameBuffer
, ARRAYSIZE(ValueNameBuffer
),
3305 L
"\\DosDevices\\%c:", Letter
);
3306 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
3308 InitializeObjectAttributes(&ObjectAttributes
,
3310 OBJ_CASE_INSENSITIVE
,
3314 Status
= NtOpenKey(&KeyHandle
,
3317 if (!NT_SUCCESS(Status
))
3319 Status
= NtCreateKey(&KeyHandle
,
3324 REG_OPTION_NON_VOLATILE
,
3328 if (!NT_SUCCESS(Status
))
3330 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
3334 MountInfo
.Signature
= Signature
;
3335 MountInfo
.StartingOffset
= StartingOffset
;
3336 Status
= NtSetValueKey(KeyHandle
,
3343 if (!NT_SUCCESS(Status
))
3345 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
3353 SetMountedDeviceValues(
3356 PLIST_ENTRY Entry1
, Entry2
;
3357 PDISKENTRY DiskEntry
;
3358 PPARTENTRY PartEntry
;
3359 LARGE_INTEGER StartingOffset
;
3364 for (Entry1
= List
->DiskListHead
.Flink
;
3365 Entry1
!= &List
->DiskListHead
;
3366 Entry1
= Entry1
->Flink
)
3368 DiskEntry
= CONTAINING_RECORD(Entry1
,
3372 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3373 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3374 Entry2
= Entry2
->Flink
)
3376 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3377 if (PartEntry
->IsPartitioned
)
3379 /* Assign a "\DosDevices\#:" mount point to this partition */
3380 if (PartEntry
->DriveLetter
)
3382 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3383 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3384 DiskEntry
->LayoutBuffer
->Signature
,
3393 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3394 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3395 Entry2
= Entry2
->Flink
)
3397 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3398 if (PartEntry
->IsPartitioned
)
3400 /* Assign a "\DosDevices\#:" mount point to this partition */
3401 if (PartEntry
->DriveLetter
)
3403 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3404 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3405 DiskEntry
->LayoutBuffer
->Signature
,
3420 IN PPARTENTRY PartEntry
,
3421 IN UCHAR PartitionType
)
3423 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3425 PartEntry
->PartitionType
= PartitionType
;
3427 DiskEntry
->Dirty
= TRUE
;
3428 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].PartitionType
= PartitionType
;
3429 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RecognizedPartition
= IsRecognizedPartition(PartitionType
);
3430 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3434 PrimaryPartitionCreationChecks(
3437 PDISKENTRY DiskEntry
;
3438 PPARTENTRY PartEntry
;
3440 DiskEntry
= List
->CurrentDisk
;
3441 PartEntry
= List
->CurrentPartition
;
3443 /* Fail if the partition is already in use */
3444 if (PartEntry
->IsPartitioned
)
3445 return ERROR_NEW_PARTITION
;
3447 /* Fail if there are already 4 primary partitions in the list */
3448 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3449 return ERROR_PARTITION_TABLE_FULL
;
3451 return ERROR_SUCCESS
;
3455 ExtendedPartitionCreationChecks(
3458 PDISKENTRY DiskEntry
;
3459 PPARTENTRY PartEntry
;
3461 DiskEntry
= List
->CurrentDisk
;
3462 PartEntry
= List
->CurrentPartition
;
3464 /* Fail if the partition is already in use */
3465 if (PartEntry
->IsPartitioned
)
3466 return ERROR_NEW_PARTITION
;
3468 /* Fail if there are already 4 primary partitions in the list */
3469 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
3470 return ERROR_PARTITION_TABLE_FULL
;
3472 /* Fail if there is another extended partition in the list */
3473 if (DiskEntry
->ExtendedPartition
!= NULL
)
3474 return ERROR_ONLY_ONE_EXTENDED
;
3476 return ERROR_SUCCESS
;
3480 LogicalPartitionCreationChecks(
3483 // PDISKENTRY DiskEntry;
3484 PPARTENTRY PartEntry
;
3486 // DiskEntry = List->CurrentDisk;
3487 PartEntry
= List
->CurrentPartition
;
3489 /* Fail if the partition is already in use */
3490 if (PartEntry
->IsPartitioned
)
3491 return ERROR_NEW_PARTITION
;
3493 return ERROR_SUCCESS
;
3497 GetNextUnformattedPartition(
3499 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3500 OUT PPARTENTRY
*pPartEntry
)
3502 PLIST_ENTRY Entry1
, Entry2
;
3503 PDISKENTRY DiskEntry
;
3504 PPARTENTRY PartEntry
;
3506 for (Entry1
= List
->DiskListHead
.Flink
;
3507 Entry1
!= &List
->DiskListHead
;
3508 Entry1
= Entry1
->Flink
)
3510 DiskEntry
= CONTAINING_RECORD(Entry1
,
3514 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3515 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3516 Entry2
= Entry2
->Flink
)
3518 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3519 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3521 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3522 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3523 *pPartEntry
= PartEntry
;
3528 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3529 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3530 Entry2
= Entry2
->Flink
)
3532 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3533 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3535 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3536 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3537 *pPartEntry
= PartEntry
;
3543 if (pDiskEntry
) *pDiskEntry
= NULL
;
3550 GetNextUncheckedPartition(
3552 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
3553 OUT PPARTENTRY
*pPartEntry
)
3555 PLIST_ENTRY Entry1
, Entry2
;
3556 PDISKENTRY DiskEntry
;
3557 PPARTENTRY PartEntry
;
3559 for (Entry1
= List
->DiskListHead
.Flink
;
3560 Entry1
!= &List
->DiskListHead
;
3561 Entry1
= Entry1
->Flink
)
3563 DiskEntry
= CONTAINING_RECORD(Entry1
,
3567 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3568 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3569 Entry2
= Entry2
->Flink
)
3571 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3572 if (PartEntry
->NeedsCheck
== TRUE
)
3574 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3575 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3576 *pPartEntry
= PartEntry
;
3581 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3582 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3583 Entry2
= Entry2
->Flink
)
3585 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3586 if (PartEntry
->NeedsCheck
== TRUE
)
3588 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3589 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
3590 *pPartEntry
= PartEntry
;
3596 if (pDiskEntry
) *pDiskEntry
= NULL
;