3 * Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: base/setup/usetup/partlist.c
22 * PURPOSE: Partition list functions
23 * PROGRAMMER: Eric Kohl
24 * Casper S. Hornstrup (chorns@users.sourceforge.net)
34 //#define DUMP_PARTITION_TABLE
36 /* HELPERS FOR PARTITION TYPES **********************************************/
38 typedef struct _PARTITION_TYPE
42 } PARTITION_TYPE
, *PPARTITION_TYPE
;
45 * This partiton type list was ripped off the kernelDisk.c module from:
47 * Visopsys Operating System
48 * Copyright (C) 1998-2015 J. Andrew McLaughlin
50 * This program is free software; you can redistribute it and/or modify it
51 * under the terms of the GNU General Public License as published by the Free
52 * Software Foundation; either version 2 of the License, or (at your option)
55 * This program is distributed in the hope that it will be useful, but
56 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
57 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
60 * You should have received a copy of the GNU General Public License along
61 * with this program; if not, write to the Free Software Foundation, Inc.,
62 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
65 * See also https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
66 * and http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
67 * for a complete list.
70 /* This is a table for keeping known partition type codes and descriptions */
71 static PARTITION_TYPE PartitionTypes
[] =
75 { 0x02, "XENIX root" },
76 { 0x03, "XENIX /usr" },
77 { 0x04, "FAT16 (small)" },
80 { 0x07, "NTFS/HPFS/exFAT" },
81 { 0x08, "OS/2 or AIX boot" },
83 { 0x0A, "OS/2 Boot Manager" },
85 { 0x0C, "FAT32 (LBA)" },
86 { 0x0E, "FAT16 (LBA)" },
87 { 0x0F, "Extended (LBA)" },
88 { 0x11, "Hidden FAT12" },
89 { 0x12, "FAT diagnostic" },
90 { 0x14, "Hidden FAT16 (small)" },
91 { 0x16, "Hidden FAT16" },
92 { 0x17, "Hidden HPFS or NTFS" },
93 { 0x1B, "Hidden FAT32" },
94 { 0x1C, "Hidden FAT32 (LBA)" },
95 { 0x1E, "Hidden FAT16 (LBA)" },
98 { 0x3C, "PartitionMagic" },
99 { 0x3D, "Hidden Netware" },
100 { 0x41, "PowerPC PReP" },
101 { 0x42, "Win2K dynamic extended" },
102 { 0x43, "Old Linux" },
105 { 0x4D, "QNX4.x 2nd" },
106 { 0x4D, "QNX4.x 3rd" },
107 { 0x50, "Ontrack R/O" },
108 { 0x51, "Ontrack R/W or Novell" },
110 { 0x63, "GNU HURD or UNIX SysV" },
111 { 0x64, "Netware 2" },
112 { 0x65, "Netware 3/4" },
113 { 0x66, "Netware SMS" },
116 { 0x69, "Netware 5+" },
117 { 0x7E, "Veritas VxVM public" },
118 { 0x7F, "Veritas VxVM private" },
120 { 0x81, "Linux or Minix" },
121 { 0x82, "Linux swap or Solaris" },
123 { 0x84, "Hibernation" },
124 { 0x85, "Linux extended" },
125 { 0x86, "HPFS or NTFS mirrored" },
126 { 0x87, "HPFS or NTFS mirrored" },
127 { 0x8E, "Linux LVM" },
128 { 0x93, "Hidden Linux" },
130 { 0xA0, "Laptop hibernation" },
131 { 0xA1, "Laptop hibernation" },
132 { 0xA5, "BSD, NetBSD, FreeBSD" },
134 { 0xA7, "NeXTSTEP" },
135 { 0xA8, "OS-X UFS" },
137 { 0xAB, "OS-X boot" },
138 { 0xAF, "OS-X HFS" },
139 { 0xB6, "NT corrupt mirror" },
141 { 0xB8, "BSDI swap" },
142 { 0xBE, "Solaris 8 boot" },
143 { 0xBF, "Solaris x86" },
145 { 0xC1, "DR-DOS FAT12" },
146 { 0xC2, "Hidden Linux" },
147 { 0xC3, "Hidden Linux swap" },
148 { 0xC4, "DR-DOS FAT16 (small)" },
149 { 0xC5, "DR-DOS Extended" },
150 { 0xC6, "DR-DOS FAT16" },
151 { 0xC7, "HPFS mirrored" },
152 { 0xCB, "DR-DOS FAT32" },
153 { 0xCC, "DR-DOS FAT32 (LBA)" },
154 { 0xCE, "DR-DOS FAT16 (LBA)" },
156 { 0xD1, "MDOS FAT12" },
157 { 0xD4, "MDOS FAT16 (small)" },
158 { 0xD5, "MDOS Extended" },
159 { 0xD6, "MDOS FAT16" },
161 { 0xDF, "BootIt EMBRM(FAT16/32)" },
162 { 0xEB, "BeOS BFS" },
163 { 0xEE, "EFI GPT protective" },
164 { 0xEF, "EFI filesystem" },
165 { 0xF0, "Linux/PA-RISC boot" },
166 { 0xF2, "DOS 3.3+ second" },
169 { 0xFC, "VmWare swap" },
170 { 0xFD, "Linux RAID" },
171 { 0xFE, "NT hidden" },
175 GetPartTypeStringFromPartitionType(
180 /* Determine partition type */
182 if (IsContainerPartition(partitionType
))
184 StringCchCopy(strPartType
, cchPartType
, MUIGetString(STRING_EXTENDED_PARTITION
));
186 else if (partitionType
== PARTITION_ENTRY_UNUSED
)
188 StringCchCopy(strPartType
, cchPartType
, MUIGetString(STRING_FORMATUNUSED
));
194 /* Do the table lookup */
195 for (i
= 0; i
< ARRAYSIZE(PartitionTypes
); i
++)
197 if (partitionType
== PartitionTypes
[i
].Type
)
199 StringCchCopy(strPartType
, cchPartType
, PartitionTypes
[i
].Description
);
204 /* We are here because the partition type is unknown */
205 StringCchCopy(strPartType
, cchPartType
, MUIGetString(STRING_FORMATUNKNOWN
));
209 /* FUNCTIONS ****************************************************************/
211 #ifdef DUMP_PARTITION_TABLE
215 PDISKENTRY DiskEntry
)
217 PPARTITION_INFORMATION PartitionInfo
;
221 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
222 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
224 for (i
= 0; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
++)
226 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[i
];
227 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
229 PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
,
230 PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
,
231 PartitionInfo
->HiddenSectors
,
232 PartitionInfo
->PartitionNumber
,
233 PartitionInfo
->PartitionType
,
234 PartitionInfo
->BootIndicator
? '*': ' ',
235 PartitionInfo
->RewritePartition
? 'Y': 'N');
250 Temp
= Value
/ Alignment
;
252 return Temp
* Alignment
;
261 ULONGLONG Temp
, Result
;
263 Temp
= Value
/ Alignment
;
265 Result
= Temp
* Alignment
;
266 if (Value
% Alignment
)
274 IN ULONGLONG Dividend
,
275 IN ULONGLONG Divisor
)
277 return (Dividend
+ Divisor
/ 2) / Divisor
;
284 PDISKENTRY DiskEntry
)
286 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
290 RtlInitUnicodeString(&DiskEntry
->DriverName
,
294 L
"\\Scsi\\Scsi Port %lu",
297 RtlZeroMemory(&QueryTable
,
300 QueryTable
[0].Name
= L
"Driver";
301 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
302 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
304 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
309 if (!NT_SUCCESS(Status
))
311 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
321 PDISKENTRY DiskEntry
;
322 PPARTENTRY PartEntry
;
329 /* Assign drive letters to primary partitions */
330 Entry1
= List
->DiskListHead
.Flink
;
331 while (Entry1
!= &List
->DiskListHead
)
333 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
335 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
336 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
338 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
340 PartEntry
->DriveLetter
= 0;
342 if (PartEntry
->IsPartitioned
&&
343 !IsContainerPartition(PartEntry
->PartitionType
))
345 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
346 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
347 PartEntry
->SectorCount
.QuadPart
!= 0LL))
351 PartEntry
->DriveLetter
= Letter
;
357 Entry2
= Entry2
->Flink
;
360 Entry1
= Entry1
->Flink
;
363 /* Assign drive letters to logical drives */
364 Entry1
= List
->DiskListHead
.Flink
;
365 while (Entry1
!= &List
->DiskListHead
)
367 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
369 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
370 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
372 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
374 PartEntry
->DriveLetter
= 0;
376 if (PartEntry
->IsPartitioned
)
378 if (IsRecognizedPartition(PartEntry
->PartitionType
) ||
379 (PartEntry
->PartitionType
== PARTITION_ENTRY_UNUSED
&&
380 PartEntry
->SectorCount
.QuadPart
!= 0LL))
384 PartEntry
->DriveLetter
= Letter
;
390 Entry2
= Entry2
->Flink
;
393 Entry1
= Entry1
->Flink
;
400 DiskIdentifierQueryRoutine(
408 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
409 UNICODE_STRING NameU
;
411 if (ValueType
== REG_SZ
&&
412 ValueLength
== 20 * sizeof(WCHAR
))
414 NameU
.Buffer
= (PWCHAR
)ValueData
;
415 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
416 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
418 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
419 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
421 return STATUS_SUCCESS
;
424 return STATUS_UNSUCCESSFUL
;
430 DiskConfigurationDataQueryRoutine(
438 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
439 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
440 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
443 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
444 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
445 return STATUS_UNSUCCESSFUL
;
447 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
449 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
451 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
452 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
453 return STATUS_UNSUCCESSFUL
;
456 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
458 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
459 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
462 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
463 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
465 return STATUS_SUCCESS
;
468 return STATUS_UNSUCCESSFUL
;
474 SystemConfigurationDataQueryRoutine(
482 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
483 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
486 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
487 ValueLength
< sizeof (CM_FULL_RESOURCE_DESCRIPTOR
))
488 return STATUS_UNSUCCESSFUL
;
490 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
492 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
494 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
495 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
496 return STATUS_UNSUCCESSFUL
;
499 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
501 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
502 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
505 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*) RtlAllocateHeap(ProcessHeap
, 0, FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
506 if (*Int13Drives
== NULL
)
507 return STATUS_NO_MEMORY
;
510 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
511 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
512 return STATUS_SUCCESS
;
515 return STATUS_UNSUCCESSFUL
;
519 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
522 EnumerateBiosDiskEntries(
525 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
530 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
531 PBIOSDISKENTRY BiosDiskEntry
;
533 memset(QueryTable
, 0, sizeof(QueryTable
));
535 QueryTable
[1].Name
= L
"Configuration Data";
536 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
538 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
539 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
543 if (!NT_SUCCESS(Status
))
545 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
552 swprintf(Name
, L
"%s\\%lu", ROOT_NAME
, AdapterCount
);
553 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
558 if (!NT_SUCCESS(Status
))
563 swprintf(Name
, L
"%s\\%lu\\DiskController", ROOT_NAME
, AdapterCount
);
564 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
569 if (NT_SUCCESS(Status
))
573 swprintf(Name
, L
"%s\\%lu\\DiskController\\0", ROOT_NAME
, AdapterCount
);
574 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
579 if (!NT_SUCCESS(Status
))
581 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
585 swprintf(Name
, L
"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME
, AdapterCount
);
586 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
591 if (NT_SUCCESS(Status
))
593 QueryTable
[0].Name
= L
"Identifier";
594 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
595 QueryTable
[1].Name
= L
"Configuration Data";
596 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
601 BiosDiskEntry
= (BIOSDISKENTRY
*) RtlAllocateHeap(ProcessHeap
, HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
602 if (BiosDiskEntry
== NULL
)
607 swprintf(Name
, L
"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME
, AdapterCount
, DiskCount
);
608 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
611 (PVOID
)BiosDiskEntry
,
613 if (!NT_SUCCESS(Status
))
615 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
619 BiosDiskEntry
->DiskNumber
= DiskCount
;
620 BiosDiskEntry
->Recognized
= FALSE
;
622 if (DiskCount
< Int13Drives
[0].NumberDrives
)
624 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
628 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount
);
631 InsertTailList(&PartList
->BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
633 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
634 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
635 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
636 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
637 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
638 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
639 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
640 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
641 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
642 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
643 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
649 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
657 RtlFreeHeap(ProcessHeap
, 0, Int13Drives
);
665 PDISKENTRY DiskEntry
,
666 ULONG PartitionIndex
,
667 BOOLEAN LogicalPartition
)
669 PPARTITION_INFORMATION PartitionInfo
;
670 PPARTENTRY PartEntry
;
672 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
673 if (PartitionInfo
->PartitionType
== 0 ||
674 (LogicalPartition
== TRUE
&& IsContainerPartition(PartitionInfo
->PartitionType
)))
677 PartEntry
= RtlAllocateHeap(ProcessHeap
,
680 if (PartEntry
== NULL
)
685 PartEntry
->DiskEntry
= DiskEntry
;
687 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
688 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
690 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
691 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
692 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
694 PartEntry
->LogicalPartition
= LogicalPartition
;
695 PartEntry
->IsPartitioned
= TRUE
;
696 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
697 PartEntry
->PartitionIndex
= PartitionIndex
;
699 if (IsContainerPartition(PartEntry
->PartitionType
))
701 PartEntry
->FormatState
= Unformatted
;
703 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
704 DiskEntry
->ExtendedPartition
= PartEntry
;
706 else if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
707 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
708 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
709 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
710 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
711 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
714 if (CheckFatFormat())
716 PartEntry
->FormatState
= Preformatted
;
720 PartEntry
->FormatState
= Unformatted
;
723 PartEntry
->FormatState
= Preformatted
;
725 else if (PartEntry
->PartitionType
== PARTITION_EXT2
)
728 if (CheckExt2Format())
730 PartEntry
->FormatState
= Preformatted
;
734 PartEntry
->FormatState
= Unformatted
;
737 PartEntry
->FormatState
= Preformatted
;
739 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
742 if (CheckNtfsFormat())
744 PartEntry
->FormatState
= Preformatted
;
746 else if (CheckHpfsFormat())
748 PartEntry
->FormatState
= Preformatted
;
752 PartEntry
->FormatState
= Unformatted
;
755 PartEntry
->FormatState
= Preformatted
;
759 PartEntry
->FormatState
= UnknownFormat
;
762 if (LogicalPartition
)
763 InsertTailList(&DiskEntry
->LogicalPartListHead
,
764 &PartEntry
->ListEntry
);
766 InsertTailList(&DiskEntry
->PrimaryPartListHead
,
767 &PartEntry
->ListEntry
);
773 ScanForUnpartitionedDiskSpace(
774 PDISKENTRY DiskEntry
)
776 ULONGLONG LastStartSector
;
777 ULONGLONG LastSectorCount
;
778 ULONGLONG LastUnusedSectorCount
;
779 PPARTENTRY PartEntry
;
780 PPARTENTRY NewPartEntry
;
783 DPRINT("ScanForUnpartitionedDiskSpace()\n");
785 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
787 DPRINT1("No primary partition!\n");
789 /* Create a partition table that represents the empty disk */
790 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
793 if (NewPartEntry
== NULL
)
796 NewPartEntry
->DiskEntry
= DiskEntry
;
798 NewPartEntry
->IsPartitioned
= FALSE
;
799 NewPartEntry
->StartSector
.QuadPart
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
800 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) -
801 NewPartEntry
->StartSector
.QuadPart
;
803 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
804 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
805 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
807 NewPartEntry
->FormatState
= Unformatted
;
809 InsertTailList(&DiskEntry
->PrimaryPartListHead
,
810 &NewPartEntry
->ListEntry
);
815 /* Start partition at head 1, cylinder 0 */
816 LastStartSector
= DiskEntry
->SectorAlignment
;
817 LastSectorCount
= 0ULL;
818 LastUnusedSectorCount
= 0ULL;
820 Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
821 while (Entry
!= &DiskEntry
->PrimaryPartListHead
)
823 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
825 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
826 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
828 LastUnusedSectorCount
=
829 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
831 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
832 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
834 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
836 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
839 if (NewPartEntry
== NULL
)
842 NewPartEntry
->DiskEntry
= DiskEntry
;
844 NewPartEntry
->IsPartitioned
= FALSE
;
845 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
846 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
847 NewPartEntry
->StartSector
.QuadPart
;
849 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
850 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
851 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
853 NewPartEntry
->FormatState
= Unformatted
;
855 /* Insert the table into the list */
856 InsertTailList(&PartEntry
->ListEntry
,
857 &NewPartEntry
->ListEntry
);
860 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
861 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
864 Entry
= Entry
->Flink
;
867 /* Check for trailing unpartitioned disk space */
868 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
870 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
872 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
874 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
876 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
879 if (NewPartEntry
== NULL
)
882 NewPartEntry
->DiskEntry
= DiskEntry
;
884 NewPartEntry
->IsPartitioned
= FALSE
;
885 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
886 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
887 NewPartEntry
->StartSector
.QuadPart
;
889 DPRINT("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
890 DPRINT("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
891 DPRINT("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
893 NewPartEntry
->FormatState
= Unformatted
;
895 /* Append the table to the list */
896 InsertTailList(&DiskEntry
->PrimaryPartListHead
,
897 &NewPartEntry
->ListEntry
);
901 if (DiskEntry
->ExtendedPartition
!= NULL
)
903 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
905 DPRINT1("No logical partition!\n");
907 /* Create a partition table entry that represents the empty extended partition */
908 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
911 if (NewPartEntry
== NULL
)
914 NewPartEntry
->DiskEntry
= DiskEntry
;
915 NewPartEntry
->LogicalPartition
= TRUE
;
917 NewPartEntry
->IsPartitioned
= FALSE
;
918 NewPartEntry
->StartSector
.QuadPart
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
919 NewPartEntry
->SectorCount
.QuadPart
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
921 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
922 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
923 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
925 NewPartEntry
->FormatState
= Unformatted
;
927 InsertTailList(&DiskEntry
->LogicalPartListHead
,
928 &NewPartEntry
->ListEntry
);
933 /* Start partition at head 1, cylinder 0 */
934 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
935 LastSectorCount
= 0ULL;
936 LastUnusedSectorCount
= 0ULL;
938 Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
939 while (Entry
!= &DiskEntry
->LogicalPartListHead
)
941 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
943 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
944 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
946 LastUnusedSectorCount
=
947 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
949 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
950 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
952 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
954 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
957 if (NewPartEntry
== NULL
)
960 NewPartEntry
->DiskEntry
= DiskEntry
;
961 NewPartEntry
->LogicalPartition
= TRUE
;
963 NewPartEntry
->IsPartitioned
= FALSE
;
964 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
965 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
966 NewPartEntry
->StartSector
.QuadPart
;
968 DPRINT("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
969 DPRINT("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
970 DPRINT("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
972 NewPartEntry
->FormatState
= Unformatted
;
974 /* Insert the table into the list */
975 InsertTailList(&PartEntry
->ListEntry
,
976 &NewPartEntry
->ListEntry
);
979 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
980 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
983 Entry
= Entry
->Flink
;
986 /* Check for trailing unpartitioned disk space */
987 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
989 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
991 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
993 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
995 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
998 if (NewPartEntry
== NULL
)
1001 NewPartEntry
->DiskEntry
= DiskEntry
;
1002 NewPartEntry
->LogicalPartition
= TRUE
;
1004 NewPartEntry
->IsPartitioned
= FALSE
;
1005 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
1006 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
1007 NewPartEntry
->StartSector
.QuadPart
;
1009 DPRINT("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
1010 DPRINT("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
1011 DPRINT("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
1013 NewPartEntry
->FormatState
= Unformatted
;
1015 /* Append the table to the list */
1016 InsertTailList(&DiskEntry
->LogicalPartListHead
,
1017 &NewPartEntry
->ListEntry
);
1022 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1030 IN PDISKENTRY DiskEntry
)
1032 LARGE_INTEGER SystemTime
;
1033 TIME_FIELDS TimeFields
;
1035 PDISKENTRY DiskEntry2
;
1038 Buffer
= (PUCHAR
)&DiskEntry
->LayoutBuffer
->Signature
;
1042 NtQuerySystemTime(&SystemTime
);
1043 RtlTimeToTimeFields(&SystemTime
, &TimeFields
);
1045 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
1046 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
1047 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
1048 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
1050 if (DiskEntry
->LayoutBuffer
->Signature
== 0)
1055 /* check if the signature already exist */
1057 * Check also signatures from disks, which are
1058 * not visible (bootable) by the bios.
1060 Entry2
= List
->DiskListHead
.Flink
;
1061 while (Entry2
!= &List
->DiskListHead
)
1063 DiskEntry2
= CONTAINING_RECORD(Entry2
, DISKENTRY
, ListEntry
);
1065 if (DiskEntry
!= DiskEntry2
&&
1066 DiskEntry
->LayoutBuffer
->Signature
== DiskEntry2
->LayoutBuffer
->Signature
)
1069 Entry2
= Entry2
->Flink
;
1072 if (Entry2
== &List
->DiskListHead
)
1080 UpdateDiskSignatures(
1084 PDISKENTRY DiskEntry
;
1086 /* Print partition lines*/
1087 Entry
= List
->DiskListHead
.Flink
;
1088 while (Entry
!= &List
->DiskListHead
)
1090 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1092 if (DiskEntry
->LayoutBuffer
&&
1093 DiskEntry
->LayoutBuffer
->Signature
== 0)
1095 SetDiskSignature(List
, DiskEntry
);
1096 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].RewritePartition
= TRUE
;
1099 Entry
= Entry
->Flink
;
1111 DISK_GEOMETRY DiskGeometry
;
1112 SCSI_ADDRESS ScsiAddress
;
1113 PDISKENTRY DiskEntry
;
1114 IO_STATUS_BLOCK Iosb
;
1116 PPARTITION_SECTOR Mbr
;
1118 LARGE_INTEGER FileOffset
;
1119 WCHAR Identifier
[20];
1123 PLIST_ENTRY ListEntry
;
1124 PBIOSDISKENTRY BiosDiskEntry
;
1125 ULONG LayoutBufferSize
;
1126 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
1128 Status
= NtDeviceIoControlFile(FileHandle
,
1133 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1137 sizeof(DISK_GEOMETRY
));
1138 if (!NT_SUCCESS(Status
))
1143 if (DiskGeometry
.MediaType
!= FixedMedia
&&
1144 DiskGeometry
.MediaType
!= RemovableMedia
)
1149 Status
= NtDeviceIoControlFile(FileHandle
,
1154 IOCTL_SCSI_GET_ADDRESS
,
1158 sizeof(SCSI_ADDRESS
));
1159 if (!NT_SUCCESS(Status
))
1164 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(ProcessHeap
,
1166 DiskGeometry
.BytesPerSector
);
1172 FileOffset
.QuadPart
= 0;
1173 Status
= NtReadFile(FileHandle
,
1179 DiskGeometry
.BytesPerSector
,
1182 if (!NT_SUCCESS(Status
))
1184 RtlFreeHeap(ProcessHeap
,
1187 DPRINT1("NtReadFile failed, status=%x\n", Status
);
1190 Signature
= Mbr
->Signature
;
1192 /* Calculate the MBR checksum */
1194 Buffer
= (PULONG
)Mbr
;
1195 for (i
= 0; i
< 128; i
++)
1197 Checksum
+= Buffer
[i
];
1199 Checksum
= ~Checksum
+ 1;
1201 swprintf(Identifier
, L
"%08x-%08x-A", Checksum
, Signature
);
1202 DPRINT("Identifier: %S\n", Identifier
);
1204 DiskEntry
= RtlAllocateHeap(ProcessHeap
,
1207 if (DiskEntry
== NULL
)
1212 // DiskEntry->Checksum = Checksum;
1213 // DiskEntry->Signature = Signature;
1214 DiskEntry
->BiosFound
= FALSE
;
1216 /* Check if this disk has a valid MBR */
1217 if (Mbr
->BootCode
[0] == 0 && Mbr
->BootCode
[1] == 0)
1218 DiskEntry
->NoMbr
= TRUE
;
1220 DiskEntry
->NoMbr
= FALSE
;
1222 /* Free Mbr sector buffer */
1223 RtlFreeHeap(ProcessHeap
,
1227 ListEntry
= List
->BiosDiskListHead
.Flink
;
1228 while(ListEntry
!= &List
->BiosDiskListHead
)
1230 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
1232 * Compare the size from bios and the reported size from driver.
1233 * If we have more than one disk with a zero or with the same signatur
1234 * we must create new signatures and reboot. After the reboot,
1235 * it is possible to identify the disks.
1237 if (BiosDiskEntry
->Signature
== Signature
&&
1238 BiosDiskEntry
->Checksum
== Checksum
&&
1239 !BiosDiskEntry
->Recognized
)
1241 if (!DiskEntry
->BiosFound
)
1243 DiskEntry
->BiosDiskNumber
= BiosDiskEntry
->DiskNumber
;
1244 DiskEntry
->BiosFound
= TRUE
;
1245 BiosDiskEntry
->Recognized
= TRUE
;
1251 ListEntry
= ListEntry
->Flink
;
1254 if (!DiskEntry
->BiosFound
)
1257 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1260 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber
);
1264 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
1265 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
1267 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
1268 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
1269 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
1270 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
1272 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
1273 DPRINT("TracksPerCylinder %I64u\n", DiskEntry
->TracksPerCylinder
);
1274 DPRINT("SectorsPerTrack %I64u\n", DiskEntry
->SectorsPerTrack
);
1275 DPRINT("BytesPerSector %I64u\n", DiskEntry
->BytesPerSector
);
1277 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
1278 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
1279 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
1281 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
1282 DiskEntry
->CylinderAlignment
= DiskGeometry
.TracksPerCylinder
*
1283 DiskGeometry
.SectorsPerTrack
;
1285 DPRINT("SectorCount %I64u\n", DiskEntry
->SectorCount
);
1286 DPRINT("SectorAlignment %lu\n", DiskEntry
->SectorAlignment
);
1288 DiskEntry
->DiskNumber
= DiskNumber
;
1289 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
1290 DiskEntry
->Bus
= ScsiAddress
.PathId
;
1291 DiskEntry
->Id
= ScsiAddress
.TargetId
;
1293 GetDriverName(DiskEntry
);
1295 InsertAscendingList(&List
->DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
1297 /* Allocate a layout buffer with 4 partition entries first */
1298 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
1299 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
1300 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(ProcessHeap
,
1303 if (DiskEntry
->LayoutBuffer
== NULL
)
1305 DPRINT1("Failed to allocate the disk layout buffer!\n");
1311 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
1312 Status
= NtDeviceIoControlFile(FileHandle
,
1317 IOCTL_DISK_GET_DRIVE_LAYOUT
,
1320 DiskEntry
->LayoutBuffer
,
1322 if (NT_SUCCESS(Status
))
1325 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1327 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
1331 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
1332 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
1334 DiskEntry
->LayoutBuffer
,
1336 if (NewLayoutBuffer
== NULL
)
1338 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1342 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
1345 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1347 #ifdef DUMP_PARTITION_TABLE
1348 DumpPartitionTable(DiskEntry
);
1351 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1352 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1353 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= 0)
1355 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1357 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1359 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1361 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1365 DPRINT1("No matching aligment found! Partiton 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1370 DPRINT1("No valid partiton table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1374 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1376 DiskEntry
->NewDisk
= TRUE
;
1377 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1379 for (i
= 0; i
< 4; i
++)
1380 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1384 for (i
= 0; i
< 4; i
++)
1386 AddPartitionToDisk(DiskNumber
,
1392 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1394 AddPartitionToDisk(DiskNumber
,
1401 ScanForUnpartitionedDiskSpace(DiskEntry
);
1406 CreatePartitionList(
1413 OBJECT_ATTRIBUTES ObjectAttributes
;
1414 SYSTEM_DEVICE_INFORMATION Sdi
;
1415 IO_STATUS_BLOCK Iosb
;
1419 WCHAR Buffer
[MAX_PATH
];
1420 UNICODE_STRING Name
;
1423 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
,
1431 List
->Right
= Right
;
1432 List
->Bottom
= Bottom
;
1437 List
->TopDisk
= (ULONG
)-1;
1438 List
->TopPartition
= (ULONG
)-1;
1440 List
->CurrentDisk
= NULL
;
1441 List
->CurrentPartition
= NULL
;
1443 List
->BootDisk
= NULL
;
1444 List
->BootPartition
= NULL
;
1446 List
->TempDisk
= NULL
;
1447 List
->TempPartition
= NULL
;
1448 List
->FormatState
= Start
;
1450 InitializeListHead(&List
->DiskListHead
);
1451 InitializeListHead(&List
->BiosDiskListHead
);
1453 EnumerateBiosDiskEntries(List
);
1455 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1457 sizeof(SYSTEM_DEVICE_INFORMATION
),
1459 if (!NT_SUCCESS(Status
))
1461 RtlFreeHeap(ProcessHeap
, 0, List
);
1465 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1468 L
"\\Device\\Harddisk%d\\Partition0",
1470 RtlInitUnicodeString(&Name
,
1473 InitializeObjectAttributes(&ObjectAttributes
,
1479 Status
= NtOpenFile(&FileHandle
,
1480 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1484 FILE_SYNCHRONOUS_IO_NONALERT
);
1485 if (NT_SUCCESS(Status
))
1487 AddDiskToList(FileHandle
,
1491 NtClose(FileHandle
);
1495 UpdateDiskSignatures(List
);
1497 AssignDriveLetters(List
);
1500 List
->TopPartition
= 0;
1502 /* Search for first usable disk and partition */
1503 if (IsListEmpty(&List
->DiskListHead
))
1505 List
->CurrentDisk
= NULL
;
1506 List
->CurrentPartition
= NULL
;
1510 List
->CurrentDisk
= CONTAINING_RECORD(List
->DiskListHead
.Flink
,
1514 if (IsListEmpty(&List
->CurrentDisk
->PrimaryPartListHead
))
1516 List
->CurrentPartition
= 0;
1520 List
->CurrentPartition
= CONTAINING_RECORD(List
->CurrentDisk
->PrimaryPartListHead
.Flink
,
1531 DestroyPartitionList(
1534 PDISKENTRY DiskEntry
;
1535 PBIOSDISKENTRY BiosDiskEntry
;
1536 PPARTENTRY PartEntry
;
1539 /* Release disk and partition info */
1540 while (!IsListEmpty(&List
->DiskListHead
))
1542 Entry
= RemoveHeadList(&List
->DiskListHead
);
1543 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1545 /* Release driver name */
1546 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1548 /* Release primary partition list */
1549 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1551 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1552 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1554 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1557 /* Release logical partition list */
1558 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1560 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1561 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1563 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
1566 /* Release layout buffer */
1567 if (DiskEntry
->LayoutBuffer
!= NULL
)
1568 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
->LayoutBuffer
);
1571 /* Release disk entry */
1572 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
1575 /* release the bios disk info */
1576 while(!IsListEmpty(&List
->BiosDiskListHead
))
1578 Entry
= RemoveHeadList(&List
->BiosDiskListHead
);
1579 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1581 RtlFreeHeap(ProcessHeap
, 0, BiosDiskEntry
);
1584 /* Release list head */
1585 RtlFreeHeap(ProcessHeap
, 0, List
);
1599 Width
= List
->Right
- List
->Left
- 1;
1600 Height
= List
->Bottom
- List
->Top
- 2;
1602 coPos
.X
= List
->Left
+ 1;
1603 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
1605 if (List
->Line
>= 0 && List
->Line
<= Height
)
1607 FillConsoleOutputAttribute(StdOutput
,
1608 FOREGROUND_WHITE
| BACKGROUND_BLUE
,
1613 FillConsoleOutputCharacterA(StdOutput
,
1628 PDISKENTRY DiskEntry
,
1629 PPARTENTRY PartEntry
)
1631 CHAR LineBuffer
[128];
1636 LARGE_INTEGER PartSize
;
1639 CHAR PartTypeString
[32];
1641 PartType
= PartTypeString
;
1643 Width
= List
->Right
- List
->Left
- 1;
1644 Height
= List
->Bottom
- List
->Top
- 2;
1646 coPos
.X
= List
->Left
+ 1;
1647 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
1649 if (PartEntry
->IsPartitioned
== FALSE
)
1651 PartSize
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1653 if (PartSize
.QuadPart
>= 10737418240) /* 10 GB */
1655 PartSize
.QuadPart
= RoundingDivide(PartSize
.QuadPart
, 1073741824);
1656 Unit
= MUIGetString(STRING_GB
);
1660 if (PartSize
.QuadPart
>= 10485760) /* 10 MB */
1662 PartSize
.QuadPart
= RoundingDivide(PartSize
.QuadPart
, 1048576);
1663 Unit
= MUIGetString(STRING_MB
);
1667 PartSize
.QuadPart
= RoundingDivide(PartSize
.QuadPart
, 1024);
1668 Unit
= MUIGetString(STRING_KB
);
1672 MUIGetString(STRING_UNPSPACE
),
1673 PartEntry
->LogicalPartition
? " " : "",
1674 PartEntry
->LogicalPartition
? "" : " ",
1680 /* Determine partition type */
1681 PartTypeString
[0] = '\0';
1682 if (PartEntry
->New
== TRUE
)
1684 PartType
= MUIGetString(STRING_UNFORMATTED
);
1686 else if (PartEntry
->IsPartitioned
== TRUE
)
1688 GetPartTypeStringFromPartitionType(PartEntry
->PartitionType
,
1691 PartType
= PartTypeString
;
1694 PartSize
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1696 if (PartSize
.QuadPart
>= 10737418240) /* 10 GB */
1698 PartSize
.QuadPart
= RoundingDivide(PartSize
.QuadPart
, 1073741824);
1699 Unit
= MUIGetString(STRING_GB
);
1703 if (PartSize
.QuadPart
>= 10485760) /* 10 MB */
1705 PartSize
.QuadPart
= RoundingDivide(PartSize
.QuadPart
, 1048576);
1706 Unit
= MUIGetString(STRING_MB
);
1710 PartSize
.QuadPart
= RoundingDivide(PartSize
.QuadPart
, 1024);
1711 Unit
= MUIGetString(STRING_KB
);
1714 if (strcmp(PartType
, MUIGetString(STRING_FORMATUNKNOWN
)) == 0)
1717 MUIGetString(STRING_HDDINFOUNK5
),
1718 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
1719 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
1720 PartEntry
->BootIndicator
? '*' : ' ',
1721 PartEntry
->LogicalPartition
? " " : "",
1722 PartEntry
->PartitionType
,
1723 PartEntry
->LogicalPartition
? "" : " ",
1730 "%c%c %c %s%-24s%s %6lu %s",
1731 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
1732 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
1733 PartEntry
->BootIndicator
? '*' : ' ',
1734 PartEntry
->LogicalPartition
? " " : "",
1736 PartEntry
->LogicalPartition
? "" : " ",
1742 Attribute
= (List
->CurrentDisk
== DiskEntry
&&
1743 List
->CurrentPartition
== PartEntry
) ?
1744 FOREGROUND_BLUE
| BACKGROUND_WHITE
:
1745 FOREGROUND_WHITE
| BACKGROUND_BLUE
;
1747 if (List
->Line
>= 0 && List
->Line
<= Height
)
1749 FillConsoleOutputCharacterA(StdOutput
,
1757 if (List
->Line
>= 0 && List
->Line
<= Height
)
1759 FillConsoleOutputAttribute(StdOutput
,
1767 if (List
->Line
>= 0 && List
->Line
<= Height
)
1769 WriteConsoleOutputCharacterA(StdOutput
,
1771 min(strlen(LineBuffer
), Width
),
1784 PDISKENTRY DiskEntry
)
1786 PPARTENTRY PrimaryPartEntry
, LogicalPartEntry
;
1787 PLIST_ENTRY PrimaryEntry
, LogicalEntry
;
1788 CHAR LineBuffer
[128];
1793 ULARGE_INTEGER DiskSize
;
1796 Width
= List
->Right
- List
->Left
- 1;
1797 Height
= List
->Bottom
- List
->Top
- 2;
1799 coPos
.X
= List
->Left
+ 1;
1800 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
1802 DiskSize
.QuadPart
= DiskEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
1803 if (DiskSize
.QuadPart
>= 10737418240) /* 10 GB */
1805 DiskSize
.QuadPart
= RoundingDivide(DiskSize
.QuadPart
, 1073741824);
1806 Unit
= MUIGetString(STRING_GB
);
1810 DiskSize
.QuadPart
= RoundingDivide(DiskSize
.QuadPart
, 1048576);
1811 if (DiskSize
.QuadPart
== 0)
1812 DiskSize
.QuadPart
= 1;
1813 Unit
= MUIGetString(STRING_MB
);
1816 if (DiskEntry
->DriverName
.Length
> 0)
1819 MUIGetString(STRING_HDINFOPARTSELECT
),
1822 DiskEntry
->DiskNumber
,
1826 DiskEntry
->DriverName
.Buffer
);
1831 MUIGetString(STRING_HDDINFOUNK6
),
1834 DiskEntry
->DiskNumber
,
1840 if (List
->Line
>= 0 && List
->Line
<= Height
)
1842 FillConsoleOutputAttribute(StdOutput
,
1843 FOREGROUND_WHITE
| BACKGROUND_BLUE
,
1848 FillConsoleOutputCharacterA(StdOutput
,
1856 if (List
->Line
>= 0 && List
->Line
<= Height
)
1858 WriteConsoleOutputCharacterA(StdOutput
,
1860 min((USHORT
)strlen(LineBuffer
), Width
- 2),
1867 /* Print separator line */
1868 PrintEmptyLine(List
);
1870 /* Print partition lines*/
1871 PrimaryEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
1872 while (PrimaryEntry
!= &DiskEntry
->PrimaryPartListHead
)
1874 PrimaryPartEntry
= CONTAINING_RECORD(PrimaryEntry
, PARTENTRY
, ListEntry
);
1876 PrintPartitionData(List
,
1880 if (IsContainerPartition(PrimaryPartEntry
->PartitionType
))
1882 LogicalEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
1883 while (LogicalEntry
!= &DiskEntry
->LogicalPartListHead
)
1885 LogicalPartEntry
= CONTAINING_RECORD(LogicalEntry
, PARTENTRY
, ListEntry
);
1887 PrintPartitionData(List
,
1891 LogicalEntry
= LogicalEntry
->Flink
;
1895 PrimaryEntry
= PrimaryEntry
->Flink
;
1898 /* Print separator line */
1899 PrintEmptyLine(List
);
1907 PLIST_ENTRY Entry
, Entry2
;
1908 PDISKENTRY DiskEntry
;
1909 PPARTENTRY PartEntry
= NULL
;
1913 SHORT CurrentDiskLine
;
1914 SHORT CurrentPartLine
;
1916 BOOL CurrentPartLineFound
= FALSE
;
1917 BOOL CurrentDiskLineFound
= FALSE
;
1919 /* Calculate the line of the current disk and partition */
1920 CurrentDiskLine
= 0;
1921 CurrentPartLine
= 0;
1924 Entry
= List
->DiskListHead
.Flink
;
1925 while (Entry
!= &List
->DiskListHead
)
1927 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1930 if (CurrentPartLineFound
== FALSE
)
1932 CurrentPartLine
+= 2;
1935 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
1936 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
1938 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
1939 if (PartEntry
== List
->CurrentPartition
)
1941 CurrentPartLineFound
= TRUE
;
1944 Entry2
= Entry2
->Flink
;
1945 if (CurrentPartLineFound
== FALSE
)
1953 if (DiskEntry
== List
->CurrentDisk
)
1955 CurrentDiskLineFound
= TRUE
;
1958 Entry
= Entry
->Flink
;
1959 if (Entry
!= &List
->DiskListHead
)
1961 if (CurrentDiskLineFound
== FALSE
)
1964 CurrentDiskLine
= CurrentPartLine
;
1975 /* If it possible, make the disk name visible */
1976 if (CurrentPartLine
< List
->Offset
)
1978 List
->Offset
= CurrentPartLine
;
1980 else if (CurrentPartLine
- List
->Offset
> List
->Bottom
- List
->Top
- 2)
1982 List
->Offset
= CurrentPartLine
- (List
->Bottom
- List
->Top
- 2);
1985 if (CurrentDiskLine
< List
->Offset
&& CurrentPartLine
- CurrentDiskLine
< List
->Bottom
- List
->Top
- 2)
1987 List
->Offset
= CurrentDiskLine
;
1990 /* draw upper left corner */
1991 coPos
.X
= List
->Left
;
1992 coPos
.Y
= List
->Top
;
1993 FillConsoleOutputCharacterA(StdOutput
,
1999 /* draw upper edge */
2000 coPos
.X
= List
->Left
+ 1;
2001 coPos
.Y
= List
->Top
;
2002 if (List
->Offset
== 0)
2004 FillConsoleOutputCharacterA(StdOutput
,
2006 List
->Right
- List
->Left
- 1,
2012 FillConsoleOutputCharacterA(StdOutput
,
2014 List
->Right
- List
->Left
- 5,
2017 coPos
.X
= List
->Right
- 5;
2018 WriteConsoleOutputCharacterA(StdOutput
,
2023 coPos
.X
= List
->Right
- 2;
2024 FillConsoleOutputCharacterA(StdOutput
,
2031 /* draw upper right corner */
2032 coPos
.X
= List
->Right
;
2033 coPos
.Y
= List
->Top
;
2034 FillConsoleOutputCharacterA(StdOutput
,
2040 /* draw left and right edge */
2041 for (i
= List
->Top
+ 1; i
< List
->Bottom
; i
++)
2043 coPos
.X
= List
->Left
;
2045 FillConsoleOutputCharacterA(StdOutput
,
2051 coPos
.X
= List
->Right
;
2052 FillConsoleOutputCharacterA(StdOutput
,
2059 /* draw lower left corner */
2060 coPos
.X
= List
->Left
;
2061 coPos
.Y
= List
->Bottom
;
2062 FillConsoleOutputCharacterA(StdOutput
,
2068 /* draw lower edge */
2069 coPos
.X
= List
->Left
+ 1;
2070 coPos
.Y
= List
->Bottom
;
2071 if (LastLine
- List
->Offset
<= List
->Bottom
- List
->Top
- 2)
2073 FillConsoleOutputCharacterA(StdOutput
,
2075 List
->Right
- List
->Left
- 1,
2081 FillConsoleOutputCharacterA(StdOutput
,
2083 List
->Right
- List
->Left
- 5,
2086 coPos
.X
= List
->Right
- 5;
2087 WriteConsoleOutputCharacterA(StdOutput
,
2088 "(\x19)", // "(down)"
2092 coPos
.X
= List
->Right
- 2;
2093 FillConsoleOutputCharacterA(StdOutput
,
2100 /* draw lower right corner */
2101 coPos
.X
= List
->Right
;
2102 coPos
.Y
= List
->Bottom
;
2103 FillConsoleOutputCharacterA(StdOutput
,
2109 /* print list entries */
2110 List
->Line
= - List
->Offset
;
2112 Entry
= List
->DiskListHead
.Flink
;
2113 while (Entry
!= &List
->DiskListHead
)
2115 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
2117 /* Print disk entry */
2121 Entry
= Entry
->Flink
;
2130 ULONG PartitionNumber
)
2132 PDISKENTRY DiskEntry
;
2133 PPARTENTRY PartEntry
;
2137 /* Check for empty disks */
2138 if (IsListEmpty(&List
->DiskListHead
))
2141 /* Check for first usable entry on next disk */
2142 Entry1
= List
->CurrentDisk
->ListEntry
.Flink
;
2143 while (Entry1
!= &List
->DiskListHead
)
2145 DiskEntry
= CONTAINING_RECORD(Entry1
, DISKENTRY
, ListEntry
);
2147 if (DiskEntry
->DiskNumber
== DiskNumber
)
2149 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
2150 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
2152 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
2154 if (PartEntry
->PartitionNumber
== PartitionNumber
)
2156 List
->CurrentDisk
= DiskEntry
;
2157 List
->CurrentPartition
= PartEntry
;
2158 DrawPartitionList(List
);
2162 Entry2
= Entry2
->Flink
;
2168 Entry1
= Entry1
->Flink
;
2176 ScrollDownPartitionList(
2179 PLIST_ENTRY DiskListEntry
;
2180 PLIST_ENTRY PartListEntry
;
2181 PDISKENTRY DiskEntry
;
2182 PPARTENTRY PartEntry
;
2184 /* Fail, if no disks are available */
2185 if (IsListEmpty(&List
->DiskListHead
))
2188 /* Check for next usable entry on current disk */
2189 if (List
->CurrentPartition
!= NULL
)
2191 if (List
->CurrentPartition
->LogicalPartition
)
2193 /* Logical partition */
2195 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2196 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2198 /* Next logical partition */
2199 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2201 List
->CurrentPartition
= PartEntry
;
2206 PartListEntry
= List
->CurrentDisk
->ExtendedPartition
->ListEntry
.Flink
;
2207 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2209 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2211 List
->CurrentPartition
= PartEntry
;
2218 /* Primary or extended partition */
2220 if (List
->CurrentPartition
->IsPartitioned
== TRUE
&&
2221 IsContainerPartition(List
->CurrentPartition
->PartitionType
))
2223 /* First logical partition */
2224 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Flink
;
2225 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2227 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2229 List
->CurrentPartition
= PartEntry
;
2235 /* Next primary partition */
2236 PartListEntry
= List
->CurrentPartition
->ListEntry
.Flink
;
2237 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2239 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2241 List
->CurrentPartition
= PartEntry
;
2248 /* Search for the first partition entry on the next disk */
2249 DiskListEntry
= List
->CurrentDisk
->ListEntry
.Flink
;
2250 while (DiskListEntry
!= &List
->DiskListHead
)
2252 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2254 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2255 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2257 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2259 List
->CurrentDisk
= DiskEntry
;
2260 List
->CurrentPartition
= PartEntry
;
2264 DiskListEntry
= DiskListEntry
->Flink
;
2272 ScrollUpPartitionList(
2275 PLIST_ENTRY DiskListEntry
;
2276 PLIST_ENTRY PartListEntry
;
2277 PDISKENTRY DiskEntry
;
2278 PPARTENTRY PartEntry
;
2280 /* Fail, if no disks are available */
2281 if (IsListEmpty(&List
->DiskListHead
))
2284 /* Check for previous usable entry on current disk */
2285 if (List
->CurrentPartition
!= NULL
)
2287 if (List
->CurrentPartition
->LogicalPartition
)
2289 /* Logical partition */
2290 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2291 if (PartListEntry
!= &List
->CurrentDisk
->LogicalPartListHead
)
2293 /* Previous logical partition */
2294 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2298 /* Extended partition*/
2299 PartEntry
= List
->CurrentDisk
->ExtendedPartition
;
2302 List
->CurrentPartition
= PartEntry
;
2307 /* Primary or extended partition */
2309 PartListEntry
= List
->CurrentPartition
->ListEntry
.Blink
;
2310 if (PartListEntry
!= &List
->CurrentDisk
->PrimaryPartListHead
)
2312 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2314 if (PartEntry
->IsPartitioned
== TRUE
&&
2315 IsContainerPartition(PartEntry
->PartitionType
))
2317 PartListEntry
= List
->CurrentDisk
->LogicalPartListHead
.Blink
;
2318 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2321 List
->CurrentPartition
= PartEntry
;
2328 /* Search for the last partition entry on the previous disk */
2329 DiskListEntry
= List
->CurrentDisk
->ListEntry
.Blink
;
2330 while (DiskListEntry
!= &List
->DiskListHead
)
2332 DiskEntry
= CONTAINING_RECORD(DiskListEntry
, DISKENTRY
, ListEntry
);
2334 PartListEntry
= DiskEntry
->PrimaryPartListHead
.Blink
;
2335 if (PartListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2337 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2339 if (PartEntry
->IsPartitioned
== TRUE
&&
2340 IsContainerPartition(PartEntry
->PartitionType
))
2342 PartListEntry
= DiskEntry
->LogicalPartListHead
.Blink
;
2343 if (PartListEntry
!= &DiskEntry
->LogicalPartListHead
)
2345 PartEntry
= CONTAINING_RECORD(PartListEntry
, PARTENTRY
, ListEntry
);
2347 List
->CurrentDisk
= DiskEntry
;
2348 List
->CurrentPartition
= PartEntry
;
2354 List
->CurrentDisk
= DiskEntry
;
2355 List
->CurrentPartition
= PartEntry
;
2360 DiskListEntry
= DiskListEntry
->Blink
;
2370 PPARTITION_INFORMATION PartitionInfo
)
2372 if (PartitionInfo
->StartingOffset
.QuadPart
== 0 &&
2373 PartitionInfo
->PartitionLength
.QuadPart
== 0)
2382 IsSamePrimaryLayoutEntry(
2383 IN PPARTITION_INFORMATION PartitionInfo
,
2384 IN PDISKENTRY DiskEntry
,
2385 IN PPARTENTRY PartEntry
)
2387 if (PartitionInfo
->StartingOffset
.QuadPart
== PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
&&
2388 PartitionInfo
->PartitionLength
.QuadPart
== PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
)
2389 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2390 // PartitionInfo->PartitionType == PartEntry->PartitionType
2399 GetPrimaryPartitionCount(
2400 IN PDISKENTRY DiskEntry
)
2403 PPARTENTRY PartEntry
;
2406 Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2407 while (Entry
!= &DiskEntry
->PrimaryPartListHead
)
2409 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
2410 if (PartEntry
->IsPartitioned
== TRUE
)
2413 Entry
= Entry
->Flink
;
2422 GetLogicalPartitionCount(
2423 PDISKENTRY DiskEntry
)
2425 PLIST_ENTRY ListEntry
;
2426 PPARTENTRY PartEntry
;
2429 ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2430 while (ListEntry
!= &DiskEntry
->LogicalPartListHead
)
2432 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2433 if (PartEntry
->IsPartitioned
)
2436 ListEntry
= ListEntry
->Flink
;
2445 ReAllocateLayoutBuffer(
2446 PDISKENTRY DiskEntry
)
2448 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
2449 ULONG NewPartitionCount
;
2450 ULONG CurrentPartitionCount
= 0;
2451 ULONG LayoutBufferSize
;
2454 DPRINT1("ReAllocateLayoutBuffer()\n");
2456 NewPartitionCount
= 4 + GetLogicalPartitionCount(DiskEntry
) * 4;
2458 if (DiskEntry
->LayoutBuffer
)
2459 CurrentPartitionCount
= DiskEntry
->LayoutBuffer
->PartitionCount
;
2461 DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
2462 CurrentPartitionCount
, NewPartitionCount
);
2464 if (CurrentPartitionCount
== NewPartitionCount
)
2467 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
2468 ((NewPartitionCount
- ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
2469 NewLayoutBuffer
= RtlReAllocateHeap(ProcessHeap
,
2471 DiskEntry
->LayoutBuffer
,
2473 if (NewLayoutBuffer
== NULL
)
2475 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize
);
2479 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2480 if (NewPartitionCount
> CurrentPartitionCount
)
2482 for (i
= CurrentPartitionCount
; i
< NewPartitionCount
; i
++)
2483 NewLayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
2486 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
2487 DiskEntry
->LayoutBuffer
->PartitionCount
= NewPartitionCount
;
2496 IN PDISKENTRY DiskEntry
)
2498 PPARTITION_INFORMATION PartitionInfo
;
2499 PPARTITION_INFORMATION LinkInfo
= NULL
;
2500 PLIST_ENTRY ListEntry
;
2501 PPARTENTRY PartEntry
;
2502 LARGE_INTEGER HiddenSectors64
;
2504 ULONG PartitionNumber
= 1;
2506 DPRINT1("UpdateDiskLayout()\n");
2508 /* Resize the layout buffer if necessary */
2509 if (ReAllocateLayoutBuffer(DiskEntry
) == FALSE
)
2511 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2515 /* Update the primary partition table */
2517 ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
2518 while (ListEntry
!= &DiskEntry
->PrimaryPartListHead
)
2520 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2522 if (PartEntry
->IsPartitioned
== TRUE
)
2524 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2526 if (!IsSamePrimaryLayoutEntry(PartitionInfo
, DiskEntry
, PartEntry
))
2528 DPRINT1("Updating primary partition entry %lu\n", Index
);
2530 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2531 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2532 PartitionInfo
->HiddenSectors
= PartEntry
->StartSector
.LowPart
;
2533 PartitionInfo
->PartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
)) ? PartitionNumber
: 0;
2534 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2535 PartitionInfo
->BootIndicator
= PartEntry
->BootIndicator
;
2536 PartitionInfo
->RecognizedPartition
= FALSE
;
2537 PartitionInfo
->RewritePartition
= TRUE
;
2540 PartEntry
->PartitionNumber
= (!IsContainerPartition(PartEntry
->PartitionType
)) ? PartitionNumber
: 0;
2541 PartEntry
->PartitionIndex
= Index
;
2543 if (!IsContainerPartition(PartEntry
->PartitionType
))
2549 ListEntry
= ListEntry
->Flink
;
2552 /* Update the logical partition tables */
2554 ListEntry
= DiskEntry
->LogicalPartListHead
.Flink
;
2555 while (ListEntry
!= &DiskEntry
->LogicalPartListHead
)
2557 PartEntry
= CONTAINING_RECORD(ListEntry
, PARTENTRY
, ListEntry
);
2559 if (PartEntry
->IsPartitioned
)
2561 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2563 DPRINT1("Updating logical partition entry %lu\n", Index
);
2565 PartitionInfo
->StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
2566 PartitionInfo
->PartitionLength
.QuadPart
= PartEntry
->SectorCount
.QuadPart
* DiskEntry
->BytesPerSector
;
2567 PartitionInfo
->HiddenSectors
= DiskEntry
->SectorAlignment
;
2568 PartitionInfo
->PartitionNumber
= PartitionNumber
;
2569 PartitionInfo
->PartitionType
= PartEntry
->PartitionType
;
2570 PartitionInfo
->BootIndicator
= FALSE
;
2571 PartitionInfo
->RecognizedPartition
= FALSE
;
2572 PartitionInfo
->RewritePartition
= TRUE
;
2574 PartEntry
->PartitionNumber
= PartitionNumber
;
2575 PartEntry
->PartitionIndex
= Index
;
2577 /* Fill the link entry of the previous partition table */
2578 if (LinkInfo
!= NULL
)
2580 LinkInfo
->StartingOffset
.QuadPart
= (PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2581 LinkInfo
->PartitionLength
.QuadPart
= (PartEntry
->StartSector
.QuadPart
+ DiskEntry
->SectorAlignment
) * DiskEntry
->BytesPerSector
;
2582 HiddenSectors64
.QuadPart
= PartEntry
->StartSector
.QuadPart
- DiskEntry
->SectorAlignment
- DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
;
2583 LinkInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2584 LinkInfo
->PartitionNumber
= 0;
2585 LinkInfo
->PartitionType
= PARTITION_EXTENDED
;
2586 LinkInfo
->BootIndicator
= FALSE
;
2587 LinkInfo
->RecognizedPartition
= FALSE
;
2588 LinkInfo
->RewritePartition
= TRUE
;
2591 /* Save a pointer to the link entry of the current partition table */
2592 LinkInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
+ 1];
2598 ListEntry
= ListEntry
->Flink
;
2601 /* Wipe unused primary partition table entries */
2602 for (Index
= GetPrimaryPartitionCount(DiskEntry
); Index
< 4; Index
++)
2604 DPRINT1("Primary partition entry %lu\n", Index
);
2606 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2608 if (!IsEmptyLayoutEntry(PartitionInfo
))
2610 DPRINT1("Wiping primary partition entry %lu\n", Index
);
2612 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2613 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2614 PartitionInfo
->HiddenSectors
= 0;
2615 PartitionInfo
->PartitionNumber
= 0;
2616 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2617 PartitionInfo
->BootIndicator
= FALSE
;
2618 PartitionInfo
->RecognizedPartition
= FALSE
;
2619 PartitionInfo
->RewritePartition
= TRUE
;
2623 /* Wipe unused logical partition table entries */
2624 for (Index
= 4; Index
< DiskEntry
->LayoutBuffer
->PartitionCount
; Index
++)
2628 DPRINT1("Logical partition entry %lu\n", Index
);
2630 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[Index
];
2632 if (!IsEmptyLayoutEntry(PartitionInfo
))
2634 DPRINT1("Wiping partition entry %lu\n", Index
);
2636 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2637 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2638 PartitionInfo
->HiddenSectors
= 0;
2639 PartitionInfo
->PartitionNumber
= 0;
2640 PartitionInfo
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2641 PartitionInfo
->BootIndicator
= FALSE
;
2642 PartitionInfo
->RecognizedPartition
= FALSE
;
2643 PartitionInfo
->RewritePartition
= TRUE
;
2648 #ifdef DUMP_PARTITION_TABLE
2649 DumpPartitionTable(DiskEntry
);
2656 GetPrevUnpartitionedEntry(
2657 PDISKENTRY DiskEntry
,
2658 PPARTENTRY PartEntry
)
2660 PPARTENTRY PrevPartEntry
;
2661 PLIST_ENTRY ListHead
;
2663 if (PartEntry
->LogicalPartition
)
2664 ListHead
= &DiskEntry
->LogicalPartListHead
;
2666 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2668 if (PartEntry
->ListEntry
.Blink
!= ListHead
)
2670 PrevPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Blink
,
2673 if (PrevPartEntry
->IsPartitioned
== FALSE
)
2674 return PrevPartEntry
;
2683 GetNextUnpartitionedEntry(
2684 PDISKENTRY DiskEntry
,
2685 PPARTENTRY PartEntry
)
2687 PPARTENTRY NextPartEntry
;
2688 PLIST_ENTRY ListHead
;
2690 if (PartEntry
->LogicalPartition
)
2691 ListHead
= &DiskEntry
->LogicalPartListHead
;
2693 ListHead
= &DiskEntry
->PrimaryPartListHead
;
2695 if (PartEntry
->ListEntry
.Flink
!= ListHead
)
2697 NextPartEntry
= CONTAINING_RECORD(PartEntry
->ListEntry
.Flink
,
2700 if (NextPartEntry
->IsPartitioned
== FALSE
)
2701 return NextPartEntry
;
2709 CreatePrimaryPartition(
2711 ULONGLONG SectorCount
,
2714 PDISKENTRY DiskEntry
;
2715 PPARTENTRY PartEntry
;
2716 PPARTENTRY NewPartEntry
;
2718 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount
);
2721 List
->CurrentDisk
== NULL
||
2722 List
->CurrentPartition
== NULL
||
2723 List
->CurrentPartition
->IsPartitioned
== TRUE
)
2728 DiskEntry
= List
->CurrentDisk
;
2729 PartEntry
= List
->CurrentPartition
;
2731 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
2733 if (AutoCreate
== TRUE
||
2734 AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) - PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
)
2736 DPRINT1("Convert existing partition entry\n");
2738 /* Convert current entry to 'new (unformatted)' */
2739 PartEntry
->IsPartitioned
= TRUE
;
2740 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2741 PartEntry
->FormatState
= Unformatted
;
2742 PartEntry
->AutoCreate
= AutoCreate
;
2743 PartEntry
->New
= TRUE
;
2744 PartEntry
->BootIndicator
= FALSE
;
2746 DPRINT1("First Sector: %I64u\n", PartEntry
->StartSector
.QuadPart
);
2747 DPRINT1("Last Sector: %I64u\n", PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1);
2748 DPRINT1("Total Sectors: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
2752 DPRINT1("Add new partition entry\n");
2754 /* Insert and initialize a new partition entry */
2755 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
2758 if (NewPartEntry
== NULL
)
2761 /* Insert the new entry into the list */
2762 InsertTailList(&PartEntry
->ListEntry
,
2763 &NewPartEntry
->ListEntry
);
2765 NewPartEntry
->DiskEntry
= DiskEntry
;
2767 NewPartEntry
->IsPartitioned
= TRUE
;
2768 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
2769 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
2770 NewPartEntry
->StartSector
.QuadPart
;
2771 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2773 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
2774 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
2775 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
2777 NewPartEntry
->New
= TRUE
;
2778 NewPartEntry
->FormatState
= Unformatted
;
2779 NewPartEntry
->BootIndicator
= FALSE
;
2781 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
2782 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
2785 UpdateDiskLayout(DiskEntry
);
2787 DiskEntry
->Dirty
= TRUE
;
2789 AssignDriveLetters(List
);
2795 AddLogicalDiskSpace(
2796 PDISKENTRY DiskEntry
)
2798 PPARTENTRY NewPartEntry
;
2800 DPRINT1("AddLogicalDiskSpace()\n");
2802 /* Create a partition table entry that represents the empty space in the container partition */
2803 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
2806 if (NewPartEntry
== NULL
)
2809 NewPartEntry
->DiskEntry
= DiskEntry
;
2810 NewPartEntry
->LogicalPartition
= TRUE
;
2812 NewPartEntry
->IsPartitioned
= FALSE
;
2813 NewPartEntry
->StartSector
.QuadPart
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
2814 NewPartEntry
->SectorCount
.QuadPart
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
2816 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
2817 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
2818 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
2820 NewPartEntry
->FormatState
= Unformatted
;
2822 InsertTailList(&DiskEntry
->LogicalPartListHead
,
2823 &NewPartEntry
->ListEntry
);
2828 CreateExtendedPartition(
2830 ULONGLONG SectorCount
)
2832 PDISKENTRY DiskEntry
;
2833 PPARTENTRY PartEntry
;
2834 PPARTENTRY NewPartEntry
;
2836 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount
);
2839 List
->CurrentDisk
== NULL
||
2840 List
->CurrentPartition
== NULL
||
2841 List
->CurrentPartition
->IsPartitioned
== TRUE
)
2846 DiskEntry
= List
->CurrentDisk
;
2847 PartEntry
= List
->CurrentPartition
;
2849 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
2851 if (AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) - PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
)
2853 DPRINT1("Convert existing partition entry\n");
2855 /* Convert current entry to 'new (unformatted)' */
2856 PartEntry
->IsPartitioned
= TRUE
;
2857 PartEntry
->FormatState
= Formatted
;
2858 PartEntry
->AutoCreate
= FALSE
;
2859 PartEntry
->New
= FALSE
;
2860 PartEntry
->BootIndicator
= FALSE
;
2862 if (PartEntry
->StartSector
.QuadPart
< 1450560)
2864 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2865 PartEntry
->PartitionType
= PARTITION_EXTENDED
;
2869 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2870 PartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2873 DiskEntry
->ExtendedPartition
= PartEntry
;
2875 DPRINT1("First Sector: %I64u\n", PartEntry
->StartSector
.QuadPart
);
2876 DPRINT1("Last Sector: %I64u\n", PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1);
2877 DPRINT1("Total Sectors: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
2881 DPRINT1("Add new partition entry\n");
2883 /* Insert and initialize a new partition entry */
2884 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
2887 if (NewPartEntry
== NULL
)
2890 /* Insert the new entry into the list */
2891 InsertTailList(&PartEntry
->ListEntry
,
2892 &NewPartEntry
->ListEntry
);
2894 NewPartEntry
->DiskEntry
= DiskEntry
;
2896 NewPartEntry
->IsPartitioned
= TRUE
;
2897 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
2898 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
2899 NewPartEntry
->StartSector
.QuadPart
;
2901 NewPartEntry
->New
= FALSE
;
2902 NewPartEntry
->FormatState
= Formatted
;
2903 NewPartEntry
->BootIndicator
= FALSE
;
2905 if (NewPartEntry
->StartSector
.QuadPart
< 1450560)
2907 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2908 NewPartEntry
->PartitionType
= PARTITION_EXTENDED
;
2912 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2913 NewPartEntry
->PartitionType
= PARTITION_XINT13_EXTENDED
;
2916 DiskEntry
->ExtendedPartition
= NewPartEntry
;
2918 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
2919 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
2921 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
2922 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
2923 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
2926 AddLogicalDiskSpace(DiskEntry
);
2928 UpdateDiskLayout(DiskEntry
);
2930 DiskEntry
->Dirty
= TRUE
;
2932 AssignDriveLetters(List
);
2937 CreateLogicalPartition(
2939 ULONGLONG SectorCount
,
2942 PDISKENTRY DiskEntry
;
2943 PPARTENTRY PartEntry
;
2944 PPARTENTRY NewPartEntry
;
2946 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount
);
2949 List
->CurrentDisk
== NULL
||
2950 List
->CurrentPartition
== NULL
||
2951 List
->CurrentPartition
->IsPartitioned
== TRUE
)
2956 DiskEntry
= List
->CurrentDisk
;
2957 PartEntry
= List
->CurrentPartition
;
2959 DPRINT1("Current partition sector count: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
2961 if (AutoCreate
== TRUE
||
2962 AlignDown(PartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) - PartEntry
->StartSector
.QuadPart
== PartEntry
->SectorCount
.QuadPart
)
2964 DPRINT1("Convert existing partition entry\n");
2966 /* Convert current entry to 'new (unformatted)' */
2967 PartEntry
->IsPartitioned
= TRUE
;
2968 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
2969 PartEntry
->FormatState
= Unformatted
;
2970 PartEntry
->AutoCreate
= FALSE
;
2971 PartEntry
->New
= TRUE
;
2972 PartEntry
->BootIndicator
= FALSE
;
2973 PartEntry
->LogicalPartition
= TRUE
;
2975 DPRINT1("First Sector: %I64u\n", PartEntry
->StartSector
.QuadPart
);
2976 DPRINT1("Last Sector: %I64u\n", PartEntry
->StartSector
.QuadPart
+ PartEntry
->SectorCount
.QuadPart
- 1);
2977 DPRINT1("Total Sectors: %I64u\n", PartEntry
->SectorCount
.QuadPart
);
2981 DPRINT1("Add new partition entry\n");
2983 /* Insert and initialize a new partition entry */
2984 NewPartEntry
= RtlAllocateHeap(ProcessHeap
,
2987 if (NewPartEntry
== NULL
)
2990 /* Insert the new entry into the list */
2991 InsertTailList(&PartEntry
->ListEntry
,
2992 &NewPartEntry
->ListEntry
);
2994 NewPartEntry
->DiskEntry
= DiskEntry
;
2996 NewPartEntry
->IsPartitioned
= TRUE
;
2997 NewPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
2998 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ SectorCount
, DiskEntry
->SectorAlignment
) -
2999 NewPartEntry
->StartSector
.QuadPart
;
3000 NewPartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
3002 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
3003 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
3004 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
3006 NewPartEntry
->New
= TRUE
;
3007 NewPartEntry
->FormatState
= Unformatted
;
3008 NewPartEntry
->BootIndicator
= FALSE
;
3009 NewPartEntry
->LogicalPartition
= TRUE
;
3011 PartEntry
->StartSector
.QuadPart
= NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
;
3012 PartEntry
->SectorCount
.QuadPart
-= (PartEntry
->StartSector
.QuadPart
- NewPartEntry
->StartSector
.QuadPart
);
3015 UpdateDiskLayout(DiskEntry
);
3017 DiskEntry
->Dirty
= TRUE
;
3019 AssignDriveLetters(List
);
3024 DeleteCurrentPartition(
3027 PDISKENTRY DiskEntry
;
3028 PPARTENTRY PartEntry
;
3029 PPARTENTRY PrevPartEntry
;
3030 PPARTENTRY NextPartEntry
;
3031 PPARTENTRY LogicalPartEntry
;
3035 List
->CurrentDisk
== NULL
||
3036 List
->CurrentPartition
== NULL
||
3037 List
->CurrentPartition
->IsPartitioned
== FALSE
)
3042 DiskEntry
= List
->CurrentDisk
;
3043 PartEntry
= List
->CurrentPartition
;
3045 /* Delete all logical partiton entries if an extended partition will be deleted */
3046 if (DiskEntry
->ExtendedPartition
== PartEntry
)
3048 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
3050 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
3051 LogicalPartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
3053 RtlFreeHeap(ProcessHeap
, 0, LogicalPartEntry
);
3056 DiskEntry
->ExtendedPartition
= NULL
;
3059 /* Adjust unpartitioned disk space entries */
3061 /* Get pointer to previous and next unpartitioned entries */
3062 PrevPartEntry
= GetPrevUnpartitionedEntry(DiskEntry
,
3065 NextPartEntry
= GetNextUnpartitionedEntry(DiskEntry
,
3068 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
3070 /* Merge previous, current and next unpartitioned entry */
3072 /* Adjust the previous entries length */
3073 PrevPartEntry
->SectorCount
.QuadPart
+= (PartEntry
->SectorCount
.QuadPart
+ NextPartEntry
->SectorCount
.QuadPart
);
3075 /* Remove the current entry */
3076 RemoveEntryList(&PartEntry
->ListEntry
);
3077 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3079 /* Remove the next entry */
3080 RemoveEntryList (&NextPartEntry
->ListEntry
);
3081 RtlFreeHeap(ProcessHeap
, 0, NextPartEntry
);
3083 /* Update current partition */
3084 List
->CurrentPartition
= PrevPartEntry
;
3086 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
3088 /* Merge current and previous unpartitioned entry */
3090 /* Adjust the previous entries length */
3091 PrevPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3093 /* Remove the current entry */
3094 RemoveEntryList(&PartEntry
->ListEntry
);
3095 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3097 /* Update current partition */
3098 List
->CurrentPartition
= PrevPartEntry
;
3100 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
3102 /* Merge current and next unpartitioned entry */
3104 /* Adjust the next entries offset and length */
3105 NextPartEntry
->StartSector
.QuadPart
= PartEntry
->StartSector
.QuadPart
;
3106 NextPartEntry
->SectorCount
.QuadPart
+= PartEntry
->SectorCount
.QuadPart
;
3108 /* Remove the current entry */
3109 RemoveEntryList(&PartEntry
->ListEntry
);
3110 RtlFreeHeap(ProcessHeap
, 0, PartEntry
);
3112 /* Update current partition */
3113 List
->CurrentPartition
= NextPartEntry
;
3117 /* Nothing to merge but change current entry */
3118 PartEntry
->IsPartitioned
= FALSE
;
3119 PartEntry
->PartitionType
= PARTITION_ENTRY_UNUSED
;
3120 PartEntry
->FormatState
= Unformatted
;
3121 PartEntry
->DriveLetter
= 0;
3124 UpdateDiskLayout(DiskEntry
);
3126 DiskEntry
->Dirty
= TRUE
;
3128 AssignDriveLetters(List
);
3133 CheckActiveBootPartition(
3136 PDISKENTRY DiskEntry
;
3137 PPARTENTRY PartEntry
;
3138 PLIST_ENTRY ListEntry
;
3140 /* Check for empty disk list */
3141 if (IsListEmpty (&List
->DiskListHead
))
3143 List
->BootDisk
= NULL
;
3144 List
->BootPartition
= NULL
;
3149 if (List
->BootDisk
!= NULL
&&
3150 List
->BootPartition
!= NULL
)
3152 /* We already have an active boot partition */
3157 /* Choose the currently selected disk */
3158 DiskEntry
= List
->CurrentDisk
;
3160 /* Check for empty partition list */
3161 if (IsListEmpty (&DiskEntry
->PrimaryPartListHead
))
3163 List
->BootDisk
= NULL
;
3164 List
->BootPartition
= NULL
;
3168 PartEntry
= CONTAINING_RECORD(DiskEntry
->PrimaryPartListHead
.Flink
,
3172 /* Set active boot partition */
3173 if ((DiskEntry
->NewDisk
== TRUE
) ||
3174 (PartEntry
->BootIndicator
== FALSE
))
3176 PartEntry
->BootIndicator
= TRUE
;
3177 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].BootIndicator
= TRUE
;
3178 DiskEntry
->LayoutBuffer
->PartitionEntry
[PartEntry
->PartitionIndex
].RewritePartition
= TRUE
;
3179 DiskEntry
->Dirty
= TRUE
;
3181 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
3182 List
->BootDisk
= DiskEntry
;
3183 List
->BootPartition
= PartEntry
;
3188 /* Disk is not new, scan all partitions to find a bootable one */
3189 List
->BootDisk
= NULL
;
3190 List
->BootPartition
= NULL
;
3192 ListEntry
= DiskEntry
->PrimaryPartListHead
.Flink
;
3193 while (ListEntry
!= &DiskEntry
->PrimaryPartListHead
)
3195 PartEntry
= CONTAINING_RECORD(ListEntry
,
3199 /* Check if it is partitioned */
3200 if (PartEntry
->IsPartitioned
)
3202 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
&&
3203 PartEntry
->BootIndicator
)
3205 /* Yes, we found it */
3206 List
->BootDisk
= DiskEntry
;
3207 List
->BootPartition
= PartEntry
;
3209 DPRINT("Found bootable partition disk %d, drive letter %c\n",
3210 DiskEntry
->DiskNumber
, PartEntry
->DriveLetter
);
3215 /* Go to the next one */
3216 ListEntry
= ListEntry
->Flink
;
3225 IN PDISKENTRY DiskEntry
)
3227 WCHAR DstPath
[MAX_PATH
];
3228 OBJECT_ATTRIBUTES ObjectAttributes
;
3229 IO_STATUS_BLOCK Iosb
;
3230 UNICODE_STRING Name
;
3232 HANDLE FileHandle
= NULL
;
3235 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry
->DiskNumber
);
3238 L
"\\Device\\Harddisk%d\\Partition0",
3239 DiskEntry
->DiskNumber
);
3240 RtlInitUnicodeString(&Name
,
3242 InitializeObjectAttributes(&ObjectAttributes
,
3248 Status
= NtOpenFile(&FileHandle
,
3249 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
3253 FILE_SYNCHRONOUS_IO_NONALERT
);
3254 if (!NT_SUCCESS(Status
))
3256 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status
);
3260 #ifdef DUMP_PARTITION_TABLE
3261 DumpPartitionTable(DiskEntry
);
3264 BufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
3265 ((DiskEntry
->LayoutBuffer
->PartitionCount
- 1) * sizeof(PARTITION_INFORMATION
));
3266 Status
= NtDeviceIoControlFile(FileHandle
,
3271 IOCTL_DISK_SET_DRIVE_LAYOUT
,
3272 DiskEntry
->LayoutBuffer
,
3276 if (!NT_SUCCESS(Status
))
3278 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status
);
3281 if (FileHandle
!= NULL
)
3282 NtClose(FileHandle
);
3289 WritePartitionsToDisk(
3293 PDISKENTRY DiskEntry
;
3298 Entry
= List
->DiskListHead
.Flink
;
3299 while (Entry
!= &List
->DiskListHead
)
3301 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
3303 if (DiskEntry
->Dirty
== TRUE
)
3305 WritePartitions(List
, DiskEntry
);
3306 DiskEntry
->Dirty
= FALSE
;
3309 Entry
= Entry
->Flink
;
3317 SetMountedDeviceValues(
3320 PLIST_ENTRY Entry1
, Entry2
;
3321 PDISKENTRY DiskEntry
;
3322 PPARTENTRY PartEntry
;
3323 LARGE_INTEGER StartingOffset
;
3330 Entry1
= List
->DiskListHead
.Flink
;
3331 while (Entry1
!= &List
->DiskListHead
)
3333 DiskEntry
= CONTAINING_RECORD(Entry1
,
3337 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3338 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
3340 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3341 if (PartEntry
->IsPartitioned
)
3343 if (PartEntry
->DriveLetter
)
3345 StartingOffset
.QuadPart
= PartEntry
->StartSector
.QuadPart
* DiskEntry
->BytesPerSector
;
3346 if (!SetMountedDeviceValue(PartEntry
->DriveLetter
,
3347 DiskEntry
->LayoutBuffer
->Signature
,
3355 Entry2
= Entry2
->Flink
;
3358 Entry1
= Entry1
->Flink
;
3366 PrimaryPartitionCreationChecks(
3369 PDISKENTRY DiskEntry
;
3370 PPARTENTRY PartEntry
;
3372 DiskEntry
= List
->CurrentDisk
;
3373 PartEntry
= List
->CurrentPartition
;
3375 /* Fail if partition is already in use */
3376 if (PartEntry
->IsPartitioned
== TRUE
)
3377 return ERROR_NEW_PARTITION
;
3379 /* Fail if there are more than 4 partitions in the list */
3380 if (GetPrimaryPartitionCount(DiskEntry
) > 4)
3381 return ERROR_PARTITION_TABLE_FULL
;
3383 return ERROR_SUCCESS
;
3388 ExtendedPartitionCreationChecks(
3391 PDISKENTRY DiskEntry
;
3392 PPARTENTRY PartEntry
;
3394 DiskEntry
= List
->CurrentDisk
;
3395 PartEntry
= List
->CurrentPartition
;
3397 /* Fail if partition is already in use */
3398 if (PartEntry
->IsPartitioned
== TRUE
)
3399 return ERROR_NEW_PARTITION
;
3401 /* Fail if there are more than 4 partitions in the list */
3402 if (GetPrimaryPartitionCount(DiskEntry
) > 4)
3403 return ERROR_PARTITION_TABLE_FULL
;
3405 /* Fail if there is another extended partition in the list */
3406 if (DiskEntry
->ExtendedPartition
!= NULL
)
3407 return ERROR_ONLY_ONE_EXTENDED
;
3409 return ERROR_SUCCESS
;
3414 LogicalPartitionCreationChecks(
3417 // PDISKENTRY DiskEntry;
3418 PPARTENTRY PartEntry
;
3420 // DiskEntry = List->CurrentDisk;
3421 PartEntry
= List
->CurrentPartition
;
3423 /* Fail if partition is already in use */
3424 if (PartEntry
->IsPartitioned
== TRUE
)
3425 return ERROR_NEW_PARTITION
;
3427 return ERROR_SUCCESS
;
3432 GetNextUnformattedPartition(
3434 OUT PDISKENTRY
*pDiskEntry
,
3435 OUT PPARTENTRY
*pPartEntry
)
3437 PLIST_ENTRY Entry1
, Entry2
;
3438 PDISKENTRY DiskEntry
;
3439 PPARTENTRY PartEntry
;
3441 Entry1
= List
->DiskListHead
.Flink
;
3442 while (Entry1
!= &List
->DiskListHead
)
3444 DiskEntry
= CONTAINING_RECORD(Entry1
,
3448 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3449 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
3451 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3452 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3454 *pDiskEntry
= DiskEntry
;
3455 *pPartEntry
= PartEntry
;
3459 Entry2
= Entry2
->Flink
;
3462 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3463 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
3465 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3466 if (PartEntry
->IsPartitioned
&& PartEntry
->New
)
3468 *pDiskEntry
= DiskEntry
;
3469 *pPartEntry
= PartEntry
;
3473 Entry2
= Entry2
->Flink
;
3476 Entry1
= Entry1
->Flink
;
3487 GetNextUncheckedPartition(
3489 OUT PDISKENTRY
*pDiskEntry
,
3490 OUT PPARTENTRY
*pPartEntry
)
3492 PLIST_ENTRY Entry1
, Entry2
;
3493 PDISKENTRY DiskEntry
;
3494 PPARTENTRY PartEntry
;
3496 Entry1
= List
->DiskListHead
.Flink
;
3497 while (Entry1
!= &List
->DiskListHead
)
3499 DiskEntry
= CONTAINING_RECORD(Entry1
,
3503 Entry2
= DiskEntry
->PrimaryPartListHead
.Flink
;
3504 while (Entry2
!= &DiskEntry
->PrimaryPartListHead
)
3506 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3507 if (PartEntry
->NeedsCheck
== TRUE
)
3509 *pDiskEntry
= DiskEntry
;
3510 *pPartEntry
= PartEntry
;
3514 Entry2
= Entry2
->Flink
;
3517 Entry2
= DiskEntry
->LogicalPartListHead
.Flink
;
3518 while (Entry2
!= &DiskEntry
->LogicalPartListHead
)
3520 PartEntry
= CONTAINING_RECORD(Entry2
, PARTENTRY
, ListEntry
);
3521 if (PartEntry
->NeedsCheck
== TRUE
)
3523 *pDiskEntry
= DiskEntry
;
3524 *pPartEntry
= PartEntry
;
3528 Entry2
= Entry2
->Flink
;
3531 Entry1
= Entry1
->Flink
;