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