3 * Copyright (C) 2002, 2003 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: partlist.c,v 1.26 2003/12/01 18:28:54 navaraf Exp $
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/partlist.c
23 * PURPOSE: Partition list functions
24 * PROGRAMMER: Eric Kohl
25 * Casper S. Hornstrup (chorns@users.sourceforge.net)
28 #include <ddk/ntddk.h>
29 #include <ddk/ntddscsi.h>
31 #include <ntdll/rtl.h>
33 #include <ntos/minmax.h>
44 /* FUNCTIONS ****************************************************************/
47 GetDriverName (PDISKENTRY DiskEntry
)
49 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
53 RtlInitUnicodeString (&DiskEntry
->DriverName
,
57 L
"\\Scsi\\Scsi Port %lu",
60 RtlZeroMemory (&QueryTable
,
63 QueryTable
[0].Name
= L
"Driver";
64 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
65 QueryTable
[0].EntryContext
= &DiskEntry
->DriverName
;
67 Status
= RtlQueryRegistryValues (RTL_REGISTRY_DEVICEMAP
,
72 if (!NT_SUCCESS (Status
))
74 DPRINT1 ("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
80 AssignDriverLetters (PPARTLIST List
)
90 /* Assign drive letters to primary partitions */
91 Entry1
= List
->DiskListHead
.Flink
;
92 while (Entry1
!= &List
->DiskListHead
)
94 DiskEntry
= CONTAINING_RECORD (Entry1
, DISKENTRY
, ListEntry
);
96 if (!IsListEmpty (&DiskEntry
->PartListHead
))
98 PartEntry
= CONTAINING_RECORD (DiskEntry
->PartListHead
.Flink
,
102 PartEntry
->DriveLetter
= 0;
104 if (PartEntry
->Unpartitioned
== FALSE
&&
105 !IsContainerPartition (PartEntry
->PartInfo
[0].PartitionType
))
107 if (IsRecognizedPartition (PartEntry
->PartInfo
[0].PartitionType
) ||
108 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_ENTRY_UNUSED
&&
109 PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
!= 0LL))
113 PartEntry
->DriveLetter
= Letter
;
120 Entry1
= Entry1
->Flink
;
124 /* Assign drive letters to logical drives */
125 Entry1
= List
->DiskListHead
.Flink
;
126 while (Entry1
!= &List
->DiskListHead
)
128 DiskEntry
= CONTAINING_RECORD (Entry1
, DISKENTRY
, ListEntry
);
130 Entry2
= DiskEntry
->PartListHead
.Flink
;
131 if (Entry2
!= &DiskEntry
->PartListHead
)
133 Entry2
= Entry2
->Flink
;
134 while (Entry2
!= &DiskEntry
->PartListHead
)
136 PartEntry
= CONTAINING_RECORD (Entry2
,
140 PartEntry
->DriveLetter
= 0;
142 if (PartEntry
->Unpartitioned
== FALSE
&&
143 !IsContainerPartition (PartEntry
->PartInfo
[0].PartitionType
))
145 if (IsRecognizedPartition (PartEntry
->PartInfo
[0].PartitionType
) ||
146 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_ENTRY_UNUSED
&&
147 PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
!= 0LL))
151 PartEntry
->DriveLetter
= Letter
;
157 Entry2
= Entry2
->Flink
;
161 Entry1
= Entry1
->Flink
;
167 UpdatePartitionNumbers (PDISKENTRY DiskEntry
)
169 PPARTENTRY PartEntry
;
175 Entry
= DiskEntry
->PartListHead
.Flink
;
176 while (Entry
!= &DiskEntry
->PartListHead
)
178 PartEntry
= CONTAINING_RECORD (Entry
,
182 if (PartEntry
->Unpartitioned
== TRUE
)
184 for (i
= 0; i
< 4; i
++)
186 PartEntry
->PartInfo
[i
].PartitionNumber
= 0;
191 for (i
= 0; i
< 4; i
++)
193 if (IsContainerPartition (PartEntry
->PartInfo
[i
].PartitionType
))
195 PartEntry
->PartInfo
[i
].PartitionNumber
= 0;
197 else if (PartEntry
->PartInfo
[i
].PartitionType
== PARTITION_ENTRY_UNUSED
&&
198 PartEntry
->PartInfo
[i
].PartitionLength
.QuadPart
== 0ULL)
200 PartEntry
->PartInfo
[i
].PartitionNumber
= 0;
204 PartEntry
->PartInfo
[i
].PartitionNumber
= PartNumber
;
210 Entry
= Entry
->Flink
;
216 AddPartitionToList (ULONG DiskNumber
,
217 PDISKENTRY DiskEntry
,
218 DRIVE_LAYOUT_INFORMATION
*LayoutBuffer
)
220 PPARTENTRY PartEntry
;
224 for (i
= 0; i
< LayoutBuffer
->PartitionCount
; i
+= 4)
226 for (j
= 0; j
< 4; j
++)
228 if (LayoutBuffer
->PartitionEntry
[j
].PartitionType
!= PARTITION_ENTRY_UNUSED
||
229 LayoutBuffer
->PartitionEntry
[j
].PartitionLength
.QuadPart
!= 0ULL)
239 PartEntry
= (PPARTENTRY
)RtlAllocateHeap (ProcessHeap
,
242 if (PartEntry
== NULL
)
247 RtlZeroMemory (PartEntry
,
250 PartEntry
->Unpartitioned
= FALSE
;
252 for (j
= 0; j
< 4; j
++)
254 RtlCopyMemory (&PartEntry
->PartInfo
[j
],
255 &LayoutBuffer
->PartitionEntry
[i
+j
],
256 sizeof(PARTITION_INFORMATION
));
259 if (IsContainerPartition(PartEntry
->PartInfo
[0].PartitionType
))
261 PartEntry
->FormatState
= Unformatted
;
263 else if ((PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT_12
) ||
264 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT_16
) ||
265 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_HUGE
) ||
266 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_XINT13
) ||
267 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT32
) ||
268 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT32_XINT13
))
271 if (CheckFatFormat())
273 PartEntry
->FormatState
= Preformatted
;
277 PartEntry
->FormatState
= Unformatted
;
280 PartEntry
->FormatState
= Preformatted
;
282 else if (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_IFS
)
285 if (CheckNtfsFormat())
287 PartEntry
->FormatState
= Preformatted
;
289 else if (CheckHpfsFormat())
291 PartEntry
->FormatState
= Preformatted
;
295 PartEntry
->FormatState
= Unformatted
;
298 PartEntry
->FormatState
= Preformatted
;
302 PartEntry
->FormatState
= Unknown
;
305 InsertTailList (&DiskEntry
->PartListHead
,
306 &PartEntry
->ListEntry
);
312 ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry
)
314 ULONGLONG LastStartingOffset
;
315 ULONGLONG LastPartitionLength
;
316 ULONGLONG LastUnusedPartitionLength
;
317 PPARTENTRY PartEntry
;
318 PPARTENTRY NewPartEntry
;
323 if (IsListEmpty (&DiskEntry
->PartListHead
))
325 /* Create a partition table that represents the empty disk */
326 PartEntry
= (PPARTENTRY
)RtlAllocateHeap (ProcessHeap
,
329 if (PartEntry
== NULL
)
332 RtlZeroMemory (PartEntry
,
335 PartEntry
->Unpartitioned
= TRUE
;
336 PartEntry
->UnpartitionedOffset
= 0ULL;
337 PartEntry
->UnpartitionedLength
= DiskEntry
->DiskSize
;
339 PartEntry
->FormatState
= Unformatted
;
341 InsertTailList (&DiskEntry
->PartListHead
,
342 &PartEntry
->ListEntry
);
346 /* Start partition at head 1, cylinder 0 */
347 LastStartingOffset
= DiskEntry
->TrackSize
;
348 LastPartitionLength
= 0ULL;
349 LastUnusedPartitionLength
= 0ULL;
352 Entry
= DiskEntry
->PartListHead
.Flink
;
353 while (Entry
!= &DiskEntry
->PartListHead
)
355 PartEntry
= CONTAINING_RECORD (Entry
, PARTENTRY
, ListEntry
);
357 for (j
= 0; j
< 4; j
++)
359 if ((!IsContainerPartition (PartEntry
->PartInfo
[j
].PartitionType
)) &&
360 (PartEntry
->PartInfo
[j
].PartitionType
!= PARTITION_ENTRY_UNUSED
||
361 PartEntry
->PartInfo
[j
].PartitionLength
.QuadPart
!= 0LL))
363 LastUnusedPartitionLength
=
364 PartEntry
->PartInfo
[j
].StartingOffset
.QuadPart
-
365 (LastStartingOffset
+ LastPartitionLength
);
367 if (LastUnusedPartitionLength
>= DiskEntry
->CylinderSize
)
369 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength
);
371 NewPartEntry
= (PPARTENTRY
)RtlAllocateHeap (ProcessHeap
,
374 if (NewPartEntry
== NULL
)
377 RtlZeroMemory (NewPartEntry
,
380 NewPartEntry
->Unpartitioned
= TRUE
;
381 NewPartEntry
->UnpartitionedOffset
= LastStartingOffset
+ LastPartitionLength
;
382 NewPartEntry
->UnpartitionedLength
= LastUnusedPartitionLength
;
384 NewPartEntry
->UnpartitionedLength
-= DiskEntry
->TrackSize
;
386 NewPartEntry
->FormatState
= Unformatted
;
388 /* Insert the table into the list */
389 InsertTailList (&PartEntry
->ListEntry
,
390 &NewPartEntry
->ListEntry
);
393 LastStartingOffset
= PartEntry
->PartInfo
[j
].StartingOffset
.QuadPart
;
394 LastPartitionLength
= PartEntry
->PartInfo
[j
].PartitionLength
.QuadPart
;
399 Entry
= Entry
->Flink
;
402 /* Check for trailing unpartitioned disk space */
403 if (DiskEntry
->DiskSize
> (LastStartingOffset
+ LastPartitionLength
))
405 /* Round-down to cylinder size */
406 LastUnusedPartitionLength
=
407 ROUND_DOWN (DiskEntry
->DiskSize
- (LastStartingOffset
+ LastPartitionLength
),
408 DiskEntry
->CylinderSize
);
410 if (LastUnusedPartitionLength
>= DiskEntry
->CylinderSize
)
412 DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength
);
414 NewPartEntry
= (PPARTENTRY
)RtlAllocateHeap (ProcessHeap
,
417 if (NewPartEntry
== NULL
)
420 RtlZeroMemory (NewPartEntry
,
423 NewPartEntry
->Unpartitioned
= TRUE
;
424 NewPartEntry
->UnpartitionedOffset
= LastStartingOffset
+ LastPartitionLength
;
425 NewPartEntry
->UnpartitionedLength
= LastUnusedPartitionLength
;
427 /* Append the table to the list */
428 InsertTailList (&DiskEntry
->PartListHead
,
429 &NewPartEntry
->ListEntry
);
437 AddDiskToList (HANDLE FileHandle
,
441 DRIVE_LAYOUT_INFORMATION
*LayoutBuffer
;
442 DISK_GEOMETRY DiskGeometry
;
443 SCSI_ADDRESS ScsiAddress
;
444 PDISKENTRY DiskEntry
;
445 IO_STATUS_BLOCK Iosb
;
448 Status
= NtDeviceIoControlFile (FileHandle
,
453 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
457 sizeof(DISK_GEOMETRY
));
458 if (!NT_SUCCESS (Status
))
463 if (DiskGeometry
.MediaType
!= FixedMedia
)
468 Status
= NtDeviceIoControlFile (FileHandle
,
473 IOCTL_SCSI_GET_ADDRESS
,
477 sizeof(SCSI_ADDRESS
));
478 if (!NT_SUCCESS(Status
))
483 DiskEntry
= (PDISKENTRY
)RtlAllocateHeap (ProcessHeap
,
486 if (DiskEntry
== NULL
)
491 InitializeListHead (&DiskEntry
->PartListHead
);
493 DiskEntry
->Cylinders
= DiskGeometry
.Cylinders
.QuadPart
;
494 DiskEntry
->TracksPerCylinder
= DiskGeometry
.TracksPerCylinder
;
495 DiskEntry
->SectorsPerTrack
= DiskGeometry
.SectorsPerTrack
;
496 DiskEntry
->BytesPerSector
= DiskGeometry
.BytesPerSector
;
498 DPRINT ("Cylinders %d\n", DiskEntry
->Cylinders
);
499 DPRINT ("TracksPerCylinder %d\n", DiskEntry
->TracksPerCylinder
);
500 DPRINT ("SectorsPerTrack %d\n", DiskEntry
->SectorsPerTrack
);
501 DPRINT ("BytesPerSector %d\n", DiskEntry
->BytesPerSector
);
503 DiskEntry
->DiskSize
=
504 DiskGeometry
.Cylinders
.QuadPart
*
505 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
506 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
507 (ULONGLONG
)DiskGeometry
.BytesPerSector
;
508 DiskEntry
->CylinderSize
=
509 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
510 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
511 (ULONGLONG
)DiskGeometry
.BytesPerSector
;
512 DiskEntry
->TrackSize
=
513 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
514 (ULONGLONG
)DiskGeometry
.BytesPerSector
;
516 DiskEntry
->DiskNumber
= DiskNumber
;
517 DiskEntry
->Port
= ScsiAddress
.PortNumber
;
518 DiskEntry
->Bus
= ScsiAddress
.PathId
;
519 DiskEntry
->Id
= ScsiAddress
.TargetId
;
521 GetDriverName (DiskEntry
);
523 InsertTailList (&List
->DiskListHead
,
524 &DiskEntry
->ListEntry
);
526 LayoutBuffer
= (DRIVE_LAYOUT_INFORMATION
*)RtlAllocateHeap (ProcessHeap
,
529 if (LayoutBuffer
== NULL
)
534 Status
= NtDeviceIoControlFile (FileHandle
,
539 IOCTL_DISK_GET_DRIVE_LAYOUT
,
544 if (NT_SUCCESS (Status
))
546 if (LayoutBuffer
->PartitionCount
== 0)
548 DiskEntry
->NewDisk
= TRUE
;
551 AddPartitionToList (DiskNumber
,
555 ScanForUnpartitionedDiskSpace (DiskEntry
);
558 RtlFreeHeap (ProcessHeap
,
565 CreatePartitionList (SHORT Left
,
571 OBJECT_ATTRIBUTES ObjectAttributes
;
572 SYSTEM_DEVICE_INFORMATION Sdi
;
573 IO_STATUS_BLOCK Iosb
;
577 WCHAR Buffer
[MAX_PATH
];
581 List
= (PPARTLIST
)RtlAllocateHeap (ProcessHeap
,
590 List
->Bottom
= Bottom
;
594 List
->TopDisk
= (ULONG
)-1;
595 List
->TopPartition
= (ULONG
)-1;
597 List
->CurrentDisk
= NULL
;
598 List
->CurrentPartition
= NULL
;
600 InitializeListHead (&List
->DiskListHead
);
602 Status
= NtQuerySystemInformation (SystemDeviceInformation
,
604 sizeof(SYSTEM_DEVICE_INFORMATION
),
606 if (!NT_SUCCESS (Status
))
608 RtlFreeHeap (ProcessHeap
, 0, List
);
612 for (DiskNumber
= 0; DiskNumber
< Sdi
.NumberOfDisks
; DiskNumber
++)
615 L
"\\Device\\Harddisk%d\\Partition0",
617 RtlInitUnicodeString (&Name
,
620 InitializeObjectAttributes (&ObjectAttributes
,
626 Status
= NtOpenFile (&FileHandle
,
631 FILE_SYNCHRONOUS_IO_NONALERT
);
632 if (NT_SUCCESS(Status
))
634 AddDiskToList (FileHandle
,
642 AssignDriverLetters (List
);
645 List
->TopPartition
= 0;
647 /* Search for first usable disk and partition */
648 if (IsListEmpty (&List
->DiskListHead
))
650 List
->CurrentDisk
= NULL
;
651 List
->CurrentPartition
= NULL
;
656 CONTAINING_RECORD (List
->DiskListHead
.Flink
,
660 if (IsListEmpty (&List
->CurrentDisk
->PartListHead
))
662 List
->CurrentPartition
= 0;
666 List
->CurrentPartition
=
667 CONTAINING_RECORD (List
->CurrentDisk
->PartListHead
.Flink
,
678 DestroyPartitionList (PPARTLIST List
)
680 PDISKENTRY DiskEntry
;
681 PPARTENTRY PartEntry
;
684 /* Release disk and partition info */
685 while (!IsListEmpty (&List
->DiskListHead
))
687 Entry
= RemoveHeadList (&List
->DiskListHead
);
688 DiskEntry
= CONTAINING_RECORD (Entry
, DISKENTRY
, ListEntry
);
690 /* Release driver name */
691 RtlFreeUnicodeString(&DiskEntry
->DriverName
);
693 /* Release partition array */
694 while (!IsListEmpty (&DiskEntry
->PartListHead
))
696 Entry
= RemoveHeadList (&DiskEntry
->PartListHead
);
697 PartEntry
= CONTAINING_RECORD (Entry
, PARTENTRY
, ListEntry
);
699 RtlFreeHeap (ProcessHeap
,
704 /* Release disk entry */
705 RtlFreeHeap (ProcessHeap
, 0, DiskEntry
);
708 /* Release list head */
709 RtlFreeHeap (ProcessHeap
, 0, List
);
714 PrintEmptyLine (PPARTLIST List
)
721 Width
= List
->Right
- List
->Left
- 1;
722 Height
= List
->Bottom
- List
->Top
- 1;
724 if (List
->Line
< 0 || List
->Line
> Height
)
727 coPos
.X
= List
->Left
+ 1;
728 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
730 FillConsoleOutputAttribute (0x17,
735 FillConsoleOutputCharacter (' ',
745 PrintPartitionData (PPARTLIST List
,
746 PDISKENTRY DiskEntry
,
747 PPARTENTRY PartEntry
)
749 CHAR LineBuffer
[128];
760 Width
= List
->Right
- List
->Left
- 1;
761 Height
= List
->Bottom
- List
->Top
- 1;
763 if (List
->Line
< 0 || List
->Line
> Height
)
766 coPos
.X
= List
->Left
+ 1;
767 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
769 if (PartEntry
->Unpartitioned
== TRUE
)
772 if (PartEntry
->UnpartitionledLength
>= 0x280000000ULL
) /* 10 GB */
774 PartSize
= (PartEntry
->UnpartitionedLength
+ (1 << 29)) >> 30;
779 if (PartEntry
->UnpartitionedLength
>= 0xA00000ULL
) /* 10 MB */
781 PartSize
= (PartEntry
->UnpartitionedLength
+ (1 << 19)) >> 20;
786 PartSize
= (PartEntry
->UnpartitionedLength
+ (1 << 9)) >> 10;
791 " Unpartitioned space %6I64u %s",
797 /* Determine partition type */
799 if (PartEntry
->New
== TRUE
)
801 PartType
= "New (Unformatted)";
803 else if (PartEntry
->Unpartitioned
== FALSE
)
805 if ((PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT_12
) ||
806 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT_16
) ||
807 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_HUGE
) ||
808 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_XINT13
))
812 else if ((PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT32
) ||
813 (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_FAT32_XINT13
))
817 else if (PartEntry
->PartInfo
[0].PartitionType
== PARTITION_IFS
)
819 PartType
= "NTFS"; /* FIXME: Not quite correct! */
824 if (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
>= 0x280000000ULL
) /* 10 GB */
826 PartSize
= (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ (1 << 29)) >> 30;
831 if (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
>= 0xA00000ULL
) /* 10 MB */
833 PartSize
= (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ (1 << 19)) >> 20;
838 PartSize
= (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ (1 << 9)) >> 10;
842 if (PartType
== NULL
)
845 "%c%c Type %-3u %6I64u %s",
846 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
847 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
848 PartEntry
->PartInfo
[0].PartitionType
,
855 "%c%c %-24s %6I64u %s",
856 (PartEntry
->DriveLetter
== 0) ? '-' : PartEntry
->DriveLetter
,
857 (PartEntry
->DriveLetter
== 0) ? '-' : ':',
864 Attribute
= (List
->CurrentDisk
== DiskEntry
&&
865 List
->CurrentPartition
== PartEntry
) ? 0x71 : 0x17;
867 FillConsoleOutputCharacter (' ',
874 FillConsoleOutputAttribute (Attribute
,
881 WriteConsoleOutputCharacters (LineBuffer
,
882 min (strlen (LineBuffer
), Width
),
890 PrintDiskData (PPARTLIST List
,
891 PDISKENTRY DiskEntry
)
893 PPARTENTRY PartEntry
;
895 CHAR LineBuffer
[128];
903 Width
= List
->Right
- List
->Left
- 1;
904 Height
= List
->Bottom
- List
->Top
- 1;
906 if (List
->Line
< 0 || List
->Line
> Height
)
909 coPos
.X
= List
->Left
+ 1;
910 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
913 if (DiskEntry
->DiskSize
>= 0x280000000ULL
) /* 10 GB */
915 DiskSize
= (DiskEntry
->DiskSize
+ (1 << 29)) >> 30;
921 DiskSize
= (DiskEntry
->DiskSize
+ (1 << 19)) >> 20;
927 if (DiskEntry
->DriverName
.Length
> 0)
930 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
933 DiskEntry
->DiskNumber
,
937 &DiskEntry
->DriverName
);
942 "%6I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
945 DiskEntry
->DiskNumber
,
951 FillConsoleOutputAttribute (0x17,
956 FillConsoleOutputCharacter (' ',
962 WriteConsoleOutputCharacters (LineBuffer
,
963 min (strlen (LineBuffer
), Width
- 2),
968 /* Print separator line */
969 PrintEmptyLine (List
);
971 /* Print partition lines*/
972 Entry
= DiskEntry
->PartListHead
.Flink
;
973 while (Entry
!= &DiskEntry
->PartListHead
)
975 PartEntry
= CONTAINING_RECORD (Entry
, PARTENTRY
, ListEntry
);
977 /* Print disk entry */
978 PrintPartitionData (List
,
982 Entry
= Entry
->Flink
;
985 /* Print separator line */
986 PrintEmptyLine (List
);
991 DrawPartitionList (PPARTLIST List
)
994 PDISKENTRY DiskEntry
;
999 /* draw upper left corner */
1000 coPos
.X
= List
->Left
;
1001 coPos
.Y
= List
->Top
;
1002 FillConsoleOutputCharacter (0xDA, // '+',
1007 /* draw upper edge */
1008 coPos
.X
= List
->Left
+ 1;
1009 coPos
.Y
= List
->Top
;
1010 FillConsoleOutputCharacter (0xC4, // '-',
1011 List
->Right
- List
->Left
- 1,
1015 /* draw upper right corner */
1016 coPos
.X
= List
->Right
;
1017 coPos
.Y
= List
->Top
;
1018 FillConsoleOutputCharacter (0xBF, // '+',
1023 /* draw left and right edge */
1024 for (i
= List
->Top
+ 1; i
< List
->Bottom
; i
++)
1026 coPos
.X
= List
->Left
;
1028 FillConsoleOutputCharacter (0xB3, // '|',
1033 coPos
.X
= List
->Right
;
1034 FillConsoleOutputCharacter (0xB3, //'|',
1040 /* draw lower left corner */
1041 coPos
.X
= List
->Left
;
1042 coPos
.Y
= List
->Bottom
;
1043 FillConsoleOutputCharacter (0xC0, // '+',
1048 /* draw lower edge */
1049 coPos
.X
= List
->Left
+ 1;
1050 coPos
.Y
= List
->Bottom
;
1051 FillConsoleOutputCharacter (0xC4, // '-',
1052 List
->Right
- List
->Left
- 1,
1056 /* draw lower right corner */
1057 coPos
.X
= List
->Right
;
1058 coPos
.Y
= List
->Bottom
;
1059 FillConsoleOutputCharacter (0xD9, // '+',
1064 /* print list entries */
1067 Entry
= List
->DiskListHead
.Flink
;
1068 while (Entry
!= &List
->DiskListHead
)
1070 DiskEntry
= CONTAINING_RECORD (Entry
, DISKENTRY
, ListEntry
);
1072 /* Print disk entry */
1073 PrintDiskData (List
,
1076 Entry
= Entry
->Flink
;
1082 SelectPartition(PPARTLIST List
, ULONG DiskNumber
, ULONG PartitionNumber
)
1084 PDISKENTRY DiskEntry
;
1085 PPARTENTRY PartEntry
;
1090 /* Check for empty disks */
1091 if (IsListEmpty (&List
->DiskListHead
))
1094 /* Check for first usable entry on next disk */
1095 Entry1
= List
->CurrentDisk
->ListEntry
.Flink
;
1096 while (Entry1
!= &List
->DiskListHead
)
1098 DiskEntry
= CONTAINING_RECORD (Entry1
, DISKENTRY
, ListEntry
);
1100 if (DiskEntry
->DiskNumber
== DiskNumber
)
1102 Entry2
= DiskEntry
->PartListHead
.Flink
;
1103 while (Entry2
!= &DiskEntry
->PartListHead
)
1105 PartEntry
= CONTAINING_RECORD (Entry2
, PARTENTRY
, ListEntry
);
1107 for (i
= 0; i
< 4; i
++)
1109 if (PartEntry
->PartInfo
[i
].PartitionNumber
== PartitionNumber
)
1111 List
->CurrentDisk
= DiskEntry
;
1112 List
->CurrentPartition
= PartEntry
;
1113 DrawPartitionList (List
);
1117 Entry2
= Entry2
->Flink
;
1121 Entry1
= Entry1
->Flink
;
1127 ScrollDownPartitionList (PPARTLIST List
)
1129 PDISKENTRY DiskEntry
;
1130 PPARTENTRY PartEntry
;
1134 /* Check for empty disks */
1135 if (IsListEmpty (&List
->DiskListHead
))
1138 /* Check for next usable entry on current disk */
1139 if (List
->CurrentPartition
!= NULL
)
1141 Entry2
= List
->CurrentPartition
->ListEntry
.Flink
;
1142 while (Entry2
!= &List
->CurrentDisk
->PartListHead
)
1144 PartEntry
= CONTAINING_RECORD (Entry2
, PARTENTRY
, ListEntry
);
1146 // if (PartEntry->HidePartEntry == FALSE)
1148 List
->CurrentPartition
= PartEntry
;
1149 DrawPartitionList (List
);
1152 Entry2
= Entry2
->Flink
;
1156 /* Check for first usable entry on next disk */
1157 if (List
->CurrentDisk
!= NULL
)
1159 Entry1
= List
->CurrentDisk
->ListEntry
.Flink
;
1160 while (Entry1
!= &List
->DiskListHead
)
1162 DiskEntry
= CONTAINING_RECORD (Entry1
, DISKENTRY
, ListEntry
);
1164 Entry2
= DiskEntry
->PartListHead
.Flink
;
1165 while (Entry2
!= &DiskEntry
->PartListHead
)
1167 PartEntry
= CONTAINING_RECORD (Entry2
, PARTENTRY
, ListEntry
);
1169 // if (PartEntry->HidePartEntry == FALSE)
1171 List
->CurrentDisk
= DiskEntry
;
1172 List
->CurrentPartition
= PartEntry
;
1173 DrawPartitionList (List
);
1177 Entry2
= Entry2
->Flink
;
1180 Entry1
= Entry1
->Flink
;
1187 ScrollUpPartitionList (PPARTLIST List
)
1189 PDISKENTRY DiskEntry
;
1190 PPARTENTRY PartEntry
;
1194 /* Check for empty disks */
1195 if (IsListEmpty (&List
->DiskListHead
))
1198 /* check for previous usable entry on current disk */
1199 if (List
->CurrentPartition
!= NULL
)
1201 Entry2
= List
->CurrentPartition
->ListEntry
.Blink
;
1202 while (Entry2
!= &List
->CurrentDisk
->PartListHead
)
1204 PartEntry
= CONTAINING_RECORD (Entry2
, PARTENTRY
, ListEntry
);
1206 // if (PartEntry->HidePartEntry == FALSE)
1208 List
->CurrentPartition
= PartEntry
;
1209 DrawPartitionList (List
);
1212 Entry2
= Entry2
->Blink
;
1217 /* check for last usable entry on previous disk */
1218 if (List
->CurrentDisk
!= NULL
)
1220 Entry1
= List
->CurrentDisk
->ListEntry
.Blink
;
1221 while (Entry1
!= &List
->DiskListHead
)
1223 DiskEntry
= CONTAINING_RECORD (Entry1
, DISKENTRY
, ListEntry
);
1225 Entry2
= DiskEntry
->PartListHead
.Blink
;
1226 while (Entry2
!= &DiskEntry
->PartListHead
)
1228 PartEntry
= CONTAINING_RECORD (Entry2
, PARTENTRY
, ListEntry
);
1230 // if (PartEntry->HidePartEntry == FALSE)
1232 List
->CurrentDisk
= DiskEntry
;
1233 List
->CurrentPartition
= PartEntry
;
1234 DrawPartitionList (List
);
1238 Entry2
= Entry2
->Blink
;
1241 Entry1
= Entry1
->Blink
;
1248 GetPrevPartitionedEntry (PDISKENTRY DiskEntry
,
1249 PPARTENTRY CurrentEntry
)
1251 PPARTENTRY PrevEntry
;
1254 if (CurrentEntry
->ListEntry
.Blink
== &DiskEntry
->PartListHead
)
1257 Entry
= CurrentEntry
->ListEntry
.Blink
;
1258 while (Entry
!= &DiskEntry
->PartListHead
)
1260 PrevEntry
= CONTAINING_RECORD (Entry
,
1263 if (PrevEntry
->Unpartitioned
== FALSE
)
1266 Entry
= Entry
->Blink
;
1274 GetNextPartitionedEntry (PDISKENTRY DiskEntry
,
1275 PPARTENTRY CurrentEntry
)
1277 PPARTENTRY NextEntry
;
1280 if (CurrentEntry
->ListEntry
.Flink
== &DiskEntry
->PartListHead
)
1283 Entry
= CurrentEntry
->ListEntry
.Flink
;
1284 while (Entry
!= &DiskEntry
->PartListHead
)
1286 NextEntry
= CONTAINING_RECORD (Entry
,
1289 if (NextEntry
->Unpartitioned
== FALSE
)
1292 Entry
= Entry
->Flink
;
1300 GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry
,
1301 PPARTENTRY PartEntry
)
1303 PPARTENTRY PrevPartEntry
;
1305 if (PartEntry
->ListEntry
.Blink
!= &DiskEntry
->PartListHead
)
1307 PrevPartEntry
= CONTAINING_RECORD (PartEntry
->ListEntry
.Blink
,
1310 if (PrevPartEntry
->Unpartitioned
== TRUE
)
1311 return PrevPartEntry
;
1319 GetNextUnpartitionedEntry (PDISKENTRY DiskEntry
,
1320 PPARTENTRY PartEntry
)
1322 PPARTENTRY NextPartEntry
;
1324 if (PartEntry
->ListEntry
.Flink
!= &DiskEntry
->PartListHead
)
1326 NextPartEntry
= CONTAINING_RECORD (PartEntry
->ListEntry
.Flink
,
1329 if (NextPartEntry
->Unpartitioned
== TRUE
)
1330 return NextPartEntry
;
1338 CreateNewPartition (PPARTLIST List
,
1339 ULONGLONG PartitionSize
,
1342 PDISKENTRY DiskEntry
;
1343 PPARTENTRY PartEntry
;
1344 PPARTENTRY PrevPartEntry
;
1345 PPARTENTRY NextPartEntry
;
1346 PPARTENTRY NewPartEntry
;
1349 List
->CurrentDisk
== NULL
||
1350 List
->CurrentPartition
== NULL
||
1351 List
->CurrentPartition
->Unpartitioned
== FALSE
)
1356 DiskEntry
= List
->CurrentDisk
;
1357 PartEntry
= List
->CurrentPartition
;
1359 if (AutoCreate
== TRUE
||
1360 PartitionSize
== PartEntry
->UnpartitionedLength
)
1362 /* Convert current entry to 'new (unformatted)' */
1363 PartEntry
->FormatState
= Unformatted
;
1364 PartEntry
->PartInfo
[0].StartingOffset
.QuadPart
=
1365 PartEntry
->UnpartitionedOffset
+ DiskEntry
->TrackSize
;
1366 PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
=
1367 PartEntry
->UnpartitionedLength
- DiskEntry
->TrackSize
;
1368 PartEntry
->PartInfo
[0].PartitionType
= PARTITION_ENTRY_UNUSED
;
1369 PartEntry
->PartInfo
[0].BootIndicator
= FALSE
; /* FIXME */
1370 PartEntry
->PartInfo
[0].RewritePartition
= TRUE
;
1371 PartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1372 PartEntry
->PartInfo
[2].RewritePartition
= TRUE
;
1373 PartEntry
->PartInfo
[3].RewritePartition
= TRUE
;
1375 /* Get previous and next partition entries */
1376 PrevPartEntry
= GetPrevPartitionedEntry (DiskEntry
,
1378 NextPartEntry
= GetNextPartitionedEntry (DiskEntry
,
1381 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
1383 /* Current entry is in the middle of the list */
1385 /* Copy previous container partition data to current entry */
1386 RtlCopyMemory (&PartEntry
->PartInfo
[1],
1387 &PrevPartEntry
->PartInfo
[1],
1388 sizeof(PARTITION_INFORMATION
));
1389 PartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1391 /* Update previous container partition data */
1393 PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
=
1394 PartEntry
->PartInfo
[0].StartingOffset
.QuadPart
- DiskEntry
->TrackSize
;
1396 if (DiskEntry
->PartListHead
.Flink
== &PrevPartEntry
->ListEntry
)
1398 /* Special case - previous partition is first partition */
1399 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1400 DiskEntry
->DiskSize
- PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
;
1404 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1405 PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
;
1408 PrevPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1410 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
1412 /* Current entry is the first entry */
1415 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
1417 /* Current entry is the last entry */
1419 PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
=
1420 PartEntry
->PartInfo
[0].StartingOffset
.QuadPart
- DiskEntry
->TrackSize
;
1422 if (DiskEntry
->PartListHead
.Flink
== &PrevPartEntry
->ListEntry
)
1424 /* Special case - previous partition is first partition */
1425 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1426 DiskEntry
->DiskSize
- PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
;
1430 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1431 PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
;
1434 if ((PartEntry
->PartInfo
[1].StartingOffset
.QuadPart
+
1435 PartEntry
->PartInfo
[1].PartitionLength
.QuadPart
) <
1436 (1024ULL * 255ULL * 63ULL * 512ULL))
1438 PrevPartEntry
->PartInfo
[1].PartitionType
= PARTITION_EXTENDED
;
1442 PrevPartEntry
->PartInfo
[1].PartitionType
= PARTITION_XINT13_EXTENDED
;
1445 PrevPartEntry
->PartInfo
[1].BootIndicator
= FALSE
;
1446 PrevPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1449 PartEntry
->AutoCreate
= AutoCreate
;
1450 PartEntry
->New
= TRUE
;
1451 PartEntry
->Unpartitioned
= FALSE
;
1452 PartEntry
->UnpartitionedOffset
= 0ULL;
1453 PartEntry
->UnpartitionedLength
= 0ULL;
1457 /* Insert an initialize a new partition entry */
1458 NewPartEntry
= (PPARTENTRY
)RtlAllocateHeap (ProcessHeap
,
1461 if (NewPartEntry
== NULL
)
1464 RtlZeroMemory (NewPartEntry
,
1467 /* Insert the new entry into the list */
1468 InsertTailList (&PartEntry
->ListEntry
,
1469 &NewPartEntry
->ListEntry
);
1471 NewPartEntry
->New
= TRUE
;
1473 NewPartEntry
->FormatState
= Unformatted
;
1474 NewPartEntry
->PartInfo
[0].StartingOffset
.QuadPart
=
1475 PartEntry
->UnpartitionedOffset
+ DiskEntry
->TrackSize
;
1476 NewPartEntry
->PartInfo
[0].PartitionLength
.QuadPart
=
1477 PartitionSize
- DiskEntry
->TrackSize
;
1478 NewPartEntry
->PartInfo
[0].PartitionType
= PARTITION_ENTRY_UNUSED
;
1479 NewPartEntry
->PartInfo
[0].BootIndicator
= FALSE
; /* FIXME */
1480 NewPartEntry
->PartInfo
[0].RewritePartition
= TRUE
;
1481 NewPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1482 NewPartEntry
->PartInfo
[2].RewritePartition
= TRUE
;
1483 NewPartEntry
->PartInfo
[3].RewritePartition
= TRUE
;
1485 /* Get previous and next partition entries */
1486 PrevPartEntry
= GetPrevPartitionedEntry (DiskEntry
,
1488 NextPartEntry
= GetNextPartitionedEntry (DiskEntry
,
1491 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
1493 /* Current entry is in the middle of the list */
1495 /* Copy previous container partition data to current entry */
1496 RtlCopyMemory (&NewPartEntry
->PartInfo
[1],
1497 &PrevPartEntry
->PartInfo
[1],
1498 sizeof(PARTITION_INFORMATION
));
1499 NewPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1501 /* Update previous container partition data */
1503 PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
=
1504 NewPartEntry
->PartInfo
[0].StartingOffset
.QuadPart
- DiskEntry
->TrackSize
;
1506 if (DiskEntry
->PartListHead
.Flink
== &PrevPartEntry
->ListEntry
)
1508 /* Special case - previous partition is first partition */
1509 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1510 DiskEntry
->DiskSize
- PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
;
1514 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1515 NewPartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
;
1518 PrevPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1520 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
1522 /* Current entry is the first entry */
1525 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
1527 /* Current entry is the last entry */
1529 PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
=
1530 NewPartEntry
->PartInfo
[0].StartingOffset
.QuadPart
- DiskEntry
->TrackSize
;
1532 if (DiskEntry
->PartListHead
.Flink
== &PrevPartEntry
->ListEntry
)
1534 /* Special case - previous partition is first partition */
1535 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1536 DiskEntry
->DiskSize
- PrevPartEntry
->PartInfo
[1].StartingOffset
.QuadPart
;
1540 PrevPartEntry
->PartInfo
[1].PartitionLength
.QuadPart
=
1541 NewPartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
;
1544 if ((PartEntry
->PartInfo
[1].StartingOffset
.QuadPart
+
1545 PartEntry
->PartInfo
[1].PartitionLength
.QuadPart
) <
1546 (1024ULL * 255ULL * 63ULL * 512ULL))
1548 PrevPartEntry
->PartInfo
[1].PartitionType
= PARTITION_EXTENDED
;
1552 PrevPartEntry
->PartInfo
[1].PartitionType
= PARTITION_XINT13_EXTENDED
;
1555 PrevPartEntry
->PartInfo
[1].BootIndicator
= FALSE
;
1556 PrevPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1559 /* Update offset and size of the remaining unpartitioned disk space */
1560 PartEntry
->UnpartitionedOffset
+= PartitionSize
;
1561 PartEntry
->UnpartitionedLength
-= PartitionSize
;
1564 DiskEntry
->Modified
= TRUE
;
1566 UpdatePartitionNumbers (DiskEntry
);
1568 AssignDriverLetters (List
);
1573 DeleteCurrentPartition (PPARTLIST List
)
1575 PDISKENTRY DiskEntry
;
1576 PPARTENTRY PartEntry
;
1577 PPARTENTRY PrevPartEntry
;
1578 PPARTENTRY NextPartEntry
;
1581 List
->CurrentDisk
== NULL
||
1582 List
->CurrentPartition
== NULL
||
1583 List
->CurrentPartition
->Unpartitioned
== TRUE
)
1588 DiskEntry
= List
->CurrentDisk
;
1589 PartEntry
= List
->CurrentPartition
;
1591 /* Adjust container partition entries */
1593 /* Get previous and next partition entries */
1594 PrevPartEntry
= GetPrevPartitionedEntry (DiskEntry
,
1596 NextPartEntry
= GetNextPartitionedEntry (DiskEntry
,
1599 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
1601 /* Current entry is in the middle of the list */
1604 * The first extended partition can not be deleted
1605 * as long as other extended partitions are present.
1607 if (PrevPartEntry
->ListEntry
.Blink
== &DiskEntry
->PartListHead
)
1610 /* Copy previous container partition data to current entry */
1611 RtlCopyMemory (&PrevPartEntry
->PartInfo
[1],
1612 &PartEntry
->PartInfo
[1],
1613 sizeof(PARTITION_INFORMATION
));
1614 PrevPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1616 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
1619 * A primary partition can not be deleted as long as
1620 * extended partitions are present.
1624 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
1626 /* Current entry is the last entry */
1627 RtlZeroMemory (&PrevPartEntry
->PartInfo
[1],
1628 sizeof(PARTITION_INFORMATION
));
1629 PrevPartEntry
->PartInfo
[1].RewritePartition
= TRUE
;
1633 /* Adjust unpartitioned disk space entries */
1635 /* Get pointer to previous and next unpartitioned entries */
1636 PrevPartEntry
= GetPrevUnpartitionedEntry (DiskEntry
,
1639 NextPartEntry
= GetNextUnpartitionedEntry (DiskEntry
,
1642 if (PrevPartEntry
!= NULL
&& NextPartEntry
!= NULL
)
1644 /* Merge previous, current and next unpartitioned entry */
1646 /* Adjust the previous entries length */
1647 PrevPartEntry
->UnpartitionedLength
+=
1648 (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
+
1649 NextPartEntry
->UnpartitionedLength
);
1651 /* Remove the current entry */
1652 RemoveEntryList (&PartEntry
->ListEntry
);
1653 RtlFreeHeap (ProcessHeap
,
1657 /* Remove the next entry */
1658 RemoveEntryList (&NextPartEntry
->ListEntry
);
1659 RtlFreeHeap (ProcessHeap
,
1663 /* Update current partition */
1664 List
->CurrentPartition
= PrevPartEntry
;
1666 else if (PrevPartEntry
!= NULL
&& NextPartEntry
== NULL
)
1668 /* Merge current and previous unpartitioned entry */
1670 /* Adjust the previous entries length */
1671 PrevPartEntry
->UnpartitionedLength
+=
1672 (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
);
1674 /* Remove the current entry */
1675 RemoveEntryList (&PartEntry
->ListEntry
);
1676 RtlFreeHeap (ProcessHeap
,
1680 /* Update current partition */
1681 List
->CurrentPartition
= PrevPartEntry
;
1683 else if (PrevPartEntry
== NULL
&& NextPartEntry
!= NULL
)
1685 /* Merge current and next unpartitioned entry */
1687 /* Adjust the next entries offset and length */
1688 NextPartEntry
->UnpartitionedOffset
=
1689 PartEntry
->PartInfo
[0].StartingOffset
.QuadPart
- DiskEntry
->TrackSize
;
1690 NextPartEntry
->UnpartitionedLength
+=
1691 (PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
);
1693 /* Remove the current entry */
1694 RemoveEntryList (&PartEntry
->ListEntry
);
1695 RtlFreeHeap (ProcessHeap
,
1699 /* Update current partition */
1700 List
->CurrentPartition
= NextPartEntry
;
1704 /* Nothing to merge but change current entry */
1705 PartEntry
->New
= FALSE
;
1706 PartEntry
->Unpartitioned
= TRUE
;
1707 PartEntry
->UnpartitionedOffset
=
1708 PartEntry
->PartInfo
[0].StartingOffset
.QuadPart
- DiskEntry
->TrackSize
;
1709 PartEntry
->UnpartitionedLength
=
1710 PartEntry
->PartInfo
[0].PartitionLength
.QuadPart
+ DiskEntry
->TrackSize
;
1712 /* Wipe the partition table */
1713 RtlZeroMemory (&PartEntry
->PartInfo
,
1714 sizeof(PartEntry
->PartInfo
));
1717 DiskEntry
->Modified
= TRUE
;
1719 UpdatePartitionNumbers (DiskEntry
);
1721 AssignDriverLetters (List
);
1726 CheckActiveBootPartition (PPARTLIST List
)
1728 PDISKENTRY DiskEntry
;
1729 PPARTENTRY PartEntry
;
1731 /* Check for empty disk list */
1732 if (IsListEmpty (&List
->DiskListHead
))
1734 List
->ActiveBootDisk
= NULL
;
1735 List
->ActiveBootPartition
= NULL
;
1740 if (List
->ActiveBootDisk
!= NULL
&&
1741 List
->ActiveBootPartition
!= NULL
)
1743 /* We already have an active boot partition */
1748 DiskEntry
= CONTAINING_RECORD (List
->DiskListHead
.Flink
,
1752 /* Check for empty partition list */
1753 if (IsListEmpty (&DiskEntry
->PartListHead
))
1755 List
->ActiveBootDisk
= NULL
;
1756 List
->ActiveBootPartition
= NULL
;
1760 PartEntry
= CONTAINING_RECORD (DiskEntry
->PartListHead
.Flink
,
1764 /* Set active boot partition */
1765 if ((DiskEntry
->NewDisk
== TRUE
) ||
1766 (PartEntry
->PartInfo
[0].BootIndicator
== FALSE
&&
1767 PartEntry
->PartInfo
[1].BootIndicator
== FALSE
&&
1768 PartEntry
->PartInfo
[2].BootIndicator
== FALSE
&&
1769 PartEntry
->PartInfo
[3].BootIndicator
== FALSE
))
1771 PartEntry
->PartInfo
[0].BootIndicator
= TRUE
;
1772 PartEntry
->PartInfo
[0].RewritePartition
= TRUE
;
1773 DiskEntry
->Modified
= TRUE
;
1776 /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
1777 List
->ActiveBootDisk
= DiskEntry
;
1778 List
->ActiveBootPartition
= PartEntry
;
1783 CheckForLinuxFdiskPartitions (PPARTLIST List
)
1785 PDISKENTRY DiskEntry
;
1786 PPARTENTRY PartEntry
;
1789 ULONG PartitionCount
;
1792 Entry1
= List
->DiskListHead
.Flink
;
1793 while (Entry1
!= &List
->DiskListHead
)
1795 DiskEntry
= CONTAINING_RECORD (Entry1
,
1799 Entry2
= DiskEntry
->PartListHead
.Flink
;
1800 while (Entry2
!= &DiskEntry
->PartListHead
)
1802 PartEntry
= CONTAINING_RECORD (Entry2
,
1806 if (PartEntry
->Unpartitioned
== FALSE
)
1810 for (i
= 0; i
< 4; i
++)
1812 if (!IsContainerPartition (PartEntry
->PartInfo
[i
].PartitionType
) &&
1813 PartEntry
->PartInfo
[i
].PartitionLength
.QuadPart
!= 0ULL)
1819 if (PartitionCount
> 1)
1825 Entry2
= Entry2
->Flink
;
1828 Entry1
= Entry1
->Flink
;
1836 WritePartitionsToDisk (PPARTLIST List
)
1838 PDRIVE_LAYOUT_INFORMATION DriveLayout
;
1839 OBJECT_ATTRIBUTES ObjectAttributes
;
1840 IO_STATUS_BLOCK Iosb
;
1841 WCHAR SrcPath
[MAX_PATH
];
1842 WCHAR DstPath
[MAX_PATH
];
1843 UNICODE_STRING Name
;
1845 PDISKENTRY DiskEntry
;
1846 PPARTENTRY PartEntry
;
1849 ULONG PartitionCount
;
1850 ULONG DriveLayoutSize
;
1859 Entry1
= List
->DiskListHead
.Flink
;
1860 while (Entry1
!= &List
->DiskListHead
)
1862 DiskEntry
= CONTAINING_RECORD (Entry1
,
1866 if (DiskEntry
->Modified
== TRUE
)
1868 /* Count partitioned entries */
1870 Entry2
= DiskEntry
->PartListHead
.Flink
;
1871 while (Entry2
!= &DiskEntry
->PartListHead
)
1873 PartEntry
= CONTAINING_RECORD (Entry2
,
1876 if (PartEntry
->Unpartitioned
== FALSE
)
1878 PartitionCount
+= 4;
1881 Entry2
= Entry2
->Flink
;
1884 if (PartitionCount
> 0)
1886 DriveLayoutSize
= sizeof (DRIVE_LAYOUT_INFORMATION
) +
1887 ((PartitionCount
- 1) * sizeof (PARTITION_INFORMATION
));
1888 DriveLayout
= (PDRIVE_LAYOUT_INFORMATION
)RtlAllocateHeap (ProcessHeap
,
1891 if (DriveLayout
== NULL
)
1893 DPRINT1 ("RtlAllocateHeap() failed\n");
1897 RtlZeroMemory (DriveLayout
,
1900 DriveLayout
->PartitionCount
= PartitionCount
;
1903 Entry2
= DiskEntry
->PartListHead
.Flink
;
1904 while (Entry2
!= &DiskEntry
->PartListHead
)
1906 PartEntry
= CONTAINING_RECORD (Entry2
,
1909 if (PartEntry
->Unpartitioned
== FALSE
)
1911 RtlCopyMemory (&DriveLayout
->PartitionEntry
[Index
],
1912 &PartEntry
->PartInfo
[0],
1913 4 * sizeof (PARTITION_INFORMATION
));
1917 Entry2
= Entry2
->Flink
;
1921 L
"\\Device\\Harddisk%d\\Partition0",
1922 DiskEntry
->DiskNumber
);
1923 RtlInitUnicodeString (&Name
,
1925 InitializeObjectAttributes (&ObjectAttributes
,
1931 Status
= NtOpenFile (&FileHandle
,
1936 FILE_SYNCHRONOUS_IO_NONALERT
);
1937 if (!NT_SUCCESS (Status
))
1939 DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status
);
1943 Status
= NtDeviceIoControlFile (FileHandle
,
1948 IOCTL_DISK_SET_DRIVE_LAYOUT
,
1953 if (!NT_SUCCESS (Status
))
1955 DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status
);
1956 NtClose (FileHandle
);
1960 RtlFreeHeap (ProcessHeap
,
1964 NtClose (FileHandle
);
1966 /* Install MBR code if the disk is new */
1967 if (DiskEntry
->NewDisk
== TRUE
)
1969 wcscpy (SrcPath
, SourceRootPath
.Buffer
);
1970 wcscat (SrcPath
, L
"\\loader\\dosmbr.bin");
1972 DPRINT1 ("Install MBR bootcode: %S ==> %S\n",
1975 /* Install MBR bootcode */
1976 Status
= InstallMbrBootCodeToDisk (SrcPath
,
1978 if (!NT_SUCCESS (Status
))
1980 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
1985 DiskEntry
->NewDisk
= FALSE
;
1990 Entry1
= Entry1
->Flink
;