[SETUPLIB][USETUP] Don't store UI-related display strings in GENERIC_LIST_ENTRY-ies...
[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 /* If there's just a single language in the list skip
512 * the language selection process altogether! */
513 if (GenericListHasSingleEntry(LanguageList))
514 {
515 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
516 return WELCOME_PAGE;
517 }
518
519 InitGenericListUi(&ListUi, LanguageList, GetSettingDescription);
520 DrawGenericList(&ListUi,
521 2, 18,
522 xScreen - 3,
523 yScreen - 3);
524
525 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
526
527 MUIDisplayPage(LANGUAGE_PAGE);
528
529 while (TRUE)
530 {
531 CONSOLE_ConInKey(Ir);
532
533 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
534 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
535 {
536 ScrollDownGenericList(&ListUi);
537 RefreshPage = TRUE;
538 }
539 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
540 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
541 {
542 ScrollUpGenericList(&ListUi);
543 RefreshPage = TRUE;
544 }
545 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
546 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
547 {
548 ScrollPageDownGenericList(&ListUi);
549 RefreshPage = TRUE;
550 }
551 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
552 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
553 {
554 ScrollPageUpGenericList(&ListUi);
555 RefreshPage = TRUE;
556 }
557 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
558 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
559 {
560 if (ConfirmQuit(Ir))
561 return QUIT_PAGE;
562 else
563 RedrawGenericList(&ListUi);
564 }
565 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
566 {
567 //
568 // FIXME: That stuff crashes when the list is empty!!
569 //
570 SelectedLanguageId =
571 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(LanguageList)))->Id;
572
573 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
574
575 if (wcscmp(SelectedLanguageId, DefaultLanguage))
576 {
577 UpdateKBLayout();
578 }
579
580 /* Load the font */
581 SetConsoleCodePage();
582
583 return WELCOME_PAGE;
584 }
585 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
586 {
587 /* a-z */
588 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
589 RefreshPage = TRUE;
590 }
591
592 if (RefreshPage)
593 {
594 //
595 // FIXME: That stuff crashes when the list is empty!!
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 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
901 {
902 RepairUpdateFlag = FALSE;
903
904 // return INSTALL_INTRO_PAGE;
905 return DEVICE_SETTINGS_PAGE;
906 // return SCSI_CONTROLLER_PAGE;
907 }
908
909 MUIDisplayPage(UPGRADE_REPAIR_PAGE);
910
911 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
912 DrawGenericList(&ListUi,
913 2, 23,
914 xScreen - 3,
915 yScreen - 3);
916
917 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
918 while (TRUE)
919 {
920 CONSOLE_ConInKey(Ir);
921
922 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
923 {
924 switch (Ir->Event.KeyEvent.wVirtualKeyCode)
925 {
926 case VK_DOWN: /* DOWN */
927 ScrollDownGenericList(&ListUi);
928 break;
929 case VK_UP: /* UP */
930 ScrollUpGenericList(&ListUi);
931 break;
932 case VK_NEXT: /* PAGE DOWN */
933 ScrollPageDownGenericList(&ListUi);
934 break;
935 case VK_PRIOR: /* PAGE UP */
936 ScrollPageUpGenericList(&ListUi);
937 break;
938 case VK_F3: /* F3 */
939 {
940 if (ConfirmQuit(Ir))
941 return QUIT_PAGE;
942 else
943 RedrawGenericList(&ListUi);
944 break;
945 }
946 case VK_ESCAPE: /* ESC */
947 {
948 RestoreGenericListUiState(&ListUi);
949 // return nextPage; // prevPage;
950
951 // return INSTALL_INTRO_PAGE;
952 return DEVICE_SETTINGS_PAGE;
953 // return SCSI_CONTROLLER_PAGE;
954 }
955 }
956 }
957 else
958 {
959 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
960 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
961 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
962 {
963 /* Retrieve the current installation */
964 //
965 // FIXME: That stuff crashes when the list is empty!!
966 //
967 CurrentInstallation =
968 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList));
969
970 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
971 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
972
973 RepairUpdateFlag = TRUE;
974
975 // return nextPage;
976 /***/return INSTALL_INTRO_PAGE;/***/
977 }
978 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
979 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */
980 {
981 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
982 }
983 }
984 }
985
986 return UPGRADE_REPAIR_PAGE;
987 }
988
989
990 /*
991 * Displays the InstallIntroPage.
992 *
993 * Next pages:
994 * DeviceSettingsPage (At once if repair or update is selected)
995 * SelectPartitionPage (At once if unattended setup)
996 * DeviceSettingsPage (default)
997 * QuitPage
998 *
999 * RETURNS
1000 * Number of the next page.
1001 */
1002 static PAGE_NUMBER
1003 InstallIntroPage(PINPUT_RECORD Ir)
1004 {
1005 if (RepairUpdateFlag)
1006 {
1007 #if 1 /* Old code that looks good */
1008
1009 // return SELECT_PARTITION_PAGE;
1010 return DEVICE_SETTINGS_PAGE;
1011
1012 #else /* Possible new code? */
1013
1014 return DEVICE_SETTINGS_PAGE;
1015 // return SCSI_CONTROLLER_PAGE;
1016
1017 #endif
1018 }
1019
1020 if (IsUnattendedSetup)
1021 return SELECT_PARTITION_PAGE;
1022
1023 MUIDisplayPage(INSTALL_INTRO_PAGE);
1024
1025 while (TRUE)
1026 {
1027 CONSOLE_ConInKey(Ir);
1028
1029 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1030 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1031 {
1032 if (ConfirmQuit(Ir))
1033 return QUIT_PAGE;
1034
1035 break;
1036 }
1037 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1038 {
1039 return UPGRADE_REPAIR_PAGE;
1040 }
1041 }
1042
1043 return INSTALL_INTRO_PAGE;
1044 }
1045
1046
1047 #if 0
1048 static PAGE_NUMBER
1049 ScsiControllerPage(PINPUT_RECORD Ir)
1050 {
1051 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1052
1053 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1054
1055 /* FIXME: print loaded mass storage driver descriptions */
1056 #if 0
1057 CONSOLE_SetTextXY(8, 10, "TEST device");
1058 #endif
1059
1060 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1061
1062 while (TRUE)
1063 {
1064 CONSOLE_ConInKey(Ir);
1065
1066 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1067 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1068 {
1069 if (ConfirmQuit(Ir))
1070 return QUIT_PAGE;
1071
1072 break;
1073 }
1074 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1075 {
1076 return DEVICE_SETTINGS_PAGE;
1077 }
1078 }
1079
1080 return SCSI_CONTROLLER_PAGE;
1081 }
1082
1083 static PAGE_NUMBER
1084 OemDriverPage(PINPUT_RECORD Ir)
1085 {
1086 // MUIDisplayPage(OEM_DRIVER_PAGE);
1087
1088 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1089
1090 /* FIXME: Implement!! */
1091
1092 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1093
1094 while (TRUE)
1095 {
1096 CONSOLE_ConInKey(Ir);
1097
1098 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1099 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1100 {
1101 if (ConfirmQuit(Ir))
1102 return QUIT_PAGE;
1103
1104 break;
1105 }
1106 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1107 {
1108 return DEVICE_SETTINGS_PAGE;
1109 }
1110 }
1111
1112 return OEM_DRIVER_PAGE;
1113 }
1114 #endif
1115
1116
1117 /*
1118 * Displays the DeviceSettingsPage.
1119 *
1120 * Next pages:
1121 * SelectPartitionPage (At once if repair or update is selected)
1122 * ComputerSettingsPage
1123 * DisplaySettingsPage
1124 * KeyboardSettingsPage
1125 * LayoutsettingsPage
1126 * SelectPartitionPage
1127 * QuitPage
1128 *
1129 * SIDEEFFECTS
1130 * Init ComputerList
1131 * Init DisplayList
1132 * Init KeyboardList
1133 * Init LayoutList
1134 *
1135 * RETURNS
1136 * Number of the next page.
1137 */
1138 static PAGE_NUMBER
1139 DeviceSettingsPage(PINPUT_RECORD Ir)
1140 {
1141 static ULONG Line = 16;
1142
1143 /* Initialize the computer settings list */
1144 if (ComputerList == NULL)
1145 {
1146 ComputerList = CreateComputerTypeList(SetupInf);
1147 if (ComputerList == NULL)
1148 {
1149 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1150 return QUIT_PAGE;
1151 }
1152 }
1153
1154 /* Initialize the display settings list */
1155 if (DisplayList == NULL)
1156 {
1157 DisplayList = CreateDisplayDriverList(SetupInf);
1158 if (DisplayList == NULL)
1159 {
1160 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1161 return QUIT_PAGE;
1162 }
1163 }
1164
1165 /* Initialize the keyboard settings list */
1166 if (KeyboardList == NULL)
1167 {
1168 KeyboardList = CreateKeyboardDriverList(SetupInf);
1169 if (KeyboardList == NULL)
1170 {
1171 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1172 return QUIT_PAGE;
1173 }
1174 }
1175
1176 /* Initialize the keyboard layout list */
1177 if (LayoutList == NULL)
1178 {
1179 LayoutList = CreateKeyboardLayoutList(SetupInf, SelectedLanguageId, DefaultKBLayout);
1180 if (LayoutList == NULL)
1181 {
1182 /* FIXME: report error */
1183 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1184 return QUIT_PAGE;
1185 }
1186 }
1187
1188 if (RepairUpdateFlag)
1189 return SELECT_PARTITION_PAGE;
1190
1191 // if (IsUnattendedSetup)
1192 // return SELECT_PARTITION_PAGE;
1193
1194 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1195
1196 DrawGenericListCurrentItem(ComputerList, GetSettingDescription, 25, 11);
1197 DrawGenericListCurrentItem(DisplayList , GetSettingDescription, 25, 12);
1198 DrawGenericListCurrentItem(KeyboardList, GetSettingDescription, 25, 13);
1199 DrawGenericListCurrentItem(LayoutList , GetSettingDescription, 25, 14);
1200
1201 CONSOLE_InvertTextXY(24, Line, 48, 1);
1202
1203 while (TRUE)
1204 {
1205 CONSOLE_ConInKey(Ir);
1206
1207 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1208 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1209 {
1210 CONSOLE_NormalTextXY(24, Line, 48, 1);
1211
1212 if (Line == 14)
1213 Line = 16;
1214 else if (Line == 16)
1215 Line = 11;
1216 else
1217 Line++;
1218
1219 CONSOLE_InvertTextXY(24, Line, 48, 1);
1220 }
1221 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1222 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1223 {
1224 CONSOLE_NormalTextXY(24, Line, 48, 1);
1225
1226 if (Line == 11)
1227 Line = 16;
1228 else if (Line == 16)
1229 Line = 14;
1230 else
1231 Line--;
1232
1233 CONSOLE_InvertTextXY(24, Line, 48, 1);
1234 }
1235 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1236 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1237 {
1238 if (ConfirmQuit(Ir))
1239 return QUIT_PAGE;
1240
1241 break;
1242 }
1243 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1244 {
1245 if (Line == 11)
1246 return COMPUTER_SETTINGS_PAGE;
1247 else if (Line == 12)
1248 return DISPLAY_SETTINGS_PAGE;
1249 else if (Line == 13)
1250 return KEYBOARD_SETTINGS_PAGE;
1251 else if (Line == 14)
1252 return LAYOUT_SETTINGS_PAGE;
1253 else if (Line == 16)
1254 return SELECT_PARTITION_PAGE;
1255 }
1256 }
1257
1258 return DEVICE_SETTINGS_PAGE;
1259 }
1260
1261
1262 /*
1263 * Handles generic selection lists.
1264 *
1265 * PARAMS
1266 * GenericList: The list to handle.
1267 * nextPage: The page it needs to jump to after this page.
1268 * Ir: The PINPUT_RECORD
1269 */
1270 static PAGE_NUMBER
1271 HandleGenericList(PGENERIC_LIST_UI ListUi,
1272 PAGE_NUMBER nextPage,
1273 PINPUT_RECORD Ir)
1274 {
1275 while (TRUE)
1276 {
1277 CONSOLE_ConInKey(Ir);
1278
1279 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1280 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1281 {
1282 ScrollDownGenericList(ListUi);
1283 }
1284 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1285 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1286 {
1287 ScrollUpGenericList(ListUi);
1288 }
1289 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1290 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1291 {
1292 ScrollPageDownGenericList(ListUi);
1293 }
1294 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1295 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1296 {
1297 ScrollPageUpGenericList(ListUi);
1298 }
1299 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1300 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1301 {
1302 if (ConfirmQuit(Ir))
1303 return QUIT_PAGE;
1304 else
1305 RedrawGenericList(ListUi);
1306 }
1307 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1308 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1309 {
1310 RestoreGenericListUiState(ListUi);
1311 return nextPage; // Use some "prevPage;" instead?
1312 }
1313 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1314 {
1315 return nextPage;
1316 }
1317 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1318 {
1319 /* a-z */
1320 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1321 }
1322 }
1323 }
1324
1325
1326 /*
1327 * Displays the ComputerSettingsPage.
1328 *
1329 * Next pages:
1330 * DeviceSettingsPage
1331 * QuitPage
1332 *
1333 * RETURNS
1334 * Number of the next page.
1335 */
1336 static PAGE_NUMBER
1337 ComputerSettingsPage(PINPUT_RECORD Ir)
1338 {
1339 GENERIC_LIST_UI ListUi;
1340 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1341
1342 InitGenericListUi(&ListUi, ComputerList, GetSettingDescription);
1343 DrawGenericList(&ListUi,
1344 2, 18,
1345 xScreen - 3,
1346 yScreen - 3);
1347
1348 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1349 }
1350
1351
1352 /*
1353 * Displays the DisplaySettingsPage.
1354 *
1355 * Next pages:
1356 * DeviceSettingsPage
1357 * QuitPage
1358 *
1359 * RETURNS
1360 * Number of the next page.
1361 */
1362 static PAGE_NUMBER
1363 DisplaySettingsPage(PINPUT_RECORD Ir)
1364 {
1365 GENERIC_LIST_UI ListUi;
1366 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1367
1368 InitGenericListUi(&ListUi, DisplayList, GetSettingDescription);
1369 DrawGenericList(&ListUi,
1370 2, 18,
1371 xScreen - 3,
1372 yScreen - 3);
1373
1374 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1375 }
1376
1377
1378 /*
1379 * Displays the KeyboardSettingsPage.
1380 *
1381 * Next pages:
1382 * DeviceSettingsPage
1383 * QuitPage
1384 *
1385 * RETURNS
1386 * Number of the next page.
1387 */
1388 static PAGE_NUMBER
1389 KeyboardSettingsPage(PINPUT_RECORD Ir)
1390 {
1391 GENERIC_LIST_UI ListUi;
1392 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1393
1394 InitGenericListUi(&ListUi, KeyboardList, GetSettingDescription);
1395 DrawGenericList(&ListUi,
1396 2, 18,
1397 xScreen - 3,
1398 yScreen - 3);
1399
1400 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1401 }
1402
1403
1404 /*
1405 * Displays the LayoutSettingsPage.
1406 *
1407 * Next pages:
1408 * DeviceSettingsPage
1409 * QuitPage
1410 *
1411 * RETURNS
1412 * Number of the next page.
1413 */
1414 static PAGE_NUMBER
1415 LayoutSettingsPage(PINPUT_RECORD Ir)
1416 {
1417 GENERIC_LIST_UI ListUi;
1418 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1419
1420 InitGenericListUi(&ListUi, LayoutList, GetSettingDescription);
1421 DrawGenericList(&ListUi,
1422 2, 18,
1423 xScreen - 3,
1424 yScreen - 3);
1425
1426 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1427 }
1428
1429
1430 static BOOL
1431 IsDiskSizeValid(PPARTENTRY PartEntry)
1432 {
1433 ULONGLONG size;
1434
1435 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1436 size = (size + (512 * KB)) / MB; /* in MBytes */
1437
1438 if (size < USetupData.RequiredPartitionDiskSpace)
1439 {
1440 /* Partition is too small so ask for another one */
1441 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
1442 return FALSE;
1443 }
1444 else
1445 {
1446 return TRUE;
1447 }
1448 }
1449
1450
1451 /*
1452 * Displays the SelectPartitionPage.
1453 *
1454 * Next pages:
1455 * SelectFileSystemPage (At once if unattended)
1456 * SelectFileSystemPage (Default if free space is selected)
1457 * CreatePrimaryPartitionPage
1458 * CreateExtendedPartitionPage
1459 * CreateLogicalPartitionPage
1460 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1461 * DeletePartitionPage
1462 * QuitPage
1463 *
1464 * SIDEEFFECTS
1465 * Set InstallShortcut (only if not unattended + free space is selected)
1466 *
1467 * RETURNS
1468 * Number of the next page.
1469 */
1470 static PAGE_NUMBER
1471 SelectPartitionPage(PINPUT_RECORD Ir)
1472 {
1473 PARTLIST_UI ListUi;
1474 ULONG Error;
1475
1476 if (PartitionList == NULL)
1477 {
1478 PartitionList = CreatePartitionList();
1479 if (PartitionList == NULL)
1480 {
1481 /* FIXME: show an error dialog */
1482 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1483 return QUIT_PAGE;
1484 }
1485 else if (IsListEmpty(&PartitionList->DiskListHead))
1486 {
1487 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1488 return QUIT_PAGE;
1489 }
1490
1491 TempPartition = NULL;
1492 FormatState = Start;
1493 }
1494
1495 if (RepairUpdateFlag)
1496 {
1497 /* Determine the selected installation disk & partition */
1498 if (!SelectPartition(PartitionList,
1499 CurrentInstallation->DiskNumber,
1500 CurrentInstallation->PartitionNumber))
1501 {
1502 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1503 ASSERT(FALSE);
1504 }
1505
1506 return SELECT_FILE_SYSTEM_PAGE;
1507 }
1508
1509 MUIDisplayPage(SELECT_PARTITION_PAGE);
1510
1511 InitPartitionListUi(&ListUi, PartitionList,
1512 2,
1513 23,
1514 xScreen - 3,
1515 yScreen - 3);
1516 DrawPartitionList(&ListUi);
1517
1518 if (IsUnattendedSetup)
1519 {
1520 if (!SelectPartition(PartitionList,
1521 USetupData.DestinationDiskNumber,
1522 USetupData.DestinationPartitionNumber))
1523 {
1524 if (USetupData.AutoPartition)
1525 {
1526 if (PartitionList->CurrentPartition->LogicalPartition)
1527 {
1528 CreateLogicalPartition(PartitionList,
1529 PartitionList->CurrentPartition->SectorCount.QuadPart,
1530 TRUE);
1531 }
1532 else
1533 {
1534 CreatePrimaryPartition(PartitionList,
1535 PartitionList->CurrentPartition->SectorCount.QuadPart,
1536 TRUE);
1537 }
1538
1539 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1540 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1541 {
1542 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1543 USetupData.RequiredPartitionDiskSpace);
1544 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1545 }
1546
1547 return SELECT_FILE_SYSTEM_PAGE;
1548 }
1549 }
1550 else
1551 {
1552 DrawPartitionList(&ListUi);
1553
1554 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1555 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1556 {
1557 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1558 USetupData.RequiredPartitionDiskSpace);
1559 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1560 }
1561
1562 return SELECT_FILE_SYSTEM_PAGE;
1563 }
1564 }
1565
1566 while (TRUE)
1567 {
1568 /* Update status text */
1569 if (PartitionList->CurrentPartition == NULL)
1570 {
1571 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1572 }
1573 else if (PartitionList->CurrentPartition->LogicalPartition)
1574 {
1575 if (PartitionList->CurrentPartition->IsPartitioned)
1576 {
1577 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1578 }
1579 else
1580 {
1581 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1582 }
1583 }
1584 else
1585 {
1586 if (PartitionList->CurrentPartition->IsPartitioned)
1587 {
1588 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1589 {
1590 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1591 }
1592 else
1593 {
1594 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1595 }
1596 }
1597 else
1598 {
1599 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1600 }
1601 }
1602
1603 CONSOLE_ConInKey(Ir);
1604
1605 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1606 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1607 {
1608 if (ConfirmQuit(Ir))
1609 {
1610 DestroyPartitionList(PartitionList);
1611 PartitionList = NULL;
1612 return QUIT_PAGE;
1613 }
1614
1615 break;
1616 }
1617 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1618 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1619 {
1620 ScrollDownPartitionList(&ListUi);
1621 }
1622 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1623 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1624 {
1625 ScrollUpPartitionList(&ListUi);
1626 }
1627 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1628 {
1629 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1630 continue; // return SELECT_PARTITION_PAGE;
1631
1632 if (PartitionList->CurrentPartition == NULL ||
1633 PartitionList->CurrentPartition->IsPartitioned == FALSE)
1634 {
1635 if (PartitionList->CurrentPartition->LogicalPartition)
1636 {
1637 CreateLogicalPartition(PartitionList,
1638 0ULL,
1639 TRUE);
1640 }
1641 else
1642 {
1643 CreatePrimaryPartition(PartitionList,
1644 0ULL,
1645 TRUE);
1646 }
1647 }
1648
1649 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1650 {
1651 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1652 USetupData.RequiredPartitionDiskSpace);
1653 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1654 }
1655
1656 return SELECT_FILE_SYSTEM_PAGE;
1657 }
1658 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1659 {
1660 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1661 {
1662 Error = PrimaryPartitionCreationChecks(PartitionList);
1663 if (Error != NOT_AN_ERROR)
1664 {
1665 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1666 return SELECT_PARTITION_PAGE;
1667 }
1668
1669 return CREATE_PRIMARY_PARTITION_PAGE;
1670 }
1671 }
1672 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1673 {
1674 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1675 {
1676 Error = ExtendedPartitionCreationChecks(PartitionList);
1677 if (Error != NOT_AN_ERROR)
1678 {
1679 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1680 return SELECT_PARTITION_PAGE;
1681 }
1682
1683 return CREATE_EXTENDED_PARTITION_PAGE;
1684 }
1685 }
1686 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1687 {
1688 if (PartitionList->CurrentPartition->LogicalPartition)
1689 {
1690 Error = LogicalPartitionCreationChecks(PartitionList);
1691 if (Error != NOT_AN_ERROR)
1692 {
1693 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1694 return SELECT_PARTITION_PAGE;
1695 }
1696
1697 return CREATE_LOGICAL_PARTITION_PAGE;
1698 }
1699 }
1700 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1701 {
1702 WCHAR PathBuffer[MAX_PATH];
1703 UNICODE_STRING CurrentPartition;
1704
1705 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1706 {
1707 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1708 return SELECT_PARTITION_PAGE;
1709 }
1710
1711 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1712 L"\\Device\\Harddisk%lu\\Partition%lu\\",
1713 PartitionList->CurrentDisk->DiskNumber,
1714 PartitionList->CurrentPartition->PartitionNumber);
1715 RtlInitUnicodeString(&CurrentPartition, PathBuffer);
1716
1717 /*
1718 * Check whether the user attempts to delete the partition on which
1719 * the installation source is present. If so, fail with an error.
1720 */
1721 // &USetupData.SourceRootPath
1722 if (RtlPrefixUnicodeString(&CurrentPartition, &USetupData.SourcePath, TRUE))
1723 {
1724 PopupError("You cannot delete the partition containing the installation source!",
1725 MUIGetString(STRING_CONTINUE),
1726 Ir, POPUP_WAIT_ENTER);
1727 return SELECT_PARTITION_PAGE;
1728 }
1729
1730 if (PartitionList->CurrentPartition->BootIndicator ||
1731 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1732 {
1733 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1734 }
1735
1736 return DELETE_PARTITION_PAGE;
1737 }
1738 }
1739
1740 return SELECT_PARTITION_PAGE;
1741 }
1742
1743
1744 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1745 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1746 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1747
1748 static VOID
1749 ShowPartitionSizeInputBox(SHORT Left,
1750 SHORT Top,
1751 SHORT Right,
1752 SHORT Bottom,
1753 ULONG MaxSize,
1754 PWSTR InputBuffer,
1755 PBOOLEAN Quit,
1756 PBOOLEAN Cancel)
1757 {
1758 INPUT_RECORD Ir;
1759 COORD coPos;
1760 DWORD Written;
1761 CHAR Buffer[128];
1762 INT Length, Pos;
1763 WCHAR ch;
1764 SHORT iLeft;
1765 SHORT iTop;
1766
1767 if (Quit != NULL)
1768 *Quit = FALSE;
1769
1770 if (Cancel != NULL)
1771 *Cancel = FALSE;
1772
1773 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1774
1775 /* Print message */
1776 coPos.X = Left + 2;
1777 coPos.Y = Top + 2;
1778 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1779 iLeft = coPos.X + strlen(Buffer) + 1;
1780 iTop = coPos.Y;
1781
1782 WriteConsoleOutputCharacterA(StdOutput,
1783 Buffer,
1784 strlen(Buffer),
1785 coPos,
1786 &Written);
1787
1788 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1789 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1790 coPos.Y = iTop;
1791 WriteConsoleOutputCharacterA(StdOutput,
1792 Buffer,
1793 strlen(Buffer),
1794 coPos,
1795 &Written);
1796
1797 swprintf(InputBuffer, L"%lu", MaxSize);
1798 Length = wcslen(InputBuffer);
1799 Pos = Length;
1800 CONSOLE_SetInputTextXY(iLeft,
1801 iTop,
1802 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1803 InputBuffer);
1804 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1805 CONSOLE_SetCursorType(TRUE, TRUE);
1806
1807 while (TRUE)
1808 {
1809 CONSOLE_ConInKey(&Ir);
1810
1811 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1812 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1813 {
1814 if (Quit != NULL)
1815 *Quit = TRUE;
1816
1817 InputBuffer[0] = UNICODE_NULL;
1818 CONSOLE_SetCursorType(TRUE, FALSE);
1819 break;
1820 }
1821 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1822 {
1823 CONSOLE_SetCursorType(TRUE, FALSE);
1824 break;
1825 }
1826 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1827 {
1828 if (Cancel != NULL)
1829 *Cancel = TRUE;
1830
1831 InputBuffer[0] = UNICODE_NULL;
1832 CONSOLE_SetCursorType(TRUE, FALSE);
1833 break;
1834 }
1835 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1836 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1837 {
1838 Pos = 0;
1839 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1840 }
1841 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1842 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1843 {
1844 Pos = Length;
1845 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1846 }
1847 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1848 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1849 {
1850 if (Pos > 0)
1851 {
1852 Pos--;
1853 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1854 }
1855 }
1856 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1857 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1858 {
1859 if (Pos < Length)
1860 {
1861 Pos++;
1862 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1863 }
1864 }
1865 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1866 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1867 {
1868 if (Pos < Length)
1869 {
1870 memmove(&InputBuffer[Pos],
1871 &InputBuffer[Pos + 1],
1872 (Length - Pos - 1) * sizeof(WCHAR));
1873 InputBuffer[Length - 1] = UNICODE_NULL;
1874
1875 Length--;
1876 CONSOLE_SetInputTextXY(iLeft,
1877 iTop,
1878 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1879 InputBuffer);
1880 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1881 }
1882 }
1883 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1884 {
1885 if (Pos > 0)
1886 {
1887 if (Pos < Length)
1888 memmove(&InputBuffer[Pos - 1],
1889 &InputBuffer[Pos],
1890 (Length - Pos) * sizeof(WCHAR));
1891 InputBuffer[Length - 1] = UNICODE_NULL;
1892
1893 Pos--;
1894 Length--;
1895 CONSOLE_SetInputTextXY(iLeft,
1896 iTop,
1897 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1898 InputBuffer);
1899 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1900 }
1901 }
1902 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1903 {
1904 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1905 {
1906 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1907
1908 if ((ch >= L'0') && (ch <= L'9'))
1909 {
1910 if (Pos < Length)
1911 memmove(&InputBuffer[Pos + 1],
1912 &InputBuffer[Pos],
1913 (Length - Pos) * sizeof(WCHAR));
1914 InputBuffer[Length + 1] = UNICODE_NULL;
1915 InputBuffer[Pos] = ch;
1916
1917 Pos++;
1918 Length++;
1919 CONSOLE_SetInputTextXY(iLeft,
1920 iTop,
1921 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1922 InputBuffer);
1923 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1924 }
1925 }
1926 }
1927 }
1928 }
1929
1930
1931 /*
1932 * Displays the CreatePrimaryPartitionPage.
1933 *
1934 * Next pages:
1935 * SelectPartitionPage
1936 * SelectFileSystemPage (default)
1937 * QuitPage
1938 *
1939 * RETURNS
1940 * Number of the next page.
1941 */
1942 static PAGE_NUMBER
1943 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1944 {
1945 PDISKENTRY DiskEntry;
1946 PPARTENTRY PartEntry;
1947 BOOLEAN Quit;
1948 BOOLEAN Cancel;
1949 WCHAR InputBuffer[50];
1950 ULONG MaxSize;
1951 ULONGLONG PartSize;
1952 ULONGLONG DiskSize;
1953 ULONGLONG SectorCount;
1954 PCHAR Unit;
1955
1956 if (PartitionList == NULL ||
1957 PartitionList->CurrentDisk == NULL ||
1958 PartitionList->CurrentPartition == NULL)
1959 {
1960 /* FIXME: show an error dialog */
1961 return QUIT_PAGE;
1962 }
1963
1964 DiskEntry = PartitionList->CurrentDisk;
1965 PartEntry = PartitionList->CurrentPartition;
1966
1967 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1968
1969 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1970
1971 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1972 #if 0
1973 if (DiskSize >= 10 * GB) /* 10 GB */
1974 {
1975 DiskSize = DiskSize / GB;
1976 Unit = MUIGetString(STRING_GB);
1977 }
1978 else
1979 #endif
1980 {
1981 DiskSize = DiskSize / MB;
1982 if (DiskSize == 0)
1983 DiskSize = 1;
1984
1985 Unit = MUIGetString(STRING_MB);
1986 }
1987
1988 if (DiskEntry->DriverName.Length > 0)
1989 {
1990 CONSOLE_PrintTextXY(6, 10,
1991 MUIGetString(STRING_HDINFOPARTCREATE_1),
1992 DiskSize,
1993 Unit,
1994 DiskEntry->DiskNumber,
1995 DiskEntry->Port,
1996 DiskEntry->Bus,
1997 DiskEntry->Id,
1998 &DiskEntry->DriverName,
1999 DiskEntry->NoMbr ? "GPT" : "MBR");
2000 }
2001 else
2002 {
2003 CONSOLE_PrintTextXY(6, 10,
2004 MUIGetString(STRING_HDINFOPARTCREATE_2),
2005 DiskSize,
2006 Unit,
2007 DiskEntry->DiskNumber,
2008 DiskEntry->Port,
2009 DiskEntry->Bus,
2010 DiskEntry->Id,
2011 DiskEntry->NoMbr ? "GPT" : "MBR");
2012 }
2013
2014 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2015
2016 #if 0
2017 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2018 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2019 #endif
2020
2021 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2022
2023 PartEntry = PartitionList->CurrentPartition;
2024 while (TRUE)
2025 {
2026 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2027
2028 if (MaxSize > PARTITION_MAXSIZE)
2029 MaxSize = PARTITION_MAXSIZE;
2030
2031 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2032 MaxSize, InputBuffer, &Quit, &Cancel);
2033
2034 if (Quit)
2035 {
2036 if (ConfirmQuit(Ir))
2037 return QUIT_PAGE;
2038
2039 break;
2040 }
2041 else if (Cancel)
2042 {
2043 return SELECT_PARTITION_PAGE;
2044 }
2045 else
2046 {
2047 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2048
2049 if (PartSize < 1)
2050 {
2051 /* Too small */
2052 continue;
2053 }
2054
2055 if (PartSize > MaxSize)
2056 {
2057 /* Too large */
2058 continue;
2059 }
2060
2061 /* Convert to bytes */
2062 if (PartSize == MaxSize)
2063 {
2064 /* Use all of the unpartitioned disk space */
2065 SectorCount = PartEntry->SectorCount.QuadPart;
2066 }
2067 else
2068 {
2069 /* Calculate the sector count from the size in MB */
2070 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2071
2072 /* But never get larger than the unpartitioned disk space */
2073 if (SectorCount > PartEntry->SectorCount.QuadPart)
2074 SectorCount = PartEntry->SectorCount.QuadPart;
2075 }
2076
2077 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2078
2079 CreatePrimaryPartition(PartitionList,
2080 SectorCount,
2081 FALSE);
2082
2083 return SELECT_PARTITION_PAGE;
2084 }
2085 }
2086
2087 return CREATE_PRIMARY_PARTITION_PAGE;
2088 }
2089
2090
2091 /*
2092 * Displays the CreateExtendedPartitionPage.
2093 *
2094 * Next pages:
2095 * SelectPartitionPage (default)
2096 * QuitPage
2097 *
2098 * RETURNS
2099 * Number of the next page.
2100 */
2101 static PAGE_NUMBER
2102 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2103 {
2104 PDISKENTRY DiskEntry;
2105 PPARTENTRY PartEntry;
2106 BOOLEAN Quit;
2107 BOOLEAN Cancel;
2108 WCHAR InputBuffer[50];
2109 ULONG MaxSize;
2110 ULONGLONG PartSize;
2111 ULONGLONG DiskSize;
2112 ULONGLONG SectorCount;
2113 PCHAR Unit;
2114
2115 if (PartitionList == NULL ||
2116 PartitionList->CurrentDisk == NULL ||
2117 PartitionList->CurrentPartition == NULL)
2118 {
2119 /* FIXME: show an error dialog */
2120 return QUIT_PAGE;
2121 }
2122
2123 DiskEntry = PartitionList->CurrentDisk;
2124 PartEntry = PartitionList->CurrentPartition;
2125
2126 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2127
2128 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2129
2130 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2131 #if 0
2132 if (DiskSize >= 10 * GB) /* 10 GB */
2133 {
2134 DiskSize = DiskSize / GB;
2135 Unit = MUIGetString(STRING_GB);
2136 }
2137 else
2138 #endif
2139 {
2140 DiskSize = DiskSize / MB;
2141 if (DiskSize == 0)
2142 DiskSize = 1;
2143
2144 Unit = MUIGetString(STRING_MB);
2145 }
2146
2147 if (DiskEntry->DriverName.Length > 0)
2148 {
2149 CONSOLE_PrintTextXY(6, 10,
2150 MUIGetString(STRING_HDINFOPARTCREATE_1),
2151 DiskSize,
2152 Unit,
2153 DiskEntry->DiskNumber,
2154 DiskEntry->Port,
2155 DiskEntry->Bus,
2156 DiskEntry->Id,
2157 &DiskEntry->DriverName,
2158 DiskEntry->NoMbr ? "GPT" : "MBR");
2159 }
2160 else
2161 {
2162 CONSOLE_PrintTextXY(6, 10,
2163 MUIGetString(STRING_HDINFOPARTCREATE_2),
2164 DiskSize,
2165 Unit,
2166 DiskEntry->DiskNumber,
2167 DiskEntry->Port,
2168 DiskEntry->Bus,
2169 DiskEntry->Id,
2170 DiskEntry->NoMbr ? "GPT" : "MBR");
2171 }
2172
2173 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2174
2175 #if 0
2176 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2177 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2178 #endif
2179
2180 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2181
2182 PartEntry = PartitionList->CurrentPartition;
2183 while (TRUE)
2184 {
2185 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2186
2187 if (MaxSize > PARTITION_MAXSIZE)
2188 MaxSize = PARTITION_MAXSIZE;
2189
2190 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2191 MaxSize, InputBuffer, &Quit, &Cancel);
2192
2193 if (Quit)
2194 {
2195 if (ConfirmQuit(Ir))
2196 return QUIT_PAGE;
2197
2198 break;
2199 }
2200 else if (Cancel)
2201 {
2202 return SELECT_PARTITION_PAGE;
2203 }
2204 else
2205 {
2206 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2207
2208 if (PartSize < 1)
2209 {
2210 /* Too small */
2211 continue;
2212 }
2213
2214 if (PartSize > MaxSize)
2215 {
2216 /* Too large */
2217 continue;
2218 }
2219
2220 /* Convert to bytes */
2221 if (PartSize == MaxSize)
2222 {
2223 /* Use all of the unpartitioned disk space */
2224 SectorCount = PartEntry->SectorCount.QuadPart;
2225 }
2226 else
2227 {
2228 /* Calculate the sector count from the size in MB */
2229 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2230
2231 /* But never get larger than the unpartitioned disk space */
2232 if (SectorCount > PartEntry->SectorCount.QuadPart)
2233 SectorCount = PartEntry->SectorCount.QuadPart;
2234 }
2235
2236 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2237
2238 CreateExtendedPartition(PartitionList,
2239 SectorCount);
2240
2241 return SELECT_PARTITION_PAGE;
2242 }
2243 }
2244
2245 return CREATE_EXTENDED_PARTITION_PAGE;
2246 }
2247
2248
2249 /*
2250 * Displays the CreateLogicalPartitionPage.
2251 *
2252 * Next pages:
2253 * SelectFileSystemPage (default)
2254 * QuitPage
2255 *
2256 * RETURNS
2257 * Number of the next page.
2258 */
2259 static PAGE_NUMBER
2260 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2261 {
2262 PDISKENTRY DiskEntry;
2263 PPARTENTRY PartEntry;
2264 BOOLEAN Quit;
2265 BOOLEAN Cancel;
2266 WCHAR InputBuffer[50];
2267 ULONG MaxSize;
2268 ULONGLONG PartSize;
2269 ULONGLONG DiskSize;
2270 ULONGLONG SectorCount;
2271 PCHAR Unit;
2272
2273 if (PartitionList == NULL ||
2274 PartitionList->CurrentDisk == NULL ||
2275 PartitionList->CurrentPartition == NULL)
2276 {
2277 /* FIXME: show an error dialog */
2278 return QUIT_PAGE;
2279 }
2280
2281 DiskEntry = PartitionList->CurrentDisk;
2282 PartEntry = PartitionList->CurrentPartition;
2283
2284 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2285
2286 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2287
2288 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2289 #if 0
2290 if (DiskSize >= 10 * GB) /* 10 GB */
2291 {
2292 DiskSize = DiskSize / GB;
2293 Unit = MUIGetString(STRING_GB);
2294 }
2295 else
2296 #endif
2297 {
2298 DiskSize = DiskSize / MB;
2299 if (DiskSize == 0)
2300 DiskSize = 1;
2301
2302 Unit = MUIGetString(STRING_MB);
2303 }
2304
2305 if (DiskEntry->DriverName.Length > 0)
2306 {
2307 CONSOLE_PrintTextXY(6, 10,
2308 MUIGetString(STRING_HDINFOPARTCREATE_1),
2309 DiskSize,
2310 Unit,
2311 DiskEntry->DiskNumber,
2312 DiskEntry->Port,
2313 DiskEntry->Bus,
2314 DiskEntry->Id,
2315 &DiskEntry->DriverName,
2316 DiskEntry->NoMbr ? "GPT" : "MBR");
2317 }
2318 else
2319 {
2320 CONSOLE_PrintTextXY(6, 10,
2321 MUIGetString(STRING_HDINFOPARTCREATE_2),
2322 DiskSize,
2323 Unit,
2324 DiskEntry->DiskNumber,
2325 DiskEntry->Port,
2326 DiskEntry->Bus,
2327 DiskEntry->Id,
2328 DiskEntry->NoMbr ? "GPT" : "MBR");
2329 }
2330
2331 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2332
2333 #if 0
2334 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2335 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2336 #endif
2337
2338 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2339
2340 PartEntry = PartitionList->CurrentPartition;
2341 while (TRUE)
2342 {
2343 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2344
2345 if (MaxSize > PARTITION_MAXSIZE)
2346 MaxSize = PARTITION_MAXSIZE;
2347
2348 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2349 MaxSize, InputBuffer, &Quit, &Cancel);
2350
2351 if (Quit)
2352 {
2353 if (ConfirmQuit(Ir))
2354 return QUIT_PAGE;
2355
2356 break;
2357 }
2358 else if (Cancel)
2359 {
2360 return SELECT_PARTITION_PAGE;
2361 }
2362 else
2363 {
2364 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2365
2366 if (PartSize < 1)
2367 {
2368 /* Too small */
2369 continue;
2370 }
2371
2372 if (PartSize > MaxSize)
2373 {
2374 /* Too large */
2375 continue;
2376 }
2377
2378 /* Convert to bytes */
2379 if (PartSize == MaxSize)
2380 {
2381 /* Use all of the unpartitioned disk space */
2382 SectorCount = PartEntry->SectorCount.QuadPart;
2383 }
2384 else
2385 {
2386 /* Calculate the sector count from the size in MB */
2387 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2388
2389 /* But never get larger than the unpartitioned disk space */
2390 if (SectorCount > PartEntry->SectorCount.QuadPart)
2391 SectorCount = PartEntry->SectorCount.QuadPart;
2392 }
2393
2394 DPRINT("Partition size: %I64u bytes\n", PartSize);
2395
2396 CreateLogicalPartition(PartitionList,
2397 SectorCount,
2398 FALSE);
2399
2400 return SELECT_PARTITION_PAGE;
2401 }
2402 }
2403
2404 return CREATE_LOGICAL_PARTITION_PAGE;
2405 }
2406
2407
2408 /*
2409 * Displays the ConfirmDeleteSystemPartitionPage.
2410 *
2411 * Next pages:
2412 * DeletePartitionPage (default)
2413 * SelectPartitionPage
2414 *
2415 * RETURNS
2416 * Number of the next page.
2417 */
2418 static PAGE_NUMBER
2419 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2420 {
2421 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2422
2423 while (TRUE)
2424 {
2425 CONSOLE_ConInKey(Ir);
2426
2427 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2428 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2429 {
2430 if (ConfirmQuit(Ir))
2431 return QUIT_PAGE;
2432
2433 break;
2434 }
2435 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2436 {
2437 return DELETE_PARTITION_PAGE;
2438 }
2439 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2440 {
2441 return SELECT_PARTITION_PAGE;
2442 }
2443 }
2444
2445 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2446 }
2447
2448
2449 /*
2450 * Displays the DeletePartitionPage.
2451 *
2452 * Next pages:
2453 * SelectPartitionPage (default)
2454 * QuitPage
2455 *
2456 * RETURNS
2457 * Number of the next page.
2458 */
2459 static PAGE_NUMBER
2460 DeletePartitionPage(PINPUT_RECORD Ir)
2461 {
2462 PDISKENTRY DiskEntry;
2463 PPARTENTRY PartEntry;
2464 ULONGLONG DiskSize;
2465 ULONGLONG PartSize;
2466 PCHAR Unit;
2467 CHAR PartTypeString[32];
2468
2469 if (PartitionList == NULL ||
2470 PartitionList->CurrentDisk == NULL ||
2471 PartitionList->CurrentPartition == NULL)
2472 {
2473 /* FIXME: show an error dialog */
2474 return QUIT_PAGE;
2475 }
2476
2477 DiskEntry = PartitionList->CurrentDisk;
2478 PartEntry = PartitionList->CurrentPartition;
2479
2480 MUIDisplayPage(DELETE_PARTITION_PAGE);
2481
2482 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2483 PartTypeString,
2484 ARRAYSIZE(PartTypeString));
2485
2486 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2487 #if 0
2488 if (PartSize >= 10 * GB) /* 10 GB */
2489 {
2490 PartSize = PartSize / GB;
2491 Unit = MUIGetString(STRING_GB);
2492 }
2493 else
2494 #endif
2495 if (PartSize >= 10 * MB) /* 10 MB */
2496 {
2497 PartSize = PartSize / MB;
2498 Unit = MUIGetString(STRING_MB);
2499 }
2500 else
2501 {
2502 PartSize = PartSize / KB;
2503 Unit = MUIGetString(STRING_KB);
2504 }
2505
2506 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2507 {
2508 CONSOLE_PrintTextXY(6, 10,
2509 MUIGetString(STRING_HDDINFOUNK2),
2510 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2511 (PartEntry->DriveLetter == 0) ? '-' : ':',
2512 PartEntry->PartitionType,
2513 PartSize,
2514 Unit);
2515 }
2516 else
2517 {
2518 CONSOLE_PrintTextXY(6, 10,
2519 " %c%c %s %I64u %s",
2520 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2521 (PartEntry->DriveLetter == 0) ? '-' : ':',
2522 PartTypeString,
2523 PartSize,
2524 Unit);
2525 }
2526
2527 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2528 #if 0
2529 if (DiskSize >= 10 * GB) /* 10 GB */
2530 {
2531 DiskSize = DiskSize / GB;
2532 Unit = MUIGetString(STRING_GB);
2533 }
2534 else
2535 #endif
2536 {
2537 DiskSize = DiskSize / MB;
2538 if (DiskSize == 0)
2539 DiskSize = 1;
2540
2541 Unit = MUIGetString(STRING_MB);
2542 }
2543
2544 if (DiskEntry->DriverName.Length > 0)
2545 {
2546 CONSOLE_PrintTextXY(6, 12,
2547 MUIGetString(STRING_HDINFOPARTDELETE_1),
2548 DiskSize,
2549 Unit,
2550 DiskEntry->DiskNumber,
2551 DiskEntry->Port,
2552 DiskEntry->Bus,
2553 DiskEntry->Id,
2554 &DiskEntry->DriverName,
2555 DiskEntry->NoMbr ? "GPT" : "MBR");
2556 }
2557 else
2558 {
2559 CONSOLE_PrintTextXY(6, 12,
2560 MUIGetString(STRING_HDINFOPARTDELETE_2),
2561 DiskSize,
2562 Unit,
2563 DiskEntry->DiskNumber,
2564 DiskEntry->Port,
2565 DiskEntry->Bus,
2566 DiskEntry->Id,
2567 DiskEntry->NoMbr ? "GPT" : "MBR");
2568 }
2569
2570 while (TRUE)
2571 {
2572 CONSOLE_ConInKey(Ir);
2573
2574 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2575 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2576 {
2577 if (ConfirmQuit(Ir))
2578 return QUIT_PAGE;
2579
2580 break;
2581 }
2582 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2583 {
2584 return SELECT_PARTITION_PAGE;
2585 }
2586 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2587 {
2588 DeleteCurrentPartition(PartitionList);
2589
2590 return SELECT_PARTITION_PAGE;
2591 }
2592 }
2593
2594 return DELETE_PARTITION_PAGE;
2595 }
2596
2597
2598 /*
2599 * Displays the SelectFileSystemPage.
2600 *
2601 * Next pages:
2602 * CheckFileSystemPage (At once if RepairUpdate is selected)
2603 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2604 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2605 * SelectPartitionPage (If the user aborts)
2606 * FormatPartitionPage (Default)
2607 * QuitPage
2608 *
2609 * SIDEEFFECTS
2610 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2611 * Calls CheckActiveSystemPartition()
2612 *
2613 * RETURNS
2614 * Number of the next page.
2615 */
2616 static PAGE_NUMBER
2617 SelectFileSystemPage(PINPUT_RECORD Ir)
2618 {
2619 PDISKENTRY DiskEntry;
2620 PPARTENTRY PartEntry;
2621 ULONGLONG DiskSize;
2622 ULONGLONG PartSize;
2623 PCHAR DiskUnit;
2624 PCHAR PartUnit;
2625 CHAR PartTypeString[32];
2626 FORMATMACHINESTATE PreviousFormatState;
2627
2628 DPRINT("SelectFileSystemPage()\n");
2629
2630 if (PartitionList == NULL ||
2631 PartitionList->CurrentDisk == NULL ||
2632 PartitionList->CurrentPartition == NULL)
2633 {
2634 /* FIXME: show an error dialog */
2635 return QUIT_PAGE;
2636 }
2637
2638 /* Find or set the active system partition */
2639 CheckActiveSystemPartition(PartitionList);
2640 if (PartitionList->SystemPartition == NULL)
2641 {
2642 /* FIXME: show an error dialog */
2643 //
2644 // Error dialog should say that we cannot find a suitable
2645 // system partition and create one on the system. At this point,
2646 // it may be nice to ask the user whether he wants to continue,
2647 // or use an external drive as the system drive/partition
2648 // (e.g. floppy, USB drive, etc...)
2649 //
2650 return QUIT_PAGE;
2651 }
2652
2653 PreviousFormatState = FormatState;
2654 switch (FormatState)
2655 {
2656 case Start:
2657 {
2658 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2659 {
2660 TempPartition = PartitionList->SystemPartition;
2661 TempPartition->NeedsCheck = TRUE;
2662
2663 FormatState = FormatSystemPartition;
2664 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2665 }
2666 else
2667 {
2668 TempPartition = PartitionList->CurrentPartition;
2669 TempPartition->NeedsCheck = TRUE;
2670
2671 FormatState = FormatInstallPartition;
2672 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2673 }
2674 break;
2675 }
2676
2677 case FormatSystemPartition:
2678 {
2679 TempPartition = PartitionList->CurrentPartition;
2680 TempPartition->NeedsCheck = TRUE;
2681
2682 FormatState = FormatInstallPartition;
2683 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2684 break;
2685 }
2686
2687 case FormatInstallPartition:
2688 {
2689 if (GetNextUnformattedPartition(PartitionList,
2690 NULL,
2691 &TempPartition))
2692 {
2693 FormatState = FormatOtherPartition;
2694 TempPartition->NeedsCheck = TRUE;
2695 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2696 }
2697 else
2698 {
2699 FormatState = FormatDone;
2700 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2701 return CHECK_FILE_SYSTEM_PAGE;
2702 }
2703 break;
2704 }
2705
2706 case FormatOtherPartition:
2707 {
2708 if (GetNextUnformattedPartition(PartitionList,
2709 NULL,
2710 &TempPartition))
2711 {
2712 FormatState = FormatOtherPartition;
2713 TempPartition->NeedsCheck = TRUE;
2714 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2715 }
2716 else
2717 {
2718 FormatState = FormatDone;
2719 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2720 return CHECK_FILE_SYSTEM_PAGE;
2721 }
2722 break;
2723 }
2724
2725 default:
2726 {
2727 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2728 /* FIXME: show an error dialog */
2729 return QUIT_PAGE;
2730 }
2731 }
2732
2733 PartEntry = TempPartition;
2734 DiskEntry = PartEntry->DiskEntry;
2735
2736 /* Adjust disk size */
2737 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2738 if (DiskSize >= 10 * GB) /* 10 GB */
2739 {
2740 DiskSize = DiskSize / GB;
2741 DiskUnit = MUIGetString(STRING_GB);
2742 }
2743 else
2744 {
2745 DiskSize = DiskSize / MB;
2746 DiskUnit = MUIGetString(STRING_MB);
2747 }
2748
2749 /* Adjust partition size */
2750 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2751 if (PartSize >= 10 * GB) /* 10 GB */
2752 {
2753 PartSize = PartSize / GB;
2754 PartUnit = MUIGetString(STRING_GB);
2755 }
2756 else
2757 {
2758 PartSize = PartSize / MB;
2759 PartUnit = MUIGetString(STRING_MB);
2760 }
2761
2762 /* Adjust partition type */
2763 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2764 PartTypeString,
2765 ARRAYSIZE(PartTypeString));
2766
2767 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2768
2769 if (PartEntry->AutoCreate)
2770 {
2771 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2772
2773 #if 0
2774 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2775 PartEntry->PartitionNumber,
2776 PartSize,
2777 PartUnit,
2778 PartTypeString);
2779 #endif
2780
2781 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2782 DiskEntry->DiskNumber,
2783 DiskSize,
2784 DiskUnit,
2785 DiskEntry->Port,
2786 DiskEntry->Bus,
2787 DiskEntry->Id,
2788 &DiskEntry->DriverName,
2789 DiskEntry->NoMbr ? "GPT" : "MBR");
2790
2791 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2792
2793 PartEntry->AutoCreate = FALSE;
2794 }
2795 else if (PartEntry->New)
2796 {
2797 switch (FormatState)
2798 {
2799 case FormatSystemPartition:
2800 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2801 break;
2802
2803 case FormatInstallPartition:
2804 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2805 break;
2806
2807 case FormatOtherPartition:
2808 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2809 break;
2810
2811 default:
2812 break;
2813 }
2814
2815 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2816 }
2817 else
2818 {
2819 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2820
2821 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2822 {
2823 CONSOLE_PrintTextXY(8, 10,
2824 MUIGetString(STRING_HDDINFOUNK4),
2825 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2826 (PartEntry->DriveLetter == 0) ? '-' : ':',
2827 PartEntry->PartitionType,
2828 PartSize,
2829 PartUnit);
2830 }
2831 else
2832 {
2833 CONSOLE_PrintTextXY(8, 10,
2834 "%c%c %s %I64u %s",
2835 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2836 (PartEntry->DriveLetter == 0) ? '-' : ':',
2837 PartTypeString,
2838 PartSize,
2839 PartUnit);
2840 }
2841
2842 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
2843 DiskEntry->DiskNumber,
2844 DiskSize,
2845 DiskUnit,
2846 DiskEntry->Port,
2847 DiskEntry->Bus,
2848 DiskEntry->Id,
2849 &DiskEntry->DriverName,
2850 DiskEntry->NoMbr ? "GPT" : "MBR");
2851 }
2852
2853 if (FileSystemList == NULL)
2854 {
2855 /* Create the file system list, and by default select the "FAT" file system */
2856 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2857 if (FileSystemList == NULL)
2858 {
2859 /* FIXME: show an error dialog */
2860 return QUIT_PAGE;
2861 }
2862 }
2863
2864 if (RepairUpdateFlag)
2865 {
2866 return CHECK_FILE_SYSTEM_PAGE;
2867 //return SELECT_PARTITION_PAGE;
2868 }
2869
2870 if (IsUnattendedSetup)
2871 {
2872 if (USetupData.FormatPartition)
2873 {
2874 /*
2875 * We use whatever currently selected file system we have
2876 * (by default, this is "FAT", as per the initialization
2877 * performed above). Note that it may be interesting to specify
2878 * which file system to use in unattended installations, in the
2879 * txtsetup.sif file.
2880 */
2881 return FORMAT_PARTITION_PAGE;
2882 }
2883
2884 return CHECK_FILE_SYSTEM_PAGE;
2885 }
2886
2887 DrawFileSystemList(FileSystemList);
2888
2889 while (TRUE)
2890 {
2891 CONSOLE_ConInKey(Ir);
2892
2893 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2894 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2895 {
2896 if (ConfirmQuit(Ir))
2897 return QUIT_PAGE;
2898
2899 break;
2900 }
2901 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2902 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2903 {
2904 FormatState = Start;
2905 return SELECT_PARTITION_PAGE;
2906 }
2907 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2908 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2909 {
2910 ScrollDownFileSystemList(FileSystemList);
2911 }
2912 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2913 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2914 {
2915 ScrollUpFileSystemList(FileSystemList);
2916 }
2917 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2918 {
2919 if (!FileSystemList->Selected->FileSystem)
2920 return SELECT_FILE_SYSTEM_PAGE;
2921 else
2922 return FORMAT_PARTITION_PAGE;
2923 }
2924 }
2925
2926 FormatState = PreviousFormatState;
2927
2928 return SELECT_FILE_SYSTEM_PAGE;
2929 }
2930
2931
2932 /*
2933 * Displays the FormatPartitionPage.
2934 *
2935 * Next pages:
2936 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2937 * SelectPartitionPage (At once)
2938 * QuitPage
2939 *
2940 * SIDEEFFECTS
2941 * Sets PartitionList->CurrentPartition->FormatState
2942 * Sets USetupData.DestinationRootPath
2943 *
2944 * RETURNS
2945 * Number of the next page.
2946 */
2947 static PAGE_NUMBER
2948 FormatPartitionPage(PINPUT_RECORD Ir)
2949 {
2950 NTSTATUS Status;
2951 PDISKENTRY DiskEntry;
2952 PPARTENTRY PartEntry;
2953 PFILE_SYSTEM_ITEM SelectedFileSystem;
2954 UNICODE_STRING PartitionRootPath;
2955 WCHAR PathBuffer[MAX_PATH];
2956 CHAR Buffer[MAX_PATH];
2957
2958 #ifndef NDEBUG
2959 ULONG Line;
2960 ULONG i;
2961 PPARTITION_INFORMATION PartitionInfo;
2962 #endif
2963
2964 DPRINT("FormatPartitionPage()\n");
2965
2966 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2967
2968 if (PartitionList == NULL || TempPartition == NULL)
2969 {
2970 /* FIXME: show an error dialog */
2971 return QUIT_PAGE;
2972 }
2973
2974 PartEntry = TempPartition;
2975 DiskEntry = PartEntry->DiskEntry;
2976
2977 SelectedFileSystem = FileSystemList->Selected;
2978
2979 while (TRUE)
2980 {
2981 if (!IsUnattendedSetup)
2982 {
2983 CONSOLE_ConInKey(Ir);
2984 }
2985
2986 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2987 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2988 {
2989 if (ConfirmQuit(Ir))
2990 return QUIT_PAGE;
2991
2992 break;
2993 }
2994 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2995 {
2996 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2997
2998 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
2999 {
3000 /* FIXME: show an error dialog */
3001 return QUIT_PAGE;
3002 }
3003
3004 #ifndef NDEBUG
3005 CONSOLE_PrintTextXY(6, 12,
3006 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3007 DiskEntry->Cylinders,
3008 DiskEntry->TracksPerCylinder,
3009 DiskEntry->SectorsPerTrack,
3010 DiskEntry->BytesPerSector,
3011 DiskEntry->Dirty ? '*' : ' ');
3012
3013 Line = 13;
3014
3015 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3016 {
3017 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3018
3019 CONSOLE_PrintTextXY(6, Line,
3020 "%2u: %2lu %c %12I64u %12I64u %02x",
3021 i,
3022 PartitionInfo->PartitionNumber,
3023 PartitionInfo->BootIndicator ? 'A' : '-',
3024 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3025 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3026 PartitionInfo->PartitionType);
3027 Line++;
3028 }
3029 #endif
3030
3031 /* Commit the partition changes to the disk */
3032 if (!WritePartitionsToDisk(PartitionList))
3033 {
3034 DPRINT("WritePartitionsToDisk() failed\n");
3035 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3036 return QUIT_PAGE;
3037 }
3038
3039 /* Set PartitionRootPath */
3040 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3041 L"\\Device\\Harddisk%lu\\Partition%lu",
3042 DiskEntry->DiskNumber,
3043 PartEntry->PartitionNumber);
3044 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3045 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3046
3047 /* Format the partition */
3048 if (SelectedFileSystem->FileSystem)
3049 {
3050 Status = FormatPartition(&PartitionRootPath,
3051 SelectedFileSystem);
3052 if (Status == STATUS_NOT_SUPPORTED)
3053 {
3054 sprintf(Buffer,
3055 "Setup is currently unable to format a partition in %S.\n"
3056 "\n"
3057 " \x07 Press ENTER to continue Setup.\n"
3058 " \x07 Press F3 to quit Setup.",
3059 SelectedFileSystem->FileSystem->FileSystemName);
3060
3061 PopupError(Buffer,
3062 MUIGetString(STRING_QUITCONTINUE),
3063 NULL, POPUP_WAIT_NONE);
3064
3065 while (TRUE)
3066 {
3067 CONSOLE_ConInKey(Ir);
3068
3069 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3070 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3071 {
3072 if (ConfirmQuit(Ir))
3073 return QUIT_PAGE;
3074 else
3075 return SELECT_FILE_SYSTEM_PAGE;
3076 }
3077 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3078 {
3079 return SELECT_FILE_SYSTEM_PAGE;
3080 }
3081 }
3082 }
3083 else if (!NT_SUCCESS(Status))
3084 {
3085 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3086 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3087 return QUIT_PAGE;
3088 }
3089
3090 PartEntry->FormatState = Formatted;
3091 // PartEntry->FileSystem = FileSystem;
3092 PartEntry->New = FALSE;
3093 }
3094
3095 #ifndef NDEBUG
3096 CONSOLE_SetStatusText(" Done. Press any key ...");
3097 CONSOLE_ConInKey(Ir);
3098 #endif
3099
3100 return SELECT_FILE_SYSTEM_PAGE;
3101 }
3102 }
3103
3104 return FORMAT_PARTITION_PAGE;
3105 }
3106
3107
3108 /*
3109 * Displays the CheckFileSystemPage.
3110 *
3111 * Next pages:
3112 * InstallDirectoryPage (At once)
3113 * QuitPage
3114 *
3115 * SIDEEFFECTS
3116 * Inits or reloads FileSystemList
3117 *
3118 * RETURNS
3119 * Number of the next page.
3120 */
3121 static PAGE_NUMBER
3122 CheckFileSystemPage(PINPUT_RECORD Ir)
3123 {
3124 NTSTATUS Status;
3125 PDISKENTRY DiskEntry;
3126 PPARTENTRY PartEntry;
3127 PFILE_SYSTEM CurrentFileSystem;
3128 UNICODE_STRING PartitionRootPath;
3129 WCHAR PathBuffer[MAX_PATH];
3130 CHAR Buffer[MAX_PATH];
3131
3132 if (PartitionList == NULL)
3133 {
3134 /* FIXME: show an error dialog */
3135 return QUIT_PAGE;
3136 }
3137
3138 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3139 {
3140 return INSTALL_DIRECTORY_PAGE;
3141 }
3142
3143 /* Set PartitionRootPath */
3144 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3145 L"\\Device\\Harddisk%lu\\Partition%lu",
3146 DiskEntry->DiskNumber,
3147 PartEntry->PartitionNumber);
3148 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3149 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3150
3151 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3152
3153 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3154
3155 CurrentFileSystem = PartEntry->FileSystem;
3156 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3157 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3158
3159 /* HACK: Do not try to check a partition with an unknown filesystem */
3160 if (CurrentFileSystem == NULL)
3161 {
3162 PartEntry->NeedsCheck = FALSE;
3163 return CHECK_FILE_SYSTEM_PAGE;
3164 }
3165
3166 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3167 if (Status == STATUS_NOT_SUPPORTED)
3168 {
3169 sprintf(Buffer,
3170 "Setup is currently unable to check a partition formatted in %S.\n"
3171 "\n"
3172 " \x07 Press ENTER to continue Setup.\n"
3173 " \x07 Press F3 to quit Setup.",
3174 CurrentFileSystem->FileSystemName);
3175
3176 PopupError(Buffer,
3177 MUIGetString(STRING_QUITCONTINUE),
3178 NULL, POPUP_WAIT_NONE);
3179
3180 while (TRUE)
3181 {
3182 CONSOLE_ConInKey(Ir);
3183
3184 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3185 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3186 {
3187 if (ConfirmQuit(Ir))
3188 return QUIT_PAGE;
3189 else
3190 return CHECK_FILE_SYSTEM_PAGE;
3191 }
3192 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3193 {
3194 PartEntry->NeedsCheck = FALSE;
3195 return CHECK_FILE_SYSTEM_PAGE;
3196 }
3197 }
3198 }
3199 else if (!NT_SUCCESS(Status))
3200 {
3201 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3202 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3203 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3204 "(Status 0x%08lx).\n", Status);
3205 PopupError(Buffer,
3206 // MUIGetString(STRING_REBOOTCOMPUTER),
3207 MUIGetString(STRING_CONTINUE),
3208 Ir, POPUP_WAIT_ENTER);
3209
3210 // return QUIT_PAGE;
3211 }
3212
3213 PartEntry->NeedsCheck = FALSE;
3214 return CHECK_FILE_SYSTEM_PAGE;
3215 }
3216
3217
3218 static VOID
3219 BuildInstallPaths(PWSTR InstallDir,
3220 PDISKENTRY DiskEntry,
3221 PPARTENTRY PartEntry)
3222 {
3223 WCHAR PathBuffer[MAX_PATH];
3224
3225 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
3226 /* Create 'InstallPath' string */
3227 RtlFreeUnicodeString(&InstallPath);
3228 RtlCreateUnicodeString(&InstallPath, InstallDir);
3229
3230 /* Create 'USetupData.DestinationRootPath' string */
3231 RtlFreeUnicodeString(&USetupData.DestinationRootPath);
3232 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3233 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3234 DiskEntry->DiskNumber,
3235 PartEntry->PartitionNumber);
3236 RtlCreateUnicodeString(&USetupData.DestinationRootPath, PathBuffer);
3237 DPRINT("DestinationRootPath: %wZ\n", &USetupData.DestinationRootPath);
3238
3239 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
3240 /* Create 'USetupData.DestinationPath' string */
3241 RtlFreeUnicodeString(&USetupData.DestinationPath);
3242 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3243 USetupData.DestinationRootPath.Buffer, InstallDir);
3244 RtlCreateUnicodeString(&USetupData.DestinationPath, PathBuffer);
3245
3246 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
3247 /* Create 'USetupData.DestinationArcPath' */
3248 RtlFreeUnicodeString(&USetupData.DestinationArcPath);
3249 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3250 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3251 DiskEntry->BiosDiskNumber,
3252 PartEntry->PartitionNumber);
3253 ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
3254 RtlCreateUnicodeString(&USetupData.DestinationArcPath, PathBuffer);
3255
3256 /* Initialize DestinationDriveLetter */
3257 DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
3258 }
3259
3260
3261 /*
3262 * Displays the InstallDirectoryPage.
3263 *
3264 * Next pages:
3265 * PrepareCopyPage
3266 * QuitPage
3267 *
3268 * RETURNS
3269 * Number of the next page.
3270 */
3271 static PAGE_NUMBER
3272 InstallDirectoryPage(PINPUT_RECORD Ir)
3273 {
3274 PDISKENTRY DiskEntry;
3275 PPARTENTRY PartEntry;
3276 WCHAR InstallDir[MAX_PATH];
3277 WCHAR c;
3278 ULONG Length, Pos;
3279
3280 /* We do not need the filesystem list anymore */
3281 if (FileSystemList != NULL)
3282 {
3283 DestroyFileSystemList(FileSystemList);
3284 FileSystemList = NULL;
3285 }
3286
3287 if (PartitionList == NULL ||
3288 PartitionList->CurrentDisk == NULL ||
3289 PartitionList->CurrentPartition == NULL)
3290 {
3291 /* FIXME: show an error dialog */
3292 return QUIT_PAGE;
3293 }
3294
3295 DiskEntry = PartitionList->CurrentDisk;
3296 PartEntry = PartitionList->CurrentPartition;
3297
3298 // if (IsUnattendedSetup)
3299 if (RepairUpdateFlag)
3300 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3301 else if (USetupData.InstallationDirectory[0])
3302 wcscpy(InstallDir, USetupData.InstallationDirectory);
3303 else
3304 wcscpy(InstallDir, L"\\ReactOS");
3305
3306 /*
3307 * Check the validity of the predefined 'InstallDir'. If we are either
3308 * in unattended setup or in update/repair mode, and the installation path
3309 * is valid, just perform the installation. Otherwise (either in the case
3310 * of an invalid path, or we are in regular setup), display the UI and allow
3311 * the user to specify a new installation path.
3312 */
3313 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3314 {
3315 BuildInstallPaths(InstallDir,
3316 DiskEntry,
3317 PartEntry);
3318
3319 /*
3320 * Check whether the user attempts to install ReactOS within the
3321 * installation source directory, or in a subdirectory thereof.
3322 * If so, fail with an error.
3323 */
3324 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3325 {
3326 PopupError("You cannot install ReactOS within the installation source directory!",
3327 MUIGetString(STRING_CONTINUE),
3328 Ir, POPUP_WAIT_ENTER);
3329 return INSTALL_DIRECTORY_PAGE;
3330 }
3331
3332 return PREPARE_COPY_PAGE;
3333 }
3334
3335 Length = wcslen(InstallDir);
3336 Pos = Length;
3337
3338 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3339 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3340 CONSOLE_SetCursorXY(8 + Pos, 11);
3341 CONSOLE_SetCursorType(TRUE, TRUE);
3342
3343 while (TRUE)
3344 {
3345 CONSOLE_ConInKey(Ir);
3346
3347 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3348 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3349 {
3350 CONSOLE_SetCursorType(TRUE, FALSE);
3351
3352 if (ConfirmQuit(Ir))
3353 return QUIT_PAGE;
3354
3355 CONSOLE_SetCursorType(TRUE, TRUE);
3356 break;
3357 }
3358 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3359 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3360 {
3361 if (Pos < Length)
3362 {
3363 memmove(&InstallDir[Pos],
3364 &InstallDir[Pos + 1],
3365 (Length - Pos - 1) * sizeof(WCHAR));
3366 InstallDir[Length - 1] = UNICODE_NULL;
3367
3368 Length--;
3369 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3370 CONSOLE_SetCursorXY(8 + Pos, 11);
3371 }
3372 }
3373 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3374 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3375 {
3376 Pos = 0;
3377 CONSOLE_SetCursorXY(8 + Pos, 11);
3378 }
3379 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3380 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3381 {
3382 Pos = Length;
3383 CONSOLE_SetCursorXY(8 + Pos, 11);
3384 }
3385 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3386 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3387 {
3388 if (Pos > 0)
3389 {
3390 Pos--;
3391 CONSOLE_SetCursorXY(8 + Pos, 11);
3392 }
3393 }
3394 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3395 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3396 {
3397 if (Pos < Length)
3398 {
3399 Pos++;
3400 CONSOLE_SetCursorXY(8 + Pos, 11);
3401 }
3402 }
3403 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3404 {
3405 CONSOLE_SetCursorType(TRUE, FALSE);
3406
3407 /*
3408 * Check for the validity of the installation directory and pop up
3409 * an error if it is not the case. Then the user can fix its input.
3410 */
3411 if (!IsValidPath(InstallDir))
3412 {
3413 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3414 return INSTALL_DIRECTORY_PAGE;
3415 }
3416
3417 BuildInstallPaths(InstallDir,
3418 DiskEntry,
3419 PartEntry);
3420
3421 /*
3422 * Check whether the user attempts to install ReactOS within the
3423 * installation source directory, or in a subdirectory thereof.
3424 * If so, fail with an error.
3425 */
3426 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3427 {
3428 PopupError("You cannot install ReactOS within the installation source directory!",
3429 MUIGetString(STRING_CONTINUE),
3430 Ir, POPUP_WAIT_ENTER);
3431 return INSTALL_DIRECTORY_PAGE;
3432 }
3433
3434 return PREPARE_COPY_PAGE;
3435 }
3436 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3437 {
3438 if (Pos > 0)
3439 {
3440 if (Pos < Length)
3441 memmove(&InstallDir[Pos - 1],
3442 &InstallDir[Pos],
3443 (Length - Pos) * sizeof(WCHAR));
3444 InstallDir[Length - 1] = UNICODE_NULL;
3445
3446 Pos--;
3447 Length--;
3448 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3449 CONSOLE_SetCursorXY(8 + Pos, 11);
3450 }
3451 }
3452 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3453 {
3454 if (Length < 50)
3455 {
3456 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3457 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3458 {
3459 if (Pos < Length)
3460 memmove(&InstallDir[Pos + 1],
3461 &InstallDir[Pos],
3462 (Length - Pos) * sizeof(WCHAR));
3463 InstallDir[Length + 1] = UNICODE_NULL;
3464 InstallDir[Pos] = c;
3465
3466 Pos++;
3467 Length++;
3468 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3469 CONSOLE_SetCursorXY(8 + Pos, 11);
3470 }
3471 }
3472 }
3473 }
3474
3475 return INSTALL_DIRECTORY_PAGE;
3476 }
3477
3478
3479 static BOOLEAN
3480 AddSectionToCopyQueueCab(HINF InfFile,
3481 PWCHAR SectionName,
3482 PWCHAR SourceCabinet,
3483 PCUNICODE_STRING DestinationPath,
3484 PINPUT_RECORD Ir)
3485 {
3486 INFCONTEXT FilesContext;
3487 INFCONTEXT DirContext;
3488 PWCHAR FileKeyName;
3489 PWCHAR FileKeyValue;
3490 PWCHAR DirKeyValue;
3491 PWCHAR TargetFileName;
3492
3493 /*
3494 * This code enumerates the list of files in reactos.dff / reactos.inf
3495 * that need to be extracted from reactos.cab and be installed in their
3496 * respective directories.
3497 */
3498
3499 /* Search for the SectionName section */
3500 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3501 {
3502 CHAR Buffer[128];
3503 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3504 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3505 return FALSE;
3506 }
3507
3508 /*
3509 * Enumerate the files in the section and add them to the file queue.
3510 */
3511 do
3512 {
3513 /* Get source file name and target directory id */
3514 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3515 {
3516 /* FIXME: Handle error! */
3517 DPRINT1("INF_GetData() failed\n");
3518 break;
3519 }
3520
3521 /* Get optional target file name */
3522 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
3523 TargetFileName = NULL;
3524
3525 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3526
3527 /* Lookup target directory */
3528 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3529 {
3530 /* FIXME: Handle error! */
3531 DPRINT1("SetupFindFirstLine() failed\n");
3532 INF_FreeData(FileKeyName);
3533 INF_FreeData(FileKeyValue);
3534 INF_FreeData(TargetFileName);
3535 break;
3536 }
3537
3538 INF_FreeData(FileKeyValue);
3539
3540 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3541 {
3542 /* FIXME: Handle error! */
3543 DPRINT1("INF_GetData() failed\n");
3544 INF_FreeData(FileKeyName);
3545 INF_FreeData(TargetFileName);
3546 break;
3547 }
3548
3549 if (!SetupQueueCopy(SetupFileQueue,
3550 SourceCabinet,
3551 USetupData.SourceRootPath.Buffer,
3552 USetupData.SourceRootDir.Buffer,
3553 FileKeyName,
3554 DirKeyValue,
3555 TargetFileName))
3556 {
3557 /* FIXME: Handle error! */
3558 DPRINT1("SetupQueueCopy() failed\n");
3559 }
3560
3561 INF_FreeData(FileKeyName);
3562 INF_FreeData(TargetFileName);
3563 INF_FreeData(DirKeyValue);
3564 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3565
3566 return TRUE;
3567 }
3568
3569
3570 static BOOLEAN
3571 AddSectionToCopyQueue(HINF InfFile,
3572 PWCHAR SectionName,
3573 PWCHAR SourceCabinet,
3574 PCUNICODE_STRING DestinationPath,
3575 PINPUT_RECORD Ir)
3576 {
3577 INFCONTEXT FilesContext;
3578 INFCONTEXT DirContext;
3579 PWCHAR FileKeyName;
3580 PWCHAR FileKeyValue;
3581 PWCHAR DirKeyValue;
3582 PWCHAR TargetFileName;
3583 WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
3584
3585 if (SourceCabinet)
3586 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
3587
3588 /*
3589 * This code enumerates the list of files in txtsetup.sif
3590 * that need to be installed in their respective directories.
3591 */
3592
3593 /* Search for the SectionName section */
3594 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3595 {
3596 CHAR Buffer[128];
3597 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3598 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3599 return FALSE;
3600 }
3601
3602 /*
3603 * Enumerate the files in the section and add them to the file queue.
3604 */
3605 do
3606 {
3607 /* Get source file name */
3608 if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
3609 {
3610 /* FIXME: Handle error! */
3611 DPRINT1("INF_GetData() failed\n");
3612 break;
3613 }
3614
3615 /* Get target directory id */
3616 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
3617 {
3618 /* FIXME: Handle error! */
3619 DPRINT1("INF_GetData() failed\n");
3620 INF_FreeData(FileKeyName);
3621 break;
3622 }
3623
3624 /* Get optional target file name */
3625 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
3626 TargetFileName = NULL;
3627 else if (!*TargetFileName)
3628 TargetFileName = NULL;
3629
3630 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3631
3632 /* Lookup target directory */
3633 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3634 {
3635 /* FIXME: Handle error! */
3636 DPRINT1("SetupFindFirstLine() failed\n");
3637 INF_FreeData(FileKeyName);
3638 INF_FreeData(FileKeyValue);
3639 INF_FreeData(TargetFileName);
3640 break;
3641 }
3642
3643 INF_FreeData(FileKeyValue);
3644
3645 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3646 {
3647 /* FIXME: Handle error! */
3648 DPRINT1("INF_GetData() failed\n");
3649 INF_FreeData(FileKeyName);
3650 INF_FreeData(TargetFileName);
3651 break;
3652 }
3653
3654 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3655 {
3656 /* Installation path */
3657 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3658
3659 RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3660 USetupData.SourceRootDir.Buffer);
3661
3662 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
3663 }
3664 else if (DirKeyValue[0] == L'\\')
3665 {
3666 /* Absolute path */
3667 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3668
3669 RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3670 DirKeyValue);
3671
3672 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
3673 }
3674 else // if (DirKeyValue[0] != L'\\')
3675 {
3676 /* Path relative to the installation path */
3677 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3678
3679 CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
3680 USetupData.SourceRootDir.Buffer, DirKeyValue);
3681
3682 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
3683 }
3684
3685 if (!SetupQueueCopy(SetupFileQueue,
3686 SourceCabinet,
3687 USetupData.SourceRootPath.Buffer,
3688 CompleteOrigDirName,
3689 FileKeyName,
3690 DirKeyValue,
3691 TargetFileName))
3692 {
3693 /* FIXME: Handle error! */
3694 DPRINT1("SetupQueueCopy() failed\n");
3695 }
3696
3697 INF_FreeData(FileKeyName);
3698 INF_FreeData(TargetFileName);
3699 INF_FreeData(DirKeyValue);
3700 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3701
3702 return TRUE;
3703 }
3704
3705
3706 static BOOLEAN
3707 PrepareCopyPageInfFile(HINF InfFile,
3708 PWCHAR SourceCabinet,
3709 PINPUT_RECORD Ir)
3710 {
3711 NTSTATUS Status;
3712 INFCONTEXT DirContext;
3713 PWCHAR AdditionalSectionName = NULL;
3714 PWCHAR DirKeyValue;
3715 WCHAR PathBuffer[MAX_PATH];
3716
3717 /* Add common files */
3718 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &USetupData.DestinationPath, Ir))
3719 return FALSE;
3720
3721 /* Add specific files depending of computer type */
3722 if (SourceCabinet == NULL)
3723 {
3724 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
3725 return FALSE;
3726
3727 if (AdditionalSectionName)
3728 {
3729 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
3730 return FALSE;
3731 }
3732 }
3733
3734 /* Create directories */
3735
3736 /*
3737 * FIXME:
3738 * Copying files to USetupData.DestinationRootPath should be done from within
3739 * the SystemPartitionFiles section.
3740 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3741 * For installing to USetupData.DestinationPath specify just '\' .
3742 */
3743
3744 /* Get destination path */
3745 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
3746
3747 DPRINT("FullPath(1): '%S'\n", PathBuffer);
3748
3749 /* Create the install directory */
3750 Status = SetupCreateDirectory(PathBuffer);
3751 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3752 {
3753 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
3754 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
3755 return FALSE;
3756 }
3757
3758 /* Search for the 'Directories' section */
3759 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3760 {
3761 if (SourceCabinet)
3762 {
3763 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
3764 }
3765 else
3766 {
3767 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
3768 }
3769
3770 return FALSE;
3771 }
3772
3773 /* Enumerate the directory values and create the subdirectories */
3774 do
3775 {
3776 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3777 {
3778 DPRINT1("break\n");
3779 break;
3780 }
3781
3782 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3783 {
3784 /* Installation path */
3785 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3786
3787 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
3788 USetupData.DestinationPath.Buffer);
3789
3790 DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
3791 }
3792 else if (DirKeyValue[0] == L'\\')
3793 {
3794 /* Absolute path */
3795 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3796
3797 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3798 USetupData.DestinationRootPath.Buffer, DirKeyValue);
3799
3800 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
3801
3802 Status = SetupCreateDirectory(PathBuffer);
3803 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3804 {
3805 INF_FreeData(DirKeyValue);
3806 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3807 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3808 return FALSE;
3809 }
3810 }
3811 else // if (DirKeyValue[0] != L'\\')
3812 {
3813 /* Path relative to the installation path */
3814 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3815
3816 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3817 USetupData.DestinationPath.Buffer, DirKeyValue);
3818
3819 DPRINT("RelativePath(2): '%S'\n", PathBuffer);
3820
3821 Status = SetupCreateDirectory(PathBuffer);
3822 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3823 {
3824 INF_FreeData(DirKeyValue);
3825 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3826 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3827 return FALSE;
3828 }
3829 }
3830
3831 INF_FreeData(DirKeyValue);
3832 } while (SetupFindNextLine(&DirContext, &DirContext));
3833
3834 return TRUE;
3835 }
3836
3837
3838 /*
3839 * Displays the PrepareCopyPage.
3840 *
3841 * Next pages:
3842 * FileCopyPage(At once)
3843 * QuitPage
3844 *
3845 * SIDEEFFECTS
3846 * Inits SetupFileQueue
3847 * Calls PrepareCopyPageInfFile
3848 *
3849 * RETURNS
3850 * Number of the next page.
3851 */
3852 static PAGE_NUMBER
3853 PrepareCopyPage(PINPUT_RECORD Ir)
3854 {
3855 HINF InfHandle;
3856 WCHAR PathBuffer[MAX_PATH];
3857 INFCONTEXT CabinetsContext;
3858 ULONG InfFileSize;
3859 PWCHAR KeyValue;
3860 UINT ErrorLine;
3861 PVOID InfFileData;
3862
3863 MUIDisplayPage(PREPARE_COPY_PAGE);
3864
3865 /* Create the file queue */
3866 SetupFileQueue = SetupOpenFileQueue();
3867 if (SetupFileQueue == NULL)
3868 {
3869 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
3870 return QUIT_PAGE;
3871 }
3872
3873 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
3874 {
3875 /* FIXME: show an error dialog */
3876 return QUIT_PAGE;
3877 }
3878
3879 /* Search for the 'Cabinets' section */
3880 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
3881 {
3882 return FILE_COPY_PAGE;
3883 }
3884
3885 /*
3886 * Enumerate the directory values in the 'Cabinets'
3887 * section and parse their inf files.
3888 */
3889 do
3890 {
3891 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3892 break;
3893
3894 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3895 USetupData.SourcePath.Buffer, KeyValue);
3896
3897 CabinetInitialize();
3898 CabinetSetEventHandlers(NULL, NULL, NULL);
3899 CabinetSetCabinetName(PathBuffer);
3900
3901 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3902 {
3903 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3904
3905 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3906 if (InfFileData == NULL)
3907 {
3908 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3909 return QUIT_PAGE;
3910 }
3911 }
3912 else
3913 {
3914 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3915 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3916 return QUIT_PAGE;
3917 }
3918
3919 InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
3920 InfFileSize,
3921 NULL,
3922 INF_STYLE_WIN4,
3923 USetupData.LanguageId,
3924 &ErrorLine);
3925
3926 if (InfHandle == INVALID_HANDLE_VALUE)
3927 {
3928 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3929 return QUIT_PAGE;
3930 }
3931
3932 CabinetCleanup();
3933
3934 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3935 {
3936 /* FIXME: show an error dialog */
3937 return QUIT_PAGE;
3938 }
3939 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3940
3941 return FILE_COPY_PAGE;
3942 }
3943
3944
3945 VOID
3946 NTAPI
3947 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3948 IN BOOLEAN First)
3949 {
3950 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3951
3952 /* Get the memory information from the system */
3953 NtQuerySystemInformation(SystemPerformanceInformation,
3954 &PerfInfo,