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