xref: /reactos/base/setup/usetup/partlist.c (revision a6726659)
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 VOID
34 GetPartTypeStringFromPartitionType(
35     IN UCHAR partitionType,
36     OUT PCHAR strPartType,
37     IN ULONG cchPartType)
38 {
39     /* Determine partition type */
40 
41     if (IsContainerPartition(partitionType))
42     {
43         RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
44     }
45     else if (partitionType == PARTITION_ENTRY_UNUSED)
46     {
47         RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
48     }
49     else
50     {
51         UINT i;
52 
53         /* Do the table lookup */
54         for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
55         {
56             if (partitionType == PartitionTypes[i].Type)
57             {
58                 RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
59                 return;
60             }
61         }
62 
63         /* We are here because the partition type is unknown */
64         RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
65     }
66 }
67 
68 
69 /* FUNCTIONS ****************************************************************/
70 
71 VOID
72 InitPartitionListUi(
73     IN OUT PPARTLIST_UI ListUi,
74     IN PPARTLIST List,
75     IN SHORT Left,
76     IN SHORT Top,
77     IN SHORT Right,
78     IN SHORT Bottom)
79 {
80     ListUi->List = List;
81     // ListUi->FirstShown = NULL;
82     // ListUi->LastShown = NULL;
83 
84     ListUi->Left = Left;
85     ListUi->Top = Top;
86     ListUi->Right = Right;
87     ListUi->Bottom = Bottom;
88 
89     ListUi->Line = 0;
90     ListUi->Offset = 0;
91 
92     // ListUi->Redraw = TRUE;
93 }
94 
95 static
96 VOID
97 PrintEmptyLine(
98     IN PPARTLIST_UI ListUi)
99 {
100     COORD coPos;
101     ULONG Written;
102     USHORT Width;
103     USHORT Height;
104 
105     Width = ListUi->Right - ListUi->Left - 1;
106     Height = ListUi->Bottom - ListUi->Top - 2;
107 
108     coPos.X = ListUi->Left + 1;
109     coPos.Y = ListUi->Top + 1 + ListUi->Line;
110 
111     if (ListUi->Line >= 0 && ListUi->Line <= Height)
112     {
113         FillConsoleOutputAttribute(StdOutput,
114                                    FOREGROUND_WHITE | BACKGROUND_BLUE,
115                                    Width,
116                                    coPos,
117                                    &Written);
118 
119         FillConsoleOutputCharacterA(StdOutput,
120                                     ' ',
121                                     Width,
122                                     coPos,
123                                     &Written);
124     }
125 
126     ListUi->Line++;
127 }
128 
129 static
130 VOID
131 PrintPartitionData(
132     IN PPARTLIST_UI ListUi,
133     IN PDISKENTRY DiskEntry,
134     IN PPARTENTRY PartEntry)
135 {
136     PPARTLIST List = ListUi->List;
137     CHAR LineBuffer[128];
138     COORD coPos;
139     ULONG Written;
140     USHORT Width;
141     USHORT Height;
142     LARGE_INTEGER PartSize;
143     PCHAR Unit;
144     UCHAR Attribute;
145     CHAR PartTypeString[32];
146     PCHAR PartType = PartTypeString;
147 
148     Width = ListUi->Right - ListUi->Left - 1;
149     Height = ListUi->Bottom - ListUi->Top - 2;
150 
151     coPos.X = ListUi->Left + 1;
152     coPos.Y = ListUi->Top + 1 + ListUi->Line;
153 
154     /* Get the partition size */
155     PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
156 #if 0
157     if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
158     {
159         PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
160         Unit = MUIGetString(STRING_GB);
161     }
162     else
163 #endif
164     if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
165     {
166         PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
167         Unit = MUIGetString(STRING_MB);
168     }
169     else
170     {
171         PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
172         Unit = MUIGetString(STRING_KB);
173     }
174 
175     if (PartEntry->IsPartitioned == FALSE)
176     {
177         sprintf(LineBuffer,
178                 MUIGetString(STRING_UNPSPACE),
179                 PartEntry->LogicalPartition ? "  " : "",
180                 PartEntry->LogicalPartition ? "" : "  ",
181                 PartSize.u.LowPart,
182                 Unit);
183     }
184     else
185     {
186         /* Determine partition type */
187         PartTypeString[0] = '\0';
188         if (PartEntry->New != FALSE)
189         {
190             PartType = MUIGetString(STRING_UNFORMATTED);
191         }
192         else if (PartEntry->IsPartitioned != FALSE)
193         {
194             GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
195                                                PartTypeString,
196                                                ARRAYSIZE(PartTypeString));
197             PartType = PartTypeString;
198         }
199 
200         if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
201         {
202             sprintf(LineBuffer,
203                     MUIGetString(STRING_HDDINFOUNK5),
204                     (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
205                     (PartEntry->DriveLetter == 0) ? '-' : ':',
206                     PartEntry->BootIndicator ? '*' : ' ',
207                     PartEntry->LogicalPartition ? "  " : "",
208                     PartEntry->PartitionType,
209                     PartEntry->LogicalPartition ? "" : "  ",
210                     PartSize.u.LowPart,
211                     Unit);
212         }
213         else
214         {
215             sprintf(LineBuffer,
216                     "%c%c %c %s%-24s%s     %6lu %s",
217                     (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
218                     (PartEntry->DriveLetter == 0) ? '-' : ':',
219                     PartEntry->BootIndicator ? '*' : ' ',
220                     PartEntry->LogicalPartition ? "  " : "",
221                     PartType,
222                     PartEntry->LogicalPartition ? "" : "  ",
223                     PartSize.u.LowPart,
224                     Unit);
225         }
226     }
227 
228     Attribute = (List->CurrentDisk == DiskEntry &&
229                  List->CurrentPartition == PartEntry) ?
230                  FOREGROUND_BLUE | BACKGROUND_WHITE :
231                  FOREGROUND_WHITE | BACKGROUND_BLUE;
232 
233     if (ListUi->Line >= 0 && ListUi->Line <= Height)
234     {
235         FillConsoleOutputCharacterA(StdOutput,
236                                     ' ',
237                                     Width,
238                                     coPos,
239                                     &Written);
240     }
241     coPos.X += 4;
242     Width -= 8;
243     if (ListUi->Line >= 0 && ListUi->Line <= Height)
244     {
245         FillConsoleOutputAttribute(StdOutput,
246                                    Attribute,
247                                    Width,
248                                    coPos,
249                                    &Written);
250     }
251     coPos.X++;
252     Width -= 2;
253     if (ListUi->Line >= 0 && ListUi->Line <= Height)
254     {
255         WriteConsoleOutputCharacterA(StdOutput,
256                                      LineBuffer,
257                                      min(strlen(LineBuffer), Width),
258                                      coPos,
259                                      &Written);
260     }
261 
262     ListUi->Line++;
263 }
264 
265 static
266 VOID
267 PrintDiskData(
268     IN PPARTLIST_UI ListUi,
269     IN PDISKENTRY DiskEntry)
270 {
271     // PPARTLIST List = ListUi->List;
272     PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
273     PLIST_ENTRY PrimaryEntry, LogicalEntry;
274     CHAR LineBuffer[128];
275     COORD coPos;
276     ULONG Written;
277     USHORT Width;
278     USHORT Height;
279     ULARGE_INTEGER DiskSize;
280     PCHAR Unit;
281 
282     Width = ListUi->Right - ListUi->Left - 1;
283     Height = ListUi->Bottom - ListUi->Top - 2;
284 
285     coPos.X = ListUi->Left + 1;
286     coPos.Y = ListUi->Top + 1 + ListUi->Line;
287 
288     DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
289     if (DiskSize.QuadPart >= 10 * GB) /* 10 GB */
290     {
291         DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, GB);
292         Unit = MUIGetString(STRING_GB);
293     }
294     else
295     {
296         DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, MB);
297         if (DiskSize.QuadPart == 0)
298             DiskSize.QuadPart = 1;
299         Unit = MUIGetString(STRING_MB);
300     }
301 
302     //
303     // FIXME: We *MUST* use TXTSETUP.SIF strings from section "DiskDriverMap" !!
304     //
305     if (DiskEntry->DriverName.Length > 0)
306     {
307         sprintf(LineBuffer,
308                 MUIGetString(STRING_HDINFOPARTSELECT_1),
309                 DiskSize.u.LowPart,
310                 Unit,
311                 DiskEntry->DiskNumber,
312                 DiskEntry->Port,
313                 DiskEntry->Bus,
314                 DiskEntry->Id,
315                 &DiskEntry->DriverName,
316                 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
317                 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
318                                                               "RAW");
319     }
320     else
321     {
322         sprintf(LineBuffer,
323                 MUIGetString(STRING_HDINFOPARTSELECT_2),
324                 DiskSize.u.LowPart,
325                 Unit,
326                 DiskEntry->DiskNumber,
327                 DiskEntry->Port,
328                 DiskEntry->Bus,
329                 DiskEntry->Id,
330                 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
331                 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
332                                                               "RAW");
333     }
334 
335     if (ListUi->Line >= 0 && ListUi->Line <= Height)
336     {
337         FillConsoleOutputAttribute(StdOutput,
338                                    FOREGROUND_WHITE | BACKGROUND_BLUE,
339                                    Width,
340                                    coPos,
341                                    &Written);
342 
343         FillConsoleOutputCharacterA(StdOutput,
344                                     ' ',
345                                     Width,
346                                     coPos,
347                                     &Written);
348     }
349 
350     coPos.X++;
351     if (ListUi->Line >= 0 && ListUi->Line <= Height)
352     {
353         WriteConsoleOutputCharacterA(StdOutput,
354                                      LineBuffer,
355                                      min((USHORT)strlen(LineBuffer), Width - 2),
356                                      coPos,
357                                      &Written);
358     }
359 
360     ListUi->Line++;
361 
362     /* Print separator line */
363     PrintEmptyLine(ListUi);
364 
365     /* Print partition lines */
366     PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
367     while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
368     {
369         PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
370 
371         PrintPartitionData(ListUi,
372                            DiskEntry,
373                            PrimaryPartEntry);
374 
375         if (IsContainerPartition(PrimaryPartEntry->PartitionType))
376         {
377             LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
378             while (LogicalEntry != &DiskEntry->LogicalPartListHead)
379             {
380                 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
381 
382                 PrintPartitionData(ListUi,
383                                    DiskEntry,
384                                    LogicalPartEntry);
385 
386                 LogicalEntry = LogicalEntry->Flink;
387             }
388         }
389 
390         PrimaryEntry = PrimaryEntry->Flink;
391     }
392 
393     /* Print separator line */
394     PrintEmptyLine(ListUi);
395 }
396 
397 VOID
398 DrawPartitionList(
399     IN PPARTLIST_UI ListUi)
400 {
401     PPARTLIST List = ListUi->List;
402     PLIST_ENTRY Entry, Entry2;
403     PDISKENTRY DiskEntry;
404     PPARTENTRY PartEntry = NULL;
405     COORD coPos;
406     ULONG Written;
407     SHORT i;
408     SHORT CurrentDiskLine;
409     SHORT CurrentPartLine;
410     SHORT LastLine;
411     BOOLEAN CurrentPartLineFound = FALSE;
412     BOOLEAN CurrentDiskLineFound = FALSE;
413 
414     /* Calculate the line of the current disk and partition */
415     CurrentDiskLine = 0;
416     CurrentPartLine = 0;
417     LastLine = 0;
418 
419     Entry = List->DiskListHead.Flink;
420     while (Entry != &List->DiskListHead)
421     {
422         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
423 
424         LastLine += 2;
425         if (CurrentPartLineFound == FALSE)
426         {
427             CurrentPartLine += 2;
428         }
429 
430         Entry2 = DiskEntry->PrimaryPartListHead.Flink;
431         while (Entry2 != &DiskEntry->PrimaryPartListHead)
432         {
433             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
434             if (PartEntry == List->CurrentPartition)
435             {
436                 CurrentPartLineFound = TRUE;
437             }
438 
439             Entry2 = Entry2->Flink;
440             if (CurrentPartLineFound == FALSE)
441             {
442                 CurrentPartLine++;
443             }
444 
445             LastLine++;
446         }
447 
448         if (CurrentPartLineFound == FALSE)
449         {
450             Entry2 = DiskEntry->LogicalPartListHead.Flink;
451             while (Entry2 != &DiskEntry->LogicalPartListHead)
452             {
453                 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
454                 if (PartEntry == List->CurrentPartition)
455                 {
456                     CurrentPartLineFound = TRUE;
457                 }
458 
459                 Entry2 = Entry2->Flink;
460                 if (CurrentPartLineFound == FALSE)
461                 {
462                     CurrentPartLine++;
463                 }
464 
465                 LastLine++;
466             }
467         }
468 
469         if (DiskEntry == List->CurrentDisk)
470         {
471             CurrentDiskLineFound = TRUE;
472         }
473 
474         Entry = Entry->Flink;
475         if (Entry != &List->DiskListHead)
476         {
477             if (CurrentDiskLineFound == FALSE)
478             {
479                 CurrentPartLine ++;
480                 CurrentDiskLine = CurrentPartLine;
481             }
482 
483             LastLine++;
484         }
485         else
486         {
487             LastLine--;
488         }
489     }
490 
491     /* If it possible, make the disk name visible */
492     if (CurrentPartLine < ListUi->Offset)
493     {
494         ListUi->Offset = CurrentPartLine;
495     }
496     else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
497     {
498         ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
499     }
500 
501     if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
502     {
503         ListUi->Offset = CurrentDiskLine;
504     }
505 
506     /* Draw upper left corner */
507     coPos.X = ListUi->Left;
508     coPos.Y = ListUi->Top;
509     FillConsoleOutputCharacterA(StdOutput,
510                                 0xDA, // '+',
511                                 1,
512                                 coPos,
513                                 &Written);
514 
515     /* Draw upper edge */
516     coPos.X = ListUi->Left + 1;
517     coPos.Y = ListUi->Top;
518     if (ListUi->Offset == 0)
519     {
520         FillConsoleOutputCharacterA(StdOutput,
521                                     0xC4, // '-',
522                                     ListUi->Right - ListUi->Left - 1,
523                                     coPos,
524                                     &Written);
525     }
526     else
527     {
528         FillConsoleOutputCharacterA(StdOutput,
529                                     0xC4, // '-',
530                                     ListUi->Right - ListUi->Left - 5,
531                                     coPos,
532                                     &Written);
533         coPos.X = ListUi->Right - 5;
534         WriteConsoleOutputCharacterA(StdOutput,
535                                      "(\x18)", // "(up)"
536                                      3,
537                                      coPos,
538                                      &Written);
539         coPos.X = ListUi->Right - 2;
540         FillConsoleOutputCharacterA(StdOutput,
541                                     0xC4, // '-',
542                                     2,
543                                     coPos,
544                                     &Written);
545     }
546 
547     /* Draw upper right corner */
548     coPos.X = ListUi->Right;
549     coPos.Y = ListUi->Top;
550     FillConsoleOutputCharacterA(StdOutput,
551                                 0xBF, // '+',
552                                 1,
553                                 coPos,
554                                 &Written);
555 
556     /* Draw left and right edge */
557     for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
558     {
559         coPos.X = ListUi->Left;
560         coPos.Y = i;
561         FillConsoleOutputCharacterA(StdOutput,
562                                     0xB3, // '|',
563                                     1,
564                                     coPos,
565                                     &Written);
566 
567         coPos.X = ListUi->Right;
568         FillConsoleOutputCharacterA(StdOutput,
569                                     0xB3, //'|',
570                                     1,
571                                     coPos,
572                                     &Written);
573     }
574 
575     /* Draw lower left corner */
576     coPos.X = ListUi->Left;
577     coPos.Y = ListUi->Bottom;
578     FillConsoleOutputCharacterA(StdOutput,
579                                 0xC0, // '+',
580                                 1,
581                                 coPos,
582                                 &Written);
583 
584     /* Draw lower edge */
585     coPos.X = ListUi->Left + 1;
586     coPos.Y = ListUi->Bottom;
587     if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
588     {
589         FillConsoleOutputCharacterA(StdOutput,
590                                     0xC4, // '-',
591                                     ListUi->Right - ListUi->Left - 1,
592                                     coPos,
593                                     &Written);
594     }
595     else
596     {
597         FillConsoleOutputCharacterA(StdOutput,
598                                     0xC4, // '-',
599                                     ListUi->Right - ListUi->Left - 5,
600                                     coPos,
601                                     &Written);
602         coPos.X = ListUi->Right - 5;
603         WriteConsoleOutputCharacterA(StdOutput,
604                                      "(\x19)", // "(down)"
605                                      3,
606                                      coPos,
607                                      &Written);
608        coPos.X = ListUi->Right - 2;
609        FillConsoleOutputCharacterA(StdOutput,
610                                    0xC4, // '-',
611                                    2,
612                                    coPos,
613                                    &Written);
614     }
615 
616     /* Draw lower right corner */
617     coPos.X = ListUi->Right;
618     coPos.Y = ListUi->Bottom;
619     FillConsoleOutputCharacterA(StdOutput,
620                                 0xD9, // '+',
621                                 1,
622                                 coPos,
623                                 &Written);
624 
625     /* print list entries */
626     ListUi->Line = - ListUi->Offset;
627 
628     Entry = List->DiskListHead.Flink;
629     while (Entry != &List->DiskListHead)
630     {
631         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
632 
633         /* Print disk entry */
634         PrintDiskData(ListUi, DiskEntry);
635 
636         Entry = Entry->Flink;
637     }
638 }
639 
640 VOID
641 ScrollDownPartitionList(
642     IN PPARTLIST_UI ListUi)
643 {
644     if (GetNextPartition(ListUi->List))
645         DrawPartitionList(ListUi);
646 }
647 
648 VOID
649 ScrollUpPartitionList(
650     IN PPARTLIST_UI ListUi)
651 {
652     if (GetPrevPartition(ListUi->List))
653         DrawPartitionList(ListUi);
654 }
655 
656 /* EOF */
657