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