[USETUP]: Isolate the recognition of the filesystem of a partition into its own function.
[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 {
1971 return QUIT_PAGE;
1972 }
1973 }
1974 else if (Cancel == TRUE)
1975 {
1976 return SELECT_PARTITION_PAGE;
1977 }
1978 else
1979 {
1980 PartSize = atoi(InputBuffer);
1981
1982 if (PartSize < 1)
1983 {
1984 /* Too small */
1985 continue;
1986 }
1987
1988 if (PartSize > MaxSize)
1989 {
1990 /* Too large */
1991 continue;
1992 }
1993
1994 /* Convert to bytes */
1995 if (PartSize == MaxSize)
1996 {
1997 /* Use all of the unpartitioned disk space */
1998 SectorCount = PartEntry->SectorCount.QuadPart;
1999 }
2000 else
2001 {
2002 /* Calculate the sector count from the size in MB */
2003 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2004
2005 /* But never get larger than the unpartitioned disk space */
2006 if (SectorCount > PartEntry->SectorCount.QuadPart)
2007 SectorCount = PartEntry->SectorCount.QuadPart;
2008 }
2009
2010 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2011
2012 CreatePrimaryPartition(PartitionList,
2013 SectorCount,
2014 FALSE);
2015
2016 return SELECT_PARTITION_PAGE;
2017 }
2018 }
2019
2020 return CREATE_PRIMARY_PARTITION_PAGE;
2021 }
2022
2023
2024 /*
2025 * Displays the CreateExtendedPartitionPage.
2026 *
2027 * Next pages:
2028 * SelectPartitionPage (default)
2029 * QuitPage
2030 *
2031 * RETURNS
2032 * Number of the next page.
2033 */
2034 static PAGE_NUMBER
2035 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2036 {
2037 PDISKENTRY DiskEntry;
2038 PPARTENTRY PartEntry;
2039 BOOLEAN Quit;
2040 BOOLEAN Cancel;
2041 CHAR InputBuffer[50];
2042 ULONG MaxSize;
2043 ULONGLONG PartSize;
2044 ULONGLONG DiskSize;
2045 ULONGLONG SectorCount;
2046 PCHAR Unit;
2047
2048 if (PartitionList == NULL ||
2049 PartitionList->CurrentDisk == NULL ||
2050 PartitionList->CurrentPartition == NULL)
2051 {
2052 /* FIXME: show an error dialog */
2053 return QUIT_PAGE;
2054 }
2055
2056 DiskEntry = PartitionList->CurrentDisk;
2057 PartEntry = PartitionList->CurrentPartition;
2058
2059 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2060
2061 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2062
2063 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2064 #if 0
2065 if (DiskSize >= 10737418240) /* 10 GB */
2066 {
2067 DiskSize = DiskSize / 1073741824;
2068 Unit = MUIGetString(STRING_GB);
2069 }
2070 else
2071 #endif
2072 {
2073 DiskSize = DiskSize / 1048576;
2074 if (DiskSize == 0)
2075 DiskSize = 1;
2076
2077 Unit = MUIGetString(STRING_MB);
2078 }
2079
2080 if (DiskEntry->DriverName.Length > 0)
2081 {
2082 CONSOLE_PrintTextXY(6, 10,
2083 MUIGetString(STRING_HDINFOPARTCREATE),
2084 DiskSize,
2085 Unit,
2086 DiskEntry->DiskNumber,
2087 DiskEntry->Port,
2088 DiskEntry->Bus,
2089 DiskEntry->Id,
2090 &DiskEntry->DriverName);
2091 }
2092 else
2093 {
2094 CONSOLE_PrintTextXY(6, 10,
2095 MUIGetString(STRING_HDDINFOUNK1),
2096 DiskSize,
2097 Unit,
2098 DiskEntry->DiskNumber,
2099 DiskEntry->Port,
2100 DiskEntry->Bus,
2101 DiskEntry->Id);
2102 }
2103
2104 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2105
2106 #if 0
2107 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2108 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2109 #endif
2110
2111 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2112
2113 PartEntry = PartitionList->CurrentPartition;
2114 while (TRUE)
2115 {
2116 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2117
2118 if (MaxSize > PARTITION_MAXSIZE)
2119 MaxSize = PARTITION_MAXSIZE;
2120
2121 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2122 MaxSize, InputBuffer, &Quit, &Cancel);
2123
2124 if (Quit == TRUE)
2125 {
2126 if (ConfirmQuit (Ir) == TRUE)
2127 {
2128 return QUIT_PAGE;
2129 }
2130 }
2131 else if (Cancel == TRUE)
2132 {
2133 return SELECT_PARTITION_PAGE;
2134 }
2135 else
2136 {
2137 PartSize = atoi(InputBuffer);
2138
2139 if (PartSize < 1)
2140 {
2141 /* Too small */
2142 continue;
2143 }
2144
2145 if (PartSize > MaxSize)
2146 {
2147 /* Too large */
2148 continue;
2149 }
2150
2151 /* Convert to bytes */
2152 if (PartSize == MaxSize)
2153 {
2154 /* Use all of the unpartitioned disk space */
2155 SectorCount = PartEntry->SectorCount.QuadPart;
2156 }
2157 else
2158 {
2159 /* Calculate the sector count from the size in MB */
2160 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2161
2162 /* But never get larger than the unpartitioned disk space */
2163 if (SectorCount > PartEntry->SectorCount.QuadPart)
2164 SectorCount = PartEntry->SectorCount.QuadPart;
2165 }
2166
2167 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2168
2169 CreateExtendedPartition(PartitionList,
2170 SectorCount);
2171
2172 return SELECT_PARTITION_PAGE;
2173 }
2174 }
2175
2176 return CREATE_EXTENDED_PARTITION_PAGE;
2177 }
2178
2179
2180 /*
2181 * Displays the CreateLogicalPartitionPage.
2182 *
2183 * Next pages:
2184 * SelectFileSystemPage (default)
2185 * QuitPage
2186 *
2187 * RETURNS
2188 * Number of the next page.
2189 */
2190 static PAGE_NUMBER
2191 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2192 {
2193 PDISKENTRY DiskEntry;
2194 PPARTENTRY PartEntry;
2195 BOOLEAN Quit;
2196 BOOLEAN Cancel;
2197 CHAR InputBuffer[50];
2198 ULONG MaxSize;
2199 ULONGLONG PartSize;
2200 ULONGLONG DiskSize;
2201 ULONGLONG SectorCount;
2202 PCHAR Unit;
2203
2204 if (PartitionList == NULL ||
2205 PartitionList->CurrentDisk == NULL ||
2206 PartitionList->CurrentPartition == NULL)
2207 {
2208 /* FIXME: show an error dialog */
2209 return QUIT_PAGE;
2210 }
2211
2212 DiskEntry = PartitionList->CurrentDisk;
2213 PartEntry = PartitionList->CurrentPartition;
2214
2215 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2216
2217 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2218
2219 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2220 #if 0
2221 if (DiskSize >= 10737418240) /* 10 GB */
2222 {
2223 DiskSize = DiskSize / 1073741824;
2224 Unit = MUIGetString(STRING_GB);
2225 }
2226 else
2227 #endif
2228 {
2229 DiskSize = DiskSize / 1048576;
2230 if (DiskSize == 0)
2231 DiskSize = 1;
2232
2233 Unit = MUIGetString(STRING_MB);
2234 }
2235
2236 if (DiskEntry->DriverName.Length > 0)
2237 {
2238 CONSOLE_PrintTextXY(6, 10,
2239 MUIGetString(STRING_HDINFOPARTCREATE),
2240 DiskSize,
2241 Unit,
2242 DiskEntry->DiskNumber,
2243 DiskEntry->Port,
2244 DiskEntry->Bus,
2245 DiskEntry->Id,
2246 &DiskEntry->DriverName);
2247 }
2248 else
2249 {
2250 CONSOLE_PrintTextXY(6, 10,
2251 MUIGetString(STRING_HDDINFOUNK1),
2252 DiskSize,
2253 Unit,
2254 DiskEntry->DiskNumber,
2255 DiskEntry->Port,
2256 DiskEntry->Bus,
2257 DiskEntry->Id);
2258 }
2259
2260 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2261
2262 #if 0
2263 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2264 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2265 #endif
2266
2267 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2268
2269 PartEntry = PartitionList->CurrentPartition;
2270 while (TRUE)
2271 {
2272 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2273
2274 if (MaxSize > PARTITION_MAXSIZE)
2275 MaxSize = PARTITION_MAXSIZE;
2276
2277 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2278 MaxSize, InputBuffer, &Quit, &Cancel);
2279
2280 if (Quit == TRUE)
2281 {
2282 if (ConfirmQuit (Ir) == TRUE)
2283 {
2284 return QUIT_PAGE;
2285 }
2286 }
2287 else if (Cancel == TRUE)
2288 {
2289 return SELECT_PARTITION_PAGE;
2290 }
2291 else
2292 {
2293 PartSize = atoi(InputBuffer);
2294
2295 if (PartSize < 1)
2296 {
2297 /* Too small */
2298 continue;
2299 }
2300
2301 if (PartSize > MaxSize)
2302 {
2303 /* Too large */
2304 continue;
2305 }
2306
2307 /* Convert to bytes */
2308 if (PartSize == MaxSize)
2309 {
2310 /* Use all of the unpartitioned disk space */
2311 SectorCount = PartEntry->SectorCount.QuadPart;
2312 }
2313 else
2314 {
2315 /* Calculate the sector count from the size in MB */
2316 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2317
2318 /* But never get larger than the unpartitioned disk space */
2319 if (SectorCount > PartEntry->SectorCount.QuadPart)
2320 SectorCount = PartEntry->SectorCount.QuadPart;
2321 }
2322
2323 DPRINT("Partition size: %I64u bytes\n", PartSize);
2324
2325 CreateLogicalPartition(PartitionList,
2326 SectorCount,
2327 FALSE);
2328
2329 return SELECT_PARTITION_PAGE;
2330 }
2331 }
2332
2333 return CREATE_LOGICAL_PARTITION_PAGE;
2334 }
2335
2336
2337 /*
2338 * Displays the ConfirmDeleteSystemPartitionPage.
2339 *
2340 * Next pages:
2341 * DeletePartitionPage (default)
2342 * SelectPartitionPage
2343 *
2344 * RETURNS
2345 * Number of the next page.
2346 */
2347 static PAGE_NUMBER
2348 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2349 {
2350 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2351
2352 while (TRUE)
2353 {
2354 CONSOLE_ConInKey(Ir);
2355
2356 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2357 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2358 {
2359 if (ConfirmQuit(Ir) == TRUE)
2360 {
2361 return QUIT_PAGE;
2362 }
2363
2364 break;
2365 }
2366 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2367 {
2368 return DELETE_PARTITION_PAGE;
2369 }
2370 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2371 {
2372 return SELECT_PARTITION_PAGE;
2373 }
2374 }
2375
2376 return SELECT_PARTITION_PAGE;
2377 }
2378
2379
2380 /*
2381 * Displays the DeletePartitionPage.
2382 *
2383 * Next pages:
2384 * SelectPartitionPage (default)
2385 * QuitPage
2386 *
2387 * RETURNS
2388 * Number of the next page.
2389 */
2390 static PAGE_NUMBER
2391 DeletePartitionPage(PINPUT_RECORD Ir)
2392 {
2393 PDISKENTRY DiskEntry;
2394 PPARTENTRY PartEntry;
2395 ULONGLONG DiskSize;
2396 ULONGLONG PartSize;
2397 PCHAR Unit;
2398 CHAR PartType[32];
2399
2400 if (PartitionList == NULL ||
2401 PartitionList->CurrentDisk == NULL ||
2402 PartitionList->CurrentPartition == NULL)
2403 {
2404 /* FIXME: show an error dialog */
2405 return QUIT_PAGE;
2406 }
2407
2408 DiskEntry = PartitionList->CurrentDisk;
2409 PartEntry = PartitionList->CurrentPartition;
2410
2411 MUIDisplayPage(DELETE_PARTITION_PAGE);
2412
2413 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, PartType, 30);
2414
2415 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2416 #if 0
2417 if (PartSize >= 10737418240) /* 10 GB */
2418 {
2419 PartSize = PartSize / 1073741824;
2420 Unit = MUIGetString(STRING_GB);
2421 }
2422 else
2423 #endif
2424 if (PartSize >= 10485760) /* 10 MB */
2425 {
2426 PartSize = PartSize / 1048576;
2427 Unit = MUIGetString(STRING_MB);
2428 }
2429 else
2430 {
2431 PartSize = PartSize / 1024;
2432 Unit = MUIGetString(STRING_KB);
2433 }
2434
2435 if (PartType == NULL)
2436 {
2437 CONSOLE_PrintTextXY(6, 10,
2438 MUIGetString(STRING_HDDINFOUNK2),
2439 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2440 (PartEntry->DriveLetter == 0) ? '-' : ':',
2441 PartEntry->PartitionType,
2442 PartSize,
2443 Unit);
2444 }
2445 else
2446 {
2447 CONSOLE_PrintTextXY(6, 10,
2448 " %c%c %s %I64u %s",
2449 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2450 (PartEntry->DriveLetter == 0) ? '-' : ':',
2451 PartType,
2452 PartSize,
2453 Unit);
2454 }
2455
2456 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2457 #if 0
2458 if (DiskSize >= 10737418240) /* 10 GB */
2459 {
2460 DiskSize = DiskSize / 1073741824;
2461 Unit = MUIGetString(STRING_GB);
2462 }
2463 else
2464 #endif
2465 {
2466 DiskSize = DiskSize / 1048576;
2467 if (DiskSize == 0)
2468 DiskSize = 1;
2469
2470 Unit = MUIGetString(STRING_MB);
2471 }
2472
2473 if (DiskEntry->DriverName.Length > 0)
2474 {
2475 CONSOLE_PrintTextXY(6, 12,
2476 MUIGetString(STRING_HDINFOPARTDELETE),
2477 DiskSize,
2478 Unit,
2479 DiskEntry->DiskNumber,
2480 DiskEntry->Port,
2481 DiskEntry->Bus,
2482 DiskEntry->Id,
2483 &DiskEntry->DriverName);
2484 }
2485 else
2486 {
2487 CONSOLE_PrintTextXY(6, 12,
2488 MUIGetString(STRING_HDDINFOUNK3),
2489 DiskSize,
2490 Unit,
2491 DiskEntry->DiskNumber,
2492 DiskEntry->Port,
2493 DiskEntry->Bus,
2494 DiskEntry->Id);
2495 }
2496
2497 while (TRUE)
2498 {
2499 CONSOLE_ConInKey(Ir);
2500
2501 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2502 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2503 {
2504 if (ConfirmQuit(Ir) == TRUE)
2505 {
2506 return QUIT_PAGE;
2507 }
2508
2509 break;
2510 }
2511 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2512 {
2513 return SELECT_PARTITION_PAGE;
2514 }
2515 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2516 {
2517 DeleteCurrentPartition(PartitionList);
2518
2519 return SELECT_PARTITION_PAGE;
2520 }
2521 }
2522
2523 return DELETE_PARTITION_PAGE;
2524 }
2525
2526
2527 /*
2528 * Displays the SelectFileSystemPage.
2529 *
2530 * Next pages:
2531 * CheckFileSystemPage (At once if RepairUpdate is selected)
2532 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2533 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2534 * SelectPartitionPage (If the user aborts)
2535 * FormatPartitionPage (Default)
2536 * QuitPage
2537 *
2538 * SIDEEFFECTS
2539 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2540 * Calls CheckActiveSystemPartition()
2541 *
2542 * RETURNS
2543 * Number of the next page.
2544 */
2545 static PAGE_NUMBER
2546 SelectFileSystemPage(PINPUT_RECORD Ir)
2547 {
2548 PDISKENTRY DiskEntry;
2549 PPARTENTRY PartEntry;
2550 ULONGLONG DiskSize;
2551 ULONGLONG PartSize;
2552 PCHAR DiskUnit;
2553 PCHAR PartUnit;
2554 CHAR PartTypeString[32];
2555
2556 DPRINT("SelectFileSystemPage()\n");
2557
2558 if (PartitionList == NULL ||
2559 PartitionList->CurrentDisk == NULL ||
2560 PartitionList->CurrentPartition == NULL)
2561 {
2562 /* FIXME: show an error dialog */
2563 return QUIT_PAGE;
2564 }
2565
2566 /* Find or set the active system partition */
2567 CheckActiveSystemPartition(PartitionList);
2568
2569 if (PartitionList->SystemDisk == NULL ||
2570 PartitionList->SystemPartition == NULL)
2571 {
2572 /* FIXME: show an error dialog */
2573 return QUIT_PAGE;
2574 }
2575
2576 switch (PartitionList->FormatState)
2577 {
2578 case Start:
2579 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2580 {
2581 PartitionList->TempDisk = PartitionList->SystemDisk;
2582 PartitionList->TempPartition = PartitionList->SystemPartition;
2583 PartitionList->TempPartition->NeedsCheck = TRUE;
2584
2585 PartitionList->FormatState = FormatSystemPartition;
2586 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2587 }
2588 else
2589 {
2590 PartitionList->TempDisk = PartitionList->CurrentDisk;
2591 PartitionList->TempPartition = PartitionList->CurrentPartition;
2592 PartitionList->TempPartition->NeedsCheck = TRUE;
2593
2594 PartitionList->FormatState = FormatInstallPartition;
2595 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2596 }
2597 break;
2598
2599 case FormatSystemPartition:
2600 PartitionList->TempDisk = PartitionList->CurrentDisk;
2601 PartitionList->TempPartition = PartitionList->CurrentPartition;
2602 PartitionList->TempPartition->NeedsCheck = TRUE;
2603
2604 PartitionList->FormatState = FormatInstallPartition;
2605 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2606 break;
2607
2608 case FormatInstallPartition:
2609 if (GetNextUnformattedPartition(PartitionList,
2610 &PartitionList->TempDisk,
2611 &PartitionList->TempPartition))
2612 {
2613 PartitionList->FormatState = FormatOtherPartition;
2614 PartitionList->TempPartition->NeedsCheck = TRUE;
2615 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2616 }
2617 else
2618 {
2619 PartitionList->FormatState = FormatDone;
2620 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2621 return CHECK_FILE_SYSTEM_PAGE;
2622 }
2623 break;
2624
2625 case FormatOtherPartition:
2626 if (GetNextUnformattedPartition(PartitionList,
2627 &PartitionList->TempDisk,
2628 &PartitionList->TempPartition))
2629 {
2630 PartitionList->FormatState = FormatOtherPartition;
2631 PartitionList->TempPartition->NeedsCheck = TRUE;
2632 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2633 }
2634 else
2635 {
2636 PartitionList->FormatState = FormatDone;
2637 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2638 return CHECK_FILE_SYSTEM_PAGE;
2639 }
2640 break;
2641
2642 default:
2643 DPRINT1("FormatState: Invalid value %ld\n", PartitionList->FormatState);
2644 /* FIXME: show an error dialog */
2645 return QUIT_PAGE;
2646 }
2647
2648 DiskEntry = PartitionList->TempDisk;
2649 PartEntry = PartitionList->TempPartition;
2650
2651 /* adjust disk size */
2652 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2653 if (DiskSize >= 10737418240) /* 10 GB */
2654 {
2655 DiskSize = DiskSize / 1073741824;
2656 DiskUnit = MUIGetString(STRING_GB);
2657 }
2658 else
2659 {
2660 DiskSize = DiskSize / 1048576;
2661 DiskUnit = MUIGetString(STRING_MB);
2662 }
2663
2664 /* adjust partition size */
2665 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2666 if (PartSize >= 10737418240) /* 10 GB */
2667 {
2668 PartSize = PartSize / 1073741824;
2669 PartUnit = MUIGetString(STRING_GB);
2670 }
2671 else
2672 {
2673 PartSize = PartSize / 1048576;
2674 PartUnit = MUIGetString(STRING_MB);
2675 }
2676
2677 /* adjust partition type */
2678 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, PartTypeString, 30);
2679
2680 if (PartEntry->AutoCreate == TRUE)
2681 {
2682 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2683
2684 #if 0
2685 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2686 PartEntry->PartitionNumber,
2687 PartSize,
2688 PartUnit,
2689 PartType);
2690 #endif
2691
2692 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
2693 DiskEntry->DiskNumber,
2694 DiskSize,
2695 DiskUnit,
2696 DiskEntry->Port,
2697 DiskEntry->Bus,
2698 DiskEntry->Id,
2699 &DiskEntry->DriverName);
2700
2701 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2702
2703
2704 PartEntry->AutoCreate = FALSE;
2705 }
2706 else if (PartEntry->New == TRUE)
2707 {
2708 switch (PartitionList->FormatState)
2709 {
2710 case FormatSystemPartition:
2711 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2712 break;
2713
2714 case FormatInstallPartition:
2715 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2716 break;
2717
2718 case FormatOtherPartition:
2719 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2720 break;
2721
2722 default:
2723 break;
2724 }
2725
2726 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2727 }
2728 else
2729 {
2730 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2731
2732 if (PartTypeString == NULL)
2733 {
2734 CONSOLE_PrintTextXY(8, 10,
2735 MUIGetString(STRING_HDDINFOUNK4),
2736 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2737 (PartEntry->DriveLetter == 0) ? '-' : ':',
2738 PartEntry->PartitionType,
2739 PartSize,
2740 PartUnit);
2741 }
2742 else
2743 {
2744 CONSOLE_PrintTextXY(8, 10,
2745 "%c%c %s %I64u %s",
2746 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2747 (PartEntry->DriveLetter == 0) ? '-' : ':',
2748 PartTypeString,
2749 PartSize,
2750 PartUnit);
2751 }
2752
2753 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
2754 DiskEntry->DiskNumber,
2755 DiskSize,
2756 DiskUnit,
2757 DiskEntry->Port,
2758 DiskEntry->Bus,
2759 DiskEntry->Id,
2760 &DiskEntry->DriverName);
2761 }
2762
2763 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2764
2765 if (FileSystemList == NULL)
2766 {
2767 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2768 if (FileSystemList == NULL)
2769 {
2770 /* FIXME: show an error dialog */
2771 return QUIT_PAGE;
2772 }
2773
2774 /* FIXME: Add file systems to list */
2775 }
2776
2777 DrawFileSystemList(FileSystemList);
2778
2779 if (RepairUpdateFlag)
2780 {
2781 return CHECK_FILE_SYSTEM_PAGE;
2782 //return SELECT_PARTITION_PAGE;
2783 }
2784
2785 if (IsUnattendedSetup)
2786 {
2787 if (UnattendFormatPartition)
2788 {
2789 PartEntry->FileSystem = GetFileSystemByName(FileSystemList, L"FAT");
2790 return FORMAT_PARTITION_PAGE;
2791 }
2792
2793 return CHECK_FILE_SYSTEM_PAGE;
2794 }
2795
2796 while (TRUE)
2797 {
2798 CONSOLE_ConInKey(Ir);
2799
2800 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2801 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2802 {
2803 if (ConfirmQuit(Ir) == TRUE)
2804 {
2805 return QUIT_PAGE;
2806 }
2807
2808 break;
2809 }
2810 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2811 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2812 {
2813 return SELECT_PARTITION_PAGE;
2814 }
2815 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2816 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2817 {
2818 ScrollDownFileSystemList(FileSystemList);
2819 }
2820 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2821 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2822 {
2823 ScrollUpFileSystemList(FileSystemList);
2824 }
2825 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2826 {
2827 if (!FileSystemList->Selected->FormatFunc)
2828 {
2829 return SELECT_FILE_SYSTEM_PAGE;
2830 }
2831 else
2832 {
2833 PartEntry->FileSystem = FileSystemList->Selected;
2834 return FORMAT_PARTITION_PAGE;
2835 }
2836 }
2837 }
2838
2839 return SELECT_FILE_SYSTEM_PAGE;
2840 }
2841
2842
2843 /*
2844 * Displays the FormatPartitionPage.
2845 *
2846 * Next pages:
2847 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2848 * SelectPartitionPage (At once)
2849 * QuitPage
2850 *
2851 * SIDEEFFECTS
2852 * Sets PartitionList->CurrentPartition->FormatState
2853 * Sets DestinationRootPath
2854 *
2855 * RETURNS
2856 * Number of the next page.
2857 */
2858 static ULONG
2859 FormatPartitionPage(PINPUT_RECORD Ir)
2860 {
2861 UNICODE_STRING PartitionRootPath;
2862 WCHAR PathBuffer[MAX_PATH];
2863 PDISKENTRY DiskEntry;
2864 PPARTENTRY PartEntry;
2865 NTSTATUS Status;
2866
2867 #ifndef NDEBUG
2868 ULONG Line;
2869 ULONG i;
2870 PLIST_ENTRY Entry;
2871 #endif
2872
2873 DPRINT("FormatPartitionPage()\n");
2874
2875 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2876
2877 if (PartitionList == NULL ||
2878 PartitionList->TempDisk == NULL ||
2879 PartitionList->TempPartition == NULL)
2880 {
2881 /* FIXME: show an error dialog */
2882 return QUIT_PAGE;
2883 }
2884
2885 DiskEntry = PartitionList->TempDisk;
2886 PartEntry = PartitionList->TempPartition;
2887
2888 while (TRUE)
2889 {
2890 if (!IsUnattendedSetup)
2891 {
2892 CONSOLE_ConInKey(Ir);
2893 }
2894
2895 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2896 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2897 {
2898 if (ConfirmQuit(Ir) == TRUE)
2899 {
2900 return QUIT_PAGE;
2901 }
2902
2903 break;
2904 }
2905 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2906 {
2907 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2908
2909 if (wcscmp(PartEntry->FileSystem->FileSystemName, L"FAT") == 0)
2910 {
2911 if (PartEntry->SectorCount.QuadPart < 8192)
2912 {
2913 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
2914 PartEntry->PartitionType = PARTITION_FAT_12;
2915 }
2916 else if (PartEntry->StartSector.QuadPart < 1450560)
2917 {
2918 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2919
2920 if (PartEntry->SectorCount.QuadPart < 65536)
2921 {
2922 /* FAT16 CHS partition (partiton size < 32MB) */
2923 PartEntry->PartitionType = PARTITION_FAT_16;
2924 }
2925 else if (PartEntry->SectorCount.QuadPart < 1048576)
2926 {
2927 /* FAT16 CHS partition (partition size < 512MB) */
2928 PartEntry->PartitionType = PARTITION_HUGE;
2929 }
2930 else
2931 {
2932 /* FAT32 CHS partition (partition size >= 512MB) */
2933 PartEntry->PartitionType = PARTITION_FAT32;
2934 }
2935 }
2936 else
2937 {
2938 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2939
2940 if (PartEntry->SectorCount.QuadPart < 1048576)
2941 {
2942 /* FAT16 LBA partition (partition size < 512MB) */
2943 PartEntry->PartitionType = PARTITION_XINT13;
2944 }
2945 else
2946 {
2947 /* FAT32 LBA partition (partition size >= 512MB) */
2948 PartEntry->PartitionType = PARTITION_FAT32_XINT13;
2949 }
2950 }
2951
2952 DiskEntry->Dirty = TRUE;
2953 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
2954 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2955 }
2956 #if 0
2957 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"EXT2") == 0)
2958 {
2959 PartEntry->PartitionType = PARTITION_EXT2;
2960
2961 DiskEntry->Dirty = TRUE;
2962 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
2963 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2964 }
2965 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"NTFS") == 0)
2966 {
2967 PartEntry->PartitionType = PARTITION_IFS;
2968
2969 DiskEntry->Dirty = TRUE;
2970 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
2971 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2972 }
2973 #endif
2974 else if (!PartEntry->FileSystem->FormatFunc)
2975 {
2976 return QUIT_PAGE;
2977 }
2978
2979 #ifndef NDEBUG
2980 CONSOLE_PrintTextXY(6, 12,
2981 "Disk: %I64u Cylinder: %I64u Track: %I64u",
2982 DiskEntry->DiskSize,
2983 DiskEntry->CylinderSize,
2984 DiskEntry->TrackSize);
2985
2986 Line = 13;
2987 DiskEntry = PartitionList->TempDisk;
2988 Entry = DiskEntry->PartListHead.Flink;
2989
2990 while (Entry != &DiskEntry->PrimaryPartListHead)
2991 {
2992 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2993
2994 if (PartEntry->IsPartitioned == TRUE)
2995 {
2996 CONSOLE_PrintTextXY(6, Line,
2997 "%2u: %2u %c %12I64u %12I64u %2u %c",
2998 i,
2999 PartEntry->PartitionNumber,
3000 PartEntry->BootIndicator ? 'A' : '-',
3001 PartEntry->StartSector.QuadPart,
3002 PartEntry->SectorCount.QuadPart,
3003 PartEntry->PartitionType,
3004 PartEntry->Dirty ? '*' : ' ');
3005 Line++;
3006 }
3007
3008 Entry = Entry->Flink;
3009 }
3010
3011 /* Restore the old entry */
3012 PartEntry = PartitionList->TempPartition;
3013 #endif
3014
3015 if (WritePartitionsToDisk(PartitionList) == FALSE)
3016 {
3017 DPRINT("WritePartitionsToDisk() failed\n");
3018 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3019 return QUIT_PAGE;
3020 }
3021
3022 /* Set PartitionRootPath */
3023 swprintf(PathBuffer,
3024 L"\\Device\\Harddisk%lu\\Partition%lu",
3025 DiskEntry->DiskNumber,
3026 PartEntry->PartitionNumber);
3027 RtlInitUnicodeString(&PartitionRootPath,
3028 PathBuffer);
3029 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3030
3031 if (PartEntry->FileSystem->FormatFunc)
3032 {
3033 Status = FormatPartition(&PartitionRootPath,
3034 PartEntry->FileSystem);
3035 if (!NT_SUCCESS(Status))
3036 {
3037 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3038 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3039 return QUIT_PAGE;
3040 }
3041
3042 PartEntry->New = FALSE;
3043 }
3044
3045 #ifndef NDEBUG
3046 CONSOLE_SetStatusText(" Done. Press any key ...");
3047 CONSOLE_ConInKey(Ir);
3048 #endif
3049
3050 return SELECT_FILE_SYSTEM_PAGE;
3051 }
3052 }
3053
3054 return FORMAT_PARTITION_PAGE;
3055 }
3056
3057
3058 /*
3059 * Displays the CheckFileSystemPage.
3060 *
3061 * Next pages:
3062 * InstallDirectoryPage (At once)
3063 * QuitPage
3064 *
3065 * SIDEEFFECTS
3066 * Inits or reloads FileSystemList
3067 *
3068 * RETURNS
3069 * Number of the next page.
3070 */
3071 static ULONG
3072 CheckFileSystemPage(PINPUT_RECORD Ir)
3073 {
3074 PFILE_SYSTEM_ITEM CurrentFileSystem;
3075 UNICODE_STRING PartitionRootPath;
3076 WCHAR PathBuffer[MAX_PATH];
3077 CHAR Buffer[MAX_PATH];
3078 PDISKENTRY DiskEntry;
3079 PPARTENTRY PartEntry;
3080 NTSTATUS Status;
3081
3082 if (PartitionList == NULL)
3083 {
3084 /* FIXME: show an error dialog */
3085 return QUIT_PAGE;
3086 }
3087
3088 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3089 {
3090 return INSTALL_DIRECTORY_PAGE;
3091 }
3092
3093 /* Set PartitionRootPath */
3094 swprintf(PathBuffer,
3095 L"\\Device\\Harddisk%lu\\Partition%lu",
3096 DiskEntry->DiskNumber,
3097 PartEntry->PartitionNumber);
3098 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3099 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3100
3101 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3102
3103 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3104
3105 CurrentFileSystem = GetFileSystem(FileSystemList, PartEntry);
3106 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3107 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3108
3109 /* HACK: Do not try to check a partition with an unknown filesytem */
3110 if (CurrentFileSystem == NULL)
3111 {
3112 PartEntry->NeedsCheck = FALSE;
3113 return CHECK_FILE_SYSTEM_PAGE;
3114 }
3115
3116 if (CurrentFileSystem->ChkdskFunc == NULL)
3117 {
3118 sprintf(Buffer,
3119 "Setup is currently unable to check a partition formatted in %S.\n"
3120 "\n"
3121 " \x07 Press ENTER to continue Setup.\n"
3122 " \x07 Press F3 to quit Setup.",
3123 CurrentFileSystem->FileSystemName);
3124
3125 PopupError(Buffer,
3126 MUIGetString(STRING_QUITCONTINUE),
3127 NULL, POPUP_WAIT_NONE);
3128
3129 while (TRUE)
3130 {
3131 CONSOLE_ConInKey(Ir);
3132
3133 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3134 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3135 {
3136 if (ConfirmQuit(Ir))
3137 return QUIT_PAGE;
3138 else
3139 return CHECK_FILE_SYSTEM_PAGE;
3140 }
3141 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3142 {
3143 PartEntry->NeedsCheck = FALSE;
3144 return CHECK_FILE_SYSTEM_PAGE;
3145 }
3146 }
3147 }
3148 else
3149 {
3150 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3151 if (!NT_SUCCESS(Status))
3152 {
3153 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3154 sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3155 "(Status 0x%08lx).\n", Status);
3156 PopupError(Buffer,
3157 MUIGetString(STRING_REBOOTCOMPUTER),
3158 Ir, POPUP_WAIT_ENTER);
3159
3160 return QUIT_PAGE;
3161 }
3162
3163 PartEntry->NeedsCheck = FALSE;
3164 return CHECK_FILE_SYSTEM_PAGE;
3165 }
3166 }
3167
3168
3169 /*
3170 * Displays the InstallDirectoryPage1.
3171 *
3172 * Next pages:
3173 * PrepareCopyPage (At once)
3174 *
3175 * SIDEEFFECTS
3176 * Inits DestinationRootPath
3177 * Inits DestinationPath
3178 * Inits DestinationArcPath
3179 *
3180 * RETURNS
3181 * Number of the next page.
3182 */
3183 static PAGE_NUMBER
3184 InstallDirectoryPage1(PWCHAR InstallDir,
3185 PDISKENTRY DiskEntry,
3186 PPARTENTRY PartEntry)
3187 {
3188 WCHAR PathBuffer[MAX_PATH];
3189
3190 /* Create 'InstallPath' string */
3191 RtlFreeUnicodeString(&InstallPath);
3192 RtlCreateUnicodeString(&InstallPath, InstallDir);
3193
3194 /* Create 'DestinationRootPath' string */
3195 RtlFreeUnicodeString(&DestinationRootPath);
3196 swprintf(PathBuffer,
3197 L"\\Device\\Harddisk%lu\\Partition%lu",
3198 DiskEntry->DiskNumber,
3199 PartEntry->PartitionNumber);
3200 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
3201 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
3202
3203 /* Create 'DestinationPath' string */
3204 RtlFreeUnicodeString(&DestinationPath);
3205 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3206
3207 if (InstallDir[0] != L'\\')
3208 wcscat(PathBuffer, L"\\");
3209
3210 wcscat(PathBuffer, InstallDir);
3211 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
3212
3213 /* Create 'DestinationArcPath' */
3214 RtlFreeUnicodeString(&DestinationArcPath);
3215 swprintf(PathBuffer,
3216 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
3217 DiskEntry->BiosDiskNumber,
3218 PartEntry->PartitionNumber);
3219
3220 if (InstallDir[0] != L'\\')
3221 wcscat(PathBuffer, L"\\");
3222
3223 wcscat(PathBuffer, InstallDir);
3224 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
3225
3226 return PREPARE_COPY_PAGE;
3227 }
3228
3229
3230 /*
3231 * Displays the InstallDirectoryPage.
3232 *
3233 * Next pages:
3234 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3235 * QuitPage
3236 *
3237 * RETURNS
3238 * Number of the next page.
3239 */
3240 static PAGE_NUMBER
3241 InstallDirectoryPage(PINPUT_RECORD Ir)
3242 {
3243 PDISKENTRY DiskEntry;
3244 PPARTENTRY PartEntry;
3245 WCHAR InstallDir[51];
3246 WCHAR c;
3247 ULONG Length;
3248
3249 /* We do not need the filsystem list any more */
3250 DestroyFileSystemList(FileSystemList);
3251 FileSystemList = NULL;
3252
3253 if (PartitionList == NULL ||
3254 PartitionList->CurrentDisk == NULL ||
3255 PartitionList->CurrentPartition == NULL)
3256 {
3257 /* FIXME: show an error dialog */
3258 return QUIT_PAGE;
3259 }
3260
3261 DiskEntry = PartitionList->CurrentDisk;
3262 PartEntry = PartitionList->CurrentPartition;
3263
3264 if (IsUnattendedSetup)
3265 wcscpy(InstallDir, UnattendInstallationDirectory);
3266 else
3267 wcscpy(InstallDir, L"\\ReactOS");
3268
3269 Length = wcslen(InstallDir);
3270 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3271 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3272
3273 // FIXME: Check the validity of the InstallDir; however what to do
3274 // if it is invalid but we are in unattended setup? (case of somebody
3275 // specified an invalid installation directory in the unattended file).
3276
3277 if (IsUnattendedSetup)
3278 {
3279 return InstallDirectoryPage1(InstallDir,
3280 DiskEntry,
3281 PartEntry);
3282 }
3283
3284 while (TRUE)
3285 {
3286 CONSOLE_ConInKey(Ir);
3287
3288 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3289 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3290 {
3291 if (ConfirmQuit(Ir) == TRUE)
3292 return QUIT_PAGE;
3293
3294 break;
3295 }
3296 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3297 {
3298 /*
3299 * Check for the validity of the installation directory and pop up
3300 * an error if it is not the case. Then the user can fix its input.
3301 */
3302 if (!IsValidPath(InstallDir, Length))
3303 {
3304 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3305 return INSTALL_DIRECTORY_PAGE;
3306 }
3307 return InstallDirectoryPage1(InstallDir,
3308 DiskEntry,
3309 PartEntry);
3310 }
3311 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3312 {
3313 if (Length > 0)
3314 {
3315 Length--;
3316 InstallDir[Length] = 0;
3317 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3318 }
3319 }
3320 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3321 {
3322 if (Length < 50)
3323 {
3324 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3325 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3326 {
3327 InstallDir[Length] = c;
3328 Length++;
3329 InstallDir[Length] = 0;
3330 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3331 }
3332 }
3333 }
3334 }
3335
3336 return INSTALL_DIRECTORY_PAGE;
3337 }
3338
3339
3340 static BOOLEAN
3341 AddSectionToCopyQueueCab(HINF InfFile,
3342 PWCHAR SectionName,
3343 PWCHAR SourceCabinet,
3344 PCUNICODE_STRING DestinationPath,
3345 PINPUT_RECORD Ir)
3346 {
3347 INFCONTEXT FilesContext;
3348 INFCONTEXT DirContext;
3349 PWCHAR FileKeyName;
3350 PWCHAR FileKeyValue;
3351 PWCHAR DirKeyValue;
3352 PWCHAR TargetFileName;
3353
3354 /* Search for the SectionName section */
3355 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3356 {
3357 char Buffer[128];
3358 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3359 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3360 return FALSE;
3361 }
3362
3363 /*
3364 * Enumerate the files in the section
3365 * and add them to the file queue.
3366 */
3367 do
3368 {
3369 /* Get source file name and target directory id */
3370 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3371 {
3372 /* FIXME: Handle error! */
3373 DPRINT1("INF_GetData() failed\n");
3374 break;
3375 }
3376
3377 /* Get optional target file name */
3378 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
3379 TargetFileName = NULL;
3380
3381 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3382
3383 /* Lookup target directory */
3384 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3385 {
3386 /* FIXME: Handle error! */
3387 DPRINT1("SetupFindFirstLine() failed\n");
3388 break;
3389 }
3390
3391 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3392 {
3393 /* FIXME: Handle error! */
3394 DPRINT1("INF_GetData() failed\n");
3395 break;
3396 }
3397
3398 if (!SetupQueueCopy(SetupFileQueue,
3399 SourceCabinet,
3400 SourceRootPath.Buffer,
3401 SourceRootDir.Buffer,
3402 FileKeyName,
3403 DirKeyValue,
3404 TargetFileName))
3405 {
3406 /* FIXME: Handle error! */
3407 DPRINT1("SetupQueueCopy() failed\n");
3408 }
3409 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3410
3411 return TRUE;
3412 }
3413
3414
3415 static BOOLEAN
3416 AddSectionToCopyQueue(HINF InfFile,
3417 PWCHAR SectionName,
3418 PWCHAR SourceCabinet,
3419 PCUNICODE_STRING DestinationPath,
3420 PINPUT_RECORD Ir)
3421 {
3422 INFCONTEXT FilesContext;
3423 INFCONTEXT DirContext;
3424 PWCHAR FileKeyName;
3425 PWCHAR FileKeyValue;
3426 PWCHAR DirKeyValue;
3427 PWCHAR TargetFileName;
3428 ULONG Length;
3429 WCHAR CompleteOrigDirName[512];
3430
3431 if (SourceCabinet)
3432 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
3433
3434 /* Search for the SectionName section */
3435 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3436 {
3437 char Buffer[128];
3438 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3439 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3440 return FALSE;
3441 }
3442
3443 /*
3444 * Enumerate the files in the section
3445 * and add them to the file queue.
3446 */
3447 do
3448 {
3449 /* Get source file name and target directory id */
3450 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3451 {
3452 /* FIXME: Handle error! */
3453 DPRINT1("INF_GetData() failed\n");
3454 break;
3455 }
3456
3457 /* Get target directory id */
3458 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
3459 {
3460 /* FIXME: Handle error! */
3461 DPRINT1("INF_GetData() failed\n");
3462 break;
3463 }
3464
3465 /* Get optional target file name */
3466 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
3467 TargetFileName = NULL;
3468 else if (!*TargetFileName)
3469 TargetFileName = NULL;
3470
3471 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3472
3473 /* Lookup target directory */
3474 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3475 {
3476 /* FIXME: Handle error! */
3477 DPRINT1("SetupFindFirstLine() failed\n");
3478 break;
3479 }
3480
3481 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3482 {
3483 /* FIXME: Handle error! */
3484 DPRINT1("INF_GetData() failed\n");
3485 break;
3486 }
3487
3488 if ((DirKeyValue[0] == 0) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == 0))
3489 {
3490 /* Installation path */
3491 wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
3492 }
3493 else if (DirKeyValue[0] == L'\\')
3494 {
3495 /* Absolute path */
3496 wcscpy(CompleteOrigDirName, DirKeyValue);
3497 }
3498 else // if (DirKeyValue[0] != L'\\')
3499 {
3500 /* Path relative to the installation path */
3501 wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
3502 wcscat(CompleteOrigDirName, L"\\");
3503 wcscat(CompleteOrigDirName, DirKeyValue);
3504 }
3505
3506 /* Remove trailing backslash */
3507 Length = wcslen(CompleteOrigDirName);
3508 if ((Length > 0) && (CompleteOrigDirName[Length - 1] == L'\\'))
3509 {
3510 CompleteOrigDirName[Length - 1] = 0;
3511 }
3512
3513 if (!SetupQueueCopy(SetupFileQueue,
3514 SourceCabinet,
3515 SourceRootPath.Buffer,
3516 CompleteOrigDirName,
3517 FileKeyName,
3518 DirKeyValue,
3519 TargetFileName))
3520 {
3521 /* FIXME: Handle error! */
3522 DPRINT1("SetupQueueCopy() failed\n");
3523 }
3524 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3525
3526 return TRUE;
3527 }
3528
3529
3530 static BOOLEAN
3531 PrepareCopyPageInfFile(HINF InfFile,
3532 PWCHAR SourceCabinet,
3533 PINPUT_RECORD Ir)
3534 {
3535 WCHAR PathBuffer[MAX_PATH];
3536 INFCONTEXT DirContext;
3537 PWCHAR AdditionalSectionName = NULL;
3538 PWCHAR DirKeyValue;
3539 ULONG Length;
3540 NTSTATUS Status;
3541
3542 /* Add common files */
3543 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
3544 return FALSE;
3545
3546 /* Add specific files depending of computer type */
3547 if (SourceCabinet == NULL)
3548 {
3549 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
3550 return FALSE;
3551
3552 if (AdditionalSectionName)
3553 {
3554 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
3555 return FALSE;
3556 }
3557 }
3558
3559 /* Create directories */
3560
3561 /*
3562 * FIXME:
3563 * - Install directories like '\reactos\test' are not handled yet.
3564 * - Copying files to DestinationRootPath should be done from within
3565 * the SystemPartitionFiles section.
3566 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3567 * For installing to DestinationPath specify just '\' .
3568 */
3569
3570 /* Get destination path */
3571 wcscpy(PathBuffer, DestinationPath.Buffer);
3572
3573 /* Remove trailing backslash */
3574 Length = wcslen(PathBuffer);
3575 if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
3576 {
3577 PathBuffer[Length - 1] = 0;
3578 }
3579
3580 /* Create the install directory */
3581 Status = SetupCreateDirectory(PathBuffer);
3582 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3583 {
3584 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3585 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
3586 return FALSE;
3587 }
3588
3589 /* Search for the 'Directories' section */
3590 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3591 {
3592 if (SourceCabinet)
3593 {
3594 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
3595 }
3596 else
3597 {
3598 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
3599 }
3600
3601 return FALSE;
3602 }
3603
3604 /* Enumerate the directory values and create the subdirectories */
3605 do
3606 {
3607 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3608 {
3609 DPRINT1("break\n");
3610 break;
3611 }
3612
3613 if ((DirKeyValue[0] == 0) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == 0))
3614 {
3615 /* Installation path */
3616 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3617
3618 wcscpy(PathBuffer, DestinationPath.Buffer);
3619
3620 DPRINT("FullPath: '%S'\n", PathBuffer);
3621 }
3622 else if (DirKeyValue[0] == L'\\')
3623 {
3624 /* Absolute path */
3625 DPRINT("Absolute Path: '%S'\n", DirKeyValue);
3626
3627 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3628 wcscat(PathBuffer, DirKeyValue);
3629
3630 /* Remove trailing backslash */
3631 Length = wcslen(PathBuffer);
3632 if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
3633 {
3634 PathBuffer[Length - 1] = 0;
3635 }
3636
3637 DPRINT("FullPath: '%S'\n", PathBuffer);
3638
3639 Status = SetupCreateDirectory(PathBuffer);
3640 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3641 {
3642 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3643 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3644 return FALSE;
3645 }
3646 }
3647 else // if (DirKeyValue[0] != L'\\')
3648 {
3649 /* Path relative to the installation path */
3650 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3651
3652 wcscpy(PathBuffer, DestinationPath.Buffer);
3653 wcscat(PathBuffer, L"\\");
3654 wcscat(PathBuffer, DirKeyValue);
3655
3656 /* Remove trailing backslash */
3657 Length = wcslen(PathBuffer);
3658 if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
3659 {
3660 PathBuffer[Length - 1] = 0;
3661 }
3662
3663 DPRINT("FullPath: '%S'\n", PathBuffer);
3664
3665 Status = SetupCreateDirectory(PathBuffer);
3666 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3667 {
3668 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3669 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3670 return FALSE;
3671 }
3672 }
3673 } while (SetupFindNextLine(&DirContext, &DirContext));
3674
3675 return TRUE;
3676 }
3677
3678
3679 /*
3680 * Displays the PrepareCopyPage.
3681 *
3682 * Next pages:
3683 * FileCopyPage(At once)
3684 * QuitPage
3685 *
3686 * SIDEEFFECTS
3687 * Inits SetupFileQueue
3688 * Calls PrepareCopyPageInfFile
3689 *
3690 * RETURNS
3691 * Number of the next page.
3692 */
3693 static PAGE_NUMBER
3694 PrepareCopyPage(PINPUT_RECORD Ir)
3695 {
3696 HINF InfHandle;
3697 WCHAR PathBuffer[MAX_PATH];
3698 INFCONTEXT CabinetsContext;
3699 ULONG InfFileSize;
3700 PWCHAR KeyValue;
3701 UINT ErrorLine;
3702 PVOID InfFileData;
3703
3704 MUIDisplayPage(PREPARE_COPY_PAGE);
3705
3706 /* Create the file queue */
3707 SetupFileQueue = SetupOpenFileQueue();
3708 if (SetupFileQueue == NULL)
3709 {
3710 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
3711 return(QUIT_PAGE);
3712 }
3713
3714 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
3715 {
3716 return QUIT_PAGE;
3717 }
3718
3719 /* Search for the 'Cabinets' section */
3720 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
3721 {
3722 return FILE_COPY_PAGE;
3723 }
3724
3725 /*
3726 * Enumerate the directory values in the 'Cabinets'
3727 * section and parse their inf files.
3728 */
3729 do
3730 {
3731 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3732 break;
3733
3734 wcscpy(PathBuffer, SourcePath.Buffer);
3735 wcscat(PathBuffer, L"\\");
3736 wcscat(PathBuffer, KeyValue);
3737
3738 #ifdef __REACTOS__
3739 CabinetInitialize();
3740 CabinetSetEventHandlers(NULL, NULL, NULL);
3741 CabinetSetCabinetName(PathBuffer);
3742
3743 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3744 {
3745 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3746
3747 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3748 if (InfFileData == NULL)
3749 {
3750 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3751 return QUIT_PAGE;
3752 }
3753 }
3754 else
3755 {
3756 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3757 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3758 return QUIT_PAGE;
3759 }
3760
3761 InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
3762 InfFileSize,
3763 (const CHAR*) NULL,
3764 INF_STYLE_WIN4,
3765 LanguageId,
3766 &ErrorLine);
3767
3768 if (InfHandle == INVALID_HANDLE_VALUE)
3769 {
3770 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3771 return QUIT_PAGE;
3772 }
3773
3774 CabinetCleanup();
3775
3776 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3777 {
3778 return QUIT_PAGE;
3779 }
3780 #endif
3781 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3782
3783 return FILE_COPY_PAGE;
3784 }
3785
3786
3787 VOID
3788 NTAPI
3789 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3790 IN BOOLEAN First)
3791 {
3792 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3793
3794 /* Get the memory information from the system */
3795 NtQuerySystemInformation(SystemPerformanceInformation,
3796 &PerfInfo,
3797 sizeof(PerfInfo),
3798 NULL);
3799
3800 /* Check if this is initial setup */
3801 if (First)
3802 {
3803 /* Set maximum limits to be total RAM pages */
3804 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3805 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3806 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3807 }
3808
3809 /* Set current values */
3810 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3811 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3812 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3813 }
3814
3815
3816 static UINT
3817 CALLBACK
3818 FileCopyCallback(PVOID Context,
3819 UINT Notification,
3820 UINT_PTR Param1,
3821 UINT_PTR Param2)
3822 {
3823 PCOPYCONTEXT CopyContext;
3824
3825 CopyContext = (PCOPYCONTEXT)Context;
3826
3827 switch (Notification)
3828 {
3829 case SPFILENOTIFY_STARTSUBQUEUE:
3830 CopyContext->TotalOperations = (ULONG)Param2;
3831 ProgressSetStepCount(CopyContext->ProgressBar,
3832 CopyContext->TotalOperations);
3833 SetupUpdateMemoryInfo(CopyContext, TRUE);
3834 break;
3835
3836 case SPFILENOTIFY_STARTCOPY:
3837 /* Display copy message */
3838 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
3839 SetupUpdateMemoryInfo(CopyContext, FALSE);
3840 break;
3841
3842 case SPFILENOTIFY_ENDCOPY:
3843 CopyContext->CompletedOperations++;
3844
3845 /* SYSREG checkpoint */
3846 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
3847 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3848
3849 ProgressNextStep(CopyContext->ProgressBar);
3850 SetupUpdateMemoryInfo(CopyContext, FALSE);
3851 break;
3852 }
3853
3854 return 0;
3855 }
3856
3857
3858 /*
3859 * Displays the FileCopyPage.
3860 *
3861 * Next pages:
3862 * RegistryPage(At once)
3863 *
3864 * SIDEEFFECTS
3865 * Calls SetupCommitFileQueueW
3866 * Calls SetupCloseFileQueue
3867 *
3868 * RETURNS
3869 * Number of the next page.
3870 */
3871 static
3872 PAGE_NUMBER
3873 FileCopyPage(PINPUT_RECORD Ir)
3874 {
3875 COPYCONTEXT CopyContext;
3876 unsigned int mem_bar_width;
3877
3878 MUIDisplayPage(FILE_COPY_PAGE);
3879
3880 /* Create context for the copy process */
3881 CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
3882 CopyContext.InstallPath = InstallPath.Buffer;
3883 CopyContext.TotalOperations = 0;
3884 CopyContext.CompletedOperations = 0;
3885
3886 /* Create the progress bar as well */
3887 CopyContext.ProgressBar = CreateProgressBar(13,
3888 26,
3889 xScreen - 13,
3890 yScreen - 20,
3891 10,
3892 24,
3893 TRUE,
3894 MUIGetString(STRING_SETUPCOPYINGFILES));
3895
3896 // fit memory bars to screen width, distribute them uniform
3897 mem_bar_width = (xScreen - 26) / 5;
3898 mem_bar_width -= mem_bar_width % 2; // make even
3899 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3900 /* Create the paged pool progress bar */
3901 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3902 40,
3903 13 + mem_bar_width,
3904 43,
3905 13,
3906 44,
3907 FALSE,
3908 "Kernel Pool");
3909
3910 /* Create the non paged pool progress bar */
3911 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
3912 40,
3913 (xScreen / 2) + (mem_bar_width / 2),
3914 43,
3915 (xScreen / 2)- (mem_bar_width / 2),
3916 44,
3917 FALSE,
3918 "Kernel Cache");
3919
3920 /* Create the global memory progress bar */
3921 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
3922 40,
3923 xScreen - 13,
3924 43,
3925 xScreen - 13 - mem_bar_width,
3926 44,
3927 FALSE,
3928 "Free Memory");
3929
3930 /* Do the file copying */
3931 SetupCommitFileQueueW(NULL,
3932 SetupFileQueue,
3933 FileCopyCallback,
3934 &CopyContext);
3935
3936 /* If we get here, we're done, so cleanup the queue and progress bar */
3937 SetupCloseFileQueue(SetupFileQueue);
3938 DestroyProgressBar(CopyContext.ProgressBar);
3939 DestroyProgressBar(CopyContext.MemoryBars[0]);
3940 DestroyProgressBar(CopyContext.MemoryBars[1]);
3941 DestroyProgressBar(CopyContext.MemoryBars[2]);
3942
3943 /* Go display the next page */
3944 return REGISTRY_PAGE;
3945 }
3946
3947
3948 /*
3949 * Displays the RegistryPage.
3950 *
3951 * Next pages:
3952 * SuccessPage (if RepairUpdate)
3953 * BootLoaderPage (default)
3954 * QuitPage
3955 *
3956 * SIDEEFFECTS
3957 * Calls SetInstallPathValue
3958 * Calls NtInitializeRegistry
3959 * Calls ImportRegistryFile
3960 * Calls SetDefaultPagefile
3961 * Calls SetMountedDeviceValues
3962 *
3963 * RETURNS
3964 * Number of the next page.
3965 */
3966 static PAGE_NUMBER
3967 RegistryPage(PINPUT_RECORD Ir)
3968 {
3969 INFCONTEXT InfContext;
3970 PWSTR Action;
3971 PWSTR File;
3972 PWSTR Section;
3973 BOOLEAN Delete;
3974 NTSTATUS Status;
3975
3976 MUIDisplayPage(REGISTRY_PAGE);
3977
3978 if (RepairUpdateFlag)
3979 {
3980 return SUCCESS_PAGE;
3981 }
3982
3983 if (!SetInstallPathValue(&DestinationPath))
3984 {
3985 DPRINT1("SetInstallPathValue() failed\n");
3986 MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
3987 return QUIT_PAGE;
3988 }
3989
3990 /* Create the default hives */
3991 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
3992 if (!NT_SUCCESS(Status))
3993 {
3994 DPRINT1("NtInitializeRegistry() failed (Status %lx)\n", Status);
3995 MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
3996 return QUIT_PAGE;
3997 }
3998
3999 /* Update registry */
4000 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
4001
4002 if (!SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext))
4003 {
4004 DPRINT1("SetupFindFirstLine() failed\n");
4005 MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
4006 return QUIT_PAGE;
4007 }
4008
4009 do
4010 {
4011 INF_GetDataField (&InfContext, 0, &Action);
4012 INF_GetDataField (&InfContext, 1, &File);
4013 INF_GetDataField (&InfContext, 2, &Section);
4014
4015 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section);
4016
4017 if (Action == NULL)
4018 break; // Hackfix
4019
4020 if (!_wcsicmp (Action, L"AddReg"))
4021 {
4022 Delete = FALSE;
4023 }
4024 else if (!_wcsicmp (Action, L"DelReg"))
4025 {
4026 Delete = TRUE;
4027 }
4028 else
4029 {
4030 continue;
4031 }
4032
4033 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
4034
4035 if (!ImportRegistryFile(File, Section, LanguageId, Delete))
4036 {
4037 DPRINT1("Importing %S failed\n", File);
4038
4039 MUIDisplayError(ERROR_IMPORT_HIVE, Ir, POPUP_WAIT_ENTER);
4040 return QUIT_PAGE;
4041 }
4042 } while (SetupFindNextLine(&InfContext, &InfContext));
4043
4044 /* Update display registry settings */
4045 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
4046 if (!ProcessDisplayRegistry(SetupInf, DisplayList))
4047 {
4048 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
4049 return QUIT_PAGE;
4050 }
4051
4052 /* Set the locale */
4053 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
4054 if (!ProcessLocaleRegistry(LanguageList))
4055 {
4056 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
4057 return QUIT_PAGE;
4058 }
4059
4060 /* Add keyboard layouts */
4061 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
4062 if (!AddKeyboardLayouts())
4063 {
4064 MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
4065 return QUIT_PAGE;
4066 }
4067
4068 /* Set GeoID */
4069
4070 if (!SetGeoID(MUIGetGeoID()))
4071 {
4072 MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
4073 return QUIT_PAGE;
4074 }
4075
4076 if (!IsUnattendedSetup)
4077 {
4078 /* Update keyboard layout settings */
4079 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
4080 if (!ProcessKeyboardLayoutRegistry(LayoutList))
4081 {
4082 MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
4083 return QUIT_PAGE;
4084 }
4085 }
4086
4087 /* Add codepage information to registry */
4088 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
4089 if (!AddCodePage())
4090 {
4091 MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
4092 return QUIT_PAGE;
4093 }
4094
4095 /* Set the default pagefile entry */
4096 SetDefaultPagefile(DestinationDriveLetter);
4097
4098 /* Update the mounted devices list */
4099 SetMountedDeviceValues(PartitionList);
4100
4101 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
4102
4103 return BOOT_LOADER_PAGE;
4104 }
4105
4106
4107 /*
4108 * Displays the BootLoaderPage.
4109 *
4110 * Next pages:
4111 * SuccessPage (if RepairUpdate)
4112 * BootLoaderHarddiskMbrPage
4113 * BootLoaderHarddiskVbrPage
4114 * BootLoaderFloppyPage
4115 * SuccessPage
4116 * QuitPage
4117 *
4118 * SIDEEFFECTS
4119 * Calls SetInstallPathValue
4120 * Calls NtInitializeRegistry
4121 * Calls ImportRegistryFile
4122 * Calls SetDefaultPagefile
4123 * Calls SetMountedDeviceValues
4124 *
4125 * RETURNS
4126 * Number of the next page.
4127 */
4128 static PAGE_NUMBER
4129 BootLoaderPage(PINPUT_RECORD Ir)
4130 {
4131 UCHAR PartitionType;
4132 BOOLEAN InstallOnFloppy;
4133 USHORT Line = 12;
4134 WCHAR PathBuffer[MAX_PATH];
4135
4136 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4137
4138 RtlFreeUnicodeString(&SystemRootPath);
4139 swprintf(PathBuffer,
4140 L"\\Device\\Harddisk%lu\\Partition%lu",
4141 PartitionList->SystemDisk->DiskNumber,
4142 PartitionList->SystemPartition->PartitionNumber);
4143 RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
4144 DPRINT("SystemRootPath: %wZ\n", &SystemRootPath);
4145
4146 PartitionType = PartitionList->SystemPartition->PartitionType;
4147
4148 if (IsUnattendedSetup)
4149 {
4150 if (UnattendMBRInstallType == 0) /* skip MBR installation */
4151 {
4152 return SUCCESS_PAGE;
4153 }
4154 else if (UnattendMBRInstallType == 1) /* install on floppy */
4155 {
4156 return BOOT_LOADER_FLOPPY_PAGE;
4157 }
4158 }
4159
4160 if (PartitionType == PARTITION_ENTRY_UNUSED)
4161 {
4162 DPRINT("Error: system partition invalid (unused)\n");
4163 InstallOnFloppy = TRUE;
4164 }
4165 else if (PartitionType == PARTITION_OS2BOOTMGR)
4166 {
4167 /* OS/2 boot manager partition */
4168 DPRINT("Found OS/2 boot manager partition\n");
4169 InstallOnFloppy = TRUE;
4170 }
4171 else if (PartitionType == PARTITION_EXT2)
4172 {
4173 /* Linux EXT2 partition */
4174 DPRINT("Found Linux EXT2 partition\n");
4175 InstallOnFloppy = FALSE;
4176 }
4177 else if (PartitionType == PARTITION_IFS)
4178 {
4179 /* NTFS partition */
4180 DPRINT("Found NTFS partition\n");
4181
4182 // FIXME: Make it FALSE when we'll support NTFS installation!
4183 InstallOnFloppy = TRUE;
4184 }
4185 else if ((PartitionType == PARTITION_FAT_12) ||
4186 (PartitionType == PARTITION_FAT_16) ||
4187 (PartitionType == PARTITION_HUGE) ||
4188 (PartitionType == PARTITION_XINT13) ||
4189 (PartitionType == PARTITION_FAT32) ||
4190 (PartitionType == PARTITION_FAT32_XINT13))
4191 {
4192 DPRINT("Found FAT partition\n");
4193 InstallOnFloppy = FALSE;
4194 }
4195 else
4196 {
4197 /* Unknown partition */
4198 DPRINT("Unknown partition found\n");
4199 InstallOnFloppy = TRUE;
4200 }
4201
4202 if (InstallOnFloppy == TRUE)
4203 {
4204 return BOOT_LOADER_FLOPPY_PAGE;
4205 }
4206
4207 /* Unattended install on hdd? */
4208 if (IsUnattendedSetup && UnattendMBRInstallType == 2)
4209 {
4210 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4211 }
4212
4213 MUIDisplayPage(BOOT_LOADER_PAGE);
4214 CONSOLE_InvertTextXY(8, Line, 60, 1);
4215
4216 while (TRUE)
4217 {
4218 CONSOLE_ConInKey(Ir);
4219
4220 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4221 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
4222 {
4223 CONSOLE_NormalTextXY(8, Line, 60, 1);
4224
4225 Line++;
4226 if (Line<12)
4227 Line=15;
4228
4229 if (Line>15)
4230 Line=12;
4231
4232 CONSOLE_InvertTextXY(8, Line, 60, 1);
4233 }
4234 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4235 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
4236 {
4237 CONSOLE_NormalTextXY(8, Line, 60, 1);
4238
4239 Line--;
4240 if (Line<12)
4241 Line=15;
4242
4243 if (Line>15)
4244 Line=12;
4245
4246 CONSOLE_InvertTextXY(8, Line, 60, 1);
4247 }
4248 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4249 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4250 {
4251 if (ConfirmQuit(Ir) == TRUE)
4252 return QUIT_PAGE;
4253
4254 break;
4255 }
4256 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4257 {
4258 if (Line == 12)
4259 {
4260 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4261 }
4262 else if (Line == 13)
4263 {
4264 return BOOT_LOADER_HARDDISK_VBR_PAGE;
4265 }
4266 else if (Line == 14)
4267 {
4268 return BOOT_LOADER_FLOPPY_PAGE;
4269 }
4270 else if (Line == 15)
4271 {
4272 return SUCCESS_PAGE;
4273 }
4274
4275 return BOOT_LOADER_PAGE;
4276 }
4277 }
4278
4279 return BOOT_LOADER_PAGE;
4280 }
4281
4282
4283 /*
4284 * Displays the BootLoaderFloppyPage.
4285 *
4286 * Next pages:
4287 * SuccessPage (At once)
4288 * QuitPage
4289 *
4290 * SIDEEFFECTS
4291 * Calls InstallFatBootcodeToFloppy()
4292 *
4293 * RETURNS
4294 * Number of the next page.
4295 */
4296 static PAGE_NUMBER
4297 BootLoaderFloppyPage(PINPUT_RECORD Ir)
4298 {
4299 NTSTATUS Status;
4300
4301 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
4302
4303 // SetStatusText(" Please wait...");
4304
4305 while (TRUE)
4306 {
4307 CONSOLE_ConInKey(Ir);
4308
4309 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4310 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4311 {
4312 if (ConfirmQuit(Ir) == TRUE)
4313 return QUIT_PAGE;
4314
4315 break;
4316 }
4317 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4318 {
4319 if (DoesFileExist(L"\\Device\\Floppy0", L"\\") == FALSE)
4320 {
4321 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
4322 return BOOT_LOADER_FLOPPY_PAGE;
4323 }
4324
4325 Status = InstallFatBootcodeToFloppy(&SourceRootPath, &DestinationArcPath);
4326 if (!NT_SUCCESS(Status))
4327 {
4328 /* Print error message */
4329 return BOOT_LOADER_FLOPPY_PAGE;
4330 }
4331
4332 return SUCCESS_PAGE;
4333 }
4334 }
4335
4336 return BOOT_LOADER_FLOPPY_PAGE;
4337 }
4338
4339
4340 /*
4341 * Displays the BootLoaderHarddiskVbrPage.
4342 *
4343 * Next pages:
4344 * SuccessPage (At once)
4345 * QuitPage
4346 *
4347 * SIDEEFFECTS
4348 * Calls InstallVBRToPartition()
4349 *
4350 * RETURNS
4351 * Number of the next page.
4352 */
4353 static PAGE_NUMBER
4354 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
4355 {
4356 UCHAR PartitionType;
4357 NTSTATUS Status;
4358
4359 PartitionType = PartitionList->SystemPartition->PartitionType;
4360
4361 Status = InstallVBRToPartition(&SystemRootPath,
4362 &SourceRootPath,
4363 &DestinationArcPath,
4364 PartitionType);
4365 if (!NT_SUCCESS(Status))
4366 {
4367 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4368 return QUIT_PAGE;
4369 }
4370
4371 return SUCCESS_PAGE;
4372 }
4373
4374
4375 /*
4376 * Displays the BootLoaderHarddiskMbrPage.
4377 *
4378 * Next pages:
4379 * SuccessPage (At once)
4380 * QuitPage
4381 *
4382 * SIDEEFFECTS
4383 * Calls InstallVBRToPartition()
4384 * CallsInstallMbrBootCodeToDisk()
4385 *
4386 * RETURNS
4387 * Number of the next page.
4388 */
4389 static PAGE_NUMBER
4390 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
4391 {
4392 UCHAR PartitionType;
4393 NTSTATUS Status;
4394 WCHAR DestinationDevicePathBuffer[MAX_PATH];
4395 WCHAR SourceMbrPathBuffer[MAX_PATH];
4396
4397 /* Step 1: Write the VBR */
4398 PartitionType = PartitionList->SystemPartition->PartitionType;
4399
4400 Status = InstallVBRToPartition(&SystemRootPath,
4401 &SourceRootPath,
4402 &DestinationArcPath,
4403 PartitionType);
4404 if (!NT_SUCCESS(Status))
4405 {
4406 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4407 return QUIT_PAGE;
4408 }
4409
4410 /* Step 2: Write the MBR */
4411 swprintf(DestinationDevicePathBuffer,
4412 L"\\Device\\Harddisk%d\\Partition0",
4413 PartitionList->SystemDisk->DiskNumber);
4414
4415 wcscpy(SourceMbrPathBuffer, SourceRootPath.Buffer);
4416 wcscat(SourceMbrPathBuffer, L"\\loader\\dosmbr.bin");
4417
4418 DPRINT("Install MBR bootcode: %S ==> %S\n",
4419 SourceMbrPathBuffer, DestinationDevicePathBuffer);
4420
4421 Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer,
4422 DestinationDevicePathBuffer);
4423 if (!NT_SUCCESS (Status))
4424 {
4425 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4426 Status);
4427 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
4428 return QUIT_PAGE;
4429 }
4430
4431 return SUCCESS_PAGE;
4432 }
4433
4434
4435 /*
4436 * Displays the QuitPage.
4437 *
4438 * Next pages:
4439 * FlushPage (At once)
4440 *
4441 * SIDEEFFECTS
4442 * Destroy the Lists
4443 *
4444 * RETURNS
4445 * Number of the next page.
4446 */
4447 static PAGE_NUMBER
4448 QuitPage(PINPUT_RECORD Ir)
4449 {
4450 MUIDisplayPage(QUIT_PAGE);
4451
4452 /* Destroy partition list */
4453 if (PartitionList != NULL)
4454 {
4455 DestroyPartitionList (PartitionList);
4456 PartitionList = NULL;
4457 }
4458
4459 /* Destroy filesystem list */
4460 if (FileSystemList != NULL)
4461 {
4462 DestroyFileSystemList (FileSystemList);
4463 FileSystemList = NULL;
4464 }
4465
4466 /* Destroy computer settings list */
4467 if (ComputerList != NULL)
4468 {
4469 DestroyGenericList(ComputerList, TRUE);
4470 ComputerList = NULL;
4471 }
4472
4473 /* Destroy display settings list */
4474 if (DisplayList != NULL)
4475 {
4476 DestroyGenericList(DisplayList, TRUE);
4477 DisplayList = NULL;
4478 }
4479
4480 /* Destroy keyboard settings list */
4481 if (KeyboardList != NULL)
4482 {
4483 DestroyGenericList(KeyboardList, TRUE);
4484 KeyboardList = NULL;
4485 }
4486
4487 /* Destroy keyboard layout list */
4488 if (LayoutList != NULL)
4489 {
4490 DestroyGenericList(LayoutList, TRUE);
4491 LayoutList = NULL;
4492 }
4493
4494 if (LanguageList != NULL)
4495 {
4496 DestroyGenericList(LanguageList, FALSE);
4497 LanguageList = NULL;
4498 }
4499
4500 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
4501
4502 while (TRUE)
4503 {
4504 CONSOLE_ConInKey(Ir);
4505
4506 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4507 {
4508 return FLUSH_PAGE;
4509 }
4510 }
4511 }
4512
4513
4514 /*
4515 * Displays the SuccessPage.
4516 *
4517 * Next pages:
4518 * FlushPage (At once)
4519 *
4520 * SIDEEFFECTS
4521 * Destroy the Lists
4522 *
4523 * RETURNS
4524 * Number of the next page.
4525 */
4526 static PAGE_NUMBER
4527 SuccessPage(PINPUT_RECORD Ir)
4528 {
4529 MUIDisplayPage(SUCCESS_PAGE);
4530
4531 if (IsUnattendedSetup)
4532 {
4533 return FLUSH_PAGE;
4534 }
4535
4536 while (TRUE)
4537 {
4538 CONSOLE_ConInKey(Ir);
4539
4540 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4541 {
4542 return FLUSH_PAGE;
4543 }
4544 }
4545 }
4546
4547
4548 /*
4549 * Displays the FlushPage.
4550 *
4551 * Next pages:
4552 * RebootPage (At once)
4553 *
4554 * RETURNS
4555 * Number of the next page.
4556 */
4557 static PAGE_NUMBER
4558 FlushPage(PINPUT_RECORD Ir)
4559 {
4560 MUIDisplayPage(FLUSH_PAGE);
4561 return REBOOT_PAGE;
4562 }
4563
4564
4565 DWORD WINAPI
4566 PnpEventThread(IN LPVOID lpParameter);
4567
4568
4569 /*
4570 * The start routine and page management
4571 */
4572 VOID
4573 RunUSetup(VOID)
4574 {
4575 INPUT_RECORD Ir;
4576 PAGE_NUMBER Page;
4577 LARGE_INTEGER Time;
4578 NTSTATUS Status;
4579 BOOLEAN Old;
4580
4581 NtQuerySystemTime(&Time);
4582
4583 Status = RtlCreateUserThread(NtCurrentProcess(),
4584 NULL,
4585 TRUE,
4586 0,
4587 0,
4588 0,
4589 PnpEventThread,
4590 &SetupInf,
4591 &hPnpThread,
4592 NULL);
4593 if (!NT_SUCCESS(Status))
4594 hPnpThread = INVALID_HANDLE_VALUE;
4595
4596 if (!CONSOLE_Init())
4597 {
4598 PrintString(MUIGetString(STRING_CONSOLEFAIL1));
4599 PrintString(MUIGetString(STRING_CONSOLEFAIL2));
4600 PrintString(MUIGetString(STRING_CONSOLEFAIL3));
4601
4602 /* Raise a hard error (crash the system/BSOD) */
4603 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
4604 0,0,0,0,0);
4605 }
4606
4607 /* Initialize global unicode strings */
4608 RtlInitUnicodeString(&SourcePath, NULL);
4609 RtlInitUnicodeString(&SourceRootPath, NULL);
4610 RtlInitUnicodeString(&SourceRootDir, NULL);
4611 RtlInitUnicodeString(&InstallPath, NULL);
4612 RtlInitUnicodeString(&DestinationPath, NULL);
4613 RtlInitUnicodeString(&DestinationArcPath, NULL);
4614 RtlInitUnicodeString(&DestinationRootPath, NULL);
4615 RtlInitUnicodeString(&SystemRootPath, NULL);
4616
4617 /* Hide the cursor */
4618 CONSOLE_SetCursorType(TRUE, FALSE);
4619
4620 Page = START_PAGE;
4621 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
4622 {
4623 CONSOLE_ClearScreen();
4624 CONSOLE_Flush();
4625
4626 //CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4627 //CONSOLE_Flush();
4628
4629 switch (Page)
4630 {
4631 /* Start page */
4632 case START_PAGE:
4633 Page = SetupStartPage(&Ir);
4634 break;
4635
4636 /* Language page */
4637 case LANGUAGE_PAGE:
4638 Page = LanguagePage(&Ir);
4639 break;
4640
4641 /* License page */
4642 case LICENSE_PAGE:
4643 Page = LicensePage(&Ir);
4644 break;
4645
4646 /* Intro page */
4647 case INTRO_PAGE:
4648 Page = IntroPage(&Ir);
4649 break;
4650
4651 /* Install pages */
4652 case INSTALL_INTRO_PAGE:
4653 Page = InstallIntroPage(&Ir);
4654 break;
4655
4656 #if 0
4657 case SCSI_CONTROLLER_PAGE:
4658 Page = ScsiControllerPage(&Ir);
4659 break;
4660 #endif
4661
4662 #if 0
4663 case OEM_DRIVER_PAGE:
4664 Page = OemDriverPage(&Ir);
4665 break;
4666 #endif
4667
4668 case DEVICE_SETTINGS_PAGE:
4669 Page = DeviceSettingsPage(&Ir);
4670 break;
4671
4672 case COMPUTER_SETTINGS_PAGE:
4673 Page = ComputerSettingsPage(&Ir);
4674 break;
4675
4676 case DISPLAY_SETTINGS_PAGE:
4677 Page = DisplaySettingsPage(&Ir);
4678 break;
4679
4680 case KEYBOARD_SETTINGS_PAGE:
4681 Page = KeyboardSettingsPage(&Ir);
4682 break;
4683
4684 case LAYOUT_SETTINGS_PAGE:
4685 Page = LayoutSettingsPage(&Ir);
4686 break;
4687
4688 case SELECT_PARTITION_PAGE:
4689 Page = SelectPartitionPage(&Ir);
4690 break;
4691
4692 case CREATE_PRIMARY_PARTITION_PAGE:
4693 Page = CreatePrimaryPartitionPage(&Ir);
4694 break;
4695
4696 case CREATE_EXTENDED_PARTITION_PAGE:
4697 Page = CreateExtendedPartitionPage(&Ir);
4698 break;
4699
4700 case CREATE_LOGICAL_PARTITION_PAGE:
4701 Page = CreateLogicalPartitionPage(&Ir);
4702 break;
4703
4704 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE:
4705 Page = ConfirmDeleteSystemPartitionPage(&Ir);
4706 break;
4707
4708 case DELETE_PARTITION_PAGE:
4709 Page = DeletePartitionPage(&Ir);
4710 break;
4711
4712 case SELECT_FILE_SYSTEM_PAGE:
4713 Page = SelectFileSystemPage(&Ir);
4714 break;
4715
4716 case FORMAT_PARTITION_PAGE:
4717 Page = (PAGE_NUMBER) FormatPartitionPage(&Ir);
4718 break;
4719
4720 case CHECK_FILE_SYSTEM_PAGE:
4721 Page = (PAGE_NUMBER) CheckFileSystemPage(&Ir);
4722 break;
4723
4724 case INSTALL_DIRECTORY_PAGE:
4725 Page = InstallDirectoryPage(&Ir);
4726 break;
4727
4728 case PREPARE_COPY_PAGE:
4729 Page = PrepareCopyPage(&Ir);
4730 break;
4731
4732 case FILE_COPY_PAGE:
4733 Page = FileCopyPage(&Ir);
4734 break;
4735
4736 case REGISTRY_PAGE:
4737 Page = RegistryPage(&Ir);
4738 break;
4739
4740 case BOOT_LOADER_PAGE:
4741 Page = BootLoaderPage(&Ir);
4742 break;
4743
4744 case BOOT_LOADER_FLOPPY_PAGE:
4745 Page = BootLoaderFloppyPage(&Ir);
4746 break;
4747
4748 case BOOT_LOADER_HARDDISK_MBR_PAGE:
4749 Page = BootLoaderHarddiskMbrPage(&Ir);
4750 break;
4751
4752 case BOOT_LOADER_HARDDISK_VBR_PAGE:
4753 Page = BootLoaderHarddiskVbrPage(&Ir);
4754 break;
4755
4756 /* Repair pages */
4757 case REPAIR_INTRO_PAGE:
4758 Page = RepairIntroPage(&Ir);
4759 break;
4760
4761 case SUCCESS_PAGE:
4762 Page = SuccessPage(&Ir);
4763 break;
4764
4765 case FLUSH_PAGE:
4766 Page = FlushPage(&Ir);
4767 break;
4768
4769 case QUIT_PAGE:
4770 Page = QuitPage(&Ir);
4771 break;
4772
4773 case RECOVERY_PAGE:
4774 case REBOOT_PAGE:
4775 break;
4776 }
4777 }
4778
4779 if (Page == RECOVERY_PAGE)
4780 RecoveryConsole();
4781
4782 FreeConsole();
4783
4784 /* Avoid bugcheck */
4785 Time.QuadPart += 50000000;
4786 NtDelayExecution(FALSE, &Time);
4787
4788 /* Reboot */
4789 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
4790 NtShutdownSystem(ShutdownReboot);
4791 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
4792 NtTerminateProcess(NtCurrentProcess(), 0);
4793 }
4794
4795
4796 #ifdef __REACTOS__
4797
4798 VOID NTAPI
4799 NtProcessStartup(PPEB Peb)
4800 {
4801 RtlNormalizeProcessParams(Peb->ProcessParameters);
4802
4803 ProcessHeap = Peb->ProcessHeap;
4804 InfSetHeap(ProcessHeap);
4805 RunUSetup();
4806 }
4807 #endif /* __REACTOS__ */
4808
4809 /* EOF */