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