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