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