3 * Copyright (C) 2002 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.
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
27 #include <ddk/ntddk.h>
28 #include <ddk/ntddscsi.h>
30 #include <ntdll/rtl.h>
32 #include <ntos/minmax.h>
40 /* FUNCTIONS ****************************************************************/
43 AddPartitionList(ULONG DiskNumber,
45 DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
54 * Determine required number of partiton entries.
55 * This must include entries for unused disk space.
58 /* Check for unpartitioned disk */
59 if (LayoutBuffer->PartitionCount == 0)
67 for (i = 0; i < LayoutBuffer->PartitionCount; i++)
73 EntryCount = LayoutBuffer->PartitionCount;
77 DiskEntry->PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap,
79 EntryCount * sizeof(PARTENTRY));
80 DiskEntry->PartCount = EntryCount;
82 RtlZeroMemory(DiskEntry->PartArray,
83 EntryCount * sizeof(PARTENTRY));
85 if (LayoutBuffer->PartitionCount == 0)
87 /* Initialize an 'Unpartitioned space' entry */
88 PartEntry = &DiskEntry->PartArray[0];
90 PartEntry->Unpartitioned = TRUE;
91 PartEntry->PartSize = 0; /* ?? */
93 PartEntry->Used = TRUE;
97 for (i = 0; i < LayoutBuffer->PartitionCount; i++)
99 PartEntry = &DiskEntry->PartArray[i];
101 if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) &&
102 (!IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType)))
104 PartEntry->PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
105 PartEntry->PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber,
106 PartEntry->PartType = LayoutBuffer->PartitionEntry[i].PartitionType;
107 PartEntry->Active = LayoutBuffer->PartitionEntry[i].BootIndicator;
109 PartEntry->DriveLetter = GetDriveLetter(DiskNumber,
110 LayoutBuffer->PartitionEntry[i].PartitionNumber);
112 PartEntry->Unpartitioned = FALSE;
114 PartEntry->Used = TRUE;
118 PartEntry->Used = FALSE;
126 GetDriverName(PDISKENTRY DiskEntry)
128 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
132 RtlInitUnicodeString(&DiskEntry->DriverName,
136 L"\\Scsi\\Scsi Port %lu",
139 RtlZeroMemory(&QueryTable,
142 QueryTable[0].Name = L"Driver";
143 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
144 QueryTable[0].EntryContext = &DiskEntry->DriverName;
146 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
151 if (!NT_SUCCESS(Status))
153 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
159 CreatePartitionList(SHORT Left,
165 OBJECT_ATTRIBUTES ObjectAttributes;
166 SYSTEM_DEVICE_INFORMATION Sdi;
167 DISK_GEOMETRY DiskGeometry;
168 IO_STATUS_BLOCK Iosb;
172 WCHAR Buffer[MAX_PATH];
175 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
176 SCSI_ADDRESS ScsiAddress;
178 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST));
185 List->Bottom = Bottom;
189 List->TopDisk = (ULONG)-1;
190 List->TopPartition = (ULONG)-1;
192 List->CurrentDisk = (ULONG)-1;
193 List->CurrentPartition = (ULONG)-1;
196 List->DiskArray = NULL;
199 Status = NtQuerySystemInformation(SystemDeviceInformation,
201 sizeof(SYSTEM_DEVICE_INFORMATION),
203 if (!NT_SUCCESS(Status))
205 RtlFreeHeap(ProcessHeap, 0, List);
209 List->DiskArray = (PDISKENTRY)RtlAllocateHeap(ProcessHeap,
211 Sdi.NumberOfDisks * sizeof(DISKENTRY));
212 List->DiskCount = Sdi.NumberOfDisks;
214 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
217 L"\\Device\\Harddisk%d\\Partition0",
219 RtlInitUnicodeString(&Name,
222 InitializeObjectAttributes(&ObjectAttributes,
228 Status = NtOpenFile(&FileHandle,
233 FILE_SYNCHRONOUS_IO_NONALERT);
234 if (NT_SUCCESS(Status))
236 Status = NtDeviceIoControlFile(FileHandle,
241 IOCTL_DISK_GET_DRIVE_GEOMETRY,
245 sizeof(DISK_GEOMETRY));
246 if (NT_SUCCESS(Status))
248 if (DiskGeometry.MediaType == FixedMedia)
250 Status = NtDeviceIoControlFile(FileHandle,
255 IOCTL_SCSI_GET_ADDRESS,
259 sizeof(SCSI_ADDRESS));
262 List->DiskArray[DiskNumber].DiskSize =
263 DiskGeometry.Cylinders.QuadPart *
264 (ULONGLONG)DiskGeometry.TracksPerCylinder *
265 (ULONGLONG)DiskGeometry.SectorsPerTrack *
266 (ULONGLONG)DiskGeometry.BytesPerSector;
267 List->DiskArray[DiskNumber].DiskNumber = DiskNumber;
268 List->DiskArray[DiskNumber].Port = ScsiAddress.PortNumber;
269 List->DiskArray[DiskNumber].Bus = ScsiAddress.PathId;
270 List->DiskArray[DiskNumber].Id = ScsiAddress.TargetId;
272 List->DiskArray[DiskNumber].FixedDisk = TRUE;
274 GetDriverName(&List->DiskArray[DiskNumber]);
276 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
278 Status = NtDeviceIoControlFile(FileHandle,
283 IOCTL_DISK_GET_DRIVE_LAYOUT,
288 if (NT_SUCCESS(Status))
290 AddPartitionList(DiskNumber,
291 &List->DiskArray[DiskNumber],
295 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
299 /* mark removable disk entry */
300 List->DiskArray[DiskNumber].FixedDisk = FALSE;
301 List->DiskArray[DiskNumber].PartCount = 0;
302 List->DiskArray[DiskNumber].PartArray = NULL;
311 List->TopPartition = 0;
313 /* FIXME: search for first usable disk and partition */
314 List->CurrentDisk = 0;
315 List->CurrentPartition = 0;
317 DrawPartitionList(List);
324 DestroyPartitionList(PPARTLIST List)
331 /* clear occupied screen area */
332 coPos.X = List->Left;
333 Width = List->Right - List->Left + 1;
334 for (coPos.Y = List->Top; coPos.Y <= List->Bottom; coPos.Y++)
336 FillConsoleOutputAttribute(0x17,
341 FillConsoleOutputCharacter(' ',
348 /* Release disk and partition info */
349 if (List->DiskArray != NULL)
351 for (i = 0; i < List->DiskCount; i++)
353 /* Release driver name */
354 RtlFreeUnicodeString(&List->DiskArray[i].DriverName);
356 /* Release partition array */
357 if (List->DiskArray[i].PartArray != NULL)
359 RtlFreeHeap(ProcessHeap, 0, List->DiskArray[i].PartArray);
360 List->DiskArray[i].PartCount = 0;
361 List->DiskArray[i].PartArray = NULL;
365 /* Release disk array */
366 RtlFreeHeap(ProcessHeap, 0, List->DiskArray);
368 List->DiskArray = NULL;
371 /* Release list head */
372 RtlFreeHeap(ProcessHeap, 0, List);
377 PrintEmptyLine(PPARTLIST List)
384 Width = List->Right - List->Left - 1;
385 Height = List->Bottom - List->Top - 1;
387 if (List->Line < 0 || List->Line > Height)
390 coPos.X = List->Left + 1;
391 coPos.Y = List->Top + 1 + List->Line;
393 FillConsoleOutputAttribute(0x17,
398 FillConsoleOutputCharacter(' ',
408 PrintPartitionData(PPARTLIST List,
412 PPARTENTRY PartEntry;
413 CHAR LineBuffer[128];
424 Width = List->Right - List->Left - 1;
425 Height = List->Bottom - List->Top - 1;
427 if (List->Line < 0 || List->Line > Height)
430 coPos.X = List->Left + 1;
431 coPos.Y = List->Top + 1 + List->Line;
433 PartEntry = &List->DiskArray[DiskIndex].PartArray[PartIndex];
435 /* Determine partition type */
437 if (PartEntry->Unpartitioned == FALSE)
439 if ((PartEntry->PartType == PARTITION_FAT_12) ||
440 (PartEntry->PartType == PARTITION_FAT_16) ||
441 (PartEntry->PartType == PARTITION_HUGE) ||
442 (PartEntry->PartType == PARTITION_XINT13))
446 else if ((PartEntry->PartType == PARTITION_FAT32) ||
447 (PartEntry->PartType == PARTITION_FAT32_XINT13))
451 else if (PartEntry->PartType == PARTITION_IFS)
453 PartType = "NTFS"; /* FIXME: Not quite correct! */
459 if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */
461 PartSize = (PartEntry->PartSize + (1 << 29)) >> 30;
466 if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */
468 PartSize = (PartEntry->PartSize + (1 << 19)) >> 20;
473 PartSize = (PartEntry->PartSize + (1 << 9)) >> 10;
478 if (PartEntry->Unpartitioned == TRUE)
481 " Unpartitioned space %I64u %s",
485 else if (PartEntry->DriveLetter != (CHAR)0)
487 if (PartType == NULL)
490 "%c: Type %-3lu %I64u %s",
491 PartEntry->DriveLetter,
500 PartEntry->DriveLetter,
508 "%c: %s (%d: nr: %d type: %x) %I64u %s",
509 PartEntry->DriveLetter,
512 PartEntry->PartNumber,
521 "-- %s (%d: nr: %d type: %x) %I64u %s",
522 PartEntry->FileSystemName,
524 PartEntry->PartNumber,
530 Attribute = (List->CurrentDisk == DiskIndex &&
531 List->CurrentPartition == PartIndex) ? 0x71 : 0x17;
533 FillConsoleOutputCharacter(' ',
540 FillConsoleOutputAttribute(Attribute,
547 WriteConsoleOutputCharacters(LineBuffer,
548 min(strlen(LineBuffer), Width),
556 PrintDiskData(PPARTLIST List,
559 PDISKENTRY DiskEntry;
560 CHAR LineBuffer[128];
569 DiskEntry = &List->DiskArray[DiskIndex];
571 Width = List->Right - List->Left - 1;
572 Height = List->Bottom - List->Top - 1;
574 if (List->Line < 0 || List->Line > Height)
577 coPos.X = List->Left + 1;
578 coPos.Y = List->Top + 1 + List->Line;
581 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
583 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
589 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
595 if (DiskEntry->DriverName.Length > 0)
598 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
601 DiskEntry->DiskNumber,
605 &DiskEntry->DriverName);
610 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
613 DiskEntry->DiskNumber,
619 FillConsoleOutputAttribute(0x17,
624 FillConsoleOutputCharacter(' ',
630 WriteConsoleOutputCharacters(LineBuffer,
631 min(strlen(LineBuffer), Width - 2),
636 /* Print separator line */
637 PrintEmptyLine(List);
640 /* Print partition lines*/
641 for (PartIndex = 0; PartIndex < DiskEntry->PartCount; PartIndex++)
643 if (DiskEntry->PartArray[PartIndex].Used == TRUE)
645 PrintPartitionData(List,
651 /* Print separator line */
652 PrintEmptyLine(List);
657 DrawPartitionList(PPARTLIST List)
659 CHAR LineBuffer[128];
665 /* draw upper left corner */
666 coPos.X = List->Left;
668 FillConsoleOutputCharacter(0xDA, // '+',
673 /* draw upper edge */
674 coPos.X = List->Left + 1;
676 FillConsoleOutputCharacter(0xC4, // '-',
677 List->Right - List->Left - 1,
681 /* draw upper right corner */
682 coPos.X = List->Right;
684 FillConsoleOutputCharacter(0xBF, // '+',
689 /* draw left and right edge */
690 for (i = List->Top + 1; i < List->Bottom; i++)
692 coPos.X = List->Left;
694 FillConsoleOutputCharacter(0xB3, // '|',
699 coPos.X = List->Right;
700 FillConsoleOutputCharacter(0xB3, //'|',
706 /* draw lower left corner */
707 coPos.X = List->Left;
708 coPos.Y = List->Bottom;
709 FillConsoleOutputCharacter(0xC0, // '+',
714 /* draw lower edge */
715 coPos.X = List->Left + 1;
716 coPos.Y = List->Bottom;
717 FillConsoleOutputCharacter(0xC4, // '-',
718 List->Right - List->Left - 1,
722 /* draw lower right corner */
723 coPos.X = List->Right;
724 coPos.Y = List->Bottom;
725 FillConsoleOutputCharacter(0xD9, // '+',
730 /* print list entries */
732 for (DiskIndex = 0; DiskIndex < List->DiskCount; DiskIndex++)
734 if (List->DiskArray[DiskIndex].FixedDisk == TRUE)
736 /* Print disk entry */
745 ScrollDownPartitionList(PPARTLIST List)
750 /* check for available disks */
751 if (List->DiskCount == 0)
754 /* check for next usable entry on current disk */
755 for (i = List->CurrentPartition + 1; i < List->DiskArray[List->CurrentDisk].PartCount; i++)
757 if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
759 List->CurrentPartition = i;
760 DrawPartitionList(List);
765 /* check for first usable entry on next disk */
766 for (j = List->CurrentDisk + 1; j < List->DiskCount; j++)
768 for (i = 0; i < List->DiskArray[j].PartCount; i++)
770 if (List->DiskArray[j].PartArray[i].Used == TRUE)
772 List->CurrentDisk = j;
773 List->CurrentPartition = i;
774 DrawPartitionList(List);
783 ScrollUpPartitionList(PPARTLIST List)
788 /* check for available disks */
789 if (List->DiskCount == 0)
792 /* check for previous usable entry on current disk */
793 for (i = List->CurrentPartition - 1; i != (ULONG)-1; i--)
795 if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
797 List->CurrentPartition = i;
798 DrawPartitionList(List);
803 /* check for last usable entry on previous disk */
804 for (j = List->CurrentDisk - 1; j != (ULONG)-1; j--)
806 for (i = List->DiskArray[j].PartCount - 1; i != (ULONG)-1; i--)
808 if (List->DiskArray[j].PartArray[i].Used == TRUE)
810 List->CurrentDisk = j;
811 List->CurrentPartition = i;
812 DrawPartitionList(List);
821 GetSelectedPartition(PPARTLIST List,
824 PDISKENTRY DiskEntry;
825 PPARTENTRY PartEntry;
827 if (List->CurrentDisk >= List->DiskCount)
830 DiskEntry = &List->DiskArray[List->CurrentDisk];
832 if (DiskEntry->FixedDisk == FALSE)
835 if (List->CurrentPartition >= DiskEntry->PartCount)
838 PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
840 if (PartEntry->Used == FALSE)
843 /* Copy disk-specific data */
844 Data->DiskSize = DiskEntry->DiskSize;
845 Data->DiskNumber = DiskEntry->DiskNumber;
846 Data->Port = DiskEntry->Port;
847 Data->Bus = DiskEntry->Bus;
848 Data->Id = DiskEntry->Id;
850 /* Copy driver name */
851 RtlInitUnicodeString(&Data->DriverName,
853 if (DiskEntry->DriverName.Length != 0)
855 Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
857 DiskEntry->DriverName.MaximumLength);
858 if (Data->DriverName.Buffer != NULL)
860 Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
861 Data->DriverName.Length = DiskEntry->DriverName.Length;
862 RtlCopyMemory(Data->DriverName.Buffer,
863 DiskEntry->DriverName.Buffer,
864 DiskEntry->DriverName.MaximumLength);
868 /* Copy partition-specific data */
869 Data->PartSize = PartEntry->PartSize;
870 Data->PartNumber = PartEntry->PartNumber;
871 Data->PartType = PartEntry->PartType;
872 Data->DriveLetter = PartEntry->DriveLetter;
879 GetActiveBootPartition(PPARTLIST List,
882 PDISKENTRY DiskEntry;
883 PPARTENTRY PartEntry;
886 if (List->CurrentDisk >= List->DiskCount)
889 DiskEntry = &List->DiskArray[0];
891 if (DiskEntry->FixedDisk == FALSE)
894 for (i = 0; i < DiskEntry->PartCount; i++)
896 if (DiskEntry->PartArray[i].Active)
898 PartEntry = &DiskEntry->PartArray[i];
900 if (PartEntry->Used == FALSE)
903 /* Copy disk-specific data */
904 Data->DiskSize = DiskEntry->DiskSize;
905 Data->DiskNumber = DiskEntry->DiskNumber;
906 Data->Port = DiskEntry->Port;
907 Data->Bus = DiskEntry->Bus;
908 Data->Id = DiskEntry->Id;
910 /* Copy driver name */
911 RtlInitUnicodeString(&Data->DriverName,
913 if (DiskEntry->DriverName.Length != 0)
915 Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
917 DiskEntry->DriverName.MaximumLength);
918 if (Data->DriverName.Buffer != NULL)
920 Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
921 Data->DriverName.Length = DiskEntry->DriverName.Length;
922 RtlCopyMemory(Data->DriverName.Buffer,
923 DiskEntry->DriverName.Buffer,
924 DiskEntry->DriverName.MaximumLength);
928 /* Copy partition-specific data */
929 Data->PartSize = PartEntry->PartSize;
930 Data->PartNumber = PartEntry->PartNumber;
931 Data->PartType = PartEntry->PartType;
932 Data->DriveLetter = PartEntry->DriveLetter;