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