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