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