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