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