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