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