[SETUPLIB] Improve the bootloader 'validity' checks -- Addendum to f06734e5 (r74512).
[reactos.git] / base / setup / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: base/setup/usetup/partlist.c
22 * PURPOSE: Partition list functions
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 */
25
26 #include "usetup.h"
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /* HELPERS FOR PARTITION TYPES **********************************************/
32
33 typedef struct _PARTITION_TYPE
34 {
35 UCHAR Type;
36 PCHAR Description;
37 } PARTITION_TYPE, *PPARTITION_TYPE;
38
39 /*
40 * This partition type list was ripped off the kernelDisk.c module from:
41 *
42 * Visopsys Operating System
43 * Copyright (C) 1998-2015 J. Andrew McLaughlin
44 *
45 * This program is free software; you can redistribute it and/or modify it
46 * under the terms of the GNU General Public License as published by the Free
47 * Software Foundation; either version 2 of the License, or (at your option)
48 * any later version.
49 *
50 * This program is distributed in the hope that it will be useful, but
51 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
52 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
53 * for more details.
54 *
55 * You should have received a copy of the GNU General Public License along
56 * with this program; if not, write to the Free Software Foundation, Inc.,
57 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
58 *
59 *
60 * See also https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
61 * and http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
62 * for a complete list.
63 */
64
65 /* This is a table for keeping known partition type codes and descriptions */
66 static PARTITION_TYPE PartitionTypes[] =
67 {
68 { 0x00, "(Empty)" },
69 { 0x01, "FAT12" },
70 { 0x02, "XENIX root" },
71 { 0x03, "XENIX /usr" },
72 { 0x04, "FAT16 (small)" },
73 { 0x05, "Extended" },
74 { 0x06, "FAT16" },
75 { 0x07, "NTFS/HPFS/exFAT" },
76 { 0x08, "OS/2 or AIX boot" },
77 { 0x09, "AIX data" },
78 { 0x0A, "OS/2 Boot Manager" },
79 { 0x0B, "FAT32" },
80 { 0x0C, "FAT32 (LBA)" },
81 { 0x0E, "FAT16 (LBA)" },
82 { 0x0F, "Extended (LBA)" },
83 { 0x11, "Hidden FAT12" },
84 { 0x12, "FAT diagnostic" },
85 { 0x14, "Hidden FAT16 (small)" },
86 { 0x16, "Hidden FAT16" },
87 { 0x17, "Hidden HPFS or NTFS" },
88 { 0x1B, "Hidden FAT32" },
89 { 0x1C, "Hidden FAT32 (LBA)" },
90 { 0x1E, "Hidden FAT16 (LBA)" },
91 { 0x35, "JFS" },
92 { 0x39, "Plan 9" },
93 { 0x3C, "PartitionMagic" },
94 { 0x3D, "Hidden Netware" },
95 { 0x41, "PowerPC PReP" },
96 { 0x42, "Win2K dynamic extended" },
97 { 0x43, "Old Linux" },
98 { 0x44, "GoBack" },
99 { 0x4D, "QNX4.x" },
100 { 0x4D, "QNX4.x 2nd" },
101 { 0x4D, "QNX4.x 3rd" },
102 { 0x50, "Ontrack R/O" },
103 { 0x51, "Ontrack R/W or Novell" },
104 { 0x52, "CP/M" },
105 { 0x63, "GNU HURD or UNIX SysV" },
106 { 0x64, "Netware 2" },
107 { 0x65, "Netware 3/4" },
108 { 0x66, "Netware SMS" },
109 { 0x67, "Novell" },
110 { 0x68, "Novell" },
111 { 0x69, "Netware 5+" },
112 { 0x7E, "Veritas VxVM public" },
113 { 0x7F, "Veritas VxVM private" },
114 { 0x80, "Minix" },
115 { 0x81, "Linux or Minix" },
116 { 0x82, "Linux swap or Solaris" },
117 { 0x83, "Linux" },
118 { 0x84, "Hibernation" },
119 { 0x85, "Linux extended" },
120 { 0x86, "HPFS or NTFS mirrored" },
121 { 0x87, "HPFS or NTFS mirrored" },
122 { 0x8E, "Linux LVM" },
123 { 0x93, "Hidden Linux" },
124 { 0x96, "CDFS/ISO-9660" },
125 { 0x9F, "BSD/OS" },
126 { 0xA0, "Laptop hibernation" },
127 { 0xA1, "Laptop hibernation" },
128 { 0xA5, "BSD, NetBSD, FreeBSD" },
129 { 0xA6, "OpenBSD" },
130 { 0xA7, "NeXTSTEP" },
131 { 0xA8, "OS-X UFS" },
132 { 0xA9, "NetBSD" },
133 { 0xAB, "OS-X boot" },
134 { 0xAF, "OS-X HFS" },
135 { 0xB6, "NT corrupt mirror" },
136 { 0xB7, "BSDI" },
137 { 0xB8, "BSDI swap" },
138 { 0xBE, "Solaris 8 boot" },
139 { 0xBF, "Solaris x86" },
140 { 0xC0, "NTFT" },
141 { 0xC1, "DR-DOS FAT12" },
142 { 0xC2, "Hidden Linux" },
143 { 0xC3, "Hidden Linux swap" },
144 { 0xC4, "DR-DOS FAT16 (small)" },
145 { 0xC5, "DR-DOS Extended" },
146 { 0xC6, "DR-DOS FAT16" },
147 { 0xC7, "HPFS mirrored" },
148 { 0xCB, "DR-DOS FAT32" },
149 { 0xCC, "DR-DOS FAT32 (LBA)" },
150 { 0xCE, "DR-DOS FAT16 (LBA)" },
151 { 0xD0, "MDOS" },
152 { 0xD1, "MDOS FAT12" },
153 { 0xD4, "MDOS FAT16 (small)" },
154 { 0xD5, "MDOS Extended" },
155 { 0xD6, "MDOS FAT16" },
156 { 0xD8, "CP/M-86" },
157 { 0xDF, "BootIt EMBRM(FAT16/32)" },
158 { 0xEB, "BeOS BFS" },
159 { 0xEE, "EFI GPT protective" },
160 { 0xEF, "EFI filesystem" },
161 { 0xF0, "Linux/PA-RISC boot" },
162 { 0xF2, "DOS 3.3+ second" },
163 { 0xFA, "Bochs" },
164 { 0xFB, "VmWare" },
165 { 0xFC, "VmWare swap" },
166 { 0xFD, "Linux RAID" },
167 { 0xFE, "NT hidden" },
168 };
169
170 VOID
171 GetPartTypeStringFromPartitionType(
172 IN UCHAR partitionType,
173 OUT PCHAR strPartType,
174 IN ULONG cchPartType)
175 {
176 /* Determine partition type */
177
178 if (IsContainerPartition(partitionType))
179 {
180 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
181 }
182 else if (partitionType == PARTITION_ENTRY_UNUSED)
183 {
184 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
185 }
186 else
187 {
188 UINT i;
189
190 /* Do the table lookup */
191 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
192 {
193 if (partitionType == PartitionTypes[i].Type)
194 {
195 RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
196 return;
197 }
198 }
199
200 /* We are here because the partition type is unknown */
201 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
202 }
203 }
204
205
206 /* FUNCTIONS ****************************************************************/
207
208 VOID
209 InitPartitionListUi(
210 IN OUT PPARTLIST_UI ListUi,
211 IN PPARTLIST List,
212 IN SHORT Left,
213 IN SHORT Top,
214 IN SHORT Right,
215 IN SHORT Bottom)
216 {
217 ListUi->List = List;
218 // ListUi->FirstShown = NULL;
219 // ListUi->LastShown = NULL;
220
221 ListUi->Left = Left;
222 ListUi->Top = Top;
223 ListUi->Right = Right;
224 ListUi->Bottom = Bottom;
225
226 ListUi->Line = 0;
227 ListUi->Offset = 0;
228
229 // ListUi->Redraw = TRUE;
230 }
231
232 static
233 VOID
234 PrintEmptyLine(
235 IN PPARTLIST_UI ListUi)
236 {
237 COORD coPos;
238 ULONG Written;
239 USHORT Width;
240 USHORT Height;
241
242 Width = ListUi->Right - ListUi->Left - 1;
243 Height = ListUi->Bottom - ListUi->Top - 2;
244
245 coPos.X = ListUi->Left + 1;
246 coPos.Y = ListUi->Top + 1 + ListUi->Line;
247
248 if (ListUi->Line >= 0 && ListUi->Line <= Height)
249 {
250 FillConsoleOutputAttribute(StdOutput,
251 FOREGROUND_WHITE | BACKGROUND_BLUE,
252 Width,
253 coPos,
254 &Written);
255
256 FillConsoleOutputCharacterA(StdOutput,
257 ' ',
258 Width,
259 coPos,
260 &Written);
261 }
262
263 ListUi->Line++;
264 }
265
266 static
267 VOID
268 PrintPartitionData(
269 IN PPARTLIST_UI ListUi,
270 IN PDISKENTRY DiskEntry,
271 IN PPARTENTRY PartEntry)
272 {
273 PPARTLIST List = ListUi->List;
274 CHAR LineBuffer[128];
275 COORD coPos;
276 ULONG Written;
277 USHORT Width;
278 USHORT Height;
279 LARGE_INTEGER PartSize;
280 PCHAR Unit;
281 UCHAR Attribute;
282 CHAR PartTypeString[32];
283 PCHAR PartType = PartTypeString;
284
285 Width = ListUi->Right - ListUi->Left - 1;
286 Height = ListUi->Bottom - ListUi->Top - 2;
287
288 coPos.X = ListUi->Left + 1;
289 coPos.Y = ListUi->Top + 1 + ListUi->Line;
290
291 if (PartEntry->IsPartitioned == FALSE)
292 {
293 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
294 #if 0
295 if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
296 {
297 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
298 Unit = MUIGetString(STRING_GB);
299 }
300 else
301 #endif
302 if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
303 {
304 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
305 Unit = MUIGetString(STRING_MB);
306 }
307 else
308 {
309 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
310 Unit = MUIGetString(STRING_KB);
311 }
312
313 sprintf(LineBuffer,
314 MUIGetString(STRING_UNPSPACE),
315 PartEntry->LogicalPartition ? " " : "",
316 PartEntry->LogicalPartition ? "" : " ",
317 PartSize.u.LowPart,
318 Unit);
319 }
320 else
321 {
322 /* Determine partition type */
323 PartTypeString[0] = '\0';
324 if (PartEntry->New != FALSE)
325 {
326 PartType = MUIGetString(STRING_UNFORMATTED);
327 }
328 else if (PartEntry->IsPartitioned != FALSE)
329 {
330 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
331 PartTypeString,
332 ARRAYSIZE(PartTypeString));
333 PartType = PartTypeString;
334 }
335
336 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
337 #if 0
338 if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
339 {
340 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
341 Unit = MUIGetString(STRING_GB);
342 }
343 else
344 #endif
345 if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
346 {
347 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
348 Unit = MUIGetString(STRING_MB);
349 }
350 else
351 {
352 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
353 Unit = MUIGetString(STRING_KB);
354 }
355
356 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
357 {
358 sprintf(LineBuffer,
359 MUIGetString(STRING_HDDINFOUNK5),
360 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
361 (PartEntry->DriveLetter == 0) ? '-' : ':',
362 PartEntry->BootIndicator ? '*' : ' ',
363 PartEntry->LogicalPartition ? " " : "",
364 PartEntry->PartitionType,
365 PartEntry->LogicalPartition ? "" : " ",
366 PartSize.u.LowPart,
367 Unit);
368 }
369 else
370 {
371 sprintf(LineBuffer,
372 "%c%c %c %s%-24s%s %6lu %s",
373 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
374 (PartEntry->DriveLetter == 0) ? '-' : ':',
375 PartEntry->BootIndicator ? '*' : ' ',
376 PartEntry->LogicalPartition ? " " : "",
377 PartType,
378 PartEntry->LogicalPartition ? "" : " ",
379 PartSize.u.LowPart,
380 Unit);
381 }
382 }
383
384 Attribute = (List->CurrentDisk == DiskEntry &&
385 List->CurrentPartition == PartEntry) ?
386 FOREGROUND_BLUE | BACKGROUND_WHITE :
387 FOREGROUND_WHITE | BACKGROUND_BLUE;
388
389 if (ListUi->Line >= 0 && ListUi->Line <= Height)
390 {
391 FillConsoleOutputCharacterA(StdOutput,
392 ' ',
393 Width,
394 coPos,
395 &Written);
396 }
397 coPos.X += 4;
398 Width -= 8;
399 if (ListUi->Line >= 0 && ListUi->Line <= Height)
400 {
401 FillConsoleOutputAttribute(StdOutput,
402 Attribute,
403 Width,
404 coPos,
405 &Written);
406 }
407 coPos.X++;
408 Width -= 2;
409 if (ListUi->Line >= 0 && ListUi->Line <= Height)
410 {
411 WriteConsoleOutputCharacterA(StdOutput,
412 LineBuffer,
413 min(strlen(LineBuffer), Width),
414 coPos,
415 &Written);
416 }
417
418 ListUi->Line++;
419 }
420
421 static
422 VOID
423 PrintDiskData(
424 IN PPARTLIST_UI ListUi,
425 IN PDISKENTRY DiskEntry)
426 {
427 // PPARTLIST List = ListUi->List;
428 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
429 PLIST_ENTRY PrimaryEntry, LogicalEntry;
430 CHAR LineBuffer[128];
431 COORD coPos;
432 ULONG Written;
433 USHORT Width;
434 USHORT Height;
435 ULARGE_INTEGER DiskSize;
436 PCHAR Unit;
437
438 Width = ListUi->Right - ListUi->Left - 1;
439 Height = ListUi->Bottom - ListUi->Top - 2;
440
441 coPos.X = ListUi->Left + 1;
442 coPos.Y = ListUi->Top + 1 + ListUi->Line;
443
444 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
445 if (DiskSize.QuadPart >= 10 * GB) /* 10 GB */
446 {
447 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, GB);
448 Unit = MUIGetString(STRING_GB);
449 }
450 else
451 {
452 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, MB);
453 if (DiskSize.QuadPart == 0)
454 DiskSize.QuadPart = 1;
455 Unit = MUIGetString(STRING_MB);
456 }
457
458 if (DiskEntry->DriverName.Length > 0)
459 {
460 sprintf(LineBuffer,
461 MUIGetString(STRING_HDINFOPARTSELECT_1),
462 DiskSize.u.LowPart,
463 Unit,
464 DiskEntry->DiskNumber,
465 DiskEntry->Port,
466 DiskEntry->Bus,
467 DiskEntry->Id,
468 &DiskEntry->DriverName,
469 DiskEntry->NoMbr ? "GPT" : "MBR");
470 }
471 else
472 {
473 sprintf(LineBuffer,
474 MUIGetString(STRING_HDINFOPARTSELECT_2),
475 DiskSize.u.LowPart,
476 Unit,
477 DiskEntry->DiskNumber,
478 DiskEntry->Port,
479 DiskEntry->Bus,
480 DiskEntry->Id,
481 DiskEntry->NoMbr ? "GPT" : "MBR");
482 }
483
484 if (ListUi->Line >= 0 && ListUi->Line <= Height)
485 {
486 FillConsoleOutputAttribute(StdOutput,
487 FOREGROUND_WHITE | BACKGROUND_BLUE,
488 Width,
489 coPos,
490 &Written);
491
492 FillConsoleOutputCharacterA(StdOutput,
493 ' ',
494 Width,
495 coPos,
496 &Written);
497 }
498
499 coPos.X++;
500 if (ListUi->Line >= 0 && ListUi->Line <= Height)
501 {
502 WriteConsoleOutputCharacterA(StdOutput,
503 LineBuffer,
504 min((USHORT)strlen(LineBuffer), Width - 2),
505 coPos,
506 &Written);
507 }
508
509 ListUi->Line++;
510
511 /* Print separator line */
512 PrintEmptyLine(ListUi);
513
514 /* Print partition lines */
515 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
516 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
517 {
518 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
519
520 PrintPartitionData(ListUi,
521 DiskEntry,
522 PrimaryPartEntry);
523
524 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
525 {
526 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
527 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
528 {
529 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
530
531 PrintPartitionData(ListUi,
532 DiskEntry,
533 LogicalPartEntry);
534
535 LogicalEntry = LogicalEntry->Flink;
536 }
537 }
538
539 PrimaryEntry = PrimaryEntry->Flink;
540 }
541
542 /* Print separator line */
543 PrintEmptyLine(ListUi);
544 }
545
546 VOID
547 DrawPartitionList(
548 IN PPARTLIST_UI ListUi)
549 {
550 PPARTLIST List = ListUi->List;
551 PLIST_ENTRY Entry, Entry2;
552 PDISKENTRY DiskEntry;
553 PPARTENTRY PartEntry = NULL;
554 COORD coPos;
555 ULONG Written;
556 SHORT i;
557 SHORT CurrentDiskLine;
558 SHORT CurrentPartLine;
559 SHORT LastLine;
560 BOOLEAN CurrentPartLineFound = FALSE;
561 BOOLEAN CurrentDiskLineFound = FALSE;
562
563 /* Calculate the line of the current disk and partition */
564 CurrentDiskLine = 0;
565 CurrentPartLine = 0;
566 LastLine = 0;
567
568 Entry = List->DiskListHead.Flink;
569 while (Entry != &List->DiskListHead)
570 {
571 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
572
573 LastLine += 2;
574 if (CurrentPartLineFound == FALSE)
575 {
576 CurrentPartLine += 2;
577 }
578
579 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
580 while (Entry2 != &DiskEntry->PrimaryPartListHead)
581 {
582 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
583 if (PartEntry == List->CurrentPartition)
584 {
585 CurrentPartLineFound = TRUE;
586 }
587
588 Entry2 = Entry2->Flink;
589 if (CurrentPartLineFound == FALSE)
590 {
591 CurrentPartLine++;
592 }
593
594 LastLine++;
595 }
596
597 if (CurrentPartLineFound == FALSE)
598 {
599 Entry2 = DiskEntry->LogicalPartListHead.Flink;
600 while (Entry2 != &DiskEntry->LogicalPartListHead)
601 {
602 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
603 if (PartEntry == List->CurrentPartition)
604 {
605 CurrentPartLineFound = TRUE;
606 }
607
608 Entry2 = Entry2->Flink;
609 if (CurrentPartLineFound == FALSE)
610 {
611 CurrentPartLine++;
612 }
613
614 LastLine++;
615 }
616 }
617
618 if (DiskEntry == List->CurrentDisk)
619 {
620 CurrentDiskLineFound = TRUE;
621 }
622
623 Entry = Entry->Flink;
624 if (Entry != &List->DiskListHead)
625 {
626 if (CurrentDiskLineFound == FALSE)
627 {
628 CurrentPartLine ++;
629 CurrentDiskLine = CurrentPartLine;
630 }
631
632 LastLine++;
633 }
634 else
635 {
636 LastLine--;
637 }
638 }
639
640 /* If it possible, make the disk name visible */
641 if (CurrentPartLine < ListUi->Offset)
642 {
643 ListUi->Offset = CurrentPartLine;
644 }
645 else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
646 {
647 ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
648 }
649
650 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
651 {
652 ListUi->Offset = CurrentDiskLine;
653 }
654
655 /* Draw upper left corner */
656 coPos.X = ListUi->Left;
657 coPos.Y = ListUi->Top;
658 FillConsoleOutputCharacterA(StdOutput,
659 0xDA, // '+',
660 1,
661 coPos,
662 &Written);
663
664 /* Draw upper edge */
665 coPos.X = ListUi->Left + 1;
666 coPos.Y = ListUi->Top;
667 if (ListUi->Offset == 0)
668 {
669 FillConsoleOutputCharacterA(StdOutput,
670 0xC4, // '-',
671 ListUi->Right - ListUi->Left - 1,
672 coPos,
673 &Written);
674 }
675 else
676 {
677 FillConsoleOutputCharacterA(StdOutput,
678 0xC4, // '-',
679 ListUi->Right - ListUi->Left - 5,
680 coPos,
681 &Written);
682 coPos.X = ListUi->Right - 5;
683 WriteConsoleOutputCharacterA(StdOutput,
684 "(\x18)", // "(up)"
685 3,
686 coPos,
687 &Written);
688 coPos.X = ListUi->Right - 2;
689 FillConsoleOutputCharacterA(StdOutput,
690 0xC4, // '-',
691 2,
692 coPos,
693 &Written);
694 }
695
696 /* Draw upper right corner */
697 coPos.X = ListUi->Right;
698 coPos.Y = ListUi->Top;
699 FillConsoleOutputCharacterA(StdOutput,
700 0xBF, // '+',
701 1,
702 coPos,
703 &Written);
704
705 /* Draw left and right edge */
706 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
707 {
708 coPos.X = ListUi->Left;
709 coPos.Y = i;
710 FillConsoleOutputCharacterA(StdOutput,
711 0xB3, // '|',
712 1,
713 coPos,
714 &Written);
715
716 coPos.X = ListUi->Right;
717 FillConsoleOutputCharacterA(StdOutput,
718 0xB3, //'|',
719 1,
720 coPos,
721 &Written);
722 }
723
724 /* Draw lower left corner */
725 coPos.X = ListUi->Left;
726 coPos.Y = ListUi->Bottom;
727 FillConsoleOutputCharacterA(StdOutput,
728 0xC0, // '+',
729 1,
730 coPos,
731 &Written);
732
733 /* Draw lower edge */
734 coPos.X = ListUi->Left + 1;
735 coPos.Y = ListUi->Bottom;
736 if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
737 {
738 FillConsoleOutputCharacterA(StdOutput,
739 0xC4, // '-',
740 ListUi->Right - ListUi->Left - 1,
741 coPos,
742 &Written);
743 }
744 else
745 {
746 FillConsoleOutputCharacterA(StdOutput,
747 0xC4, // '-',
748 ListUi->Right - ListUi->Left - 5,
749 coPos,
750 &Written);
751 coPos.X = ListUi->Right - 5;
752 WriteConsoleOutputCharacterA(StdOutput,
753 "(\x19)", // "(down)"
754 3,
755 coPos,
756 &Written);
757 coPos.X = ListUi->Right - 2;
758 FillConsoleOutputCharacterA(StdOutput,
759 0xC4, // '-',
760 2,
761 coPos,
762 &Written);
763 }
764
765 /* Draw lower right corner */
766 coPos.X = ListUi->Right;
767 coPos.Y = ListUi->Bottom;
768 FillConsoleOutputCharacterA(StdOutput,
769 0xD9, // '+',
770 1,
771 coPos,
772 &Written);
773
774 /* print list entries */
775 ListUi->Line = - ListUi->Offset;
776
777 Entry = List->DiskListHead.Flink;
778 while (Entry != &List->DiskListHead)
779 {
780 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
781
782 /* Print disk entry */
783 PrintDiskData(ListUi, DiskEntry);
784
785 Entry = Entry->Flink;
786 }
787 }
788
789 VOID
790 ScrollDownPartitionList(
791 IN PPARTLIST_UI ListUi)
792 {
793 if (GetNextPartition(ListUi->List))
794 DrawPartitionList(ListUi);
795 }
796
797 VOID
798 ScrollUpPartitionList(
799 IN PPARTLIST_UI ListUi)
800 {
801 if (GetPrevPartition(ListUi->List))
802 DrawPartitionList(ListUi);
803 }
804
805 /* EOF */