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