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