a8e72676d300af93580764aaa24528ccf68b0542
[reactos.git] / base / setup / usetup / usetup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004 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/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 #include <usetup.h>
29 #include <math.h>
30
31 #include "bootsup.h"
32 #include "chkdsk.h"
33 #include "cmdcons.h"
34 #include "format.h"
35 #include "drivesup.h"
36 #include "settings.h"
37
38 #define NDEBUG
39 #include <debug.h>
40
41 // HACK!
42 #include <strsafe.h>
43
44
45 /* GLOBALS ******************************************************************/
46
47 HANDLE ProcessHeap;
48
49 static UNICODE_STRING SourceRootPath;
50 static UNICODE_STRING SourceRootDir;
51 /* static */ UNICODE_STRING SourcePath;
52
53 BOOLEAN IsUnattendedSetup = FALSE;
54 LONG UnattendDestinationDiskNumber;
55 LONG UnattendDestinationPartitionNumber;
56 LONG UnattendMBRInstallType = -1;
57 LONG UnattendFormatPartition = 0;
58 LONG AutoPartition = 0;
59 WCHAR UnattendInstallationDirectory[MAX_PATH];
60 PWCHAR SelectedLanguageId;
61 WCHAR LocaleID[9];
62 WCHAR DefaultLanguage[20];
63 WCHAR DefaultKBLayout[20];
64 static BOOLEAN RepairUpdateFlag = FALSE;
65 static HANDLE hPnpThread = INVALID_HANDLE_VALUE;
66
67 static PPARTLIST PartitionList = NULL;
68 static PPARTENTRY TempPartition = NULL;
69 static FORMATMACHINESTATE FormatState = Start;
70
71
72 /* LOCALS *******************************************************************/
73
74 static PFILE_SYSTEM_LIST FileSystemList = NULL;
75
76 static UNICODE_STRING InstallPath;
77
78 /*
79 * Path to the system partition, where the boot manager resides.
80 * On x86 PCs, this is usually the active partition.
81 * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
82 *
83 * For more information, see:
84 * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
85 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
86 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
87 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
88 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
89 * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
90 */
91 static UNICODE_STRING SystemRootPath;
92
93 /* Path to the install directory inside the ReactOS boot partition */
94 static UNICODE_STRING DestinationPath;
95 static UNICODE_STRING DestinationArcPath;
96 static UNICODE_STRING DestinationRootPath;
97
98 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
99 static WCHAR DestinationDriveLetter;
100
101 static HINF SetupInf;
102
103 static HSPFILEQ SetupFileQueue = NULL;
104
105 static PGENERIC_LIST ComputerList = NULL;
106 static PGENERIC_LIST DisplayList = NULL;
107 static PGENERIC_LIST KeyboardList = NULL;
108 static PGENERIC_LIST LayoutList = NULL;
109 static PGENERIC_LIST LanguageList = NULL;
110
111 static LANGID LanguageId = 0;
112
113 static ULONG RequiredPartitionDiskSpace = ~0;
114
115 /* FUNCTIONS ****************************************************************/
116
117 static VOID
118 PrintString(char* fmt,...)
119 {
120 char buffer[512];
121 va_list ap;
122 UNICODE_STRING UnicodeString;
123 ANSI_STRING AnsiString;
124
125 va_start(ap, fmt);
126 vsprintf(buffer, fmt, ap);
127 va_end(ap);
128
129 RtlInitAnsiString(&AnsiString, buffer);
130 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
131 NtDisplayString(&UnicodeString);
132 RtlFreeUnicodeString(&UnicodeString);
133 }
134
135
136 static VOID
137 DrawBox(IN SHORT xLeft,
138 IN SHORT yTop,
139 IN SHORT Width,
140 IN SHORT Height)
141 {
142 COORD coPos;
143 DWORD Written;
144
145 /* draw upper left corner */
146 coPos.X = xLeft;
147 coPos.Y = yTop;
148 FillConsoleOutputCharacterA(StdOutput,
149 0xDA, // '+',
150 1,
151 coPos,
152 &Written);
153
154 /* draw upper edge */
155 coPos.X = xLeft + 1;
156 coPos.Y = yTop;
157 FillConsoleOutputCharacterA(StdOutput,
158 0xC4, // '-',
159 Width - 2,
160 coPos,
161 &Written);
162
163 /* draw upper right corner */
164 coPos.X = xLeft + Width - 1;
165 coPos.Y = yTop;
166 FillConsoleOutputCharacterA(StdOutput,
167 0xBF, // '+',
168 1,
169 coPos,
170 &Written);
171
172 /* Draw right edge, inner space and left edge */
173 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
174 {
175 coPos.X = xLeft;
176 FillConsoleOutputCharacterA(StdOutput,
177 0xB3, // '|',
178 1,
179 coPos,
180 &Written);
181
182 coPos.X = xLeft + 1;
183 FillConsoleOutputCharacterA(StdOutput,
184 ' ',
185 Width - 2,
186 coPos,
187 &Written);
188
189 coPos.X = xLeft + Width - 1;
190 FillConsoleOutputCharacterA(StdOutput,
191 0xB3, // '|',
192 1,
193 coPos,
194 &Written);
195 }
196
197 /* draw lower left corner */
198 coPos.X = xLeft;
199 coPos.Y = yTop + Height - 1;
200 FillConsoleOutputCharacterA(StdOutput,
201 0xC0, // '+',
202 1,
203 coPos,
204 &Written);
205
206 /* draw lower edge */
207 coPos.X = xLeft + 1;
208 coPos.Y = yTop + Height - 1;
209 FillConsoleOutputCharacterA(StdOutput,
210 0xC4, // '-',
211 Width - 2,
212 coPos,
213 &Written);
214
215 /* draw lower right corner */
216 coPos.X = xLeft + Width - 1;
217 coPos.Y = yTop + Height - 1;
218 FillConsoleOutputCharacterA(StdOutput,
219 0xD9, // '+',
220 1,
221 coPos,
222 &Written);
223 }
224
225
226 VOID
227 PopupError(PCCH Text,
228 PCCH Status,
229 PINPUT_RECORD Ir,
230 ULONG WaitEvent)
231 {
232 SHORT yTop;
233 SHORT xLeft;
234 COORD coPos;
235 DWORD Written;
236 ULONG Length;
237 ULONG MaxLength;
238 ULONG Lines;
239 PCHAR p;
240 PCCH pnext;
241 BOOLEAN LastLine;
242 SHORT Width;
243 SHORT Height;
244
245 /* Count text lines and longest line */
246 MaxLength = 0;
247 Lines = 0;
248 pnext = Text;
249
250 while (TRUE)
251 {
252 p = strchr(pnext, '\n');
253
254 if (p == NULL)
255 {
256 Length = strlen(pnext);
257 LastLine = TRUE;
258 }
259 else
260 {
261 Length = (ULONG)(p - pnext);
262 LastLine = FALSE;
263 }
264
265 Lines++;
266
267 if (Length > MaxLength)
268 MaxLength = Length;
269
270 if (LastLine != FALSE)
271 break;
272
273 pnext = p + 1;
274 }
275
276 /* Check length of status line */
277 if (Status != NULL)
278 {
279 Length = strlen(Status);
280
281 if (Length > MaxLength)
282 MaxLength = Length;
283 }
284
285 Width = MaxLength + 4;
286 Height = Lines + 2;
287
288 if (Status != NULL)
289 Height += 2;
290
291 yTop = (yScreen - Height) / 2;
292 xLeft = (xScreen - Width) / 2;
293
294
295 /* Set screen attributes */
296 coPos.X = xLeft;
297 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
298 {
299 FillConsoleOutputAttribute(StdOutput,
300 FOREGROUND_RED | BACKGROUND_WHITE,
301 Width,
302 coPos,
303 &Written);
304 }
305
306 DrawBox(xLeft, yTop, Width, Height);
307
308 /* Print message text */
309 coPos.Y = yTop + 1;
310 pnext = Text;
311 while (TRUE)
312 {
313 p = strchr(pnext, '\n');
314
315 if (p == NULL)
316 {
317 Length = strlen(pnext);
318 LastLine = TRUE;
319 }
320 else
321 {
322 Length = (ULONG)(p - pnext);
323 LastLine = FALSE;
324 }
325
326 if (Length != 0)
327 {
328 coPos.X = xLeft + 2;
329 WriteConsoleOutputCharacterA(StdOutput,
330 pnext,
331 Length,
332 coPos,
333 &Written);
334 }
335
336 if (LastLine != FALSE)
337 break;
338
339 coPos.Y++;
340 pnext = p + 1;
341 }
342
343 /* Print separator line and status text */
344 if (Status != NULL)
345 {
346 coPos.Y = yTop + Height - 3;
347 coPos.X = xLeft;
348 FillConsoleOutputCharacterA(StdOutput,
349 0xC3, // '+',
350 1,
351 coPos,
352 &Written);
353
354 coPos.X = xLeft + 1;
355 FillConsoleOutputCharacterA(StdOutput,
356 0xC4, // '-',
357 Width - 2,
358 coPos,
359 &Written);
360
361 coPos.X = xLeft + Width - 1;
362 FillConsoleOutputCharacterA(StdOutput,
363 0xB4, // '+',
364 1,
365 coPos,
366 &Written);
367
368 coPos.Y++;
369 coPos.X = xLeft + 2;
370 WriteConsoleOutputCharacterA(StdOutput,
371 Status,
372 min(strlen(Status), (SIZE_T)Width - 4),
373 coPos,
374 &Written);
375 }
376
377 if (WaitEvent == POPUP_WAIT_NONE)
378 return;
379
380 while (TRUE)
381 {
382 CONSOLE_ConInKey(Ir);
383
384 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
385 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
386 {
387 return;
388 }
389 }
390 }
391
392
393 /*
394 * Confirm quit setup
395 * RETURNS
396 * TRUE: Quit setup.
397 * FALSE: Don't quit setup.
398 */
399 static BOOL
400 ConfirmQuit(PINPUT_RECORD Ir)
401 {
402 BOOL Result = FALSE;
403 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
404
405 while (TRUE)
406 {
407 CONSOLE_ConInKey(Ir);
408
409 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
410 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
411 {
412 Result = TRUE;
413 break;
414 }
415 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
416 {
417 Result = FALSE;
418 break;
419 }
420 }
421
422 return Result;
423 }
424
425
426 static VOID
427 CheckUnattendedSetup(VOID)
428 {
429 WCHAR UnattendInfPath[MAX_PATH];
430 INFCONTEXT Context;
431 HINF UnattendInf;
432 UINT ErrorLine;
433 INT IntValue;
434 PWCHAR Value;
435
436 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, SourcePath.Buffer, L"unattend.inf");
437
438 if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
439 {
440 DPRINT("Does not exist: %S\n", UnattendInfPath);
441 return;
442 }
443
444 /* Load 'unattend.inf' from install media. */
445 UnattendInf = SetupOpenInfFileW(UnattendInfPath,
446 NULL,
447 INF_STYLE_WIN4,
448 LanguageId,
449 &ErrorLine);
450
451 if (UnattendInf == INVALID_HANDLE_VALUE)
452 {
453 DPRINT("SetupOpenInfFileW() failed\n");
454 return;
455 }
456
457 /* Open 'Unattend' section */
458 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"Signature", &Context))
459 {
460 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
461 SetupCloseInfFile(UnattendInf);
462 return;
463 }
464
465 /* Get pointer 'Signature' key */
466 if (!INF_GetData(&Context, NULL, &Value))
467 {
468 DPRINT("INF_GetData() failed for key 'Signature'\n");
469 SetupCloseInfFile(UnattendInf);
470 return;
471 }
472
473 /* Check 'Signature' string */
474 if (_wcsicmp(Value, L"$ReactOS$") != 0)
475 {
476 DPRINT("Signature not $ReactOS$\n");
477 SetupCloseInfFile(UnattendInf);
478 return;
479 }
480
481 /* Check if Unattend setup is enabled */
482 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
483 {
484 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
485 SetupCloseInfFile(UnattendInf);
486 return;
487 }
488
489 if (!INF_GetData(&Context, NULL, &Value))
490 {
491 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
492 SetupCloseInfFile(UnattendInf);
493 return;
494 }
495
496 if (_wcsicmp(Value, L"yes") != 0)
497 {
498 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
499 SetupCloseInfFile(UnattendInf);
500 return;
501 }
502
503 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
504 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
505 {
506 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
507 SetupCloseInfFile(UnattendInf);
508 return;
509 }
510
511 if (!SetupGetIntField(&Context, 1, &IntValue))
512 {
513 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
514 SetupCloseInfFile(UnattendInf);
515 return;
516 }
517
518 UnattendDestinationDiskNumber = (LONG)IntValue;
519
520 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
521 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
522 {
523 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
524 SetupCloseInfFile(UnattendInf);
525 return;
526 }
527
528 if (!SetupGetIntField(&Context, 1, &IntValue))
529 {
530 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
531 SetupCloseInfFile(UnattendInf);
532 return;
533 }
534
535 UnattendDestinationPartitionNumber = (LONG)IntValue;
536
537 /* Search for 'InstallationDirectory' in the 'Unattend' section */
538 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
539 {
540 DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
541 SetupCloseInfFile(UnattendInf);
542 return;
543 }
544
545 /* Get pointer 'InstallationDirectory' key */
546 if (!INF_GetData(&Context, NULL, &Value))
547 {
548 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
549 SetupCloseInfFile(UnattendInf);
550 return;
551 }
552
553 wcscpy(UnattendInstallationDirectory, Value);
554
555 IsUnattendedSetup = TRUE;
556 DPRINT("Running unattended setup\n");
557
558 /* Search for 'MBRInstallType' in the 'Unattend' section */
559 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
560 {
561 if (SetupGetIntField(&Context, 1, &IntValue))
562 {
563 UnattendMBRInstallType = IntValue;
564 }
565 }
566
567 /* Search for 'FormatPartition' in the 'Unattend' section */
568 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
569 {
570 if (SetupGetIntField(&Context, 1, &IntValue))
571 {
572 UnattendFormatPartition = IntValue;
573 }
574 }
575
576 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
577 {
578 if (SetupGetIntField(&Context, 1, &IntValue))
579 {
580 AutoPartition = IntValue;
581 }
582 }
583
584 /* search for LocaleID in the 'Unattend' section*/
585 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"LocaleID", &Context))
586 {
587 if (INF_GetData(&Context, NULL, &Value))
588 {
589 LONG Id = wcstol(Value, NULL, 16);
590 swprintf(LocaleID, L"%08lx", Id);
591 }
592 }
593
594 SetupCloseInfFile(UnattendInf);
595 }
596
597
598 static VOID
599 UpdateKBLayout(VOID)
600 {
601 PGENERIC_LIST_ENTRY ListEntry;
602 LPCWSTR pszNewLayout;
603
604 pszNewLayout = MUIDefaultKeyboardLayout();
605
606 if (LayoutList == NULL)
607 {
608 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
609 if (LayoutList == NULL)
610 {
611 /* FIXME: Handle error! */
612 return;
613 }
614 }
615
616 ListEntry = GetFirstListEntry(LayoutList);
617
618 /* Search for default layout (if provided) */
619 if (pszNewLayout != NULL)
620 {
621 while (ListEntry != NULL)
622 {
623 if (!wcscmp(pszNewLayout, GetListEntryUserData(ListEntry)))
624 {
625 SetCurrentListEntry(LayoutList, ListEntry);
626 break;
627 }
628
629 ListEntry = GetNextListEntry(ListEntry);
630 }
631 }
632 }
633
634
635 /*
636 * Displays the LanguagePage.
637 *
638 * Next pages: WelcomePage, QuitPage
639 *
640 * SIDEEFFECTS
641 * Init SelectedLanguageId
642 * Init LanguageId
643 *
644 * RETURNS
645 * Number of the next page.
646 */
647 static PAGE_NUMBER
648 LanguagePage(PINPUT_RECORD Ir)
649 {
650 GENERIC_LIST_UI ListUi;
651 PWCHAR NewLanguageId;
652 BOOL RefreshPage = FALSE;
653
654 /* Initialize the computer settings list */
655 if (LanguageList == NULL)
656 {
657 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
658 if (LanguageList == NULL)
659 {
660 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
661 return WELCOME_PAGE;
662 }
663 }
664
665 /* Load the font */
666 SelectedLanguageId = DefaultLanguage;
667 SetConsoleCodePage();
668 UpdateKBLayout();
669
670 /* If there's just a single language in the list skip
671 * the language selection process altogether! */
672 if (GenericListHasSingleEntry(LanguageList))
673 {
674 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
675 return WELCOME_PAGE;
676 }
677
678 InitGenericListUi(&ListUi, LanguageList);
679 DrawGenericList(&ListUi,
680 2,
681 18,
682 xScreen - 3,
683 yScreen - 3);
684
685 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
686
687 MUIDisplayPage(LANGUAGE_PAGE);
688
689 while (TRUE)
690 {
691 CONSOLE_ConInKey(Ir);
692
693 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
694 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
695 {
696 ScrollDownGenericList(&ListUi);
697 RefreshPage = TRUE;
698 }
699 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
700 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
701 {
702 ScrollUpGenericList(&ListUi);
703 RefreshPage = TRUE;
704 }
705 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
706 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
707 {
708 ScrollPageDownGenericList(&ListUi);
709 RefreshPage = TRUE;
710 }
711 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
712 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
713 {
714 ScrollPageUpGenericList(&ListUi);
715 RefreshPage = TRUE;
716 }
717 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
718 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
719 {
720 if (ConfirmQuit(Ir) != FALSE)
721 return QUIT_PAGE;
722 else
723 RedrawGenericList(&ListUi);
724 }
725 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
726 {
727 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
728
729 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
730
731 if (wcscmp(SelectedLanguageId, DefaultLanguage))
732 {
733 UpdateKBLayout();
734 }
735
736 /* Load the font */
737 SetConsoleCodePage();
738
739 return WELCOME_PAGE;
740 }
741 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
742 {
743 /* a-z */
744 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
745 RefreshPage = TRUE;
746 }
747
748 if (RefreshPage)
749 {
750 NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
751
752 if (SelectedLanguageId != NewLanguageId)
753 {
754 /* Clear the language page */
755 MUIClearPage(LANGUAGE_PAGE);
756
757 SelectedLanguageId = NewLanguageId;
758
759 /* Load the font */
760 SetConsoleCodePage();
761
762 /* Redraw language selection page in native language */
763 MUIDisplayPage(LANGUAGE_PAGE);
764 }
765
766 RefreshPage = FALSE;
767 }
768 }
769
770 return WELCOME_PAGE;
771 }
772
773
774 /*
775 * Start page
776 *
777 * Next pages:
778 * LanguagePage (at once, default)
779 * InstallIntroPage (at once, if unattended)
780 * QuitPage
781 *
782 * SIDEEFFECTS
783 * Init Sdi
784 * Init SourcePath
785 * Init SourceRootPath
786 * Init SourceRootDir
787 * Init SetupInf
788 * Init RequiredPartitionDiskSpace
789 * Init IsUnattendedSetup
790 * If unattended, init *List and sets the Codepage
791 * If unattended, init SelectedLanguageId
792 * If unattended, init LanguageId
793 *
794 * RETURNS
795 * Number of the next page.
796 */
797 static PAGE_NUMBER
798 SetupStartPage(PINPUT_RECORD Ir)
799 {
800 NTSTATUS Status;
801 WCHAR FileNameBuffer[MAX_PATH];
802 INFCONTEXT Context;
803 PWCHAR Value;
804 UINT ErrorLine;
805 PGENERIC_LIST_ENTRY ListEntry;
806 INT IntValue;
807
808 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
809
810 /* Get the source path and source root path */
811 Status = GetSourcePaths(&SourcePath,
812 &SourceRootPath,
813 &SourceRootDir);
814 if (!NT_SUCCESS(Status))
815 {
816 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
817 MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
818 return QUIT_PAGE;
819 }
820 DPRINT1("SourcePath: '%wZ'\n", &SourcePath);
821 DPRINT1("SourceRootPath: '%wZ'\n", &SourceRootPath);
822 DPRINT1("SourceRootDir: '%wZ'\n", &SourceRootDir);
823
824 /* Load txtsetup.sif from install media. */
825 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, SourcePath.Buffer, L"txtsetup.sif");
826 SetupInf = SetupOpenInfFileW(FileNameBuffer,
827 NULL,
828 INF_STYLE_WIN4,
829 LanguageId,
830 &ErrorLine);
831
832 if (SetupInf == INVALID_HANDLE_VALUE)
833 {
834 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
835 return QUIT_PAGE;
836 }
837
838 /* Open 'Version' section */
839 if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
840 {
841 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
842 return QUIT_PAGE;
843 }
844
845 /* Get pointer 'Signature' key */
846 if (!INF_GetData(&Context, NULL, &Value))
847 {
848 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
849 return QUIT_PAGE;
850 }
851
852 /* Check 'Signature' string */
853 if (_wcsicmp(Value, L"$ReactOS$") != 0)
854 {
855 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
856 return QUIT_PAGE;
857 }
858
859 /* Open 'DiskSpaceRequirements' section */
860 if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
861 {
862 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
863 return QUIT_PAGE;
864 }
865
866 /* Get the 'FreeSysPartDiskSpace' value */
867 if (!SetupGetIntField(&Context, 1, &IntValue))
868 {
869 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
870 return QUIT_PAGE;
871 }
872
873 RequiredPartitionDiskSpace = (ULONG)IntValue;
874
875 /* Start the PnP thread */
876 if (hPnpThread != INVALID_HANDLE_VALUE)
877 {
878 NtResumeThread(hPnpThread, NULL);
879 hPnpThread = INVALID_HANDLE_VALUE;
880 }
881
882 CheckUnattendedSetup();
883
884 if (IsUnattendedSetup)
885 {
886 // TODO: Read options from inf
887 ComputerList = CreateComputerTypeList(SetupInf);
888 DisplayList = CreateDisplayDriverList(SetupInf);
889 KeyboardList = CreateKeyboardDriverList(SetupInf);
890 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
891 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
892
893 /* new part */
894 wcscpy(SelectedLanguageId, LocaleID);
895 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
896
897 /* first we hack LanguageList */
898 ListEntry = GetFirstListEntry(LanguageList);
899 while (ListEntry != NULL)
900 {
901 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
902 {
903 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
904 SetCurrentListEntry(LanguageList, ListEntry);
905 break;
906 }
907
908 ListEntry = GetNextListEntry(ListEntry);
909 }
910
911 /* now LayoutList */
912 ListEntry = GetFirstListEntry(LayoutList);
913 while (ListEntry != NULL)
914 {
915 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
916 {
917 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
918 SetCurrentListEntry(LayoutList, ListEntry);
919 break;
920 }
921
922 ListEntry = GetNextListEntry(ListEntry);
923 }
924
925 SetConsoleCodePage();
926
927 return INSTALL_INTRO_PAGE;
928 }
929
930 return LANGUAGE_PAGE;
931 }
932
933
934 /*
935 * Displays the WelcomePage.
936 *
937 * Next pages:
938 * InstallIntroPage (default)
939 * RepairIntroPage
940 * LicensePage
941 * QuitPage
942 *
943 * RETURNS
944 * Number of the next page.
945 */
946 static PAGE_NUMBER
947 WelcomePage(PINPUT_RECORD Ir)
948 {
949 MUIDisplayPage(WELCOME_PAGE);
950
951 while (TRUE)
952 {
953 CONSOLE_ConInKey(Ir);
954
955 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
956 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
957 {
958 if (ConfirmQuit(Ir) != FALSE)
959 return QUIT_PAGE;
960
961 break;
962 }
963 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
964 {
965 return INSTALL_INTRO_PAGE;
966 }
967 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
968 {
969 return REPAIR_INTRO_PAGE;
970 }
971 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
972 {
973 return LICENSE_PAGE;
974 }
975 }
976
977 return WELCOME_PAGE;
978 }
979
980
981 /*
982 * Displays the License page.
983 *
984 * Next page:
985 * WelcomePage (default)
986 *
987 * RETURNS
988 * Number of the next page.
989 */
990 static PAGE_NUMBER
991 LicensePage(PINPUT_RECORD Ir)
992 {
993 MUIDisplayPage(LICENSE_PAGE);
994
995 while (TRUE)
996 {
997 CONSOLE_ConInKey(Ir);
998
999 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1000 {
1001 return WELCOME_PAGE;
1002 }
1003 }
1004
1005 return LICENSE_PAGE;
1006 }
1007
1008
1009 /*
1010 * Displays the RepairIntroPage.
1011 *
1012 * Next pages:
1013 * RebootPage (default)
1014 * InstallIntroPage
1015 * RecoveryPage
1016 * IntroPage
1017 *
1018 * RETURNS
1019 * Number of the next page.
1020 */
1021 static PAGE_NUMBER
1022 RepairIntroPage(PINPUT_RECORD Ir)
1023 {
1024 MUIDisplayPage(REPAIR_INTRO_PAGE);
1025
1026 while(TRUE)
1027 {
1028 CONSOLE_ConInKey(Ir);
1029
1030 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1031 {
1032 return REBOOT_PAGE;
1033 }
1034 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
1035 {
1036 RepairUpdateFlag = TRUE;
1037 return INSTALL_INTRO_PAGE;
1038 }
1039 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
1040 {
1041 return RECOVERY_PAGE;
1042 }
1043 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1044 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1045 {
1046 return WELCOME_PAGE;
1047 }
1048 }
1049
1050 return REPAIR_INTRO_PAGE;
1051 }
1052
1053 /*
1054 * Displays the InstallIntroPage.
1055 *
1056 * Next pages:
1057 * DeviceSettingsPage (At once if repair or update is selected)
1058 * SelectPartitionPage (At once if unattended setup)
1059 * DeviceSettingsPage (default)
1060 * QuitPage
1061 *
1062 * RETURNS
1063 * Number of the next page.
1064 */
1065 static PAGE_NUMBER
1066 InstallIntroPage(PINPUT_RECORD Ir)
1067 {
1068 if (RepairUpdateFlag)
1069 {
1070 //return SELECT_PARTITION_PAGE;
1071 return DEVICE_SETTINGS_PAGE;
1072 }
1073
1074 if (IsUnattendedSetup)
1075 return SELECT_PARTITION_PAGE;
1076
1077 MUIDisplayPage(INSTALL_INTRO_PAGE);
1078
1079 while (TRUE)
1080 {
1081 CONSOLE_ConInKey(Ir);
1082
1083 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1084 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1085 {
1086 if (ConfirmQuit(Ir) != FALSE)
1087 return QUIT_PAGE;
1088
1089 break;
1090 }
1091 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1092 {
1093 return DEVICE_SETTINGS_PAGE;
1094 // return SCSI_CONTROLLER_PAGE;
1095 }
1096 }
1097
1098 return INSTALL_INTRO_PAGE;
1099 }
1100
1101
1102 #if 0
1103 static PAGE_NUMBER
1104 ScsiControllerPage(PINPUT_RECORD Ir)
1105 {
1106 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1107
1108 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1109
1110 /* FIXME: print loaded mass storage driver descriptions */
1111 #if 0
1112 CONSOLE_SetTextXY(8, 10, "TEST device");
1113 #endif
1114
1115 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1116
1117 while (TRUE)
1118 {
1119 CONSOLE_ConInKey(Ir);
1120
1121 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1122 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1123 {
1124 if (ConfirmQuit(Ir) != FALSE)
1125 return QUIT_PAGE;
1126
1127 break;
1128 }
1129 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1130 {
1131 return DEVICE_SETTINGS_PAGE;
1132 }
1133 }
1134
1135 return SCSI_CONTROLLER_PAGE;
1136 }
1137
1138 static PAGE_NUMBER
1139 OemDriverPage(PINPUT_RECORD Ir)
1140 {
1141 // MUIDisplayPage(OEM_DRIVER_PAGE);
1142
1143 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1144
1145 /* FIXME: Implement!! */
1146
1147 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1148
1149 while (TRUE)
1150 {
1151 CONSOLE_ConInKey(Ir);
1152
1153 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1154 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1155 {
1156 if (ConfirmQuit(Ir) == TRUE)
1157 return QUIT_PAGE;
1158
1159 break;
1160 }
1161 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1162 {
1163 return DEVICE_SETTINGS_PAGE;
1164 }
1165 }
1166
1167 return OEM_DRIVER_PAGE;
1168 }
1169 #endif
1170
1171
1172 /*
1173 * Displays the DeviceSettingsPage.
1174 *
1175 * Next pages:
1176 * SelectPartitionPage (At once if repair or update is selected)
1177 * ComputerSettingsPage
1178 * DisplaySettingsPage
1179 * KeyboardSettingsPage
1180 * LayoutsettingsPage
1181 * SelectPartitionPage
1182 * QuitPage
1183 *
1184 * SIDEEFFECTS
1185 * Init ComputerList
1186 * Init DisplayList
1187 * Init KeyboardList
1188 * Init LayoutList
1189 *
1190 * RETURNS
1191 * Number of the next page.
1192 */
1193 static PAGE_NUMBER
1194 DeviceSettingsPage(PINPUT_RECORD Ir)
1195 {
1196 static ULONG Line = 16;
1197
1198 /* Initialize the computer settings list */
1199 if (ComputerList == NULL)
1200 {
1201 ComputerList = CreateComputerTypeList(SetupInf);
1202 if (ComputerList == NULL)
1203 {
1204 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1205 return QUIT_PAGE;
1206 }
1207 }
1208
1209 /* Initialize the display settings list */
1210 if (DisplayList == NULL)
1211 {
1212 DisplayList = CreateDisplayDriverList(SetupInf);
1213 if (DisplayList == NULL)
1214 {
1215 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1216 return QUIT_PAGE;
1217 }
1218 }
1219
1220 /* Initialize the keyboard settings list */
1221 if (KeyboardList == NULL)
1222 {
1223 KeyboardList = CreateKeyboardDriverList(SetupInf);
1224 if (KeyboardList == NULL)
1225 {
1226 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1227 return QUIT_PAGE;
1228 }
1229 }
1230
1231 /* Initialize the keyboard layout list */
1232 if (LayoutList == NULL)
1233 {
1234 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
1235 if (LayoutList == NULL)
1236 {
1237 /* FIXME: report error */
1238 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1239 return QUIT_PAGE;
1240 }
1241 }
1242
1243 if (RepairUpdateFlag)
1244 return SELECT_PARTITION_PAGE;
1245
1246 // if (IsUnattendedSetup)
1247 // return SELECT_PARTITION_PAGE;
1248
1249 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1250
1251 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry(ComputerList)));
1252 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry(DisplayList)));
1253 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry(KeyboardList)));
1254 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry(LayoutList)));
1255
1256 CONSOLE_InvertTextXY(24, Line, 48, 1);
1257
1258 while (TRUE)
1259 {
1260 CONSOLE_ConInKey(Ir);
1261
1262 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1263 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1264 {
1265 CONSOLE_NormalTextXY(24, Line, 48, 1);
1266
1267 if (Line == 14)
1268 Line = 16;
1269 else if (Line == 16)
1270 Line = 11;
1271 else
1272 Line++;
1273
1274 CONSOLE_InvertTextXY(24, Line, 48, 1);
1275 }
1276 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1277 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1278 {
1279 CONSOLE_NormalTextXY(24, Line, 48, 1);
1280
1281 if (Line == 11)
1282 Line = 16;
1283 else if (Line == 16)
1284 Line = 14;
1285 else
1286 Line--;
1287
1288 CONSOLE_InvertTextXY(24, Line, 48, 1);
1289 }
1290 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1291 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1292 {
1293 if (ConfirmQuit(Ir) != FALSE)
1294 return QUIT_PAGE;
1295
1296 break;
1297 }
1298 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1299 {
1300 if (Line == 11)
1301 return COMPUTER_SETTINGS_PAGE;
1302 else if (Line == 12)
1303 return DISPLAY_SETTINGS_PAGE;
1304 else if (Line == 13)
1305 return KEYBOARD_SETTINGS_PAGE;
1306 else if (Line == 14)
1307 return LAYOUT_SETTINGS_PAGE;
1308 else if (Line == 16)
1309 return SELECT_PARTITION_PAGE;
1310 }
1311 }
1312
1313 return DEVICE_SETTINGS_PAGE;
1314 }
1315
1316
1317 /*
1318 * Handles generic selection lists.
1319 *
1320 * PARAMS
1321 * GenericList: The list to handle.
1322 * nextPage: The page it needs to jump to after this page.
1323 * Ir: The PINPUT_RECORD
1324 */
1325 static PAGE_NUMBER
1326 HandleGenericList(PGENERIC_LIST_UI ListUi,
1327 PAGE_NUMBER nextPage,
1328 PINPUT_RECORD Ir)
1329 {
1330 while (TRUE)
1331 {
1332 CONSOLE_ConInKey(Ir);
1333
1334 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1335 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1336 {
1337 ScrollDownGenericList(ListUi);
1338 }
1339 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1340 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1341 {
1342 ScrollUpGenericList(ListUi);
1343 }
1344 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1345 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1346 {
1347 ScrollPageDownGenericList(ListUi);
1348 }
1349 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1350 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1351 {
1352 ScrollPageUpGenericList(ListUi);
1353 }
1354 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1355 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1356 {
1357 if (ConfirmQuit(Ir) != FALSE)
1358 return QUIT_PAGE;
1359 else
1360 RedrawGenericList(ListUi);
1361 }
1362 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1363 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1364 {
1365 RestoreGenericListState(ListUi->List);
1366 return nextPage; // Use some "prevPage;" instead?
1367 }
1368 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1369 {
1370 return nextPage;
1371 }
1372 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1373 {
1374 /* a-z */
1375 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1376 }
1377 }
1378 }
1379
1380
1381 /*
1382 * Displays the ComputerSettingsPage.
1383 *
1384 * Next pages:
1385 * DeviceSettingsPage
1386 * QuitPage
1387 *
1388 * RETURNS
1389 * Number of the next page.
1390 */
1391 static PAGE_NUMBER
1392 ComputerSettingsPage(PINPUT_RECORD Ir)
1393 {
1394 GENERIC_LIST_UI ListUi;
1395 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1396
1397 InitGenericListUi(&ListUi, ComputerList);
1398 DrawGenericList(&ListUi,
1399 2,
1400 18,
1401 xScreen - 3,
1402 yScreen - 3);
1403
1404 SaveGenericListState(ComputerList);
1405
1406 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1407 }
1408
1409
1410 /*
1411 * Displays the DisplaySettingsPage.
1412 *
1413 * Next pages:
1414 * DeviceSettingsPage
1415 * QuitPage
1416 *
1417 * RETURNS
1418 * Number of the next page.
1419 */
1420 static PAGE_NUMBER
1421 DisplaySettingsPage(PINPUT_RECORD Ir)
1422 {
1423 GENERIC_LIST_UI ListUi;
1424 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1425
1426 InitGenericListUi(&ListUi, DisplayList);
1427 DrawGenericList(&ListUi,
1428 2,
1429 18,
1430 xScreen - 3,
1431 yScreen - 3);
1432
1433 SaveGenericListState(DisplayList);
1434
1435 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1436 }
1437
1438
1439 /*
1440 * Displays the KeyboardSettingsPage.
1441 *
1442 * Next pages:
1443 * DeviceSettingsPage
1444 * QuitPage
1445 *
1446 * RETURNS
1447 * Number of the next page.
1448 */
1449 static PAGE_NUMBER
1450 KeyboardSettingsPage(PINPUT_RECORD Ir)
1451 {
1452 GENERIC_LIST_UI ListUi;
1453 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1454
1455 InitGenericListUi(&ListUi, KeyboardList);
1456 DrawGenericList(&ListUi,
1457 2,
1458 18,
1459 xScreen - 3,
1460 yScreen - 3);
1461
1462 SaveGenericListState(KeyboardList);
1463
1464 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1465 }
1466
1467
1468 /*
1469 * Displays the LayoutSettingsPage.
1470 *
1471 * Next pages:
1472 * DeviceSettingsPage
1473 * QuitPage
1474 *
1475 * RETURNS
1476 * Number of the next page.
1477 */
1478 static PAGE_NUMBER
1479 LayoutSettingsPage(PINPUT_RECORD Ir)
1480 {
1481 GENERIC_LIST_UI ListUi;
1482 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1483
1484 InitGenericListUi(&ListUi, LayoutList);
1485 DrawGenericList(&ListUi,
1486 2,
1487 18,
1488 xScreen - 3,
1489 yScreen - 3);
1490
1491 SaveGenericListState(LayoutList);
1492
1493 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1494 }
1495
1496
1497 static BOOL
1498 IsDiskSizeValid(PPARTENTRY PartEntry)
1499 {
1500 ULONGLONG size;
1501
1502 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1503 size = (size + 524288) / 1048576; /* in MBytes */
1504
1505 if (size < RequiredPartitionDiskSpace)
1506 {
1507 /* Partition is too small so ask for another one */
1508 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, RequiredPartitionDiskSpace);
1509 return FALSE;
1510 }
1511 else
1512 {
1513 return TRUE;
1514 }
1515 }
1516
1517
1518 /*
1519 * Displays the SelectPartitionPage.
1520 *
1521 * Next pages:
1522 * SelectFileSystemPage (At once if unattended)
1523 * SelectFileSystemPage (Default if free space is selected)
1524 * CreatePrimaryPartitionPage
1525 * CreateExtendedPartitionPage
1526 * CreateLogicalPartitionPage
1527 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1528 * DeletePartitionPage
1529 * QuitPage
1530 *
1531 * SIDEEFFECTS
1532 * Set InstallShortcut (only if not unattended + free space is selected)
1533 *
1534 * RETURNS
1535 * Number of the next page.
1536 */
1537 static PAGE_NUMBER
1538 SelectPartitionPage(PINPUT_RECORD Ir)
1539 {
1540 PARTLIST_UI ListUi;
1541 ULONG Error;
1542
1543 if (PartitionList == NULL)
1544 {
1545 PartitionList = CreatePartitionList();
1546 if (PartitionList == NULL)
1547 {
1548 /* FIXME: show an error dialog */
1549 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1550 return QUIT_PAGE;
1551 }
1552 else if (IsListEmpty(&PartitionList->DiskListHead))
1553 {
1554 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1555 return QUIT_PAGE;
1556 }
1557
1558 TempPartition = NULL;
1559 FormatState = Start;
1560 }
1561
1562 MUIDisplayPage(SELECT_PARTITION_PAGE);
1563
1564 InitPartitionListUi(&ListUi, PartitionList,
1565 2,
1566 23,
1567 xScreen - 3,
1568 yScreen - 3);
1569 DrawPartitionList(&ListUi);
1570
1571 if (IsUnattendedSetup)
1572 {
1573 if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
1574 {
1575 if (AutoPartition)
1576 {
1577 if (PartitionList->CurrentPartition->LogicalPartition)
1578 {
1579 CreateLogicalPartition(PartitionList,
1580 PartitionList->CurrentPartition->SectorCount.QuadPart,
1581 TRUE);
1582 }
1583 else
1584 {
1585 CreatePrimaryPartition(PartitionList,
1586 PartitionList->CurrentPartition->SectorCount.QuadPart,
1587 TRUE);
1588 }
1589
1590 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1591 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1592 {
1593 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1594 RequiredPartitionDiskSpace);
1595 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1596 }
1597
1598 return SELECT_FILE_SYSTEM_PAGE;
1599 }
1600 }
1601 else
1602 {
1603 DrawPartitionList(&ListUi);
1604
1605 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1606 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1607 {
1608 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1609 RequiredPartitionDiskSpace);
1610 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1611 }
1612
1613 return SELECT_FILE_SYSTEM_PAGE;
1614 }
1615 }
1616
1617 while (TRUE)
1618 {
1619 /* Update status text */
1620 if (PartitionList->CurrentPartition == NULL)
1621 {
1622 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1623 }
1624 else if (PartitionList->CurrentPartition->LogicalPartition)
1625 {
1626 if (PartitionList->CurrentPartition->IsPartitioned)
1627 {
1628 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1629 }
1630 else
1631 {
1632 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1633 }
1634 }
1635 else
1636 {
1637 if (PartitionList->CurrentPartition->IsPartitioned)
1638 {
1639 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1640 {
1641 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1642 }
1643 else
1644 {
1645 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1646 }
1647 }
1648 else
1649 {
1650 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1651 }
1652 }
1653
1654 CONSOLE_ConInKey(Ir);
1655
1656 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1657 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1658 {
1659 if (ConfirmQuit(Ir) != FALSE)
1660 {
1661 DestroyPartitionList(PartitionList);
1662 PartitionList = NULL;
1663 return QUIT_PAGE;
1664 }
1665
1666 break;
1667 }
1668 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1669 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1670 {
1671 ScrollDownPartitionList(&ListUi);
1672 }
1673 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1674 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1675 {
1676 ScrollUpPartitionList(&ListUi);
1677 }
1678 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1679 {
1680 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1681 continue; // return SELECT_PARTITION_PAGE;
1682
1683 if (PartitionList->CurrentPartition == NULL ||
1684 PartitionList->CurrentPartition->IsPartitioned == FALSE)
1685 {
1686 if (PartitionList->CurrentPartition->LogicalPartition)
1687 {
1688 CreateLogicalPartition(PartitionList,
1689 0ULL,
1690 TRUE);
1691 }
1692 else
1693 {
1694 CreatePrimaryPartition(PartitionList,
1695 0ULL,
1696 TRUE);
1697 }
1698 }
1699
1700 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1701 {
1702 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1703 RequiredPartitionDiskSpace);
1704 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1705 }
1706
1707 return SELECT_FILE_SYSTEM_PAGE;
1708 }
1709 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1710 {
1711 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1712 {
1713 Error = PrimaryPartitionCreationChecks(PartitionList);
1714 if (Error != NOT_AN_ERROR)
1715 {
1716 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1717 return SELECT_PARTITION_PAGE;
1718 }
1719
1720 return CREATE_PRIMARY_PARTITION_PAGE;
1721 }
1722 }
1723 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1724 {
1725 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1726 {
1727 Error = ExtendedPartitionCreationChecks(PartitionList);
1728 if (Error != NOT_AN_ERROR)
1729 {
1730 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1731 return SELECT_PARTITION_PAGE;
1732 }
1733
1734 return CREATE_EXTENDED_PARTITION_PAGE;
1735 }
1736 }
1737 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1738 {
1739 if (PartitionList->CurrentPartition->LogicalPartition != FALSE)
1740 {
1741 Error = LogicalPartitionCreationChecks(PartitionList);
1742 if (Error != NOT_AN_ERROR)
1743 {
1744 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1745 return SELECT_PARTITION_PAGE;
1746 }
1747
1748 return CREATE_LOGICAL_PARTITION_PAGE;
1749 }
1750 }
1751 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1752 {
1753 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1754 {
1755 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1756 return SELECT_PARTITION_PAGE;
1757 }
1758
1759 if (PartitionList->CurrentPartition->BootIndicator ||
1760 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1761 {
1762 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1763 }
1764
1765 return DELETE_PARTITION_PAGE;
1766 }
1767 }
1768
1769 return SELECT_PARTITION_PAGE;
1770 }
1771
1772
1773 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1774 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1775 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1776
1777 static VOID
1778 ShowPartitionSizeInputBox(SHORT Left,
1779 SHORT Top,
1780 SHORT Right,
1781 SHORT Bottom,
1782 ULONG MaxSize,
1783 PWSTR InputBuffer,
1784 PBOOLEAN Quit,
1785 PBOOLEAN Cancel)
1786 {
1787 INPUT_RECORD Ir;
1788 COORD coPos;
1789 DWORD Written;
1790 CHAR Buffer[128];
1791 INT Length, Pos;
1792 WCHAR ch;
1793 SHORT iLeft;
1794 SHORT iTop;
1795
1796 if (Quit != NULL)
1797 *Quit = FALSE;
1798
1799 if (Cancel != NULL)
1800 *Cancel = FALSE;
1801
1802 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1803
1804 /* Print message */
1805 coPos.X = Left + 2;
1806 coPos.Y = Top + 2;
1807 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1808 iLeft = coPos.X + strlen(Buffer) + 1;
1809 iTop = coPos.Y;
1810
1811 WriteConsoleOutputCharacterA(StdOutput,
1812 Buffer,
1813 strlen(Buffer),
1814 coPos,
1815 &Written);
1816
1817 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1818 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1819 coPos.Y = iTop;
1820 WriteConsoleOutputCharacterA(StdOutput,
1821 Buffer,
1822 strlen(Buffer),
1823 coPos,
1824 &Written);
1825
1826 swprintf(InputBuffer, L"%lu", MaxSize);
1827 Length = wcslen(InputBuffer);
1828 Pos = Length;
1829 CONSOLE_SetInputTextXY(iLeft,
1830 iTop,
1831 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1832 InputBuffer);
1833 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1834 CONSOLE_SetCursorType(TRUE, TRUE);
1835
1836 while (TRUE)
1837 {
1838 CONSOLE_ConInKey(&Ir);
1839
1840 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1841 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1842 {
1843 if (Quit != NULL)
1844 *Quit = TRUE;
1845
1846 InputBuffer[0] = UNICODE_NULL;
1847 CONSOLE_SetCursorType(TRUE, FALSE);
1848 break;
1849 }
1850 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1851 {
1852 CONSOLE_SetCursorType(TRUE, FALSE);
1853 break;
1854 }
1855 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1856 {
1857 if (Cancel != NULL)
1858 *Cancel = TRUE;
1859
1860 InputBuffer[0] = UNICODE_NULL;
1861 CONSOLE_SetCursorType(TRUE, FALSE);
1862 break;
1863 }
1864 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1865 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1866 {
1867 Pos = 0;
1868 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1869 }
1870 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1871 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1872 {
1873 Pos = Length;
1874 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1875 }
1876 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1877 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1878 {
1879 if (Pos > 0)
1880 {
1881 Pos--;
1882 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1883 }
1884 }
1885 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1886 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1887 {
1888 if (Pos < Length)
1889 {
1890 Pos++;
1891 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1892 }
1893 }
1894 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1895 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1896 {
1897 if (Pos < Length)
1898 {
1899 memmove(&InputBuffer[Pos],
1900 &InputBuffer[Pos + 1],
1901 (Length - Pos - 1) * sizeof(WCHAR));
1902 InputBuffer[Length - 1] = UNICODE_NULL;
1903
1904 Length--;
1905 CONSOLE_SetInputTextXY(iLeft,
1906 iTop,
1907 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1908 InputBuffer);
1909 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1910 }
1911 }
1912 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1913 {
1914 if (Pos > 0)
1915 {
1916 if (Pos < Length)
1917 memmove(&InputBuffer[Pos - 1],
1918 &InputBuffer[Pos],
1919 (Length - Pos) * sizeof(WCHAR));
1920 InputBuffer[Length - 1] = UNICODE_NULL;
1921
1922 Pos--;
1923 Length--;
1924 CONSOLE_SetInputTextXY(iLeft,
1925 iTop,
1926 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1927 InputBuffer);
1928 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1929 }
1930 }
1931 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1932 {
1933 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1934 {
1935 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1936
1937 if ((ch >= L'0') && (ch <= L'9'))
1938 {
1939 if (Pos < Length)
1940 memmove(&InputBuffer[Pos + 1],
1941 &InputBuffer[Pos],
1942 (Length - Pos) * sizeof(WCHAR));
1943 InputBuffer[Length + 1] = UNICODE_NULL;
1944 InputBuffer[Pos] = ch;
1945
1946 Pos++;
1947 Length++;
1948 CONSOLE_SetInputTextXY(iLeft,
1949 iTop,
1950 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1951 InputBuffer);
1952 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1953 }
1954 }
1955 }
1956 }
1957 }
1958
1959
1960 /*
1961 * Displays the CreatePrimaryPartitionPage.
1962 *
1963 * Next pages:
1964 * SelectPartitionPage
1965 * SelectFileSystemPage (default)
1966 * QuitPage
1967 *
1968 * RETURNS
1969 * Number of the next page.
1970 */
1971 static PAGE_NUMBER
1972 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1973 {
1974 PDISKENTRY DiskEntry;
1975 PPARTENTRY PartEntry;
1976 BOOLEAN Quit;
1977 BOOLEAN Cancel;
1978 WCHAR InputBuffer[50];
1979 ULONG MaxSize;
1980 ULONGLONG PartSize;
1981 ULONGLONG DiskSize;
1982 ULONGLONG SectorCount;
1983 PCHAR Unit;
1984
1985 if (PartitionList == NULL ||
1986 PartitionList->CurrentDisk == NULL ||
1987 PartitionList->CurrentPartition == NULL)
1988 {
1989 /* FIXME: show an error dialog */
1990 return QUIT_PAGE;
1991 }
1992
1993 DiskEntry = PartitionList->CurrentDisk;
1994 PartEntry = PartitionList->CurrentPartition;
1995
1996 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1997
1998 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1999
2000 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2001 #if 0
2002 if (DiskSize >= 10737418240) /* 10 GB */
2003 {
2004 DiskSize = DiskSize / 1073741824;
2005 Unit = MUIGetString(STRING_GB);
2006 }
2007 else
2008 #endif
2009 {
2010 DiskSize = DiskSize / 1048576;
2011 if (DiskSize == 0)
2012 DiskSize = 1;
2013
2014 Unit = MUIGetString(STRING_MB);
2015 }
2016
2017 if (DiskEntry->DriverName.Length > 0)
2018 {
2019 CONSOLE_PrintTextXY(6, 10,
2020 MUIGetString(STRING_HDINFOPARTCREATE_1),
2021 DiskSize,
2022 Unit,
2023 DiskEntry->DiskNumber,
2024 DiskEntry->Port,
2025 DiskEntry->Bus,
2026 DiskEntry->Id,
2027 &DiskEntry->DriverName,
2028 DiskEntry->NoMbr ? "GPT" : "MBR");
2029 }
2030 else
2031 {
2032 CONSOLE_PrintTextXY(6, 10,
2033 MUIGetString(STRING_HDINFOPARTCREATE_2),
2034 DiskSize,
2035 Unit,
2036 DiskEntry->DiskNumber,
2037 DiskEntry->Port,
2038 DiskEntry->Bus,
2039 DiskEntry->Id,
2040 DiskEntry->NoMbr ? "GPT" : "MBR");
2041 }
2042
2043 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2044
2045 #if 0
2046 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2047 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2048 #endif
2049
2050 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2051
2052 PartEntry = PartitionList->CurrentPartition;
2053 while (TRUE)
2054 {
2055 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2056
2057 if (MaxSize > PARTITION_MAXSIZE)
2058 MaxSize = PARTITION_MAXSIZE;
2059
2060 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2061 MaxSize, InputBuffer, &Quit, &Cancel);
2062
2063 if (Quit != FALSE)
2064 {
2065 if (ConfirmQuit(Ir) != FALSE)
2066 return QUIT_PAGE;
2067
2068 break;
2069 }
2070 else if (Cancel != FALSE)
2071 {
2072 return SELECT_PARTITION_PAGE;
2073 }
2074 else
2075 {
2076 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2077
2078 if (PartSize < 1)
2079 {
2080 /* Too small */
2081 continue;
2082 }
2083
2084 if (PartSize > MaxSize)
2085 {
2086 /* Too large */
2087 continue;
2088 }
2089
2090 /* Convert to bytes */
2091 if (PartSize == MaxSize)
2092 {
2093 /* Use all of the unpartitioned disk space */
2094 SectorCount = PartEntry->SectorCount.QuadPart;
2095 }
2096 else
2097 {
2098 /* Calculate the sector count from the size in MB */
2099 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2100
2101 /* But never get larger than the unpartitioned disk space */
2102 if (SectorCount > PartEntry->SectorCount.QuadPart)
2103 SectorCount = PartEntry->SectorCount.QuadPart;
2104 }
2105
2106 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2107
2108 CreatePrimaryPartition(PartitionList,
2109 SectorCount,
2110 FALSE);
2111
2112 return SELECT_PARTITION_PAGE;
2113 }
2114 }
2115
2116 return CREATE_PRIMARY_PARTITION_PAGE;
2117 }
2118
2119
2120 /*
2121 * Displays the CreateExtendedPartitionPage.
2122 *
2123 * Next pages:
2124 * SelectPartitionPage (default)
2125 * QuitPage
2126 *
2127 * RETURNS
2128 * Number of the next page.
2129 */
2130 static PAGE_NUMBER
2131 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2132 {
2133 PDISKENTRY DiskEntry;
2134 PPARTENTRY PartEntry;
2135 BOOLEAN Quit;
2136 BOOLEAN Cancel;
2137 WCHAR InputBuffer[50];
2138 ULONG MaxSize;
2139 ULONGLONG PartSize;
2140 ULONGLONG DiskSize;
2141 ULONGLONG SectorCount;
2142 PCHAR Unit;
2143
2144 if (PartitionList == NULL ||
2145 PartitionList->CurrentDisk == NULL ||
2146 PartitionList->CurrentPartition == NULL)
2147 {
2148 /* FIXME: show an error dialog */
2149 return QUIT_PAGE;
2150 }
2151
2152 DiskEntry = PartitionList->CurrentDisk;
2153 PartEntry = PartitionList->CurrentPartition;
2154
2155 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2156
2157 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2158
2159 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2160 #if 0
2161 if (DiskSize >= 10737418240) /* 10 GB */
2162 {
2163 DiskSize = DiskSize / 1073741824;
2164 Unit = MUIGetString(STRING_GB);
2165 }
2166 else
2167 #endif
2168 {
2169 DiskSize = DiskSize / 1048576;
2170 if (DiskSize == 0)
2171 DiskSize = 1;
2172
2173 Unit = MUIGetString(STRING_MB);
2174 }
2175
2176 if (DiskEntry->DriverName.Length > 0)
2177 {
2178 CONSOLE_PrintTextXY(6, 10,
2179 MUIGetString(STRING_HDINFOPARTCREATE_1),
2180 DiskSize,
2181 Unit,
2182 DiskEntry->DiskNumber,
2183 DiskEntry->Port,
2184 DiskEntry->Bus,
2185 DiskEntry->Id,
2186 &DiskEntry->DriverName,
2187 DiskEntry->NoMbr ? "GPT" : "MBR");
2188 }
2189 else
2190 {
2191 CONSOLE_PrintTextXY(6, 10,
2192 MUIGetString(STRING_HDINFOPARTCREATE_2),
2193 DiskSize,
2194 Unit,
2195 DiskEntry->DiskNumber,
2196 DiskEntry->Port,
2197 DiskEntry->Bus,
2198 DiskEntry->Id,
2199 DiskEntry->NoMbr ? "GPT" : "MBR");
2200 }
2201
2202 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2203
2204 #if 0
2205 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2206 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2207 #endif
2208
2209 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2210
2211 PartEntry = PartitionList->CurrentPartition;
2212 while (TRUE)
2213 {
2214 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2215
2216 if (MaxSize > PARTITION_MAXSIZE)
2217 MaxSize = PARTITION_MAXSIZE;
2218
2219 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2220 MaxSize, InputBuffer, &Quit, &Cancel);
2221
2222 if (Quit != FALSE)
2223 {
2224 if (ConfirmQuit(Ir) != FALSE)
2225 return QUIT_PAGE;
2226
2227 break;
2228 }
2229 else if (Cancel != FALSE)
2230 {
2231 return SELECT_PARTITION_PAGE;
2232 }
2233 else
2234 {
2235 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2236
2237 if (PartSize < 1)
2238 {
2239 /* Too small */
2240 continue;
2241 }
2242
2243 if (PartSize > MaxSize)
2244 {
2245 /* Too large */
2246 continue;
2247 }
2248
2249 /* Convert to bytes */
2250 if (PartSize == MaxSize)
2251 {
2252 /* Use all of the unpartitioned disk space */
2253 SectorCount = PartEntry->SectorCount.QuadPart;
2254 }
2255 else
2256 {
2257 /* Calculate the sector count from the size in MB */
2258 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2259
2260 /* But never get larger than the unpartitioned disk space */
2261 if (SectorCount > PartEntry->SectorCount.QuadPart)
2262 SectorCount = PartEntry->SectorCount.QuadPart;
2263 }
2264
2265 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2266
2267 CreateExtendedPartition(PartitionList,
2268 SectorCount);
2269
2270 return SELECT_PARTITION_PAGE;
2271 }
2272 }
2273
2274 return CREATE_EXTENDED_PARTITION_PAGE;
2275 }
2276
2277
2278 /*
2279 * Displays the CreateLogicalPartitionPage.
2280 *
2281 * Next pages:
2282 * SelectFileSystemPage (default)
2283 * QuitPage
2284 *
2285 * RETURNS
2286 * Number of the next page.
2287 */
2288 static PAGE_NUMBER
2289 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2290 {
2291 PDISKENTRY DiskEntry;
2292 PPARTENTRY PartEntry;
2293 BOOLEAN Quit;
2294 BOOLEAN Cancel;
2295 WCHAR InputBuffer[50];
2296 ULONG MaxSize;
2297 ULONGLONG PartSize;
2298 ULONGLONG DiskSize;
2299 ULONGLONG SectorCount;
2300 PCHAR Unit;
2301
2302 if (PartitionList == NULL ||
2303 PartitionList->CurrentDisk == NULL ||
2304 PartitionList->CurrentPartition == NULL)
2305 {
2306 /* FIXME: show an error dialog */
2307 return QUIT_PAGE;
2308 }
2309
2310 DiskEntry = PartitionList->CurrentDisk;
2311 PartEntry = PartitionList->CurrentPartition;
2312
2313 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2314
2315 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2316
2317 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2318 #if 0
2319 if (DiskSize >= 10737418240) /* 10 GB */
2320 {
2321 DiskSize = DiskSize / 1073741824;
2322 Unit = MUIGetString(STRING_GB);
2323 }
2324 else
2325 #endif
2326 {
2327 DiskSize = DiskSize / 1048576;
2328 if (DiskSize == 0)
2329 DiskSize = 1;
2330
2331 Unit = MUIGetString(STRING_MB);
2332 }
2333
2334 if (DiskEntry->DriverName.Length > 0)
2335 {
2336 CONSOLE_PrintTextXY(6, 10,
2337 MUIGetString(STRING_HDINFOPARTCREATE_1),
2338 DiskSize,
2339 Unit,
2340 DiskEntry->DiskNumber,
2341 DiskEntry->Port,
2342 DiskEntry->Bus,
2343 DiskEntry->Id,
2344 &DiskEntry->DriverName,
2345 DiskEntry->NoMbr ? "GPT" : "MBR");
2346 }
2347 else
2348 {
2349 CONSOLE_PrintTextXY(6, 10,
2350 MUIGetString(STRING_HDINFOPARTCREATE_2),
2351 DiskSize,
2352 Unit,
2353 DiskEntry->DiskNumber,
2354 DiskEntry->Port,
2355 DiskEntry->Bus,
2356 DiskEntry->Id,
2357 DiskEntry->NoMbr ? "GPT" : "MBR");
2358 }
2359
2360 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2361
2362 #if 0
2363 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2364 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2365 #endif
2366
2367 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2368
2369 PartEntry = PartitionList->CurrentPartition;
2370 while (TRUE)
2371 {
2372 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2373
2374 if (MaxSize > PARTITION_MAXSIZE)
2375 MaxSize = PARTITION_MAXSIZE;
2376
2377 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2378 MaxSize, InputBuffer, &Quit, &Cancel);
2379
2380 if (Quit != FALSE)
2381 {
2382 if (ConfirmQuit(Ir) != FALSE)
2383 return QUIT_PAGE;
2384
2385 break;
2386 }
2387 else if (Cancel != FALSE)
2388 {
2389 return SELECT_PARTITION_PAGE;
2390 }
2391 else
2392 {
2393 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2394
2395 if (PartSize < 1)
2396 {
2397 /* Too small */
2398 continue;
2399 }
2400
2401 if (PartSize > MaxSize)
2402 {
2403 /* Too large */
2404 continue;
2405 }
2406
2407 /* Convert to bytes */
2408 if (PartSize == MaxSize)
2409 {
2410 /* Use all of the unpartitioned disk space */
2411 SectorCount = PartEntry->SectorCount.QuadPart;
2412 }
2413 else
2414 {
2415 /* Calculate the sector count from the size in MB */
2416 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2417
2418 /* But never get larger than the unpartitioned disk space */
2419 if (SectorCount > PartEntry->SectorCount.QuadPart)
2420 SectorCount = PartEntry->SectorCount.QuadPart;
2421 }
2422
2423 DPRINT("Partition size: %I64u bytes\n", PartSize);
2424
2425 CreateLogicalPartition(PartitionList,
2426 SectorCount,
2427 FALSE);
2428
2429 return SELECT_PARTITION_PAGE;
2430 }
2431 }
2432
2433 return CREATE_LOGICAL_PARTITION_PAGE;
2434 }
2435
2436
2437 /*
2438 * Displays the ConfirmDeleteSystemPartitionPage.
2439 *
2440 * Next pages:
2441 * DeletePartitionPage (default)
2442 * SelectPartitionPage
2443 *
2444 * RETURNS
2445 * Number of the next page.
2446 */
2447 static PAGE_NUMBER
2448 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2449 {
2450 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2451
2452 while (TRUE)
2453 {
2454 CONSOLE_ConInKey(Ir);
2455
2456 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2457 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2458 {
2459 if (ConfirmQuit(Ir) == TRUE)
2460 return QUIT_PAGE;
2461
2462 break;
2463 }
2464 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2465 {
2466 return DELETE_PARTITION_PAGE;
2467 }
2468 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2469 {
2470 return SELECT_PARTITION_PAGE;
2471 }
2472 }
2473
2474 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2475 }
2476
2477
2478 /*
2479 * Displays the DeletePartitionPage.
2480 *
2481 * Next pages:
2482 * SelectPartitionPage (default)
2483 * QuitPage
2484 *
2485 * RETURNS
2486 * Number of the next page.
2487 */
2488 static PAGE_NUMBER
2489 DeletePartitionPage(PINPUT_RECORD Ir)
2490 {
2491 PDISKENTRY DiskEntry;
2492 PPARTENTRY PartEntry;
2493 ULONGLONG DiskSize;
2494 ULONGLONG PartSize;
2495 PCHAR Unit;
2496 CHAR PartTypeString[32];
2497
2498 if (PartitionList == NULL ||
2499 PartitionList->CurrentDisk == NULL ||
2500 PartitionList->CurrentPartition == NULL)
2501 {
2502 /* FIXME: show an error dialog */
2503 return QUIT_PAGE;
2504 }
2505
2506 DiskEntry = PartitionList->CurrentDisk;
2507 PartEntry = PartitionList->CurrentPartition;
2508
2509 MUIDisplayPage(DELETE_PARTITION_PAGE);
2510
2511 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2512 PartTypeString,
2513 ARRAYSIZE(PartTypeString));
2514
2515 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2516 #if 0
2517 if (PartSize >= 10737418240) /* 10 GB */
2518 {
2519 PartSize = PartSize / 1073741824;
2520 Unit = MUIGetString(STRING_GB);
2521 }
2522 else
2523 #endif
2524 if (PartSize >= 10485760) /* 10 MB */
2525 {
2526 PartSize = PartSize / 1048576;
2527 Unit = MUIGetString(STRING_MB);
2528 }
2529 else
2530 {
2531 PartSize = PartSize / 1024;
2532 Unit = MUIGetString(STRING_KB);
2533 }
2534
2535 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2536 {
2537 CONSOLE_PrintTextXY(6, 10,
2538 MUIGetString(STRING_HDDINFOUNK2),
2539 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2540 (PartEntry->DriveLetter == 0) ? '-' : ':',
2541 PartEntry->PartitionType,
2542 PartSize,
2543 Unit);
2544 }
2545 else
2546 {
2547 CONSOLE_PrintTextXY(6, 10,
2548 " %c%c %s %I64u %s",
2549 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2550 (PartEntry->DriveLetter == 0) ? '-' : ':',
2551 PartTypeString,
2552 PartSize,
2553 Unit);
2554 }
2555
2556 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2557 #if 0
2558 if (DiskSize >= 10737418240) /* 10 GB */
2559 {
2560 DiskSize = DiskSize / 1073741824;
2561 Unit = MUIGetString(STRING_GB);
2562 }
2563 else
2564 #endif
2565 {
2566 DiskSize = DiskSize / 1048576;
2567 if (DiskSize == 0)
2568 DiskSize = 1;
2569
2570 Unit = MUIGetString(STRING_MB);
2571 }
2572
2573 if (DiskEntry->DriverName.Length > 0)
2574 {
2575 CONSOLE_PrintTextXY(6, 12,
2576 MUIGetString(STRING_HDINFOPARTDELETE_1),
2577 DiskSize,
2578 Unit,
2579 DiskEntry->DiskNumber,
2580 DiskEntry->Port,
2581 DiskEntry->Bus,
2582 DiskEntry->Id,
2583 &DiskEntry->DriverName,
2584 DiskEntry->NoMbr ? "GPT" : "MBR");
2585 }
2586 else
2587 {
2588 CONSOLE_PrintTextXY(6, 12,
2589 MUIGetString(STRING_HDINFOPARTDELETE_2),
2590 DiskSize,
2591 Unit,
2592 DiskEntry->DiskNumber,
2593 DiskEntry->Port,
2594 DiskEntry->Bus,
2595 DiskEntry->Id,
2596 DiskEntry->NoMbr ? "GPT" : "MBR");
2597 }
2598
2599 while (TRUE)
2600 {
2601 CONSOLE_ConInKey(Ir);
2602
2603 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2604 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2605 {
2606 if (ConfirmQuit(Ir) != FALSE)
2607 return QUIT_PAGE;
2608
2609 break;
2610 }
2611 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2612 {
2613 return SELECT_PARTITION_PAGE;
2614 }
2615 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2616 {
2617 DeleteCurrentPartition(PartitionList);
2618
2619 return SELECT_PARTITION_PAGE;
2620 }
2621 }
2622
2623 return DELETE_PARTITION_PAGE;
2624 }
2625
2626
2627 /*
2628 * Displays the SelectFileSystemPage.
2629 *
2630 * Next pages:
2631 * CheckFileSystemPage (At once if RepairUpdate is selected)
2632 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2633 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2634 * SelectPartitionPage (If the user aborts)
2635 * FormatPartitionPage (Default)
2636 * QuitPage
2637 *
2638 * SIDEEFFECTS
2639 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2640 * Calls CheckActiveSystemPartition()
2641 *
2642 * RETURNS
2643 * Number of the next page.
2644 */
2645 static PAGE_NUMBER
2646 SelectFileSystemPage(PINPUT_RECORD Ir)
2647 {
2648 PDISKENTRY DiskEntry;
2649 PPARTENTRY PartEntry;
2650 ULONGLONG DiskSize;
2651 ULONGLONG PartSize;
2652 PCHAR DiskUnit;
2653 PCHAR PartUnit;
2654 CHAR PartTypeString[32];
2655 FORMATMACHINESTATE PreviousFormatState;
2656
2657 DPRINT("SelectFileSystemPage()\n");
2658
2659 if (PartitionList == NULL ||
2660 PartitionList->CurrentDisk == NULL ||
2661 PartitionList->CurrentPartition == NULL)
2662 {
2663 /* FIXME: show an error dialog */
2664 return QUIT_PAGE;
2665 }
2666
2667 /* Find or set the active system partition */
2668 CheckActiveSystemPartition(PartitionList);
2669 if (PartitionList->SystemPartition == NULL)
2670 {
2671 /* FIXME: show an error dialog */
2672 //
2673 // Error dialog should say that we cannot find a suitable
2674 // system partition and create one on the system. At this point,
2675 // it may be nice to ask the user whether he wants to continue,
2676 // or use an external drive as the system drive/partition
2677 // (e.g. floppy, USB drive, etc...)
2678 //
2679 return QUIT_PAGE;
2680 }
2681
2682 PreviousFormatState = FormatState;
2683 switch (FormatState)
2684 {
2685 case Start:
2686 {
2687 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2688 {
2689 TempPartition = PartitionList->SystemPartition;
2690 TempPartition->NeedsCheck = TRUE;
2691
2692 FormatState = FormatSystemPartition;
2693 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2694 }
2695 else
2696 {
2697 TempPartition = PartitionList->CurrentPartition;
2698 TempPartition->NeedsCheck = TRUE;
2699
2700 FormatState = FormatInstallPartition;
2701 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2702 }
2703 break;
2704 }
2705
2706 case FormatSystemPartition:
2707 {
2708 TempPartition = PartitionList->CurrentPartition;
2709 TempPartition->NeedsCheck = TRUE;
2710
2711 FormatState = FormatInstallPartition;
2712 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2713 break;
2714 }
2715
2716 case FormatInstallPartition:
2717 {
2718 if (GetNextUnformattedPartition(PartitionList,
2719 NULL,
2720 &TempPartition))
2721 {
2722 FormatState = FormatOtherPartition;
2723 TempPartition->NeedsCheck = TRUE;
2724 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2725 }
2726 else
2727 {
2728 FormatState = FormatDone;
2729 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2730 return CHECK_FILE_SYSTEM_PAGE;
2731 }
2732 break;
2733 }
2734
2735 case FormatOtherPartition:
2736 {
2737 if (GetNextUnformattedPartition(PartitionList,
2738 NULL,
2739 &TempPartition))
2740 {
2741 FormatState = FormatOtherPartition;
2742 TempPartition->NeedsCheck = TRUE;
2743 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2744 }
2745 else
2746 {
2747 FormatState = FormatDone;
2748 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2749 return CHECK_FILE_SYSTEM_PAGE;
2750 }
2751 break;
2752 }
2753
2754 default:
2755 {
2756 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2757 /* FIXME: show an error dialog */
2758 return QUIT_PAGE;
2759 }
2760 }
2761
2762 PartEntry = TempPartition;
2763 DiskEntry = PartEntry->DiskEntry;
2764
2765 /* Adjust disk size */
2766 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2767 if (DiskSize >= 10737418240) /* 10 GB */
2768 {
2769 DiskSize = DiskSize / 1073741824;
2770 DiskUnit = MUIGetString(STRING_GB);
2771 }
2772 else
2773 {
2774 DiskSize = DiskSize / 1048576;
2775 DiskUnit = MUIGetString(STRING_MB);
2776 }
2777
2778 /* Adjust partition size */
2779 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2780 if (PartSize >= 10737418240) /* 10 GB */
2781 {
2782 PartSize = PartSize / 1073741824;
2783 PartUnit = MUIGetString(STRING_GB);
2784 }
2785 else
2786 {
2787 PartSize = PartSize / 1048576;
2788 PartUnit = MUIGetString(STRING_MB);
2789 }
2790
2791 /* Adjust partition type */
2792 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2793 PartTypeString,
2794 ARRAYSIZE(PartTypeString));
2795
2796 if (PartEntry->AutoCreate != FALSE)
2797 {
2798 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2799
2800 #if 0
2801 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2802 PartEntry->PartitionNumber,
2803 PartSize,
2804 PartUnit,
2805 PartTypeString);
2806 #endif
2807
2808 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2809 DiskEntry->DiskNumber,
2810 DiskSize,
2811 DiskUnit,
2812 DiskEntry->Port,
2813 DiskEntry->Bus,
2814 DiskEntry->Id,
2815 &DiskEntry->DriverName,
2816 DiskEntry->NoMbr ? "GPT" : "MBR");
2817
2818 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2819
2820 PartEntry->AutoCreate = FALSE;
2821 }
2822 else if (PartEntry->New != FALSE)
2823 {
2824 switch (FormatState)
2825 {
2826 case FormatSystemPartition:
2827 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2828 break;
2829
2830 case FormatInstallPartition:
2831 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2832 break;
2833
2834 case FormatOtherPartition:
2835 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2836 break;
2837
2838 default:
2839 break;
2840 }
2841
2842 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2843 }
2844 else
2845 {
2846 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2847
2848 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2849 {
2850 CONSOLE_PrintTextXY(8, 10,
2851 MUIGetString(STRING_HDDINFOUNK4),
2852 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2853 (PartEntry->DriveLetter == 0) ? '-' : ':',
2854 PartEntry->PartitionType,
2855 PartSize,
2856 PartUnit);
2857 }
2858 else
2859 {
2860 CONSOLE_PrintTextXY(8, 10,
2861 "%c%c %s %I64u %s",
2862 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2863 (PartEntry->DriveLetter == 0) ? '-' : ':',
2864 PartTypeString,
2865 PartSize,
2866 PartUnit);
2867 }
2868
2869 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
2870 DiskEntry->DiskNumber,
2871 DiskSize,
2872 DiskUnit,
2873 DiskEntry->Port,
2874 DiskEntry->Bus,
2875 DiskEntry->Id,
2876 &DiskEntry->DriverName,
2877 DiskEntry->NoMbr ? "GPT" : "MBR");
2878 }
2879
2880 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2881
2882 if (FileSystemList == NULL)
2883 {
2884 /* Create the file system list, and by default select the "FAT" file system */
2885 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2886 if (FileSystemList == NULL)
2887 {
2888 /* FIXME: show an error dialog */
2889 return QUIT_PAGE;
2890 }
2891 }
2892
2893 if (RepairUpdateFlag)
2894 {
2895 return CHECK_FILE_SYSTEM_PAGE;
2896 //return SELECT_PARTITION_PAGE;
2897 }
2898
2899 if (IsUnattendedSetup)
2900 {
2901 if (UnattendFormatPartition)
2902 {
2903 /*
2904 * We use whatever currently selected file system we have
2905 * (by default, this is "FAT", as per the initialization
2906 * performed above). Note that it may be interesting to specify
2907 * which file system to use in unattended installations, in the
2908 * txtsetup.sif file.
2909 */
2910 return FORMAT_PARTITION_PAGE;
2911 }
2912
2913 return CHECK_FILE_SYSTEM_PAGE;
2914 }
2915
2916 DrawFileSystemList(FileSystemList);
2917
2918 while (TRUE)
2919 {
2920 CONSOLE_ConInKey(Ir);
2921
2922 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2923 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2924 {
2925 if (ConfirmQuit(Ir) != FALSE)
2926 return QUIT_PAGE;
2927
2928 break;
2929 }
2930 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2931 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2932 {
2933 FormatState = Start;
2934 return SELECT_PARTITION_PAGE;
2935 }
2936 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2937 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2938 {
2939 ScrollDownFileSystemList(FileSystemList);
2940 }
2941 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2942 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2943 {
2944 ScrollUpFileSystemList(FileSystemList);
2945 }
2946 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2947 {
2948 if (!FileSystemList->Selected->FileSystem)
2949 return SELECT_FILE_SYSTEM_PAGE;
2950 else
2951 return FORMAT_PARTITION_PAGE;
2952 }
2953 }
2954
2955 FormatState = PreviousFormatState;
2956
2957 return SELECT_FILE_SYSTEM_PAGE;
2958 }
2959
2960
2961 /*
2962 * Displays the FormatPartitionPage.
2963 *
2964 * Next pages:
2965 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2966 * SelectPartitionPage (At once)
2967 * QuitPage
2968 *
2969 * SIDEEFFECTS
2970 * Sets PartitionList->CurrentPartition->FormatState
2971 * Sets DestinationRootPath
2972 *
2973 * RETURNS
2974 * Number of the next page.
2975 */
2976 static PAGE_NUMBER
2977 FormatPartitionPage(PINPUT_RECORD Ir)
2978 {
2979 UNICODE_STRING PartitionRootPath;
2980 WCHAR PathBuffer[MAX_PATH];
2981 PDISKENTRY DiskEntry;
2982 PPARTENTRY PartEntry;
2983 PFILE_SYSTEM_ITEM SelectedFileSystem;
2984 NTSTATUS Status;
2985
2986 #ifndef NDEBUG
2987 ULONG Line;
2988 ULONG i;
2989 PPARTITION_INFORMATION PartitionInfo;
2990 #endif
2991
2992 DPRINT("FormatPartitionPage()\n");
2993
2994 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2995
2996 if (PartitionList == NULL || TempPartition == NULL)
2997 {
2998 /* FIXME: show an error dialog */
2999 return QUIT_PAGE;
3000 }
3001
3002 PartEntry = TempPartition;
3003 DiskEntry = PartEntry->DiskEntry;
3004
3005 SelectedFileSystem = FileSystemList->Selected;
3006
3007 while (TRUE)
3008 {
3009 if (!IsUnattendedSetup)
3010 {
3011 CONSOLE_ConInKey(Ir);
3012 }
3013
3014 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3015 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3016 {
3017 if (ConfirmQuit(Ir) != FALSE)
3018 return QUIT_PAGE;
3019
3020 break;
3021 }
3022 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3023 {
3024 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3025
3026 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
3027 {
3028 /* FIXME: show an error dialog */
3029 return QUIT_PAGE;
3030 }
3031
3032 #ifndef NDEBUG
3033 CONSOLE_PrintTextXY(6, 12,
3034 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3035 DiskEntry->Cylinders,
3036 DiskEntry->TracksPerCylinder,
3037 DiskEntry->SectorsPerTrack,
3038 DiskEntry->BytesPerSector,
3039 DiskEntry->Dirty ? '*' : ' ');
3040
3041 Line = 13;
3042
3043 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3044 {
3045 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3046
3047 CONSOLE_PrintTextXY(6, Line,
3048 "%2u: %2lu %c %12I64u %12I64u %02x",
3049 i,
3050 PartitionInfo->PartitionNumber,
3051 PartitionInfo->BootIndicator ? 'A' : '-',
3052 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3053 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3054 PartitionInfo->PartitionType);
3055 Line++;
3056 }
3057 #endif
3058
3059 /* Commit the partition changes to the disk */
3060 if (!WritePartitionsToDisk(PartitionList))
3061 {
3062 DPRINT("WritePartitionsToDisk() failed\n");
3063 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3064 return QUIT_PAGE;
3065 }
3066
3067 /* Set PartitionRootPath */
3068 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3069 L"\\Device\\Harddisk%lu\\Partition%lu",
3070 DiskEntry->DiskNumber,
3071 PartEntry->PartitionNumber);
3072 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3073 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3074
3075 /* Format the partition */
3076 if (SelectedFileSystem->FileSystem)
3077 {
3078 Status = FormatPartition(&PartitionRootPath,
3079 SelectedFileSystem);
3080 if (!NT_SUCCESS(Status))
3081 {
3082 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3083 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3084 return QUIT_PAGE;
3085 }
3086
3087 PartEntry->FormatState = Formatted;
3088 // PartEntry->FileSystem = FileSystem;
3089 PartEntry->New = FALSE;
3090 }
3091
3092 #ifndef NDEBUG
3093 CONSOLE_SetStatusText(" Done. Press any key ...");
3094 CONSOLE_ConInKey(Ir);
3095 #endif
3096
3097 return SELECT_FILE_SYSTEM_PAGE;
3098 }
3099 }
3100
3101 return FORMAT_PARTITION_PAGE;
3102 }
3103
3104
3105 /*
3106 * Displays the CheckFileSystemPage.
3107 *
3108 * Next pages:
3109 * InstallDirectoryPage (At once)
3110 * QuitPage
3111 *
3112 * SIDEEFFECTS
3113 * Inits or reloads FileSystemList
3114 *
3115 * RETURNS
3116 * Number of the next page.
3117 */
3118 static PAGE_NUMBER
3119 CheckFileSystemPage(PINPUT_RECORD Ir)
3120 {
3121 PFILE_SYSTEM CurrentFileSystem;
3122 UNICODE_STRING PartitionRootPath;
3123 WCHAR PathBuffer[MAX_PATH];
3124 CHAR Buffer[MAX_PATH];
3125 PDISKENTRY DiskEntry;
3126 PPARTENTRY PartEntry;
3127 NTSTATUS Status;
3128
3129 if (PartitionList == NULL)
3130 {
3131 /* FIXME: show an error dialog */
3132 return QUIT_PAGE;
3133 }
3134
3135 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3136 {
3137 return INSTALL_DIRECTORY_PAGE;
3138 }
3139
3140 /* Set PartitionRootPath */
3141 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3142 L"\\Device\\Harddisk%lu\\Partition%lu",
3143 DiskEntry->DiskNumber,
3144 PartEntry->PartitionNumber);
3145 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3146 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3147
3148 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3149
3150 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3151
3152 CurrentFileSystem = PartEntry->FileSystem;
3153 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3154 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3155
3156 /* HACK: Do not try to check a partition with an unknown filesystem */
3157 if (CurrentFileSystem == NULL)
3158 {
3159 PartEntry->NeedsCheck = FALSE;
3160 return CHECK_FILE_SYSTEM_PAGE;
3161 }
3162
3163 if (CurrentFileSystem->ChkdskFunc == NULL)
3164 {
3165 sprintf(Buffer,
3166 "Setup is currently unable to check a partition formatted in %S.\n"
3167 "\n"
3168 " \x07 Press ENTER to continue Setup.\n"
3169 " \x07 Press F3 to quit Setup.",
3170 CurrentFileSystem->FileSystemName);
3171
3172 PopupError(Buffer,
3173 MUIGetString(STRING_QUITCONTINUE),
3174 NULL, POPUP_WAIT_NONE);
3175
3176 while (TRUE)
3177 {
3178 CONSOLE_ConInKey(Ir);
3179
3180 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3181 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3182 {
3183 if (ConfirmQuit(Ir))
3184 return QUIT_PAGE;
3185 else
3186 return CHECK_FILE_SYSTEM_PAGE;
3187 }
3188 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3189 {
3190 PartEntry->NeedsCheck = FALSE;
3191 return CHECK_FILE_SYSTEM_PAGE;
3192 }
3193 }
3194 }
3195 else
3196 {
3197 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3198 if (!NT_SUCCESS(Status))
3199 {
3200 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3201 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3202 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3203 "(Status 0x%08lx).\n", Status);
3204 PopupError(Buffer,
3205 // MUIGetString(STRING_REBOOTCOMPUTER),
3206 MUIGetString(STRING_CONTINUE),
3207 Ir, POPUP_WAIT_ENTER);
3208
3209 // return QUIT_PAGE;
3210 }
3211
3212 PartEntry->NeedsCheck = FALSE;
3213 return CHECK_FILE_SYSTEM_PAGE;
3214 }
3215 }
3216
3217
3218 static VOID
3219 BuildInstallPaths(PWSTR InstallDir,
3220 PDISKENTRY DiskEntry,
3221 PPARTENTRY PartEntry)
3222 {
3223 WCHAR PathBuffer[MAX_PATH];
3224
3225 /* Create 'InstallPath' string */
3226 RtlFreeUnicodeString(&InstallPath);
3227 RtlCreateUnicodeString(&InstallPath, InstallDir);
3228
3229 /* Create 'DestinationRootPath' string */
3230 RtlFreeUnicodeString(&DestinationRootPath);
3231 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3232 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3233 DiskEntry->DiskNumber,
3234 PartEntry->PartitionNumber);
3235 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
3236 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
3237
3238 /* Create 'DestinationPath' string */
3239 RtlFreeUnicodeString(&DestinationPath);
3240 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3241 DestinationRootPath.Buffer, InstallDir);
3242 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
3243
3244 /* Create 'DestinationArcPath' */
3245 RtlFreeUnicodeString(&DestinationArcPath);
3246 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3247 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3248 DiskEntry->BiosDiskNumber,
3249 PartEntry->PartitionNumber);
3250 ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
3251 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
3252
3253 /* Initialize DestinationDriveLetter */
3254 DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
3255 }
3256
3257
3258 /*
3259 * Displays the InstallDirectoryPage.
3260 *
3261 * Next pages:
3262 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3263 * QuitPage
3264 *
3265 * RETURNS
3266 * Number of the next page.
3267 */
3268 static PAGE_NUMBER
3269 InstallDirectoryPage(PINPUT_RECORD Ir)
3270 {
3271 PDISKENTRY DiskEntry;
3272 PPARTENTRY PartEntry;
3273 WCHAR InstallDir[51];
3274 WCHAR c;
3275 ULONG Length, Pos;
3276
3277 /* We do not need the filesystem list any more */
3278 if (FileSystemList != NULL)
3279 {
3280 DestroyFileSystemList(FileSystemList);
3281 FileSystemList = NULL;
3282 }
3283
3284 if (PartitionList == NULL ||
3285 PartitionList->CurrentDisk == NULL ||
3286 PartitionList->CurrentPartition == NULL)
3287 {
3288 /* FIXME: show an error dialog */
3289 return QUIT_PAGE;
3290 }
3291
3292 DiskEntry = PartitionList->CurrentDisk;
3293 PartEntry = PartitionList->CurrentPartition;
3294
3295 #if 0
3296 if (RepairUpdateFlag)
3297 {
3298 if (!IsValidPath(CurrentInstallation->PathComponent)) // SystemNtPath
3299 {
3300 /* FIXME: Log the error? */
3301 return QUIT_PAGE;
3302 }
3303
3304 BuildInstallPaths(CurrentInstallation->PathComponent, // SystemNtPath
3305 DiskEntry,
3306 PartEntry);
3307
3308 return PREPARE_COPY_PAGE;
3309 }
3310 #endif
3311 if (IsUnattendedSetup)
3312 {
3313 if (!IsValidPath(UnattendInstallationDirectory))
3314 {
3315 /* FIXME: Log the error? */
3316 return QUIT_PAGE;
3317 }
3318
3319 BuildInstallPaths(UnattendInstallationDirectory,
3320 DiskEntry,
3321 PartEntry);
3322
3323 return PREPARE_COPY_PAGE;
3324 }
3325
3326 wcscpy(InstallDir, L"\\ReactOS");
3327
3328 Length = wcslen(InstallDir);
3329 Pos = Length;
3330 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3331 CONSOLE_SetCursorXY(8 + Pos, 11);
3332 CONSOLE_SetCursorType(TRUE, TRUE);
3333 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3334
3335 while (TRUE)
3336 {
3337 CONSOLE_ConInKey(Ir);
3338
3339 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3340 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3341 {
3342 CONSOLE_SetCursorType(TRUE, FALSE);
3343
3344 if (ConfirmQuit(Ir) != FALSE)
3345 return QUIT_PAGE;
3346
3347 CONSOLE_SetCursorType(TRUE, TRUE);
3348 break;
3349 }
3350 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3351 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3352 {
3353 if (Pos < Length)
3354 {
3355 memmove(&InstallDir[Pos],
3356 &InstallDir[Pos + 1],
3357 (Length - Pos - 1) * sizeof(WCHAR));
3358 InstallDir[Length - 1] = UNICODE_NULL;
3359
3360 Length--;
3361 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3362 CONSOLE_SetCursorXY(8 + Pos, 11);
3363 }
3364 }
3365 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3366 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3367 {
3368 Pos = 0;
3369 CONSOLE_SetCursorXY(8 + Pos, 11);
3370 }
3371 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3372 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3373 {
3374 Pos = Length;
3375 CONSOLE_SetCursorXY(8 + Pos, 11);
3376 }
3377 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3378 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3379 {
3380 if (Pos > 0)
3381 {
3382 Pos--;
3383 CONSOLE_SetCursorXY(8 + Pos, 11);
3384 }
3385 }
3386 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3387 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3388 {
3389 if (Pos < Length)
3390 {
3391 Pos++;
3392 CONSOLE_SetCursorXY(8 + Pos, 11);
3393 }
3394 }
3395 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3396 {
3397 CONSOLE_SetCursorType(TRUE, FALSE);
3398
3399 /*
3400 * Check for the validity of the installation directory and pop up
3401 * an error if it is not the case. Then the user can fix its input.
3402 */
3403 if (!IsValidPath(InstallDir))
3404 {
3405 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3406 return INSTALL_DIRECTORY_PAGE;
3407 }
3408
3409 BuildInstallPaths(InstallDir,
3410 DiskEntry,
3411 PartEntry);
3412