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