b702815caea037b763b4b060f5c47ad66da9ba41
[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(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 PWCHAR NewLanguageId;
644 BOOL RefreshPage = FALSE;
645
646 /* Initialize the computer settings list */
647 if (LanguageList == NULL)
648 {
649 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
650
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 DrawGenericList(LanguageList,
672 2,
673 18,
674 xScreen - 3,
675 yScreen - 3);
676
677 ScrollToPositionGenericList(LanguageList, GetDefaultLanguageIndex());
678
679 MUIDisplayPage(LANGUAGE_PAGE);
680
681 while (TRUE)
682 {
683 CONSOLE_ConInKey(Ir);
684
685 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
686 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
687 {
688 ScrollDownGenericList(LanguageList);
689 RefreshPage = TRUE;
690 }
691 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
692 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
693 {
694 ScrollUpGenericList(LanguageList);
695 RefreshPage = TRUE;
696 }
697 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
698 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
699 {
700 ScrollPageDownGenericList(LanguageList);
701 RefreshPage = TRUE;
702 }
703 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
704 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
705 {
706 ScrollPageUpGenericList(LanguageList);
707 RefreshPage = TRUE;
708 }
709 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
710 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
711 {
712 if (ConfirmQuit(Ir) != FALSE)
713 return QUIT_PAGE;
714 else
715 RedrawGenericList(LanguageList);
716 }
717 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
718 {
719 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
720
721 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
722
723 if (wcscmp(SelectedLanguageId, DefaultLanguage))
724 {
725 UpdateKBLayout();
726 }
727
728 /* Load the font */
729 SetConsoleCodePage();
730
731 return INTRO_PAGE;
732 }
733 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
734 {
735 /* a-z */
736 GenericListKeyPress(LanguageList, Ir->Event.KeyEvent.uChar.AsciiChar);
737 RefreshPage = TRUE;
738 }
739
740 if (RefreshPage)
741 {
742 NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
743
744 if (SelectedLanguageId != NewLanguageId)
745 {
746 /* Clear the language page */
747 MUIClearPage(LANGUAGE_PAGE);
748
749 SelectedLanguageId = NewLanguageId;
750
751 /* Load the font */
752 SetConsoleCodePage();
753
754 /* Redraw language selection page in native language */
755 MUIDisplayPage(LANGUAGE_PAGE);
756 }
757
758 RefreshPage = FALSE;
759 }
760 }
761
762 return INTRO_PAGE;
763 }
764
765
766 /*
767 * Start page
768 *
769 * Next pages:
770 * LanguagePage (at once, default)
771 * InstallIntroPage (at once, if unattended)
772 * QuitPage
773 *
774 * SIDEEFFECTS
775 * Init Sdi
776 * Init SourcePath
777 * Init SourceRootPath
778 * Init SourceRootDir
779 * Init SetupInf
780 * Init RequiredPartitionDiskSpace
781 * Init IsUnattendedSetup
782 * If unattended, init *List and sets the Codepage
783 * If unattended, init SelectedLanguageId
784 * If unattended, init LanguageId
785 *
786 * RETURNS
787 * Number of the next page.
788 */
789 static PAGE_NUMBER
790 SetupStartPage(PINPUT_RECORD Ir)
791 {
792 //SYSTEM_DEVICE_INFORMATION Sdi;
793 NTSTATUS Status;
794 WCHAR FileNameBuffer[MAX_PATH];
795 INFCONTEXT Context;
796 PWCHAR Value;
797 UINT ErrorLine;
798 //ULONG ReturnSize;
799 PGENERIC_LIST_ENTRY ListEntry;
800 INT IntValue;
801
802 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
803
804 #if 0
805 /* Check whether a harddisk is available */
806 Status = NtQuerySystemInformation(SystemDeviceInformation,
807 &Sdi,
808 sizeof(SYSTEM_DEVICE_INFORMATION),
809 &ReturnSize);
810
811 if (!NT_SUCCESS(Status))
812 {
813 CONSOLE_PrintTextXY(6, 15, "NtQuerySystemInformation() failed (Status 0x%08lx)", Status);
814 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
815 return QUIT_PAGE;
816 }
817
818 if (Sdi.NumberOfDisks == 0)
819 {
820 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
821 return QUIT_PAGE;
822 }
823 #endif
824
825 /* Get the source path and source root path */
826 Status = GetSourcePaths(&SourcePath,
827 &SourceRootPath,
828 &SourceRootDir);
829
830 if (!NT_SUCCESS(Status))
831 {
832 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
833 MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
834 return QUIT_PAGE;
835 }
836 #if 0
837 else
838 {
839 CONSOLE_PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
840 CONSOLE_PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
841 CONSOLE_PrintTextXY(6, 17, "SourceRootDir: '%wZ'", &SourceRootDir);
842 }
843 #endif
844
845 /* Load txtsetup.sif from install media. */
846 wcscpy(FileNameBuffer, SourcePath.Buffer);
847 wcscat(FileNameBuffer, L"\\txtsetup.sif");
848
849 SetupInf = SetupOpenInfFileW(FileNameBuffer,
850 NULL,
851 INF_STYLE_WIN4,
852 LanguageId,
853 &ErrorLine);
854
855 if (SetupInf == INVALID_HANDLE_VALUE)
856 {
857 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
858 return QUIT_PAGE;
859 }
860
861 /* Open 'Version' section */
862 if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
863 {
864 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
865 return QUIT_PAGE;
866 }
867
868 /* Get pointer 'Signature' key */
869 if (!INF_GetData(&Context, NULL, &Value))
870 {
871 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
872 return QUIT_PAGE;
873 }
874
875 /* Check 'Signature' string */
876 if (_wcsicmp(Value, L"$ReactOS$") != 0)
877 {
878 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
879 return QUIT_PAGE;
880 }
881
882 /* Open 'DiskSpaceRequirements' section */
883 if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
884 {
885 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
886 return QUIT_PAGE;
887 }
888
889 /* Get the 'FreeSysPartDiskSpace' value */
890 if (!SetupGetIntField(&Context, 1, &IntValue))
891 {
892 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
893 return QUIT_PAGE;
894 }
895
896 RequiredPartitionDiskSpace = (ULONG)IntValue;
897
898 /* Start PnP thread */
899 if (hPnpThread != INVALID_HANDLE_VALUE)
900 {
901 NtResumeThread(hPnpThread, NULL);
902 hPnpThread = INVALID_HANDLE_VALUE;
903 }
904
905 CheckUnattendedSetup();
906
907 if (IsUnattendedSetup)
908 {
909 //TODO
910 //read options from inf
911 ComputerList = CreateComputerTypeList(SetupInf);
912 DisplayList = CreateDisplayDriverList(SetupInf);
913 KeyboardList = CreateKeyboardDriverList(SetupInf);
914 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
915 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
916
917 /* new part */
918 wcscpy(SelectedLanguageId,LocaleID);
919 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
920
921 /* first we hack LanguageList */
922 ListEntry = GetFirstListEntry(LanguageList);
923
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
939 while (ListEntry != NULL)
940 {
941 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
942 {
943 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
944 SetCurrentListEntry(LayoutList, ListEntry);
945 break;
946 }
947
948 ListEntry = GetNextListEntry(ListEntry);
949 }
950
951 SetConsoleCodePage();
952
953 return INSTALL_INTRO_PAGE;
954 }
955
956 return LANGUAGE_PAGE;
957 }
958
959
960 /*
961 * Displays the IntroPage.
962 *
963 * Next pages:
964 * InstallIntroPage (default)
965 * RepairIntroPage
966 * LicensePage
967 * QuitPage
968 *
969 * RETURNS
970 * Number of the next page.
971 */
972 static PAGE_NUMBER
973 IntroPage(PINPUT_RECORD Ir)
974 {
975 MUIDisplayPage(START_PAGE);
976
977 while (TRUE)
978 {
979 CONSOLE_ConInKey(Ir);
980
981 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
982 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
983 {
984 if (ConfirmQuit(Ir) != FALSE)
985 return QUIT_PAGE;
986
987 break;
988 }
989 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
990 {
991 return INSTALL_INTRO_PAGE;
992 }
993 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
994 {
995 return REPAIR_INTRO_PAGE;
996 }
997 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* R */
998 {
999 return LICENSE_PAGE;
1000 }
1001 }
1002
1003 return INTRO_PAGE;
1004 }
1005
1006
1007 /*
1008 * Displays the License page.
1009 *
1010 * Next page:
1011 * IntroPage (default)
1012 *
1013 * RETURNS
1014 * Number of the next page.
1015 */
1016 static PAGE_NUMBER
1017 LicensePage(PINPUT_RECORD Ir)
1018 {
1019 MUIDisplayPage(LICENSE_PAGE);
1020
1021 while (TRUE)
1022 {
1023 CONSOLE_ConInKey(Ir);
1024
1025 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1026 {
1027 return INTRO_PAGE;
1028 }
1029 }
1030
1031 return LICENSE_PAGE;
1032 }
1033
1034
1035 /*
1036 * Displays the RepairIntroPage.
1037 *
1038 * Next pages:
1039 * RebootPage (default)
1040 * InstallIntroPage
1041 * RecoveryPage
1042 * IntroPage
1043 *
1044 * RETURNS
1045 * Number of the next page.
1046 */
1047 static PAGE_NUMBER
1048 RepairIntroPage(PINPUT_RECORD Ir)
1049 {
1050 MUIDisplayPage(REPAIR_INTRO_PAGE);
1051
1052 while(TRUE)
1053 {
1054 CONSOLE_ConInKey(Ir);
1055
1056 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1057 {
1058 return REBOOT_PAGE;
1059 }
1060 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
1061 {
1062 RepairUpdateFlag = TRUE;
1063 return INSTALL_INTRO_PAGE;
1064 }
1065 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
1066 {
1067 return RECOVERY_PAGE;
1068 }
1069 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1070 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1071 {
1072 return INTRO_PAGE;
1073 }
1074 }
1075
1076 return REPAIR_INTRO_PAGE;
1077 }
1078
1079 /*
1080 * Displays the InstallIntroPage.
1081 *
1082 * Next pages:
1083 * DeviceSettingsPage (At once if repair or update is selected)
1084 * SelectPartitionPage (At once if unattended setup)
1085 * DeviceSettingsPage (default)
1086 * QuitPage
1087 *
1088 * RETURNS
1089 * Number of the next page.
1090 */
1091 static PAGE_NUMBER
1092 InstallIntroPage(PINPUT_RECORD Ir)
1093 {
1094 MUIDisplayPage(INSTALL_INTRO_PAGE);
1095
1096 if (RepairUpdateFlag)
1097 {
1098 //return SELECT_PARTITION_PAGE;
1099 return DEVICE_SETTINGS_PAGE;
1100 }
1101
1102 if (IsUnattendedSetup)
1103 {
1104 return SELECT_PARTITION_PAGE;
1105 }
1106
1107 while (TRUE)
1108 {
1109 CONSOLE_ConInKey(Ir);
1110
1111 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1112 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1113 {
1114 if (ConfirmQuit(Ir) != FALSE)
1115 return QUIT_PAGE;
1116
1117 break;
1118 }
1119 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1120 {
1121 return DEVICE_SETTINGS_PAGE;
1122 // return SCSI_CONTROLLER_PAGE;
1123 }
1124 }
1125
1126 return INSTALL_INTRO_PAGE;
1127 }
1128
1129
1130 #if 0
1131 static PAGE_NUMBER
1132 ScsiControllerPage(PINPUT_RECORD Ir)
1133 {
1134 SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1135
1136 /* FIXME: print loaded mass storage driver descriptions */
1137 #if 0
1138 SetTextXY(8, 10, "TEST device");
1139 #endif
1140
1141
1142 SetStatusText(" ENTER = Continue F3 = Quit");
1143
1144 while (TRUE)
1145 {
1146 ConInKey(Ir);
1147
1148 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1149 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1150 {
1151 if (ConfirmQuit(Ir) != FALSE)
1152 return QUIT_PAGE;
1153
1154 break;
1155 }
1156 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1157 {
1158 return DEVICE_SETTINGS_PAGE;
1159 }
1160 }
1161
1162 return SCSI_CONTROLLER_PAGE;
1163 }
1164 #endif
1165
1166
1167 /*
1168 * Displays the DeviceSettingsPage.
1169 *
1170 * Next pages:
1171 * SelectPartitionPage (At once if repair or update is selected)
1172 * ComputerSettingsPage
1173 * DisplaySettingsPage
1174 * KeyboardSettingsPage
1175 * LayoutsettingsPage
1176 * SelectPartitionPage
1177 * QuitPage
1178 *
1179 * SIDEEFFECTS
1180 * Init ComputerList
1181 * Init DisplayList
1182 * Init KeyboardList
1183 * Init LayoutList
1184 *
1185 * RETURNS
1186 * Number of the next page.
1187 */
1188 static PAGE_NUMBER
1189 DeviceSettingsPage(PINPUT_RECORD Ir)
1190 {
1191 static ULONG Line = 16;
1192 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1193
1194 /* Initialize the computer settings list */
1195 if (ComputerList == NULL)
1196 {
1197 ComputerList = CreateComputerTypeList(SetupInf);
1198 if (ComputerList == NULL)
1199 {
1200 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1201 return QUIT_PAGE;
1202 }
1203 }
1204
1205 /* Initialize the display settings list */
1206 if (DisplayList == NULL)
1207 {
1208 DisplayList = CreateDisplayDriverList(SetupInf);
1209 if (DisplayList == NULL)
1210 {
1211 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1212 return QUIT_PAGE;
1213 }
1214 }
1215
1216 /* Initialize the keyboard settings list */
1217 if (KeyboardList == NULL)
1218 {
1219 KeyboardList = CreateKeyboardDriverList(SetupInf);
1220 if (KeyboardList == NULL)
1221 {
1222 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1223 return QUIT_PAGE;
1224 }
1225 }
1226
1227 /* Initialize the keyboard layout list */
1228 if (LayoutList == NULL)
1229 {
1230 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
1231 if (LayoutList == NULL)
1232 {
1233 /* FIXME: report error */
1234 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1235 return QUIT_PAGE;
1236 }
1237 }
1238
1239 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1240
1241
1242 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry((ComputerList))));
1243 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry((DisplayList))));
1244 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry((KeyboardList))));
1245 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry((LayoutList))));
1246
1247 CONSOLE_InvertTextXY(24, Line, 48, 1);
1248
1249 if (RepairUpdateFlag)
1250 {
1251 return SELECT_PARTITION_PAGE;
1252 }
1253
1254 while (TRUE)
1255 {
1256 CONSOLE_ConInKey(Ir);
1257
1258 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1259 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1260 {
1261 CONSOLE_NormalTextXY(24, Line, 48, 1);
1262
1263 if (Line == 14)
1264 Line = 16;
1265 else if (Line == 16)
1266 Line = 11;
1267 else
1268 Line++;
1269
1270 CONSOLE_InvertTextXY(24, Line, 48, 1);
1271 }
1272 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1273 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1274 {
1275 CONSOLE_NormalTextXY(24, Line, 48, 1);
1276
1277 if (Line == 11)
1278 Line = 16;
1279 else if (Line == 16)
1280 Line = 14;
1281 else
1282 Line--;
1283
1284 CONSOLE_InvertTextXY(24, Line, 48, 1);
1285 }
1286 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1287 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1288 {
1289 if (ConfirmQuit(Ir) != FALSE)
1290 return QUIT_PAGE;
1291
1292 break;
1293 }
1294 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1295 {
1296 if (Line == 11)
1297 return COMPUTER_SETTINGS_PAGE;
1298 else if (Line == 12)
1299 return DISPLAY_SETTINGS_PAGE;
1300 else if (Line == 13)
1301 return KEYBOARD_SETTINGS_PAGE;
1302 else if (Line == 14)
1303 return LAYOUT_SETTINGS_PAGE;
1304 else if (Line == 16)
1305 return SELECT_PARTITION_PAGE;
1306 }
1307 }
1308
1309 return DEVICE_SETTINGS_PAGE;
1310 }
1311
1312
1313 /*
1314 * Handles generic selection lists.
1315 *
1316 * PARAMS
1317 * GenericList: The list to handle.
1318 * nextPage: The page it needs to jump to after this page.
1319 * Ir: The PINPUT_RECORD
1320 */
1321 static PAGE_NUMBER
1322 HandleGenericList(PGENERIC_LIST GenericList,
1323 PAGE_NUMBER nextPage,
1324 PINPUT_RECORD Ir)
1325 {
1326 while (TRUE)
1327 {
1328 CONSOLE_ConInKey(Ir);
1329
1330 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1331 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1332 {
1333 ScrollDownGenericList(GenericList);
1334 }
1335 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1336 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1337 {
1338 ScrollUpGenericList(GenericList);
1339 }
1340 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1341 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1342 {
1343 ScrollPageDownGenericList(GenericList);
1344 }
1345 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1346 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1347 {
1348 ScrollPageUpGenericList(GenericList);
1349 }
1350 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1351 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1352 {
1353 if (ConfirmQuit(Ir) != FALSE)
1354 return QUIT_PAGE;
1355
1356 continue;
1357 }
1358 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1359 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1360 {
1361 RestoreGenericListState(GenericList);
1362 return nextPage;
1363 }
1364 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1365 {
1366 return nextPage;
1367 }
1368 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1369 {
1370 /* a-z */
1371 GenericListKeyPress(GenericList, Ir->Event.KeyEvent.uChar.AsciiChar);
1372 }
1373 }
1374 }
1375
1376
1377 /*
1378 * Displays the ComputerSettingsPage.
1379 *
1380 * Next pages:
1381 * DeviceSettingsPage
1382 * QuitPage
1383 *
1384 * RETURNS
1385 * Number of the next page.
1386 */
1387 static PAGE_NUMBER
1388 ComputerSettingsPage(PINPUT_RECORD Ir)
1389 {
1390 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1391
1392 DrawGenericList(ComputerList,
1393 2,
1394 18,
1395 xScreen - 3,
1396 yScreen - 3);
1397
1398 SaveGenericListState(ComputerList);
1399
1400 return HandleGenericList(ComputerList, DEVICE_SETTINGS_PAGE, Ir);
1401 }
1402
1403
1404 /*
1405 * Displays the DisplaySettingsPage.
1406 *
1407 * Next pages:
1408 * DeviceSettingsPage
1409 * QuitPage
1410 *
1411 * RETURNS
1412 * Number of the next page.
1413 */
1414 static PAGE_NUMBER
1415 DisplaySettingsPage(PINPUT_RECORD Ir)
1416 {
1417 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1418
1419 DrawGenericList(DisplayList,
1420 2,
1421 18,
1422 xScreen - 3,
1423 yScreen - 3);
1424
1425 SaveGenericListState(DisplayList);
1426
1427 return HandleGenericList(DisplayList, DEVICE_SETTINGS_PAGE, Ir);
1428 }
1429
1430
1431 /*
1432 * Displays the KeyboardSettingsPage.
1433 *
1434 * Next pages:
1435 * DeviceSettingsPage
1436 * QuitPage
1437 *
1438 * RETURNS
1439 * Number of the next page.
1440 */
1441 static PAGE_NUMBER
1442 KeyboardSettingsPage(PINPUT_RECORD Ir)
1443 {
1444 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1445
1446 DrawGenericList(KeyboardList,
1447 2,
1448 18,
1449 xScreen - 3,
1450 yScreen - 3);
1451
1452 SaveGenericListState(KeyboardList);
1453
1454 return HandleGenericList(KeyboardList, DEVICE_SETTINGS_PAGE, Ir);
1455 }
1456
1457
1458 /*
1459 * Displays the LayoutSettingsPage.
1460 *
1461 * Next pages:
1462 * DeviceSettingsPage
1463 * QuitPage
1464 *
1465 * RETURNS
1466 * Number of the next page.
1467 */
1468 static PAGE_NUMBER
1469 LayoutSettingsPage(PINPUT_RECORD Ir)
1470 {
1471 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1472
1473 DrawGenericList(LayoutList,
1474 2,
1475 18,
1476 xScreen - 3,
1477 yScreen - 3);
1478
1479 SaveGenericListState(LayoutList);
1480
1481 return HandleGenericList(LayoutList, DEVICE_SETTINGS_PAGE, Ir);
1482 }
1483
1484
1485 static BOOL
1486 IsDiskSizeValid(PPARTENTRY PartEntry)
1487 {
1488 ULONGLONG size;
1489
1490 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1491 size = (size + 524288) / 1048576; /* in MBytes */
1492
1493 if (size < RequiredPartitionDiskSpace)
1494 {
1495 /* partition is too small so ask for another partition */
1496 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, RequiredPartitionDiskSpace);
1497 return FALSE;
1498 }
1499 else
1500 {
1501 return TRUE;
1502 }
1503 }
1504
1505
1506 /*
1507 * Displays the SelectPartitionPage.
1508 *
1509 * Next pages:
1510 * SelectFileSystemPage (At once if unattended)
1511 * SelectFileSystemPage (Default if free space is selected)
1512 * CreatePrimaryPartitionPage
1513 * CreateExtendedPartitionPage
1514 * CreateLogicalPartitionPage
1515 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1516 * DeletePartitionPage
1517 * QuitPage
1518 *
1519 * SIDEEFFECTS
1520 * Init DestinationDriveLetter (only if unattended or not free space is selected)
1521 * Set InstallShortcut (only if not unattended + free space is selected)
1522 *
1523 * RETURNS
1524 * Number of the next page.
1525 */
1526 static PAGE_NUMBER
1527 SelectPartitionPage(PINPUT_RECORD Ir)
1528 {
1529 ULONG Error;
1530
1531 MUIDisplayPage(SELECT_PARTITION_PAGE);
1532
1533 if (PartitionList == NULL)
1534 {
1535 PartitionList = CreatePartitionList(2,
1536 23,
1537 xScreen - 3,
1538 yScreen - 3);
1539 if (PartitionList == NULL)
1540 {
1541 /* FIXME: show an error dialog */
1542 return QUIT_PAGE;
1543 }
1544 else if (IsListEmpty(&PartitionList->DiskListHead))
1545 {
1546 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1547 return QUIT_PAGE;
1548 }
1549 }
1550
1551 DrawPartitionList(PartitionList);
1552
1553 if (IsUnattendedSetup)
1554 {
1555 if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
1556 {
1557 if (AutoPartition)
1558 {
1559 if (PartitionList->CurrentPartition->LogicalPartition)
1560 {
1561 CreateLogicalPartition(PartitionList,
1562 PartitionList->CurrentPartition->SectorCount.QuadPart,
1563 TRUE);
1564 }
1565 else
1566 {
1567 CreatePrimaryPartition(PartitionList,
1568 PartitionList->CurrentPartition->SectorCount.QuadPart,
1569 TRUE);
1570 }
1571
1572 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1573 {
1574 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1575 RequiredPartitionDiskSpace);
1576 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1577 }
1578
1579 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1580
1581 return SELECT_FILE_SYSTEM_PAGE;
1582 }
1583 }
1584 else
1585 {
1586 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1587 {
1588 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1589 RequiredPartitionDiskSpace);
1590 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1591 }
1592
1593 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1594
1595 return SELECT_FILE_SYSTEM_PAGE;
1596 }
1597 }
1598
1599 while (TRUE)
1600 {
1601 /* Update status text */
1602 if (PartitionList->CurrentPartition == NULL)
1603 {
1604 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1605 }
1606 else if (PartitionList->CurrentPartition->LogicalPartition)
1607 {
1608 if (PartitionList->CurrentPartition->IsPartitioned)
1609 {
1610 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1611 }
1612 else
1613 {
1614 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1615 }
1616 }
1617 else
1618 {
1619 if (PartitionList->CurrentPartition->IsPartitioned)
1620 {
1621 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1622 {
1623 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1624 }
1625 else
1626 {
1627 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1628 }
1629 }
1630 else
1631 {
1632 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1633 }
1634 }
1635
1636 CONSOLE_ConInKey(Ir);
1637
1638 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1639 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1640 {
1641 if (ConfirmQuit(Ir) != FALSE)
1642 {
1643 DestroyPartitionList(PartitionList);
1644 PartitionList = NULL;
1645 return QUIT_PAGE;
1646 }
1647
1648 break;
1649 }
1650 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1651 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1652 {
1653 if (ScrollDownPartitionList(PartitionList))
1654 DrawPartitionList(PartitionList);
1655 }
1656 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1657 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1658 {
1659 if (ScrollUpPartitionList(PartitionList))
1660 DrawPartitionList(PartitionList);
1661 }
1662 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1663 {
1664 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1665 continue; //return SELECT_PARTITION_PAGE;
1666
1667 if (PartitionList->CurrentPartition == NULL ||
1668 PartitionList->CurrentPartition->IsPartitioned == FALSE)
1669 {
1670 if (PartitionList->CurrentPartition->LogicalPartition)
1671 {
1672 CreateLogicalPartition(PartitionList,
1673 0ULL,
1674 TRUE);
1675 }
1676 else
1677 {
1678 CreatePrimaryPartition(PartitionList,
1679 0ULL,
1680 TRUE);
1681 }
1682 }
1683
1684 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1685 {
1686 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1687 RequiredPartitionDiskSpace);
1688 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1689 }
1690
1691 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1692
1693 return SELECT_FILE_SYSTEM_PAGE;
1694 }
1695 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1696 {
1697 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1698 {
1699 Error = PrimaryPartitionCreationChecks(PartitionList);
1700 if (Error != NOT_AN_ERROR)
1701 {
1702 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1703 return SELECT_PARTITION_PAGE;
1704 }
1705
1706 return CREATE_PRIMARY_PARTITION_PAGE;
1707 }
1708 }
1709 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1710 {
1711 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1712 {
1713 Error = ExtendedPartitionCreationChecks(PartitionList);
1714 if (Error != NOT_AN_ERROR)
1715 {
1716 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1717 return SELECT_PARTITION_PAGE;
1718 }
1719
1720 return CREATE_EXTENDED_PARTITION_PAGE;
1721 }
1722 }
1723 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1724 {
1725 if (PartitionList->CurrentPartition->LogicalPartition != FALSE)
1726 {
1727 Error = LogicalPartitionCreationChecks(PartitionList);
1728 if (Error != NOT_AN_ERROR)
1729 {
1730 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1731 return SELECT_PARTITION_PAGE;
1732 }
1733
1734 return CREATE_LOGICAL_PARTITION_PAGE;
1735 }
1736 }
1737 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1738 {
1739 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1740 {
1741 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1742 return SELECT_PARTITION_PAGE;
1743 }
1744
1745 if (PartitionList->CurrentPartition->BootIndicator ||
1746 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1747 {
1748 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1749 }
1750
1751 return DELETE_PARTITION_PAGE;
1752 }
1753 }
1754
1755 return SELECT_PARTITION_PAGE;
1756 }
1757
1758
1759 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1760 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1761 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1762
1763 static VOID
1764 ShowPartitionSizeInputBox(SHORT Left,
1765 SHORT Top,
1766 SHORT Right,
1767 SHORT Bottom,
1768 ULONG MaxSize,
1769 PCHAR InputBuffer,
1770 PBOOLEAN Quit,
1771 PBOOLEAN Cancel)
1772 {
1773 INPUT_RECORD Ir;
1774 COORD coPos;
1775 DWORD Written;
1776 CHAR Buffer[128];
1777 WCHAR PartitionSizeBuffer[100];
1778 ULONG Length, Pos;
1779 WCHAR ch;
1780 SHORT iLeft;
1781 SHORT iTop;
1782
1783 if (Quit != NULL)
1784 *Quit = FALSE;
1785
1786 if (Cancel != NULL)
1787 *Cancel = FALSE;
1788
1789 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1790
1791 /* Print message */
1792 coPos.X = Left + 2;
1793 coPos.Y = Top + 2;
1794 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1795 iLeft = coPos.X + strlen(Buffer) + 1;
1796 iTop = coPos.Y;
1797
1798 WriteConsoleOutputCharacterA(StdOutput,
1799 Buffer,
1800 strlen(Buffer),
1801 coPos,
1802 &Written);
1803
1804 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1805 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1806 coPos.Y = iTop;
1807 WriteConsoleOutputCharacterA(StdOutput,
1808 Buffer,
1809 strlen(Buffer),
1810 coPos,
1811 &Written);
1812
1813 swprintf(PartitionSizeBuffer, L"%lu", MaxSize);
1814 Length = wcslen(PartitionSizeBuffer);
1815 Pos = Length;
1816 CONSOLE_SetInputTextXY(iLeft,
1817 iTop,
1818 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1819 PartitionSizeBuffer);
1820 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1821 CONSOLE_SetCursorType(TRUE, TRUE);
1822
1823 while (TRUE)
1824 {
1825 CONSOLE_ConInKey(&Ir);
1826
1827 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1828 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1829 {
1830 if (Quit != NULL)
1831 *Quit = TRUE;
1832
1833 PartitionSizeBuffer[0] = UNICODE_NULL;
1834 CONSOLE_SetCursorType(TRUE, FALSE);
1835 break;
1836 }
1837 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1838 {
1839 CONSOLE_SetCursorType(TRUE, FALSE);
1840 break;
1841 }
1842 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1843 {
1844 if (Cancel != NULL)
1845 *Cancel = TRUE;
1846
1847 PartitionSizeBuffer[0] = UNICODE_NULL;
1848 CONSOLE_SetCursorType(TRUE, FALSE);
1849 break;
1850 }
1851 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1852 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1853 {
1854 Pos = 0;
1855 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1856 }
1857 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1858 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1859 {
1860 Pos = Length;
1861 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1862 }
1863 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1864 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1865 {
1866 if (Pos > 0)
1867 {
1868 Pos--;
1869 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1870 }
1871 }
1872 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1873 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1874 {
1875 if (Pos < Length)
1876 {
1877 Pos++;
1878 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1879 }
1880 }
1881 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1882 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1883 {
1884 if (Pos < Length)
1885 {
1886 memmove(&PartitionSizeBuffer[Pos],
1887 &PartitionSizeBuffer[Pos + 1],
1888 (Length - Pos - 1) * sizeof(WCHAR));
1889 PartitionSizeBuffer[Length - 1] = UNICODE_NULL;
1890
1891 Length--;
1892 CONSOLE_SetInputTextXY(iLeft,
1893 iTop,
1894 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1895 PartitionSizeBuffer);
1896 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1897 }
1898 }
1899 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1900 {
1901 if (Pos > 0)
1902 {
1903 if (Pos < Length)
1904 memmove(&PartitionSizeBuffer[Pos - 1],
1905 &PartitionSizeBuffer[Pos],
1906 (Length - Pos) * sizeof(WCHAR));
1907 PartitionSizeBuffer[Length - 1] = UNICODE_NULL;
1908
1909 Pos--;
1910 Length--;
1911 CONSOLE_SetInputTextXY(iLeft,
1912 iTop,
1913 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1914 PartitionSizeBuffer);
1915 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1916 }
1917 }
1918 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1919 {
1920 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1921 {
1922 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1923
1924 if ((ch >= L'0') && (ch <= L'9'))
1925 {
1926 if (Pos < Length)
1927 memmove(&PartitionSizeBuffer[Pos + 1],
1928 &PartitionSizeBuffer[Pos],
1929 (Length - Pos) * sizeof(WCHAR));
1930 PartitionSizeBuffer[Length + 1] = UNICODE_NULL;
1931 PartitionSizeBuffer[Pos] = ch;
1932
1933 Pos++;
1934 Length++;
1935 CONSOLE_SetInputTextXY(iLeft,
1936 iTop,
1937 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1938 PartitionSizeBuffer);
1939 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1940 }
1941 }
1942 }
1943 }
1944
1945 /* Convert UNICODE --> ANSI the poor man's way */
1946 sprintf(InputBuffer, "%S", PartitionSizeBuffer);
1947 }
1948
1949
1950 /*
1951 * Displays the CreatePrimaryPartitionPage.
1952 *
1953 * Next pages:
1954 * SelectPartitionPage
1955 * SelectFileSystemPage (default)
1956 * QuitPage
1957 *
1958 * RETURNS
1959 * Number of the next page.
1960 */
1961 static PAGE_NUMBER
1962 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1963 {
1964 PDISKENTRY DiskEntry;
1965 PPARTENTRY PartEntry;
1966 BOOLEAN Quit;
1967 BOOLEAN Cancel;
1968 CHAR InputBuffer[50];
1969 ULONG MaxSize;
1970 ULONGLONG PartSize;
1971 ULONGLONG DiskSize;
1972 ULONGLONG SectorCount;
1973 PCHAR Unit;
1974
1975 if (PartitionList == NULL ||
1976 PartitionList->CurrentDisk == NULL ||
1977 PartitionList->CurrentPartition == NULL)
1978 {
1979 /* FIXME: show an error dialog */
1980 return QUIT_PAGE;
1981 }
1982
1983 DiskEntry = PartitionList->CurrentDisk;
1984 PartEntry = PartitionList->CurrentPartition;
1985
1986 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1987
1988 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1989
1990 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1991 #if 0
1992 if (DiskSize >= 10737418240) /* 10 GB */
1993 {
1994 DiskSize = DiskSize / 1073741824;
1995 Unit = MUIGetString(STRING_GB);
1996 }
1997 else
1998 #endif
1999 {
2000 DiskSize = DiskSize / 1048576;
2001 if (DiskSize == 0)
2002 DiskSize = 1;
2003
2004 Unit = MUIGetString(STRING_MB);
2005 }
2006
2007 if (DiskEntry->DriverName.Length > 0)
2008 {
2009 CONSOLE_PrintTextXY(6, 10,
2010 MUIGetString(STRING_HDINFOPARTCREATE),
2011 DiskSize,
2012 Unit,
2013 DiskEntry->DiskNumber,
2014 DiskEntry->Port,
2015 DiskEntry->Bus,
2016 DiskEntry->Id,
2017 &DiskEntry->DriverName);
2018 }
2019 else
2020 {
2021 CONSOLE_PrintTextXY(6, 10,
2022 MUIGetString(STRING_HDDINFOUNK1),
2023 DiskSize,
2024 Unit,
2025 DiskEntry->DiskNumber,
2026 DiskEntry->Port,
2027 DiskEntry->Bus,
2028 DiskEntry->Id);
2029 }
2030
2031 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2032
2033 #if 0
2034 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2035 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2036 #endif
2037
2038 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2039
2040 PartEntry = PartitionList->CurrentPartition;
2041 while (TRUE)
2042 {
2043 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2044
2045 if (MaxSize > PARTITION_MAXSIZE)
2046 MaxSize = PARTITION_MAXSIZE;
2047
2048 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2049 MaxSize, InputBuffer, &Quit, &Cancel);
2050
2051 if (Quit != FALSE)
2052 {
2053 if (ConfirmQuit(Ir) != FALSE)
2054 return QUIT_PAGE;
2055
2056 break;
2057 }
2058 else if (Cancel != FALSE)
2059 {
2060 return SELECT_PARTITION_PAGE;
2061 }
2062 else
2063 {
2064 PartSize = atoi(InputBuffer);
2065
2066 if (PartSize < 1)
2067 {
2068 /* Too small */
2069 continue;
2070 }
2071
2072 if (PartSize > MaxSize)
2073 {
2074 /* Too large */
2075 continue;
2076 }
2077
2078 /* Convert to bytes */
2079 if (PartSize == MaxSize)
2080 {
2081 /* Use all of the unpartitioned disk space */
2082 SectorCount = PartEntry->SectorCount.QuadPart;
2083 }
2084 else
2085 {
2086 /* Calculate the sector count from the size in MB */
2087 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2088
2089 /* But never get larger than the unpartitioned disk space */
2090 if (SectorCount > PartEntry->SectorCount.QuadPart)
2091 SectorCount = PartEntry->SectorCount.QuadPart;
2092 }
2093
2094 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2095
2096 CreatePrimaryPartition(PartitionList,
2097 SectorCount,
2098 FALSE);
2099
2100 return SELECT_PARTITION_PAGE;
2101 }
2102 }
2103
2104 return CREATE_PRIMARY_PARTITION_PAGE;
2105 }
2106
2107
2108 /*
2109 * Displays the CreateExtendedPartitionPage.
2110 *
2111 * Next pages:
2112 * SelectPartitionPage (default)
2113 * QuitPage
2114 *
2115 * RETURNS
2116 * Number of the next page.
2117 */
2118 static PAGE_NUMBER
2119 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2120 {
2121 PDISKENTRY DiskEntry;
2122 PPARTENTRY PartEntry;
2123 BOOLEAN Quit;
2124 BOOLEAN Cancel;
2125 CHAR InputBuffer[50];
2126 ULONG MaxSize;
2127 ULONGLONG PartSize;
2128 ULONGLONG DiskSize;
2129 ULONGLONG SectorCount;
2130 PCHAR Unit;
2131
2132 if (PartitionList == NULL ||
2133 PartitionList->CurrentDisk == NULL ||
2134 PartitionList->CurrentPartition == NULL)
2135 {
2136 /* FIXME: show an error dialog */
2137 return QUIT_PAGE;
2138 }
2139
2140 DiskEntry = PartitionList->CurrentDisk;
2141 PartEntry = PartitionList->CurrentPartition;
2142
2143 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2144
2145 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2146
2147 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2148 #if 0
2149 if (DiskSize >= 10737418240) /* 10 GB */
2150 {
2151 DiskSize = DiskSize / 1073741824;
2152 Unit = MUIGetString(STRING_GB);
2153 }
2154 else
2155 #endif
2156 {
2157 DiskSize = DiskSize / 1048576;
2158 if (DiskSize == 0)
2159 DiskSize = 1;
2160
2161 Unit = MUIGetString(STRING_MB);
2162 }
2163
2164 if (DiskEntry->DriverName.Length > 0)
2165 {
2166 CONSOLE_PrintTextXY(6, 10,
2167 MUIGetString(STRING_HDINFOPARTCREATE),
2168 DiskSize,
2169 Unit,
2170 DiskEntry->DiskNumber,
2171 DiskEntry->Port,
2172 DiskEntry->Bus,
2173 DiskEntry->Id,
2174 &DiskEntry->DriverName);
2175 }
2176 else
2177 {
2178 CONSOLE_PrintTextXY(6, 10,
2179 MUIGetString(STRING_HDDINFOUNK1),
2180 DiskSize,
2181 Unit,
2182 DiskEntry->DiskNumber,
2183 DiskEntry->Port,
2184 DiskEntry->Bus,
2185 DiskEntry->Id);
2186 }
2187
2188 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2189
2190 #if 0
2191 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2192 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2193 #endif
2194
2195 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2196
2197 PartEntry = PartitionList->CurrentPartition;
2198 while (TRUE)
2199 {
2200 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2201
2202 if (MaxSize > PARTITION_MAXSIZE)
2203 MaxSize = PARTITION_MAXSIZE;
2204
2205 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2206 MaxSize, InputBuffer, &Quit, &Cancel);
2207
2208 if (Quit != FALSE)
2209 {
2210 if (ConfirmQuit(Ir) != FALSE)
2211 return QUIT_PAGE;
2212
2213 break;
2214 }
2215 else if (Cancel != FALSE)
2216 {
2217 return SELECT_PARTITION_PAGE;
2218 }
2219 else
2220 {
2221 PartSize = atoi(InputBuffer);
2222
2223 if (PartSize < 1)
2224 {
2225 /* Too small */
2226 continue;
2227 }
2228
2229 if (PartSize > MaxSize)
2230 {
2231 /* Too large */
2232 continue;
2233 }
2234
2235 /* Convert to bytes */
2236 if (PartSize == MaxSize)
2237 {
2238 /* Use all of the unpartitioned disk space */
2239 SectorCount = PartEntry->SectorCount.QuadPart;
2240 }
2241 else
2242 {
2243 /* Calculate the sector count from the size in MB */
2244 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2245
2246 /* But never get larger than the unpartitioned disk space */
2247 if (SectorCount > PartEntry->SectorCount.QuadPart)
2248 SectorCount = PartEntry->SectorCount.QuadPart;
2249 }
2250
2251 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2252
2253 CreateExtendedPartition(PartitionList,
2254 SectorCount);
2255
2256 return SELECT_PARTITION_PAGE;
2257 }
2258 }
2259
2260 return CREATE_EXTENDED_PARTITION_PAGE;
2261 }
2262
2263
2264 /*
2265 * Displays the CreateLogicalPartitionPage.
2266 *
2267 * Next pages:
2268 * SelectFileSystemPage (default)
2269 * QuitPage
2270 *
2271 * RETURNS
2272 * Number of the next page.
2273 */
2274 static PAGE_NUMBER
2275 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2276 {
2277 PDISKENTRY DiskEntry;
2278 PPARTENTRY PartEntry;
2279 BOOLEAN Quit;
2280 BOOLEAN Cancel;
2281 CHAR InputBuffer[50];
2282 ULONG MaxSize;
2283 ULONGLONG PartSize;
2284 ULONGLONG DiskSize;
2285 ULONGLONG SectorCount;
2286 PCHAR Unit;
2287
2288 if (PartitionList == NULL ||
2289 PartitionList->CurrentDisk == NULL ||
2290 PartitionList->CurrentPartition == NULL)
2291 {
2292 /* FIXME: show an error dialog */
2293 return QUIT_PAGE;
2294 }
2295
2296 DiskEntry = PartitionList->CurrentDisk;
2297 PartEntry = PartitionList->CurrentPartition;
2298
2299 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2300
2301 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2302
2303 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2304 #if 0
2305 if (DiskSize >= 10737418240) /* 10 GB */
2306 {
2307 DiskSize = DiskSize / 1073741824;
2308 Unit = MUIGetString(STRING_GB);
2309 }
2310 else
2311 #endif
2312 {
2313 DiskSize = DiskSize / 1048576;
2314 if (DiskSize == 0)
2315 DiskSize = 1;
2316
2317 Unit = MUIGetString(STRING_MB);
2318 }
2319
2320 if (DiskEntry->DriverName.Length > 0)
2321 {
2322 CONSOLE_PrintTextXY(6, 10,
2323 MUIGetString(STRING_HDINFOPARTCREATE),
2324 DiskSize,
2325 Unit,
2326 DiskEntry->DiskNumber,
2327 DiskEntry->Port,
2328 DiskEntry->Bus,
2329 DiskEntry->Id,
2330 &DiskEntry->DriverName);
2331 }
2332 else
2333 {
2334 CONSOLE_PrintTextXY(6, 10,
2335 MUIGetString(STRING_HDDINFOUNK1),
2336 DiskSize,
2337 Unit,
2338 DiskEntry->DiskNumber,
2339 DiskEntry->Port,
2340 DiskEntry->Bus,
2341 DiskEntry->Id);
2342 }
2343
2344 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2345
2346 #if 0
2347 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2348 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2349 #endif
2350
2351 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2352
2353 PartEntry = PartitionList->CurrentPartition;
2354 while (TRUE)
2355 {
2356 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2357
2358 if (MaxSize > PARTITION_MAXSIZE)
2359 MaxSize = PARTITION_MAXSIZE;
2360
2361 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2362 MaxSize, InputBuffer, &Quit, &Cancel);
2363
2364 if (Quit != FALSE)
2365 {
2366 if (ConfirmQuit(Ir) != FALSE)
2367 return QUIT_PAGE;
2368
2369 break;
2370 }
2371 else if (Cancel != FALSE)
2372 {
2373 return SELECT_PARTITION_PAGE;
2374 }
2375 else
2376 {
2377 PartSize = atoi(InputBuffer);
2378
2379 if (PartSize < 1)
2380 {
2381 /* Too small */
2382 continue;
2383 }
2384
2385 if (PartSize > MaxSize)
2386 {
2387 /* Too large */
2388 continue;
2389 }
2390
2391 /* Convert to bytes */
2392 if (PartSize == MaxSize)
2393 {
2394 /* Use all of the unpartitioned disk space */
2395 SectorCount = PartEntry->SectorCount.QuadPart;
2396 }
2397 else
2398 {
2399 /* Calculate the sector count from the size in MB */
2400 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2401
2402 /* But never get larger than the unpartitioned disk space */
2403 if (SectorCount > PartEntry->SectorCount.QuadPart)
2404 SectorCount = PartEntry->SectorCount.QuadPart;
2405 }
2406
2407 DPRINT("Partition size: %I64u bytes\n", PartSize);
2408
2409 CreateLogicalPartition(PartitionList,
2410 SectorCount,
2411 FALSE);
2412
2413 return SELECT_PARTITION_PAGE;
2414 }
2415 }
2416
2417 return CREATE_LOGICAL_PARTITION_PAGE;
2418 }
2419
2420
2421 /*
2422 * Displays the ConfirmDeleteSystemPartitionPage.
2423 *
2424 * Next pages:
2425 * DeletePartitionPage (default)
2426 * SelectPartitionPage
2427 *
2428 * RETURNS
2429 * Number of the next page.
2430 */
2431 static PAGE_NUMBER
2432 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2433 {
2434 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2435
2436 while (TRUE)
2437 {
2438 CONSOLE_ConInKey(Ir);
2439
2440 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2441 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2442 {
2443 if (ConfirmQuit(Ir) == TRUE)
2444 return QUIT_PAGE;
2445
2446 break;
2447 }
2448 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2449 {
2450 return DELETE_PARTITION_PAGE;
2451 }
2452 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2453 {
2454 return SELECT_PARTITION_PAGE;
2455 }
2456 }
2457
2458 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2459 }
2460
2461
2462 /*
2463 * Displays the DeletePartitionPage.
2464 *
2465 * Next pages:
2466 * SelectPartitionPage (default)
2467 * QuitPage
2468 *
2469 * RETURNS
2470 * Number of the next page.
2471 */
2472 static PAGE_NUMBER
2473 DeletePartitionPage(PINPUT_RECORD Ir)
2474 {
2475 PDISKENTRY DiskEntry;
2476 PPARTENTRY PartEntry;
2477 ULONGLONG DiskSize;
2478 ULONGLONG PartSize;
2479 PCHAR Unit;
2480 CHAR PartTypeString[32];
2481
2482 if (PartitionList == NULL ||
2483 PartitionList->CurrentDisk == NULL ||
2484 PartitionList->CurrentPartition == NULL)
2485 {
2486 /* FIXME: show an error dialog */
2487 return QUIT_PAGE;
2488 }
2489
2490 DiskEntry = PartitionList->CurrentDisk;
2491 PartEntry = PartitionList->CurrentPartition;
2492
2493 MUIDisplayPage(DELETE_PARTITION_PAGE);
2494
2495 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2496 PartTypeString,
2497 ARRAYSIZE(PartTypeString));
2498
2499 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2500 #if 0
2501 if (PartSize >= 10737418240) /* 10 GB */
2502 {
2503 PartSize = PartSize / 1073741824;
2504 Unit = MUIGetString(STRING_GB);
2505 }
2506 else
2507 #endif
2508 if (PartSize >= 10485760) /* 10 MB */
2509 {
2510 PartSize = PartSize / 1048576;
2511 Unit = MUIGetString(STRING_MB);
2512 }
2513 else
2514 {
2515 PartSize = PartSize / 1024;
2516 Unit = MUIGetString(STRING_KB);
2517 }
2518
2519 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2520 {
2521 CONSOLE_PrintTextXY(6, 10,
2522 MUIGetString(STRING_HDDINFOUNK2),
2523 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2524 (PartEntry->DriveLetter == 0) ? '-' : ':',
2525 PartEntry->PartitionType,
2526 PartSize,
2527 Unit);
2528 }
2529 else
2530 {
2531 CONSOLE_PrintTextXY(6, 10,
2532 " %c%c %s %I64u %s",
2533 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2534 (PartEntry->DriveLetter == 0) ? '-' : ':',
2535 PartTypeString,
2536 PartSize,
2537 Unit);
2538 }
2539
2540 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2541 #if 0
2542 if (DiskSize >= 10737418240) /* 10 GB */
2543 {
2544 DiskSize = DiskSize / 1073741824;
2545 Unit = MUIGetString(STRING_GB);
2546 }
2547 else
2548 #endif
2549 {
2550 DiskSize = DiskSize / 1048576;
2551 if (DiskSize == 0)
2552 DiskSize = 1;
2553
2554 Unit = MUIGetString(STRING_MB);
2555 }
2556
2557 if (DiskEntry->DriverName.Length > 0)
2558 {
2559 CONSOLE_PrintTextXY(6, 12,
2560 MUIGetString(STRING_HDINFOPARTDELETE),
2561 DiskSize,
2562 Unit,
2563 DiskEntry->DiskNumber,
2564 DiskEntry->Port,
2565 DiskEntry->Bus,
2566 DiskEntry->Id,
2567 &DiskEntry->DriverName);
2568 }
2569 else
2570 {
2571 CONSOLE_PrintTextXY(6, 12,
2572 MUIGetString(STRING_HDDINFOUNK3),
2573 DiskSize,
2574 Unit,
2575 DiskEntry->DiskNumber,
2576 DiskEntry->Port,
2577 DiskEntry->Bus,
2578 DiskEntry->Id);
2579 }
2580
2581 while (TRUE)
2582 {
2583 CONSOLE_ConInKey(Ir);
2584
2585 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2586 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2587 {
2588 if (ConfirmQuit(Ir) != FALSE)
2589 return QUIT_PAGE;
2590
2591 break;
2592 }
2593 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2594 {
2595 return SELECT_PARTITION_PAGE;
2596 }
2597 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2598 {
2599 DeleteCurrentPartition(PartitionList);
2600
2601 return SELECT_PARTITION_PAGE;
2602 }
2603 }
2604
2605 return DELETE_PARTITION_PAGE;
2606 }
2607
2608
2609 /*
2610 * Displays the SelectFileSystemPage.
2611 *
2612 * Next pages:
2613 * CheckFileSystemPage (At once if RepairUpdate is selected)
2614 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2615 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2616 * SelectPartitionPage (If the user aborts)
2617 * FormatPartitionPage (Default)
2618 * QuitPage
2619 *
2620 * SIDEEFFECTS
2621 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2622 * Calls CheckActiveSystemPartition()
2623 *
2624 * RETURNS
2625 * Number of the next page.
2626 */
2627 static PAGE_NUMBER
2628 SelectFileSystemPage(PINPUT_RECORD Ir)
2629 {
2630 PDISKENTRY DiskEntry;
2631 PPARTENTRY PartEntry;
2632 ULONGLONG DiskSize;
2633 ULONGLONG PartSize;
2634 PCHAR DiskUnit;
2635 PCHAR PartUnit;
2636 CHAR PartTypeString[32];
2637 FORMATMACHINESTATE PreviousFormatState;
2638
2639 DPRINT("SelectFileSystemPage()\n");
2640
2641 if (PartitionList == NULL ||
2642 PartitionList->CurrentDisk == NULL ||
2643 PartitionList->CurrentPartition == NULL)
2644 {
2645 /* FIXME: show an error dialog */
2646 return QUIT_PAGE;
2647 }
2648
2649 /*** HACK! ***/
2650 if (FileSystemList == NULL)
2651 {
2652 FileSystemList = CreateFileSystemList(6, 26, PartitionList->CurrentPartition->New, L"FAT");
2653 if (FileSystemList == NULL)
2654 {
2655 /* FIXME: show an error dialog */
2656 return QUIT_PAGE;
2657 }
2658
2659 /* FIXME: Add file systems to list */
2660 }
2661
2662 /* Find or set the active system partition */
2663 CheckActiveSystemPartition(PartitionList, FileSystemList);
2664
2665 if (PartitionList->SystemDisk == NULL ||
2666 PartitionList->SystemPartition == NULL)
2667 {
2668 /* FIXME: show an error dialog */
2669 return QUIT_PAGE;
2670 }
2671
2672 PreviousFormatState = PartitionList->FormatState;
2673 switch (PartitionList->FormatState)
2674 {
2675 case Start:
2676 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2677 {
2678 PartitionList->TempDisk = PartitionList->SystemDisk;
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->TempDisk = PartitionList->CurrentDisk;
2688 PartitionList->TempPartition = PartitionList->CurrentPartition;
2689 PartitionList->TempPartition->NeedsCheck = TRUE;
2690
2691 PartitionList->FormatState = FormatInstallPartition;
2692 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2693 }
2694 break;
2695
2696 case FormatSystemPartition:
2697 PartitionList->TempDisk = PartitionList->CurrentDisk;
2698 PartitionList->TempPartition = PartitionList->CurrentPartition;
2699 PartitionList->TempPartition->NeedsCheck = TRUE;
2700
2701 PartitionList->FormatState = FormatInstallPartition;
2702 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2703 break;
2704
2705 case FormatInstallPartition:
2706 if (GetNextUnformattedPartition(PartitionList,
2707 &PartitionList->TempDisk,
2708 &PartitionList->TempPartition))
2709 {
2710 PartitionList->FormatState = FormatOtherPartition;
2711 PartitionList->TempPartition->NeedsCheck = TRUE;
2712 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2713 }
2714 else
2715 {
2716 PartitionList->FormatState = FormatDone;
2717 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2718 return CHECK_FILE_SYSTEM_PAGE;
2719 }
2720 break;
2721
2722 case FormatOtherPartition:
2723 if (GetNextUnformattedPartition(PartitionList,
2724 &PartitionList->TempDisk,
2725 &PartitionList->TempPartition))
2726 {
2727 PartitionList->FormatState = FormatOtherPartition;
2728 PartitionList->TempPartition->NeedsCheck = TRUE;
2729 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2730 }
2731 else
2732 {
2733 PartitionList->FormatState = FormatDone;
2734 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2735 return CHECK_FILE_SYSTEM_PAGE;
2736 }
2737 break;
2738
2739 default:
2740 DPRINT1("FormatState: Invalid value %ld\n", PartitionList->FormatState);
2741 /* FIXME: show an error dialog */
2742 return QUIT_PAGE;
2743 }
2744
2745 DiskEntry = PartitionList->TempDisk;
2746 PartEntry = PartitionList->TempPartition;
2747
2748 /* adjust disk size */
2749 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2750 if (DiskSize >= 10737418240) /* 10 GB */
2751 {
2752 DiskSize = DiskSize / 1073741824;
2753 DiskUnit = MUIGetString(STRING_GB);
2754 }
2755 else
2756 {
2757 DiskSize = DiskSize / 1048576;
2758 DiskUnit = MUIGetString(STRING_MB);
2759 }
2760
2761 /* adjust partition size */
2762 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2763 if (PartSize >= 10737418240) /* 10 GB */
2764 {
2765 PartSize = PartSize / 1073741824;
2766 PartUnit = MUIGetString(STRING_GB);
2767 }
2768 else
2769 {
2770 PartSize = PartSize / 1048576;
2771 PartUnit = MUIGetString(STRING_MB);
2772 }
2773
2774 /* adjust partition type */
2775 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2776 PartTypeString,
2777 ARRAYSIZE(PartTypeString));
2778
2779 if (PartEntry->AutoCreate != FALSE)
2780 {
2781 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2782
2783 #if 0
2784 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2785 PartEntry->PartitionNumber,
2786 PartSize,
2787 PartUnit,
2788 PartTypeString);
2789 #endif
2790
2791 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
2792 DiskEntry->DiskNumber,
2793 DiskSize,
2794 DiskUnit,
2795 DiskEntry->Port,
2796 DiskEntry->Bus,
2797 DiskEntry->Id,
2798 &DiskEntry->DriverName);
2799
2800 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2801
2802
2803 PartEntry->AutoCreate = FALSE;
2804 }
2805 else if (PartEntry->New != FALSE)
2806 {
2807 switch (PartitionList->FormatState)
2808 {
2809 case FormatSystemPartition:
2810 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2811 break;
2812
2813 case FormatInstallPartition:
2814 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2815 break;
2816
2817 case FormatOtherPartition:
2818 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2819 break;
2820
2821 default:
2822 break;
2823 }
2824
2825 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2826 }
2827 else
2828 {
2829 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2830
2831 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2832 {
2833 CONSOLE_PrintTextXY(8, 10,
2834 MUIGetString(STRING_HDDINFOUNK4),
2835 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2836 (PartEntry->DriveLetter == 0) ? '-' : ':',
2837 PartEntry->PartitionType,
2838 PartSize,
2839 PartUnit);
2840 }
2841 else
2842 {
2843 CONSOLE_PrintTextXY(8, 10,
2844 "%c%c %s %I64u %s",
2845 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2846 (PartEntry->DriveLetter == 0) ? '-' : ':',
2847 PartTypeString,
2848 PartSize,
2849 PartUnit);
2850 }
2851
2852 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
2853 DiskEntry->DiskNumber,
2854 DiskSize,
2855 DiskUnit,
2856 DiskEntry->Port,
2857 DiskEntry->Bus,
2858 DiskEntry->Id,
2859 &DiskEntry->DriverName);
2860 }
2861
2862 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2863
2864 if (FileSystemList == NULL)
2865 {
2866 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2867 if (FileSystemList == NULL)
2868 {
2869 /* FIXME: show an error dialog */
2870 return QUIT_PAGE;
2871 }
2872
2873 /* FIXME: Add file systems to list */
2874 }
2875
2876 DrawFileSystemList(FileSystemList);
2877
2878 if (RepairUpdateFlag)
2879 {
2880 return CHECK_FILE_SYSTEM_PAGE;
2881 //return SELECT_PARTITION_PAGE;
2882 }
2883
2884 if (IsUnattendedSetup)
2885 {
2886 if (UnattendFormatPartition)
2887 {
2888 PartEntry->FileSystem = GetFileSystemByName(FileSystemList, L"FAT");
2889 return FORMAT_PARTITION_PAGE;
2890 }
2891
2892 return CHECK_FILE_SYSTEM_PAGE;
2893 }
2894
2895 while (TRUE)
2896 {
2897 CONSOLE_ConInKey(Ir);
2898
2899 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2900 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2901 {
2902 if (ConfirmQuit(Ir) != FALSE)
2903 return QUIT_PAGE;
2904
2905 break;
2906 }
2907 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2908 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2909 {
2910 PartitionList->FormatState = Start;
2911 return SELECT_PARTITION_PAGE;
2912 }
2913 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2914 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2915 {
2916 ScrollDownFileSystemList(FileSystemList);
2917 }
2918 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2919 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2920 {
2921 ScrollUpFileSystemList(FileSystemList);
2922 }
2923 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2924 {
2925 if (!FileSystemList->Selected->FormatFunc)
2926 {
2927 return SELECT_FILE_SYSTEM_PAGE;
2928 }
2929 else
2930 {
2931 PartEntry->FileSystem = FileSystemList->Selected;
2932 return FORMAT_PARTITION_PAGE;
2933 }
2934 }
2935 }
2936
2937 PartitionList->FormatState = PreviousFormatState;
2938
2939 return SELECT_FILE_SYSTEM_PAGE;
2940 }
2941
2942
2943 /*
2944 * Displays the FormatPartitionPage.
2945 *
2946 * Next pages:
2947 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2948 * SelectPartitionPage (At once)
2949 * QuitPage
2950 *
2951 * SIDEEFFECTS
2952 * Sets PartitionList->CurrentPartition->FormatState
2953 * Sets DestinationRootPath
2954 *
2955 * RETURNS
2956 * Number of the next page.
2957 */
2958 static ULONG
2959 FormatPartitionPage(PINPUT_RECORD Ir)
2960 {
2961 UNICODE_STRING PartitionRootPath;
2962 WCHAR PathBuffer[MAX_PATH];
2963 PDISKENTRY DiskEntry;
2964 PPARTENTRY PartEntry;
2965 NTSTATUS Status;
2966
2967 #ifndef NDEBUG
2968 ULONG Line;
2969 ULONG i;
2970 PPARTITION_INFORMATION PartitionInfo;
2971 #endif
2972
2973 DPRINT("FormatPartitionPage()\n");
2974
2975 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2976
2977 if (PartitionList == NULL ||
2978 PartitionList->TempDisk == NULL ||
2979 PartitionList->TempPartition == NULL)
2980 {
2981 /* FIXME: show an error dialog */
2982 return QUIT_PAGE;
2983 }
2984
2985 DiskEntry = PartitionList->TempDisk;
2986 PartEntry = PartitionList->TempPartition;
2987
2988 while (TRUE)
2989 {
2990 if (!IsUnattendedSetup)
2991 {
2992 CONSOLE_ConInKey(Ir);
2993 }
2994
2995 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2996 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2997 {
2998 if (ConfirmQuit(Ir) != FALSE)
2999 return QUIT_PAGE;
3000
3001 break;
3002 }
3003 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3004 {
3005 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3006
3007 if (wcscmp(PartEntry->FileSystem->FileSystemName, L"FAT") == 0)
3008 {
3009 if (PartEntry->SectorCount.QuadPart < 8192)
3010 {
3011 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
3012 PartEntry->PartitionType = PARTITION_FAT_12;
3013 }
3014 else if (PartEntry->StartSector.QuadPart < 1450560)
3015 {
3016 /* Partition starts below the 8.4GB boundary ==> CHS partition */
3017
3018 if (PartEntry->SectorCount.QuadPart < 65536)
3019 {
3020 /* FAT16 CHS partition (partition size < 32MB) */
3021 PartEntry->PartitionType = PARTITION_FAT_16;
3022 }
3023 else if (PartEntry->SectorCount.QuadPart < 1048576)
3024 {
3025 /* FAT16 CHS partition (partition size < 512MB) */
3026 PartEntry->PartitionType = PARTITION_HUGE;
3027 }
3028 else
3029 {
3030 /* FAT32 CHS partition (partition size >= 512MB) */
3031 PartEntry->PartitionType = PARTITION_FAT32;
3032 }
3033 }
3034 else
3035 {
3036 /* Partition starts above the 8.4GB boundary ==> LBA partition */
3037
3038 if (PartEntry->SectorCount.QuadPart < 1048576)
3039 {
3040 /* FAT16 LBA partition (partition size < 512MB) */
3041 PartEntry->PartitionType = PARTITION_XINT13;
3042 }
3043 else
3044 {
3045 /* FAT32 LBA partition (partition size >= 512MB) */
3046 PartEntry->PartitionType = PARTITION_FAT32_XINT13;
3047 }
3048 }
3049
3050 DiskEntry->Dirty = TRUE;
3051 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
3052 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3053 }
3054 #if 0
3055 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"EXT2") == 0)
3056 {
3057 PartEntry->PartitionType = PARTITION_EXT2;
3058
3059 DiskEntry->Dirty = TRUE;
3060 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
3061 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3062 }
3063 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"NTFS") == 0)
3064 {
3065 PartEntry->PartitionType = PARTITION_IFS;
3066
3067 DiskEntry->Dirty = TRUE;
3068 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
3069 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3070 }
3071 #endif
3072 else if (!PartEntry->FileSystem->FormatFunc)
3073 {
3074 /* FIXME: show an error dialog */
3075 return QUIT_PAGE;
3076 }
3077
3078 #ifndef NDEBUG
3079 CONSOLE_PrintTextXY(6, 12,
3080 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3081 DiskEntry->Cylinders,
3082 DiskEntry->TracksPerCylinder,
3083 DiskEntry->SectorsPerTrack,
3084 DiskEntry->BytesPerSector,
3085 DiskEntry->Dirty ? '*' : ' ');
3086
3087 Line = 13;
3088
3089 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3090 {
3091 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3092
3093 CONSOLE_PrintTextXY(6, Line,
3094 "%2u: %2lu %c %12I64u %12I64u %02x",
3095 i,
3096 PartitionInfo->PartitionNumber,
3097 PartitionInfo->BootIndicator ? 'A' : '-',
3098 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3099 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3100 PartitionInfo->PartitionType);
3101 Line++;
3102 }
3103 #endif
3104
3105 if (WritePartitionsToDisk(PartitionList) == FALSE)
3106 {
3107 DPRINT("WritePartitionsToDisk() failed\n");
3108 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3109 return QUIT_PAGE;
3110 }
3111
3112 /* Set PartitionRootPath */
3113 swprintf(PathBuffer,
3114 L"\\Device\\Harddisk%lu\\Partition%lu",
3115 DiskEntry->DiskNumber,
3116 PartEntry->PartitionNumber);
3117 RtlInitUnicodeString(&PartitionRootPath,
3118 PathBuffer);
3119 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3120
3121 if (PartEntry->FileSystem->FormatFunc)
3122 {
3123 Status = FormatPartition(&PartitionRootPath,
3124 PartEntry->FileSystem);
3125 if (!NT_SUCCESS(Status))
3126 {
3127 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3128 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3129 return QUIT_PAGE;
3130 }
3131
3132 PartEntry->New = FALSE;
3133 }
3134
3135 #ifndef NDEBUG
3136 CONSOLE_SetStatusText(" Done. Press any key ...");
3137 CONSOLE_ConInKey(Ir);
3138 #endif
3139
3140 return SELECT_FILE_SYSTEM_PAGE;
3141 }
3142 }
3143
3144 return FORMAT_PARTITION_PAGE;
3145 }
3146
3147
3148 /*
3149 * Displays the CheckFileSystemPage.
3150 *
3151 * Next pages:
3152 * InstallDirectoryPage (At once)
3153 * QuitPage
3154 *
3155 * SIDEEFFECTS
3156 * Inits or reloads FileSystemList
3157 *
3158 * RETURNS
3159 * Number of the next page.
3160 */
3161 static ULONG
3162 CheckFileSystemPage(PINPUT_RECORD Ir)
3163 {
3164 PFILE_SYSTEM_ITEM CurrentFileSystem;
3165 UNICODE_STRING PartitionRootPath;
3166 WCHAR PathBuffer[MAX_PATH];
3167 CHAR Buffer[MAX_PATH];
3168 PDISKENTRY DiskEntry;
3169 PPARTENTRY PartEntry;
3170 NTSTATUS Status;
3171
3172 if (PartitionList == NULL)
3173 {
3174 /* FIXME: show an error dialog */
3175 return QUIT_PAGE;
3176 }
3177
3178 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3179 {
3180 return INSTALL_DIRECTORY_PAGE;
3181 }
3182
3183 /* Set PartitionRootPath */
3184 swprintf(PathBuffer,
3185 L"\\Device\\Harddisk%lu\\Partition%lu",
3186 DiskEntry->DiskNumber,
3187 PartEntry->PartitionNumber);
3188 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3189 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3190
3191 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3192
3193 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3194
3195 CurrentFileSystem = GetFileSystem(FileSystemList, PartEntry);
3196 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3197 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3198
3199 /* HACK: Do not try to check a partition with an unknown filesystem */
3200 if (CurrentFileSystem == NULL)
3201 {
3202 PartEntry->NeedsCheck = FALSE;
3203 return CHECK_FILE_SYSTEM_PAGE;
3204 }
3205
3206 if (CurrentFileSystem->ChkdskFunc == NULL)
3207 {
3208 sprintf(Buffer,
3209 "Setup is currently unable to check a partition formatted in %S.\n"
3210 "\n"
3211 " \x07 Press ENTER to continue Setup.\n"
3212 " \x07 Press F3 to quit Setup.",
3213 CurrentFileSystem->FileSystemName);
3214
3215 PopupError(Buffer,
3216 MUIGetString(STRING_QUITCONTINUE),
3217 NULL, POPUP_WAIT_NONE);
3218
3219 while (TRUE)
3220 {
3221 CONSOLE_ConInKey(Ir);
3222
3223 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3224 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3225 {
3226 if (ConfirmQuit(Ir))
3227 return QUIT_PAGE;
3228 else
3229 return CHECK_FILE_SYSTEM_PAGE;
3230 }
3231 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3232 {
3233 PartEntry->NeedsCheck = FALSE;
3234 return CHECK_FILE_SYSTEM_PAGE;
3235 }
3236 }
3237 }
3238 else
3239 {
3240 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3241 if (!NT_SUCCESS(Status))
3242 {
3243 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3244 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3245 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3246 "(Status 0x%08lx).\n", Status);
3247 PopupError(Buffer,
3248 // MUIGetString(STRING_REBOOTCOMPUTER),
3249 MUIGetString(STRING_CONTINUE),
3250 Ir, POPUP_WAIT_ENTER);
3251
3252 // return QUIT_PAGE;
3253 }
3254
3255 PartEntry->NeedsCheck = FALSE;
3256 return CHECK_FILE_SYSTEM_PAGE;
3257 }
3258 }
3259
3260
3261 static
3262 VOID
3263 BuildInstallPaths(PWCHAR InstallDir,
3264 PDISKENTRY DiskEntry,
3265 PPARTENTRY PartEntry)
3266 {
3267 WCHAR PathBuffer[MAX_PATH];
3268
3269 /* Create 'InstallPath' string */
3270 RtlFreeUnicodeString(&InstallPath);
3271 RtlCreateUnicodeString(&InstallPath, InstallDir);
3272
3273 /* Create 'DestinationRootPath' string */
3274 RtlFreeUnicodeString(&DestinationRootPath);
3275 swprintf(PathBuffer,
3276 L"\\Device\\Harddisk%lu\\Partition%lu",
3277 DiskEntry->DiskNumber,
3278 PartEntry->PartitionNumber);
3279 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
3280 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
3281
3282 /* Create 'DestinationPath' string */
3283 RtlFreeUnicodeString(&DestinationPath);
3284 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3285
3286 if (InstallDir[0] != L'\\')
3287 wcscat(PathBuffer, L"\\");
3288
3289 wcscat(PathBuffer, InstallDir);
3290 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
3291
3292 /* Create 'DestinationArcPath' */
3293 RtlFreeUnicodeString(&DestinationArcPath);
3294 swprintf(PathBuffer,
3295 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
3296 DiskEntry->BiosDiskNumber,
3297 PartEntry->PartitionNumber);
3298
3299 if (InstallDir[0] != L'\\')
3300 wcscat(PathBuffer, L"\\");
3301
3302 wcscat(PathBuffer, InstallDir);
3303 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
3304 }
3305
3306
3307 /*
3308 * Displays the InstallDirectoryPage.
3309 *
3310 * Next pages:
3311 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3312 * QuitPage
3313 *
3314 * RETURNS
3315 * Number of the next page.
3316 */
3317 static PAGE_NUMBER
3318 InstallDirectoryPage(PINPUT_RECORD Ir)
3319 {
3320 PDISKENTRY DiskEntry;
3321 PPARTENTRY PartEntry;
3322 WCHAR InstallDir[51];
3323 WCHAR c;
3324 ULONG Length, Pos;
3325
3326 /* We do not need the filesystem list any more */
3327 if (FileSystemList != NULL)
3328 {
3329 DestroyFileSystemList(FileSystemList);
3330 FileSystemList = NULL;
3331 }
3332
3333 if (PartitionList == NULL ||
3334 PartitionList->CurrentDisk == NULL ||
3335 PartitionList->CurrentPartition == NULL)
3336 {
3337 /* FIXME: show an error dialog */
3338 return QUIT_PAGE;
3339 }
3340
3341 DiskEntry = PartitionList->CurrentDisk;
3342 PartEntry = PartitionList->CurrentPartition;
3343
3344 if (IsUnattendedSetup)
3345 {
3346 if (!IsValidPath(UnattendInstallationDirectory))
3347 {
3348 /* FIXME: Log the error? */
3349 return QUIT_PAGE;
3350 }
3351
3352 BuildInstallPaths(UnattendInstallationDirectory,
3353 DiskEntry,
3354 PartEntry);
3355
3356 return PREPARE_COPY_PAGE;
3357 }
3358
3359 wcscpy(InstallDir, L"\\ReactOS");
3360
3361 Length = wcslen(InstallDir);
3362 Pos = Length;
3363 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3364 CONSOLE_SetCursorXY(8 + Pos, 11);
3365 CONSOLE_SetCursorType(TRUE, TRUE);
3366 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3367
3368 while (TRUE)
3369 {
3370 CONSOLE_ConInKey(Ir);
3371
3372 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3373 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3374 {
3375 CONSOLE_SetCursorType(TRUE, FALSE);
3376
3377 if (ConfirmQuit(Ir) != FALSE)
3378 return QUIT_PAGE;
3379
3380 CONSOLE_SetCursorType(TRUE, TRUE);
3381 break;
3382 }
3383 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3384 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3385 {
3386 if (Pos < Length)
3387 {
3388 memmove(&InstallDir[Pos],
3389 &InstallDir[Pos + 1],
3390 (Length - Pos - 1) * sizeof(WCHAR));
3391 InstallDir[Length - 1] = UNICODE_NULL;
3392
3393 Length--;
3394 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3395 CONSOLE_SetCursorXY(8 + Pos, 11);
3396 }
3397 }
3398 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3399 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3400 {
3401 Pos = 0;
3402 CONSOLE_SetCursorXY(8 + Pos, 11);
3403 }
3404 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3405 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3406 {
3407 Pos = Length;