[USETUP] Add & modify some file utility functions that are going to be used next.
[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
2661 if (PartitionList->SystemDisk == NULL ||
2662 PartitionList->SystemPartition == NULL)
2663 {
2664 /* FIXME: show an error dialog */
2665 return QUIT_PAGE;
2666 }
2667
2668 PreviousFormatState = PartitionList->FormatState;
2669 switch (PartitionList->FormatState)
2670 {
2671 case Start:
2672 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2673 {
2674 PartitionList->TempDisk = PartitionList->SystemDisk;
2675 PartitionList->TempPartition = PartitionList->SystemPartition;
2676 PartitionList->TempPartition->NeedsCheck = TRUE;
2677
2678 PartitionList->FormatState = FormatSystemPartition;
2679 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2680 }
2681 else
2682 {
2683 PartitionList->TempDisk = PartitionList->CurrentDisk;
2684 PartitionList->TempPartition = PartitionList->CurrentPartition;
2685 PartitionList->TempPartition->NeedsCheck = TRUE;
2686
2687 PartitionList->FormatState = FormatInstallPartition;
2688 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2689 }
2690 break;
2691
2692 case FormatSystemPartition:
2693 PartitionList->TempDisk = PartitionList->CurrentDisk;
2694 PartitionList->TempPartition = PartitionList->CurrentPartition;
2695 PartitionList->TempPartition->NeedsCheck = TRUE;
2696
2697 PartitionList->FormatState = FormatInstallPartition;
2698 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2699 break;
2700
2701 case FormatInstallPartition:
2702 if (GetNextUnformattedPartition(PartitionList,
2703 &PartitionList->TempDisk,
2704 &PartitionList->TempPartition))
2705 {
2706 PartitionList->FormatState = FormatOtherPartition;
2707 PartitionList->TempPartition->NeedsCheck = TRUE;
2708 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2709 }
2710 else
2711 {
2712 PartitionList->FormatState = FormatDone;
2713 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2714 return CHECK_FILE_SYSTEM_PAGE;
2715 }
2716 break;
2717
2718 case FormatOtherPartition:
2719 if (GetNextUnformattedPartition(PartitionList,
2720 &PartitionList->TempDisk,
2721 &PartitionList->TempPartition))
2722 {
2723 PartitionList->FormatState = FormatOtherPartition;
2724 PartitionList->TempPartition->NeedsCheck = TRUE;
2725 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2726 }
2727 else
2728 {
2729 PartitionList->FormatState = FormatDone;
2730 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2731 return CHECK_FILE_SYSTEM_PAGE;
2732 }
2733 break;
2734
2735 default:
2736 DPRINT1("FormatState: Invalid value %ld\n", PartitionList->FormatState);
2737 /* FIXME: show an error dialog */
2738 return QUIT_PAGE;
2739 }
2740
2741 DiskEntry = PartitionList->TempDisk;
2742 PartEntry = PartitionList->TempPartition;
2743
2744 /* Adjust disk size */
2745 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2746 if (DiskSize >= 10737418240) /* 10 GB */
2747 {
2748 DiskSize = DiskSize / 1073741824;
2749 DiskUnit = MUIGetString(STRING_GB);
2750 }
2751 else
2752 {
2753 DiskSize = DiskSize / 1048576;
2754 DiskUnit = MUIGetString(STRING_MB);
2755 }
2756
2757 /* Adjust partition size */
2758 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2759 if (PartSize >= 10737418240) /* 10 GB */
2760 {
2761 PartSize = PartSize / 1073741824;
2762 PartUnit = MUIGetString(STRING_GB);
2763 }
2764 else
2765 {
2766 PartSize = PartSize / 1048576;
2767 PartUnit = MUIGetString(STRING_MB);
2768 }
2769
2770 /* Adjust partition type */
2771 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2772 PartTypeString,
2773 ARRAYSIZE(PartTypeString));
2774
2775 if (PartEntry->AutoCreate != FALSE)
2776 {
2777 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2778
2779 #if 0
2780 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2781 PartEntry->PartitionNumber,
2782 PartSize,
2783 PartUnit,
2784 PartTypeString);
2785 #endif
2786
2787 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
2788 DiskEntry->DiskNumber,
2789 DiskSize,
2790 DiskUnit,
2791 DiskEntry->Port,
2792 DiskEntry->Bus,
2793 DiskEntry->Id,
2794 &DiskEntry->DriverName);
2795
2796 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2797
2798 PartEntry->AutoCreate = FALSE;
2799 }
2800 else if (PartEntry->New != FALSE)
2801 {
2802 switch (PartitionList->FormatState)
2803 {
2804 case FormatSystemPartition:
2805 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2806 break;
2807
2808 case FormatInstallPartition:
2809 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2810 break;
2811
2812 case FormatOtherPartition:
2813 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2814 break;
2815
2816 default:
2817 break;
2818 }
2819
2820 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2821 }
2822 else
2823 {
2824 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2825
2826 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2827 {
2828 CONSOLE_PrintTextXY(8, 10,
2829 MUIGetString(STRING_HDDINFOUNK4),
2830 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2831 (PartEntry->DriveLetter == 0) ? '-' : ':',
2832 PartEntry->PartitionType,
2833 PartSize,
2834 PartUnit);
2835 }
2836 else
2837 {
2838 CONSOLE_PrintTextXY(8, 10,
2839 "%c%c %s %I64u %s",
2840 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2841 (PartEntry->DriveLetter == 0) ? '-' : ':',
2842 PartTypeString,
2843 PartSize,
2844 PartUnit);
2845 }
2846
2847 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
2848 DiskEntry->DiskNumber,
2849 DiskSize,
2850 DiskUnit,
2851 DiskEntry->Port,
2852 DiskEntry->Bus,
2853 DiskEntry->Id,
2854 &DiskEntry->DriverName);
2855 }
2856
2857 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2858
2859 if (FileSystemList == NULL)
2860 {
2861 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2862 if (FileSystemList == NULL)
2863 {
2864 /* FIXME: show an error dialog */
2865 return QUIT_PAGE;
2866 }
2867
2868 /* FIXME: Add file systems to list */
2869 }
2870
2871 DrawFileSystemList(FileSystemList);
2872
2873 if (RepairUpdateFlag)
2874 {
2875 return CHECK_FILE_SYSTEM_PAGE;
2876 //return SELECT_PARTITION_PAGE;
2877 }
2878
2879 if (IsUnattendedSetup)
2880 {
2881 if (UnattendFormatPartition)
2882 {
2883 PartEntry->FileSystem = GetFileSystemByName(FileSystemList, L"FAT");
2884 return FORMAT_PARTITION_PAGE;
2885 }
2886
2887 return CHECK_FILE_SYSTEM_PAGE;
2888 }
2889
2890 while (TRUE)
2891 {
2892 CONSOLE_ConInKey(Ir);
2893
2894 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2895 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2896 {
2897 if (ConfirmQuit(Ir) != FALSE)
2898 return QUIT_PAGE;
2899
2900 break;
2901 }
2902 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2903 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2904 {
2905 PartitionList->FormatState = Start;
2906 return SELECT_PARTITION_PAGE;
2907 }
2908 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2909 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2910 {
2911 ScrollDownFileSystemList(FileSystemList);
2912 }
2913 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2914 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2915 {
2916 ScrollUpFileSystemList(FileSystemList);
2917 }
2918 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2919 {
2920 if (!FileSystemList->Selected->FormatFunc)
2921 {
2922 return SELECT_FILE_SYSTEM_PAGE;
2923 }
2924 else
2925 {
2926 PartEntry->FileSystem = FileSystemList->Selected;
2927 return FORMAT_PARTITION_PAGE;
2928 }
2929 }
2930 }
2931
2932 PartitionList->FormatState = PreviousFormatState;
2933
2934 return SELECT_FILE_SYSTEM_PAGE;
2935 }
2936
2937
2938 /*
2939 * Displays the FormatPartitionPage.
2940 *
2941 * Next pages:
2942 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2943 * SelectPartitionPage (At once)
2944 * QuitPage
2945 *
2946 * SIDEEFFECTS
2947 * Sets PartitionList->CurrentPartition->FormatState
2948 * Sets DestinationRootPath
2949 *
2950 * RETURNS
2951 * Number of the next page.
2952 */
2953 static ULONG
2954 FormatPartitionPage(PINPUT_RECORD Ir)
2955 {
2956 UNICODE_STRING PartitionRootPath;
2957 WCHAR PathBuffer[MAX_PATH];
2958 PDISKENTRY DiskEntry;
2959 PPARTENTRY PartEntry;
2960 NTSTATUS Status;
2961
2962 #ifndef NDEBUG
2963 ULONG Line;
2964 ULONG i;
2965 PPARTITION_INFORMATION PartitionInfo;
2966 #endif
2967
2968 DPRINT("FormatPartitionPage()\n");
2969
2970 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2971
2972 if (PartitionList == NULL ||
2973 PartitionList->TempDisk == NULL ||
2974 PartitionList->TempPartition == NULL)
2975 {
2976 /* FIXME: show an error dialog */
2977 return QUIT_PAGE;
2978 }
2979
2980 DiskEntry = PartitionList->TempDisk;
2981 PartEntry = PartitionList->TempPartition;
2982
2983 while (TRUE)
2984 {
2985 if (!IsUnattendedSetup)
2986 {
2987 CONSOLE_ConInKey(Ir);
2988 }
2989
2990 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2991 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2992 {
2993 if (ConfirmQuit(Ir) != FALSE)
2994 return QUIT_PAGE;
2995
2996 break;
2997 }
2998 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2999 {
3000 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3001
3002 if (wcscmp(PartEntry->FileSystem->FileSystemName, L"FAT") == 0)
3003 {
3004 if (PartEntry->SectorCount.QuadPart < 8192)
3005 {
3006 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
3007 PartEntry->PartitionType = PARTITION_FAT_12;
3008 }
3009 else if (PartEntry->StartSector.QuadPart < 1450560)
3010 {
3011 /* Partition starts below the 8.4GB boundary ==> CHS partition */
3012
3013 if (PartEntry->SectorCount.QuadPart < 65536)
3014 {
3015 /* FAT16 CHS partition (partition size < 32MB) */
3016 PartEntry->PartitionType = PARTITION_FAT_16;
3017 }
3018 else if (PartEntry->SectorCount.QuadPart < 1048576)
3019 {
3020 /* FAT16 CHS partition (partition size < 512MB) */
3021 PartEntry->PartitionType = PARTITION_HUGE;
3022 }
3023 else
3024 {
3025 /* FAT32 CHS partition (partition size >= 512MB) */
3026 PartEntry->PartitionType = PARTITION_FAT32;
3027 }
3028 }
3029 else
3030 {
3031 /* Partition starts above the 8.4GB boundary ==> LBA partition */
3032
3033 if (PartEntry->SectorCount.QuadPart < 1048576)
3034 {
3035 /* FAT16 LBA partition (partition size < 512MB) */
3036 PartEntry->PartitionType = PARTITION_XINT13;
3037 }
3038 else
3039 {
3040 /* FAT32 LBA partition (partition size >= 512MB) */
3041 PartEntry->PartitionType = PARTITION_FAT32_XINT13;
3042 }
3043 }
3044
3045 DiskEntry->Dirty = TRUE;
3046 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
3047 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3048 }
3049 #if 0
3050 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"EXT2") == 0)
3051 {
3052 PartEntry->PartitionType = PARTITION_EXT2;
3053
3054 DiskEntry->Dirty = TRUE;
3055 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
3056 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3057 }
3058 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"NTFS") == 0)
3059 {
3060 PartEntry->PartitionType = PARTITION_IFS;
3061
3062 DiskEntry->Dirty = TRUE;
3063 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
3064 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3065 }
3066 #endif
3067 else if (!PartEntry->FileSystem->FormatFunc)
3068 {
3069 /* FIXME: show an error dialog */
3070 return QUIT_PAGE;
3071 }
3072
3073 #ifndef NDEBUG
3074 CONSOLE_PrintTextXY(6, 12,
3075 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3076 DiskEntry->Cylinders,
3077 DiskEntry->TracksPerCylinder,
3078 DiskEntry->SectorsPerTrack,
3079 DiskEntry->BytesPerSector,
3080 DiskEntry->Dirty ? '*' : ' ');
3081
3082 Line = 13;
3083
3084 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3085 {
3086 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3087
3088 CONSOLE_PrintTextXY(6, Line,
3089 "%2u: %2lu %c %12I64u %12I64u %02x",
3090 i,
3091 PartitionInfo->PartitionNumber,
3092 PartitionInfo->BootIndicator ? 'A' : '-',
3093 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3094 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3095 PartitionInfo->PartitionType);
3096 Line++;
3097 }
3098 #endif
3099
3100 if (WritePartitionsToDisk(PartitionList) == FALSE)
3101 {
3102 DPRINT("WritePartitionsToDisk() failed\n");
3103 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3104 return QUIT_PAGE;
3105 }
3106
3107 /* Set PartitionRootPath */
3108 swprintf(PathBuffer,
3109 L"\\Device\\Harddisk%lu\\Partition%lu",
3110 DiskEntry->DiskNumber,
3111 PartEntry->PartitionNumber);
3112 RtlInitUnicodeString(&PartitionRootPath,
3113 PathBuffer);
3114 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3115
3116 if (PartEntry->FileSystem->FormatFunc)
3117 {
3118 Status = FormatPartition(&PartitionRootPath,
3119 PartEntry->FileSystem);
3120 if (!NT_SUCCESS(Status))
3121 {
3122 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3123 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3124 return QUIT_PAGE;
3125 }
3126
3127 PartEntry->New = FALSE;
3128 }
3129
3130 #ifndef NDEBUG
3131 CONSOLE_SetStatusText(" Done. Press any key ...");
3132 CONSOLE_ConInKey(Ir);
3133 #endif
3134
3135 return SELECT_FILE_SYSTEM_PAGE;
3136 }
3137 }
3138
3139 return FORMAT_PARTITION_PAGE;
3140 }
3141
3142
3143 /*
3144 * Displays the CheckFileSystemPage.
3145 *
3146 * Next pages:
3147 * InstallDirectoryPage (At once)
3148 * QuitPage
3149 *
3150 * SIDEEFFECTS
3151 * Inits or reloads FileSystemList
3152 *
3153 * RETURNS
3154 * Number of the next page.
3155 */
3156 static ULONG
3157 CheckFileSystemPage(PINPUT_RECORD Ir)
3158 {
3159 PFILE_SYSTEM_ITEM CurrentFileSystem;
3160 UNICODE_STRING PartitionRootPath;
3161 WCHAR PathBuffer[MAX_PATH];
3162 CHAR Buffer[MAX_PATH];
3163 PDISKENTRY DiskEntry;
3164 PPARTENTRY PartEntry;
3165 NTSTATUS Status;
3166
3167 if (PartitionList == NULL)
3168 {
3169 /* FIXME: show an error dialog */
3170 return QUIT_PAGE;
3171 }
3172
3173 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3174 {
3175 return INSTALL_DIRECTORY_PAGE;
3176 }
3177
3178 /* Set PartitionRootPath */
3179 swprintf(PathBuffer,
3180 L"\\Device\\Harddisk%lu\\Partition%lu",
3181 DiskEntry->DiskNumber,
3182 PartEntry->PartitionNumber);
3183 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3184 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3185
3186 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3187
3188 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3189
3190 CurrentFileSystem = GetFileSystem(FileSystemList, PartEntry);
3191 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3192 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3193
3194 /* HACK: Do not try to check a partition with an unknown filesystem */
3195 if (CurrentFileSystem == NULL)
3196 {
3197 PartEntry->NeedsCheck = FALSE;
3198 return CHECK_FILE_SYSTEM_PAGE;
3199 }
3200
3201 if (CurrentFileSystem->ChkdskFunc == NULL)
3202 {
3203 sprintf(Buffer,
3204 "Setup is currently unable to check a partition formatted in %S.\n"
3205 "\n"
3206 " \x07 Press ENTER to continue Setup.\n"
3207 " \x07 Press F3 to quit Setup.",
3208 CurrentFileSystem->FileSystemName);
3209
3210 PopupError(Buffer,
3211 MUIGetString(STRING_QUITCONTINUE),
3212 NULL, POPUP_WAIT_NONE);
3213
3214 while (TRUE)
3215 {
3216 CONSOLE_ConInKey(Ir);
3217
3218 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3219 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3220 {
3221 if (ConfirmQuit(Ir))
3222 return QUIT_PAGE;
3223 else
3224 return CHECK_FILE_SYSTEM_PAGE;
3225 }
3226 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3227 {
3228 PartEntry->NeedsCheck = FALSE;
3229 return CHECK_FILE_SYSTEM_PAGE;
3230 }
3231 }
3232 }
3233 else
3234 {
3235 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3236 if (!NT_SUCCESS(Status))
3237 {
3238 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3239 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3240 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3241 "(Status 0x%08lx).\n", Status);
3242 PopupError(Buffer,
3243 // MUIGetString(STRING_REBOOTCOMPUTER),
3244 MUIGetString(STRING_CONTINUE),
3245 Ir, POPUP_WAIT_ENTER);
3246
3247 // return QUIT_PAGE;
3248 }
3249
3250 PartEntry->NeedsCheck = FALSE;
3251 return CHECK_FILE_SYSTEM_PAGE;
3252 }
3253 }
3254
3255
3256 static
3257 VOID
3258 BuildInstallPaths(PWCHAR InstallDir,
3259 PDISKENTRY DiskEntry,
3260 PPARTENTRY PartEntry)
3261 {
3262 WCHAR PathBuffer[MAX_PATH];
3263
3264 /* Create 'InstallPath' string */
3265 RtlFreeUnicodeString(&InstallPath);
3266 RtlCreateUnicodeString(&InstallPath, InstallDir);
3267
3268 /* Create 'DestinationRootPath' string */
3269 RtlFreeUnicodeString(&DestinationRootPath);
3270 swprintf(PathBuffer,
3271 L"\\Device\\Harddisk%lu\\Partition%lu",
3272 DiskEntry->DiskNumber,
3273 PartEntry->PartitionNumber);
3274 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
3275 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
3276
3277 /* Create 'DestinationPath' string */
3278 RtlFreeUnicodeString(&DestinationPath);
3279 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3280
3281 if (InstallDir[0] != L'\\')
3282 wcscat(PathBuffer, L"\\");
3283
3284 wcscat(PathBuffer, InstallDir);
3285 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
3286
3287 /* Create 'DestinationArcPath' */
3288 RtlFreeUnicodeString(&DestinationArcPath);
3289 swprintf(PathBuffer,
3290 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
3291 DiskEntry->BiosDiskNumber,
3292 PartEntry->PartitionNumber);
3293
3294 if (InstallDir[0] != L'\\')
3295 wcscat(PathBuffer, L"\\");
3296
3297 wcscat(PathBuffer, InstallDir);
3298 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
3299 }
3300
3301
3302 /*
3303 * Displays the InstallDirectoryPage.
3304 *
3305 * Next pages:
3306 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3307 * QuitPage
3308 *
3309 * RETURNS
3310 * Number of the next page.
3311 */
3312 static PAGE_NUMBER
3313 InstallDirectoryPage(PINPUT_RECORD Ir)
3314 {
3315 PDISKENTRY DiskEntry;
3316 PPARTENTRY PartEntry;
3317 WCHAR InstallDir[51];
3318 WCHAR c;
3319 ULONG Length, Pos;
3320
3321 /* We do not need the filesystem list any more */
3322 if (FileSystemList != NULL)
3323 {
3324 DestroyFileSystemList(FileSystemList);
3325 FileSystemList = NULL;
3326 }
3327
3328 if (PartitionList == NULL ||
3329 PartitionList->CurrentDisk == NULL ||
3330 PartitionList->CurrentPartition == NULL)
3331 {
3332 /* FIXME: show an error dialog */
3333 return QUIT_PAGE;
3334 }
3335
3336 DiskEntry = PartitionList->CurrentDisk;
3337 PartEntry = PartitionList->CurrentPartition;
3338
3339 if (IsUnattendedSetup)
3340 {
3341 if (!IsValidPath(UnattendInstallationDirectory))
3342 {
3343 /* FIXME: Log the error? */
3344 return QUIT_PAGE;
3345 }
3346
3347 BuildInstallPaths(UnattendInstallationDirectory,
3348 DiskEntry,
3349 PartEntry);
3350
3351 return PREPARE_COPY_PAGE;
3352 }
3353
3354 wcscpy(InstallDir, L"\\ReactOS");
3355
3356 Length = wcslen(InstallDir);
3357 Pos = Length;
3358 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3359 CONSOLE_SetCursorXY(8 + Pos, 11);
3360 CONSOLE_SetCursorType(TRUE, TRUE);
3361 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3362
3363 while (TRUE)
3364 {
3365 CONSOLE_ConInKey(Ir);
3366
3367 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3368 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3369 {
3370 CONSOLE_SetCursorType(TRUE, FALSE);
3371
3372 if (ConfirmQuit(Ir) != FALSE)
3373 return QUIT_PAGE;
3374
3375 CONSOLE_SetCursorType(TRUE, TRUE);
3376 break;
3377 }
3378 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3379 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3380 {
3381 if (Pos < Length)
3382 {
3383 memmove(&InstallDir[Pos],
3384 &InstallDir[Pos + 1],
3385 (Length - Pos - 1) * sizeof(WCHAR));
3386 InstallDir[Length - 1] = UNICODE_NULL;
3387
3388 Length--;
3389 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3390 CONSOLE_SetCursorXY(8 + Pos, 11);
3391 }
3392 }
3393 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3394 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3395 {
3396 Pos = 0;
3397 CONSOLE_SetCursorXY(8 + Pos, 11);
3398 }
3399 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3400 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3401 {
3402 Pos = Length;
3403 CONSOLE_SetCursorXY(8 + Pos, 11);
3404 }
3405 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3406 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3407 {
3408 if (Pos > 0)
3409 {
3410 Pos--;
3411 CONSOLE_SetCursorXY(8 + Pos, 11);
3412 }
3413 }
3414 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3415 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3416 {
3417 if (Pos < Length)
3418 {
3419 Pos++;
3420 CONSOLE_SetCursorXY(8 + Pos, 11);
3421 }
3422 }
3423 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3424 {
3425 CONSOLE_SetCursorType(TRUE, FALSE);
3426
3427 /*
3428 * Check for the validity of the installation directory and pop up
3429 * an error if it is not the case. Then the user can fix its input.
3430 */
3431 if (!IsValidPath(InstallDir))
3432 {
3433 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3434 return INSTALL_DIRECTORY_PAGE;
3435 }
3436
3437 BuildInstallPaths(InstallDir,
3438 DiskEntry,
3439 PartEntry);
3440
3441 return PREPARE_COPY_PAGE;
3442 }
3443 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3444 {
3445 if (Pos > 0)
3446 {
3447 if (Pos < Length)
3448 memmove(&InstallDir[Pos - 1],
3449 &InstallDir[Pos],
3450 (Length - Pos) * sizeof(WCHAR));
3451 InstallDir[Length - 1] = UNICODE_NULL;
3452
3453 Pos--;
3454 Length--;
3455 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3456 CONSOLE_SetCursorXY(8 + Pos, 11);
3457 }
3458 }
3459 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3460 {
3461 if (Length < 50)
3462 {
3463 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3464 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3465 {
3466 if (Pos < Length)
3467 memmove(&InstallDir[Pos + 1],
3468 &InstallDir[Pos],
3469 (Length - Pos) * sizeof(WCHAR));
3470 InstallDir[Length + 1] = UNICODE_NULL;
3471 InstallDir[Pos] = c;
3472
3473 Pos++;
3474 Length++;
3475 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3476 CONSOLE_SetCursorXY(8 + Pos, 11);
3477 }
3478 }
3479 }
3480 }
3481
3482 return INSTALL_DIRECTORY_PAGE;
3483 }
3484
3485
3486 static BOOLEAN
3487 AddSectionToCopyQueueCab(HINF InfFile,
3488 PWCHAR SectionName,
3489 PWCHAR SourceCabinet,
3490 PCUNICODE_STRING DestinationPath,
3491 PINPUT_RECORD Ir)
3492 {
3493 INFCONTEXT FilesContext;
3494 INFCONTEXT DirContext;
3495 PWCHAR FileKeyName;
3496 PWCHAR FileKeyValue;
3497 PWCHAR DirKeyValue;
3498 PWCHAR TargetFileName;
3499
3500 /* Search for the SectionName section */
3501 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3502 {
3503 char Buffer[128];
3504 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3505 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3506 return FALSE;
3507 }
3508
3509 /*
3510 * Enumerate the files in the section
3511 * and add them to the file queue.
3512 */
3513 do
3514 {
3515 /* Get source file name and target directory id */
3516 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3517 {
3518 /* FIXME: Handle error! */
3519 DPRINT1("INF_GetData() failed\n");
3520 break;
3521 }
3522
3523 /* Get optional target file name */
3524 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
3525 TargetFileName = NULL;
3526
3527 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3528
3529 /* Lookup target directory */
3530 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3531 {
3532 /* FIXME: Handle error! */
3533 DPRINT1("SetupFindFirstLine() failed\n");
3534 break;
3535 }
3536
3537 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3538 {
3539 /* FIXME: Handle error! */
3540 DPRINT1("INF_GetData() failed\n");
3541 break;
3542 }
3543
3544 if (!SetupQueueCopy(SetupFileQueue,
3545 SourceCabinet,
3546 SourceRootPath.Buffer,
3547 SourceRootDir.Buffer,
3548 FileKeyName,
3549 DirKeyValue,
3550 TargetFileName))
3551 {
3552 /* FIXME: Handle error! */
3553 DPRINT1("SetupQueueCopy() failed\n");
3554 }
3555 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3556
3557 return TRUE;
3558 }
3559
3560
3561 static BOOLEAN
3562 AddSectionToCopyQueue(HINF InfFile,
3563 PWCHAR SectionName,
3564 PWCHAR SourceCabinet,
3565 PCUNICODE_STRING DestinationPath,
3566 PINPUT_RECORD Ir)
3567 {
3568 INFCONTEXT FilesContext;
3569 INFCONTEXT DirContext;
3570 PWCHAR FileKeyName;
3571 PWCHAR FileKeyValue;
3572 PWCHAR DirKeyValue;
3573 PWCHAR TargetFileName;
3574 ULONG Length;
3575 WCHAR CompleteOrigDirName[512];
3576
3577 if (SourceCabinet)
3578 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
3579
3580 /* Search for the SectionName section */
3581 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3582 {
3583 char Buffer[128];
3584 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3585 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3586 return FALSE;
3587 }
3588
3589 /*
3590 * Enumerate the files in the section
3591 * and add them to the file queue.
3592 */
3593 do
3594 {
3595 /* Get source file name and target directory id */
3596 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3597 {
3598 /* FIXME: Handle error! */
3599 DPRINT1("INF_GetData() failed\n");
3600 break;
3601 }
3602
3603 /* Get target directory id */
3604 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
3605 {
3606 /* FIXME: Handle error! */
3607 DPRINT1("INF_GetData() failed\n");
3608 break;
3609 }
3610
3611 /* Get optional target file name */
3612 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
3613 TargetFileName = NULL;
3614 else if (!*TargetFileName)
3615 TargetFileName = NULL;
3616
3617 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3618
3619 /* Lookup target directory */
3620 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3621 {
3622 /* FIXME: Handle error! */
3623 DPRINT1("SetupFindFirstLine() failed\n");
3624 break;
3625 }
3626
3627 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3628 {
3629 /* FIXME: Handle error! */
3630 DPRINT1("INF_GetData() failed\n");
3631 break;
3632 }
3633
3634 if ((DirKeyValue[0] == 0) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == 0))
3635 {
3636 /* Installation path */
3637 wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
3638 }
3639 else if (DirKeyValue[0] == L'\\')
3640 {
3641 /* Absolute path */
3642 wcscpy(CompleteOrigDirName, DirKeyValue);
3643 }
3644 else // if (DirKeyValue[0] != L'\\')
3645 {
3646 /* Path relative to the installation path */
3647 wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
3648 wcscat(CompleteOrigDirName, L"\\");
3649 wcscat(CompleteOrigDirName, DirKeyValue);
3650 }
3651
3652 /* Remove trailing backslash */
3653 Length = wcslen(CompleteOrigDirName);
3654 if ((Length > 0) && (CompleteOrigDirName[Length - 1] == L'\\'))
3655 {
3656 CompleteOrigDirName[Length - 1] = 0;
3657 }
3658
3659 if (!SetupQueueCopy(SetupFileQueue,
3660 SourceCabinet,
3661 SourceRootPath.Buffer,
3662 CompleteOrigDirName,
3663 FileKeyName,
3664 DirKeyValue,
3665 TargetFileName))
3666 {
3667 /* FIXME: Handle error! */
3668 DPRINT1("SetupQueueCopy() failed\n");
3669 }
3670 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3671
3672 return TRUE;
3673 }
3674
3675
3676 static BOOLEAN
3677 PrepareCopyPageInfFile(HINF InfFile,
3678 PWCHAR SourceCabinet,
3679 PINPUT_RECORD Ir)
3680 {
3681 WCHAR PathBuffer[MAX_PATH];
3682 INFCONTEXT DirContext;
3683 PWCHAR AdditionalSectionName = NULL;
3684 PWCHAR DirKeyValue;
3685 ULONG Length;
3686 NTSTATUS Status;
3687
3688 /* Add common files */
3689 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
3690 return FALSE;
3691
3692 /* Add specific files depending of computer type */
3693 if (SourceCabinet == NULL)
3694 {
3695 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
3696 return FALSE;
3697
3698 if (AdditionalSectionName)
3699 {
3700 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
3701 return FALSE;
3702 }
3703 }
3704
3705 /* Create directories */
3706
3707 /*
3708 * FIXME:
3709 * - Install directories like '\reactos\test' are not handled yet.
3710 * - Copying files to DestinationRootPath should be done from within
3711 * the SystemPartitionFiles section.
3712 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3713 * For installing to DestinationPath specify just '\' .
3714 */
3715
3716 /* Get destination path */
3717 wcscpy(PathBuffer, DestinationPath.Buffer);
3718
3719 /* Remove trailing backslash */
3720 Length = wcslen(PathBuffer);
3721 if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
3722 {
3723 PathBuffer[Length - 1] = 0;
3724 }
3725
3726 /* Create the install directory */
3727 Status = SetupCreateDirectory(PathBuffer);
3728 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3729 {
3730 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3731 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
3732 return FALSE;
3733 }
3734
3735 /* Search for the 'Directories' section */
3736 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3737 {
3738 if (SourceCabinet)
3739 {
3740 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
3741 }
3742 else
3743 {
3744 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
3745 }
3746
3747 return FALSE;
3748 }
3749
3750 /* Enumerate the directory values and create the subdirectories */
3751 do
3752 {
3753 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3754 {
3755 DPRINT1("break\n");
3756 break;
3757 }
3758
3759 if ((DirKeyValue[0] == 0) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == 0))
3760 {
3761 /* Installation path */
3762 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3763
3764 wcscpy(PathBuffer, DestinationPath.Buffer);
3765
3766 DPRINT("FullPath: '%S'\n", PathBuffer);
3767 }
3768 else if (DirKeyValue[0] == L'\\')
3769 {
3770 /* Absolute path */
3771 DPRINT("Absolute Path: '%S'\n", DirKeyValue);
3772
3773 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3774 wcscat(PathBuffer, DirKeyValue);
3775
3776 /* Remove trailing backslash */
3777 Length = wcslen(PathBuffer);
3778 if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
3779 {
3780 PathBuffer[Length - 1] = 0;
3781 }
3782
3783 DPRINT("FullPath: '%S'\n", PathBuffer);
3784
3785 Status = SetupCreateDirectory(PathBuffer);
3786 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3787 {
3788 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3789 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3790 return FALSE;
3791 }
3792 }
3793 else // if (DirKeyValue[0] != L'\\')
3794 {
3795 /* Path relative to the installation path */
3796 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3797
3798 wcscpy(PathBuffer, DestinationPath.Buffer);
3799 wcscat(PathBuffer, L"\\");
3800 wcscat(PathBuffer, DirKeyValue);
3801
3802 /* Remove trailing backslash */
3803 Length = wcslen(PathBuffer);
3804 if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
3805 {
3806 PathBuffer[Length - 1] = 0;
3807 }
3808
3809 DPRINT("FullPath: '%S'\n", PathBuffer);
3810
3811 Status = SetupCreateDirectory(PathBuffer);
3812 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3813 {
3814 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3815 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3816 return FALSE;
3817 }
3818 }
3819 } while (SetupFindNextLine(&DirContext, &DirContext));
3820
3821 return TRUE;
3822 }
3823
3824
3825 /*
3826 * Displays the PrepareCopyPage.
3827 *
3828 * Next pages:
3829 * FileCopyPage(At once)
3830 * QuitPage
3831 *
3832 * SIDEEFFECTS
3833 * Inits SetupFileQueue
3834 * Calls PrepareCopyPageInfFile
3835 *
3836 * RETURNS
3837 * Number of the next page.
3838 */
3839 static PAGE_NUMBER
3840 PrepareCopyPage(PINPUT_RECORD Ir)
3841 {
3842 HINF InfHandle;
3843 WCHAR PathBuffer[MAX_PATH];
3844 INFCONTEXT CabinetsContext;
3845 ULONG InfFileSize;
3846 PWCHAR KeyValue;
3847 UINT ErrorLine;
3848 PVOID InfFileData;
3849
3850 MUIDisplayPage(PREPARE_COPY_PAGE);
3851
3852 /* Create the file queue */
3853 SetupFileQueue = SetupOpenFileQueue();
3854 if (SetupFileQueue == NULL)
3855 {
3856 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
3857 return QUIT_PAGE;
3858 }
3859
3860 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
3861 {
3862 /* FIXME: show an error dialog */
3863 return QUIT_PAGE;
3864 }
3865
3866 /* Search for the 'Cabinets' section */
3867 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
3868 {
3869 return FILE_COPY_PAGE;
3870 }
3871
3872 /*
3873 * Enumerate the directory values in the 'Cabinets'
3874 * section and parse their inf files.
3875 */
3876 do
3877 {
3878 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3879 break;
3880
3881 wcscpy(PathBuffer, SourcePath.Buffer);
3882 wcscat(PathBuffer, L"\\");
3883 wcscat(PathBuffer, KeyValue);
3884
3885 CabinetInitialize();
3886 CabinetSetEventHandlers(NULL, NULL, NULL);
3887 CabinetSetCabinetName(PathBuffer);
3888
3889 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3890 {
3891 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3892
3893 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3894 if (InfFileData == NULL)
3895 {
3896 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3897 return QUIT_PAGE;
3898 }
3899 }
3900 else
3901 {
3902 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3903 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3904 return QUIT_PAGE;
3905 }
3906
3907 InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
3908 InfFileSize,
3909 (const CHAR*) NULL,
3910 INF_STYLE_WIN4,
3911 LanguageId,
3912 &ErrorLine);
3913
3914 if (InfHandle == INVALID_HANDLE_VALUE)
3915 {
3916 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3917 return QUIT_PAGE;
3918 }
3919
3920 CabinetCleanup();
3921
3922 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3923 {
3924 /* FIXME: show an error dialog */
3925 return QUIT_PAGE;
3926 }
3927 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3928
3929 return FILE_COPY_PAGE;
3930 }
3931
3932
3933 VOID
3934 NTAPI
3935 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3936 IN BOOLEAN First)
3937 {
3938 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3939
3940 /* Get the memory information from the system */