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 CreatePartitionList(SHORT Left,
49 OBJECT_ATTRIBUTES ObjectAttributes;
50 SYSTEM_DEVICE_INFORMATION Sdi;
51 DISK_GEOMETRY DiskGeometry;
56 WCHAR Buffer[MAX_PATH];
59 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
60 SCSI_ADDRESS ScsiAddress;
63 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST));
70 List->Bottom = Bottom;
74 List->TopDisk = (ULONG)-1;
75 List->TopPartition = (ULONG)-1;
77 List->CurrentDisk = (ULONG)-1;
78 List->CurrentPartition = (ULONG)-1;
81 List->DiskArray = NULL;
84 Status = NtQuerySystemInformation(SystemDeviceInformation,
86 sizeof(SYSTEM_DEVICE_INFORMATION),
88 if (!NT_SUCCESS(Status))
90 RtlFreeHeap(ProcessHeap, 0, List);
94 List->DiskArray = (PDISKENTRY)RtlAllocateHeap(ProcessHeap,
96 Sdi.NumberOfDisks * sizeof(DISKENTRY));
97 List->DiskCount = Sdi.NumberOfDisks;
99 for (DiskCount = 0; DiskCount < Sdi.NumberOfDisks; DiskCount++)
102 L"\\Device\\Harddisk%d\\Partition0",
104 RtlInitUnicodeString(&Name,
107 InitializeObjectAttributes(&ObjectAttributes,
113 Status = NtOpenFile(&FileHandle,
118 FILE_SYNCHRONOUS_IO_NONALERT);
119 if (NT_SUCCESS(Status))
121 Status = NtDeviceIoControlFile(FileHandle,
126 IOCTL_DISK_GET_DRIVE_GEOMETRY,
130 sizeof(DISK_GEOMETRY));
131 if (NT_SUCCESS(Status))
133 if (DiskGeometry.MediaType == FixedMedia)
135 Status = NtDeviceIoControlFile(FileHandle,
140 IOCTL_SCSI_GET_ADDRESS,
144 sizeof(SCSI_ADDRESS));
147 List->DiskArray[DiskCount].DiskSize =
148 DiskGeometry.Cylinders.QuadPart *
149 (ULONGLONG)DiskGeometry.TracksPerCylinder *
150 (ULONGLONG)DiskGeometry.SectorsPerTrack *
151 (ULONGLONG)DiskGeometry.BytesPerSector;
152 List->DiskArray[DiskCount].DiskNumber = DiskCount;
153 List->DiskArray[DiskCount].Port = ScsiAddress.PortNumber;
154 List->DiskArray[DiskCount].Bus = ScsiAddress.PathId;
155 List->DiskArray[DiskCount].Id = ScsiAddress.TargetId;
157 List->DiskArray[DiskCount].FixedDisk = TRUE;
160 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
162 Status = NtDeviceIoControlFile(FileHandle,
167 IOCTL_DISK_GET_DRIVE_LAYOUT,
172 if (NT_SUCCESS(Status))
175 List->DiskArray[DiskCount].PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap,
177 LayoutBuffer->PartitionCount * sizeof(PARTENTRY));
178 List->DiskArray[DiskCount].PartCount = LayoutBuffer->PartitionCount;
180 for (i = 0; i < LayoutBuffer->PartitionCount; i++)
182 if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) &&
183 !IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType))
185 List->DiskArray[DiskCount].PartArray[i].PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
186 List->DiskArray[DiskCount].PartArray[i].PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber,
187 List->DiskArray[DiskCount].PartArray[i].PartType = LayoutBuffer->PartitionEntry[i].PartitionType;
189 List->DiskArray[DiskCount].PartArray[i].DriveLetter = GetDriveLetter(DiskCount,
190 LayoutBuffer->PartitionEntry[i].PartitionNumber);
192 List->DiskArray[DiskCount].PartArray[i].Used = TRUE;
196 List->DiskArray[DiskCount].PartArray[i].Used = FALSE;
201 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
205 /* mark removable disk entry */
206 List->DiskArray[DiskCount].FixedDisk = FALSE;
207 List->DiskArray[DiskCount].PartCount = 0;
208 List->DiskArray[DiskCount].PartArray = NULL;
217 List->TopPartition = 0;
219 /* FIXME: search for first usable disk and partition */
220 List->CurrentDisk = 0;
221 List->CurrentPartition = 0;
223 DrawPartitionList(List);
230 DestroyPartitionList(PPARTLIST List)
237 /* clear occupied screen area */
238 coPos.X = List->Left;
239 Width = List->Right - List->Left + 1;
240 for (coPos.Y = List->Top; coPos.Y <= List->Bottom; coPos.Y++)
242 FillConsoleOutputAttribute(0x17,
247 FillConsoleOutputCharacter(' ',
254 /* free disk and partition info */
255 if (List->DiskArray != NULL)
257 /* free partition arrays */
258 for (i = 0; i < List->DiskCount; i++)
260 if (List->DiskArray[i].PartArray != NULL)
262 RtlFreeHeap(ProcessHeap, 0, List->DiskArray[i].PartArray);
263 List->DiskArray[i].PartCount = 0;
264 List->DiskArray[i].PartArray = NULL;
268 /* free disk array */
269 RtlFreeHeap(ProcessHeap, 0, List->DiskArray);
271 List->DiskArray = NULL;
275 RtlFreeHeap(ProcessHeap, 0, List);
280 PrintEmptyLine(PPARTLIST List)
287 Width = List->Right - List->Left - 1;
288 Height = List->Bottom - List->Top - 1;
290 if (List->Line < 0 || List->Line > Height)
293 coPos.X = List->Left + 1;
294 coPos.Y = List->Top + 1 + List->Line;
296 FillConsoleOutputAttribute(0x17,
301 FillConsoleOutputCharacter(' ',
311 PrintPartitionData(PPARTLIST List,
315 PPARTENTRY PartEntry;
316 CHAR LineBuffer[128];
328 Width = List->Right - List->Left - 1;
329 Height = List->Bottom - List->Top - 1;
331 if (List->Line < 0 || List->Line > Height)
334 coPos.X = List->Left + 1;
335 coPos.Y = List->Top + 1 + List->Line;
337 PartEntry = &List->DiskArray[DiskIndex].PartArray[PartIndex];
339 if ((PartEntry->PartType == PARTITION_FAT_12) ||
340 (PartEntry->PartType == PARTITION_FAT_16) ||
341 (PartEntry->PartType == PARTITION_HUGE) ||
342 (PartEntry->PartType == PARTITION_XINT13))
346 else if ((PartEntry->PartType == PARTITION_FAT32) ||
347 (PartEntry->PartType == PARTITION_FAT32_XINT13))
351 else if (PartEntry->PartType == PARTITION_IFS)
353 PartType = "NTFS"; /* FIXME: Not quite correct! */
357 PartType = "Unknown";
360 if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */
362 PartSize = (PartEntry->PartSize + (1 << 29)) >> 30;
365 else if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */
367 PartSize = (PartEntry->PartSize + (1 << 19)) >> 20;
372 PartSize = (PartEntry->PartSize + (1 << 9)) >> 10;
376 if (PartEntry->DriveLetter != (CHAR)0)
379 "%c: %d: nr: %d type: %x (%s) %I64u %s",
380 PartEntry->DriveLetter,
382 PartEntry->PartNumber,
391 " %d: nr: %d type: %x (%s) %I64u %s",
393 PartEntry->PartNumber,
400 Attribute = (List->CurrentDisk == DiskIndex &&
401 List->CurrentPartition == PartIndex) ? 0x71 : 0x17;
403 FillConsoleOutputCharacter(' ',
410 FillConsoleOutputAttribute(Attribute,
417 WriteConsoleOutputCharacters(LineBuffer,
418 min(strlen(LineBuffer), Width),
426 PrintDiskData(PPARTLIST List,
429 PDISKENTRY DiskEntry;
430 CHAR LineBuffer[128];
440 DiskEntry = &List->DiskArray[DiskIndex];
442 Width = List->Right - List->Left - 1;
443 Height = List->Bottom - List->Top - 1;
445 if (List->Line < 0 || List->Line > Height)
448 coPos.X = List->Left + 1;
449 coPos.Y = List->Top + 1 + List->Line;
451 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
453 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
456 else if (DiskEntry->DiskSize >= 0xA00000ULL) /* 10 MB */
458 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
463 DiskSize = (DiskEntry->DiskSize + (1 << 9)) >> 10;
468 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
471 DiskEntry->DiskNumber,
476 FillConsoleOutputAttribute(0x17,
481 FillConsoleOutputCharacter(' ',
487 WriteConsoleOutputCharacters(LineBuffer,
488 min(strlen(LineBuffer), Width - 2),
493 /* Print separator line */
494 PrintEmptyLine(List);
499 /* Print partition lines*/
500 for (PartIndex = 0; PartIndex < List->DiskArray[DiskIndex].PartCount; PartIndex++)
502 if (List->DiskArray[DiskIndex].PartArray[PartIndex].Used == TRUE)
504 PrintPartitionData(List,
511 /* Print separator line */
512 if (PartPrinted == TRUE)
514 PrintEmptyLine(List);
520 DrawPartitionList(PPARTLIST List)
522 CHAR LineBuffer[128];
528 /* draw upper left corner */
529 coPos.X = List->Left;
531 FillConsoleOutputCharacter(0xDA, // '+',
536 /* draw upper edge */
537 coPos.X = List->Left + 1;
539 FillConsoleOutputCharacter(0xC4, // '-',
540 List->Right - List->Left - 1,
544 /* draw upper right corner */
545 coPos.X = List->Right;
547 FillConsoleOutputCharacter(0xBF, // '+',
552 /* draw left and right edge */
553 for (i = List->Top + 1; i < List->Bottom; i++)
555 coPos.X = List->Left;
557 FillConsoleOutputCharacter(0xB3, // '|',
562 coPos.X = List->Right;
563 FillConsoleOutputCharacter(0xB3, //'|',
569 /* draw lower left corner */
570 coPos.X = List->Left;
571 coPos.Y = List->Bottom;
572 FillConsoleOutputCharacter(0xC0, // '+',
577 /* draw lower edge */
578 coPos.X = List->Left + 1;
579 coPos.Y = List->Bottom;
580 FillConsoleOutputCharacter(0xC4, // '-',
581 List->Right - List->Left - 1,
585 /* draw upper right corner */
586 coPos.X = List->Right;
587 coPos.Y = List->Bottom;
588 FillConsoleOutputCharacter(0xD9, // '+',
593 /* print list entries */
595 for (DiskIndex = 0; DiskIndex < List->DiskCount; DiskIndex++)
597 if (List->DiskArray[DiskIndex].FixedDisk == TRUE)
599 /* Print disk entry */
608 ScrollDownPartitionList(PPARTLIST List)
613 /* check for available disks */
614 if (List->DiskCount == 0)
617 /* check for next usable entry on current disk */
618 for (i = List->CurrentPartition + 1; i < List->DiskArray[List->CurrentDisk].PartCount; i++)
620 if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
622 List->CurrentPartition = i;
623 DrawPartitionList(List);
628 /* check for first usable entry on next disk */
629 for (j = List->CurrentDisk + 1; j < List->DiskCount; j++)
631 for (i = 0; i < List->DiskArray[j].PartCount; i++)
633 if (List->DiskArray[j].PartArray[i].Used == TRUE)
635 List->CurrentDisk = j;
636 List->CurrentPartition = i;
637 DrawPartitionList(List);
646 ScrollUpPartitionList(PPARTLIST List)
651 /* check for available disks */
652 if (List->DiskCount == 0)
655 /* check for previous usable entry on current disk */
656 for (i = List->CurrentPartition - 1; i != (ULONG)-1; i--)
658 if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
660 List->CurrentPartition = i;
661 DrawPartitionList(List);
666 /* check for last usable entry on previous disk */
667 for (j = List->CurrentDisk - 1; j != (ULONG)-1; j--)
669 for (i = List->DiskArray[j].PartCount - 1; i != (ULONG)-1; i--)
671 if (List->DiskArray[j].PartArray[i].Used == TRUE)
673 List->CurrentDisk = j;
674 List->CurrentPartition = i;
675 DrawPartitionList(List);
684 GetPartitionData(PPARTLIST List,
687 if (List->CurrentDisk >= List->DiskCount)
690 if (List->DiskArray[List->CurrentDisk].FixedDisk == FALSE)
693 if (List->CurrentPartition >= List->DiskArray[List->CurrentDisk].PartCount)
696 if (List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].Used == FALSE)
699 Data->DiskSize = List->DiskArray[List->CurrentDisk].DiskSize;
700 Data->DiskNumber = List->DiskArray[List->CurrentDisk].DiskNumber;
701 Data->Port = List->DiskArray[List->CurrentDisk].Port;
702 Data->Bus = List->DiskArray[List->CurrentDisk].Bus;
703 Data->Id = List->DiskArray[List->CurrentDisk].Id;
705 Data->PartSize = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].PartSize;
706 Data->PartNumber = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].PartNumber;
707 Data->PartType = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].PartType;
709 Data->DriveLetter = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].DriveLetter;