2 * PROJECT: ReactOS DiskPart
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/diskpart/diskpart.c
5 * PURPOSE: Manages all the partitions of the OS in an interactive way
6 * PROGRAMMERS: Eric Kohl
9 /* INCLUDES *******************************************************************/
23 #define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\
27 current = (ListHead)->Flink;\
28 while (current != (ListHead))\
30 if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\
31 (NewEntry)->SortField)\
35 current = current->Flink;\
38 InsertTailList(current, &((NewEntry)->ListEntryField));\
41 /* We have to define it there, because it is not in the MS DDK */
42 #define PARTITION_EXT2 0x83
44 #define PARTITION_TBL_SIZE 4
48 typedef struct _PARTITION
50 unsigned char BootFlags
; /* bootable? 0=no, 128=yes */
51 unsigned char StartingHead
; /* beginning head number */
52 unsigned char StartingSector
; /* beginning sector number */
53 unsigned char StartingCylinder
; /* 10 bit nmbr, with high 2 bits put in begsect */
54 unsigned char PartitionType
; /* Operating System type indicator code */
55 unsigned char EndingHead
; /* ending head number */
56 unsigned char EndingSector
; /* ending sector number */
57 unsigned char EndingCylinder
; /* also a 10 bit nmbr, with same high 2 bit trick */
58 unsigned int StartingBlock
; /* first sector relative to start of disk */
59 unsigned int SectorCount
; /* number of sectors in partition */
60 } PARTITION
, *PPARTITION
;
62 typedef struct _PARTITION_SECTOR
64 UCHAR BootCode
[440]; /* 0x000 */
65 ULONG Signature
; /* 0x1B8 */
66 UCHAR Reserved
[2]; /* 0x1BC */
67 PARTITION Partition
[PARTITION_TBL_SIZE
]; /* 0x1BE */
68 USHORT Magic
; /* 0x1FE */
69 } PARTITION_SECTOR
, *PPARTITION_SECTOR
;
74 /* GLOBALS ********************************************************************/
76 LIST_ENTRY DiskListHead
;
77 LIST_ENTRY BiosDiskListHead
;
79 PDISKENTRY CurrentDisk
= NULL
;
80 PPARTENTRY CurrentPartition
= NULL
;
83 /* FUNCTIONS ******************************************************************/
92 Temp
= Value
/ Alignment
;
94 return Temp
* Alignment
;
100 PDISKENTRY DiskEntry
)
102 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
106 RtlInitUnicodeString(&DiskEntry
->DriverName
,
110 L
"\\Scsi\\Scsi Port %lu",
113 RtlZeroMemory(&QueryTable
,
116 QueryTable
[0].Name
= L
"Driver";
117 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
118 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
120 Status
= RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP
,
125 if (!NT_SUCCESS(Status
))
127 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
134 DiskIdentifierQueryRoutine(
142 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
143 UNICODE_STRING NameU
;
145 if (ValueType
== REG_SZ
&&
146 ValueLength
== 20 * sizeof(WCHAR
))
148 NameU
.Buffer
= (PWCHAR
)ValueData
;
149 NameU
.Length
= NameU
.MaximumLength
= 8 * sizeof(WCHAR
);
150 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Checksum
);
152 NameU
.Buffer
= (PWCHAR
)ValueData
+ 9;
153 RtlUnicodeStringToInteger(&NameU
, 16, &BiosDiskEntry
->Signature
);
155 return STATUS_SUCCESS
;
158 return STATUS_UNSUCCESSFUL
;
164 DiskConfigurationDataQueryRoutine(
172 PBIOSDISKENTRY BiosDiskEntry
= (PBIOSDISKENTRY
)Context
;
173 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
174 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
;
177 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
178 ValueLength
< sizeof(CM_FULL_RESOURCE_DESCRIPTOR
))
179 return STATUS_UNSUCCESSFUL
;
181 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
183 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
185 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
186 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
187 return STATUS_UNSUCCESSFUL
;
190 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
192 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
193 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
!= sizeof(CM_DISK_GEOMETRY_DEVICE_DATA
))
196 DiskGeometry
= (PCM_DISK_GEOMETRY_DEVICE_DATA
)&FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1];
197 BiosDiskEntry
->DiskGeometry
= *DiskGeometry
;
199 return STATUS_SUCCESS
;
202 return STATUS_UNSUCCESSFUL
;
208 SystemConfigurationDataQueryRoutine(
216 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
;
217 PCM_INT13_DRIVE_PARAMETER
* Int13Drives
= (PCM_INT13_DRIVE_PARAMETER
*)Context
;
220 if (ValueType
!= REG_FULL_RESOURCE_DESCRIPTOR
||
221 ValueLength
< sizeof (CM_FULL_RESOURCE_DESCRIPTOR
))
222 return STATUS_UNSUCCESSFUL
;
224 FullResourceDescriptor
= (PCM_FULL_RESOURCE_DESCRIPTOR
)ValueData
;
226 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
228 if (FullResourceDescriptor
->PartialResourceList
.Version
!= 1 ||
229 FullResourceDescriptor
->PartialResourceList
.Revision
!= 1)
230 return STATUS_UNSUCCESSFUL
;
233 for (i
= 0; i
< FullResourceDescriptor
->PartialResourceList
.Count
; i
++)
235 if (FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].Type
!= CmResourceTypeDeviceSpecific
||
236 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
% sizeof(CM_INT13_DRIVE_PARAMETER
) != 0)
239 *Int13Drives
= (CM_INT13_DRIVE_PARAMETER
*)RtlAllocateHeap(RtlGetProcessHeap(), 0,
240 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
241 if (*Int13Drives
== NULL
)
242 return STATUS_NO_MEMORY
;
245 &FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
+ 1],
246 FullResourceDescriptor
->PartialResourceList
.PartialDescriptors
[i
].u
.DeviceSpecificData
.DataSize
);
247 return STATUS_SUCCESS
;
250 return STATUS_UNSUCCESSFUL
;
254 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
258 EnumerateBiosDiskEntries(VOID
)
260 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
265 PCM_INT13_DRIVE_PARAMETER Int13Drives
;
266 PBIOSDISKENTRY BiosDiskEntry
;
268 memset(QueryTable
, 0, sizeof(QueryTable
));
270 QueryTable
[1].Name
= L
"Configuration Data";
271 QueryTable
[1].QueryRoutine
= SystemConfigurationDataQueryRoutine
;
273 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
274 L
"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
278 if (!NT_SUCCESS(Status
))
280 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status
);
287 swprintf(Name
, L
"%s\\%lu", ROOT_NAME
, AdapterCount
);
288 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
293 if (!NT_SUCCESS(Status
))
298 swprintf(Name
, L
"%s\\%lu\\DiskController", ROOT_NAME
, AdapterCount
);
299 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
304 if (NT_SUCCESS(Status
))
308 swprintf(Name
, L
"%s\\%lu\\DiskController\\0", ROOT_NAME
, AdapterCount
);
309 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
314 if (!NT_SUCCESS(Status
))
316 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives
);
320 swprintf(Name
, L
"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME
, AdapterCount
);
321 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
326 if (NT_SUCCESS(Status
))
328 QueryTable
[0].Name
= L
"Identifier";
329 QueryTable
[0].QueryRoutine
= DiskIdentifierQueryRoutine
;
330 QueryTable
[1].Name
= L
"Configuration Data";
331 QueryTable
[1].QueryRoutine
= DiskConfigurationDataQueryRoutine
;
336 BiosDiskEntry
= (BIOSDISKENTRY
*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BIOSDISKENTRY
));
337 if (BiosDiskEntry
== NULL
)
342 swprintf(Name
, L
"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME
, AdapterCount
, DiskCount
);
343 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
346 (PVOID
)BiosDiskEntry
,
348 if (!NT_SUCCESS(Status
))
350 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry
);
354 BiosDiskEntry
->DiskNumber
= DiskCount
;
355 BiosDiskEntry
->Recognized
= FALSE
;
357 if (DiskCount
< Int13Drives
[0].NumberDrives
)
359 BiosDiskEntry
->Int13DiskData
= Int13Drives
[DiskCount
];
363 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount
);
366 InsertTailList(&BiosDiskListHead
, &BiosDiskEntry
->ListEntry
);
368 DPRINT("DiskNumber: %lu\n", BiosDiskEntry
->DiskNumber
);
369 DPRINT("Signature: %08lx\n", BiosDiskEntry
->Signature
);
370 DPRINT("Checksum: %08lx\n", BiosDiskEntry
->Checksum
);
371 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry
->DiskGeometry
.BytesPerSector
);
372 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfCylinders
);
373 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry
->DiskGeometry
.NumberOfHeads
);
374 DPRINT("DriveSelect: %02x\n", BiosDiskEntry
->Int13DiskData
.DriveSelect
);
375 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry
->Int13DiskData
.MaxCylinders
);
376 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry
->Int13DiskData
.SectorsPerTrack
);
377 DPRINT("MaxHeads: %d\n", BiosDiskEntry
->Int13DiskData
.MaxHeads
);
378 DPRINT("NumberDrives: %d\n", BiosDiskEntry
->Int13DiskData
.NumberDrives
);
384 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives
);
392 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives
);
400 PDISKENTRY DiskEntry
,
401 ULONG PartitionIndex
,
402 BOOLEAN LogicalPartition
)
404 PPARTITION_INFORMATION PartitionInfo
;
405 PPARTENTRY PartEntry
;
407 PartitionInfo
= &DiskEntry
->LayoutBuffer
->PartitionEntry
[PartitionIndex
];
408 if (PartitionInfo
->PartitionType
== 0 ||
409 (LogicalPartition
== TRUE
&& IsContainerPartition(PartitionInfo
->PartitionType
)))
412 PartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
415 if (PartEntry
== NULL
)
420 PartEntry
->DiskEntry
= DiskEntry
;
422 PartEntry
->StartSector
.QuadPart
= (ULONGLONG
)PartitionInfo
->StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
;
423 PartEntry
->SectorCount
.QuadPart
= (ULONGLONG
)PartitionInfo
->PartitionLength
.QuadPart
/ DiskEntry
->BytesPerSector
;
425 PartEntry
->BootIndicator
= PartitionInfo
->BootIndicator
;
426 PartEntry
->PartitionType
= PartitionInfo
->PartitionType
;
427 PartEntry
->HiddenSectors
= PartitionInfo
->HiddenSectors
;
429 PartEntry
->LogicalPartition
= LogicalPartition
;
430 PartEntry
->IsPartitioned
= TRUE
;
431 PartEntry
->PartitionNumber
= PartitionInfo
->PartitionNumber
;
432 PartEntry
->PartitionIndex
= PartitionIndex
;
434 if (IsContainerPartition(PartEntry
->PartitionType
))
436 PartEntry
->FormatState
= Unformatted
;
438 if (LogicalPartition
== FALSE
&& DiskEntry
->ExtendedPartition
== NULL
)
439 DiskEntry
->ExtendedPartition
= PartEntry
;
441 else if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
442 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
443 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
444 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
445 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
446 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
449 if (CheckFatFormat())
451 PartEntry
->FormatState
= Preformatted
;
455 PartEntry
->FormatState
= Unformatted
;
458 PartEntry
->FormatState
= Preformatted
;
460 else if (PartEntry
->PartitionType
== PARTITION_EXT2
)
463 if (CheckExt2Format())
465 PartEntry
->FormatState
= Preformatted
;
469 PartEntry
->FormatState
= Unformatted
;
472 PartEntry
->FormatState
= Preformatted
;
474 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
477 if (CheckNtfsFormat())
479 PartEntry
->FormatState
= Preformatted
;
481 else if (CheckHpfsFormat())
483 PartEntry
->FormatState
= Preformatted
;
487 PartEntry
->FormatState
= Unformatted
;
490 PartEntry
->FormatState
= Preformatted
;
494 PartEntry
->FormatState
= UnknownFormat
;
497 if (LogicalPartition
)
498 InsertTailList(&DiskEntry
->LogicalPartListHead
,
499 &PartEntry
->ListEntry
);
501 InsertTailList(&DiskEntry
->PrimaryPartListHead
,
502 &PartEntry
->ListEntry
);
508 ScanForUnpartitionedDiskSpace(
509 PDISKENTRY DiskEntry
)
511 ULONGLONG LastStartSector
;
512 ULONGLONG LastSectorCount
;
513 ULONGLONG LastUnusedSectorCount
;
514 PPARTENTRY PartEntry
;
515 PPARTENTRY NewPartEntry
;
518 DPRINT("ScanForUnpartitionedDiskSpace()\n");
520 if (IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
522 DPRINT1("No primary partition!\n");
524 /* Create a partition table that represents the empty disk */
525 NewPartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
528 if (NewPartEntry
== NULL
)
531 NewPartEntry
->DiskEntry
= DiskEntry
;
533 NewPartEntry
->IsPartitioned
= FALSE
;
534 NewPartEntry
->StartSector
.QuadPart
= (ULONGLONG
)DiskEntry
->SectorAlignment
;
535 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(DiskEntry
->SectorCount
.QuadPart
, DiskEntry
->SectorAlignment
) -
536 NewPartEntry
->StartSector
.QuadPart
;
538 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
539 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
540 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
542 NewPartEntry
->FormatState
= Unformatted
;
544 InsertTailList(&DiskEntry
->PrimaryPartListHead
,
545 &NewPartEntry
->ListEntry
);
550 /* Start partition at head 1, cylinder 0 */
551 LastStartSector
= DiskEntry
->SectorAlignment
;
552 LastSectorCount
= 0ULL;
553 LastUnusedSectorCount
= 0ULL;
555 Entry
= DiskEntry
->PrimaryPartListHead
.Flink
;
556 while (Entry
!= &DiskEntry
->PrimaryPartListHead
)
558 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
560 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
561 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
563 LastUnusedSectorCount
=
564 PartEntry
->StartSector
.QuadPart
- (LastStartSector
+ LastSectorCount
);
566 if (PartEntry
->StartSector
.QuadPart
> (LastStartSector
+ LastSectorCount
) &&
567 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
569 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
571 NewPartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
574 if (NewPartEntry
== NULL
)
577 NewPartEntry
->DiskEntry
= DiskEntry
;
579 NewPartEntry
->IsPartitioned
= FALSE
;
580 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
581 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
582 NewPartEntry
->StartSector
.QuadPart
;
584 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
585 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
586 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
588 NewPartEntry
->FormatState
= Unformatted
;
590 /* Insert the table into the list */
591 InsertTailList(&PartEntry
->ListEntry
,
592 &NewPartEntry
->ListEntry
);
595 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
596 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
599 Entry
= Entry
->Flink
;
602 /* Check for trailing unpartitioned disk space */
603 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->SectorCount
.QuadPart
)
605 LastUnusedSectorCount
= AlignDown(DiskEntry
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
), DiskEntry
->SectorAlignment
);
607 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->CylinderAlignment
)
609 DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
611 NewPartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
614 if (NewPartEntry
== NULL
)
617 NewPartEntry
->DiskEntry
= DiskEntry
;
619 NewPartEntry
->IsPartitioned
= FALSE
;
620 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
621 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
622 NewPartEntry
->StartSector
.QuadPart
;
624 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
625 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
626 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
628 NewPartEntry
->FormatState
= Unformatted
;
630 /* Append the table to the list */
631 InsertTailList(&DiskEntry
->PrimaryPartListHead
,
632 &NewPartEntry
->ListEntry
);
636 if (DiskEntry
->ExtendedPartition
!= NULL
)
638 if (IsListEmpty(&DiskEntry
->LogicalPartListHead
))
640 DPRINT1("No logical partition!\n");
642 /* Create a partition table entry that represents the empty extended partition */
643 NewPartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
646 if (NewPartEntry
== NULL
)
649 NewPartEntry
->DiskEntry
= DiskEntry
;
650 NewPartEntry
->LogicalPartition
= TRUE
;
652 NewPartEntry
->IsPartitioned
= FALSE
;
653 NewPartEntry
->StartSector
.QuadPart
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
654 NewPartEntry
->SectorCount
.QuadPart
= DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
;
656 DPRINT1("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
657 DPRINT1("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
658 DPRINT1("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
660 NewPartEntry
->FormatState
= Unformatted
;
662 InsertTailList(&DiskEntry
->LogicalPartListHead
,
663 &NewPartEntry
->ListEntry
);
668 /* Start partition at head 1, cylinder 0 */
669 LastStartSector
= DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ (ULONGLONG
)DiskEntry
->SectorAlignment
;
670 LastSectorCount
= 0ULL;
671 LastUnusedSectorCount
= 0ULL;
673 Entry
= DiskEntry
->LogicalPartListHead
.Flink
;
674 while (Entry
!= &DiskEntry
->LogicalPartListHead
)
676 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
678 if (PartEntry
->PartitionType
!= PARTITION_ENTRY_UNUSED
||
679 PartEntry
->SectorCount
.QuadPart
!= 0ULL)
681 LastUnusedSectorCount
=
682 PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
- (LastStartSector
+ LastSectorCount
);
684 if ((PartEntry
->StartSector
.QuadPart
- (ULONGLONG
)DiskEntry
->SectorAlignment
) > (LastStartSector
+ LastSectorCount
) &&
685 LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
687 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount
);
689 NewPartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
692 if (NewPartEntry
== NULL
)
695 NewPartEntry
->DiskEntry
= DiskEntry
;
696 NewPartEntry
->LogicalPartition
= TRUE
;
698 NewPartEntry
->IsPartitioned
= FALSE
;
699 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
700 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
701 NewPartEntry
->StartSector
.QuadPart
;
703 DPRINT("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
704 DPRINT("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
705 DPRINT("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
707 NewPartEntry
->FormatState
= Unformatted
;
709 /* Insert the table into the list */
710 InsertTailList(&PartEntry
->ListEntry
,
711 &NewPartEntry
->ListEntry
);
714 LastStartSector
= PartEntry
->StartSector
.QuadPart
;
715 LastSectorCount
= PartEntry
->SectorCount
.QuadPart
;
718 Entry
= Entry
->Flink
;
721 /* Check for trailing unpartitioned disk space */
722 if ((LastStartSector
+ LastSectorCount
) < DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
)
724 LastUnusedSectorCount
= AlignDown(DiskEntry
->ExtendedPartition
->StartSector
.QuadPart
+ DiskEntry
->ExtendedPartition
->SectorCount
.QuadPart
- (LastStartSector
+ LastSectorCount
),
725 DiskEntry
->SectorAlignment
);
727 if (LastUnusedSectorCount
>= (ULONGLONG
)DiskEntry
->SectorAlignment
)
729 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount
);
731 NewPartEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
734 if (NewPartEntry
== NULL
)
737 NewPartEntry
->DiskEntry
= DiskEntry
;
738 NewPartEntry
->LogicalPartition
= TRUE
;
740 NewPartEntry
->IsPartitioned
= FALSE
;
741 NewPartEntry
->StartSector
.QuadPart
= LastStartSector
+ LastSectorCount
;
742 NewPartEntry
->SectorCount
.QuadPart
= AlignDown(NewPartEntry
->StartSector
.QuadPart
+ LastUnusedSectorCount
, DiskEntry
->SectorAlignment
) -
743 NewPartEntry
->StartSector
.QuadPart
;
745 DPRINT("First Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
);
746 DPRINT("Last Sector: %I64u\n", NewPartEntry
->StartSector
.QuadPart
+ NewPartEntry
->SectorCount
.QuadPart
- 1);
747 DPRINT("Total Sectors: %I64u\n", NewPartEntry
->SectorCount
.QuadPart
);
749 NewPartEntry
->FormatState
= Unformatted
;
751 /* Append the table to the list */
752 InsertTailList(&DiskEntry
->LogicalPartListHead
,
753 &NewPartEntry
->ListEntry
);
758 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
768 DISK_GEOMETRY DiskGeometry
;
769 SCSI_ADDRESS ScsiAddress
;
770 PDISKENTRY DiskEntry
;
771 IO_STATUS_BLOCK Iosb
;
773 PPARTITION_SECTOR Mbr
;
775 LARGE_INTEGER FileOffset
;
776 WCHAR Identifier
[20];
780 PLIST_ENTRY ListEntry
;
781 PBIOSDISKENTRY BiosDiskEntry
;
782 ULONG LayoutBufferSize
;
783 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer
;
785 Status
= NtDeviceIoControlFile(FileHandle
,
790 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
794 sizeof(DISK_GEOMETRY
));
795 if (!NT_SUCCESS(Status
))
800 if (DiskGeometry
.MediaType
!= FixedMedia
&&
801 DiskGeometry
.MediaType
!= RemovableMedia
)
806 Status
= NtDeviceIoControlFile(FileHandle
,
811 IOCTL_SCSI_GET_ADDRESS
,
815 sizeof(SCSI_ADDRESS
));
816 if (!NT_SUCCESS(Status
))
821 Mbr
= (PARTITION_SECTOR
*)RtlAllocateHeap(RtlGetProcessHeap(),
823 DiskGeometry
.BytesPerSector
);
829 FileOffset
.QuadPart
= 0;
830 Status
= NtReadFile(FileHandle
,
836 DiskGeometry
.BytesPerSector
,
839 if (!NT_SUCCESS(Status
))
841 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr
);
842 DPRINT1("NtReadFile failed, status=%x\n", Status
);
845 Signature
= Mbr
->Signature
;
847 /* Calculate the MBR checksum */
849 Buffer
= (PULONG
)Mbr
;
850 for (i
= 0; i
< 128; i
++)
852 Checksum
+= Buffer
[i
];
854 Checksum
= ~Checksum
+ 1;
856 swprintf(Identifier
, L
"%08x-%08x-A", Checksum
, Signature
);
857 DPRINT("Identifier: %S\n", Identifier
);
859 DiskEntry
= RtlAllocateHeap(RtlGetProcessHeap(),
862 if (DiskEntry
== NULL
)
867 // DiskEntry->Checksum = Checksum;
868 // DiskEntry->Signature = Signature;
869 DiskEntry
->BiosFound
= FALSE
;
871 /* Check if this disk has a valid MBR */
872 if (Mbr
->BootCode
[0] == 0 && Mbr
->BootCode
[1] == 0)
873 DiskEntry
->NoMbr
= TRUE
;
875 DiskEntry
->NoMbr
= FALSE
;
877 /* Free Mbr sector buffer */
878 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr
);
880 ListEntry
= BiosDiskListHead
.Flink
;
881 while (ListEntry
!= &BiosDiskListHead
)
883 BiosDiskEntry
= CONTAINING_RECORD(ListEntry
, BIOSDISKENTRY
, ListEntry
);
885 * Compare the size from bios and the reported size from driver.
886 * If we have more than one disk with a zero or with the same signatur
887 * we must create new signatures and reboot. After the reboot,
888 * it is possible to identify the disks.
890 if (BiosDiskEntry
->Signature
== Signature
&&
891 BiosDiskEntry
->Checksum
== Checksum
&&
892 !BiosDiskEntry
->Recognized
)
894 if (!DiskEntry
->BiosFound
)
896 DiskEntry
->BiosDiskNumber
= BiosDiskEntry
->DiskNumber
;
897 DiskEntry
->BiosFound
= TRUE
;
898 BiosDiskEntry
->Recognized
= TRUE
;
904 ListEntry
= ListEntry
->Flink
;
907 if (!DiskEntry
->BiosFound
)
910 RtlFreeHeap(ProcessHeap
, 0, DiskEntry
);
913 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber
);
917 InitializeListHead(&DiskEntry
->PrimaryPartListHead
);
918 InitializeListHead(&DiskEntry
->LogicalPartListHead
);
920 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
921 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
922 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
923 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
925 DPRINT("Cylinders %I64u\n", DiskEntry
->Cylinders
);
926 DPRINT("TracksPerCylinder %I64u\n", DiskEntry
->TracksPerCylinder
);
927 DPRINT("SectorsPerTrack %I64u\n", DiskEntry
->SectorsPerTrack
);
928 DPRINT("BytesPerSector %I64u\n", DiskEntry
->BytesPerSector
);
930 DiskEntry
->SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
931 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
932 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
;
934 DiskEntry
->SectorAlignment
= DiskGeometry
.SectorsPerTrack
;
935 DiskEntry
->CylinderAlignment
= DiskGeometry
.SectorsPerTrack
* DiskGeometry
.TracksPerCylinder
;
937 DPRINT1("SectorCount: %I64u\n", DiskEntry
->SectorCount
);
938 DPRINT1("SectorAlignment: %lu\n", DiskEntry
->SectorAlignment
);
939 DPRINT1("CylinderAlignment: %lu\n", DiskEntry
->CylinderAlignment
);
941 DiskEntry
->DiskNumber
= DiskNumber
;
942 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
943 DiskEntry
->Bus
= ScsiAddress
.PathId
;
944 DiskEntry
->Id
= ScsiAddress
.TargetId
;
946 GetDriverName(DiskEntry
);
948 InsertAscendingList(&DiskListHead
, DiskEntry
, DISKENTRY
, ListEntry
, DiskNumber
);
950 /* Allocate a layout buffer with 4 partition entries first */
951 LayoutBufferSize
= sizeof(DRIVE_LAYOUT_INFORMATION
) +
952 ((4 - ANYSIZE_ARRAY
) * sizeof(PARTITION_INFORMATION
));
953 DiskEntry
->LayoutBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
956 if (DiskEntry
->LayoutBuffer
== NULL
)
958 DPRINT1("Failed to allocate the disk layout buffer!\n");
964 DPRINT1("Buffer size: %lu\n", LayoutBufferSize
);
965 Status
= NtDeviceIoControlFile(FileHandle
,
970 IOCTL_DISK_GET_DRIVE_LAYOUT
,
973 DiskEntry
->LayoutBuffer
,
975 if (NT_SUCCESS(Status
))
978 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
980 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status
);
984 LayoutBufferSize
+= 4 * sizeof(PARTITION_INFORMATION
);
985 NewLayoutBuffer
= RtlReAllocateHeap(RtlGetProcessHeap(),
987 DiskEntry
->LayoutBuffer
,
989 if (NewLayoutBuffer
== NULL
)
991 DPRINT1("Failed to reallocate the disk layout buffer!\n");
995 DiskEntry
->LayoutBuffer
= NewLayoutBuffer
;
998 DPRINT1("PartitionCount: %lu\n", DiskEntry
->LayoutBuffer
->PartitionCount
);
1000 #ifdef DUMP_PARTITION_TABLE
1001 DumpPartitionTable(DiskEntry
);
1004 if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
!= 0 &&
1005 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionLength
.QuadPart
!= 0 &&
1006 DiskEntry
->LayoutBuffer
->PartitionEntry
[0].PartitionType
!= 0)
1008 if ((DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
/ DiskEntry
->BytesPerSector
) % DiskEntry
->SectorsPerTrack
== 0)
1010 DPRINT("Use %lu Sector alignment!\n", DiskEntry
->SectorsPerTrack
);
1012 else if (DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
% (1024 * 1024) == 0)
1014 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1018 DPRINT1("No matching aligment found! Partiton 1 starts at %I64u\n", DiskEntry
->LayoutBuffer
->PartitionEntry
[0].StartingOffset
.QuadPart
);
1023 DPRINT1("No valid partiton table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry
->BytesPerSector
);
1027 if (DiskEntry
->LayoutBuffer
->PartitionCount
== 0)
1029 DiskEntry
->NewDisk
= TRUE
;
1030 DiskEntry
->LayoutBuffer
->PartitionCount
= 4;
1032 for (i
= 0; i
< 4; i
++)
1033 DiskEntry
->LayoutBuffer
->PartitionEntry
[i
].RewritePartition
= TRUE
;
1037 for (i
= 0; i
< 4; i
++)
1039 AddPartitionToDisk(DiskNumber
,
1045 for (i
= 4; i
< DiskEntry
->LayoutBuffer
->PartitionCount
; i
+= 4)
1047 AddPartitionToDisk(DiskNumber
,
1054 ScanForUnpartitionedDiskSpace(DiskEntry
);
1059 CreatePartitionList(VOID
)
1061 OBJECT_ATTRIBUTES ObjectAttributes
;
1062 SYSTEM_DEVICE_INFORMATION Sdi
;
1063 IO_STATUS_BLOCK Iosb
;
1067 WCHAR Buffer
[MAX_PATH
];
1068 UNICODE_STRING Name
;
1072 CurrentPartition
= NULL
;
1075 // BootPartition = NULL;
1078 // TempPartition = NULL;
1079 // FormatState = Start;
1081 InitializeListHead(&DiskListHead
);
1082 InitializeListHead(&BiosDiskListHead
);
1084 EnumerateBiosDiskEntries();
1086 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
1088 sizeof(SYSTEM_DEVICE_INFORMATION
),
1090 if (!NT_SUCCESS(Status
))
1095 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
1098 L
"\\Device\\Harddisk%d\\Partition0",
1100 RtlInitUnicodeString(&Name
,
1103 InitializeObjectAttributes(&ObjectAttributes
,
1109 Status
= NtOpenFile(&FileHandle
,
1110 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
1114 FILE_SYNCHRONOUS_IO_NONALERT
);
1115 if (NT_SUCCESS(Status
))
1117 AddDiskToList(FileHandle
,
1120 NtClose(FileHandle
);
1124 // UpdateDiskSignatures(List);
1126 // AssignDriveLetters(List);
1128 return STATUS_SUCCESS
;
1133 DestroyPartitionList(VOID
)
1135 PDISKENTRY DiskEntry
;
1136 PBIOSDISKENTRY BiosDiskEntry
;
1137 PPARTENTRY PartEntry
;
1141 CurrentPartition
= NULL
;
1143 /* Release disk and partition info */
1144 while (!IsListEmpty(&DiskListHead
))
1146 Entry
= RemoveHeadList(&DiskListHead
);
1147 DiskEntry
= CONTAINING_RECORD(Entry
, DISKENTRY
, ListEntry
);
1149 /* Release driver name */
1150 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
1152 /* Release primary partition list */
1153 while (!IsListEmpty(&DiskEntry
->PrimaryPartListHead
))
1155 Entry
= RemoveHeadList(&DiskEntry
->PrimaryPartListHead
);
1156 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1158 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry
);
1161 /* Release logical partition list */
1162 while (!IsListEmpty(&DiskEntry
->LogicalPartListHead
))
1164 Entry
= RemoveHeadList(&DiskEntry
->LogicalPartListHead
);
1165 PartEntry
= CONTAINING_RECORD(Entry
, PARTENTRY
, ListEntry
);
1167 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry
);
1170 /* Release layout buffer */
1171 if (DiskEntry
->LayoutBuffer
!= NULL
)
1172 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry
->LayoutBuffer
);
1175 /* Release disk entry */
1176 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry
);
1179 /* Release the bios disk info */
1180 while(!IsListEmpty(&BiosDiskListHead
))
1182 Entry
= RemoveHeadList(&BiosDiskListHead
);
1183 BiosDiskEntry
= CONTAINING_RECORD(Entry
, BIOSDISKENTRY
, ListEntry
);
1185 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry
);