2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Partition list functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2018-2019 Hermes Belusca-Maito
19 //#define DUMP_PARTITION_TABLE
23 typedef struct _REG_DISK_MOUNT_INFO
26 LARGE_INTEGER StartingOffset
;
27 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
32 /* FUNCTIONS ****************************************************************/
34 #ifdef DUMP_PARTITION_TABLE
40 PPARTITION_INFORMATION PartitionInfo
;
44 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
45 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
47 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
49 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
50 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
52 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
53 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
54 PartitionInfo
->HiddenSectors
,
55 PartitionInfo
->PartitionNumber
,
56 PartitionInfo
->PartitionType
,
57 PartitionInfo
->BootIndicator
? '*': ' ',
58 PartitionInfo
->RewritePartition
? 'Y': 'N');
73 Temp
= Value
/ Alignment
;
75 return Temp
* Alignment
;
83 ULONGLONG Temp
, Result
;
85 Temp
= Value
/ Alignment
;
87 Result
= Temp
* Alignment
;
88 if (Value
% Alignment
)
96 IN ULONGLONG Dividend
,
99 return (Dividend
+ Divisor
/ 2) / Divisor
;
106 IN PDISKENTRY DiskEntry
)
108 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
112 RtlInitUnicodeString(&DiskEntry
->DriverName
, NULL
);
114 RtlStringCchPrintfW(KeyName
, ARRAYSIZE(KeyName
),
115 L
"\\Scsi\\Scsi Port %hu",
118 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
120 QueryTable
[0].Name
= L
"Driver";
121 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
122 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
124 /* This will allocate DiskEntry->DriverName if needed */
125 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
130 if (!NT_SUCCESS(Status
))
132 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
141 PDISKENTRY DiskEntry
;
142 PPARTENTRY PartEntry
;
149 /* Assign drive letters to primary partitions */
150 for (Entry1
= List
->DiskListHead
.Flink
;
151 Entry1
!= &List
->DiskListHead
;
152 Entry1
= Entry1
->Flink
)
154 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
156 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
157 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
158 Entry2
= Entry2
->Flink
)
160 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
162 PartEntry
->DriveLetter
= 0;
164 if (PartEntry
->IsPartitioned
&&
165 !IsContainerPartition(PartEntry
->PartitionType
))
167 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
169 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
170 PartEntry
->SectorCount
.QuadPart
!= 0LL)
174 PartEntry
->DriveLetter
= Letter
;
182 /* Assign drive letters to logical drives */
183 for (Entry1
= List
->DiskListHead
.Flink
;
184 Entry1
!= &List
->DiskListHead
;
185 Entry1
= Entry1
->Flink
)
187 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
189 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
190 Entry2
!= &DiskEntry
->LogicalPartListHead
;
191 Entry2
= Entry2
->Flink
)
193 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
195 PartEntry
->DriveLetter
= 0;
197 if (PartEntry
->IsPartitioned
)
199 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
201 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
202 PartEntry
->SectorCount
.QuadPart
!= 0LL)
206 PartEntry
->DriveLetter
= Letter
;
217 DiskIdentifierQueryRoutine(
225 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
226 UNICODE_STRING NameU
;
228 if (ValueType
== REG_SZ
&&
229 ValueLength
== 20 * sizeof(WCHAR
) &&
230 ((PWCHAR
)ValueData
)[8] == L
'-')
232 NameU
.Buffer
= (PWCHAR
)ValueData
;
233 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
234 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
236 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
237 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
239 return STATUS_SUCCESS
;
242 return STATUS_UNSUCCESSFUL
;
247 DiskConfigurationDataQueryRoutine(
255 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
256 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
257 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
260 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
261 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
262 return STATUS_UNSUCCESSFUL
;
264 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
266 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
268 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
269 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
270 return STATUS_UNSUCCESSFUL
;
273 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
275 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
276 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
279 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
280 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
282 return STATUS_SUCCESS
;
285 return STATUS_UNSUCCESSFUL
;
290 SystemConfigurationDataQueryRoutine(
298 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
299 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
302 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
303 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
304 return STATUS_UNSUCCESSFUL
;
306 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
308 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
310 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
311 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
312 return STATUS_UNSUCCESSFUL
;
315 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
317 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
318 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
321 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(ProcessHeap
, 0,
322 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
323 if (*Int13Drives
== NULL
)
324 return STATUS_NO_MEMORY
;
327 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
328 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
329 return STATUS_SUCCESS
;
332 return STATUS_UNSUCCESSFUL
;
337 EnumerateBiosDiskEntries(
338 IN PPARTLIST PartList
)
340 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
343 ULONG ControllerCount
;
346 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
347 PBIOSDISKENTRY BiosDiskEntry
;
349 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
351 memset(QueryTable
, 0, sizeof(QueryTable
));
353 QueryTable
[1].Name
= L
"Configuration Data";
354 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
356 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
357 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
361 if (!NT_SUCCESS(Status
))
363 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
367 for (AdapterCount
= 0; ; ++AdapterCount
)
369 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
371 ROOT_NAME
, AdapterCount
);
372 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
377 if (!NT_SUCCESS(Status
))
382 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
383 L
"%s\\%lu\\DiskController",
384 ROOT_NAME
, AdapterCount
);
385 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
390 if (NT_SUCCESS(Status
))
392 for (ControllerCount
= 0; ; ++ControllerCount
)
394 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
395 L
"%s\\%lu\\DiskController\\%lu",
396 ROOT_NAME
, AdapterCount
, ControllerCount
);
397 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
402 if (!NT_SUCCESS(Status
))
404 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
408 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
409 L
"%s\\%lu\\DiskController\\%lu\\DiskPeripheral",
410 ROOT_NAME
, AdapterCount
, ControllerCount
);
411 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
416 if (NT_SUCCESS(Status
))
418 QueryTable
[0].Name
= L
"Identifier";
419 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
420 QueryTable
[1].Name
= L
"Configuration Data";
421 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
423 for (DiskCount
= 0; ; ++DiskCount
)
425 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
426 if (BiosDiskEntry
== NULL
)
428 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
432 RtlStringCchPrintfW(Name
, ARRAYSIZE(Name
),
433 L
"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu",
434 ROOT_NAME
, AdapterCount
, ControllerCount
, DiskCount
);
435 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
438 (PVOID
)BiosDiskEntry
,
440 if (!NT_SUCCESS(Status
))
442 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
443 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
447 BiosDiskEntry
->AdapterNumber
= 0; // And NOT "AdapterCount" as it needs to be hardcoded for BIOS!
448 BiosDiskEntry
->ControllerNumber
= ControllerCount
;
449 BiosDiskEntry
->DiskNumber
= DiskCount
;
450 BiosDiskEntry
->DiskEntry
= NULL
;
452 if (DiskCount
< Int13Drives
[0].NumberDrives
)
454 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
458 DPRINT1("Didn't find Int13 drive data for disk %u\n", DiskCount
);
461 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
464 DPRINT("AdapterNumber: %lu\n", BiosDiskEntry
->AdapterNumber
);
465 DPRINT("ControllerNumber: %lu\n", BiosDiskEntry
->ControllerNumber
);
466 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
467 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
468 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
469 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
470 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
471 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
472 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
473 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
474 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
475 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
476 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
484 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
491 * Detects whether a disk reports as a "super-floppy", i.e. an unpartitioned
492 * disk with a valid VBR, following the criteria used by IoReadPartitionTable()
493 * and IoWritePartitionTable():
494 * only one single partition starting at the beginning of the disk; the reported
495 * defaults are: partition number being zero and its type being FAT16 non-bootable.
496 * Note also that accessing \Device\HarddiskN\Partition0 or Partition1 returns
502 IN PDISKENTRY DiskEntry
)
504 PPARTITION_INFORMATION PartitionInfo
;
505 ULONGLONG PartitionLengthEstimate
;
507 /* No layout buffer: we cannot say anything yet */
508 if (DiskEntry
->LayoutBuffer
== NULL
)
511 /* We must have only one partition */
512 if (DiskEntry
->LayoutBuffer
->PartitionCount
!= 1)
515 /* Get the single partition entry */
516 PartitionInfo
= DiskEntry
->LayoutBuffer
->PartitionEntry
;
518 /* The single partition must start at the beginning of the disk */
519 if (!(PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
520 PartitionInfo
->HiddenSectors
== 0))
525 /* The disk signature is usually set to one; warn in case it's not */
526 if (DiskEntry
->LayoutBuffer
->Signature
!= 1)
528 DPRINT1("Super-Floppy disk %lu signature %08x != 1!\n",
529 DiskEntry
->DiskNumber
, DiskEntry
->LayoutBuffer
->Signature
);
533 * The partition number must be zero or one, be recognized,
534 * have FAT16 type and report as non-bootable.
536 if ((PartitionInfo
->PartitionNumber
!= 0 &&
537 PartitionInfo
->PartitionNumber
!= 1) ||
538 PartitionInfo
->RecognizedPartition
!= TRUE
||
539 PartitionInfo
->PartitionType
!= PARTITION_FAT_16
||
540 PartitionInfo
->BootIndicator
!= FALSE
)
542 DPRINT1("Super-Floppy disk %lu does not return default settings!\n"
543 " PartitionNumber = %lu, expected 0\n"
544 " RecognizedPartition = %s, expected TRUE\n"
545 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n"
546 " BootIndicator = %s, expected FALSE\n",
547 DiskEntry
->DiskNumber
,
548 PartitionInfo
->PartitionNumber
,
549 PartitionInfo
->RecognizedPartition
? "TRUE" : "FALSE",
550 PartitionInfo
->PartitionType
,
551 PartitionInfo
->BootIndicator
? "TRUE" : "FALSE");
554 /* The partition lengths should agree */
555 PartitionLengthEstimate
= GetDiskSizeInBytes(DiskEntry
);
556 if (PartitionInfo
->PartitionLength
.QuadPart
!= PartitionLengthEstimate
)
558 DPRINT1("PartitionLength = %I64u is different from PartitionLengthEstimate = %I64u\n",
559 PartitionInfo
->PartitionLength
.QuadPart
, PartitionLengthEstimate
);
567 * Inserts the disk region represented by PartEntry into either the primary
568 * or the logical partition list of the given disk.
569 * The lists are kept sorted by increasing order of start sectors.
570 * Of course no disk region should overlap at all with one another.
575 IN PDISKENTRY DiskEntry
,
576 IN PPARTENTRY PartEntry
,
577 IN BOOLEAN LogicalPartition
)
581 PPARTENTRY PartEntry2
;
583 /* Use the correct partition list */
584 if (LogicalPartition
)
585 List
= &DiskEntry
->LogicalPartListHead
;
587 List
= &DiskEntry
->PrimaryPartListHead
;
589 /* Find the first disk region before which we need to insert the new one */
590 for (Entry
= List
->Flink
; Entry
!= List
; Entry
= Entry
->Flink
)
592 PartEntry2
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
594 /* Ignore any unused empty region */
595 if ((PartEntry2
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
596 PartEntry2
->StartSector
.QuadPart
== 0) || PartEntry2
->SectorCount
.QuadPart
== 0)
601 /* If the current region ends before the one to be inserted, try again */
602 if (PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1 < PartEntry
->StartSector
.QuadPart
)
606 * One of the disk region boundaries crosses the desired region
607 * (it starts after the desired region, or ends before the end
608 * of the desired region): this is an impossible situation because
609 * disk regions (partitions) cannot overlap!
610 * Throw an error and bail out.
612 if (max(PartEntry
->StartSector
.QuadPart
, PartEntry2
->StartSector
.QuadPart
)
614 min( PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
615 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1))
617 DPRINT1("Disk region overlap problem, stopping there!\n"
618 "Partition to be inserted:\n"
619 " StartSector = %I64u ; EndSector = %I64u\n"
620 "Existing disk region:\n"
621 " StartSector = %I64u ; EndSector = %I64u\n",
622 PartEntry
->StartSector
.QuadPart
,
623 PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1,
624 PartEntry2
->StartSector
.QuadPart
,
625 PartEntry2
->StartSector
.QuadPart
+ PartEntry2
->SectorCount
.QuadPart
- 1);
629 /* We have found the first region before which the new one has to be inserted */
633 /* Insert the disk region */
634 InsertTailList(Entry
, &PartEntry
->ListEntry
);
640 CreateInsertBlankRegion(
641 IN PDISKENTRY DiskEntry
,
642 IN OUT PLIST_ENTRY ListHead
,
643 IN ULONGLONG StartSector
,
644 IN ULONGLONG SectorCount
,
645 IN BOOLEAN LogicalSpace
)
647 PPARTENTRY NewPartEntry
;
649 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
652 if (NewPartEntry
== NULL
)
655 NewPartEntry
->DiskEntry
= DiskEntry
;
657 NewPartEntry
->StartSector
.QuadPart
= StartSector
;
658 NewPartEntry
->SectorCount
.QuadPart
= SectorCount
;
660 NewPartEntry
->LogicalPartition
= LogicalSpace
;
661 NewPartEntry
->IsPartitioned
= FALSE
;
662 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
663 NewPartEntry
->FormatState
= Unformatted
;
664 NewPartEntry
->FileSystem
[0] = L
'\0';
666 DPRINT1("First Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
667 DPRINT1("Last Sector : %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
668 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
670 /* Insert the new entry into the list */
671 InsertTailList(ListHead
, &NewPartEntry
->ListEntry
);
678 InitializePartitionEntry(
679 _Inout_ PPARTENTRY PartEntry
,
680 _In_opt_ ULONGLONG SizeBytes
)
682 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
683 ULONGLONG SectorCount
;
685 DPRINT1("Current entry sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
687 /* The entry must not be already partitioned and not be void */
688 ASSERT(!PartEntry
->IsPartitioned
);
689 ASSERT(PartEntry
->SectorCount
.QuadPart
);
691 /* Convert the size in bytes to sector count. SizeBytes being
692 * zero means the caller wants to use all the empty space. */
693 if ((SizeBytes
== 0) || (SizeBytes
== GetPartEntrySizeInBytes(PartEntry
)))
695 /* Use all of the unpartitioned disk space */
696 SectorCount
= PartEntry
->SectorCount
.QuadPart
;
700 SectorCount
= SizeBytes
/ DiskEntry
->BytesPerSector
;
701 if (SectorCount
== 0)
703 /* SizeBytes was certainly less than the minimal size, so fail */
704 DPRINT1("Partition size %I64u too small\n", SizeBytes
);
708 DPRINT1(" New sector count: %I64u\n", SectorCount
);
710 /* Fail if we request more sectors than what the entry actually contains */
711 if (SectorCount
> PartEntry
->SectorCount
.QuadPart
)
714 if ((SectorCount
== 0) ||
715 (AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
716 PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
))
718 /* Reuse the whole current entry */
722 ULONGLONG StartSector
;
723 ULONGLONG SectorCount2
;
724 PPARTENTRY NewPartEntry
;
726 /* Create a partition entry that represents the remaining space
727 * after the partition to be initialized */
729 StartSector
= AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
);
730 SectorCount2
= PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- StartSector
;
732 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
733 PartEntry
->ListEntry
.Flink
,
736 PartEntry
->LogicalPartition
);
737 if (NewPartEntry
== NULL
)
739 DPRINT1("Failed to create a new empty region for disk space!\n");
743 /* Resize down the partition entry; its StartSector remains the same */
744 PartEntry
->SectorCount
.QuadPart
= StartSector
- PartEntry
->StartSector
.QuadPart
;
747 /* Convert the partition entry to 'New (Unformatted)' */
748 PartEntry
->New
= TRUE
;
749 PartEntry
->IsPartitioned
= TRUE
;
751 // FIXME: Use FileSystemToMBRPartitionType() only for MBR, otherwise use PARTITION_BASIC_DATA_GUID.
752 PartEntry
->PartitionType
= FileSystemToMBRPartitionType(L
"RAW",
753 PartEntry
->StartSector
.QuadPart
,
754 PartEntry
->SectorCount
.QuadPart
);
755 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
757 PartEntry
->FormatState
= Unformatted
;
758 PartEntry
->FileSystem
[0] = L
'\0';
759 PartEntry
->BootIndicator
= FALSE
;
761 DPRINT1("First Sector : %I64u\n", PartEntry
->StartSector
.QuadPart
);
762 DPRINT1("Last Sector : %I64u\n", PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1);
763 DPRINT1("Total Sectors: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
773 IN PDISKENTRY DiskEntry
,
774 IN ULONG PartitionIndex
,
775 IN BOOLEAN LogicalPartition
)
778 PPARTITION_INFORMATION PartitionInfo
;
779 PPARTENTRY PartEntry
;
780 HANDLE PartitionHandle
;
781 OBJECT_ATTRIBUTES ObjectAttributes
;
782 IO_STATUS_BLOCK IoStatusBlock
;
783 WCHAR PathBuffer
[MAX_PATH
];
785 UCHAR LabelBuffer
[sizeof(FILE_FS_VOLUME_INFORMATION
) + 256 * sizeof(WCHAR
)];
786 PFILE_FS_VOLUME_INFORMATION LabelInfo
= (PFILE_FS_VOLUME_INFORMATION
)LabelBuffer
;
788 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
790 if (PartitionInfo
->PartitionType
== PARTITION_ENTRY_UNUSED
||
791 ((LogicalPartition
!= FALSE
) && IsContainerPartition(PartitionInfo
->PartitionType
)))
796 PartEntry
= RtlAllocateHeap(ProcessHeap
,
799 if (PartEntry
== NULL
)
802 PartEntry
->DiskEntry
= DiskEntry
;
804 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
805 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
807 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
808 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
810 PartEntry
->LogicalPartition
= LogicalPartition
;
811 PartEntry
->IsPartitioned
= TRUE
;
812 PartEntry
->OnDiskPartitionNumber
= PartitionInfo
->PartitionNumber
;
813 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
814 PartEntry
->PartitionIndex
= PartitionIndex
;
816 /* Specify the partition as initially unformatted */
817 PartEntry
->FormatState
= Unformatted
;
818 PartEntry
->FileSystem
[0] = L
'\0';
820 /* Initialize the partition volume label */
821 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
823 if (IsContainerPartition(PartEntry
->PartitionType
))
825 PartEntry
->FormatState
= Unformatted
;
827 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
828 DiskEntry
->ExtendedPartition
= PartEntry
;
830 else if (IsRecognizedPartition(PartEntry
->PartitionType
))
832 ASSERT(PartitionInfo
->RecognizedPartition
);
833 ASSERT(PartEntry
->IsPartitioned
&& PartEntry
->PartitionNumber
!= 0);
835 /* Try to open the volume so as to mount it */
836 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
837 L
"\\Device\\Harddisk%lu\\Partition%lu",
838 DiskEntry
->DiskNumber
,
839 PartEntry
->PartitionNumber
);
840 RtlInitUnicodeString(&Name
, PathBuffer
);
842 InitializeObjectAttributes(&ObjectAttributes
,
844 OBJ_CASE_INSENSITIVE
,
848 PartitionHandle
= NULL
;
849 Status
= NtOpenFile(&PartitionHandle
,
850 FILE_READ_DATA
| SYNCHRONIZE
,
853 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
854 FILE_SYNCHRONOUS_IO_NONALERT
);
855 if (!NT_SUCCESS(Status
))
857 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status
);
862 ASSERT(NT_SUCCESS(Status
));
864 /* We don't have a FS, try to guess one */
865 Status
= InferFileSystem(NULL
, PartitionHandle
,
866 PartEntry
->FileSystem
,
867 sizeof(PartEntry
->FileSystem
));
868 if (!NT_SUCCESS(Status
))
869 DPRINT1("InferFileSystem() failed, Status 0x%08lx\n", Status
);
871 if (*PartEntry
->FileSystem
)
873 ASSERT(PartitionHandle
);
876 * Handle partition mounted with RawFS: it is
877 * either unformatted or has an unknown format.
879 if (wcsicmp(PartEntry
->FileSystem
, L
"RAW") == 0)
882 * True unformatted partitions on NT are created with their
883 * partition type set to either one of the following values,
884 * and are mounted with RawFS. This is done this way since we
885 * are assured to have FAT support, which is the only FS that
886 * uses these partition types. Therefore, having a partition
887 * mounted with RawFS and with these partition types means that
888 * the FAT FS was unable to mount it beforehand and thus the
889 * partition is unformatted.
890 * However, any partition mounted by RawFS that does NOT have
891 * any of these partition types must be considered as having
894 if (PartEntry
->PartitionType
== PARTITION_FAT_12
||
895 PartEntry
->PartitionType
== PARTITION_FAT_16
||
896 PartEntry
->PartitionType
== PARTITION_HUGE
||
897 PartEntry
->PartitionType
== PARTITION_XINT13
||
898 PartEntry
->PartitionType
== PARTITION_FAT32
||
899 PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
)
901 PartEntry
->FormatState
= Unformatted
;
905 /* Close the partition before dismounting */
906 NtClose(PartitionHandle
);
907 PartitionHandle
= NULL
;
909 * Dismount the partition since RawFS owns it, and set its
910 * format to unknown (may or may not be actually formatted).
912 DismountVolume(PartEntry
);
913 PartEntry
->FormatState
= UnknownFormat
;
914 PartEntry
->FileSystem
[0] = L
'\0';
919 PartEntry
->FormatState
= Preformatted
;
924 PartEntry
->FormatState
= UnknownFormat
;
927 /* Retrieve the partition volume label */
930 Status
= NtQueryVolumeInformationFile(PartitionHandle
,
934 FileFsVolumeInformation
);
935 if (NT_SUCCESS(Status
))
937 /* Copy the (possibly truncated) volume label and NULL-terminate it */
938 RtlStringCbCopyNW(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
),
939 LabelInfo
->VolumeLabel
, LabelInfo
->VolumeLabelLength
);
943 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status
);
947 /* Close the partition */
949 NtClose(PartitionHandle
);
953 /* Unknown partition, hence unknown format (may or may not be actually formatted) */
954 PartEntry
->FormatState
= UnknownFormat
;
957 InsertDiskRegion(DiskEntry
, PartEntry
, LogicalPartition
);
962 ScanForUnpartitionedDiskSpace(
963 IN PDISKENTRY DiskEntry
)
965 ULONGLONG StartSector
;
966 ULONGLONG SectorCount
;
967 ULONGLONG LastStartSector
;
968 ULONGLONG LastSectorCount
;
969 ULONGLONG LastUnusedSectorCount
;
970 PPARTENTRY PartEntry
;
971 PPARTENTRY NewPartEntry
;
974 DPRINT("ScanForUnpartitionedDiskSpace()\n");
976 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
978 DPRINT1("No primary partition!\n");
980 /* Create a partition entry that represents the empty disk */
982 if (DiskEntry
->SectorAlignment
< 2048)
983 StartSector
= 2048ULL;
985 StartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
986 SectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) - StartSector
;
988 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
989 &DiskEntry
->PrimaryPartListHead
,
993 if (NewPartEntry
== NULL
)
994 DPRINT1("Failed to create a new empty region for full disk space!\n");
999 /* Start partition at head 1, cylinder 0 */
1000 if (DiskEntry
->SectorAlignment
< 2048)
1001 LastStartSector
= 2048ULL;
1003 LastStartSector
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
1004 LastSectorCount
= 0ULL;
1005 LastUnusedSectorCount
= 0ULL;
1007 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1008 Entry
!= &DiskEntry
->PrimaryPartListHead
;
1009 Entry
= Entry
->Flink
)
1011 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1013 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1014 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1016 LastUnusedSectorCount
=
1017 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
1019 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
1020 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1022 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1024 StartSector
= LastStartSector
+ LastSectorCount
;
1025 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1027 /* Insert the table into the list */
1028 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1029 &PartEntry
->ListEntry
,
1033 if (NewPartEntry
== NULL
)
1035 DPRINT1("Failed to create a new empty region for disk space!\n");
1040 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1041 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1045 /* Check for trailing unpartitioned disk space */
1046 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
1048 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
1050 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1052 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1054 StartSector
= LastStartSector
+ LastSectorCount
;
1055 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1057 /* Append the table to the list */
1058 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1059 &DiskEntry
->PrimaryPartListHead
,
1063 if (NewPartEntry
== NULL
)
1065 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1071 if (DiskEntry
->ExtendedPartition
!= NULL
)
1073 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1075 DPRINT1("No logical partition!\n");
1077 /* Create a partition entry that represents the empty extended partition */
1079 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1080 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
1082 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1083 &DiskEntry
->LogicalPartListHead
,
1087 if (NewPartEntry
== NULL
)
1089 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1096 /* Start partition at head 1, cylinder 0 */
1097 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
1098 LastSectorCount
= 0ULL;
1099 LastUnusedSectorCount
= 0ULL;
1101 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
1102 Entry
!= &DiskEntry
->LogicalPartListHead
;
1103 Entry
= Entry
->Flink
)
1105 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1107 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
1108 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
1110 LastUnusedSectorCount
=
1111 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
1113 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
1114 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1116 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
1118 StartSector
= LastStartSector
+ LastSectorCount
;
1119 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1121 /* Insert the table into the list */
1122 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1123 &PartEntry
->ListEntry
,
1127 if (NewPartEntry
== NULL
)
1129 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1134 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
1135 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
1139 /* Check for trailing unpartitioned disk space */
1140 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
1142 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+
1143 DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
1144 DiskEntry
->SectorAlignment
);
1146 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
1148 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
1150 StartSector
= LastStartSector
+ LastSectorCount
;
1151 SectorCount
= AlignDown(StartSector
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) - StartSector
;
1153 /* Append the table to the list */
1154 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
1155 &DiskEntry
->LogicalPartListHead
,
1159 if (NewPartEntry
== NULL
)
1161 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1168 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1175 IN PDISKENTRY DiskEntry
)
1177 LARGE_INTEGER SystemTime
;
1178 TIME_FIELDS TimeFields
;
1180 PDISKENTRY DiskEntry2
;
1183 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1185 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1189 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1193 NtQuerySystemTime(&SystemTime
);
1194 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1196 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1197 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1198 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1199 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1201 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1206 /* Check if the signature already exist */
1208 * Check also signatures from disks, which are
1209 * not visible (bootable) by the bios.
1211 for (Entry2
= List
->DiskListHead
.Flink
;
1212 Entry2
!= &List
->DiskListHead
;
1213 Entry2
= Entry2
->Flink
)
1215 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1217 if (DiskEntry2
->DiskStyle
== PARTITION_STYLE_GPT
)
1219 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1223 if (DiskEntry
!= DiskEntry2
&&
1224 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1228 if (Entry2
== &List
->DiskListHead
)
1235 UpdateDiskSignatures(
1239 PDISKENTRY DiskEntry
;
1241 /* Update each disk */
1242 for (Entry
= List
->DiskListHead
.Flink
;
1243 Entry
!= &List
->DiskListHead
;
1244 Entry
= Entry
->Flink
)
1246 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1248 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1250 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1254 if (DiskEntry
->LayoutBuffer
&&
1255 DiskEntry
->LayoutBuffer
->Signature
== 0)
1257 SetDiskSignature(List
, DiskEntry
);
1258 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1265 UpdateHwDiskNumbers(
1268 PLIST_ENTRY ListEntry
;
1269 PBIOSDISKENTRY BiosDiskEntry
;
1270 PDISKENTRY DiskEntry
;
1271 ULONG HwAdapterNumber
= 0;
1272 ULONG HwControllerNumber
= 0;
1273 ULONG RemovableDiskCount
= 0;
1276 * Enumerate the disks recognized by the BIOS and recompute the disk
1277 * numbers on the system when *ALL* removable disks are not connected.
1278 * The entries are inserted in increasing order of AdapterNumber,
1279 * ControllerNumber and DiskNumber.
1281 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1282 ListEntry
!= &List
->BiosDiskListHead
;
1283 ListEntry
= ListEntry
->Flink
)
1285 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1286 DiskEntry
= BiosDiskEntry
->DiskEntry
;
1289 * If the adapter or controller numbers change, update them and reset
1290 * the number of removable disks on this adapter/controller.
1292 if (HwAdapterNumber
!= BiosDiskEntry
->AdapterNumber
||
1293 HwControllerNumber
!= BiosDiskEntry
->ControllerNumber
)
1295 HwAdapterNumber
= BiosDiskEntry
->AdapterNumber
;
1296 HwControllerNumber
= BiosDiskEntry
->ControllerNumber
;
1297 RemovableDiskCount
= 0;
1300 /* Adjust the actual hardware disk number */
1303 ASSERT(DiskEntry
->HwDiskNumber
== BiosDiskEntry
->DiskNumber
);
1305 if (DiskEntry
->MediaType
== RemovableMedia
)
1307 /* Increase the number of removable disks and set the disk number to zero */
1308 ++RemovableDiskCount
;
1309 DiskEntry
->HwFixedDiskNumber
= 0;
1311 else // if (DiskEntry->MediaType == FixedMedia)
1313 /* Adjust the fixed disk number, offset by the number of removable disks found before this one */
1314 DiskEntry
->HwFixedDiskNumber
= BiosDiskEntry
->DiskNumber
- RemovableDiskCount
;
1319 DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry
->DiskNumber
);
1327 IN HANDLE FileHandle
,
1328 IN ULONG DiskNumber
,
1331 DISK_GEOMETRY DiskGeometry
;
1332 SCSI_ADDRESS ScsiAddress
;
1333 PDISKENTRY DiskEntry
;
1334 IO_STATUS_BLOCK Iosb
;
1336 PPARTITION_SECTOR Mbr
;
1338 LARGE_INTEGER FileOffset
;
1339 WCHAR Identifier
[20];
1343 PLIST_ENTRY ListEntry
;
1344 PBIOSDISKENTRY BiosDiskEntry
;
1345 ULONG LayoutBufferSize
;
1346 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1348 /* Retrieve the drive geometry */
1349 Status
= NtDeviceIoControlFile(FileHandle
,
1354 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1358 sizeof(DiskGeometry
));
1359 if (!NT_SUCCESS(Status
))
1362 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1363 DiskGeometry
.MediaType
!= RemovableMedia
)
1369 * FIXME: Here we suppose the disk is always SCSI. What if it is
1370 * of another type? To check this we need to retrieve the name of
1371 * the driver the disk device belongs to.
1373 Status
= NtDeviceIoControlFile(FileHandle
,
1378 IOCTL_SCSI_GET_ADDRESS
,
1382 sizeof(ScsiAddress
));
1383 if (!NT_SUCCESS(Status
))
1387 * Check whether the disk is initialized, by looking at its MBR.
1388 * NOTE that this must be generalized to GPT disks as well!
1391 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1393 DiskGeometry
.BytesPerSector
);
1397 FileOffset
.QuadPart
= 0;
1398 Status
= NtReadFile(FileHandle
,
1404 DiskGeometry
.BytesPerSector
,
1407 if (!NT_SUCCESS(Status
))
1409 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1410 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1413 Signature
= Mbr
->Signature
;
1415 /* Calculate the MBR checksum */
1417 Buffer
= (PULONG
)Mbr
;
1418 for (i
= 0; i
< 128; i
++)
1420 Checksum
+= Buffer
[i
];
1422 Checksum
= ~Checksum
+ 1;
1424 RtlStringCchPrintfW(Identifier
, ARRAYSIZE(Identifier
),
1426 Checksum
, Signature
,
1427 (Mbr
->Magic
== PARTITION_MAGIC
) ? L
'A' : L
'X');
1428 DPRINT("Identifier: %S\n", Identifier
);
1430 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1433 if (DiskEntry
== NULL
)
1435 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1436 DPRINT1("Failed to allocate a new disk entry.\n");
1440 DiskEntry
->PartList
= List
;
1444 FILE_FS_DEVICE_INFORMATION FileFsDevice
;
1446 /* Query the device for its type */
1447 Status
= NtQueryVolumeInformationFile(FileHandle
,
1450 sizeof(FileFsDevice
),
1451 FileFsDeviceInformation
);
1452 if (!NT_SUCCESS(Status
))
1454 DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber
, Identifier
);
1458 DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber
, FileFsDevice
.DeviceType
, FileFsDevice
.Characteristics
);
1461 // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation).
1463 DiskEntry
->MediaType
= DiskGeometry
.MediaType
;
1464 if (DiskEntry
->MediaType
== RemovableMedia
)
1466 DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber
, Identifier
);
1468 else // if (DiskEntry->MediaType == FixedMedia)
1470 DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber
, Identifier
);
1473 // DiskEntry->Checksum = Checksum;
1474 // DiskEntry->Signature = Signature;
1475 DiskEntry
->BiosFound
= FALSE
;
1478 * Check if this disk has a valid MBR: verify its signature,
1479 * and whether its two first bytes are a valid instruction
1480 * (related to this, see IsThereAValidBootSector() in partlist.c).
1482 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1485 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1487 /* If we have not the 0xAA55 then it's raw partition */
1488 if (Mbr
->Magic
!= PARTITION_MAGIC
)
1490 DiskEntry
->DiskStyle
= PARTITION_STYLE_RAW
;
1492 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1493 else if (Mbr
->Partition
[0].PartitionType
== EFI_PMBR_OSTYPE_EFI
&&
1494 Mbr
->Partition
[1].PartitionType
== 0 &&
1495 Mbr
->Partition
[2].PartitionType
== 0 &&
1496 Mbr
->Partition
[3].PartitionType
== 0)
1498 DiskEntry
->DiskStyle
= PARTITION_STYLE_GPT
;
1500 /* Otherwise, partition table is in MBR */
1503 DiskEntry
->DiskStyle
= PARTITION_STYLE_MBR
;
1506 /* Free the MBR sector buffer */
1507 RtlFreeHeap(ProcessHeap
, 0, Mbr
);
1510 for (ListEntry
= List
->BiosDiskListHead
.Flink
;
1511 ListEntry
!= &List
->BiosDiskListHead
;
1512 ListEntry
= ListEntry
->Flink
)
1514 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1516 * Compare the size from bios and the reported size from driver.
1517 * If we have more than one disk with a zero or with the same signature
1518 * we must create new signatures and reboot. After the reboot,
1519 * it is possible to identify the disks.
1521 if (BiosDiskEntry
->Signature
== Signature
&&
1522 BiosDiskEntry
->Checksum
== Checksum
&&
1523 BiosDiskEntry
->DiskEntry
== NULL
)
1525 if (!DiskEntry
->BiosFound
)
1527 DiskEntry
->HwAdapterNumber
= BiosDiskEntry
->AdapterNumber
;
1528 DiskEntry
->HwControllerNumber
= BiosDiskEntry
->ControllerNumber
;
1529 DiskEntry
->HwDiskNumber
= BiosDiskEntry
->DiskNumber
;
1531 if (DiskEntry
->MediaType
== RemovableMedia
)
1533 /* Set the removable disk number to zero */
1534 DiskEntry
->HwFixedDiskNumber
= 0;
1536 else // if (DiskEntry->MediaType == FixedMedia)
1538 /* The fixed disk number will later be adjusted using the number of removable disks */
1539 DiskEntry
->HwFixedDiskNumber
= BiosDiskEntry
->DiskNumber
;
1542 DiskEntry
->BiosFound
= TRUE
;
1543 BiosDiskEntry
->DiskEntry
= DiskEntry
;
1548 // FIXME: What to do?
1549 DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber
, Identifier
);
1554 if (!DiskEntry
->BiosFound
)
1556 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber
);
1559 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1560 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1561 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1562 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1564 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1565 DPRINT("TracksPerCylinder %lu\n", DiskEntry
->TracksPerCylinder
);
1566 DPRINT("SectorsPerTrack %lu\n", DiskEntry
->SectorsPerTrack
);
1567 DPRINT("BytesPerSector %lu\n", DiskEntry
->BytesPerSector
);
1569 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1570 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1571 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1573 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1574 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1575 DiskGeometry
.SectorsPerTrack
;
1577 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
.QuadPart
);
1578 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1580 DiskEntry
->DiskNumber
= DiskNumber
;
1581 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1582 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1583 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1585 GetDriverName(DiskEntry
);
1587 * Actually it would be more correct somehow to use:
1589 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1590 * ULONG ReturnedLength;
1592 * Status = NtQueryObject(SomeHandleToTheDisk,
1593 * ObjectNameInformation,
1599 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1602 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1603 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1605 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1609 * We now retrieve the disk partition layout
1613 * Stop there now if the disk is GPT-partitioned,
1614 * since we currently do not support such disks.
1616 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1618 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1622 /* Allocate a layout buffer with 4 partition entries first */
1623 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1624 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1625 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1628 if (DiskEntry
->LayoutBuffer
== NULL
)
1630 DPRINT1("Failed to allocate the disk layout buffer!\n");
1634 /* Keep looping while the drive layout buffer is too small */
1637 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1638 Status
= NtDeviceIoControlFile(FileHandle
,
1643 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1646 DiskEntry
->LayoutBuffer
,
1648 if (NT_SUCCESS(Status
))
1651 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1653 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1657 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1658 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1660 DiskEntry
->LayoutBuffer
,
1662 if (NewLayoutBuffer
== NULL
)
1664 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1668 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1671 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1673 #ifdef DUMP_PARTITION_TABLE
1674 DumpPartitionTable(DiskEntry
);
1677 if (IsSuperFloppy(DiskEntry
))
1678 DPRINT1("Disk %lu is a super-floppy\n", DiskNumber
);
1680 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1681 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1682 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= PARTITION_ENTRY_UNUSED
)
1684 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1686 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1688 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1690 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1694 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1699 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1702 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1704 DiskEntry
->NewDisk
= TRUE
;
1705 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1707 for (i
= 0; i
< 4; i
++)
1709 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1714 /* Enumerate and add the first four primary partitions */
1715 for (i
= 0; i
< 4; i
++)
1717 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, FALSE
);
1720 /* Enumerate and add the remaining partitions as logical ones */
1721 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1723 AddPartitionToDisk(DiskNumber
, DiskEntry
, i
, TRUE
);
1727 ScanForUnpartitionedDiskSpace(DiskEntry
);
1731 * Retrieve the system disk, i.e. the fixed disk that is accessible by the
1732 * firmware during boot time and where the system partition resides.
1733 * If no system partition has been determined, we retrieve the first disk
1734 * that verifies the mentioned criteria above.
1742 PDISKENTRY DiskEntry
;
1744 /* Check for empty disk list */
1745 if (IsListEmpty(&List
->DiskListHead
))
1749 * If we already have a system partition, the system disk
1750 * is the one on which the system partition resides.
1752 if (List
->SystemPartition
)
1753 return List
->SystemPartition
->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 /* The disk must be a fixed disk and be found by the firmware */
1763 if (DiskEntry
->MediaType
== FixedMedia
&& DiskEntry
->BiosFound
)
1768 if (Entry
== &List
->DiskListHead
)
1770 /* We haven't encountered any suitable disk */
1774 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1776 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
1783 * Retrieve the actual "active" partition of the given disk.
1784 * On MBR disks, partition with the Active/Boot flag set;
1785 * on GPT disks, partition with the correct GUID.
1789 IN PPARTENTRY PartEntry
)
1791 // TODO: Support for GPT disks!
1793 if (IsContainerPartition(PartEntry
->PartitionType
))
1796 /* Check if the partition is partitioned, used and active */
1797 if (PartEntry
->IsPartitioned
&&
1798 // !IsContainerPartition(PartEntry->PartitionType) &&
1799 PartEntry
->BootIndicator
)
1802 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
1811 GetActiveDiskPartition(
1812 IN PDISKENTRY DiskEntry
)
1814 PLIST_ENTRY ListEntry
;
1815 PPARTENTRY PartEntry
;
1816 PPARTENTRY ActivePartition
= NULL
;
1818 /* Check for empty disk list */
1819 // ASSERT(DiskEntry);
1823 /* Check for empty partition list */
1824 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1827 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
1829 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1833 /* Scan all (primary) partitions to find the active disk partition */
1834 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1835 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
1836 ListEntry
= ListEntry
->Flink
)
1838 /* Retrieve the partition */
1839 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
1840 if (IsPartitionActive(PartEntry
))
1842 /* Yes, we've found it */
1843 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
1844 ASSERT(PartEntry
->IsPartitioned
);
1846 ActivePartition
= PartEntry
;
1848 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
1849 PartEntry
->PartitionNumber
, DiskEntry
->DiskNumber
,
1850 (PartEntry
->DriveLetter
== 0) ? L
'-' : PartEntry
->DriveLetter
);
1855 /* Check if the disk is new and if so, use its first partition as the active system partition */
1856 if (DiskEntry
->NewDisk
&& ActivePartition
!= NULL
)
1858 // FIXME: What to do??
1859 DPRINT1("NewDisk TRUE but already existing active partition?\n");
1862 /* Return the active partition found (or none) */
1863 return ActivePartition
;
1867 CreatePartitionList(VOID
)
1870 PDISKENTRY SystemDisk
;
1871 OBJECT_ATTRIBUTES ObjectAttributes
;
1872 SYSTEM_DEVICE_INFORMATION Sdi
;
1873 IO_STATUS_BLOCK Iosb
;
1878 UNICODE_STRING Name
;
1879 WCHAR Buffer
[MAX_PATH
];
1881 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1887 List
->SystemPartition
= NULL
;
1889 InitializeListHead(&List
->DiskListHead
);
1890 InitializeListHead(&List
->BiosDiskListHead
);
1893 * Enumerate the disks seen by the BIOS; this will be used later
1894 * to map drives seen by NTOS with their corresponding BIOS names.
1896 EnumerateBiosDiskEntries(List
);
1898 /* Enumerate disks seen by NTOS */
1899 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1903 if (!NT_SUCCESS(Status
))
1905 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx\n", Status
);
1906 RtlFreeHeap(ProcessHeap
, 0, List
);
1910 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1912 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
1913 L
"\\Device\\Harddisk%lu\\Partition0",
1915 RtlInitUnicodeString(&Name
, Buffer
);
1917 InitializeObjectAttributes(&ObjectAttributes
,
1919 OBJ_CASE_INSENSITIVE
,
1923 Status
= NtOpenFile(&FileHandle
,
1924 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1927 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1928 FILE_SYNCHRONOUS_IO_NONALERT
);
1929 if (NT_SUCCESS(Status
))
1931 AddDiskToList(FileHandle
, DiskNumber
, List
);
1932 NtClose(FileHandle
);
1936 UpdateDiskSignatures(List
);
1937 UpdateHwDiskNumbers(List
);
1938 AssignDriveLetters(List
);
1941 * Retrieve the system partition: the active partition on the system
1942 * disk (the one that will be booted by default by the hardware).
1944 SystemDisk
= GetSystemDisk(List
);
1945 List
->SystemPartition
= (SystemDisk
? GetActiveDiskPartition(SystemDisk
) : NULL
);
1951 DestroyPartitionList(
1954 PDISKENTRY DiskEntry
;
1955 PBIOSDISKENTRY BiosDiskEntry
;
1956 PPARTENTRY PartEntry
;
1959 /* Release disk and partition info */
1960 while (!IsListEmpty(&List
->DiskListHead
))
1962 Entry
= RemoveHeadList(&List
->DiskListHead
);
1963 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1965 /* Release driver name */
1966 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1968 /* Release primary partition list */
1969 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1971 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1972 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1974 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1977 /* Release logical partition list */
1978 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1980 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1981 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1983 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1986 /* Release layout buffer */
1987 if (DiskEntry
->LayoutBuffer
!= NULL
)
1988 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1990 /* Release disk entry */
1991 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1994 /* Release the bios disk info */
1995 while (!IsListEmpty(&List
->BiosDiskListHead
))
1997 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1998 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
2000 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
2003 /* Release list head */
2004 RtlFreeHeap(ProcessHeap
, 0, List
);
2008 GetDiskByBiosNumber(
2010 IN ULONG HwDiskNumber
)
2012 PDISKENTRY DiskEntry
;
2015 /* Loop over the disks and find the correct one */
2016 for (Entry
= List
->DiskListHead
.Flink
;
2017 Entry
!= &List
->DiskListHead
;
2018 Entry
= Entry
->Flink
)
2020 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2022 if (DiskEntry
->HwDiskNumber
== HwDiskNumber
)
2029 /* Disk not found, stop there */
2036 IN ULONG DiskNumber
)
2038 PDISKENTRY DiskEntry
;
2041 /* Loop over the disks and find the correct one */
2042 for (Entry
= List
->DiskListHead
.Flink
;
2043 Entry
!= &List
->DiskListHead
;
2044 Entry
= Entry
->Flink
)
2046 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2048 if (DiskEntry
->DiskNumber
== DiskNumber
)
2055 /* Disk not found, stop there */
2066 PDISKENTRY DiskEntry
;
2069 /* Loop over the disks and find the correct one */
2070 for (Entry
= List
->DiskListHead
.Flink
;
2071 Entry
!= &List
->DiskListHead
;
2072 Entry
= Entry
->Flink
)
2074 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2076 if (DiskEntry
->Port
== Port
&&
2077 DiskEntry
->Bus
== Bus
&&
2078 DiskEntry
->Id
== Id
)
2085 /* Disk not found, stop there */
2094 PDISKENTRY DiskEntry
;
2097 /* Loop over the disks and find the correct one */
2098 for (Entry
= List
->DiskListHead
.Flink
;
2099 Entry
!= &List
->DiskListHead
;
2100 Entry
= Entry
->Flink
)
2102 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2104 if (DiskEntry
->LayoutBuffer
->Signature
== Signature
)
2111 /* Disk not found, stop there */
2117 // IN PPARTLIST List,
2118 IN PDISKENTRY DiskEntry
,
2119 IN ULONG PartitionNumber
)
2121 PPARTENTRY PartEntry
;
2124 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2126 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2130 /* Disk found, loop over the primary partitions first... */
2131 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2132 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2133 Entry
= Entry
->Flink
)
2135 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2137 if (PartEntry
->PartitionNumber
== PartitionNumber
)
2139 /* Partition found */
2144 /* ... then over the logical partitions if needed */
2145 for (Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
2146 Entry
!= &DiskEntry
->LogicalPartListHead
;
2147 Entry
= Entry
->Flink
)
2149 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2151 if (PartEntry
->PartitionNumber
== PartitionNumber
)
2153 /* Partition found */
2158 /* The partition was not found on the disk, stop there */
2165 IN ULONG DiskNumber
,
2166 IN ULONG PartitionNumber OPTIONAL
,
2167 OUT PDISKENTRY
* pDiskEntry
,
2168 OUT PPARTENTRY
* pPartEntry OPTIONAL
)
2170 PDISKENTRY DiskEntry
;
2171 PPARTENTRY PartEntry
= NULL
;
2174 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
2178 /* If we have a partition (PartitionNumber != 0), find it */
2179 if (PartitionNumber
!= 0)
2181 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2183 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2187 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
2190 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2193 /* Return the disk (and optionally the partition) */
2194 *pDiskEntry
= DiskEntry
;
2195 if (pPartEntry
) *pPartEntry
= PartEntry
;
2200 // NOTE: Was introduced broken in r6258 by Casper
2205 IN ULONG DiskNumber
,
2206 IN ULONG PartitionNumber
)
2208 PDISKENTRY DiskEntry
;
2209 PPARTENTRY PartEntry
;
2211 DiskEntry
= GetDiskByNumber(List
, DiskNumber
);
2215 PartEntry
= GetPartition(/*List,*/ DiskEntry
, PartitionNumber
);
2219 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
2220 ASSERT(DiskEntry
->DiskNumber
== DiskNumber
);
2221 ASSERT(PartEntry
->PartitionNumber
== PartitionNumber
);
2229 IN PPARTENTRY CurrentPart OPTIONAL
)
2231 PLIST_ENTRY DiskListEntry
;
2232 PLIST_ENTRY PartListEntry
;
2233 PDISKENTRY CurrentDisk
;
2235 /* Fail if no disks are available */
2236 if (IsListEmpty(&List
->DiskListHead
))
2239 /* Check for the next usable entry on the current partition's disk */
2240 if (CurrentPart
!= NULL
)
2242 CurrentDisk
= CurrentPart
->DiskEntry
;
2244 if (CurrentPart
->LogicalPartition
)
2246 /* Logical partition */
2248 PartListEntry
= CurrentPart
->ListEntry
.Flink
;
2249 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2251 /* Next logical partition */
2252 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2257 PartListEntry
= CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
2258 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2260 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2267 /* Primary or extended partition */
2269 if (CurrentPart
->IsPartitioned
&&
2270 IsContainerPartition(CurrentPart
->PartitionType
))
2272 /* First logical partition */
2273 PartListEntry
= CurrentDisk
->LogicalPartListHead
.Flink
;
2274 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2276 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2282 /* Next primary partition */
2283 PartListEntry
= CurrentPart
->ListEntry
.Flink
;
2284 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2286 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2293 /* Search for the first partition entry on the next disk */
2294 for (DiskListEntry
= (CurrentPart
? CurrentDisk
->ListEntry
.Flink
2295 : List
->DiskListHead
.Flink
);
2296 DiskListEntry
!= &List
->DiskListHead
;
2297 DiskListEntry
= DiskListEntry
->Flink
)
2299 CurrentDisk
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2301 if (CurrentDisk
->DiskStyle
== PARTITION_STYLE_GPT
)
2303 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2307 PartListEntry
= CurrentDisk
->PrimaryPartListHead
.Flink
;
2308 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2310 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2321 IN PPARTENTRY CurrentPart OPTIONAL
)
2323 PLIST_ENTRY DiskListEntry
;
2324 PLIST_ENTRY PartListEntry
;
2325 PDISKENTRY CurrentDisk
;
2327 /* Fail if no disks are available */
2328 if (IsListEmpty(&List
->DiskListHead
))
2331 /* Check for the previous usable entry on the current partition's disk */
2332 if (CurrentPart
!= NULL
)
2334 CurrentDisk
= CurrentPart
->DiskEntry
;
2336 if (CurrentPart
->LogicalPartition
)
2338 /* Logical partition */
2340 PartListEntry
= CurrentPart
->ListEntry
.Blink
;
2341 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2343 /* Previous logical partition */
2344 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2348 /* Extended partition */
2349 CurrentPart
= CurrentDisk
->ExtendedPartition
;
2355 /* Primary or extended partition */
2357 PartListEntry
= CurrentPart
->ListEntry
.Blink
;
2358 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2360 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2362 if (CurrentPart
->IsPartitioned
&&
2363 IsContainerPartition(CurrentPart
->PartitionType
))
2365 PartListEntry
= CurrentDisk
->LogicalPartListHead
.Blink
;
2366 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2374 /* Search for the last partition entry on the previous disk */
2375 for (DiskListEntry
= (CurrentPart
? CurrentDisk
->ListEntry
.Blink
2376 : List
->DiskListHead
.Blink
);
2377 DiskListEntry
!= &List
->DiskListHead
;
2378 DiskListEntry
= DiskListEntry
->Blink
)
2380 CurrentDisk
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2382 if (CurrentDisk
->DiskStyle
== PARTITION_STYLE_GPT
)
2384 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2388 PartListEntry
= CurrentDisk
->PrimaryPartListHead
.Blink
;
2389 if (PartListEntry
!= &CurrentDisk
->PrimaryPartListHead
)
2391 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2393 if (CurrentPart
->IsPartitioned
&&
2394 IsContainerPartition(CurrentPart
->PartitionType
))
2396 PartListEntry
= CurrentDisk
->LogicalPartListHead
.Blink
;
2397 if (PartListEntry
!= &CurrentDisk
->LogicalPartListHead
)
2399 CurrentPart
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2416 _In_ PPARTITION_INFORMATION PartitionInfo
)
2418 return (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2419 PartitionInfo
->PartitionLength
.QuadPart
== 0);
2424 IsSamePrimaryLayoutEntry(
2425 _In_ PPARTITION_INFORMATION PartitionInfo
,
2426 _In_ PPARTENTRY PartEntry
)
2428 return ((PartitionInfo
->StartingOffset
.QuadPart
== GetPartEntryOffsetInBytes(PartEntry
)) &&
2429 (PartitionInfo
->PartitionLength
.QuadPart
== GetPartEntrySizeInBytes(PartEntry
)));
2430 // PartitionInfo->PartitionType == PartEntry->PartitionType
2435 GetPrimaryPartitionCount(
2436 IN PDISKENTRY DiskEntry
)
2439 PPARTENTRY PartEntry
;
2442 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2444 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2448 for (Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2449 Entry
!= &DiskEntry
->PrimaryPartListHead
;
2450 Entry
= Entry
->Flink
)
2452 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2453 if (PartEntry
->IsPartitioned
)
2462 GetLogicalPartitionCount(
2463 IN PDISKENTRY DiskEntry
)
2465 PLIST_ENTRY ListEntry
;
2466 PPARTENTRY PartEntry
;
2469 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2471 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2475 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2476 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2477 ListEntry
= ListEntry
->Flink
)
2479 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2480 if (PartEntry
->IsPartitioned
)
2489 ReAllocateLayoutBuffer(
2490 IN PDISKENTRY DiskEntry
)
2492 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2493 ULONG NewPartitionCount
;
2494 ULONG CurrentPartitionCount
= 0;
2495 ULONG LayoutBufferSize
;
2498 DPRINT1("ReAllocateLayoutBuffer()\n");
2500 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2502 if (DiskEntry
->LayoutBuffer
)
2503 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2505 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2506 CurrentPartitionCount
, NewPartitionCount
);
2508 if (CurrentPartitionCount
== NewPartitionCount
)
2511 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2512 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2513 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2515 DiskEntry
->LayoutBuffer
,
2517 if (NewLayoutBuffer
== NULL
)
2519 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2523 NewLayoutBuffer
->PartitionCount
= NewPartitionCount
;
2525 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2526 if (NewPartitionCount
> CurrentPartitionCount
)
2528 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2530 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2534 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2542 IN PDISKENTRY DiskEntry
)
2544 PPARTITION_INFORMATION PartitionInfo
;
2545 PPARTITION_INFORMATION LinkInfo
= NULL
;
2546 PLIST_ENTRY ListEntry
;
2547 PPARTENTRY PartEntry
;
2548 LARGE_INTEGER HiddenSectors64
;
2550 ULONG PartitionNumber
= 1;
2552 DPRINT1("UpdateDiskLayout()\n");
2554 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2556 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2560 /* Resize the layout buffer if necessary */
2561 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2563 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2567 /* Update the primary partition table */
2569 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2570 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
2571 ListEntry
= ListEntry
->Flink
)
2573 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2575 if (PartEntry
->IsPartitioned
)
2577 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2579 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2580 PartEntry
->PartitionIndex
= Index
;
2582 /* Reset the current partition number only for newly-created (unmounted) partitions */
2584 PartEntry
->PartitionNumber
= 0;
2586 PartEntry
->OnDiskPartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
) ? PartitionNumber
: 0);
2588 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, PartEntry
))
2590 DPRINT1("Updating primary partition entry %lu\n", Index
);
2592 PartitionInfo
->StartingOffset
.QuadPart
= GetPartEntryOffsetInBytes(PartEntry
);
2593 PartitionInfo
->PartitionLength
.QuadPart
= GetPartEntrySizeInBytes(PartEntry
);
2594 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2595 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2596 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2597 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2598 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2599 PartitionInfo
->RewritePartition
= TRUE
;
2602 if (!IsContainerPartition(PartEntry
->PartitionType
))
2611 /* Update the logical partition table */
2613 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2614 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
2615 ListEntry
= ListEntry
->Flink
)
2617 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2619 if (PartEntry
->IsPartitioned
)
2621 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
2623 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2624 PartEntry
->PartitionIndex
= Index
;
2626 /* Reset the current partition number only for newly-created (unmounted) partitions */
2628 PartEntry
->PartitionNumber
= 0;
2630 PartEntry
->OnDiskPartitionNumber
= PartitionNumber
;
2632 DPRINT1("Updating logical partition entry %lu\n", Index
);
2634 PartitionInfo
->StartingOffset
.QuadPart
= GetPartEntryOffsetInBytes(PartEntry
);
2635 PartitionInfo
->PartitionLength
.QuadPart
= GetPartEntrySizeInBytes(PartEntry
);
2636 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2637 PartitionInfo
->PartitionNumber
= PartEntry
->PartitionNumber
;
2638 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2639 PartitionInfo
->BootIndicator
= FALSE
;
2640 PartitionInfo
->RecognizedPartition
= IsRecognizedPartition(PartEntry
->PartitionType
);
2641 PartitionInfo
->RewritePartition
= TRUE
;
2643 /* Fill the link entry of the previous partition entry */
2644 if (LinkInfo
!= NULL
)
2646 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2647 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2648 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2649 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2650 LinkInfo
->PartitionNumber
= 0;
2651 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2652 LinkInfo
->BootIndicator
= FALSE
;
2653 LinkInfo
->RecognizedPartition
= FALSE
;
2654 LinkInfo
->RewritePartition
= TRUE
;
2657 /* Save a pointer to the link entry of the current partition entry */
2658 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2665 /* Wipe unused primary partition entries */
2666 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2668 DPRINT1("Primary partition entry %lu\n", Index
);
2670 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2672 if (!IsEmptyLayoutEntry(PartitionInfo
))
2674 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2676 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2677 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2678 PartitionInfo
->HiddenSectors
= 0;
2679 PartitionInfo
->PartitionNumber
= 0;
2680 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2681 PartitionInfo
->BootIndicator
= FALSE
;
2682 PartitionInfo
->RecognizedPartition
= FALSE
;
2683 PartitionInfo
->RewritePartition
= TRUE
;
2687 /* Wipe unused logical partition entries */
2688 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2692 DPRINT1("Logical partition entry %lu\n", Index
);
2694 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2696 if (!IsEmptyLayoutEntry(PartitionInfo
))
2698 DPRINT1("Wiping partition entry %lu\n", Index
);
2700 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2701 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2702 PartitionInfo
->HiddenSectors
= 0;
2703 PartitionInfo
->PartitionNumber
= 0;
2704 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2705 PartitionInfo
->BootIndicator
= FALSE
;
2706 PartitionInfo
->RecognizedPartition
= FALSE
;
2707 PartitionInfo
->RewritePartition
= TRUE
;
2712 // HACK: See the FIXMEs in WritePartitions(): (Re)set the PartitionStyle to MBR.
2713 DiskEntry
->DiskStyle
= PARTITION_STYLE_MBR
;
2715 DiskEntry
->Dirty
= TRUE
;
2717 #ifdef DUMP_PARTITION_TABLE
2718 DumpPartitionTable(DiskEntry
);
2724 GetPrevUnpartitionedEntry(
2725 IN PPARTENTRY PartEntry
)
2727 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
2728 PPARTENTRY PrevPartEntry
;
2729 PLIST_ENTRY ListHead
;
2731 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2733 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2737 if (PartEntry
->LogicalPartition
)
2738 ListHead
= &DiskEntry
->LogicalPartListHead
;
2740 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2742 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2744 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2747 if (!PrevPartEntry
->IsPartitioned
)
2749 ASSERT(PrevPartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
2750 return PrevPartEntry
;
2759 GetNextUnpartitionedEntry(
2760 IN PPARTENTRY PartEntry
)
2762 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
2763 PPARTENTRY NextPartEntry
;
2764 PLIST_ENTRY ListHead
;
2766 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2768 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2772 if (PartEntry
->LogicalPartition
)
2773 ListHead
= &DiskEntry
->LogicalPartListHead
;
2775 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2777 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2779 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2782 if (!NextPartEntry
->IsPartitioned
)
2784 ASSERT(NextPartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
2785 return NextPartEntry
;
2793 PartitionCreationChecks(
2794 _In_ PPARTENTRY PartEntry
)
2796 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
2798 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2800 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2801 return ERROR_WARN_PARTITION
;
2804 /* Fail if the partition is already in use */
2805 if (PartEntry
->IsPartitioned
)
2806 return ERROR_NEW_PARTITION
;
2809 * For primary partitions
2811 if (!PartEntry
->LogicalPartition
)
2813 /* Only one primary partition is allowed on super-floppy */
2814 if (IsSuperFloppy(DiskEntry
))
2815 return ERROR_PARTITION_TABLE_FULL
;
2817 /* Fail if there are already 4 primary partitions in the list */
2818 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
2819 return ERROR_PARTITION_TABLE_FULL
;
2822 * For logical partitions
2826 // TODO: Check that we are inside an extended partition!!
2827 // Then the following check will be useless.
2829 /* Only one (primary) partition is allowed on super-floppy */
2830 if (IsSuperFloppy(DiskEntry
))
2831 return ERROR_PARTITION_TABLE_FULL
;
2834 return ERROR_SUCCESS
;
2838 ExtendedPartitionCreationChecks(
2839 _In_ PPARTENTRY PartEntry
)
2841 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
2843 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
2845 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2846 return ERROR_WARN_PARTITION
;
2849 /* Fail if the partition is already in use */
2850 if (PartEntry
->IsPartitioned
)
2851 return ERROR_NEW_PARTITION
;
2853 /* Only one primary partition is allowed on super-floppy */
2854 if (IsSuperFloppy(DiskEntry
))
2855 return ERROR_PARTITION_TABLE_FULL
;
2857 /* Fail if there are already 4 primary partitions in the list */
2858 if (GetPrimaryPartitionCount(DiskEntry
) >= 4)
2859 return ERROR_PARTITION_TABLE_FULL
;
2861 /* Fail if there is another extended partition in the list */
2862 if (DiskEntry
->ExtendedPartition
!= NULL
)
2863 return ERROR_ONLY_ONE_EXTENDED
;
2865 return ERROR_SUCCESS
;
2870 _In_ PPARTLIST List
,
2871 _Inout_ PPARTENTRY PartEntry
,
2872 _In_opt_ ULONGLONG SizeBytes
)
2876 DPRINT1("CreatePartition(%I64u bytes)\n", SizeBytes
);
2878 if (List
== NULL
|| PartEntry
== NULL
||
2879 PartEntry
->DiskEntry
== NULL
|| PartEntry
->IsPartitioned
)
2884 Error
= PartitionCreationChecks(PartEntry
);
2885 if (Error
!= NOT_AN_ERROR
)
2887 DPRINT1("PartitionCreationChecks() failed with error %lu\n", Error
);
2891 /* Initialize the partition entry, inserting a new blank region if needed */
2892 if (!InitializePartitionEntry(PartEntry
, SizeBytes
))
2895 UpdateDiskLayout(PartEntry
->DiskEntry
);
2896 AssignDriveLetters(List
);
2903 AddLogicalDiskSpace(
2904 _In_ PDISKENTRY DiskEntry
)
2906 ULONGLONG StartSector
;
2907 ULONGLONG SectorCount
;
2908 PPARTENTRY NewPartEntry
;
2910 DPRINT1("AddLogicalDiskSpace()\n");
2912 /* Create a partition entry that represents the empty space in the container partition */
2914 StartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2915 SectorCount
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2917 NewPartEntry
= CreateInsertBlankRegion(DiskEntry
,
2918 &DiskEntry
->LogicalPartListHead
,
2922 if (NewPartEntry
== NULL
)
2924 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2930 CreateExtendedPartition(
2931 _In_ PPARTLIST List
,
2932 _Inout_ PPARTENTRY PartEntry
,
2933 _In_opt_ ULONGLONG SizeBytes
)
2937 DPRINT1("CreateExtendedPartition(%I64u bytes)\n", SizeBytes
);
2939 if (List
== NULL
|| PartEntry
== NULL
||
2940 PartEntry
->DiskEntry
== NULL
|| PartEntry
->IsPartitioned
)
2945 Error
= ExtendedPartitionCreationChecks(PartEntry
);
2946 if (Error
!= NOT_AN_ERROR
)
2948 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error
);
2952 /* Initialize the partition entry, inserting a new blank region if needed */
2953 if (!InitializePartitionEntry(PartEntry
, SizeBytes
))
2956 ASSERT(PartEntry
->LogicalPartition
== FALSE
);
2958 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2960 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2961 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2965 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2966 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2969 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2970 PartEntry
->New
= FALSE
;
2971 PartEntry
->FormatState
= Formatted
;
2973 PartEntry
->DiskEntry
->ExtendedPartition
= PartEntry
;
2975 AddLogicalDiskSpace(PartEntry
->DiskEntry
);
2977 UpdateDiskLayout(PartEntry
->DiskEntry
);
2978 AssignDriveLetters(List
);
2985 IN PPARTENTRY PartEntry
)
2988 NTSTATUS LockStatus
;
2989 UNICODE_STRING Name
;
2990 OBJECT_ATTRIBUTES ObjectAttributes
;
2991 IO_STATUS_BLOCK IoStatusBlock
;
2992 HANDLE PartitionHandle
;
2993 WCHAR Buffer
[MAX_PATH
];
2995 /* Check whether the partition is valid and was mounted by the system */
2996 if (!PartEntry
->IsPartitioned
||
2997 IsContainerPartition(PartEntry
->PartitionType
) ||
2998 !IsRecognizedPartition(PartEntry
->PartitionType
) ||
2999 PartEntry
->FormatState
== UnknownFormat
||
3000 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means
3001 // it has been usually mounted with RawFS and thus needs to be dismounted.
3002 !*PartEntry
->FileSystem
||
3003 PartEntry
->PartitionNumber
== 0)
3005 /* The partition is not mounted, so just return success */
3006 return STATUS_SUCCESS
;
3009 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3011 /* Open the volume */
3012 RtlStringCchPrintfW(Buffer
, ARRAYSIZE(Buffer
),
3013 L
"\\Device\\Harddisk%lu\\Partition%lu",
3014 PartEntry
->DiskEntry
->DiskNumber
,
3015 PartEntry
->PartitionNumber
);
3016 RtlInitUnicodeString(&Name
, Buffer
);
3018 InitializeObjectAttributes(&ObjectAttributes
,
3020 OBJ_CASE_INSENSITIVE
,
3024 Status
= NtOpenFile(&PartitionHandle
,
3025 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3028 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3029 FILE_SYNCHRONOUS_IO_NONALERT
);
3030 if (!NT_SUCCESS(Status
))
3032 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name
, Status
);
3036 /* Lock the volume */
3037 LockStatus
= NtFsControlFile(PartitionHandle
,
3047 if (!NT_SUCCESS(LockStatus
))
3049 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus
);
3052 /* Dismount the volume */
3053 Status
= NtFsControlFile(PartitionHandle
,
3058 FSCTL_DISMOUNT_VOLUME
,
3063 if (!NT_SUCCESS(Status
))
3065 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status
);
3068 /* Unlock the volume */
3069 LockStatus
= NtFsControlFile(PartitionHandle
,
3074 FSCTL_UNLOCK_VOLUME
,
3079 if (!NT_SUCCESS(LockStatus
))
3081 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus
);
3084 /* Close the volume */
3085 NtClose(PartitionHandle
);
3093 IN PPARTENTRY PartEntry
,
3094 OUT PPARTENTRY
* FreeRegion OPTIONAL
)
3096 PDISKENTRY DiskEntry
;
3097 PPARTENTRY PrevPartEntry
;
3098 PPARTENTRY NextPartEntry
;
3099 PPARTENTRY LogicalPartEntry
;
3102 if (List
== NULL
|| PartEntry
== NULL
||
3103 PartEntry
->DiskEntry
== NULL
|| PartEntry
->IsPartitioned
== FALSE
)
3108 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3110 /* Clear the system partition if it is being deleted */
3111 if (List
->SystemPartition
== PartEntry
)
3113 ASSERT(List
->SystemPartition
);
3114 List
->SystemPartition
= NULL
;
3117 DiskEntry
= PartEntry
->DiskEntry
;
3119 /* Check which type of partition (primary/logical or extended) is being deleted */
3120 if (DiskEntry
->ExtendedPartition
== PartEntry
)
3122 /* An extended partition is being deleted: delete all logical partition entries */
3123 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
3125 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
3126 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
3128 /* Dismount the logical partition */
3129 DismountVolume(LogicalPartEntry
);
3132 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
3135 DiskEntry
->ExtendedPartition
= NULL
;
3139 /* A primary partition is being deleted: dismount it */
3140 DismountVolume(PartEntry
);
3143 /* Adjust the unpartitioned disk space entries */
3145 /* Get pointer to previous and next unpartitioned entries */
3146 PrevPartEntry
= GetPrevUnpartitionedEntry(PartEntry
);
3147 NextPartEntry
= GetNextUnpartitionedEntry(PartEntry
);
3149 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
3151 /* Merge the previous, current and next unpartitioned entries */
3153 /* Adjust the previous entry length */
3154 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
3156 /* Remove the current and next entries */
3157 RemoveEntryList(&PartEntry
->ListEntry
);
3158 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3159 RemoveEntryList(&NextPartEntry
->ListEntry
);
3160 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
3162 /* Optionally return the freed region */
3164 *FreeRegion
= PrevPartEntry
;
3166 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
3168 /* Merge the current and the previous unpartitioned entries */
3170 /* Adjust the previous entry length */
3171 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3173 /* Remove the current entry */
3174 RemoveEntryList(&PartEntry
->ListEntry
);
3175 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3177 /* Optionally return the freed region */
3179 *FreeRegion
= PrevPartEntry
;
3181 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
3183 /* Merge the current and the next unpartitioned entries */
3185 /* Adjust the next entry offset and length */
3186 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
3187 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3189 /* Remove the current entry */
3190 RemoveEntryList(&PartEntry
->ListEntry
);
3191 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3193 /* Optionally return the freed region */
3195 *FreeRegion
= NextPartEntry
;
3199 /* Nothing to merge but change the current entry */
3200 PartEntry
->IsPartitioned
= FALSE
;
3201 PartEntry
->OnDiskPartitionNumber
= 0;
3202 PartEntry
->PartitionNumber
= 0;
3203 // PartEntry->PartitionIndex = 0;
3204 PartEntry
->BootIndicator
= FALSE
;
3205 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
3206 PartEntry
->FormatState
= Unformatted
;
3207 PartEntry
->FileSystem
[0] = L
'\0';
3208 PartEntry
->DriveLetter
= 0;
3209 RtlZeroMemory(PartEntry
->VolumeLabel
, sizeof(PartEntry
->VolumeLabel
));
3211 /* Optionally return the freed region */
3213 *FreeRegion
= PartEntry
;
3216 UpdateDiskLayout(DiskEntry
);
3217 AssignDriveLetters(List
);
3224 IsSupportedActivePartition(
3225 IN PPARTENTRY PartEntry
)
3227 /* Check the type and the file system of this partition */
3230 * We do not support extended partition containers (on MBR disks) marked
3231 * as active, and containing code inside their extended boot records.
3233 if (IsContainerPartition(PartEntry
->PartitionType
))
3235 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3236 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3241 * ADDITIONAL CHECKS / BIG HACK:
3243 * Retrieve its file system and check whether we have
3244 * write support for it. If that is the case we are fine
3245 * and we can use it directly. However if we don't have
3246 * write support we will need to change the active system
3249 * NOTE that this is completely useless on architectures
3250 * where a real system partition is required, as on these
3251 * architectures the partition uses the FAT FS, for which
3252 * we do have write support.
3253 * NOTE also that for those architectures looking for a
3254 * partition boot indicator is insufficient.
3256 if (PartEntry
->FormatState
== Unformatted
)
3258 /* If this partition is mounted, it would use RawFS ("RAW") */
3261 else if ((PartEntry
->FormatState
== Preformatted
) ||
3262 (PartEntry
->FormatState
== Formatted
))
3264 ASSERT(*PartEntry
->FileSystem
);
3266 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3267 if (wcsicmp(PartEntry
->FileSystem
, L
"FAT") == 0 ||
3268 wcsicmp(PartEntry
->FileSystem
, L
"FAT32") == 0 ||
3269 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3270 wcsicmp(PartEntry
->FileSystem
, L
"BTRFS") == 0)
3276 // WARNING: We cannot write on this FS yet!
3277 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3278 PartEntry
->FileSystem
);
3282 else // if (PartEntry->FormatState == UnknownFormat)
3284 ASSERT(!*PartEntry
->FileSystem
);
3286 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3287 PartEntry
->PartitionNumber
, PartEntry
->DiskEntry
->DiskNumber
);
3291 // HACK: WARNING: We cannot write on this FS yet!
3292 // See fsutil.c:InferFileSystem()
3293 if (PartEntry
->PartitionType
== PARTITION_IFS
)
3295 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3296 PartEntry
->FileSystem
);
3304 FindSupportedSystemPartition(
3306 IN BOOLEAN ForceSelect
,
3307 IN PDISKENTRY AlternativeDisk OPTIONAL
,
3308 IN PPARTENTRY AlternativePart OPTIONAL
)
3310 PLIST_ENTRY ListEntry
;
3311 PDISKENTRY DiskEntry
;
3312 PPARTENTRY PartEntry
;
3313 PPARTENTRY ActivePartition
;
3314 PPARTENTRY CandidatePartition
= NULL
;
3316 /* Check for empty disk list */
3317 if (IsListEmpty(&List
->DiskListHead
))
3319 /* No system partition! */
3320 ASSERT(List
->SystemPartition
== NULL
);
3321 goto NoSystemPartition
;
3324 /* Adjust the optional alternative disk if needed */
3325 if (!AlternativeDisk
&& AlternativePart
)
3326 AlternativeDisk
= AlternativePart
->DiskEntry
;
3328 /* Ensure that the alternative partition is on the alternative disk */
3329 if (AlternativePart
)
3330 ASSERT(AlternativeDisk
&& (AlternativePart
->DiskEntry
== AlternativeDisk
));
3332 /* Ensure that the alternative disk is in the list */
3333 if (AlternativeDisk
)
3334 ASSERT(AlternativeDisk
->PartList
== List
);
3337 CandidatePartition
= NULL
;
3340 // Step 1 : Check the system disk.
3344 * First, check whether the system disk, i.e. the one that will be booted
3345 * by default by the hardware, contains an active partition. If so this
3346 * should be our system partition.
3348 DiskEntry
= GetSystemDisk(List
);
3350 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3352 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3353 goto UseAlternativeDisk
;
3356 /* If we have a system partition (in the system disk), validate it */
3357 ActivePartition
= List
->SystemPartition
;
3358 if (ActivePartition
&& IsSupportedActivePartition(ActivePartition
))
3360 CandidatePartition
= ActivePartition
;
3362 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3363 CandidatePartition
->PartitionNumber
,
3364 CandidatePartition
->DiskEntry
->DiskNumber
,
3365 (CandidatePartition
->DriveLetter
== 0) ? L
'-' : CandidatePartition
->DriveLetter
);
3367 /* Return the candidate system partition */
3368 return CandidatePartition
;
3371 /* If the system disk is not the optional alternative disk, perform the minimal checks */
3372 if (DiskEntry
!= AlternativeDisk
)
3375 * No active partition has been recognized. Enumerate all the (primary)
3376 * partitions in the system disk, excluding the possible current active
3377 * partition, to find a new candidate.
3379 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3380 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3381 ListEntry
= ListEntry
->Flink
)
3383 /* Retrieve the partition */
3384 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3386 /* Skip the current active partition */
3387 if (PartEntry
== ActivePartition
)
3390 /* Check if the partition is partitioned and used */
3391 if (PartEntry
->IsPartitioned
&&
3392 !IsContainerPartition(PartEntry
->PartitionType
))
3394 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3396 /* If we get a candidate active partition in the disk, validate it */
3397 if (IsSupportedActivePartition(PartEntry
))
3399 CandidatePartition
= PartEntry
;
3400 goto UseAlternativePartition
;
3405 /* Check if the partition is partitioned and used */
3406 if (!PartEntry
->IsPartitioned
)
3408 ASSERT(PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
3410 // TODO: Check for minimal size!!
3411 CandidatePartition
= PartEntry
;
3412 goto UseAlternativePartition
;
3418 * Still nothing, look whether there is some free space that we can use
3419 * for the new system partition. We must be sure that the total number
3420 * of partition is less than the maximum allowed, and that the minimal
3424 // TODO: Fix the handling of system partition being created in unpartitioned space!!
3425 // --> When to partition it? etc...
3427 if (GetPrimaryPartitionCount(DiskEntry
) < 4)
3429 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3430 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3431 ListEntry
= ListEntry
->Flink
)
3433 /* Retrieve the partition */
3434 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3436 /* Skip the current active partition */
3437 if (PartEntry
== ActivePartition
)
3440 /* Check for unpartitioned space */
3441 if (!PartEntry
->IsPartitioned
)
3443 ASSERT(PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
);
3445 // TODO: Check for minimal size!!
3446 CandidatePartition
= PartEntry
;
3447 goto UseAlternativePartition
;
3455 // Step 2 : No active partition found: Check the alternative disk if specified.
3459 if (!AlternativeDisk
|| (!ForceSelect
&& (DiskEntry
!= AlternativeDisk
)))
3460 goto NoSystemPartition
;
3462 if (AlternativeDisk
->DiskStyle
== PARTITION_STYLE_GPT
)
3464 DPRINT1("Alternative disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3465 goto NoSystemPartition
;
3468 if (DiskEntry
!= AlternativeDisk
)
3470 /* Choose the alternative disk */
3471 DiskEntry
= AlternativeDisk
;
3473 /* If we get a candidate active partition, validate it */
3474 ActivePartition
= GetActiveDiskPartition(DiskEntry
);
3475 if (ActivePartition
&& IsSupportedActivePartition(ActivePartition
))
3477 CandidatePartition
= ActivePartition
;
3478 goto UseAlternativePartition
;
3482 /* We now may have an unsupported active partition, or none */
3485 *** TODO: Improve the selection:
3486 *** - If we want a really separate system partition from the partition where
3487 *** we install, do something similar to what's done below in the code.
3488 *** - Otherwise if we allow for the system partition to be also the partition
3489 *** where we install, just directly fall down to using AlternativePart.
3492 /* Retrieve the first partition of the disk */
3493 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
3494 PARTENTRY
, ListEntry
);
3495 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
3497 CandidatePartition
= PartEntry
;
3500 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3503 /* Check if the disk is new and if so, use its first partition as the active system partition */
3504 if (DiskEntry
->NewDisk
)
3506 // !IsContainerPartition(PartEntry->PartitionType);
3507 if (!CandidatePartition
->IsPartitioned
|| !CandidatePartition
->BootIndicator
) /* CandidatePartition != ActivePartition */
3509 ASSERT(DiskEntry
== CandidatePartition
->DiskEntry
);
3511 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3512 CandidatePartition
->PartitionNumber
,
3513 CandidatePartition
->DiskEntry
->DiskNumber
,
3514 (CandidatePartition
->DriveLetter
== 0) ? L
'-' : CandidatePartition
->DriveLetter
);
3516 /* Return the candidate system partition */
3517 return CandidatePartition
;
3520 // FIXME: What to do??
3521 DPRINT1("NewDisk TRUE but first partition is used?\n");
3525 * The disk is not new, check if any partition is initialized;
3526 * if not, the first one becomes the system partition.
3528 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3529 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3530 ListEntry
= ListEntry
->Flink
)
3532 /* Retrieve the partition */
3533 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3535 /* Check if the partition is partitioned and is used */
3536 // !IsContainerPartition(PartEntry->PartitionType);
3537 if (/* PartEntry->IsPartitioned && */
3538 PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
|| PartEntry
->BootIndicator
)
3543 if (ListEntry
== &DiskEntry
->PrimaryPartListHead
)
3546 * OK we haven't encountered any used and active partition,
3547 * so use the first one as the system partition.
3549 ASSERT(DiskEntry
== CandidatePartition
->DiskEntry
);
3551 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3552 CandidatePartition
->PartitionNumber
,
3553 CandidatePartition
->DiskEntry
->DiskNumber
,
3554 (CandidatePartition
->DriveLetter
== 0) ? L
'-' : CandidatePartition
->DriveLetter
);
3556 /* Return the candidate system partition */
3557 return CandidatePartition
;
3561 * The disk is not new, we did not find any actual active partition,
3562 * or the one we found was not supported, or any possible other candidate
3563 * is not supported. We then use the alternative partition if specified.
3565 if (AlternativePart
)
3567 DPRINT1("No valid or supported system partition has been found, use the alternative partition!\n");
3568 CandidatePartition
= AlternativePart
;
3569 goto UseAlternativePartition
;
3574 DPRINT1("No valid or supported system partition has been found on this system!\n");
3578 UseAlternativePartition
:
3580 * We are here because we did not find any (active) candidate system
3581 * partition that we know how to support. What we are going to do is
3582 * to change the existing system partition and use the alternative partition
3583 * (e.g. on which we install ReactOS) as the new system partition.
3584 * Then we will need to add in FreeLdr's boot menu an entry for booting
3585 * from the original system partition.
3587 ASSERT(CandidatePartition
);
3589 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3590 CandidatePartition
->PartitionNumber
,
3591 CandidatePartition
->DiskEntry
->DiskNumber
,
3592 (CandidatePartition
->DriveLetter
== 0) ? L
'-' : CandidatePartition
->DriveLetter
);
3594 /* Return the candidate system partition */
3595 return CandidatePartition
;
3601 IN PPARTENTRY PartEntry
,
3602 IN PPARTENTRY OldActivePart OPTIONAL
)
3604 /* Check for empty disk list */
3605 if (IsListEmpty(&List
->DiskListHead
))
3608 /* Validate the partition entry */
3613 * If the partition entry is already the system partition, or if it is
3614 * the same as the old active partition hint the user provided (and if
3615 * it is already active), just return success.
3617 if ((PartEntry
== List
->SystemPartition
) ||
3618 ((PartEntry
== OldActivePart
) && IsPartitionActive(OldActivePart
)))
3623 ASSERT(PartEntry
->DiskEntry
);
3625 /* Ensure that the partition's disk is in the list */
3626 ASSERT(PartEntry
->DiskEntry
->PartList
== List
);
3629 * If the user provided an old active partition hint, verify that it is
3630 * indeeed active and belongs to the same disk where the new partition
3631 * belongs. Otherwise determine the current active partition on the disk
3632 * where the new partition belongs.
3634 if (!(OldActivePart
&& IsPartitionActive(OldActivePart
) && (OldActivePart
->DiskEntry
== PartEntry
->DiskEntry
)))
3636 /* It's not, determine the current active partition for the disk */
3637 OldActivePart
= GetActiveDiskPartition(PartEntry
->DiskEntry
);
3640 /* Unset the old active partition if it exists */
3643 OldActivePart
->BootIndicator
= FALSE
;
3644 OldActivePart
->DiskEntry
->LayoutBuffer
->PartitionEntry
[OldActivePart
->PartitionIndex
].BootIndicator
= FALSE
;
3645 OldActivePart
->DiskEntry
->LayoutBuffer
->PartitionEntry
[OldActivePart
->PartitionIndex
].RewritePartition
= TRUE
;
3646 OldActivePart
->DiskEntry
->Dirty
= TRUE
;
3649 /* Modify the system partition if the new partition is on the system disk */
3650 if (PartEntry
->DiskEntry
== GetSystemDisk(List
))
3651 List
->SystemPartition
= PartEntry
;
3653 /* Set the new active partition */
3654 PartEntry
->BootIndicator
= TRUE
;
3655 PartEntry
->DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].BootIndicator
= TRUE
;
3656 PartEntry
->DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3657 PartEntry
->DiskEntry
->Dirty
= TRUE
;
3664 IN PDISKENTRY DiskEntry
)
3667 OBJECT_ATTRIBUTES ObjectAttributes
;
3668 UNICODE_STRING Name
;
3670 IO_STATUS_BLOCK Iosb
;
3672 PPARTITION_INFORMATION PartitionInfo
;
3673 ULONG PartitionCount
;
3674 PLIST_ENTRY ListEntry
;
3675 PPARTENTRY PartEntry
;
3676 WCHAR DstPath
[MAX_PATH
];
3678 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3680 /* If the disk is not dirty, there is nothing to do */
3681 if (!DiskEntry
->Dirty
)
3682 return STATUS_SUCCESS
;
3684 RtlStringCchPrintfW(DstPath
, ARRAYSIZE(DstPath
),
3685 L
"\\Device\\Harddisk%lu\\Partition0",
3686 DiskEntry
->DiskNumber
);
3687 RtlInitUnicodeString(&Name
, DstPath
);
3689 InitializeObjectAttributes(&ObjectAttributes
,
3691 OBJ_CASE_INSENSITIVE
,
3695 Status
= NtOpenFile(&FileHandle
,
3696 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3700 FILE_SYNCHRONOUS_IO_NONALERT
);
3701 if (!NT_SUCCESS(Status
))
3703 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3707 #ifdef DUMP_PARTITION_TABLE
3708 DumpPartitionTable(DiskEntry
);
3712 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3713 // the disk in MBR or GPT format in case the disk was not initialized!!
3714 // For this we must ask the user which format to use.
3717 /* Save the original partition count to be restored later (see comment below) */
3718 PartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
3720 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3721 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3722 ((PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3723 Status
= NtDeviceIoControlFile(FileHandle
,
3728 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3729 DiskEntry
->LayoutBuffer
,
3731 DiskEntry
->LayoutBuffer
,
3733 NtClose(FileHandle
);
3736 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3737 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3738 * where such a table is expected to enumerate up to 4 partitions:
3739 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3740 * Due to this we need to restore the original PartitionCount number.
3742 DiskEntry
->LayoutBuffer
->PartitionCount
= PartitionCount
;
3744 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3745 if (!NT_SUCCESS(Status
))
3747 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3751 #ifdef DUMP_PARTITION_TABLE
3752 DumpPartitionTable(DiskEntry
);
3755 /* Update the partition numbers */
3757 /* Update the primary partition table */
3758 for (ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3759 ListEntry
!= &DiskEntry
->PrimaryPartListHead
;
3760 ListEntry
= ListEntry
->Flink
)
3762 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3764 if (PartEntry
->IsPartitioned
)
3766 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3767 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3768 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3772 /* Update the logical partition table */
3773 for (ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
3774 ListEntry
!= &DiskEntry
->LogicalPartListHead
;
3775 ListEntry
= ListEntry
->Flink
)
3777 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
3779 if (PartEntry
->IsPartitioned
)
3781 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3782 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
];
3783 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
3788 // NOTE: Originally (see r40437), we used to install here also a new MBR
3789 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3790 // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0.
3791 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3792 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3793 // was called too, the installation test was modified by checking whether
3794 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3797 // HACK: Parts of FIXMEs described above: (Re)set the PartitionStyle to MBR.
3798 DiskEntry
->DiskStyle
= PARTITION_STYLE_MBR
;
3800 /* The layout has been successfully updated, the disk is not dirty anymore */
3801 DiskEntry
->Dirty
= FALSE
;
3807 WritePartitionsToDisk(
3812 PDISKENTRY DiskEntry
;
3817 for (Entry
= List
->DiskListHead
.Flink
;
3818 Entry
!= &List
->DiskListHead
;
3819 Entry
= Entry
->Flink
)
3821 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3823 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3825 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3829 if (DiskEntry
->Dirty
!= FALSE
)
3831 Status
= WritePartitions(DiskEntry
);
3832 if (!NT_SUCCESS(Status
))
3834 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
3835 DiskEntry
->DiskNumber
, Status
);
3844 SetMountedDeviceValue(
3847 IN LARGE_INTEGER StartingOffset
)
3850 OBJECT_ATTRIBUTES ObjectAttributes
;
3851 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"SYSTEM\\MountedDevices");
3852 UNICODE_STRING ValueName
;
3853 WCHAR ValueNameBuffer
[16];
3855 REG_DISK_MOUNT_INFO MountInfo
;
3857 RtlStringCchPrintfW(ValueNameBuffer
, ARRAYSIZE(ValueNameBuffer
),
3858 L
"\\DosDevices\\%c:", Letter
);
3859 RtlInitUnicodeString(&ValueName
, ValueNameBuffer
);
3861 InitializeObjectAttributes(&ObjectAttributes
,
3863 OBJ_CASE_INSENSITIVE
,
3864 GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE
, NULL
),
3867 Status
= NtOpenKey(&KeyHandle
,
3870 if (!NT_SUCCESS(Status
))
3872 Status
= NtCreateKey(&KeyHandle
,
3877 REG_OPTION_NON_VOLATILE
,
3880 if (!NT_SUCCESS(Status
))
3882 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status
);
3886 MountInfo
.Signature
= Signature
;
3887 MountInfo
.StartingOffset
= StartingOffset
;
3888 Status
= NtSetValueKey(KeyHandle
,
3895 if (!NT_SUCCESS(Status
))
3897 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status
);
3905 SetMountedDeviceValues(
3908 PLIST_ENTRY Entry1
, Entry2
;
3909 PDISKENTRY DiskEntry
;
3910 PPARTENTRY PartEntry
;
3911 LARGE_INTEGER StartingOffset
;
3916 for (Entry1
= List
->DiskListHead
.Flink
;
3917 Entry1
!= &List
->DiskListHead
;
3918 Entry1
= Entry1
->Flink
)
3920 DiskEntry
= CONTAINING_RECORD(Entry1
,
3924 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
3926 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3930 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3931 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
3932 Entry2
= Entry2
->Flink
)
3934 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3935 if (PartEntry
->IsPartitioned
) // && !IsContainerPartition(PartEntry->PartitionType)
3937 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3939 /* Assign a "\DosDevices\#:" mount point to this partition */
3940 if (PartEntry
->DriveLetter
)
3942 StartingOffset
.QuadPart
= GetPartEntryOffsetInBytes(PartEntry
);
3943 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3944 DiskEntry
->LayoutBuffer
->Signature
,
3953 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3954 Entry2
!= &DiskEntry
->LogicalPartListHead
;
3955 Entry2
= Entry2
->Flink
)
3957 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3958 if (PartEntry
->IsPartitioned
) // && !IsContainerPartition(PartEntry->PartitionType)
3960 ASSERT(PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
);
3962 /* Assign a "\DosDevices\#:" mount point to this partition */
3963 if (PartEntry
->DriveLetter
)
3965 StartingOffset
.QuadPart
= GetPartEntryOffsetInBytes(PartEntry
);
3966 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3967 DiskEntry
->LayoutBuffer
->Signature
,
3981 SetMBRPartitionType(
3982 IN PPARTENTRY PartEntry
,
3983 IN UCHAR PartitionType
)
3985 PDISKENTRY DiskEntry
= PartEntry
->DiskEntry
;
3987 ASSERT(DiskEntry
->DiskStyle
== PARTITION_STYLE_MBR
);
3989 PartEntry
->PartitionType
= PartitionType
;
3991 DiskEntry
->Dirty
= TRUE
;
3992 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].PartitionType
= PartitionType
;
3993 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RecognizedPartition
= IsRecognizedPartition(PartitionType
);
3994 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3998 GetNextUnformattedPartition(
4000 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
4001 OUT PPARTENTRY
*pPartEntry
)
4003 PLIST_ENTRY Entry1
, Entry2
;
4004 PDISKENTRY DiskEntry
;
4005 PPARTENTRY PartEntry
;
4007 for (Entry1
= List
->DiskListHead
.Flink
;
4008 Entry1
!= &List
->DiskListHead
;
4009 Entry1
= Entry1
->Flink
)
4011 DiskEntry
= CONTAINING_RECORD(Entry1
,
4015 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4017 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4021 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
4022 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
4023 Entry2
= Entry2
->Flink
)
4025 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4026 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
4028 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4029 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4030 *pPartEntry
= PartEntry
;
4035 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
4036 Entry2
!= &DiskEntry
->LogicalPartListHead
;
4037 Entry2
= Entry2
->Flink
)
4039 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4040 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
4042 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4043 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4044 *pPartEntry
= PartEntry
;
4050 if (pDiskEntry
) *pDiskEntry
= NULL
;
4057 GetNextUncheckedPartition(
4059 OUT PDISKENTRY
*pDiskEntry OPTIONAL
,
4060 OUT PPARTENTRY
*pPartEntry
)
4062 PLIST_ENTRY Entry1
, Entry2
;
4063 PDISKENTRY DiskEntry
;
4064 PPARTENTRY PartEntry
;
4066 for (Entry1
= List
->DiskListHead
.Flink
;
4067 Entry1
!= &List
->DiskListHead
;
4068 Entry1
= Entry1
->Flink
)
4070 DiskEntry
= CONTAINING_RECORD(Entry1
,
4074 if (DiskEntry
->DiskStyle
== PARTITION_STYLE_GPT
)
4076 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4080 for (Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
4081 Entry2
!= &DiskEntry
->PrimaryPartListHead
;
4082 Entry2
= Entry2
->Flink
)
4084 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4085 if (PartEntry
->IsPartitioned
&& PartEntry
->NeedsCheck
)
4087 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4088 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4089 *pPartEntry
= PartEntry
;
4094 for (Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
4095 Entry2
!= &DiskEntry
->LogicalPartListHead
;
4096 Entry2
= Entry2
->Flink
)
4098 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
4099 if (PartEntry
->IsPartitioned
&& PartEntry
->NeedsCheck
)
4101 ASSERT(DiskEntry
== PartEntry
->DiskEntry
);
4102 if (pDiskEntry
) *pDiskEntry
= DiskEntry
;
4103 *pPartEntry
= PartEntry
;
4109 if (pDiskEntry
) *pDiskEntry
= NULL
;