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