1461528b88f74387c59d6531e93b9bfe68d1231b
[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
36 #define NDEBUG
37 #include <debug.h>
38
39
40 /* GLOBALS & LOCALS *********************************************************/
41
42 HANDLE ProcessHeap;
43
44 BOOLEAN IsUnattendedSetup = FALSE;
45 static USETUP_DATA USetupData;
46
47 /*
48 * NOTE: Technically only used for the COPYCONTEXT InstallPath member
49 * for the filequeue functionality.
50 */
51 static UNICODE_STRING InstallPath;
52
53 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
54 static WCHAR DestinationDriveLetter;
55
56
57 /* OTHER Stuff *****/
58
59 PCWSTR SelectedLanguageId;
60 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList
61 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList
62
63 static BOOLEAN RepairUpdateFlag = FALSE;
64
65 static HANDLE hPnpThread = NULL;
66
67 static PPARTLIST PartitionList = NULL;
68 static PPARTENTRY TempPartition = NULL;
69 static PFILE_SYSTEM_LIST FileSystemList = NULL;
70 static FORMATMACHINESTATE FormatState = Start;
71
72 /*****************************************************/
73
74 static HINF SetupInf;
75
76 static HSPFILEQ SetupFileQueue = NULL;
77
78 static PNTOS_INSTALLATION CurrentInstallation = NULL;
79 static PGENERIC_LIST NtOsInstallsList = NULL;
80
81 static PGENERIC_LIST ComputerList = NULL;
82 static PGENERIC_LIST DisplayList = NULL;
83 static PGENERIC_LIST KeyboardList = NULL;
84 static PGENERIC_LIST LayoutList = NULL;
85 static PGENERIC_LIST LanguageList = NULL;
86
87
88 /* FUNCTIONS ****************************************************************/
89
90 static VOID
91 PrintString(char* fmt,...)
92 {
93 char buffer[512];
94 va_list ap;
95 UNICODE_STRING UnicodeString;
96 ANSI_STRING AnsiString;
97
98 va_start(ap, fmt);
99 vsprintf(buffer, fmt, ap);
100 va_end(ap);
101
102 RtlInitAnsiString(&AnsiString, buffer);
103 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
104 NtDisplayString(&UnicodeString);
105 RtlFreeUnicodeString(&UnicodeString);
106 }
107
108
109 static VOID
110 DrawBox(IN SHORT xLeft,
111 IN SHORT yTop,
112 IN SHORT Width,
113 IN SHORT Height)
114 {
115 COORD coPos;
116 DWORD Written;
117
118 /* Draw upper left corner */
119 coPos.X = xLeft;
120 coPos.Y = yTop;
121 FillConsoleOutputCharacterA(StdOutput,
122 0xDA, // '+',
123 1,
124 coPos,
125 &Written);
126
127 /* Draw upper edge */
128 coPos.X = xLeft + 1;
129 coPos.Y = yTop;
130 FillConsoleOutputCharacterA(StdOutput,
131 0xC4, // '-',
132 Width - 2,
133 coPos,
134 &Written);
135
136 /* Draw upper right corner */
137 coPos.X = xLeft + Width - 1;
138 coPos.Y = yTop;
139 FillConsoleOutputCharacterA(StdOutput,
140 0xBF, // '+',
141 1,
142 coPos,
143 &Written);
144
145 /* Draw right edge, inner space and left edge */
146 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
147 {
148 coPos.X = xLeft;
149 FillConsoleOutputCharacterA(StdOutput,
150 0xB3, // '|',
151 1,
152 coPos,
153 &Written);
154
155 coPos.X = xLeft + 1;
156 FillConsoleOutputCharacterA(StdOutput,
157 ' ',
158 Width - 2,
159 coPos,
160 &Written);
161
162 coPos.X = xLeft + Width - 1;
163 FillConsoleOutputCharacterA(StdOutput,
164 0xB3, // '|',
165 1,
166 coPos,
167 &Written);
168 }
169
170 /* Draw lower left corner */
171 coPos.X = xLeft;
172 coPos.Y = yTop + Height - 1;
173 FillConsoleOutputCharacterA(StdOutput,
174 0xC0, // '+',
175 1,
176 coPos,
177 &Written);
178
179 /* Draw lower edge */
180 coPos.X = xLeft + 1;
181 coPos.Y = yTop + Height - 1;
182 FillConsoleOutputCharacterA(StdOutput,
183 0xC4, // '-',
184 Width - 2,
185 coPos,
186 &Written);
187
188 /* Draw lower right corner */
189 coPos.X = xLeft + Width - 1;
190 coPos.Y = yTop + Height - 1;
191 FillConsoleOutputCharacterA(StdOutput,
192 0xD9, // '+',
193 1,
194 coPos,
195 &Written);
196 }
197
198
199 VOID
200 PopupError(PCCH Text,
201 PCCH Status,
202 PINPUT_RECORD Ir,
203 ULONG WaitEvent)
204 {
205 SHORT yTop;
206 SHORT xLeft;
207 COORD coPos;
208 DWORD Written;
209 ULONG Length;
210 ULONG MaxLength;
211 ULONG Lines;
212 PCHAR p;
213 PCCH pnext;
214 BOOLEAN LastLine;
215 SHORT Width;
216 SHORT Height;
217
218 /* Count text lines and longest line */
219 MaxLength = 0;
220 Lines = 0;
221 pnext = Text;
222
223 while (TRUE)
224 {
225 p = strchr(pnext, '\n');
226
227 if (p == NULL)
228 {
229 Length = strlen(pnext);
230 LastLine = TRUE;
231 }
232 else
233 {
234 Length = (ULONG)(p - pnext);
235 LastLine = FALSE;
236 }
237
238 Lines++;
239
240 if (Length > MaxLength)
241 MaxLength = Length;
242
243 if (LastLine)
244 break;
245
246 pnext = p + 1;
247 }
248
249 /* Check length of status line */
250 if (Status != NULL)
251 {
252 Length = strlen(Status);
253
254 if (Length > MaxLength)
255 MaxLength = Length;
256 }
257
258 Width = MaxLength + 4;
259 Height = Lines + 2;
260
261 if (Status != NULL)
262 Height += 2;
263
264 yTop = (yScreen - Height) / 2;
265 xLeft = (xScreen - Width) / 2;
266
267
268 /* Set screen attributes */
269 coPos.X = xLeft;
270 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
271 {
272 FillConsoleOutputAttribute(StdOutput,
273 FOREGROUND_RED | BACKGROUND_WHITE,
274 Width,
275 coPos,
276 &Written);
277 }
278
279 DrawBox(xLeft, yTop, Width, Height);
280
281 /* Print message text */
282 coPos.Y = yTop + 1;
283 pnext = Text;
284 while (TRUE)
285 {
286 p = strchr(pnext, '\n');
287
288 if (p == NULL)
289 {
290 Length = strlen(pnext);
291 LastLine = TRUE;
292 }
293 else
294 {
295 Length = (ULONG)(p - pnext);
296 LastLine = FALSE;
297 }
298
299 if (Length != 0)
300 {
301 coPos.X = xLeft + 2;
302 WriteConsoleOutputCharacterA(StdOutput,
303 pnext,
304 Length,
305 coPos,
306 &Written);
307 }
308
309 if (LastLine)
310 break;
311
312 coPos.Y++;
313 pnext = p + 1;
314 }
315
316 /* Print separator line and status text */
317 if (Status != NULL)
318 {
319 coPos.Y = yTop + Height - 3;
320 coPos.X = xLeft;
321 FillConsoleOutputCharacterA(StdOutput,
322 0xC3, // '+',
323 1,
324 coPos,
325 &Written);
326
327 coPos.X = xLeft + 1;
328 FillConsoleOutputCharacterA(StdOutput,
329 0xC4, // '-',
330 Width - 2,
331 coPos,
332 &Written);
333
334 coPos.X = xLeft + Width - 1;
335 FillConsoleOutputCharacterA(StdOutput,
336 0xB4, // '+',
337 1,
338 coPos,
339 &Written);
340
341 coPos.Y++;
342 coPos.X = xLeft + 2;
343 WriteConsoleOutputCharacterA(StdOutput,
344 Status,
345 min(strlen(Status), (SIZE_T)Width - 4),
346 coPos,
347 &Written);
348 }
349
350 if (WaitEvent == POPUP_WAIT_NONE)
351 return;
352
353 while (TRUE)
354 {
355 CONSOLE_ConInKey(Ir);
356
357 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
358 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
359 {
360 return;
361 }
362 }
363 }
364
365
366 /*
367 * Confirm quit setup
368 * RETURNS
369 * TRUE: Quit setup.
370 * FALSE: Don't quit setup.
371 */
372 static BOOL
373 ConfirmQuit(PINPUT_RECORD Ir)
374 {
375 BOOL Result = FALSE;
376 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
377
378 while (TRUE)
379 {
380 CONSOLE_ConInKey(Ir);
381
382 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
383 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
384 {
385 Result = TRUE;
386 break;
387 }
388 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
389 {
390 Result = FALSE;
391 break;
392 }
393 }
394
395 return Result;
396 }
397
398
399 static VOID
400 UpdateKBLayout(VOID)
401 {
402 PGENERIC_LIST_ENTRY ListEntry;
403 PCWSTR pszNewLayout;
404
405 pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
406
407 if (LayoutList == NULL)
408 {
409 LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
410 if (LayoutList == NULL)
411 {
412 /* FIXME: Handle error! */
413 return;
414 }
415 }
416
417 /* Search for default layout (if provided) */
418 if (pszNewLayout != NULL)
419 {
420 for (ListEntry = GetFirstListEntry(LayoutList); ListEntry;
421 ListEntry = GetNextListEntry(ListEntry))
422 {
423 if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
424 {
425 SetCurrentListEntry(LayoutList, ListEntry);
426 break;
427 }
428 }
429 }
430 }
431
432
433 static NTSTATUS
434 NTAPI
435 GetSettingDescription(
436 IN PGENERIC_LIST_ENTRY Entry,
437 OUT PSTR Buffer,
438 IN SIZE_T cchBufferSize)
439 {
440 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
441 ((PGENENTRY)GetListEntryData(Entry))->Value);
442 }
443
444 static NTSTATUS
445 NTAPI
446 GetNTOSInstallationName(
447 IN PGENERIC_LIST_ENTRY Entry,
448 OUT PSTR Buffer,
449 IN SIZE_T cchBufferSize)
450 {
451 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry);
452 PPARTENTRY PartEntry = NtOsInstall->PartEntry;
453
454 if (PartEntry && PartEntry->DriveLetter)
455 {
456 /* We have retrieved a partition that is mounted */
457 return RtlStringCchPrintfA(Buffer, cchBufferSize,
458 "%c:%S \"%S\"",
459 PartEntry->DriveLetter,
460 NtOsInstall->PathComponent,
461 NtOsInstall->InstallationName);
462 }
463 else
464 {
465 /* We failed somewhere, just show the NT path */
466 return RtlStringCchPrintfA(Buffer, cchBufferSize,
467 "%wZ \"%S\"",
468 &NtOsInstall->SystemNtPath,
469 NtOsInstall->InstallationName);
470 }
471 }
472
473
474 /*
475 * Displays the LanguagePage.
476 *
477 * Next pages: WelcomePage, QuitPage
478 *
479 * SIDEEFFECTS
480 * Init SelectedLanguageId
481 * Init USetupData.LanguageId
482 *
483 * RETURNS
484 * Number of the next page.
485 */
486 static PAGE_NUMBER
487 LanguagePage(PINPUT_RECORD Ir)
488 {
489 GENERIC_LIST_UI ListUi;
490 PCWSTR NewLanguageId;
491 BOOL RefreshPage = FALSE;
492
493 /* Initialize the computer settings list */
494 if (LanguageList == NULL)
495 {
496 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
497 if (LanguageList == NULL)
498 {
499 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
500 return WELCOME_PAGE;
501 }
502 }
503
504 SelectedLanguageId = DefaultLanguage;
505 USetupData.LanguageId = 0;
506
507 /* Load the font */
508 SetConsoleCodePage();
509 UpdateKBLayout();
510
511 /*
512 * If there is no language or just a single one in the list,
513 * skip the language selection process altogether.
514 */
515 if (GetNumberOfListEntries(LanguageList) <= 1)
516 {
517 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
518 return WELCOME_PAGE;
519 }
520
521 InitGenericListUi(&ListUi, LanguageList, GetSettingDescription);
522 DrawGenericList(&ListUi,
523 2, 18,
524 xScreen - 3,
525 yScreen - 3);
526
527 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
528
529 MUIDisplayPage(LANGUAGE_PAGE);
530
531 while (TRUE)
532 {
533 CONSOLE_ConInKey(Ir);
534
535 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
536 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
537 {
538 ScrollDownGenericList(&ListUi);
539 RefreshPage = TRUE;
540 }
541 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
542 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
543 {
544 ScrollUpGenericList(&ListUi);
545 RefreshPage = TRUE;
546 }
547 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
548 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
549 {
550 ScrollPageDownGenericList(&ListUi);
551 RefreshPage = TRUE;
552 }
553 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
554 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
555 {
556 ScrollPageUpGenericList(&ListUi);
557 RefreshPage = TRUE;
558 }
559 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
560 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
561 {
562 if (ConfirmQuit(Ir))
563 return QUIT_PAGE;
564 else
565 RedrawGenericList(&ListUi);
566 }
567 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
568 {
569 ASSERT(GetNumberOfListEntries(LanguageList) >= 1);
570
571 SelectedLanguageId =
572 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(LanguageList)))->Id;
573
574 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
575
576 if (wcscmp(SelectedLanguageId, DefaultLanguage))
577 {
578 UpdateKBLayout();
579 }
580
581 /* Load the font */
582 SetConsoleCodePage();
583
584 return WELCOME_PAGE;
585 }
586 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
587 {
588 /* a-z */
589 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
590 RefreshPage = TRUE;
591 }
592
593 if (RefreshPage)
594 {
595 ASSERT(GetNumberOfListEntries(LanguageList) >= 1);
596
597 NewLanguageId =
598 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(LanguageList)))->Id;
599
600 if (wcscmp(SelectedLanguageId, NewLanguageId))
601 {
602 /* Clear the language page */
603 MUIClearPage(LANGUAGE_PAGE);
604
605 SelectedLanguageId = NewLanguageId;
606
607 /* Load the font */
608 SetConsoleCodePage();
609
610 /* Redraw language selection page in native language */
611 MUIDisplayPage(LANGUAGE_PAGE);
612 }
613
614 RefreshPage = FALSE;
615 }
616 }
617
618 return WELCOME_PAGE;
619 }
620
621
622 /*
623 * Start page
624 *
625 * Next pages:
626 * LanguagePage (at once, default)
627 * InstallIntroPage (at once, if unattended)
628 * QuitPage
629 *
630 * SIDEEFFECTS
631 * Init Sdi
632 * Init USetupData.SourcePath
633 * Init USetupData.SourceRootPath
634 * Init USetupData.SourceRootDir
635 * Init SetupInf
636 * Init USetupData.RequiredPartitionDiskSpace
637 * Init IsUnattendedSetup
638 * If unattended, init *List and sets the Codepage
639 * If unattended, init SelectedLanguageId
640 * If unattended, init USetupData.LanguageId
641 *
642 * RETURNS
643 * Number of the next page.
644 */
645 static PAGE_NUMBER
646 SetupStartPage(PINPUT_RECORD Ir)
647 {
648 NTSTATUS Status;
649 ULONG Error;
650 PGENERIC_LIST_ENTRY ListEntry;
651 PCWSTR LocaleId;
652
653 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
654
655 /* Get the source path and source root path */
656 Status = GetSourcePaths(&USetupData.SourcePath,
657 &USetupData.SourceRootPath,
658 &USetupData.SourceRootDir);
659 if (!NT_SUCCESS(Status))
660 {
661 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
662 MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
663 return QUIT_PAGE;
664 }
665 DPRINT1("SourcePath: '%wZ'\n", &USetupData.SourcePath);
666 DPRINT1("SourceRootPath: '%wZ'\n", &USetupData.SourceRootPath);
667 DPRINT1("SourceRootDir: '%wZ'\n", &USetupData.SourceRootDir);
668
669 /* Load 'txtsetup.sif' from the installation media */
670 Error = LoadSetupInf(&SetupInf, &USetupData);
671 if (Error != ERROR_SUCCESS)
672 {
673 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
674 return QUIT_PAGE;
675 }
676
677 /* Start the PnP thread */
678 if (hPnpThread != NULL)
679 {
680 NtResumeThread(hPnpThread, NULL);
681 hPnpThread = NULL;
682 }
683
684 CheckUnattendedSetup(&USetupData);
685
686 if (IsUnattendedSetup)
687 {
688 // TODO: Read options from inf
689 /* Load the hardware, language and keyboard layout lists */
690
691 ComputerList = CreateComputerTypeList(SetupInf);
692 DisplayList = CreateDisplayDriverList(SetupInf);
693 KeyboardList = CreateKeyboardDriverList(SetupInf);
694
695 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
696
697 /* new part */
698 SelectedLanguageId = DefaultLanguage;
699 wcscpy(DefaultLanguage, USetupData.LocaleID);
700 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
701
702 LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
703
704 /* first we hack LanguageList */
705 for (ListEntry = GetFirstListEntry(LanguageList); ListEntry;
706 ListEntry = GetNextListEntry(ListEntry))
707 {
708 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
709 if (!wcsicmp(USetupData.LocaleID, LocaleId))
710 {
711 DPRINT("found %S in LanguageList\n", LocaleId);
712 SetCurrentListEntry(LanguageList, ListEntry);
713 break;
714 }
715 }
716
717 /* now LayoutList */
718 for (ListEntry = GetFirstListEntry(LayoutList); ListEntry;
719 ListEntry = GetNextListEntry(ListEntry))
720 {
721 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
722 if (!wcsicmp(USetupData.LocaleID, LocaleId))
723 {
724 DPRINT("found %S in LayoutList\n", LocaleId);
725 SetCurrentListEntry(LayoutList, ListEntry);
726 break;
727 }
728 }
729
730 SetConsoleCodePage();
731
732 return INSTALL_INTRO_PAGE;
733 }
734
735 return LANGUAGE_PAGE;
736 }
737
738
739 /*
740 * Displays the WelcomePage.
741 *
742 * Next pages:
743 * InstallIntroPage (default)
744 * RepairIntroPage
745 * RecoveryPage
746 * LicensePage
747 * QuitPage
748 *
749 * RETURNS
750 * Number of the next page.
751 */
752 static PAGE_NUMBER
753 WelcomePage(PINPUT_RECORD Ir)
754 {
755 MUIDisplayPage(WELCOME_PAGE);
756
757 while (TRUE)
758 {
759 CONSOLE_ConInKey(Ir);
760
761 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
762 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
763 {
764 if (ConfirmQuit(Ir))
765 return QUIT_PAGE;
766
767 break;
768 }
769 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
770 {
771 return INSTALL_INTRO_PAGE;
772 }
773 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
774 {
775 return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
776 }
777 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
778 {
779 return LICENSE_PAGE;
780 }
781 }
782
783 return WELCOME_PAGE;
784 }
785
786
787 /*
788 * Displays the License page.
789 *
790 * Next page:
791 * WelcomePage (default)
792 *
793 * RETURNS
794 * Number of the next page.
795 */
796 static PAGE_NUMBER
797 LicensePage(PINPUT_RECORD Ir)
798 {
799 MUIDisplayPage(LICENSE_PAGE);
800
801 while (TRUE)
802 {
803 CONSOLE_ConInKey(Ir);
804
805 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
806 {
807 return WELCOME_PAGE;
808 }
809 }
810
811 return LICENSE_PAGE;
812 }
813
814
815 /*
816 * Displays the RepairIntroPage.
817 *
818 * Next pages:
819 * RebootPage (default)
820 * InstallIntroPage
821 * RecoveryPage
822 * IntroPage
823 *
824 * RETURNS
825 * Number of the next page.
826 */
827 static PAGE_NUMBER
828 RepairIntroPage(PINPUT_RECORD Ir)
829 {
830 MUIDisplayPage(REPAIR_INTRO_PAGE);
831
832 while(TRUE)
833 {
834 CONSOLE_ConInKey(Ir);
835
836 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
837 {
838 return REBOOT_PAGE;
839 }
840 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
841 {
842 RepairUpdateFlag = TRUE;
843 return INSTALL_INTRO_PAGE;
844 }
845 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
846 {
847 return RECOVERY_PAGE;
848 }
849 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
850 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
851 {
852 return WELCOME_PAGE;
853 }
854 }
855
856 return REPAIR_INTRO_PAGE;
857 }
858
859 /*
860 * Displays the UpgradeRepairPage.
861 *
862 * Next pages:
863 * RebootPage (default)
864 * InstallIntroPage
865 * RecoveryPage
866 * WelcomePage
867 *
868 * RETURNS
869 * Number of the next page.
870 */
871 static PAGE_NUMBER
872 UpgradeRepairPage(PINPUT_RECORD Ir)
873 {
874 GENERIC_LIST_UI ListUi;
875
876 /*** HACK!! ***/
877 if (PartitionList == NULL)
878 {
879 PartitionList = CreatePartitionList();
880 if (PartitionList == NULL)
881 {
882 /* FIXME: show an error dialog */
883 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
884 return QUIT_PAGE;
885 }
886 else if (IsListEmpty(&PartitionList->DiskListHead))
887 {
888 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
889 return QUIT_PAGE;
890 }
891
892 TempPartition = NULL;
893 FormatState = Start;
894 }
895 /**************/
896
897 NtOsInstallsList = CreateNTOSInstallationsList(PartitionList);
898 if (!NtOsInstallsList)
899 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
900
901 /*
902 * If there is no available installation (or just a single one??) that can
903 * be updated in the list, just continue with the regular installation.
904 */
905 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
906 {
907 RepairUpdateFlag = FALSE;
908
909 // return INSTALL_INTRO_PAGE;
910 return DEVICE_SETTINGS_PAGE;
911 // return SCSI_CONTROLLER_PAGE;
912 }
913
914 MUIDisplayPage(UPGRADE_REPAIR_PAGE);
915
916 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
917 DrawGenericList(&ListUi,
918 2, 23,
919 xScreen - 3,
920 yScreen - 3);
921
922 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
923 while (TRUE)
924 {
925 CONSOLE_ConInKey(Ir);
926
927 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
928 {
929 switch (Ir->Event.KeyEvent.wVirtualKeyCode)
930 {
931 case VK_DOWN: /* DOWN */
932 ScrollDownGenericList(&ListUi);
933 break;
934 case VK_UP: /* UP */
935 ScrollUpGenericList(&ListUi);
936 break;
937 case VK_NEXT: /* PAGE DOWN */
938 ScrollPageDownGenericList(&ListUi);
939 break;
940 case VK_PRIOR: /* PAGE UP */
941 ScrollPageUpGenericList(&ListUi);
942 break;
943 case VK_F3: /* F3 */
944 {
945 if (ConfirmQuit(Ir))
946 return QUIT_PAGE;
947 else
948 RedrawGenericList(&ListUi);
949 break;
950 }
951 case VK_ESCAPE: /* ESC */
952 {
953 RestoreGenericListUiState(&ListUi);
954 // return nextPage; // prevPage;
955
956 // return INSTALL_INTRO_PAGE;
957 return DEVICE_SETTINGS_PAGE;
958 // return SCSI_CONTROLLER_PAGE;
959 }
960 }
961 }
962 else
963 {
964 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
965 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
966 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
967 {
968 /* Retrieve the current installation */
969 ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1);
970
971 CurrentInstallation =
972 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList));
973
974 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
975 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
976
977 RepairUpdateFlag = TRUE;
978
979 // return nextPage;
980 /***/return INSTALL_INTRO_PAGE;/***/
981 }
982 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
983 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */
984 {
985 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
986 }
987 }
988 }
989
990 return UPGRADE_REPAIR_PAGE;
991 }
992
993
994 /*
995 * Displays the InstallIntroPage.
996 *
997 * Next pages:
998 * DeviceSettingsPage (At once if repair or update is selected)
999 * SelectPartitionPage (At once if unattended setup)
1000 * DeviceSettingsPage (default)
1001 * QuitPage
1002 *
1003 * RETURNS
1004 * Number of the next page.
1005 */
1006 static PAGE_NUMBER
1007 InstallIntroPage(PINPUT_RECORD Ir)
1008 {
1009 if (RepairUpdateFlag)
1010 {
1011 #if 1 /* Old code that looks good */
1012
1013 // return SELECT_PARTITION_PAGE;
1014 return DEVICE_SETTINGS_PAGE;
1015
1016 #else /* Possible new code? */
1017
1018 return DEVICE_SETTINGS_PAGE;
1019 // return SCSI_CONTROLLER_PAGE;
1020
1021 #endif
1022 }
1023
1024 if (IsUnattendedSetup)
1025 return SELECT_PARTITION_PAGE;
1026
1027 MUIDisplayPage(INSTALL_INTRO_PAGE);
1028
1029 while (TRUE)
1030 {
1031 CONSOLE_ConInKey(Ir);
1032
1033 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1034 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1035 {
1036 if (ConfirmQuit(Ir))
1037 return QUIT_PAGE;
1038
1039 break;
1040 }
1041 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1042 {
1043 return UPGRADE_REPAIR_PAGE;
1044 }
1045 }
1046
1047 return INSTALL_INTRO_PAGE;
1048 }
1049
1050
1051 #if 0
1052 static PAGE_NUMBER
1053 ScsiControllerPage(PINPUT_RECORD Ir)
1054 {
1055 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1056
1057 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1058
1059 /* FIXME: print loaded mass storage driver descriptions */
1060 #if 0
1061 CONSOLE_SetTextXY(8, 10, "TEST device");
1062 #endif
1063
1064 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1065
1066 while (TRUE)
1067 {
1068 CONSOLE_ConInKey(Ir);
1069
1070 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1071 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1072 {
1073 if (ConfirmQuit(Ir))
1074 return QUIT_PAGE;
1075
1076 break;
1077 }
1078 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1079 {
1080 return DEVICE_SETTINGS_PAGE;
1081 }
1082 }
1083
1084 return SCSI_CONTROLLER_PAGE;
1085 }
1086
1087 static PAGE_NUMBER
1088 OemDriverPage(PINPUT_RECORD Ir)
1089 {
1090 // MUIDisplayPage(OEM_DRIVER_PAGE);
1091
1092 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1093
1094 /* FIXME: Implement!! */
1095
1096 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1097
1098 while (TRUE)
1099 {
1100 CONSOLE_ConInKey(Ir);
1101
1102 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1103 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1104 {
1105 if (ConfirmQuit(Ir))
1106 return QUIT_PAGE;
1107
1108 break;
1109 }
1110 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1111 {
1112 return DEVICE_SETTINGS_PAGE;
1113 }
1114 }
1115
1116 return OEM_DRIVER_PAGE;
1117 }
1118 #endif
1119
1120
1121 /*
1122 * Displays the DeviceSettingsPage.
1123 *
1124 * Next pages:
1125 * SelectPartitionPage (At once if repair or update is selected)
1126 * ComputerSettingsPage
1127 * DisplaySettingsPage
1128 * KeyboardSettingsPage
1129 * LayoutsettingsPage
1130 * SelectPartitionPage
1131 * QuitPage
1132 *
1133 * SIDEEFFECTS
1134 * Init ComputerList
1135 * Init DisplayList
1136 * Init KeyboardList
1137 * Init LayoutList
1138 *
1139 * RETURNS
1140 * Number of the next page.
1141 */
1142 static PAGE_NUMBER
1143 DeviceSettingsPage(PINPUT_RECORD Ir)
1144 {
1145 static ULONG Line = 16;
1146
1147 /* Initialize the computer settings list */
1148 if (ComputerList == NULL)
1149 {
1150 ComputerList = CreateComputerTypeList(SetupInf);
1151 if (ComputerList == NULL)
1152 {
1153 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1154 return QUIT_PAGE;
1155 }
1156 }
1157
1158 /* Initialize the display settings list */
1159 if (DisplayList == NULL)
1160 {
1161 DisplayList = CreateDisplayDriverList(SetupInf);
1162 if (DisplayList == NULL)
1163 {
1164 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1165 return QUIT_PAGE;
1166 }
1167 }
1168
1169 /* Initialize the keyboard settings list */
1170 if (KeyboardList == NULL)
1171 {
1172 KeyboardList = CreateKeyboardDriverList(SetupInf);
1173 if (KeyboardList == NULL)
1174 {
1175 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1176 return QUIT_PAGE;
1177 }
1178 }
1179
1180 /* Initialize the keyboard layout list */
1181 if (LayoutList == NULL)
1182 {
1183 LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
1184 if (LayoutList == NULL)
1185 {
1186 /* FIXME: report error */
1187 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1188 return QUIT_PAGE;
1189 }
1190 }
1191
1192 if (RepairUpdateFlag)
1193 return SELECT_PARTITION_PAGE;
1194
1195 // if (IsUnattendedSetup)
1196 // return SELECT_PARTITION_PAGE;
1197
1198 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1199
1200 DrawGenericListCurrentItem(ComputerList, GetSettingDescription, 25, 11);
1201 DrawGenericListCurrentItem(DisplayList , GetSettingDescription, 25, 12);
1202 DrawGenericListCurrentItem(KeyboardList, GetSettingDescription, 25, 13);
1203 DrawGenericListCurrentItem(LayoutList , GetSettingDescription, 25, 14);
1204
1205 CONSOLE_InvertTextXY(24, Line, 48, 1);
1206
1207 while (TRUE)
1208 {
1209 CONSOLE_ConInKey(Ir);
1210
1211 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1212 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1213 {
1214 CONSOLE_NormalTextXY(24, Line, 48, 1);
1215
1216 if (Line == 14)
1217 Line = 16;
1218 else if (Line == 16)
1219 Line = 11;
1220 else
1221 Line++;
1222
1223 CONSOLE_InvertTextXY(24, Line, 48, 1);
1224 }
1225 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1226 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1227 {
1228 CONSOLE_NormalTextXY(24, Line, 48, 1);
1229
1230 if (Line == 11)
1231 Line = 16;
1232 else if (Line == 16)
1233 Line = 14;
1234 else
1235 Line--;
1236
1237 CONSOLE_InvertTextXY(24, Line, 48, 1);
1238 }
1239 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1240 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1241 {
1242 if (ConfirmQuit(Ir))
1243 return QUIT_PAGE;
1244
1245 break;
1246 }
1247 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1248 {
1249 if (Line == 11)
1250 return COMPUTER_SETTINGS_PAGE;
1251 else if (Line == 12)
1252 return DISPLAY_SETTINGS_PAGE;
1253 else if (Line == 13)
1254 return KEYBOARD_SETTINGS_PAGE;
1255 else if (Line == 14)
1256 return LAYOUT_SETTINGS_PAGE;
1257 else if (Line == 16)
1258 return SELECT_PARTITION_PAGE;
1259 }
1260 }
1261
1262 return DEVICE_SETTINGS_PAGE;
1263 }
1264
1265
1266 /*
1267 * Handles generic selection lists.
1268 *
1269 * PARAMS
1270 * GenericList: The list to handle.
1271 * nextPage: The page it needs to jump to after this page.
1272 * Ir: The PINPUT_RECORD
1273 */
1274 static PAGE_NUMBER
1275 HandleGenericList(PGENERIC_LIST_UI ListUi,
1276 PAGE_NUMBER nextPage,
1277 PINPUT_RECORD Ir)
1278 {
1279 while (TRUE)
1280 {
1281 CONSOLE_ConInKey(Ir);
1282
1283 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1284 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1285 {
1286 ScrollDownGenericList(ListUi);
1287 }
1288 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1289 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1290 {
1291 ScrollUpGenericList(ListUi);
1292 }
1293 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1294 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1295 {
1296 ScrollPageDownGenericList(ListUi);
1297 }
1298 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1299 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1300 {
1301 ScrollPageUpGenericList(ListUi);
1302 }
1303 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1304 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1305 {
1306 if (ConfirmQuit(Ir))
1307 return QUIT_PAGE;
1308 else
1309 RedrawGenericList(ListUi);
1310 }
1311 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1312 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1313 {
1314 RestoreGenericListUiState(ListUi);
1315 return nextPage; // Use some "prevPage;" instead?
1316 }
1317 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1318 {
1319 return nextPage;
1320 }
1321 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1322 {
1323 /* a-z */
1324 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1325 }
1326 }
1327 }
1328
1329
1330 /*
1331 * Displays the ComputerSettingsPage.
1332 *
1333 * Next pages:
1334 * DeviceSettingsPage
1335 * QuitPage
1336 *
1337 * RETURNS
1338 * Number of the next page.
1339 */
1340 static PAGE_NUMBER
1341 ComputerSettingsPage(PINPUT_RECORD Ir)
1342 {
1343 GENERIC_LIST_UI ListUi;
1344 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1345
1346 InitGenericListUi(&ListUi, ComputerList, GetSettingDescription);
1347 DrawGenericList(&ListUi,
1348 2, 18,
1349 xScreen - 3,
1350 yScreen - 3);
1351
1352 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1353 }
1354
1355
1356 /*
1357 * Displays the DisplaySettingsPage.
1358 *
1359 * Next pages:
1360 * DeviceSettingsPage
1361 * QuitPage
1362 *
1363 * RETURNS
1364 * Number of the next page.
1365 */
1366 static PAGE_NUMBER
1367 DisplaySettingsPage(PINPUT_RECORD Ir)
1368 {
1369 GENERIC_LIST_UI ListUi;
1370 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1371
1372 InitGenericListUi(&ListUi, DisplayList, GetSettingDescription);
1373 DrawGenericList(&ListUi,
1374 2, 18,
1375 xScreen - 3,
1376 yScreen - 3);
1377
1378 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1379 }
1380
1381
1382 /*
1383 * Displays the KeyboardSettingsPage.
1384 *
1385 * Next pages:
1386 * DeviceSettingsPage
1387 * QuitPage
1388 *
1389 * RETURNS
1390 * Number of the next page.
1391 */
1392 static PAGE_NUMBER
1393 KeyboardSettingsPage(PINPUT_RECORD Ir)
1394 {
1395 GENERIC_LIST_UI ListUi;
1396 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1397
1398 InitGenericListUi(&ListUi, KeyboardList, GetSettingDescription);
1399 DrawGenericList(&ListUi,
1400 2, 18,
1401 xScreen - 3,
1402 yScreen - 3);
1403
1404 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1405 }
1406
1407
1408 /*
1409 * Displays the LayoutSettingsPage.
1410 *
1411 * Next pages:
1412 * DeviceSettingsPage
1413 * QuitPage
1414 *
1415 * RETURNS
1416 * Number of the next page.
1417 */
1418 static PAGE_NUMBER
1419 LayoutSettingsPage(PINPUT_RECORD Ir)
1420 {
1421 GENERIC_LIST_UI ListUi;
1422 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1423
1424 InitGenericListUi(&ListUi, LayoutList, GetSettingDescription);
1425 DrawGenericList(&ListUi,
1426 2, 18,
1427 xScreen - 3,
1428 yScreen - 3);
1429
1430 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1431 }
1432
1433
1434 static BOOL
1435 IsDiskSizeValid(PPARTENTRY PartEntry)
1436 {
1437 ULONGLONG size;
1438
1439 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1440 size = (size + (512 * KB)) / MB; /* in MBytes */
1441
1442 if (size < USetupData.RequiredPartitionDiskSpace)
1443 {
1444 /* Partition is too small so ask for another one */
1445 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
1446 return FALSE;
1447 }
1448 else
1449 {
1450 return TRUE;
1451 }
1452 }
1453
1454
1455 /*
1456 * Displays the SelectPartitionPage.
1457 *
1458 * Next pages:
1459 * SelectFileSystemPage (At once if unattended)
1460 * SelectFileSystemPage (Default if free space is selected)
1461 * CreatePrimaryPartitionPage
1462 * CreateExtendedPartitionPage
1463 * CreateLogicalPartitionPage
1464 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1465 * DeletePartitionPage
1466 * QuitPage
1467 *
1468 * SIDEEFFECTS
1469 * Set InstallShortcut (only if not unattended + free space is selected)
1470 *
1471 * RETURNS
1472 * Number of the next page.
1473 */
1474 static PAGE_NUMBER
1475 SelectPartitionPage(PINPUT_RECORD Ir)
1476 {
1477 PARTLIST_UI ListUi;
1478 ULONG Error;
1479
1480 if (PartitionList == NULL)
1481 {
1482 PartitionList = CreatePartitionList();
1483 if (PartitionList == NULL)
1484 {
1485 /* FIXME: show an error dialog */
1486 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1487 return QUIT_PAGE;
1488 }
1489 else if (IsListEmpty(&PartitionList->DiskListHead))
1490 {
1491 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1492 return QUIT_PAGE;
1493 }
1494
1495 TempPartition = NULL;
1496 FormatState = Start;
1497 }
1498
1499 if (RepairUpdateFlag)
1500 {
1501 /* Determine the selected installation disk & partition */
1502 if (!SelectPartition(PartitionList,
1503 CurrentInstallation->DiskNumber,
1504 CurrentInstallation->PartitionNumber))
1505 {
1506 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1507 ASSERT(FALSE);
1508 }
1509
1510 return SELECT_FILE_SYSTEM_PAGE;
1511 }
1512
1513 MUIDisplayPage(SELECT_PARTITION_PAGE);
1514
1515 InitPartitionListUi(&ListUi, PartitionList,
1516 2,
1517 23,
1518 xScreen - 3,
1519 yScreen - 3);
1520 DrawPartitionList(&ListUi);
1521
1522 if (IsUnattendedSetup)
1523 {
1524 if (!SelectPartition(PartitionList,
1525 USetupData.DestinationDiskNumber,
1526 USetupData.DestinationPartitionNumber))
1527 {
1528 if (USetupData.AutoPartition)
1529 {
1530 if (PartitionList->CurrentPartition->LogicalPartition)
1531 {
1532 CreateLogicalPartition(PartitionList,
1533 PartitionList->CurrentPartition->SectorCount.QuadPart,
1534 TRUE);
1535 }
1536 else
1537 {
1538 CreatePrimaryPartition(PartitionList,
1539 PartitionList->CurrentPartition->SectorCount.QuadPart,
1540 TRUE);
1541 }
1542
1543 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1544 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1545 {
1546 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1547 USetupData.RequiredPartitionDiskSpace);
1548 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1549 }
1550
1551 return SELECT_FILE_SYSTEM_PAGE;
1552 }
1553 }
1554 else
1555 {
1556 DrawPartitionList(&ListUi);
1557
1558 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1559 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1560 {
1561 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1562 USetupData.RequiredPartitionDiskSpace);
1563 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1564 }
1565
1566 return SELECT_FILE_SYSTEM_PAGE;
1567 }
1568 }
1569
1570 while (TRUE)
1571 {
1572 /* Update status text */
1573 if (PartitionList->CurrentPartition == NULL)
1574 {
1575 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1576 }
1577 else if (PartitionList->CurrentPartition->LogicalPartition)
1578 {
1579 if (PartitionList->CurrentPartition->IsPartitioned)
1580 {
1581 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1582 }
1583 else
1584 {
1585 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1586 }
1587 }
1588 else
1589 {
1590 if (PartitionList->CurrentPartition->IsPartitioned)
1591 {
1592 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1593 {
1594 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1595 }
1596 else
1597 {
1598 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1599 }
1600 }
1601 else
1602 {
1603 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1604 }
1605 }
1606
1607 CONSOLE_ConInKey(Ir);
1608
1609 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1610 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1611 {
1612 if (ConfirmQuit(Ir))
1613 {
1614 DestroyPartitionList(PartitionList);
1615 PartitionList = NULL;
1616 return QUIT_PAGE;
1617 }
1618
1619 break;
1620 }
1621 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1622 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1623 {
1624 ScrollDownPartitionList(&ListUi);
1625 }
1626 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1627 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1628 {
1629 ScrollUpPartitionList(&ListUi);
1630 }
1631 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1632 {
1633 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1634 continue; // return SELECT_PARTITION_PAGE;
1635
1636 if (PartitionList->CurrentPartition == NULL ||
1637 PartitionList->CurrentPartition->IsPartitioned == FALSE)
1638 {
1639 if (PartitionList->CurrentPartition->LogicalPartition)
1640 {
1641 CreateLogicalPartition(PartitionList,
1642 0ULL,
1643 TRUE);
1644 }
1645 else
1646 {
1647 CreatePrimaryPartition(PartitionList,
1648 0ULL,
1649 TRUE);
1650 }
1651 }
1652
1653 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1654 {
1655 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1656 USetupData.RequiredPartitionDiskSpace);
1657 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1658 }
1659
1660 return SELECT_FILE_SYSTEM_PAGE;
1661 }
1662 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1663 {
1664 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1665 {
1666 Error = PrimaryPartitionCreationChecks(PartitionList);
1667 if (Error != NOT_AN_ERROR)
1668 {
1669 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1670 return SELECT_PARTITION_PAGE;
1671 }
1672
1673 return CREATE_PRIMARY_PARTITION_PAGE;
1674 }
1675 }
1676 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1677 {
1678 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1679 {
1680 Error = ExtendedPartitionCreationChecks(PartitionList);
1681 if (Error != NOT_AN_ERROR)
1682 {
1683 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1684 return SELECT_PARTITION_PAGE;
1685 }
1686
1687 return CREATE_EXTENDED_PARTITION_PAGE;
1688 }
1689 }
1690 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1691 {
1692 if (PartitionList->CurrentPartition->LogicalPartition)
1693 {
1694 Error = LogicalPartitionCreationChecks(PartitionList);
1695 if (Error != NOT_AN_ERROR)
1696 {
1697 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1698 return SELECT_PARTITION_PAGE;
1699 }
1700
1701 return CREATE_LOGICAL_PARTITION_PAGE;
1702 }
1703 }
1704 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1705 {
1706 WCHAR PathBuffer[MAX_PATH];
1707 UNICODE_STRING CurrentPartition;
1708
1709 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1710 {
1711 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1712 return SELECT_PARTITION_PAGE;
1713 }
1714
1715 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1716 L"\\Device\\Harddisk%lu\\Partition%lu\\",
1717 PartitionList->CurrentDisk->DiskNumber,
1718 PartitionList->CurrentPartition->PartitionNumber);
1719 RtlInitUnicodeString(&CurrentPartition, PathBuffer);
1720
1721 /*
1722 * Check whether the user attempts to delete the partition on which
1723 * the installation source is present. If so, fail with an error.
1724 */
1725 // &USetupData.SourceRootPath
1726 if (RtlPrefixUnicodeString(&CurrentPartition, &USetupData.SourcePath, TRUE))
1727 {
1728 PopupError("You cannot delete the partition containing the installation source!",
1729 MUIGetString(STRING_CONTINUE),
1730 Ir, POPUP_WAIT_ENTER);
1731 return SELECT_PARTITION_PAGE;
1732 }
1733
1734 if (PartitionList->CurrentPartition->BootIndicator ||
1735 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1736 {
1737 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1738 }
1739
1740 return DELETE_PARTITION_PAGE;
1741 }
1742 }
1743
1744 return SELECT_PARTITION_PAGE;
1745 }
1746
1747
1748 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1749 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1750 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1751
1752 static VOID
1753 ShowPartitionSizeInputBox(SHORT Left,
1754 SHORT Top,
1755 SHORT Right,
1756 SHORT Bottom,
1757 ULONG MaxSize,
1758 PWSTR InputBuffer,
1759 PBOOLEAN Quit,
1760 PBOOLEAN Cancel)
1761 {
1762 INPUT_RECORD Ir;
1763 COORD coPos;
1764 DWORD Written;
1765 CHAR Buffer[128];
1766 INT Length, Pos;
1767 WCHAR ch;
1768 SHORT iLeft;
1769 SHORT iTop;
1770
1771 if (Quit != NULL)
1772 *Quit = FALSE;
1773
1774 if (Cancel != NULL)
1775 *Cancel = FALSE;
1776
1777 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1778
1779 /* Print message */
1780 coPos.X = Left + 2;
1781 coPos.Y = Top + 2;
1782 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1783 iLeft = coPos.X + strlen(Buffer) + 1;
1784 iTop = coPos.Y;
1785
1786 WriteConsoleOutputCharacterA(StdOutput,
1787 Buffer,
1788 strlen(Buffer),
1789 coPos,
1790 &Written);
1791
1792 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1793 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1794 coPos.Y = iTop;
1795 WriteConsoleOutputCharacterA(StdOutput,
1796 Buffer,
1797 strlen(Buffer),
1798 coPos,
1799 &Written);
1800
1801 swprintf(InputBuffer, L"%lu", MaxSize);
1802 Length = wcslen(InputBuffer);
1803 Pos = Length;
1804 CONSOLE_SetInputTextXY(iLeft,
1805 iTop,
1806 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1807 InputBuffer);
1808 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1809 CONSOLE_SetCursorType(TRUE, TRUE);
1810
1811 while (TRUE)
1812 {
1813 CONSOLE_ConInKey(&Ir);
1814
1815 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1816 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1817 {
1818 if (Quit != NULL)
1819 *Quit = TRUE;
1820
1821 InputBuffer[0] = UNICODE_NULL;
1822 CONSOLE_SetCursorType(TRUE, FALSE);
1823 break;
1824 }
1825 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1826 {
1827 CONSOLE_SetCursorType(TRUE, FALSE);
1828 break;
1829 }
1830 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1831 {
1832 if (Cancel != NULL)
1833 *Cancel = TRUE;
1834
1835 InputBuffer[0] = UNICODE_NULL;
1836 CONSOLE_SetCursorType(TRUE, FALSE);
1837 break;
1838 }
1839 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1840 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1841 {
1842 Pos = 0;
1843 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1844 }
1845 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1846 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1847 {
1848 Pos = Length;
1849 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1850 }
1851 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1852 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1853 {
1854 if (Pos > 0)
1855 {
1856 Pos--;
1857 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1858 }
1859 }
1860 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1861 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1862 {
1863 if (Pos < Length)
1864 {
1865 Pos++;
1866 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1867 }
1868 }
1869 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1870 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1871 {
1872 if (Pos < Length)
1873 {
1874 memmove(&InputBuffer[Pos],
1875 &InputBuffer[Pos + 1],
1876 (Length - Pos - 1) * sizeof(WCHAR));
1877 InputBuffer[Length - 1] = UNICODE_NULL;
1878
1879 Length--;
1880 CONSOLE_SetInputTextXY(iLeft,
1881 iTop,
1882 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1883 InputBuffer);
1884 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1885 }
1886 }
1887 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1888 {
1889 if (Pos > 0)
1890 {
1891 if (Pos < Length)
1892 memmove(&InputBuffer[Pos - 1],
1893 &InputBuffer[Pos],
1894 (Length - Pos) * sizeof(WCHAR));
1895 InputBuffer[Length - 1] = UNICODE_NULL;
1896
1897 Pos--;
1898 Length--;
1899 CONSOLE_SetInputTextXY(iLeft,
1900 iTop,
1901 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1902 InputBuffer);
1903 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1904 }
1905 }
1906 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1907 {
1908 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1909 {
1910 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1911
1912 if ((ch >= L'0') && (ch <= L'9'))
1913 {
1914 if (Pos < Length)
1915 memmove(&InputBuffer[Pos + 1],
1916 &InputBuffer[Pos],
1917 (Length - Pos) * sizeof(WCHAR));
1918 InputBuffer[Length + 1] = UNICODE_NULL;
1919 InputBuffer[Pos] = ch;
1920
1921 Pos++;
1922 Length++;
1923 CONSOLE_SetInputTextXY(iLeft,
1924 iTop,
1925 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1926 InputBuffer);
1927 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1928 }
1929 }
1930 }
1931 }
1932 }
1933
1934
1935 /*
1936 * Displays the CreatePrimaryPartitionPage.
1937 *
1938 * Next pages:
1939 * SelectPartitionPage
1940 * SelectFileSystemPage (default)
1941 * QuitPage
1942 *
1943 * RETURNS
1944 * Number of the next page.
1945 */
1946 static PAGE_NUMBER
1947 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1948 {
1949 PDISKENTRY DiskEntry;
1950 PPARTENTRY PartEntry;
1951 BOOLEAN Quit;
1952 BOOLEAN Cancel;
1953 WCHAR InputBuffer[50];
1954 ULONG MaxSize;
1955 ULONGLONG PartSize;
1956 ULONGLONG DiskSize;
1957 ULONGLONG SectorCount;
1958 PCHAR Unit;
1959
1960 if (PartitionList == NULL ||
1961 PartitionList->CurrentDisk == NULL ||
1962 PartitionList->CurrentPartition == NULL)
1963 {
1964 /* FIXME: show an error dialog */
1965 return QUIT_PAGE;
1966 }
1967
1968 DiskEntry = PartitionList->CurrentDisk;
1969 PartEntry = PartitionList->CurrentPartition;
1970
1971 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1972
1973 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1974
1975 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1976 #if 0
1977 if (DiskSize >= 10 * GB) /* 10 GB */
1978 {
1979 DiskSize = DiskSize / GB;
1980 Unit = MUIGetString(STRING_GB);
1981 }
1982 else
1983 #endif
1984 {
1985 DiskSize = DiskSize / MB;
1986 if (DiskSize == 0)
1987 DiskSize = 1;
1988
1989 Unit = MUIGetString(STRING_MB);
1990 }
1991
1992 if (DiskEntry->DriverName.Length > 0)
1993 {
1994 CONSOLE_PrintTextXY(6, 10,
1995 MUIGetString(STRING_HDINFOPARTCREATE_1),
1996 DiskSize,
1997 Unit,
1998 DiskEntry->DiskNumber,
1999 DiskEntry->Port,
2000 DiskEntry->Bus,
2001 DiskEntry->Id,
2002 &DiskEntry->DriverName,
2003 DiskEntry->NoMbr ? "GPT" : "MBR");
2004 }
2005 else
2006 {
2007 CONSOLE_PrintTextXY(6, 10,
2008 MUIGetString(STRING_HDINFOPARTCREATE_2),
2009 DiskSize,
2010 Unit,
2011 DiskEntry->DiskNumber,
2012 DiskEntry->Port,
2013 DiskEntry->Bus,
2014 DiskEntry->Id,
2015 DiskEntry->NoMbr ? "GPT" : "MBR");
2016 }
2017
2018 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2019
2020 #if 0
2021 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2022 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2023 #endif
2024
2025 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2026
2027 PartEntry = PartitionList->CurrentPartition;
2028 while (TRUE)
2029 {
2030 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2031
2032 if (MaxSize > PARTITION_MAXSIZE)
2033 MaxSize = PARTITION_MAXSIZE;
2034
2035 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2036 MaxSize, InputBuffer, &Quit, &Cancel);
2037
2038 if (Quit)
2039 {
2040 if (ConfirmQuit(Ir))
2041 return QUIT_PAGE;
2042
2043 break;
2044 }
2045 else if (Cancel)
2046 {
2047 return SELECT_PARTITION_PAGE;
2048 }
2049 else
2050 {
2051 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2052
2053 if (PartSize < 1)
2054 {
2055 /* Too small */
2056 continue;
2057 }
2058
2059 if (PartSize > MaxSize)
2060 {
2061 /* Too large */
2062 continue;
2063 }
2064
2065 /* Convert to bytes */
2066 if (PartSize == MaxSize)
2067 {
2068 /* Use all of the unpartitioned disk space */
2069 SectorCount = PartEntry->SectorCount.QuadPart;
2070 }
2071 else
2072 {
2073 /* Calculate the sector count from the size in MB */
2074 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2075
2076 /* But never get larger than the unpartitioned disk space */
2077 if (SectorCount > PartEntry->SectorCount.QuadPart)
2078 SectorCount = PartEntry->SectorCount.QuadPart;
2079 }
2080
2081 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2082
2083 CreatePrimaryPartition(PartitionList,
2084 SectorCount,
2085 FALSE);
2086
2087 return SELECT_PARTITION_PAGE;
2088 }
2089 }
2090
2091 return CREATE_PRIMARY_PARTITION_PAGE;
2092 }
2093
2094
2095 /*
2096 * Displays the CreateExtendedPartitionPage.
2097 *
2098 * Next pages:
2099 * SelectPartitionPage (default)
2100 * QuitPage
2101 *
2102 * RETURNS
2103 * Number of the next page.
2104 */
2105 static PAGE_NUMBER
2106 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2107 {
2108 PDISKENTRY DiskEntry;
2109 PPARTENTRY PartEntry;
2110 BOOLEAN Quit;
2111 BOOLEAN Cancel;
2112 WCHAR InputBuffer[50];
2113 ULONG MaxSize;
2114 ULONGLONG PartSize;
2115 ULONGLONG DiskSize;
2116 ULONGLONG SectorCount;
2117 PCHAR Unit;
2118
2119 if (PartitionList == NULL ||
2120 PartitionList->CurrentDisk == NULL ||
2121 PartitionList->CurrentPartition == NULL)
2122 {
2123 /* FIXME: show an error dialog */
2124 return QUIT_PAGE;
2125 }
2126
2127 DiskEntry = PartitionList->CurrentDisk;
2128 PartEntry = PartitionList->CurrentPartition;
2129
2130 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2131
2132 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2133
2134 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2135 #if 0
2136 if (DiskSize >= 10 * GB) /* 10 GB */
2137 {
2138 DiskSize = DiskSize / GB;
2139 Unit = MUIGetString(STRING_GB);
2140 }
2141 else
2142 #endif
2143 {
2144 DiskSize = DiskSize / MB;
2145 if (DiskSize == 0)
2146 DiskSize = 1;
2147
2148 Unit = MUIGetString(STRING_MB);
2149 }
2150
2151 if (DiskEntry->DriverName.Length > 0)
2152 {
2153 CONSOLE_PrintTextXY(6, 10,
2154 MUIGetString(STRING_HDINFOPARTCREATE_1),
2155 DiskSize,
2156 Unit,
2157 DiskEntry->DiskNumber,
2158 DiskEntry->Port,
2159 DiskEntry->Bus,
2160 DiskEntry->Id,
2161 &DiskEntry->DriverName,
2162 DiskEntry->NoMbr ? "GPT" : "MBR");
2163 }
2164 else
2165 {
2166 CONSOLE_PrintTextXY(6, 10,
2167 MUIGetString(STRING_HDINFOPARTCREATE_2),
2168 DiskSize,
2169 Unit,
2170 DiskEntry->DiskNumber,
2171 DiskEntry->Port,
2172 DiskEntry->Bus,
2173 DiskEntry->Id,
2174 DiskEntry->NoMbr ? "GPT" : "MBR");
2175 }
2176
2177 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2178
2179 #if 0
2180 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2181 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2182 #endif
2183
2184 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2185
2186 PartEntry = PartitionList->CurrentPartition;
2187 while (TRUE)
2188 {
2189 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2190
2191 if (MaxSize > PARTITION_MAXSIZE)
2192 MaxSize = PARTITION_MAXSIZE;
2193
2194 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2195 MaxSize, InputBuffer, &Quit, &Cancel);
2196
2197 if (Quit)
2198 {
2199 if (ConfirmQuit(Ir))
2200 return QUIT_PAGE;
2201
2202 break;
2203 }
2204 else if (Cancel)
2205 {
2206 return SELECT_PARTITION_PAGE;
2207 }
2208 else
2209 {
2210 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2211
2212 if (PartSize < 1)
2213 {
2214 /* Too small */
2215 continue;
2216 }
2217
2218 if (PartSize > MaxSize)
2219 {
2220 /* Too large */
2221 continue;
2222 }
2223
2224 /* Convert to bytes */
2225 if (PartSize == MaxSize)
2226 {
2227 /* Use all of the unpartitioned disk space */
2228 SectorCount = PartEntry->SectorCount.QuadPart;
2229 }
2230 else
2231 {
2232 /* Calculate the sector count from the size in MB */
2233 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2234
2235 /* But never get larger than the unpartitioned disk space */
2236 if (SectorCount > PartEntry->SectorCount.QuadPart)
2237 SectorCount = PartEntry->SectorCount.QuadPart;
2238 }
2239
2240 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2241
2242 CreateExtendedPartition(PartitionList,
2243 SectorCount);
2244
2245 return SELECT_PARTITION_PAGE;
2246 }
2247 }
2248
2249 return CREATE_EXTENDED_PARTITION_PAGE;
2250 }
2251
2252
2253 /*
2254 * Displays the CreateLogicalPartitionPage.
2255 *
2256 * Next pages:
2257 * SelectFileSystemPage (default)
2258 * QuitPage
2259 *
2260 * RETURNS
2261 * Number of the next page.
2262 */
2263 static PAGE_NUMBER
2264 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2265 {
2266 PDISKENTRY DiskEntry;
2267 PPARTENTRY PartEntry;
2268 BOOLEAN Quit;
2269 BOOLEAN Cancel;
2270 WCHAR InputBuffer[50];
2271 ULONG MaxSize;
2272 ULONGLONG PartSize;
2273 ULONGLONG DiskSize;
2274 ULONGLONG SectorCount;
2275 PCHAR Unit;
2276
2277 if (PartitionList == NULL ||
2278 PartitionList->CurrentDisk == NULL ||
2279 PartitionList->CurrentPartition == NULL)
2280 {
2281 /* FIXME: show an error dialog */
2282 return QUIT_PAGE;
2283 }
2284
2285 DiskEntry = PartitionList->CurrentDisk;
2286 PartEntry = PartitionList->CurrentPartition;
2287
2288 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2289
2290 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2291
2292 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2293 #if 0
2294 if (DiskSize >= 10 * GB) /* 10 GB */
2295 {
2296 DiskSize = DiskSize / GB;
2297 Unit = MUIGetString(STRING_GB);
2298 }
2299 else
2300 #endif
2301 {
2302 DiskSize = DiskSize / MB;
2303 if (DiskSize == 0)
2304 DiskSize = 1;
2305
2306 Unit = MUIGetString(STRING_MB);
2307 }
2308
2309 if (DiskEntry->DriverName.Length > 0)
2310 {
2311 CONSOLE_PrintTextXY(6, 10,
2312 MUIGetString(STRING_HDINFOPARTCREATE_1),
2313 DiskSize,
2314 Unit,
2315 DiskEntry->DiskNumber,
2316 DiskEntry->Port,
2317 DiskEntry->Bus,
2318 DiskEntry->Id,
2319 &DiskEntry->DriverName,
2320 DiskEntry->NoMbr ? "GPT" : "MBR");
2321 }
2322 else
2323 {
2324 CONSOLE_PrintTextXY(6, 10,
2325 MUIGetString(STRING_HDINFOPARTCREATE_2),
2326 DiskSize,
2327 Unit,
2328 DiskEntry->DiskNumber,
2329 DiskEntry->Port,
2330 DiskEntry->Bus,
2331 DiskEntry->Id,
2332 DiskEntry->NoMbr ? "GPT" : "MBR");
2333 }
2334
2335 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2336
2337 #if 0
2338 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2339 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2340 #endif
2341
2342 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2343
2344 PartEntry = PartitionList->CurrentPartition;
2345 while (TRUE)
2346 {
2347 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2348
2349 if (MaxSize > PARTITION_MAXSIZE)
2350 MaxSize = PARTITION_MAXSIZE;
2351
2352 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2353 MaxSize, InputBuffer, &Quit, &Cancel);
2354
2355 if (Quit)
2356 {
2357 if (ConfirmQuit(Ir))
2358 return QUIT_PAGE;
2359
2360 break;
2361 }
2362 else if (Cancel)
2363 {
2364 return SELECT_PARTITION_PAGE;
2365 }
2366 else
2367 {
2368 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2369
2370 if (PartSize < 1)
2371 {
2372 /* Too small */
2373 continue;
2374 }
2375
2376 if (PartSize > MaxSize)
2377 {
2378 /* Too large */
2379 continue;
2380 }
2381
2382 /* Convert to bytes */
2383 if (PartSize == MaxSize)
2384 {
2385 /* Use all of the unpartitioned disk space */
2386 SectorCount = PartEntry->SectorCount.QuadPart;
2387 }
2388 else
2389 {
2390 /* Calculate the sector count from the size in MB */
2391 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2392
2393 /* But never get larger than the unpartitioned disk space */
2394 if (SectorCount > PartEntry->SectorCount.QuadPart)
2395 SectorCount = PartEntry->SectorCount.QuadPart;
2396 }
2397
2398 DPRINT("Partition size: %I64u bytes\n", PartSize);
2399
2400 CreateLogicalPartition(PartitionList,
2401 SectorCount,
2402 FALSE);
2403
2404 return SELECT_PARTITION_PAGE;
2405 }
2406 }
2407
2408 return CREATE_LOGICAL_PARTITION_PAGE;
2409 }
2410
2411
2412 /*
2413 * Displays the ConfirmDeleteSystemPartitionPage.
2414 *
2415 * Next pages:
2416 * DeletePartitionPage (default)
2417 * SelectPartitionPage
2418 *
2419 * RETURNS
2420 * Number of the next page.
2421 */
2422 static PAGE_NUMBER
2423 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2424 {
2425 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2426
2427 while (TRUE)
2428 {
2429 CONSOLE_ConInKey(Ir);
2430
2431 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2432 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2433 {
2434 if (ConfirmQuit(Ir))
2435 return QUIT_PAGE;
2436
2437 break;
2438 }
2439 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2440 {
2441 return DELETE_PARTITION_PAGE;
2442 }
2443 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2444 {
2445 return SELECT_PARTITION_PAGE;
2446 }
2447 }
2448
2449 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2450 }
2451
2452
2453 /*
2454 * Displays the DeletePartitionPage.
2455 *
2456 * Next pages:
2457 * SelectPartitionPage (default)
2458 * QuitPage
2459 *
2460 * RETURNS
2461 * Number of the next page.
2462 */
2463 static PAGE_NUMBER
2464 DeletePartitionPage(PINPUT_RECORD Ir)
2465 {
2466 PDISKENTRY DiskEntry;
2467 PPARTENTRY PartEntry;
2468 ULONGLONG DiskSize;
2469 ULONGLONG PartSize;
2470 PCHAR Unit;
2471 CHAR PartTypeString[32];
2472
2473 if (PartitionList == NULL ||
2474 PartitionList->CurrentDisk == NULL ||
2475 PartitionList->CurrentPartition == NULL)
2476 {
2477 /* FIXME: show an error dialog */
2478 return QUIT_PAGE;
2479 }
2480
2481 DiskEntry = PartitionList->CurrentDisk;
2482 PartEntry = PartitionList->CurrentPartition;
2483
2484 MUIDisplayPage(DELETE_PARTITION_PAGE);
2485
2486 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2487 PartTypeString,
2488 ARRAYSIZE(PartTypeString));
2489
2490 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2491 #if 0
2492 if (PartSize >= 10 * GB) /* 10 GB */
2493 {
2494 PartSize = PartSize / GB;
2495 Unit = MUIGetString(STRING_GB);
2496 }
2497 else
2498 #endif
2499 if (PartSize >= 10 * MB) /* 10 MB */
2500 {
2501 PartSize = PartSize / MB;
2502 Unit = MUIGetString(STRING_MB);
2503 }
2504 else
2505 {
2506 PartSize = PartSize / KB;
2507 Unit = MUIGetString(STRING_KB);
2508 }
2509
2510 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2511 {
2512 CONSOLE_PrintTextXY(6, 10,
2513 MUIGetString(STRING_HDDINFOUNK2),
2514 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2515 (PartEntry->DriveLetter == 0) ? '-' : ':',
2516 PartEntry->PartitionType,
2517 PartSize,
2518 Unit);
2519 }
2520 else
2521 {
2522 CONSOLE_PrintTextXY(6, 10,
2523 " %c%c %s %I64u %s",
2524 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2525 (PartEntry->DriveLetter == 0) ? '-' : ':',
2526 PartTypeString,
2527 PartSize,
2528 Unit);
2529 }
2530
2531 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2532 #if 0
2533 if (DiskSize >= 10 * GB) /* 10 GB */
2534 {
2535 DiskSize = DiskSize / GB;
2536 Unit = MUIGetString(STRING_GB);
2537 }
2538 else
2539 #endif
2540 {
2541 DiskSize = DiskSize / MB;
2542 if (DiskSize == 0)
2543 DiskSize = 1;
2544
2545 Unit = MUIGetString(STRING_MB);
2546 }
2547
2548 if (DiskEntry->DriverName.Length > 0)
2549 {
2550 CONSOLE_PrintTextXY(6, 12,
2551 MUIGetString(STRING_HDINFOPARTDELETE_1),
2552 DiskSize,
2553 Unit,
2554 DiskEntry->DiskNumber,
2555 DiskEntry->Port,
2556 DiskEntry->Bus,
2557 DiskEntry->Id,
2558 &DiskEntry->DriverName,
2559 DiskEntry->NoMbr ? "GPT" : "MBR");
2560 }
2561 else
2562 {
2563 CONSOLE_PrintTextXY(6, 12,
2564 MUIGetString(STRING_HDINFOPARTDELETE_2),
2565 DiskSize,
2566 Unit,
2567 DiskEntry->DiskNumber,
2568 DiskEntry->Port,
2569 DiskEntry->Bus,
2570 DiskEntry->Id,
2571 DiskEntry->NoMbr ? "GPT" : "MBR");
2572 }
2573
2574 while (TRUE)
2575 {
2576 CONSOLE_ConInKey(Ir);
2577
2578 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2579 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2580 {
2581 if (ConfirmQuit(Ir))
2582 return QUIT_PAGE;
2583
2584 break;
2585 }
2586 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2587 {
2588 return SELECT_PARTITION_PAGE;
2589 }
2590 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2591 {
2592 DeleteCurrentPartition(PartitionList);
2593
2594 return SELECT_PARTITION_PAGE;
2595 }
2596 }
2597
2598 return DELETE_PARTITION_PAGE;
2599 }
2600
2601
2602 /*
2603 * Displays the SelectFileSystemPage.
2604 *
2605 * Next pages:
2606 * CheckFileSystemPage (At once if RepairUpdate is selected)
2607 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2608 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2609 * SelectPartitionPage (If the user aborts)
2610 * FormatPartitionPage (Default)
2611 * QuitPage
2612 *
2613 * SIDEEFFECTS
2614 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2615 * Calls CheckActiveSystemPartition()
2616 *
2617 * RETURNS
2618 * Number of the next page.
2619 */
2620 static PAGE_NUMBER
2621 SelectFileSystemPage(PINPUT_RECORD Ir)
2622 {
2623 PDISKENTRY DiskEntry;
2624 PPARTENTRY PartEntry;
2625 ULONGLONG DiskSize;
2626 ULONGLONG PartSize;
2627 PCHAR DiskUnit;
2628 PCHAR PartUnit;
2629 CHAR PartTypeString[32];
2630 FORMATMACHINESTATE PreviousFormatState;
2631
2632 DPRINT("SelectFileSystemPage()\n");
2633
2634 if (PartitionList == NULL ||
2635 PartitionList->CurrentDisk == NULL ||
2636 PartitionList->CurrentPartition == NULL)
2637 {
2638 /* FIXME: show an error dialog */
2639 return QUIT_PAGE;
2640 }
2641
2642 /* Find or set the active system partition */
2643 CheckActiveSystemPartition(PartitionList);
2644 if (PartitionList->SystemPartition == NULL)
2645 {
2646 /* FIXME: show an error dialog */
2647 //
2648 // Error dialog should say that we cannot find a suitable
2649 // system partition and create one on the system. At this point,
2650 // it may be nice to ask the user whether he wants to continue,
2651 // or use an external drive as the system drive/partition
2652 // (e.g. floppy, USB drive, etc...)
2653 //
2654 return QUIT_PAGE;
2655 }
2656
2657 PreviousFormatState = FormatState;
2658 switch (FormatState)
2659 {
2660 case Start:
2661 {
2662 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2663 {
2664 TempPartition = PartitionList->SystemPartition;
2665 TempPartition->NeedsCheck = TRUE;
2666
2667 FormatState = FormatSystemPartition;
2668 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2669 }
2670 else
2671 {
2672 TempPartition = PartitionList->CurrentPartition;
2673 TempPartition->NeedsCheck = TRUE;
2674
2675 FormatState = FormatInstallPartition;
2676 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2677 }
2678 break;
2679 }
2680
2681 case FormatSystemPartition:
2682 {
2683 TempPartition = PartitionList->CurrentPartition;
2684 TempPartition->NeedsCheck = TRUE;
2685
2686 FormatState = FormatInstallPartition;
2687 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2688 break;
2689 }
2690
2691 case FormatInstallPartition:
2692 {
2693 if (GetNextUnformattedPartition(PartitionList,
2694 NULL,
2695 &TempPartition))
2696 {
2697 FormatState = FormatOtherPartition;
2698 TempPartition->NeedsCheck = TRUE;
2699 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2700 }
2701 else
2702 {
2703 FormatState = FormatDone;
2704 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2705 return CHECK_FILE_SYSTEM_PAGE;
2706 }
2707 break;
2708 }
2709
2710 case FormatOtherPartition:
2711 {
2712 if (GetNextUnformattedPartition(PartitionList,
2713 NULL,
2714 &TempPartition))
2715 {
2716 FormatState = FormatOtherPartition;
2717 TempPartition->NeedsCheck = TRUE;
2718 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2719 }
2720 else
2721 {
2722 FormatState = FormatDone;
2723 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2724 return CHECK_FILE_SYSTEM_PAGE;
2725 }
2726 break;
2727 }
2728
2729 default:
2730 {
2731 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2732 /* FIXME: show an error dialog */
2733 return QUIT_PAGE;
2734 }
2735 }
2736
2737 PartEntry = TempPartition;
2738 DiskEntry = PartEntry->DiskEntry;
2739
2740 /* Adjust disk size */
2741 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2742 if (DiskSize >= 10 * GB) /* 10 GB */
2743 {
2744 DiskSize = DiskSize / GB;
2745 DiskUnit = MUIGetString(STRING_GB);
2746 }
2747 else
2748 {
2749 DiskSize = DiskSize / MB;
2750 DiskUnit = MUIGetString(STRING_MB);
2751 }
2752
2753 /* Adjust partition size */
2754 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2755 if (PartSize >= 10 * GB) /* 10 GB */
2756 {
2757 PartSize = PartSize / GB;
2758 PartUnit = MUIGetString(STRING_GB);
2759 }
2760 else
2761 {
2762 PartSize = PartSize / MB;
2763 PartUnit = MUIGetString(STRING_MB);
2764 }
2765
2766 /* Adjust partition type */
2767 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2768 PartTypeString,
2769 ARRAYSIZE(PartTypeString));
2770
2771 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2772
2773 if (PartEntry->AutoCreate)
2774 {
2775 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2776
2777 #if 0
2778 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2779 PartEntry->PartitionNumber,
2780 PartSize,
2781 PartUnit,
2782 PartTypeString);
2783 #endif
2784
2785 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2786 DiskEntry->DiskNumber,
2787 DiskSize,
2788 DiskUnit,
2789 DiskEntry->Port,
2790 DiskEntry->Bus,
2791 DiskEntry->Id,
2792 &DiskEntry->DriverName,
2793 DiskEntry->NoMbr ? "GPT" : "MBR");
2794
2795 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2796
2797 PartEntry->AutoCreate = FALSE;
2798 }
2799 else if (PartEntry->New)
2800 {
2801 switch (FormatState)
2802 {
2803 case FormatSystemPartition:
2804 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2805 break;
2806
2807 case FormatInstallPartition:
2808 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2809 break;
2810
2811 case FormatOtherPartition:
2812 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2813 break;
2814
2815 default:
2816 break;
2817 }
2818
2819 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2820 }
2821 else
2822 {
2823 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2824
2825 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2826 {
2827 CONSOLE_PrintTextXY(8, 10,
2828 MUIGetString(STRING_HDDINFOUNK4),
2829 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2830 (PartEntry->DriveLetter == 0) ? '-' : ':',
2831 PartEntry->PartitionType,
2832 PartSize,
2833 PartUnit);
2834 }
2835 else
2836 {
2837 CONSOLE_PrintTextXY(8, 10,
2838 "%c%c %s %I64u %s",
2839 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2840 (PartEntry->DriveLetter == 0) ? '-' : ':',
2841 PartTypeString,
2842 PartSize,
2843 PartUnit);
2844 }
2845
2846 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
2847 DiskEntry->DiskNumber,
2848 DiskSize,
2849 DiskUnit,
2850 DiskEntry->Port,
2851 DiskEntry->Bus,
2852 DiskEntry->Id,
2853 &DiskEntry->DriverName,
2854 DiskEntry->NoMbr ? "GPT" : "MBR");
2855 }
2856
2857 if (FileSystemList == NULL)
2858 {
2859 /* Create the file system list, and by default select the "FAT" file system */
2860 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2861 if (FileSystemList == NULL)
2862 {
2863 /* FIXME: show an error dialog */
2864 return QUIT_PAGE;
2865 }
2866 }
2867
2868 if (RepairUpdateFlag)
2869 {
2870 return CHECK_FILE_SYSTEM_PAGE;
2871 //return SELECT_PARTITION_PAGE;
2872 }
2873
2874 if (IsUnattendedSetup)
2875 {
2876 if (USetupData.FormatPartition)
2877 {
2878 /*
2879 * We use whatever currently selected file system we have
2880 * (by default, this is "FAT", as per the initialization
2881 * performed above). Note that it may be interesting to specify
2882 * which file system to use in unattended installations, in the
2883 * txtsetup.sif file.
2884 */
2885 return FORMAT_PARTITION_PAGE;
2886 }
2887
2888 return CHECK_FILE_SYSTEM_PAGE;
2889 }
2890
2891 DrawFileSystemList(FileSystemList);
2892
2893 while (TRUE)
2894 {
2895 CONSOLE_ConInKey(Ir);
2896
2897 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2898 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2899 {
2900 if (ConfirmQuit(Ir))
2901 return QUIT_PAGE;
2902
2903 break;
2904 }
2905 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2906 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2907 {
2908 FormatState = Start;
2909 return SELECT_PARTITION_PAGE;
2910 }
2911 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2912 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2913 {
2914 ScrollDownFileSystemList(FileSystemList);
2915 }
2916 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2917 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2918 {
2919 ScrollUpFileSystemList(FileSystemList);
2920 }
2921 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2922 {
2923 if (!FileSystemList->Selected->FileSystem)
2924 return SELECT_FILE_SYSTEM_PAGE;
2925 else
2926 return FORMAT_PARTITION_PAGE;
2927 }
2928 }
2929
2930 FormatState = PreviousFormatState;
2931
2932 return SELECT_FILE_SYSTEM_PAGE;
2933 }
2934
2935
2936 /*
2937 * Displays the FormatPartitionPage.
2938 *
2939 * Next pages:
2940 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2941 * SelectPartitionPage (At once)
2942 * QuitPage
2943 *
2944 * SIDEEFFECTS
2945 * Sets PartitionList->CurrentPartition->FormatState
2946 * Sets USetupData.DestinationRootPath
2947 *
2948 * RETURNS
2949 * Number of the next page.
2950 */
2951 static PAGE_NUMBER
2952 FormatPartitionPage(PINPUT_RECORD Ir)
2953 {
2954 NTSTATUS Status;
2955 PDISKENTRY DiskEntry;
2956 PPARTENTRY PartEntry;
2957 PFILE_SYSTEM_ITEM SelectedFileSystem;
2958 UNICODE_STRING PartitionRootPath;
2959 WCHAR PathBuffer[MAX_PATH];
2960 CHAR Buffer[MAX_PATH];
2961
2962 #ifndef NDEBUG
2963 ULONG Line;
2964 ULONG i;
2965 PPARTITION_INFORMATION PartitionInfo;
2966 #endif
2967
2968 DPRINT("FormatPartitionPage()\n");
2969
2970 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2971
2972 if (PartitionList == NULL || TempPartition == NULL)
2973 {
2974 /* FIXME: show an error dialog */
2975 return QUIT_PAGE;
2976 }
2977
2978 PartEntry = TempPartition;
2979 DiskEntry = PartEntry->DiskEntry;
2980
2981 SelectedFileSystem = FileSystemList->Selected;
2982
2983 while (TRUE)
2984 {
2985 if (!IsUnattendedSetup)
2986 {
2987 CONSOLE_ConInKey(Ir);
2988 }
2989
2990 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2991 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2992 {
2993 if (ConfirmQuit(Ir))
2994 return QUIT_PAGE;
2995
2996 break;
2997 }
2998 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2999 {
3000 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3001
3002 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
3003 {
3004 /* FIXME: show an error dialog */
3005 return QUIT_PAGE;
3006 }
3007
3008 #ifndef NDEBUG
3009 CONSOLE_PrintTextXY(6, 12,
3010 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3011 DiskEntry->Cylinders,
3012 DiskEntry->TracksPerCylinder,
3013 DiskEntry->SectorsPerTrack,
3014 DiskEntry->BytesPerSector,
3015 DiskEntry->Dirty ? '*' : ' ');
3016
3017 Line = 13;
3018
3019 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3020 {
3021 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3022
3023 CONSOLE_PrintTextXY(6, Line,
3024 "%2u: %2lu %c %12I64u %12I64u %02x",
3025 i,
3026 PartitionInfo->PartitionNumber,
3027 PartitionInfo->BootIndicator ? 'A' : '-',
3028 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3029 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3030 PartitionInfo->PartitionType);
3031 Line++;
3032 }
3033 #endif
3034
3035 /* Commit the partition changes to the disk */
3036 if (!WritePartitionsToDisk(PartitionList))
3037 {
3038 DPRINT("WritePartitionsToDisk() failed\n");
3039 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3040 return QUIT_PAGE;
3041 }
3042
3043 /* Set PartitionRootPath */
3044 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3045 L"\\Device\\Harddisk%lu\\Partition%lu",
3046 DiskEntry->DiskNumber,
3047 PartEntry->PartitionNumber);
3048 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3049 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3050
3051 /* Format the partition */
3052 if (SelectedFileSystem->FileSystem)
3053 {
3054 Status = FormatPartition(&PartitionRootPath,
3055 SelectedFileSystem);
3056 if (Status == STATUS_NOT_SUPPORTED)
3057 {
3058 sprintf(Buffer,
3059 "Setup is currently unable to format a partition in %S.\n"
3060 "\n"
3061 " \x07 Press ENTER to continue Setup.\n"
3062 " \x07 Press F3 to quit Setup.",
3063 SelectedFileSystem->FileSystem->FileSystemName);
3064
3065 PopupError(Buffer,
3066 MUIGetString(STRING_QUITCONTINUE),
3067 NULL, POPUP_WAIT_NONE);
3068
3069 while (TRUE)
3070 {
3071 CONSOLE_ConInKey(Ir);
3072
3073 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3074 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3075 {
3076 if (ConfirmQuit(Ir))
3077 return QUIT_PAGE;
3078 else
3079 return SELECT_FILE_SYSTEM_PAGE;
3080 }
3081 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3082 {
3083 return SELECT_FILE_SYSTEM_PAGE;
3084 }
3085 }
3086 }
3087 else if (!NT_SUCCESS(Status))
3088 {
3089 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3090 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3091 return QUIT_PAGE;
3092 }
3093
3094 PartEntry->FormatState = Formatted;
3095 // PartEntry->FileSystem = FileSystem;
3096 PartEntry->New = FALSE;
3097 }
3098
3099 #ifndef NDEBUG
3100 CONSOLE_SetStatusText(" Done. Press any key ...");
3101 CONSOLE_ConInKey(Ir);
3102 #endif
3103
3104 return SELECT_FILE_SYSTEM_PAGE;
3105 }
3106 }
3107
3108 return FORMAT_PARTITION_PAGE;
3109 }
3110
3111
3112 /*
3113 * Displays the CheckFileSystemPage.
3114 *
3115 * Next pages:
3116 * InstallDirectoryPage (At once)
3117 * QuitPage
3118 *
3119 * SIDEEFFECTS
3120 * Inits or reloads FileSystemList
3121 *
3122 * RETURNS
3123 * Number of the next page.
3124 */
3125 static PAGE_NUMBER
3126 CheckFileSystemPage(PINPUT_RECORD Ir)
3127 {
3128 NTSTATUS Status;
3129 PDISKENTRY DiskEntry;
3130 PPARTENTRY PartEntry;
3131 PFILE_SYSTEM CurrentFileSystem;
3132 UNICODE_STRING PartitionRootPath;
3133 WCHAR PathBuffer[MAX_PATH];
3134 CHAR Buffer[MAX_PATH];
3135
3136 if (PartitionList == NULL)
3137 {
3138 /* FIXME: show an error dialog */
3139 return QUIT_PAGE;
3140 }
3141
3142 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3143 {
3144 return INSTALL_DIRECTORY_PAGE;
3145 }
3146
3147 /* Set PartitionRootPath */
3148 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3149 L"\\Device\\Harddisk%lu\\Partition%lu",
3150 DiskEntry->DiskNumber,
3151 PartEntry->PartitionNumber);
3152 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3153 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3154
3155 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3156
3157 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3158
3159 CurrentFileSystem = PartEntry->FileSystem;
3160 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3161 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3162
3163 /* HACK: Do not try to check a partition with an unknown filesystem */
3164 if (CurrentFileSystem == NULL)
3165 {
3166 PartEntry->NeedsCheck = FALSE;
3167 return CHECK_FILE_SYSTEM_PAGE;
3168 }
3169
3170 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3171 if (Status == STATUS_NOT_SUPPORTED)
3172 {
3173 sprintf(Buffer,
3174 "Setup is currently unable to check a partition formatted in %S.\n"
3175 "\n"
3176 " \x07 Press ENTER to continue Setup.\n"
3177 " \x07 Press F3 to quit Setup.",
3178 CurrentFileSystem->FileSystemName);
3179
3180 PopupError(Buffer,
3181 MUIGetString(STRING_QUITCONTINUE),
3182 NULL, POPUP_WAIT_NONE);
3183
3184 while (TRUE)
3185 {
3186 CONSOLE_ConInKey(Ir);
3187
3188 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3189 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3190 {
3191 if (ConfirmQuit(Ir))
3192 return QUIT_PAGE;
3193 else
3194 return CHECK_FILE_SYSTEM_PAGE;
3195 }
3196 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3197 {
3198 PartEntry->NeedsCheck = FALSE;
3199 return CHECK_FILE_SYSTEM_PAGE;
3200 }
3201 }
3202 }
3203 else if (!NT_SUCCESS(Status))
3204 {
3205 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3206 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3207 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3208 "(Status 0x%08lx).\n", Status);
3209 PopupError(Buffer,
3210 // MUIGetString(STRING_REBOOTCOMPUTER),
3211 MUIGetString(STRING_CONTINUE),
3212 Ir, POPUP_WAIT_ENTER);
3213
3214 // return QUIT_PAGE;
3215 }
3216
3217 PartEntry->NeedsCheck = FALSE;
3218 return CHECK_FILE_SYSTEM_PAGE;
3219 }
3220
3221
3222 static VOID
3223 BuildInstallPaths(PWSTR InstallDir,
3224 PDISKENTRY DiskEntry,
3225 PPARTENTRY PartEntry)
3226 {
3227 WCHAR PathBuffer[MAX_PATH];
3228
3229 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
3230 /* Create 'InstallPath' string */
3231 RtlFreeUnicodeString(&InstallPath);
3232 RtlCreateUnicodeString(&InstallPath, InstallDir);
3233
3234 /* Create 'USetupData.DestinationRootPath' string */
3235 RtlFreeUnicodeString(&USetupData.DestinationRootPath);
3236 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3237 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3238 DiskEntry->DiskNumber,
3239 PartEntry->PartitionNumber);
3240 RtlCreateUnicodeString(&USetupData.DestinationRootPath, PathBuffer);
3241 DPRINT("DestinationRootPath: %wZ\n", &USetupData.DestinationRootPath);
3242
3243 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
3244 /* Create 'USetupData.DestinationPath' string */
3245 RtlFreeUnicodeString(&USetupData.DestinationPath);
3246 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3247 USetupData.DestinationRootPath.Buffer, InstallDir);
3248 RtlCreateUnicodeString(&USetupData.DestinationPath, PathBuffer);
3249
3250 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
3251 /* Create 'USetupData.DestinationArcPath' */
3252 RtlFreeUnicodeString(&USetupData.DestinationArcPath);
3253 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3254 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3255 DiskEntry->BiosDiskNumber,
3256 PartEntry->PartitionNumber);
3257 ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
3258 RtlCreateUnicodeString(&USetupData.DestinationArcPath, PathBuffer);
3259
3260 /* Initialize DestinationDriveLetter */
3261 DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
3262 }
3263
3264
3265 static BOOLEAN
3266 IsValidPath(
3267 IN PCWSTR InstallDir)
3268 {
3269 UINT i, Length;
3270
3271 Length = wcslen(InstallDir);
3272
3273 // TODO: Add check for 8.3 too.
3274
3275 /* Path must be at least 2 characters long */
3276 // if (Length < 2)
3277 // return FALSE;
3278
3279 /* Path must start with a backslash */
3280 // if (InstallDir[0] != L'\\')
3281 // return FALSE;
3282
3283 /* Path must not end with a backslash */
3284 if (InstallDir[Length - 1] == L'\\')
3285 return FALSE;
3286
3287 /* Path must not contain whitespace characters */
3288 for (i = 0; i < Length; i++)
3289 {
3290 if (iswspace(InstallDir[i]))
3291 return FALSE;
3292 }
3293
3294 /* Path component must not end with a dot */
3295 for (i = 0; i < Length; i++)
3296 {
3297 if (InstallDir[i] == L'\\' && i > 0)
3298 {
3299 if (InstallDir[i - 1] == L'.')
3300 return FALSE;
3301 }
3302 }
3303
3304 if (InstallDir[Length - 1] == L'.')
3305 return FALSE;
3306
3307 return TRUE;
3308 }
3309
3310
3311 /*
3312 * Displays the InstallDirectoryPage.
3313 *
3314 * Next pages:
3315 * PrepareCopyPage
3316 * QuitPage
3317 *
3318 * RETURNS
3319 * Number of the next page.
3320 */
3321 static PAGE_NUMBER
3322 InstallDirectoryPage(PINPUT_RECORD Ir)
3323 {
3324 PDISKENTRY DiskEntry;
3325 PPARTENTRY PartEntry;
3326 WCHAR InstallDir[MAX_PATH];
3327 WCHAR c;
3328 ULONG Length, Pos;
3329
3330 /* We do not need the filesystem list anymore */
3331 if (FileSystemList != NULL)
3332 {
3333 DestroyFileSystemList(FileSystemList);
3334 FileSystemList = NULL;
3335 }
3336
3337 if (PartitionList == NULL ||
3338 PartitionList->CurrentDisk == NULL ||
3339 PartitionList->CurrentPartition == NULL)
3340 {
3341 /* FIXME: show an error dialog */
3342 return QUIT_PAGE;
3343 }
3344
3345 DiskEntry = PartitionList->CurrentDisk;
3346 PartEntry = PartitionList->CurrentPartition;
3347
3348 // if (IsUnattendedSetup)
3349 if (RepairUpdateFlag)
3350 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3351 else if (USetupData.InstallationDirectory[0])
3352 wcscpy(InstallDir, USetupData.InstallationDirectory);
3353 else
3354 wcscpy(InstallDir, L"\\ReactOS");
3355
3356 /*
3357 * Check the validity of the predefined 'InstallDir'. If we are either
3358 * in unattended setup or in update/repair mode, and the installation path
3359 * is valid, just perform the installation. Otherwise (either in the case
3360 * of an invalid path, or we are in regular setup), display the UI and allow
3361 * the user to specify a new installation path.
3362 */
3363 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3364 {
3365 BuildInstallPaths(InstallDir,
3366 DiskEntry,
3367 PartEntry);
3368
3369 /*
3370 * Check whether the user attempts to install ReactOS within the
3371 * installation source directory, or in a subdirectory thereof.
3372 * If so, fail with an error.
3373 */
3374 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3375 {
3376 PopupError("You cannot install ReactOS within the installation source directory!",
3377 MUIGetString(STRING_CONTINUE),
3378 Ir, POPUP_WAIT_ENTER);
3379 return INSTALL_DIRECTORY_PAGE;
3380 }
3381
3382 return PREPARE_COPY_PAGE;
3383 }
3384
3385 Length = wcslen(InstallDir);
3386 Pos = Length;
3387
3388 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3389 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3390 CONSOLE_SetCursorXY(8 + Pos, 11);
3391 CONSOLE_SetCursorType(TRUE, TRUE);
3392
3393 while (TRUE)
3394 {
3395 CONSOLE_ConInKey(Ir);
3396
3397 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3398 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3399 {
3400 CONSOLE_SetCursorType(TRUE, FALSE);
3401
3402 if (ConfirmQuit(Ir))
3403 return QUIT_PAGE;
3404
3405 CONSOLE_SetCursorType(TRUE, TRUE);
3406 break;
3407 }
3408 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3409 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3410 {
3411 if (Pos < Length)
3412 {
3413 memmove(&InstallDir[Pos],
3414 &InstallDir[Pos + 1],
3415 (Length - Pos - 1) * sizeof(WCHAR));
3416 InstallDir[Length - 1] = UNICODE_NULL;
3417
3418 Length--;
3419 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3420 CONSOLE_SetCursorXY(8 + Pos, 11);
3421 }
3422 }
3423 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3424 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3425 {
3426 Pos = 0;
3427 CONSOLE_SetCursorXY(8 + Pos, 11);
3428 }
3429 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3430 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3431 {
3432 Pos = Length;
3433 CONSOLE_SetCursorXY(8 + Pos, 11);
3434 }
3435 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3436 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3437 {
3438 if (Pos > 0)
3439 {
3440 Pos--;
3441 CONSOLE_SetCursorXY(8 + Pos, 11);
3442 }
3443 }
3444 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3445 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3446 {
3447 if (Pos < Length)
3448 {
3449 Pos++;
3450 CONSOLE_SetCursorXY(8 + Pos, 11);
3451 }
3452 }
3453 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3454 {
3455 CONSOLE_SetCursorType(TRUE, FALSE);
3456
3457 /*
3458 * Check for the validity of the installation directory and pop up
3459 * an error if it is not the case. Then the user can fix its input.
3460 */
3461 if (!IsValidPath(InstallDir))
3462 {
3463 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3464 return INSTALL_DIRECTORY_PAGE;
3465 }
3466
3467 BuildInstallPaths(InstallDir,
3468 DiskEntry,
3469 PartEntry);
3470
3471 /*
3472 * Check whether the user attempts to install ReactOS within the
3473 * installation source directory, or in a subdirectory thereof.
3474 * If so, fail with an error.
3475 */
3476 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3477 {
3478 PopupError("You cannot install ReactOS within the installation source directory!",
3479 MUIGetString(STRING_CONTINUE),
3480 Ir, POPUP_WAIT_ENTER);
3481 return INSTALL_DIRECTORY_PAGE;
3482 }
3483
3484 return PREPARE_COPY_PAGE;
3485 }
3486 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3487 {
3488 if (Pos > 0)
3489 {
3490 if (Pos < Length)
3491 memmove(&InstallDir[Pos - 1],
3492 &InstallDir[Pos],
3493 (Length - Pos) * sizeof(WCHAR));
3494 InstallDir[Length - 1] = UNICODE_NULL;
3495
3496 Pos--;
3497 Length--;
3498 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3499 CONSOLE_SetCursorXY(8 + Pos, 11);
3500 }
3501 }
3502 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3503 {
3504 if (Length < 50)
3505 {
3506 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3507 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3508 {
3509 if (Pos < Length)
3510 memmove(&InstallDir[Pos + 1],
3511 &InstallDir[Pos],
3512 (Length - Pos) * sizeof(WCHAR));
3513 InstallDir[Length + 1] = UNICODE_NULL;
3514 InstallDir[Pos] = c;
3515
3516 Pos++;
3517 Length++;
3518 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3519 CONSOLE_SetCursorXY(8 + Pos, 11);
3520 }
3521 }
3522 }
3523 }
3524
3525 return INSTALL_DIRECTORY_PAGE;
3526 }
3527
3528
3529 static BOOLEAN
3530 AddSectionToCopyQueueCab(HINF InfFile,
3531 PWCHAR SectionName,
3532 PWCHAR SourceCabinet,
3533 PCUNICODE_STRING DestinationPath,
3534 PINPUT_RECORD Ir)
3535 {
3536 INFCONTEXT FilesContext;
3537 INFCONTEXT DirContext;
3538 PWCHAR FileKeyName;
3539 PWCHAR FileKeyValue;
3540 PWCHAR DirKeyValue;
3541 PWCHAR TargetFileName;
3542
3543 /*
3544 * This code enumerates the list of files in reactos.dff / reactos.inf
3545 * that need to be extracted from reactos.cab and be installed in their
3546 * respective directories.
3547 */
3548
3549 /* Search for the SectionName section */
3550 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3551 {
3552 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
3553 return FALSE;
3554 }
3555
3556 /*
3557 * Enumerate the files in the section and add them to the file queue.
3558 */
3559 do
3560 {
3561 /* Get source file name and target directory id */
3562 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3563 {
3564 /* FIXME: Handle error! */
3565 DPRINT1("INF_GetData() failed\n");
3566 break;
3567 }
3568
3569 /* Get optional target file name */
3570 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
3571 TargetFileName = NULL;
3572
3573 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3574
3575 /* Lookup target directory */
3576 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3577 {
3578 /* FIXME: Handle error! */
3579 DPRINT1("SetupFindFirstLine() failed\n");
3580 INF_FreeData(FileKeyName);
3581 INF_FreeData(FileKeyValue);
3582 INF_FreeData(TargetFileName);
3583 break;
3584 }
3585
3586 INF_FreeData(FileKeyValue);
3587
3588 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3589 {
3590 /* FIXME: Handle error! */
3591 DPRINT1("INF_GetData() failed\n");
3592 INF_FreeData(FileKeyName);
3593 INF_FreeData(TargetFileName);
3594 break;
3595 }
3596
3597 if (!SetupQueueCopy(SetupFileQueue,
3598 SourceCabinet,
3599 USetupData.SourceRootPath.Buffer,
3600 USetupData.SourceRootDir.Buffer,
3601 FileKeyName,
3602 DirKeyValue,
3603 TargetFileName))
3604 {
3605 /* FIXME: Handle error! */
3606 DPRINT1("SetupQueueCopy() failed\n");
3607 }
3608
3609 INF_FreeData(FileKeyName);
3610 INF_FreeData(TargetFileName);
3611 INF_FreeData(DirKeyValue);
3612 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3613
3614 return TRUE;
3615 }
3616
3617
3618 static BOOLEAN
3619 AddSectionToCopyQueue(HINF InfFile,
3620 PWCHAR SectionName,
3621 PWCHAR SourceCabinet,
3622 PCUNICODE_STRING DestinationPath,
3623 PINPUT_RECORD Ir)
3624 {
3625 INFCONTEXT FilesContext;
3626 INFCONTEXT DirContext;
3627 PWCHAR FileKeyName;
3628 PWCHAR FileKeyValue;
3629 PWCHAR DirKeyValue;
3630 PWCHAR TargetFileName;
3631 WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
3632
3633 if (SourceCabinet)
3634 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
3635
3636 /*
3637 * This code enumerates the list of files in txtsetup.sif
3638 * that need to be installed in their respective directories.
3639 */
3640
3641 /* Search for the SectionName section */
3642 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3643 {
3644 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
3645 return FALSE;
3646 }
3647
3648 /*
3649 * Enumerate the files in the section and add them to the file queue.
3650 */
3651 do
3652 {
3653 /* Get source file name */
3654 if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
3655 {
3656 /* FIXME: Handle error! */
3657 DPRINT1("INF_GetData() failed\n");
3658 break;
3659 }
3660
3661 /* Get target directory id */
3662 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
3663 {
3664 /* FIXME: Handle error! */
3665 DPRINT1("INF_GetData() failed\n");
3666 INF_FreeData(FileKeyName);
3667 break;
3668 }
3669
3670 /* Get optional target file name */
3671 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
3672 TargetFileName = NULL;
3673 else if (!*TargetFileName)
3674 TargetFileName = NULL;
3675
3676 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3677
3678 /* Lookup target directory */
3679 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3680 {
3681 /* FIXME: Handle error! */
3682 DPRINT1("SetupFindFirstLine() failed\n");
3683 INF_FreeData(FileKeyName);
3684 INF_FreeData(FileKeyValue);
3685 INF_FreeData(TargetFileName);
3686 break;
3687 }
3688
3689 INF_FreeData(FileKeyValue);
3690
3691 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3692 {
3693 /* FIXME: Handle error! */
3694 DPRINT1("INF_GetData() failed\n");
3695 INF_FreeData(FileKeyName);
3696 INF_FreeData(TargetFileName);
3697 break;
3698 }
3699
3700 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3701 {
3702 /* Installation path */
3703 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3704
3705 RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3706 USetupData.SourceRootDir.Buffer);
3707
3708 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
3709 }
3710 else if (DirKeyValue[0] == L'\\')
3711 {
3712 /* Absolute path */
3713 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3714
3715 RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3716 DirKeyValue);
3717
3718 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
3719 }
3720 else // if (DirKeyValue[0] != L'\\')
3721 {
3722 /* Path relative to the installation path */
3723 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3724
3725 CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
3726 USetupData.SourceRootDir.Buffer, DirKeyValue);
3727
3728 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
3729 }
3730
3731 if (!SetupQueueCopy(SetupFileQueue,
3732 SourceCabinet,
3733 USetupData.SourceRootPath.Buffer,
3734 CompleteOrigDirName,
3735 FileKeyName,
3736 DirKeyValue,
3737 TargetFileName))
3738 {
3739 /* FIXME: Handle error! */
3740 DPRINT1("SetupQueueCopy() failed\n");
3741 }
3742
3743 INF_FreeData(FileKeyName);
3744 INF_FreeData(TargetFileName);
3745 INF_FreeData(DirKeyValue);
3746 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3747
3748 return TRUE;
3749 }
3750
3751
3752 static BOOLEAN
3753 PrepareCopyPageInfFile(HINF InfFile,
3754 PWCHAR SourceCabinet,
3755 PINPUT_RECORD Ir)
3756 {
3757 NTSTATUS Status;
3758 INFCONTEXT DirContext;
3759 PWCHAR AdditionalSectionName = NULL;
3760 PWCHAR DirKeyValue;
3761 WCHAR PathBuffer[MAX_PATH];
3762
3763 /* Add common files */
3764 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &USetupData.DestinationPath, Ir))
3765 return FALSE;
3766
3767 /* Add specific files depending of computer type */
3768 if (SourceCabinet == NULL)
3769 {
3770 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
3771 return FALSE;
3772
3773 if (AdditionalSectionName)
3774 {
3775 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
3776 return FALSE;
3777 }
3778 }
3779
3780 /* Create directories */
3781
3782 /*
3783 * FIXME:
3784 * Copying files to USetupData.DestinationRootPath should be done from within
3785 * the SystemPartitionFiles section.
3786 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3787 * For installing to USetupData.DestinationPath specify just '\' .
3788 */
3789
3790 /* Get destination path */
3791 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
3792
3793 DPRINT("FullPath(1): '%S'\n", PathBuffer);
3794
3795 /* Create the install directory */
3796 Status = SetupCreateDirectory(PathBuffer);
3797 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3798 {
3799 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
3800 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
3801 return FALSE;
3802 }
3803
3804 /* Search for the 'Directories' section */
3805 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3806 {
3807 if (SourceCabinet)
3808 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER, L"Directories");
3809 else
3810 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, L"Directories");
3811
3812 return FALSE;
3813 }
3814
3815 /* Enumerate the directory values and create the subdirectories */
3816 do
3817 {
3818 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3819 {
3820 DPRINT1("break\n");
3821 break;
3822 }
3823
3824 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3825 {
3826 /* Installation path */
3827 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3828
3829 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
3830 USetupData.DestinationPath.Buffer);
3831
3832 DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
3833 }
3834 else if (DirKeyValue[0] == L'\\')
3835 {
3836 /* Absolute path */
3837 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3838
3839 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3840 USetupData.DestinationRootPath.Buffer, DirKeyValue);
3841
3842 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
3843
3844 Status = SetupCreateDirectory(PathBuffer);
3845 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3846 {
3847 INF_FreeData(DirKeyValue);
3848 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3849 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3850 return FALSE;
3851 }
3852 }
3853 else // if (DirKeyValue[0] != L'\\')
3854 {
3855 /* Path relative to the installation path */
3856 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3857
3858 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3859 USetupData.DestinationPath.Buffer, DirKeyValue);
3860
3861 DPRINT("RelativePath(2): '%S'\n", PathBuffer);
3862
3863 Status = SetupCreateDirectory(PathBuffer);
3864 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3865 {
3866 INF_FreeData(DirKeyValue);
3867 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3868 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3869 return FALSE;
3870 }
3871 }
3872
3873 INF_FreeData(DirKeyValue);
3874 } while (SetupFindNextLine(&DirContext, &DirContext));
3875
3876 return TRUE;
3877 }
3878
3879
3880 /*
3881 * Displays the PrepareCopyPage.
3882 *
3883 * Next pages:
3884 * FileCopyPage(At once)
3885 * QuitPage
3886 *
3887 * SIDEEFFECTS
3888 * Inits SetupFileQueue
3889 * Calls PrepareCopyPageInfFile
3890 *
3891 * RETURNS
3892 * Number of the next page.
3893 */
3894 static PAGE_NUMBER
3895 PrepareCopyPage(PINPUT_RECORD Ir)
3896 {
3897 HINF InfHandle;
3898 WCHAR PathBuffer[MAX_PATH];
3899 INFCONTEXT CabinetsContext;
3900 ULONG InfFileSize;
3901 PWCHAR KeyValue;
3902 UINT ErrorLine;
3903 PVOID InfFileData;
3904
3905 MUIDisplayPage(PREPARE_COPY_PAGE);
3906
3907 /* Create the file queue */
3908 SetupFileQueue = SetupOpenFileQueue();
3909 if (SetupFileQueue == NULL)
3910 {
3911 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
3912 return QUIT_PAGE;
3913 }
3914
3915 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
3916 {
3917 /* FIXME: show an error dialog */
3918 return QUIT_PAGE;
3919 }
3920
3921 /* Search for the 'Cabinets' section */
3922 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
3923 {
3924 return FILE_COPY_PAGE;
3925 }
3926
3927 /*
3928 * Enumerate the directory values in the 'Cabinets'
3929 * section and parse their inf files.
3930 */
3931 do
3932 {
3933 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3934 break;
3935
3936 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3937 USetupData.SourcePath.Buffer, KeyValue);
3938
3939 CabinetInitialize();
3940 CabinetSetEventHandlers(NULL, NULL, NULL);
3941 CabinetSetCabinetName(PathBuffer);
3942
3943 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3944 {
3945 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3946
3947 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3948 if (InfFileData == NULL)
3949 {
3950 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3951 return QUIT_PAGE;
3952 }
3953 }
3954 else
3955 {
3956 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3957 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3958 return QUIT_PAGE;
3959 }
3960
3961 InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
3962 InfFileSize,
3963 NULL,
3964 INF_STYLE_WIN4,
3965 USetupData.LanguageId,
3966 &ErrorLine);
3967
3968 if (InfHandle == INVALID_HANDLE_VALUE)
3969 {
3970 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3971 return QUIT_PAGE;
3972 }
3973
3974 CabinetCleanup();
3975
3976 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3977 {
3978 /* FIXME: show an error dialog */
3979 return QUIT_PAGE;
3980 }
3981 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3982
3983 return FILE_COPY_PAGE;
3984 }
3985
3986
3987 VOID
3988 NTAPI
3989 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3990 IN BOOLEAN First)
3991 {
3992 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3993
3994 /* Get the memory information from the system */
3995 NtQuerySystemInformation(SystemPerformanceInformation,
3996 &PerfInfo,
3997 sizeof(PerfInfo),
3998 NULL);
3999
4000 /* Check if this is initial setup */
4001 if (First)
4002 {
4003 /* Set maximum limits to be total RAM pages */
4004 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
4005 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
4006 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
4007 }
4008
4009 /* Set current values */
4010 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
4011 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
4012 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
4013 }
4014
4015
4016 static UINT
4017 CALLBACK
4018 FileCopyCallback(PVOID Context,
4019 UINT Notification,
4020 UINT_PTR Param1,
4021 UINT_PTR Param2)
4022 {
4023 PCOPYCONTEXT CopyContext;
4024
4025 CopyContext = (PCOPYCONTEXT)Context;
4026
4027 switch (Notification)
4028 {
4029 case SPFILENOTIFY_STARTSUBQUEUE:
4030 CopyContext->TotalOperations = (ULONG)Param2;
4031 ProgressSetStepCount(CopyContext->ProgressBar,
4032 CopyContext->TotalOperations);
4033 SetupUpdateMemoryInfo(CopyContext, TRUE);
4034 break;
4035
4036 case SPFILENOTIFY_STARTCOPY:
4037 /* Display copy message */
4038 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
4039 SetupUpdateMemoryInfo(CopyContext, FALSE);
4040 break;
4041
4042 case SPFILENOTIFY_ENDCOPY:
4043 CopyContext->CompletedOperations++;
4044
4045 /* SYSREG checkpoint */
4046 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
4047 DPRINT1("CHECKPOINT:HALF_COPIED\n");
4048
4049 ProgressNextStep(CopyContext->ProgressBar);
4050 SetupUpdateMemoryInfo(CopyContext, FALSE);
4051 break;
4052 }
4053
4054 return 0;
4055 }
4056
4057
4058 /*
4059 * Displays the FileCopyPage.
4060 *
4061 * Next pages:
4062 * RegistryPage(At once)
4063 *
4064 * SIDEEFFECTS
4065 * Calls SetupCommitFileQueueW
4066 * Calls SetupCloseFileQueue
4067 *
4068 * RETURNS
4069 * Number of the next page.
4070 */
4071 static PAGE_NUMBER
4072 FileCopyPage(PINPUT_RECORD Ir)
4073 {
4074 COPYCONTEXT CopyContext;
4075 unsigned int mem_bar_width;
4076
4077 MUIDisplayPage(FILE_COPY_PAGE);
4078
4079 /* Create context for the copy process */
4080 CopyContext.DestinationRootPath = USetupData.DestinationRootPath.Buffer;
4081 CopyContext.InstallPath = InstallPath.Buffer;
4082 CopyContext.TotalOperations = 0;
4083 CopyContext.CompletedOperations = 0;
4084
4085 /* Create the progress bar as well */
4086 CopyContext.ProgressBar = CreateProgressBar(13,
4087 26,
4088 xScreen - 13,
4089 yScreen - 20,
4090 10,
4091 24,
4092 TRUE,
4093 MUIGetString(STRING_SETUPCOPYINGFILES));
4094
4095 // fit memory bars to screen width, distribute them uniform
4096 mem_bar_width = (xScreen - 26) / 5;
4097 mem_bar_width -= mem_bar_width % 2; // make even
4098 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4099 /* Create the paged pool progress bar */
4100 CopyContext.MemoryBars[0] = CreateProgressBar(13,
4101 40,
4102 13 + mem_bar_width,
4103 43,
4104 13,
4105 44,
4106 FALSE,
4107 "Kernel Pool");
4108
4109 /* Create the non paged pool progress bar */
4110 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
4111 40,
4112 (xScreen / 2) + (mem_bar_width / 2),
4113 43,
4114 (xScreen / 2)- (mem_bar_width / 2),
4115 44,
4116 FALSE,
4117 "Kernel Cache");
4118
4119 /* Create the global memory progress bar */
4120 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
4121 40,
4122 xScreen - 13,
4123 43,
4124 xScreen - 13 - mem_bar_width,
4125 44,
4126 FALSE,
4127 "Free Memory");
4128
4129 /* Do the file copying */
4130 SetupCommitFileQueueW(NULL,
4131 SetupFileQueue,
4132 FileCopyCallback,
4133 &CopyContext);
4134
4135 /* If we get here, we're done, so cleanup the queue and progress bar */
4136 SetupCloseFileQueue(SetupFileQueue);
4137 DestroyProgressBar(CopyContext.ProgressBar);
4138 DestroyProgressBar(CopyContext.MemoryBars[0]);
4139 DestroyProgressBar(CopyContext.MemoryBars[1]);
4140 DestroyProgressBar(CopyContext.MemoryBars[2]);
4141
4142 /* Create the $winnt$.inf file */
4143 InstallSetupInfFile(&USetupData);
4144
4145 /* Go display the next page */
4146 return REGISTRY_PAGE;
4147 }
4148
4149
4150 static VOID
4151 __cdecl
4152 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...)
4153 {
4154 /* WARNING: Please keep this lookup table in sync with the resources! */
4155 static const UINT StringIDs[] =
4156 {
4157 STRING_DONE, /* Success */
4158 STRING_REGHIVEUPDATE, /* RegHiveUpdate */
4159 STRING_IMPORTFILE, /* ImportRegHive */
4160 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */
4161 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */
4162 STRING_ADDKBLAYOUTS, /* KeybLayouts */
4163 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */
4164 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */
4165 };
4166
4167 va_list args;
4168
4169 if (RegStatus < ARRAYSIZE(StringIDs))
4170 {
4171 va_start(args, RegStatus);
4172 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
4173 va_end(args);
4174 }
4175 else
4176 {
4177 CONSOLE_SetStatusText("Unknown status %d", RegStatus);
4178 }
4179 }
4180
4181 /*
4182 * Displays the RegistryPage.
4183 *
4184 * Next pages:
4185 * SuccessPage (if RepairUpdate)
4186 * BootLoaderPage (default)
4187 * QuitPage
4188 *
4189 * SIDEEFFECTS
4190 * Calls UpdateRegistry
4191 *
4192 * RETURNS
4193 * Number of the next page.
4194 */
4195 static PAGE_NUMBER
4196 RegistryPage(PINPUT_RECORD Ir)
4197 {
4198 ULONG Error;
4199
4200 MUIDisplayPage(REGISTRY_PAGE);
4201
4202 Error = UpdateRegistry(SetupInf,
4203 &USetupData,
4204 RepairUpdateFlag,
4205 PartitionList,
4206 DestinationDriveLetter,
4207 SelectedLanguageId,
4208 DisplayList,
4209 LayoutList,
4210 LanguageList,
4211 RegistryStatus);
4212 if (Error != ERROR_SUCCESS)
4213 {
4214 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
4215 return QUIT_PAGE;
4216 }
4217 else
4218 {
4219 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
4220 return BOOT_LOADER_PAGE;
4221 }
4222 }
4223
4224
4225 /*
4226 * Displays the BootLoaderPage.
4227 *
4228 * Next pages:
4229 * SuccessPage (if RepairUpdate)
4230 * BootLoaderHarddiskMbrPage
4231 * BootLoaderHarddiskVbrPage
4232 * BootLoaderFloppyPage
4233 * SuccessPage
4234 * QuitPage
4235 *
4236 * SIDEEFFECTS
4237 * Calls RegInitializeRegistry
4238 * Calls ImportRegistryFile
4239 * Calls SetDefaultPagefile
4240 * Calls SetMountedDeviceValues
4241 *
4242 * RETURNS
4243 * Number of the next page.
4244 */
4245 static PAGE_NUMBER
4246 BootLoaderPage(PINPUT_RECORD Ir)
4247 {
4248 UCHAR PartitionType;
4249 BOOLEAN InstallOnFloppy;
4250 USHORT Line = 12;
4251 WCHAR PathBuffer[MAX_PATH];
4252
4253 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4254
4255 RtlFreeUnicodeString(&USetupData.SystemRootPath);
4256 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
4257 L"\\Device\\Harddisk%lu\\Partition%lu\\",
4258 PartitionList->SystemPartition->DiskEntry->DiskNumber,
4259 PartitionList->SystemPartition->PartitionNumber);
4260 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
4261 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
4262
4263 PartitionType = PartitionList->SystemPartition->PartitionType;
4264
4265 /* For unattended setup, skip MBR installation or install on floppy if needed */
4266 if (IsUnattendedSetup)
4267 {
4268 if ((USetupData.MBRInstallType == 0) ||
4269 (USetupData.MBRInstallType == 1))
4270 {
4271 goto Quit;
4272 }
4273 }
4274
4275 /*
4276 * We may install an MBR or VBR, but before that, check whether
4277 * we need to actually install the VBR on floppy.
4278 */
4279 if (PartitionType == PARTITION_ENTRY_UNUSED)
4280 {
4281 DPRINT("Error: system partition invalid (unused)\n");
4282 InstallOnFloppy = TRUE;
4283 }
4284 else if (PartitionType == PARTITION_OS2BOOTMGR)
4285 {
4286 /* OS/2 boot manager partition */
4287 DPRINT("Found OS/2 boot manager partition\n");
4288 InstallOnFloppy = TRUE;
4289 }
4290 else if (PartitionType == PARTITION_EXT2)
4291 {
4292 /* Linux EXT2 partition */
4293 DPRINT("Found Linux EXT2 partition\n");
4294 InstallOnFloppy = FALSE;
4295 }
4296 else if (PartitionType == PARTITION_IFS)
4297 {
4298 /* NTFS partition */
4299 DPRINT("Found NTFS partition\n");
4300
4301 // FIXME: Make it FALSE when we'll support NTFS installation!
4302 InstallOnFloppy = TRUE;
4303 }
4304 else if ((PartitionType == PARTITION_FAT_12) ||
4305 (PartitionType == PARTITION_FAT_16) ||
4306 (PartitionType == PARTITION_HUGE) ||
4307 (PartitionType == PARTITION_XINT13) ||
4308 (PartitionType == PARTITION_FAT32) ||
4309 (PartitionType == PARTITION_FAT32_XINT13))
4310 {
4311 DPRINT("Found FAT partition\n");
4312 InstallOnFloppy = FALSE;
4313 }
4314 else
4315 {
4316 /* Unknown partition */
4317 DPRINT("Unknown partition found\n");
4318 InstallOnFloppy = TRUE;
4319 }
4320
4321 /* We should install on floppy */
4322 if (InstallOnFloppy)
4323 {
4324 USetupData.MBRInstallType = 1;
4325 goto Quit;
4326 }
4327
4328 /* Is it an unattended install on hdd? */
4329 if (IsUnattendedSetup)
4330 {
4331 if ((USetupData.MBRInstallType == 2) ||
4332 (USetupData.MBRInstallType == 3))
4333 {
4334 goto Quit;
4335 }
4336 }
4337
4338 MUIDisplayPage(BOOT_LOADER_PAGE);
4339 CONSOLE_InvertTextXY(8, Line, 60, 1);
4340
4341 while (TRUE)
4342 {
4343 CONSOLE_ConInKey(Ir);
4344
4345 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4346 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
4347 {
4348 CONSOLE_NormalTextXY(8, Line, 60, 1);
4349
4350 Line++;
4351 if (Line < 12)
4352 Line = 15;
4353
4354 if (Line > 15)
4355 Line = 12;
4356
4357 CONSOLE_InvertTextXY(8, Line, 60, 1);
4358 }
4359 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4360 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
4361 {
4362 CONSOLE_NormalTextXY(8, Line, 60, 1);
4363
4364 Line--;
4365 if (Line < 12)
4366 Line = 15;
4367
4368 if (Line > 15)
4369 Line = 12;
4370
4371 CONSOLE_InvertTextXY(8, Line, 60, 1);
4372 }
4373 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4374 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4375 {
4376 if (ConfirmQuit(Ir))
4377 return QUIT_PAGE;
4378
4379 break;
4380 }
4381 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4382 {
4383 if (Line == 12)
4384 {
4385 /* Install on both MBR and VBR */
4386 USetupData.MBRInstallType = 2;
4387 break;
4388 }
4389 else if (Line == 13)
4390 {
4391 /* Install on VBR only */
4392 USetupData.MBRInstallType = 3;
4393 break;
4394 }
4395 else if (Line == 14)
4396 {
4397 /* Install on floppy */
4398 USetupData.MBRInstallType = 1;
4399 break;
4400 }
4401 else if (Line == 15)
4402 {
4403 /* Skip MBR installation */
4404 USetupData.MBRInstallType = 0;
4405 break;
4406 }
4407
4408 return BOOT_LOADER_PAGE;
4409 }
4410 }
4411
4412 Quit:
4413 switch (USetupData.MBRInstallType)
4414 {
4415 /* Skip MBR installation */
4416 case 0:
4417 return SUCCESS_PAGE;
4418
4419 /* Install on floppy */
4420 case 1:
4421 return BOOT_LOADER_FLOPPY_PAGE;
4422
4423 /* Install on both MBR and VBR */
4424 case 2:
4425 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4426
4427 /* Install on VBR only */
4428 case 3:
4429 return BOOT_LOADER_HARDDISK_VBR_PAGE;
4430 }
4431
4432 return BOOT_LOADER_PAGE;
4433 }
4434
4435
4436 /*
4437 * Displays the BootLoaderFloppyPage.
4438 *
4439 * Next pages:
4440 * SuccessPage (At once)
4441 * QuitPage
4442 *
4443 * SIDEEFFECTS
4444 * Calls InstallFatBootcodeToFloppy()
4445 *
4446 * RETURNS
4447 * Number of the next page.
4448 */
4449 static PAGE_NUMBER
4450 BootLoaderFloppyPage(PINPUT_RECORD Ir)
4451 {
4452 NTSTATUS Status;
4453
4454 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
4455
4456 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4457
4458 while (TRUE)
4459 {
4460 CONSOLE_ConInKey(Ir);
4461
4462 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4463 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4464 {
4465 if (ConfirmQuit(Ir))
4466 return QUIT_PAGE;
4467
4468 break;
4469 }
4470 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4471 {
4472 Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath,
4473 &USetupData.DestinationArcPath);
4474 if (!NT_SUCCESS(Status))
4475 {
4476 if (Status == STATUS_DEVICE_NOT_READY)
4477 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
4478
4479 /* TODO: Print error message */
4480 return BOOT_LOADER_FLOPPY_PAGE;
4481 }
4482
4483 return SUCCESS_PAGE;
4484 }
4485 }
4486
4487 return BOOT_LOADER_FLOPPY_PAGE;
4488 }
4489
4490
4491 /*
4492 * Displays the BootLoaderHarddiskVbrPage.
4493 *
4494 * Next pages:
4495 * SuccessPage (At once)
4496 * QuitPage
4497 *
4498 * SIDEEFFECTS
4499 * Calls InstallVBRToPartition()
4500 *
4501 * RETURNS
4502 * Number of the next page.
4503 */
4504 static PAGE_NUMBER
4505 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
4506 {
4507 NTSTATUS Status;
4508
4509 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4510 &USetupData.SourceRootPath,
4511 &USetupData.DestinationArcPath,
4512 PartitionList->SystemPartition->PartitionType);
4513 if (!NT_SUCCESS(Status))
4514 {
4515 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4516 return QUIT_PAGE;
4517 }
4518
4519 return SUCCESS_PAGE;
4520 }
4521
4522
4523 /*
4524 * Displays the BootLoaderHarddiskMbrPage.
4525 *
4526 * Next pages:
4527 * SuccessPage (At once)
4528 * QuitPage
4529 *
4530 * SIDEEFFECTS
4531 * Calls InstallVBRToPartition()
4532 * Calls InstallMbrBootCodeToDisk()
4533 *
4534 * RETURNS
4535 * Number of the next page.
4536 */
4537 static PAGE_NUMBER
4538 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
4539 {
4540 NTSTATUS Status;
4541 WCHAR DestinationDevicePathBuffer[MAX_PATH];
4542
4543 /* Step 1: Write the VBR */
4544 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4545 &USetupData.SourceRootPath,
4546 &USetupData.DestinationArcPath,
4547 PartitionList->SystemPartition->PartitionType);
4548 if (!NT_SUCCESS(Status))
4549 {
4550 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4551 return QUIT_PAGE;
4552 }
4553
4554 /* Step 2: Write the MBR */
4555 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
4556 L"\\Device\\Harddisk%d\\Partition0",
4557 PartitionList->SystemPartition->DiskEntry->DiskNumber);
4558 Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath,
4559 &USetupData.SourceRootPath,
4560 DestinationDevicePathBuffer);
4561 if (!NT_SUCCESS(Status))
4562 {
4563 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
4564 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
4565 return QUIT_PAGE;
4566 }
4567
4568 return SUCCESS_PAGE;
4569 }
4570
4571
4572 /**
4573 * @name ProgressTimeOutStringHandler
4574 *
4575 * Handles the generation (displaying) of the timeout
4576 * countdown to the screen dynamically.
4577 *
4578 * @param Bar
4579 * A pointer to a progress bar.
4580 *
4581 * @param AlwaysUpdate
4582 * Constantly update the progress bar (boolean type).
4583 *
4584 * @param Buffer
4585 * A pointer to a string buffer.
4586 *
4587 * @param cchBufferSize
4588 * The buffer's size in number of characters.
4589 *
4590 * @return
4591 * TRUE or FALSE on function termination.
4592 *
4593 */
4594 static
4595 BOOLEAN NTAPI
4596 ProgressTimeOutStringHandler(
4597 IN PPROGRESSBAR Bar,
4598 IN BOOLEAN AlwaysUpdate,
4599 OUT PSTR Buffer,
4600 IN SIZE_T cchBufferSize)
4601 {
4602 ULONG OldProgress = Bar->Progress;
4603
4604 if (Bar->StepCount == 0)
4605 {
4606 Bar->Progress = 0;
4607 }
4608 else
4609 {
4610 Bar->Progress = Bar->StepCount - Bar->CurrentStep;
4611 }
4612
4613 /* Build the progress string if it has changed */
4614 if (Bar->ProgressFormatText &&
4615 (AlwaysUpdate || (Bar->Progress != OldProgress)))
4616 {
4617 RtlStringCchPrintfA(Buffer, cchBufferSize,
4618 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
4619
4620 return TRUE;
4621 }
4622
4623 return FALSE;
4624 }
4625
4626 /**
4627 * @name ProgressCountdown
4628 *
4629 * Displays and draws a red-coloured progress bar with a countdown.
4630 * When the timeout is reached, the flush page is displayed for reboot.
4631 *
4632 * @param Ir
4633 * A pointer to an input keyboard record.
4634 *
4635 * @param TimeOut
4636 * Initial countdown value in seconds.
4637 *
4638 * @return
4639 * Nothing.
4640 *
4641 */
4642 static VOID
4643 ProgressCountdown(
4644 IN PINPUT_RECORD Ir,
4645 IN LONG TimeOut)
4646 {
4647 NTSTATUS Status;
4648 ULONG StartTime, BarWidth, TimerDiv;
4649 LONG TimeElapsed;
4650 LONG TimerValue, OldTimerValue;
4651 LARGE_INTEGER Timeout;
4652 PPROGRESSBAR ProgressBar;
4653 BOOLEAN RefreshProgress = TRUE;
4654
4655 /* Bail out if the timeout is already zero */
4656 if (TimeOut <= 0)
4657 return;
4658
4659 /* Create the timeout progress bar and set it up */
4660 ProgressBar = CreateProgressBarEx(13,
4661 26,
4662 xScreen - 13,
4663 yScreen - 20,
4664 10,
4665 24,
4666 TRUE,
4667 FOREGROUND_RED | BACKGROUND_BLUE,
4668 0,
4669 NULL,
4670 MUIGetString(STRING_REBOOTPROGRESSBAR),
4671 ProgressTimeOutStringHandler);
4672
4673 BarWidth = max(1, ProgressBar->Width);
4674 TimerValue = TimeOut * BarWidth;
4675 ProgressSetStepCount(ProgressBar, TimerValue);
4676
4677 StartTime = NtGetTickCount();
4678 CONSOLE_Flush();
4679
4680 TimerDiv = 1000 / BarWidth;
4681 TimerDiv = max(1, TimerDiv);
4682 OldTimerValue = TimerValue;
4683 while (TRUE)
4684 {
4685 /* Decrease the timer */
4686
4687 /*
4688 * Compute how much time the previous operations took.
4689 * This allows us in particular to take account for any time
4690 * elapsed if something slowed down.
4691 */
4692 TimeElapsed = NtGetTickCount() - StartTime;
4693 if (TimeElapsed >= TimerDiv)
4694 {
4695 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4696 TimeElapsed /= TimerDiv;
4697 StartTime += (TimerDiv * TimeElapsed);
4698
4699 if (TimeElapsed <= TimerValue)
4700 TimerValue -= TimeElapsed;
4701 else
4702 TimerValue = 0;
4703
4704 RefreshProgress = TRUE;
4705 }
4706
4707 if (RefreshProgress)
4708 {
4709 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
4710 RefreshProgress = FALSE;
4711 }
4712
4713 /* Stop when the timer reaches zero */
4714 if (TimerValue <= 0)
4715 break;
4716
4717 /* Check for user key presses */
4718
4719 /*
4720 * If the timer is used, use a passive wait of maximum 1 second
4721 * while monitoring for incoming console input events, so that
4722 * we are still able to display the timing count.
4723 */
4724
4725 /* Wait a maximum of 1 second for input events */
4726 TimeElapsed = NtGetTickCount() - StartTime;
4727 if (TimeElapsed < TimerDiv)
4728 {
4729 /* Convert the time to NT Format */
4730 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
4731 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
4732 }
4733 else
4734 {
4735 Status = STATUS_TIMEOUT;
4736 }
4737
4738 /* Check whether the input event has been signaled, or a timeout happened */
4739 if (Status == STATUS_TIMEOUT)
4740 {
4741 continue;
4742 }
4743 if (Status != STATUS_WAIT_0)
4744 {
4745 /* An error happened, bail out */
4746 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
4747 break;
4748 }
4749
4750 /* Check for an ENTER key press */
4751 while (CONSOLE_ConInKeyPeek(Ir))
4752 {
4753 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4754 {
4755 /* Found it, stop waiting */
4756 goto Exit;
4757 }
4758 }
4759 }
4760
4761 Exit:
4762 /* Destroy the progress bar and quit */
4763 DestroyProgressBar(ProgressBar);
4764 }
4765
4766
4767 /*
4768 * Displays the QuitPage.
4769 *
4770 * Next pages:
4771 * FlushPage (At once)
4772 *
4773 * SIDEEFFECTS
4774 * Destroy the Lists
4775 *
4776 * RETURNS
4777 * Number of the next page.
4778 */
4779 static PAGE_NUMBER
4780 QuitPage(PINPUT_RECORD Ir)
4781 {
4782 MUIDisplayPage(QUIT_PAGE);
4783
4784 /* Destroy the NTOS installations list */
4785 if (NtOsInstallsList != NULL)
4786 {
4787 DestroyGenericList(NtOsInstallsList, TRUE);
4788 NtOsInstallsList = NULL;
4789 }
4790
4791 /* Destroy the partition list */
4792 if (PartitionList != NULL)
4793 {
4794 DestroyPartitionList(PartitionList);
4795 PartitionList = NULL;
4796 }
4797 TempPartition = NULL;
4798 FormatState = Start;
4799
4800 /* Destroy the filesystem list */
4801 if (FileSystemList != NULL)
4802 {
4803 DestroyFileSystemList(FileSystemList);
4804 FileSystemList = NULL;
4805 }
4806
4807 /* Destroy the computer settings list */
4808 if (ComputerList != NULL)
4809 {
4810 DestroyGenericList(ComputerList, TRUE);
4811 ComputerList = NULL;
4812 }
4813
4814 /* Destroy the display settings list */
4815 if (DisplayList != NULL)
4816 {
4817 DestroyGenericList(DisplayList, TRUE);
4818 DisplayList = NULL;
4819 }
4820
4821 /* Destroy the keyboard settings list */
4822 if (KeyboardList != NULL)
4823 {
4824 DestroyGenericList(KeyboardList, TRUE);
4825 KeyboardList = NULL;
4826 }
4827
4828 /* Destroy the keyboard layout list */
4829 if (LayoutList != NULL)
4830 {
4831 DestroyGenericList(LayoutList, TRUE);
4832 LayoutList = NULL;
4833 }
4834
4835 /* Destroy the languages list */
4836 if (LanguageList != NULL)
4837 {
4838 DestroyGenericList(LanguageList, FALSE);
4839 LanguageList = NULL;
4840 }
4841
4842 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
4843
4844 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4845 ProgressCountdown(Ir, 15);
4846 return FLUSH_PAGE;
4847 }
4848
4849
4850 /*
4851 * Displays the SuccessPage.
4852 *
4853 * Next pages:
4854 * FlushPage (At once)
4855 *
4856 * SIDEEFFECTS
4857 * Destroy the Lists
4858 *
4859 * RETURNS
4860 * Number of the next page.
4861 */
4862 static PAGE_NUMBER
4863 SuccessPage(PINPUT_RECORD Ir)
4864 {
4865 MUIDisplayPage(SUCCESS_PAGE);
4866
4867 if (IsUnattendedSetup)
4868 return FLUSH_PAGE;
4869
4870 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4871 ProgressCountdown(Ir, 15);
4872 return FLUSH_PAGE;
4873 }
4874
4875
4876 /*
4877 * Displays the FlushPage.
4878 *
4879 * Next pages:
4880 * RebootPage (At once)
4881 *
4882 * RETURNS
4883 * Number of the next page.
4884 */
4885 static PAGE_NUMBER
4886 FlushPage(PINPUT_RECORD Ir)
4887 {
4888 MUIDisplayPage(FLUSH_PAGE);
4889 return REBOOT_PAGE;
4890 }
4891
4892
4893 DWORD WINAPI
4894 PnpEventThread(IN LPVOID lpParameter);
4895
4896
4897 /*
4898 * The start routine and page management
4899 */
4900 NTSTATUS
4901 RunUSetup(VOID)
4902 {
4903 NTSTATUS Status;
4904 INPUT_RECORD Ir;
4905 PAGE_NUMBER Page;
4906 BOOLEAN Old;
4907
4908 InfSetHeap(ProcessHeap);
4909
4910 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4911 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
4912 if (!NT_SUCCESS(Status))
4913 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
4914
4915 /* Create the PnP thread in suspended state */
4916 Status = RtlCreateUserThread(NtCurrentProcess(),
4917 NULL,
4918 TRUE,
4919 0,
4920 0,
4921 0,
4922 PnpEventThread,
4923 &SetupInf,
4924 &hPnpThread,
4925 NULL);
4926 if (!NT_SUCCESS(Status))
4927 hPnpThread = NULL;
4928
4929 if (!CONSOLE_Init())
4930 {
4931 PrintString(MUIGetString(STRING_CONSOLEFAIL1));
4932 PrintString(MUIGetString(STRING_CONSOLEFAIL2));
4933 PrintString(MUIGetString(STRING_CONSOLEFAIL3));
4934
4935 /* We failed to initialize the video, just quit the installer */
4936 return STATUS_APP_INIT_FAILURE;
4937 }
4938
4939 /* Initialize global unicode strings */
4940 RtlInitUnicodeString(&USetupData.SourcePath, NULL);
4941 RtlInitUnicodeString(&USetupData.SourceRootPath, NULL);
4942 RtlInitUnicodeString(&USetupData.SourceRootDir, NULL);
4943 RtlInitUnicodeString(&InstallPath, NULL);
4944 RtlInitUnicodeString(&USetupData.DestinationPath, NULL);
4945 RtlInitUnicodeString(&USetupData.DestinationArcPath, NULL);
4946 RtlInitUnicodeString(&USetupData.DestinationRootPath, NULL);
4947 RtlInitUnicodeString(&USetupData.SystemRootPath, NULL);
4948
4949 /* Hide the cursor */
4950 CONSOLE_SetCursorType(TRUE, FALSE);
4951
4952 /* Global Initialization page */
4953 CONSOLE_ClearScreen();
4954 CONSOLE_Flush();
4955 Page = SetupStartPage(&Ir);
4956
4957 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
4958 {
4959 CONSOLE_ClearScreen();
4960 CONSOLE_Flush();
4961
4962 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4963 // CONSOLE_Flush();
4964
4965 switch (Page)
4966 {
4967 /* Language page */
4968 case LANGUAGE_PAGE:
4969 Page = LanguagePage(&Ir);
4970 break;
4971
4972 /* Welcome page */
4973 case WELCOME_PAGE:
4974 Page = WelcomePage(&Ir);
4975 break;
4976
4977 /* License page */
4978 case LICENSE_PAGE:
4979 Page = LicensePage(&Ir);
4980 break;
4981
4982 /* Install pages */
4983 case INSTALL_INTRO_PAGE:
4984 Page = InstallIntroPage(&Ir);
4985 break;
4986
4987 #if 0
4988 case SCSI_CONTROLLER_PAGE:
4989 Page = ScsiControllerPage(&Ir);
4990 break;
4991
4992 case OEM_DRIVER_PAGE:
4993 Page = OemDriverPage(&Ir);
4994 break;
4995 #endif
4996
4997 case DEVICE_SETTINGS_PAGE:
4998 Page = DeviceSettingsPage(&Ir);
4999 break;
5000
5001 case COMPUTER_SETTINGS_PAGE:
5002 Page = ComputerSettingsPage(&Ir);
5003 break;
5004
5005 case DISPLAY_SETTINGS_PAGE:
5006 Page = DisplaySettingsPage(&Ir);
5007 break;
5008
5009 case KEYBOARD_SETTINGS_PAGE:
5010 Page = KeyboardSettingsPage(&Ir);
5011 break;
5012
5013 case LAYOUT_SETTINGS_PAGE:
5014 Page = LayoutSettingsPage(&Ir);
5015 break;
5016
5017 case SELECT_PARTITION_PAGE:
5018 Page = SelectPartitionPage(&Ir);
5019 break;
5020
5021 case CREATE_PRIMARY_PARTITION_PAGE:
5022 Page = CreatePrimaryPartitionPage(&Ir);
5023 break;
5024
5025 case CREATE_EXTENDED_PARTITION_PAGE:
5026 Page = CreateExtendedPartitionPage(&Ir);
5027 break;
5028
5029 case CREATE_LOGICAL_PARTITION_PAGE:
5030 Page = CreateLogicalPartitionPage(&Ir);
5031 break;
5032
5033 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE:
5034 Page = ConfirmDeleteSystemPartitionPage(&Ir);
5035 break;
5036
5037 case DELETE_PARTITION_PAGE:
5038 Page = DeletePartitionPage(&Ir);
5039 break;
5040
5041 case SELECT_FILE_SYSTEM_PAGE:
5042 Page = SelectFileSystemPage(&Ir);
5043 break;
5044
5045 case FORMAT_PARTITION_PAGE:
5046 Page = FormatPartitionPage(&Ir);
5047 break;
5048
5049 case CHECK_FILE_SYSTEM_PAGE:
5050 Page = CheckFileSystemPage(&Ir);
5051 break;
5052
5053 case INSTALL_DIRECTORY_PAGE:
5054 Page = InstallDirectoryPage(&Ir);
5055 break;
5056
5057 case PREPARE_COPY_PAGE:
5058 Page = PrepareCopyPage(&Ir);
5059 break;
5060
5061 case FILE_COPY_PAGE:
5062 Page = FileCopyPage(&Ir);
5063 break;
5064
5065 case REGISTRY_PAGE:
5066 Page = RegistryPage(&Ir);
5067 break;
5068
5069 case BOOT_LOADER_PAGE:
5070 Page = BootLoaderPage(&Ir);
5071 break;
5072
5073 case BOOT_LOADER_FLOPPY_PAGE:
5074 Page = BootLoaderFloppyPage(&Ir);
5075 break;
5076
5077 case BOOT_LOADER_HARDDISK_MBR_PAGE:
5078 Page = BootLoaderHarddiskMbrPage(&Ir);
5079 break;
5080
5081 case BOOT_LOADER_HARDDISK_VBR_PAGE:
5082 Page = BootLoaderHarddiskVbrPage(&Ir);
5083 break;
5084
5085 /* Repair pages */
5086 case REPAIR_INTRO_PAGE:
5087 Page = RepairIntroPage(&Ir);
5088 break;
5089
5090 case UPGRADE_REPAIR_PAGE:
5091 Page = UpgradeRepairPage(&Ir);
5092 break;
5093
5094 case SUCCESS_PAGE:
5095 Page = SuccessPage(&Ir);
5096 break;
5097
5098 case FLUSH_PAGE:
5099 Page = FlushPage(&Ir);
5100 break;
5101
5102 case QUIT_PAGE:
5103 Page = QuitPage(&Ir);
5104 break;
5105
5106 case RECOVERY_PAGE:
5107 case REBOOT_PAGE:
5108 break;
5109 }
5110 }
5111
5112 SetupCloseInfFile(SetupInf);
5113
5114 if (Page == RECOVERY_PAGE)
5115 RecoveryConsole();
5116
5117 FreeConsole();
5118
5119 /* Reboot */
5120 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
5121 NtShutdownSystem(ShutdownReboot);
5122 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
5123
5124 return STATUS_SUCCESS;
5125 }
5126
5127
5128 VOID NTAPI
5129 NtProcessStartup(PPEB Peb)
5130 {
5131 NTSTATUS Status;
5132 LARGE_INTEGER Time;
5133
5134 RtlNormalizeProcessParams(Peb->ProcessParameters);
5135
5136 ProcessHeap = Peb->ProcessHeap;
5137
5138 NtQuerySystemTime(&Time);
5139
5140 Status = RunUSetup();
5141
5142 if (NT_SUCCESS(Status))
5143 {
5144 /*
5145 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5146 * a protective waiting.
5147 * This wait is needed because, since we are started as SMSS.EXE,
5148 * the NT kernel explicitly waits 5 seconds for the initial process
5149 * SMSS.EXE to initialize (as a protective measure), and otherwise
5150 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5151 */
5152 Time.QuadPart += 50000000;
5153 NtDelayExecution(FALSE, &Time);
5154 }
5155 else
5156 {
5157 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5158 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
5159 0, 0, NULL, 0, NULL);
5160 }
5161
5162 NtTerminateProcess(NtCurrentProcess(), Status);
5163 }
5164
5165 /* EOF */