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