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 for (PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink; 398 PrimaryEntry != &DiskEntry->PrimaryPartListHead; 399 PrimaryEntry = PrimaryEntry->Flink) 400 { 401 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry); 402 403 PrintPartitionData(ListUi, 404 DiskEntry, 405 PrimaryPartEntry); 406 407 if (IsContainerPartition(PrimaryPartEntry->PartitionType)) 408 { 409 for (LogicalEntry = DiskEntry->LogicalPartListHead.Flink; 410 LogicalEntry != &DiskEntry->LogicalPartListHead; 411 LogicalEntry = LogicalEntry->Flink) 412 { 413 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry); 414 415 PrintPartitionData(ListUi, 416 DiskEntry, 417 LogicalPartEntry); 418 } 419 } 420 } 421 422 /* Print separator line */ 423 PrintEmptyLine(ListUi); 424 } 425 426 VOID 427 DrawPartitionList( 428 IN PPARTLIST_UI ListUi) 429 { 430 PPARTLIST List = ListUi->List; 431 PLIST_ENTRY Entry, Entry2; 432 PDISKENTRY DiskEntry; 433 PPARTENTRY PartEntry = NULL; 434 COORD coPos; 435 ULONG Written; 436 USHORT Width; 437 USHORT Height; 438 SHORT i; 439 SHORT CurrentDiskLine; 440 SHORT CurrentPartLine; 441 SHORT LastLine; 442 BOOLEAN CurrentPartLineFound = FALSE; 443 BOOLEAN CurrentDiskLineFound = FALSE; 444 445 Width = ListUi->Right - ListUi->Left - 1; 446 Height = ListUi->Bottom - ListUi->Top - 2; 447 448 /* Calculate the line of the current disk and partition */ 449 CurrentDiskLine = 0; 450 CurrentPartLine = 0; 451 LastLine = 0; 452 453 for (Entry = List->DiskListHead.Flink; 454 Entry != &List->DiskListHead; 455 Entry = Entry->Flink) 456 { 457 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 458 459 LastLine += 2; 460 if (CurrentPartLineFound == FALSE) 461 { 462 CurrentPartLine += 2; 463 } 464 465 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; 466 Entry2 != &DiskEntry->PrimaryPartListHead; 467 Entry2 = Entry2->Flink) 468 { 469 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 470 if (PartEntry == ListUi->CurrentPartition) 471 { 472 CurrentPartLineFound = TRUE; 473 } 474 475 if (CurrentPartLineFound == FALSE) 476 { 477 CurrentPartLine++; 478 } 479 480 LastLine++; 481 } 482 483 if (CurrentPartLineFound == FALSE) 484 { 485 for (Entry2 = DiskEntry->LogicalPartListHead.Flink; 486 Entry2 != &DiskEntry->LogicalPartListHead; 487 Entry2 = Entry2->Flink) 488 { 489 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); 490 if (PartEntry == ListUi->CurrentPartition) 491 { 492 CurrentPartLineFound = TRUE; 493 } 494 495 if (CurrentPartLineFound == FALSE) 496 { 497 CurrentPartLine++; 498 } 499 500 LastLine++; 501 } 502 } 503 504 if (DiskEntry == ListUi->CurrentDisk) 505 { 506 CurrentDiskLineFound = TRUE; 507 } 508 509 if (Entry->Flink != &List->DiskListHead) 510 { 511 if (CurrentDiskLineFound == FALSE) 512 { 513 CurrentPartLine++; 514 CurrentDiskLine = CurrentPartLine; 515 } 516 517 LastLine++; 518 } 519 else 520 { 521 LastLine--; 522 } 523 } 524 525 /* If it possible, make the disk name visible */ 526 if (CurrentPartLine < ListUi->Offset) 527 { 528 ListUi->Offset = CurrentPartLine; 529 } 530 else if (CurrentPartLine - ListUi->Offset > Height) 531 { 532 ListUi->Offset = CurrentPartLine - Height; 533 } 534 535 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < Height) 536 { 537 ListUi->Offset = CurrentDiskLine; 538 } 539 540 /* Draw upper left corner */ 541 coPos.X = ListUi->Left; 542 coPos.Y = ListUi->Top; 543 FillConsoleOutputCharacterA(StdOutput, 544 0xDA, // '+', 545 1, 546 coPos, 547 &Written); 548 549 /* Draw upper edge */ 550 coPos.X = ListUi->Left + 1; 551 coPos.Y = ListUi->Top; 552 if (ListUi->Offset == 0) 553 { 554 FillConsoleOutputCharacterA(StdOutput, 555 0xC4, // '-', 556 Width, 557 coPos, 558 &Written); 559 } 560 else 561 { 562 FillConsoleOutputCharacterA(StdOutput, 563 0xC4, // '-', 564 Width - 4, 565 coPos, 566 &Written); 567 coPos.X = ListUi->Right - 5; 568 WriteConsoleOutputCharacterA(StdOutput, 569 "(\x18)", // "(up)" 570 3, 571 coPos, 572 &Written); 573 coPos.X = ListUi->Right - 2; 574 FillConsoleOutputCharacterA(StdOutput, 575 0xC4, // '-', 576 2, 577 coPos, 578 &Written); 579 } 580 581 /* Draw upper right corner */ 582 coPos.X = ListUi->Right; 583 coPos.Y = ListUi->Top; 584 FillConsoleOutputCharacterA(StdOutput, 585 0xBF, // '+', 586 1, 587 coPos, 588 &Written); 589 590 /* Draw left and right edge */ 591 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++) 592 { 593 coPos.X = ListUi->Left; 594 coPos.Y = i; 595 FillConsoleOutputCharacterA(StdOutput, 596 0xB3, // '|', 597 1, 598 coPos, 599 &Written); 600 601 coPos.X = ListUi->Right; 602 FillConsoleOutputCharacterA(StdOutput, 603 0xB3, //'|', 604 1, 605 coPos, 606 &Written); 607 } 608 609 /* Draw lower left corner */ 610 coPos.X = ListUi->Left; 611 coPos.Y = ListUi->Bottom; 612 FillConsoleOutputCharacterA(StdOutput, 613 0xC0, // '+', 614 1, 615 coPos, 616 &Written); 617 618 /* Draw lower edge */ 619 coPos.X = ListUi->Left + 1; 620 coPos.Y = ListUi->Bottom; 621 if (LastLine - ListUi->Offset <= Height) 622 { 623 FillConsoleOutputCharacterA(StdOutput, 624 0xC4, // '-', 625 Width, 626 coPos, 627 &Written); 628 } 629 else 630 { 631 FillConsoleOutputCharacterA(StdOutput, 632 0xC4, // '-', 633 Width - 4, 634 coPos, 635 &Written); 636 coPos.X = ListUi->Right - 5; 637 WriteConsoleOutputCharacterA(StdOutput, 638 "(\x19)", // "(down)" 639 3, 640 coPos, 641 &Written); 642 coPos.X = ListUi->Right - 2; 643 FillConsoleOutputCharacterA(StdOutput, 644 0xC4, // '-', 645 2, 646 coPos, 647 &Written); 648 } 649 650 /* Draw lower right corner */ 651 coPos.X = ListUi->Right; 652 coPos.Y = ListUi->Bottom; 653 FillConsoleOutputCharacterA(StdOutput, 654 0xD9, // '+', 655 1, 656 coPos, 657 &Written); 658 659 /* Print list entries */ 660 ListUi->Line = -ListUi->Offset; 661 662 for (Entry = List->DiskListHead.Flink; 663 Entry != &List->DiskListHead; 664 Entry = Entry->Flink) 665 { 666 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry); 667 668 /* Print disk entry */ 669 PrintDiskData(ListUi, DiskEntry); 670 } 671 } 672 673 VOID 674 ScrollDownPartitionList( 675 IN PPARTLIST_UI ListUi) 676 { 677 PPARTENTRY NextPart = GetNextPartition(ListUi->List, ListUi->CurrentPartition); 678 if (NextPart) 679 { 680 ListUi->CurrentPartition = NextPart; 681 ListUi->CurrentDisk = NextPart->DiskEntry; 682 DrawPartitionList(ListUi); 683 } 684 } 685 686 VOID 687 ScrollUpPartitionList( 688 IN PPARTLIST_UI ListUi) 689 { 690 PPARTENTRY PrevPart = GetPrevPartition(ListUi->List, ListUi->CurrentPartition); 691 if (PrevPart) 692 { 693 ListUi->CurrentPartition = PrevPart; 694 ListUi->CurrentDisk = PrevPart->DiskEntry; 695 DrawPartitionList(ListUi); 696 } 697 } 698 699 /* EOF */ 700