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