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