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