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