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>
39 /* FUNCTIONS ****************************************************************/
42 CreatePartitionList(SHORT Left
,
48 OBJECT_ATTRIBUTES ObjectAttributes
;
49 SYSTEM_DEVICE_INFORMATION Sdi
;
50 DISK_GEOMETRY DiskGeometry
;
55 WCHAR Buffer
[MAX_PATH
];
58 DRIVE_LAYOUT_INFORMATION
*LayoutBuffer
;
59 SCSI_ADDRESS ScsiAddress
;
62 List
= (PPARTLIST
)RtlAllocateHeap(ProcessHeap
, 0, sizeof(PARTLIST
));
69 List
->Bottom
= Bottom
;
73 List
->TopDisk
= (ULONG
)-1;
74 List
->TopPartition
= (ULONG
)-1;
76 List
->CurrentDisk
= (ULONG
)-1;
77 List
->CurrentPartition
= (ULONG
)-1;
80 List
->DiskArray
= NULL
;
83 Status
= NtQuerySystemInformation(SystemDeviceInformation
,
85 sizeof(SYSTEM_DEVICE_INFORMATION
),
87 if (!NT_SUCCESS(Status
))
89 RtlFreeHeap(ProcessHeap
, 0, List
);
93 List
->DiskArray
= (PDISKENTRY
)RtlAllocateHeap(ProcessHeap
,
95 Sdi
.NumberOfDisks
* sizeof(DISKENTRY
));
96 List
->DiskCount
= Sdi
.NumberOfDisks
;
98 for (DiskCount
= 0; DiskCount
< Sdi
.NumberOfDisks
; DiskCount
++)
101 L
"\\Device\\Harddisk%d\\Partition0",
103 RtlInitUnicodeString(&Name
,
106 InitializeObjectAttributes(&ObjectAttributes
,
112 Status
= NtOpenFile(&FileHandle
,
117 FILE_SYNCHRONOUS_IO_NONALERT
);
118 if (NT_SUCCESS(Status
))
120 Status
= NtDeviceIoControlFile(FileHandle
,
125 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
129 sizeof(DISK_GEOMETRY
));
130 if (NT_SUCCESS(Status
))
132 if (DiskGeometry
.MediaType
== FixedMedia
)
134 Status
= NtDeviceIoControlFile(FileHandle
,
139 IOCTL_SCSI_GET_ADDRESS
,
143 sizeof(SCSI_ADDRESS
));
146 List
->DiskArray
[DiskCount
].DiskSize
=
147 DiskGeometry
.Cylinders
.QuadPart
*
148 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
149 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
150 (ULONGLONG
)DiskGeometry
.BytesPerSector
;
151 List
->DiskArray
[DiskCount
].DiskNumber
= DiskCount
;
152 List
->DiskArray
[DiskCount
].Port
= ScsiAddress
.PortNumber
;
153 List
->DiskArray
[DiskCount
].Bus
= ScsiAddress
.PathId
;
154 List
->DiskArray
[DiskCount
].Id
= ScsiAddress
.TargetId
;
156 List
->DiskArray
[DiskCount
].FixedDisk
= TRUE
;
159 LayoutBuffer
= (DRIVE_LAYOUT_INFORMATION
*)RtlAllocateHeap(ProcessHeap
, 0, 8192);
161 Status
= NtDeviceIoControlFile(FileHandle
,
166 IOCTL_DISK_GET_DRIVE_LAYOUT
,
171 if (NT_SUCCESS(Status
))
174 List
->DiskArray
[DiskCount
].PartArray
= (PPARTENTRY
)RtlAllocateHeap(ProcessHeap
,
176 LayoutBuffer
->PartitionCount
* sizeof(PARTENTRY
));
177 List
->DiskArray
[DiskCount
].PartCount
= LayoutBuffer
->PartitionCount
;
179 for (i
= 0; i
< LayoutBuffer
->PartitionCount
; i
++)
181 if ((LayoutBuffer
->PartitionEntry
[i
].PartitionType
!= PARTITION_ENTRY_UNUSED
) &&
182 !IsContainerPartition(LayoutBuffer
->PartitionEntry
[i
].PartitionType
))
184 List
->DiskArray
[DiskCount
].PartArray
[i
].PartSize
= LayoutBuffer
->PartitionEntry
[i
].PartitionLength
.QuadPart
;
185 List
->DiskArray
[DiskCount
].PartArray
[i
].PartNumber
= LayoutBuffer
->PartitionEntry
[i
].PartitionNumber
,
186 List
->DiskArray
[DiskCount
].PartArray
[i
].PartType
= LayoutBuffer
->PartitionEntry
[i
].PartitionType
;
187 List
->DiskArray
[DiskCount
].PartArray
[i
].Used
= TRUE
;
191 List
->DiskArray
[DiskCount
].PartArray
[i
].Used
= FALSE
;
196 RtlFreeHeap(ProcessHeap
, 0, LayoutBuffer
);
200 /* mark removable disk entry */
201 List
->DiskArray
[DiskCount
].FixedDisk
= FALSE
;
202 List
->DiskArray
[DiskCount
].PartCount
= 0;
203 List
->DiskArray
[DiskCount
].PartArray
= NULL
;
212 List
->TopPartition
= 0;
214 /* FIXME: search for first usable disk and partition */
215 List
->CurrentDisk
= 0;
216 List
->CurrentPartition
= 0;
218 DrawPartitionList(List
);
225 DestroyPartitionList(PPARTLIST List
)
232 /* clear occupied screen area */
233 coPos
.X
= List
->Left
;
234 Width
= List
->Right
- List
->Left
+ 1;
235 for (coPos
.Y
= List
->Top
; coPos
.Y
<= List
->Bottom
; coPos
.Y
++)
237 FillConsoleOutputAttribute(0x17,
242 FillConsoleOutputCharacter(' ',
249 /* free disk and partition info */
250 if (List
->DiskArray
!= NULL
)
252 /* free partition arrays */
253 for (i
= 0; i
< List
->DiskCount
; i
++)
255 if (List
->DiskArray
[i
].PartArray
!= NULL
)
257 RtlFreeHeap(ProcessHeap
, 0, List
->DiskArray
[i
].PartArray
);
258 List
->DiskArray
[i
].PartCount
= 0;
259 List
->DiskArray
[i
].PartArray
= NULL
;
263 /* free disk array */
264 RtlFreeHeap(ProcessHeap
, 0, List
->DiskArray
);
266 List
->DiskArray
= NULL
;
270 RtlFreeHeap(ProcessHeap
, 0, List
);
275 PrintEmptyLine(PPARTLIST List
)
282 Width
= List
->Right
- List
->Left
- 1;
283 Height
= List
->Bottom
- List
->Top
- 1;
285 if (List
->Line
< 0 || List
->Line
> Height
)
288 coPos
.X
= List
->Left
+ 1;
289 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
291 FillConsoleOutputAttribute(0x17,
296 FillConsoleOutputCharacter(' ',
306 PrintPartitionData(PPARTLIST List
,
310 PPARTENTRY PartEntry
;
311 CHAR LineBuffer
[128];
323 Width
= List
->Right
- List
->Left
- 1;
324 Height
= List
->Bottom
- List
->Top
- 1;
326 if (List
->Line
< 0 || List
->Line
> Height
)
329 coPos
.X
= List
->Left
+ 1;
330 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
332 PartEntry
= &List
->DiskArray
[DiskIndex
].PartArray
[PartIndex
];
334 if ((PartEntry
->PartType
== PARTITION_FAT_12
) ||
335 (PartEntry
->PartType
== PARTITION_FAT_16
) ||
336 (PartEntry
->PartType
== PARTITION_HUGE
) ||
337 (PartEntry
->PartType
== PARTITION_XINT13
))
341 else if ((PartEntry
->PartType
== PARTITION_FAT32
) ||
342 (PartEntry
->PartType
== PARTITION_FAT32_XINT13
))
346 else if (PartEntry
->PartType
== PARTITION_IFS
)
348 PartType
= "NTFS"; /* FIXME: Not quite correct! */
352 PartType
= "Unknown";
355 if (PartEntry
->PartSize
>= 0x280000000ULL
) /* 10 GB */
357 PartSize
= (PartEntry
->PartSize
+ (1 << 29)) >> 30;
360 else if (PartEntry
->PartSize
>= 0xA00000ULL
) /* 10 MB */
362 PartSize
= (PartEntry
->PartSize
+ (1 << 19)) >> 20;
367 PartSize
= (PartEntry
->PartSize
+ (1 << 9)) >> 10;
372 "%d: nr: %d type: %x (%s) %I64u %s",
374 PartEntry
->PartNumber
,
381 Attribute
= (List
->CurrentDisk
== DiskIndex
&&
382 List
->CurrentPartition
== PartIndex
) ? 0x71 : 0x17;
384 FillConsoleOutputCharacter(' ',
391 FillConsoleOutputAttribute(Attribute
,
398 WriteConsoleOutputCharacters(LineBuffer
,
399 min(strlen(LineBuffer
), Width
),
407 PrintDiskData(PPARTLIST List
,
410 PDISKENTRY DiskEntry
;
411 CHAR LineBuffer
[128];
421 DiskEntry
= &List
->DiskArray
[DiskIndex
];
423 Width
= List
->Right
- List
->Left
- 1;
424 Height
= List
->Bottom
- List
->Top
- 1;
426 if (List
->Line
< 0 || List
->Line
> Height
)
429 coPos
.X
= List
->Left
+ 1;
430 coPos
.Y
= List
->Top
+ 1 + List
->Line
;
432 if (DiskEntry
->DiskSize
>= 0x280000000ULL
) /* 10 GB */
434 DiskSize
= (DiskEntry
->DiskSize
+ (1 << 29)) >> 30;
437 else if (DiskEntry
->DiskSize
>= 0xA00000ULL
) /* 10 MB */
439 DiskSize
= (DiskEntry
->DiskSize
+ (1 << 19)) >> 20;
444 DiskSize
= (DiskEntry
->DiskSize
+ (1 << 9)) >> 10;
449 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
452 DiskEntry
->DiskNumber
,
457 FillConsoleOutputAttribute(0x17,
462 FillConsoleOutputCharacter(' ',
468 WriteConsoleOutputCharacters(LineBuffer
,
469 min(strlen(LineBuffer
), Width
- 2),
474 /* Print separator line */
475 PrintEmptyLine(List
);
480 /* Print partition lines*/
481 for (PartIndex
= 0; PartIndex
< List
->DiskArray
[DiskIndex
].PartCount
; PartIndex
++)
483 if (List
->DiskArray
[DiskIndex
].PartArray
[PartIndex
].Used
== TRUE
)
485 PrintPartitionData(List
,
492 /* Print separator line */
493 if (PartPrinted
== TRUE
)
495 PrintEmptyLine(List
);
501 DrawPartitionList(PPARTLIST List
)
503 CHAR LineBuffer
[128];
509 /* draw upper left corner */
510 coPos
.X
= List
->Left
;
512 FillConsoleOutputCharacter(0xDA, // '+',
517 /* draw upper edge */
518 coPos
.X
= List
->Left
+ 1;
520 FillConsoleOutputCharacter(0xC4, // '-',
521 List
->Right
- List
->Left
- 1,
525 /* draw upper right corner */
526 coPos
.X
= List
->Right
;
528 FillConsoleOutputCharacter(0xBF, // '+',
533 /* draw left and right edge */
534 for (i
= List
->Top
+ 1; i
< List
->Bottom
; i
++)
536 coPos
.X
= List
->Left
;
538 FillConsoleOutputCharacter(0xB3, // '|',
543 coPos
.X
= List
->Right
;
544 FillConsoleOutputCharacter(0xB3, //'|',
550 /* draw lower left corner */
551 coPos
.X
= List
->Left
;
552 coPos
.Y
= List
->Bottom
;
553 FillConsoleOutputCharacter(0xC0, // '+',
558 /* draw lower edge */
559 coPos
.X
= List
->Left
+ 1;
560 coPos
.Y
= List
->Bottom
;
561 FillConsoleOutputCharacter(0xC4, // '-',
562 List
->Right
- List
->Left
- 1,
566 /* draw upper right corner */
567 coPos
.X
= List
->Right
;
568 coPos
.Y
= List
->Bottom
;
569 FillConsoleOutputCharacter(0xD9, // '+',
574 /* print list entries */
576 for (DiskIndex
= 0; DiskIndex
< List
->DiskCount
; DiskIndex
++)
578 if (List
->DiskArray
[DiskIndex
].FixedDisk
== TRUE
)
580 /* Print disk entry */
589 ScrollDownPartitionList(PPARTLIST List
)
594 /* check for available disks */
595 if (List
->DiskCount
== 0)
598 /* check for next usable entry on current disk */
599 for (i
= List
->CurrentPartition
+ 1; i
< List
->DiskArray
[List
->CurrentDisk
].PartCount
; i
++)
601 if (List
->DiskArray
[List
->CurrentDisk
].PartArray
[i
].Used
== TRUE
)
603 List
->CurrentPartition
= i
;
604 DrawPartitionList(List
);
609 /* check for first usable entry on next disk */
610 for (j
= List
->CurrentDisk
+ 1; j
< List
->DiskCount
; j
++)
612 for (i
= 0; i
< List
->DiskArray
[j
].PartCount
; i
++)
614 if (List
->DiskArray
[j
].PartArray
[i
].Used
== TRUE
)
616 List
->CurrentDisk
= j
;
617 List
->CurrentPartition
= i
;
618 DrawPartitionList(List
);
627 ScrollUpPartitionList(PPARTLIST List
)
632 /* check for available disks */
633 if (List
->DiskCount
== 0)
636 /* check for previous usable entry on current disk */
637 for (i
= List
->CurrentPartition
- 1; i
!= (ULONG
)-1; i
--)
639 if (List
->DiskArray
[List
->CurrentDisk
].PartArray
[i
].Used
== TRUE
)
641 List
->CurrentPartition
= i
;
642 DrawPartitionList(List
);
647 /* check for last usable entry on previous disk */
648 for (j
= List
->CurrentDisk
- 1; j
!= (ULONG
)-1; j
--)
650 for (i
= List
->DiskArray
[j
].PartCount
- 1; i
!= (ULONG
)-1; i
--)
652 if (List
->DiskArray
[j
].PartArray
[i
].Used
== TRUE
)
654 List
->CurrentDisk
= j
;
655 List
->CurrentPartition
= i
;
656 DrawPartitionList(List
);
665 GetPartitionData(PPARTLIST List
,
668 if (List
->CurrentDisk
>= List
->DiskCount
)
671 if (List
->DiskArray
[List
->CurrentDisk
].FixedDisk
== FALSE
)
674 if (List
->CurrentPartition
>= List
->DiskArray
[List
->CurrentDisk
].PartCount
)
677 if (List
->DiskArray
[List
->CurrentDisk
].PartArray
[List
->CurrentPartition
].Used
== FALSE
)
680 Data
->DiskSize
= List
->DiskArray
[List
->CurrentDisk
].DiskSize
;
681 Data
->DiskNumber
= List
->DiskArray
[List
->CurrentDisk
].DiskNumber
;
682 Data
->Port
= List
->DiskArray
[List
->CurrentDisk
].Port
;
683 Data
->Bus
= List
->DiskArray
[List
->CurrentDisk
].Bus
;
684 Data
->Id
= List
->DiskArray
[List
->CurrentDisk
].Id
;
686 Data
->PartSize
= List
->DiskArray
[List
->CurrentDisk
].PartArray
[List
->CurrentPartition
].PartSize
;
687 Data
->PartNumber
= List
->DiskArray
[List
->CurrentDisk
].PartArray
[List
->CurrentPartition
].PartNumber
;
688 Data
->PartType
= List
->DiskArray
[List
->CurrentDisk
].PartArray
[List
->CurrentPartition
].PartType
;