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