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