[USETUP]
[reactos.git] / reactos / base / setup / usetup / interface / 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/interface/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 == TRUE)
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 == TRUE)
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 * RETURNS
633 * Number of the next page.
634 */
635 static PAGE_NUMBER
636 LanguagePage(PINPUT_RECORD Ir)
637 {
638 PWCHAR NewLanguageId;
639 BOOL RefreshPage = FALSE;
640
641 /* Initialize the computer settings list */
642 if (LanguageList == NULL)
643 {
644 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
645
646 if (LanguageList == NULL)
647 {
648 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
649 return INTRO_PAGE;
650 }
651 }
652
653 /* Load the font */
654 SelectedLanguageId = DefaultLanguage;
655 SetConsoleCodePage();
656 UpdateKBLayout();
657
658 /* If there's just a single language in the list skip
659 * the language selection process altogether! */
660 if (GenericListHasSingleEntry(LanguageList))
661 return INTRO_PAGE;
662
663 DrawGenericList(LanguageList,
664 2,
665 18,
666 xScreen - 3,
667 yScreen - 3);
668
669 ScrollToPositionGenericList(LanguageList, GetDefaultLanguageIndex());
670
671 MUIDisplayPage(LANGUAGE_PAGE);
672
673 while (TRUE)
674 {
675 CONSOLE_ConInKey(Ir);
676
677 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
678 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
679 {
680 ScrollDownGenericList(LanguageList);
681 RefreshPage = TRUE;
682 }
683 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
684 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
685 {
686 ScrollUpGenericList(LanguageList);
687 RefreshPage = TRUE;
688 }
689 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
690 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
691 {
692 ScrollPageDownGenericList(LanguageList);
693 RefreshPage = TRUE;
694 }
695 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
696 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
697 {
698 ScrollPageUpGenericList(LanguageList);
699 RefreshPage = TRUE;
700 }
701 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
702 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
703 {
704 if (ConfirmQuit(Ir) == TRUE)
705 return QUIT_PAGE;
706 else
707 RedrawGenericList(LanguageList);
708 }
709 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
710 {
711 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
712
713 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
714
715 if (wcscmp(SelectedLanguageId, DefaultLanguage))
716 {
717 UpdateKBLayout();
718 }
719
720 /* Load the font */
721 SetConsoleCodePage();
722
723 return INTRO_PAGE;
724 }
725 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
726 {
727 /* a-z */
728 GenericListKeyPress(LanguageList, Ir->Event.KeyEvent.uChar.AsciiChar);
729 RefreshPage = TRUE;
730 }
731
732 if (RefreshPage)
733 {
734 NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
735
736 if (SelectedLanguageId != NewLanguageId)
737 {
738 /* Clear the language page */
739 MUIClearPage(LANGUAGE_PAGE);
740
741 SelectedLanguageId = NewLanguageId;
742
743 /* Load the font */
744 SetConsoleCodePage();
745
746 /* Redraw language selection page in native language */
747 MUIDisplayPage(LANGUAGE_PAGE);
748 }
749
750 RefreshPage = FALSE;
751 }
752 }
753
754 return INTRO_PAGE;
755 }
756
757
758 /*
759 * Start page
760 *
761 * Next pages:
762 * LanguagePage (at once, default)
763 * InstallIntroPage (at once, if unattended)
764 * QuitPage
765 *
766 * SIDEEFFECTS
767 * Init Sdi
768 * Init SourcePath
769 * Init SourceRootPath
770 * Init SourceRootDir
771 * Init SetupInf
772 * Init RequiredPartitionDiskSpace
773 * Init IsUnattendedSetup
774 * If unattended, init *List and sets the Codepage
775 *
776 * RETURNS
777 * Number of the next page.
778 */
779 static PAGE_NUMBER
780 SetupStartPage(PINPUT_RECORD Ir)
781 {
782 //SYSTEM_DEVICE_INFORMATION Sdi;
783 NTSTATUS Status;
784 WCHAR FileNameBuffer[MAX_PATH];
785 INFCONTEXT Context;
786 PWCHAR Value;
787 UINT ErrorLine;
788 //ULONG ReturnSize;
789 PGENERIC_LIST_ENTRY ListEntry;
790 INT IntValue;
791
792 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
793
794 #if 0
795 /* Check whether a harddisk is available */
796 Status = NtQuerySystemInformation(SystemDeviceInformation,
797 &Sdi,
798 sizeof(SYSTEM_DEVICE_INFORMATION),
799 &ReturnSize);
800
801 if (!NT_SUCCESS(Status))
802 {
803 CONSOLE_PrintTextXY(6, 15, "NtQuerySystemInformation() failed (Status 0x%08lx)", Status);
804 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
805 return QUIT_PAGE;
806 }
807
808 if (Sdi.NumberOfDisks == 0)
809 {
810 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
811 return QUIT_PAGE;
812 }
813 #endif
814
815 /* Get the source path and source root path */
816 Status = GetSourcePaths(&SourcePath,
817 &SourceRootPath,
818 &SourceRootDir);
819
820 if (!NT_SUCCESS(Status))
821 {
822 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
823 MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
824 return QUIT_PAGE;
825 }
826 #if 0
827 else
828 {
829 CONSOLE_PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
830 CONSOLE_PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
831 CONSOLE_PrintTextXY(6, 17, "SourceRootDir: '%wZ'", &SourceRootDir);
832 }
833 #endif
834
835 /* Load txtsetup.sif from install media. */
836 wcscpy(FileNameBuffer, SourcePath.Buffer);
837 wcscat(FileNameBuffer, L"\\txtsetup.sif");
838
839 SetupInf = SetupOpenInfFileW(FileNameBuffer,
840 NULL,
841 INF_STYLE_WIN4,
842 LanguageId,
843 &ErrorLine);
844
845 if (SetupInf == INVALID_HANDLE_VALUE)
846 {
847 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
848 return QUIT_PAGE;
849 }
850
851 /* Open 'Version' section */
852 if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
853 {
854 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
855 return QUIT_PAGE;
856 }
857
858 /* Get pointer 'Signature' key */
859 if (!INF_GetData(&Context, NULL, &Value))
860 {
861 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
862 return QUIT_PAGE;
863 }
864
865 /* Check 'Signature' string */
866 if (_wcsicmp(Value, L"$ReactOS$") != 0)
867 {
868 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
869 return QUIT_PAGE;
870 }
871
872 /* Open 'DiskSpaceRequirements' section */
873 if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
874 {
875 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
876 return QUIT_PAGE;
877 }
878
879 /* Get the 'FreeSysPartDiskSpace' value */
880 if (!SetupGetIntField(&Context, 1, &IntValue))
881 {
882 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
883 return QUIT_PAGE;
884 }
885
886 RequiredPartitionDiskSpace = (ULONG)IntValue;
887
888 /* Start PnP thread */
889 if (hPnpThread != INVALID_HANDLE_VALUE)
890 {
891 NtResumeThread(hPnpThread, NULL);
892 hPnpThread = INVALID_HANDLE_VALUE;
893 }
894
895 CheckUnattendedSetup();
896
897 if (IsUnattendedSetup)
898 {
899 //TODO
900 //read options from inf
901 ComputerList = CreateComputerTypeList(SetupInf);
902 DisplayList = CreateDisplayDriverList(SetupInf);
903 KeyboardList = CreateKeyboardDriverList(SetupInf);
904 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
905 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
906
907 /* new part */
908 wcscpy(SelectedLanguageId,LocaleID);
909
910 /* first we hack LanguageList */
911 ListEntry = GetFirstListEntry(LanguageList);
912
913 while (ListEntry != NULL)
914 {
915 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
916 {
917 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
918 SetCurrentListEntry(LanguageList, ListEntry);
919 break;
920 }
921
922 ListEntry = GetNextListEntry(ListEntry);
923 }
924
925 /* now LayoutList */
926 ListEntry = GetFirstListEntry(LayoutList);
927
928 while (ListEntry != NULL)
929 {
930 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
931 {
932 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
933 SetCurrentListEntry(LayoutList, ListEntry);
934 break;
935 }
936
937 ListEntry = GetNextListEntry(ListEntry);
938 }
939
940 SetConsoleCodePage();
941
942 return INSTALL_INTRO_PAGE;
943 }
944
945 return LANGUAGE_PAGE;
946 }
947
948
949 /*
950 * Displays the IntroPage.
951 *
952 * Next pages:
953 * InstallIntroPage (default)
954 * RepairIntroPage
955 * LicensePage
956 * QuitPage
957 *
958 * RETURNS
959 * Number of the next page.
960 */
961 static PAGE_NUMBER
962 IntroPage(PINPUT_RECORD Ir)
963 {
964 MUIDisplayPage(START_PAGE);
965
966 while (TRUE)
967 {
968 CONSOLE_ConInKey(Ir);
969
970 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
971 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
972 {
973 if (ConfirmQuit(Ir) == TRUE)
974 return QUIT_PAGE;
975
976 break;
977 }
978 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
979 {
980 return INSTALL_INTRO_PAGE;
981 }
982 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
983 {
984 return REPAIR_INTRO_PAGE;
985 }
986 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* R */
987 {
988 return LICENSE_PAGE;
989 }
990 }
991
992 return INTRO_PAGE;
993 }
994
995
996 /*
997 * Displays the License page.
998 *
999 * Next page:
1000 * IntroPage (default)
1001 *
1002 * RETURNS
1003 * Number of the next page.
1004 */
1005 static PAGE_NUMBER
1006 LicensePage(PINPUT_RECORD Ir)
1007 {
1008 MUIDisplayPage(LICENSE_PAGE);
1009
1010 while (TRUE)
1011 {
1012 CONSOLE_ConInKey(Ir);
1013
1014 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1015 {
1016 return INTRO_PAGE;
1017 }
1018 }
1019
1020 return LICENSE_PAGE;
1021 }
1022
1023
1024 /*
1025 * Displays the RepairIntroPage.
1026 *
1027 * Next pages:
1028 * RebootPage (default)
1029 * InstallIntroPage
1030 * RecoveryPage
1031 * IntroPage
1032 *
1033 * RETURNS
1034 * Number of the next page.
1035 */
1036 static PAGE_NUMBER
1037 RepairIntroPage(PINPUT_RECORD Ir)
1038 {
1039 MUIDisplayPage(REPAIR_INTRO_PAGE);
1040
1041 while(TRUE)
1042 {
1043 CONSOLE_ConInKey(Ir);
1044
1045 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1046 {
1047 return REBOOT_PAGE;
1048 }
1049 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
1050 {
1051 RepairUpdateFlag = TRUE;
1052 return INSTALL_INTRO_PAGE;
1053 }
1054 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
1055 {
1056 return RECOVERY_PAGE;
1057 }
1058 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1059 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1060 {
1061 return INTRO_PAGE;
1062 }
1063 }
1064
1065 return REPAIR_INTRO_PAGE;
1066 }
1067
1068 /*
1069 * Displays the InstallIntroPage.
1070 *
1071 * Next pages:
1072 * DeviceSettingsPage (At once if repair or update is selected)
1073 * SelectPartitionPage (At once if unattended setup)
1074 * DeviceSettingsPage (default)
1075 * QuitPage
1076 *
1077 * RETURNS
1078 * Number of the next page.
1079 */
1080 static PAGE_NUMBER
1081 InstallIntroPage(PINPUT_RECORD Ir)
1082 {
1083 MUIDisplayPage(INSTALL_INTRO_PAGE);
1084
1085 if (RepairUpdateFlag)
1086 {
1087 //return SELECT_PARTITION_PAGE;
1088 return DEVICE_SETTINGS_PAGE;
1089 }
1090
1091 if (IsUnattendedSetup)
1092 {
1093 return SELECT_PARTITION_PAGE;
1094 }
1095
1096 while (TRUE)
1097 {
1098 CONSOLE_ConInKey(Ir);
1099
1100 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1101 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1102 {
1103 if (ConfirmQuit(Ir) == TRUE)
1104 return QUIT_PAGE;
1105
1106 break;
1107 }
1108 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1109 {
1110 return DEVICE_SETTINGS_PAGE;
1111 // return SCSI_CONTROLLER_PAGE;
1112 }
1113 }
1114
1115 return INSTALL_INTRO_PAGE;
1116 }
1117
1118
1119 #if 0
1120 static PAGE_NUMBER
1121 ScsiControllerPage(PINPUT_RECORD Ir)
1122 {
1123 SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1124
1125 /* FIXME: print loaded mass storage driver descriptions */
1126 #if 0
1127 SetTextXY(8, 10, "TEST device");
1128 #endif
1129
1130
1131 SetStatusText(" ENTER = Continue F3 = Quit");
1132
1133 while (TRUE)
1134 {
1135 ConInKey(Ir);
1136
1137 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1138 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1139 {
1140 if (ConfirmQuit(Ir) == TRUE)
1141 return QUIT_PAGE;
1142
1143 break;
1144 }
1145 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1146 {
1147 return DEVICE_SETTINGS_PAGE;
1148 }
1149 }
1150
1151 return SCSI_CONTROLLER_PAGE;
1152 }
1153 #endif
1154
1155
1156 /*
1157 * Displays the DeviceSettingsPage.
1158 *
1159 * Next pages:
1160 * SelectPartitionPage (At once if repair or update is selected)
1161 * ComputerSettingsPage
1162 * DisplaySettingsPage
1163 * KeyboardSettingsPage
1164 * LayoutsettingsPage
1165 * SelectPartitionPage
1166 * QuitPage
1167 *
1168 * SIDEEFFECTS
1169 * Init ComputerList
1170 * Init DisplayList
1171 * Init KeyboardList
1172 * Init LayoutList
1173 *
1174 * RETURNS
1175 * Number of the next page.
1176 */
1177 static PAGE_NUMBER
1178 DeviceSettingsPage(PINPUT_RECORD Ir)
1179 {
1180 static ULONG Line = 16;
1181 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1182
1183 /* Initialize the computer settings list */
1184 if (ComputerList == NULL)
1185 {
1186 ComputerList = CreateComputerTypeList(SetupInf);
1187 if (ComputerList == NULL)
1188 {
1189 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1190 return QUIT_PAGE;
1191 }
1192 }
1193
1194 /* Initialize the display settings list */
1195 if (DisplayList == NULL)
1196 {
1197 DisplayList = CreateDisplayDriverList(SetupInf);
1198 if (DisplayList == NULL)
1199 {
1200 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1201 return QUIT_PAGE;
1202 }
1203 }
1204
1205 /* Initialize the keyboard settings list */
1206 if (KeyboardList == NULL)
1207 {
1208 KeyboardList = CreateKeyboardDriverList(SetupInf);
1209 if (KeyboardList == NULL)
1210 {
1211 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1212 return QUIT_PAGE;
1213 }
1214 }
1215
1216 /* Initialize the keyboard layout list */
1217 if (LayoutList == NULL)
1218 {
1219 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
1220 if (LayoutList == NULL)
1221 {
1222 /* FIXME: report error */
1223 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1224 return QUIT_PAGE;
1225 }
1226 }
1227
1228 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1229
1230
1231 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry((ComputerList))));
1232 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry((DisplayList))));
1233 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry((KeyboardList))));
1234 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry((LayoutList))));
1235
1236 CONSOLE_InvertTextXY(24, Line, 48, 1);
1237
1238 if (RepairUpdateFlag)
1239 {
1240 return SELECT_PARTITION_PAGE;
1241 }
1242
1243 while (TRUE)
1244 {
1245 CONSOLE_ConInKey(Ir);
1246
1247 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1248 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1249 {
1250 CONSOLE_NormalTextXY(24, Line, 48, 1);
1251
1252 if (Line == 14)
1253 Line = 16;
1254 else if (Line == 16)
1255 Line = 11;
1256 else
1257 Line++;
1258
1259 CONSOLE_InvertTextXY(24, Line, 48, 1);
1260 }
1261 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1262 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1263 {
1264 CONSOLE_NormalTextXY(24, Line, 48, 1);
1265
1266 if (Line == 11)
1267 Line = 16;
1268 else if (Line == 16)
1269 Line = 14;
1270 else
1271 Line--;
1272
1273 CONSOLE_InvertTextXY(24, Line, 48, 1);
1274 }
1275 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1276 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1277 {
1278 if (ConfirmQuit(Ir) == TRUE)
1279 return QUIT_PAGE;
1280
1281 break;
1282 }
1283 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1284 {
1285 if (Line == 11)
1286 return COMPUTER_SETTINGS_PAGE;
1287 else if (Line == 12)
1288 return DISPLAY_SETTINGS_PAGE;
1289 else if (Line == 13)
1290 return KEYBOARD_SETTINGS_PAGE;
1291 else if (Line == 14)
1292 return LAYOUT_SETTINGS_PAGE;
1293 else if (Line == 16)
1294 return SELECT_PARTITION_PAGE;
1295 }
1296 }
1297
1298 return DEVICE_SETTINGS_PAGE;
1299 }
1300
1301
1302 /*
1303 * Handles generic selection lists.
1304 *
1305 * PARAMS
1306 * GenericList: The list to handle.
1307 * nextPage: The page it needs to jump to after this page.
1308 * Ir: The PINPUT_RECORD
1309 */
1310 static PAGE_NUMBER
1311 HandleGenericList(PGENERIC_LIST GenericList,
1312 PAGE_NUMBER nextPage,
1313 PINPUT_RECORD Ir)
1314 {
1315 while (TRUE)
1316 {
1317 CONSOLE_ConInKey(Ir);
1318
1319 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1320 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1321 {
1322 ScrollDownGenericList(GenericList);
1323 }
1324 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1325 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1326 {
1327 ScrollUpGenericList(GenericList);
1328 }
1329 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1330 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1331 {
1332 ScrollPageDownGenericList(GenericList);
1333 }
1334 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1335 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1336 {
1337 ScrollPageUpGenericList(GenericList);
1338 }
1339 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1340 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1341 {
1342 if (ConfirmQuit(Ir) == TRUE)
1343 return QUIT_PAGE;
1344
1345 continue;
1346 }
1347 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1348 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1349 {
1350 RestoreGenericListState(GenericList);
1351 return nextPage;
1352 }
1353 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1354 {
1355 return nextPage;
1356 }
1357 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1358 {
1359 /* a-z */
1360 GenericListKeyPress(GenericList, Ir->Event.KeyEvent.uChar.AsciiChar);
1361 }
1362 }
1363 }
1364
1365
1366 /*
1367 * Displays the ComputerSettingsPage.
1368 *
1369 * Next pages:
1370 * DeviceSettingsPage
1371 * QuitPage
1372 *
1373 * RETURNS
1374 * Number of the next page.
1375 */
1376 static PAGE_NUMBER
1377 ComputerSettingsPage(PINPUT_RECORD Ir)
1378 {
1379 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1380
1381 DrawGenericList(ComputerList,
1382 2,
1383 18,
1384 xScreen - 3,
1385 yScreen - 3);
1386
1387 SaveGenericListState(ComputerList);
1388
1389 return HandleGenericList(ComputerList, DEVICE_SETTINGS_PAGE, Ir);
1390 }
1391
1392
1393 /*
1394 * Displays the DisplaySettingsPage.
1395 *
1396 * Next pages:
1397 * DeviceSettingsPage
1398 * QuitPage
1399 *
1400 * RETURNS
1401 * Number of the next page.
1402 */
1403 static PAGE_NUMBER
1404 DisplaySettingsPage(PINPUT_RECORD Ir)
1405 {
1406 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1407
1408 DrawGenericList(DisplayList,
1409 2,
1410 18,
1411 xScreen - 3,
1412 yScreen - 3);
1413
1414 SaveGenericListState(DisplayList);
1415
1416 return HandleGenericList(DisplayList, DEVICE_SETTINGS_PAGE, Ir);
1417 }
1418
1419
1420 /*
1421 * Displays the KeyboardSettingsPage.
1422 *
1423 * Next pages:
1424 * DeviceSettingsPage
1425 * QuitPage
1426 *
1427 * RETURNS
1428 * Number of the next page.
1429 */
1430 static PAGE_NUMBER
1431 KeyboardSettingsPage(PINPUT_RECORD Ir)
1432 {
1433 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1434
1435 DrawGenericList(KeyboardList,
1436 2,
1437 18,
1438 xScreen - 3,
1439 yScreen - 3);
1440
1441 SaveGenericListState(KeyboardList);
1442
1443 return HandleGenericList(KeyboardList, DEVICE_SETTINGS_PAGE, Ir);
1444 }
1445
1446
1447 /*
1448 * Displays the LayoutSettingsPage.
1449 *
1450 * Next pages:
1451 * DeviceSettingsPage
1452 * QuitPage
1453 *
1454 * RETURNS
1455 * Number of the next page.
1456 */
1457 static PAGE_NUMBER
1458 LayoutSettingsPage(PINPUT_RECORD Ir)
1459 {
1460 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1461
1462 DrawGenericList(LayoutList,
1463 2,
1464 18,
1465 xScreen - 3,
1466 yScreen - 3);
1467
1468 SaveGenericListState(LayoutList);
1469
1470 return HandleGenericList(LayoutList, DEVICE_SETTINGS_PAGE, Ir);
1471 }
1472
1473
1474 static BOOL
1475 IsDiskSizeValid(PPARTENTRY PartEntry)
1476 {
1477 ULONGLONG size;
1478
1479 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1480 size = (size + 524288) / 1048576; /* in MBytes */
1481
1482 if (size < RequiredPartitionDiskSpace)
1483 {
1484 /* partition is too small so ask for another partion */
1485 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, RequiredPartitionDiskSpace);
1486 return FALSE;
1487 }
1488 else
1489 {
1490 return TRUE;
1491 }
1492 }
1493
1494
1495 /*
1496 * Displays the SelectPartitionPage.
1497 *
1498 * Next pages:
1499 * SelectFileSystemPage (At once if unattended)
1500 * SelectFileSystemPage (Default if free space is selected)
1501 * CreatePrimaryPartitionPage
1502 * CreateExtendedPartitionPage
1503 * CreateLogicalPartitionPage
1504 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1505 * DeletePartitionPage
1506 * QuitPage
1507 *
1508 * SIDEEFFECTS
1509 * Init DestinationDriveLetter (only if unattended or not free space is selected)
1510 * Set InstallShortcut (only if not unattended + free space is selected)
1511 *
1512 * RETURNS
1513 * Number of the next page.
1514 */
1515 static PAGE_NUMBER
1516 SelectPartitionPage(PINPUT_RECORD Ir)
1517 {
1518 ULONG Error;
1519
1520 MUIDisplayPage(SELECT_PARTITION_PAGE);
1521
1522 if (PartitionList == NULL)
1523 {
1524 PartitionList = CreatePartitionList(2,
1525 23,
1526 xScreen - 3,
1527 yScreen - 3);
1528 if (PartitionList == NULL)
1529 {
1530 /* FIXME: show an error dialog */
1531 return QUIT_PAGE;
1532 }
1533 else if (IsListEmpty(&PartitionList->DiskListHead))
1534 {
1535 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1536 return QUIT_PAGE;
1537 }
1538 }
1539
1540 DrawPartitionList(PartitionList);
1541
1542 if (IsUnattendedSetup)
1543 {
1544 if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
1545 {
1546 if (AutoPartition)
1547 {
1548 if (PartitionList->CurrentPartition->LogicalPartition)
1549 {
1550 CreateLogicalPartition(PartitionList,
1551 PartitionList->CurrentPartition->SectorCount.QuadPart,
1552 TRUE);
1553 }
1554 else
1555 {
1556 CreatePrimaryPartition(PartitionList,
1557 PartitionList->CurrentPartition->SectorCount.QuadPart,
1558 TRUE);
1559 }
1560
1561 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1562 {
1563 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1564 RequiredPartitionDiskSpace);
1565 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1566 }
1567
1568 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1569
1570 return SELECT_FILE_SYSTEM_PAGE;
1571 }
1572 }
1573 else
1574 {
1575 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1576 {
1577 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1578 RequiredPartitionDiskSpace);
1579 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1580 }
1581
1582 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1583
1584 return SELECT_FILE_SYSTEM_PAGE;
1585 }
1586 }
1587
1588 while (TRUE)
1589 {
1590 /* Update status text */
1591 if (PartitionList->CurrentPartition == NULL)
1592 {
1593 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1594 }
1595 else if (PartitionList->CurrentPartition->LogicalPartition)
1596 {
1597 if (PartitionList->CurrentPartition->IsPartitioned)
1598 {
1599 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1600 }
1601 else
1602 {
1603 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1604 }
1605 }
1606 else
1607 {
1608 if (PartitionList->CurrentPartition->IsPartitioned)
1609 {
1610 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1611 {
1612 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1613 }
1614 else
1615 {
1616 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1617 }
1618 }
1619 else
1620 {
1621 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1622 }
1623 }
1624
1625 CONSOLE_ConInKey(Ir);
1626
1627 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1628 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1629 {
1630 if (ConfirmQuit(Ir) == TRUE)
1631 {
1632 DestroyPartitionList(PartitionList);
1633 PartitionList = NULL;
1634 return QUIT_PAGE;
1635 }
1636
1637 break;
1638 }
1639 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1640 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1641 {
1642 if (ScrollDownPartitionList(PartitionList))
1643 DrawPartitionList(PartitionList);
1644 }
1645 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1646 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1647 {
1648 if (ScrollUpPartitionList(PartitionList))
1649 DrawPartitionList(PartitionList);
1650 }
1651 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1652 {
1653 if (IsContainerPartition(PartitionList->CurrentPartition->PartitionType))
1654 continue; //return SELECT_PARTITION_PAGE;
1655
1656 if (PartitionList->CurrentPartition == NULL ||
1657 PartitionList->CurrentPartition->IsPartitioned == FALSE)
1658 {
1659 if (PartitionList->CurrentPartition->LogicalPartition)
1660 {
1661 CreateLogicalPartition(PartitionList,
1662 0ULL,
1663 TRUE);
1664 }
1665 else
1666 {
1667 CreatePrimaryPartition(PartitionList,
1668 0ULL,
1669 TRUE);
1670 }
1671 }
1672
1673 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1674 {
1675 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1676 RequiredPartitionDiskSpace);
1677 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1678 }
1679
1680 DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
1681
1682 return SELECT_FILE_SYSTEM_PAGE;
1683 }
1684 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1685 {
1686 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1687 {
1688 Error = PrimaryPartitionCreationChecks(PartitionList);
1689 if (Error != NOT_AN_ERROR)
1690 {
1691 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1692 return SELECT_PARTITION_PAGE;
1693 }
1694
1695 return CREATE_PRIMARY_PARTITION_PAGE;
1696 }
1697 }
1698 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1699 {
1700 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1701 {
1702 Error = ExtendedPartitionCreationChecks(PartitionList);
1703 if (Error != NOT_AN_ERROR)
1704 {
1705 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1706 return SELECT_PARTITION_PAGE;
1707 }
1708
1709 return CREATE_EXTENDED_PARTITION_PAGE;
1710 }
1711 }
1712 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1713 {
1714 if (PartitionList->CurrentPartition->LogicalPartition == TRUE)
1715 {
1716 Error = LogicalPartitionCreationChecks(PartitionList);
1717 if (Error != NOT_AN_ERROR)
1718 {
1719 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1720 return SELECT_PARTITION_PAGE;
1721 }
1722
1723 return CREATE_LOGICAL_PARTITION_PAGE;
1724 }
1725 }
1726 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1727 {
1728 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1729 {
1730 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1731 return SELECT_PARTITION_PAGE;
1732 }
1733
1734 if (PartitionList->CurrentPartition->BootIndicator)
1735 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1736
1737 return DELETE_PARTITION_PAGE;
1738 }
1739 }
1740
1741 return SELECT_PARTITION_PAGE;
1742 }
1743
1744
1745 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 6
1746 /* Restriction for MaxSize: pow(10, PARTITION_SIZE_INPUT_FIELD_LENGTH)-1 */
1747 #define PARTITION_MAXSIZE 999999
1748
1749 static VOID
1750 ShowPartitionSizeInputBox(SHORT Left,
1751 SHORT Top,
1752 SHORT Right,
1753 SHORT Bottom,
1754 ULONG MaxSize,
1755 PCHAR InputBuffer,
1756 PBOOLEAN Quit,
1757 PBOOLEAN Cancel)
1758 {
1759 INPUT_RECORD Ir;
1760 COORD coPos;
1761 DWORD Written;
1762 CHAR Buffer[128];
1763 WCHAR PartitionSizeBuffer[100];
1764 ULONG Index;
1765 WCHAR ch;
1766 SHORT iLeft;
1767 SHORT iTop;
1768
1769 if (Quit != NULL)
1770 *Quit = FALSE;
1771
1772 if (Cancel != NULL)
1773 *Cancel = FALSE;
1774
1775 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1776
1777 /* Print message */
1778 coPos.X = Left + 2;
1779 coPos.Y = Top + 2;
1780 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1781 iLeft = coPos.X + strlen(Buffer) + 1;
1782 iTop = coPos.Y;
1783
1784 WriteConsoleOutputCharacterA(StdOutput,
1785 Buffer,
1786 strlen(Buffer),
1787 coPos,
1788 &Written);
1789
1790 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1791 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1792 coPos.Y = iTop;
1793 WriteConsoleOutputCharacterA(StdOutput,
1794 Buffer,
1795 strlen(Buffer),
1796 coPos,
1797 &Written);
1798
1799 swprintf(PartitionSizeBuffer, L"%lu", MaxSize);
1800 Index = wcslen(PartitionSizeBuffer);
1801 CONSOLE_SetInputTextXY(iLeft,
1802 iTop,
1803 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1804 PartitionSizeBuffer);
1805
1806 while (TRUE)
1807 {
1808 CONSOLE_ConInKey(&Ir);
1809
1810 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1811 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1812 {
1813 if (Quit != NULL)
1814 *Quit = TRUE;
1815
1816 PartitionSizeBuffer[0] = 0;
1817 break;
1818 }
1819 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1820 {
1821 break;
1822 }
1823 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1824 {
1825 if (Cancel != NULL)
1826 *Cancel = TRUE;
1827
1828 PartitionSizeBuffer[0] = 0;
1829 break;
1830 }
1831 else if ((Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) && /* BACKSPACE */
1832 (Index > 0))
1833 {
1834 Index--;
1835 PartitionSizeBuffer[Index] = 0;
1836
1837 CONSOLE_SetInputTextXY(iLeft,
1838 iTop,
1839 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1840 PartitionSizeBuffer);
1841 }
1842 else if ((Ir.Event.KeyEvent.uChar.AsciiChar != 0x00) &&
1843 (Index < PARTITION_SIZE_INPUT_FIELD_LENGTH))
1844 {
1845 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1846
1847 if ((ch >= L'0') && (ch <= L'9'))
1848 {
1849 PartitionSizeBuffer[Index] = ch;
1850 Index++;
1851 PartitionSizeBuffer[Index] = 0;
1852
1853 CONSOLE_SetInputTextXY(iLeft,
1854 iTop,
1855 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1856 PartitionSizeBuffer);
1857 }
1858 }
1859 }
1860
1861 /* Convert UNICODE --> ANSI the poor man's way */
1862 sprintf(InputBuffer, "%S", PartitionSizeBuffer);
1863 }
1864
1865
1866 /*
1867 * Displays the CreatePrimaryPartitionPage.
1868 *
1869 * Next pages:
1870 * SelectPartitionPage
1871 * SelectFileSystemPage (default)
1872 * QuitPage
1873 *
1874 * RETURNS
1875 * Number of the next page.
1876 */
1877 static PAGE_NUMBER
1878 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1879 {
1880 PDISKENTRY DiskEntry;
1881 PPARTENTRY PartEntry;
1882 BOOLEAN Quit;
1883 BOOLEAN Cancel;
1884 CHAR InputBuffer[50];
1885 ULONG MaxSize;
1886 ULONGLONG PartSize;
1887 ULONGLONG DiskSize;
1888 ULONGLONG SectorCount;
1889 PCHAR Unit;
1890
1891 if (PartitionList == NULL ||
1892 PartitionList->CurrentDisk == NULL ||
1893 PartitionList->CurrentPartition == NULL)
1894 {
1895 /* FIXME: show an error dialog */
1896 return QUIT_PAGE;
1897 }
1898
1899 DiskEntry = PartitionList->CurrentDisk;
1900 PartEntry = PartitionList->CurrentPartition;
1901
1902 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1903
1904 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1905
1906 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1907 #if 0
1908 if (DiskSize >= 10737418240) /* 10 GB */
1909 {
1910 DiskSize = DiskSize / 1073741824;
1911 Unit = MUIGetString(STRING_GB);
1912 }
1913 else
1914 #endif
1915 {
1916 DiskSize = DiskSize / 1048576;
1917 if (DiskSize == 0)
1918 DiskSize = 1;
1919
1920 Unit = MUIGetString(STRING_MB);
1921 }
1922
1923 if (DiskEntry->DriverName.Length > 0)
1924 {
1925 CONSOLE_PrintTextXY(6, 10,
1926 MUIGetString(STRING_HDINFOPARTCREATE),
1927 DiskSize,
1928 Unit,
1929 DiskEntry->DiskNumber,
1930 DiskEntry->Port,
1931 DiskEntry->Bus,
1932 DiskEntry->Id,
1933 &DiskEntry->DriverName);
1934 }
1935 else
1936 {
1937 CONSOLE_PrintTextXY(6, 10,
1938 MUIGetString(STRING_HDDINFOUNK1),
1939 DiskSize,
1940 Unit,
1941 DiskEntry->DiskNumber,
1942 DiskEntry->Port,
1943 DiskEntry->Bus,
1944 DiskEntry->Id);
1945 }
1946
1947 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
1948
1949 #if 0
1950 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
1951 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
1952 #endif
1953
1954 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
1955
1956 PartEntry = PartitionList->CurrentPartition;
1957 while (TRUE)
1958 {
1959 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
1960
1961 if (MaxSize > PARTITION_MAXSIZE)
1962 MaxSize = PARTITION_MAXSIZE;
1963
1964 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
1965 MaxSize, InputBuffer, &Quit, &Cancel);
1966
1967 if (Quit == TRUE)
1968 {
1969 if (ConfirmQuit(Ir) == TRUE)
1970 return QUIT_PAGE;
1971 }
1972 else if (Cancel == TRUE)
1973 {
1974 return SELECT_PARTITION_PAGE;
1975 }
1976 else
1977 {
1978 PartSize = atoi(InputBuffer);
1979
1980 if (PartSize < 1)
1981 {
1982 /* Too small */
1983 continue;
1984 }
1985
1986 if (PartSize > MaxSize)
1987 {
1988 /* Too large */
1989 continue;
1990 }
1991
1992 /* Convert to bytes */
1993 if (PartSize == MaxSize)
1994 {
1995 /* Use all of the unpartitioned disk space */
1996 SectorCount = PartEntry->SectorCount.QuadPart;
1997 }
1998 else
1999 {
2000 /* Calculate the sector count from the size in MB */
2001 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2002
2003 /* But never get larger than the unpartitioned disk space */
2004 if (SectorCount > PartEntry->SectorCount.QuadPart)
2005 SectorCount = PartEntry->SectorCount.QuadPart;
2006 }
2007
2008 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2009
2010 CreatePrimaryPartition(PartitionList,
2011 SectorCount,
2012 FALSE);
2013
2014 return SELECT_PARTITION_PAGE;
2015 }
2016 }
2017
2018 return CREATE_PRIMARY_PARTITION_PAGE;
2019 }
2020
2021
2022 /*
2023 * Displays the CreateExtendedPartitionPage.
2024 *
2025 * Next pages:
2026 * SelectPartitionPage (default)
2027 * QuitPage
2028 *
2029 * RETURNS
2030 * Number of the next page.
2031 */
2032 static PAGE_NUMBER
2033 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2034 {
2035 PDISKENTRY DiskEntry;
2036 PPARTENTRY PartEntry;
2037 BOOLEAN Quit;
2038 BOOLEAN Cancel;
2039 CHAR InputBuffer[50];
2040 ULONG MaxSize;
2041 ULONGLONG PartSize;
2042 ULONGLONG DiskSize;
2043 ULONGLONG SectorCount;
2044 PCHAR Unit;
2045
2046 if (PartitionList == NULL ||
2047 PartitionList->CurrentDisk == NULL ||
2048 PartitionList->CurrentPartition == NULL)
2049 {
2050 /* FIXME: show an error dialog */
2051 return QUIT_PAGE;
2052 }
2053
2054 DiskEntry = PartitionList->CurrentDisk;
2055 PartEntry = PartitionList->CurrentPartition;
2056
2057 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2058
2059 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2060
2061 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2062 #if 0
2063 if (DiskSize >= 10737418240) /* 10 GB */
2064 {
2065 DiskSize = DiskSize / 1073741824;
2066 Unit = MUIGetString(STRING_GB);
2067 }
2068 else
2069 #endif
2070 {
2071 DiskSize = DiskSize / 1048576;
2072 if (DiskSize == 0)
2073 DiskSize = 1;
2074
2075 Unit = MUIGetString(STRING_MB);
2076 }
2077
2078 if (DiskEntry->DriverName.Length > 0)
2079 {
2080 CONSOLE_PrintTextXY(6, 10,
2081 MUIGetString(STRING_HDINFOPARTCREATE),
2082 DiskSize,
2083 Unit,
2084 DiskEntry->DiskNumber,
2085 DiskEntry->Port,
2086 DiskEntry->Bus,
2087 DiskEntry->Id,
2088 &DiskEntry->DriverName);
2089 }
2090 else
2091 {
2092 CONSOLE_PrintTextXY(6, 10,
2093 MUIGetString(STRING_HDDINFOUNK1),
2094 DiskSize,
2095 Unit,
2096 DiskEntry->DiskNumber,
2097 DiskEntry->Port,
2098 DiskEntry->Bus,
2099 DiskEntry->Id);
2100 }
2101
2102 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2103
2104 #if 0
2105 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2106 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2107 #endif
2108
2109 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2110
2111 PartEntry = PartitionList->CurrentPartition;
2112 while (TRUE)
2113 {
2114 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2115
2116 if (MaxSize > PARTITION_MAXSIZE)
2117 MaxSize = PARTITION_MAXSIZE;
2118
2119 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2120 MaxSize, InputBuffer, &Quit, &Cancel);
2121
2122 if (Quit == TRUE)
2123 {
2124 if (ConfirmQuit(Ir) == TRUE)
2125 return QUIT_PAGE;
2126 }
2127 else if (Cancel == TRUE)
2128 {
2129 return SELECT_PARTITION_PAGE;
2130 }
2131 else
2132 {
2133 PartSize = atoi(InputBuffer);
2134
2135 if (PartSize < 1)
2136 {
2137 /* Too small */
2138 continue;
2139 }
2140
2141 if (PartSize > MaxSize)
2142 {
2143 /* Too large */
2144 continue;
2145 }
2146
2147 /* Convert to bytes */
2148 if (PartSize == MaxSize)
2149 {
2150 /* Use all of the unpartitioned disk space */
2151 SectorCount = PartEntry->SectorCount.QuadPart;
2152 }
2153 else
2154 {
2155 /* Calculate the sector count from the size in MB */
2156 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2157
2158 /* But never get larger than the unpartitioned disk space */
2159 if (SectorCount > PartEntry->SectorCount.QuadPart)
2160 SectorCount = PartEntry->SectorCount.QuadPart;
2161 }
2162
2163 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2164
2165 CreateExtendedPartition(PartitionList,
2166 SectorCount);
2167
2168 return SELECT_PARTITION_PAGE;
2169 }
2170 }
2171
2172 return CREATE_EXTENDED_PARTITION_PAGE;
2173 }
2174
2175
2176 /*
2177 * Displays the CreateLogicalPartitionPage.
2178 *
2179 * Next pages:
2180 * SelectFileSystemPage (default)
2181 * QuitPage
2182 *
2183 * RETURNS
2184 * Number of the next page.
2185 */
2186 static PAGE_NUMBER
2187 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2188 {
2189 PDISKENTRY DiskEntry;
2190 PPARTENTRY PartEntry;
2191 BOOLEAN Quit;
2192 BOOLEAN Cancel;
2193 CHAR InputBuffer[50];
2194 ULONG MaxSize;
2195 ULONGLONG PartSize;
2196 ULONGLONG DiskSize;
2197 ULONGLONG SectorCount;
2198 PCHAR Unit;
2199
2200 if (PartitionList == NULL ||
2201 PartitionList->CurrentDisk == NULL ||
2202 PartitionList->CurrentPartition == NULL)
2203 {
2204 /* FIXME: show an error dialog */
2205 return QUIT_PAGE;
2206 }
2207
2208 DiskEntry = PartitionList->CurrentDisk;
2209 PartEntry = PartitionList->CurrentPartition;
2210
2211 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2212
2213 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2214
2215 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2216 #if 0
2217 if (DiskSize >= 10737418240) /* 10 GB */
2218 {
2219 DiskSize = DiskSize / 1073741824;
2220 Unit = MUIGetString(STRING_GB);
2221 }
2222 else
2223 #endif
2224 {
2225 DiskSize = DiskSize / 1048576;
2226 if (DiskSize == 0)
2227 DiskSize = 1;
2228
2229 Unit = MUIGetString(STRING_MB);
2230 }
2231
2232 if (DiskEntry->DriverName.Length > 0)
2233 {
2234 CONSOLE_PrintTextXY(6, 10,
2235 MUIGetString(STRING_HDINFOPARTCREATE),
2236 DiskSize,
2237 Unit,
2238 DiskEntry->DiskNumber,
2239 DiskEntry->Port,
2240 DiskEntry->Bus,
2241 DiskEntry->Id,
2242 &DiskEntry->DriverName);
2243 }
2244 else
2245 {
2246 CONSOLE_PrintTextXY(6, 10,
2247 MUIGetString(STRING_HDDINFOUNK1),
2248 DiskSize,
2249 Unit,
2250 DiskEntry->DiskNumber,
2251 DiskEntry->Port,
2252 DiskEntry->Bus,
2253 DiskEntry->Id);
2254 }
2255
2256 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2257
2258 #if 0
2259 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2260 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
2261 #endif
2262
2263 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2264
2265 PartEntry = PartitionList->CurrentPartition;
2266 while (TRUE)
2267 {
2268 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576; /* in MBytes (rounded) */
2269
2270 if (MaxSize > PARTITION_MAXSIZE)
2271 MaxSize = PARTITION_MAXSIZE;
2272
2273 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2274 MaxSize, InputBuffer, &Quit, &Cancel);
2275
2276 if (Quit == TRUE)
2277 {
2278 if (ConfirmQuit(Ir) == TRUE)
2279 return QUIT_PAGE;
2280 }
2281 else if (Cancel == TRUE)
2282 {
2283 return SELECT_PARTITION_PAGE;
2284 }
2285 else
2286 {
2287 PartSize = atoi(InputBuffer);
2288
2289 if (PartSize < 1)
2290 {
2291 /* Too small */
2292 continue;
2293 }
2294
2295 if (PartSize > MaxSize)
2296 {
2297 /* Too large */
2298 continue;
2299 }
2300
2301 /* Convert to bytes */
2302 if (PartSize == MaxSize)
2303 {
2304 /* Use all of the unpartitioned disk space */
2305 SectorCount = PartEntry->SectorCount.QuadPart;
2306 }
2307 else
2308 {
2309 /* Calculate the sector count from the size in MB */
2310 SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
2311
2312 /* But never get larger than the unpartitioned disk space */
2313 if (SectorCount > PartEntry->SectorCount.QuadPart)
2314 SectorCount = PartEntry->SectorCount.QuadPart;
2315 }
2316
2317 DPRINT("Partition size: %I64u bytes\n", PartSize);
2318
2319 CreateLogicalPartition(PartitionList,
2320 SectorCount,
2321 FALSE);
2322
2323 return SELECT_PARTITION_PAGE;
2324 }
2325 }
2326
2327 return CREATE_LOGICAL_PARTITION_PAGE;
2328 }
2329
2330
2331 /*
2332 * Displays the ConfirmDeleteSystemPartitionPage.
2333 *
2334 * Next pages:
2335 * DeletePartitionPage (default)
2336 * SelectPartitionPage
2337 *
2338 * RETURNS
2339 * Number of the next page.
2340 */
2341 static PAGE_NUMBER
2342 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2343 {
2344 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2345
2346 while (TRUE)
2347 {
2348 CONSOLE_ConInKey(Ir);
2349
2350 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2351 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2352 {
2353 if (ConfirmQuit(Ir) == TRUE)
2354 return QUIT_PAGE;
2355
2356 break;
2357 }
2358 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2359 {
2360 return DELETE_PARTITION_PAGE;
2361 }
2362 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2363 {
2364 return SELECT_PARTITION_PAGE;
2365 }
2366 }
2367
2368 return SELECT_PARTITION_PAGE;
2369 }
2370
2371
2372 /*
2373 * Displays the DeletePartitionPage.
2374 *
2375 * Next pages:
2376 * SelectPartitionPage (default)
2377 * QuitPage
2378 *
2379 * RETURNS
2380 * Number of the next page.
2381 */
2382 static PAGE_NUMBER
2383 DeletePartitionPage(PINPUT_RECORD Ir)
2384 {
2385 PDISKENTRY DiskEntry;
2386 PPARTENTRY PartEntry;
2387 ULONGLONG DiskSize;
2388 ULONGLONG PartSize;
2389 PCHAR Unit;
2390 CHAR PartType[32];
2391
2392 if (PartitionList == NULL ||
2393 PartitionList->CurrentDisk == NULL ||
2394 PartitionList->CurrentPartition == NULL)
2395 {
2396 /* FIXME: show an error dialog */
2397 return QUIT_PAGE;
2398 }
2399
2400 DiskEntry = PartitionList->CurrentDisk;
2401 PartEntry = PartitionList->CurrentPartition;
2402
2403 MUIDisplayPage(DELETE_PARTITION_PAGE);
2404
2405 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, PartType, 30);
2406
2407 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2408 #if 0
2409 if (PartSize >= 10737418240) /* 10 GB */
2410 {
2411 PartSize = PartSize / 1073741824;
2412 Unit = MUIGetString(STRING_GB);
2413 }
2414 else
2415 #endif
2416 if (PartSize >= 10485760) /* 10 MB */
2417 {
2418 PartSize = PartSize / 1048576;
2419 Unit = MUIGetString(STRING_MB);
2420 }
2421 else
2422 {
2423 PartSize = PartSize / 1024;
2424 Unit = MUIGetString(STRING_KB);
2425 }
2426
2427 if (PartType == NULL)
2428 {
2429 CONSOLE_PrintTextXY(6, 10,
2430 MUIGetString(STRING_HDDINFOUNK2),
2431 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2432 (PartEntry->DriveLetter == 0) ? '-' : ':',
2433 PartEntry->PartitionType,
2434 PartSize,
2435 Unit);
2436 }
2437 else
2438 {
2439 CONSOLE_PrintTextXY(6, 10,
2440 " %c%c %s %I64u %s",
2441 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2442 (PartEntry->DriveLetter == 0) ? '-' : ':',
2443 PartType,
2444 PartSize,
2445 Unit);
2446 }
2447
2448 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2449 #if 0
2450 if (DiskSize >= 10737418240) /* 10 GB */
2451 {
2452 DiskSize = DiskSize / 1073741824;
2453 Unit = MUIGetString(STRING_GB);
2454 }
2455 else
2456 #endif
2457 {
2458 DiskSize = DiskSize / 1048576;
2459 if (DiskSize == 0)
2460 DiskSize = 1;
2461
2462 Unit = MUIGetString(STRING_MB);
2463 }
2464
2465 if (DiskEntry->DriverName.Length > 0)
2466 {
2467 CONSOLE_PrintTextXY(6, 12,
2468 MUIGetString(STRING_HDINFOPARTDELETE),
2469 DiskSize,
2470 Unit,
2471 DiskEntry->DiskNumber,
2472 DiskEntry->Port,
2473 DiskEntry->Bus,
2474 DiskEntry->Id,
2475 &DiskEntry->DriverName);
2476 }
2477 else
2478 {
2479 CONSOLE_PrintTextXY(6, 12,
2480 MUIGetString(STRING_HDDINFOUNK3),
2481 DiskSize,
2482 Unit,
2483 DiskEntry->DiskNumber,
2484 DiskEntry->Port,
2485 DiskEntry->Bus,
2486 DiskEntry->Id);
2487 }
2488
2489 while (TRUE)
2490 {
2491 CONSOLE_ConInKey(Ir);
2492
2493 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2494 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2495 {
2496 if (ConfirmQuit(Ir) == TRUE)
2497 return QUIT_PAGE;
2498
2499 break;
2500 }
2501 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2502 {
2503 return SELECT_PARTITION_PAGE;
2504 }
2505 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2506 {
2507 DeleteCurrentPartition(PartitionList);
2508
2509 return SELECT_PARTITION_PAGE;
2510 }
2511 }
2512
2513 return DELETE_PARTITION_PAGE;
2514 }
2515
2516
2517 /*
2518 * Displays the SelectFileSystemPage.
2519 *
2520 * Next pages:
2521 * CheckFileSystemPage (At once if RepairUpdate is selected)
2522 * CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
2523 * FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
2524 * SelectPartitionPage (If the user aborts)
2525 * FormatPartitionPage (Default)
2526 * QuitPage
2527 *
2528 * SIDEEFFECTS
2529 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2530 * Calls CheckActiveSystemPartition()
2531 *
2532 * RETURNS
2533 * Number of the next page.
2534 */
2535 static PAGE_NUMBER
2536 SelectFileSystemPage(PINPUT_RECORD Ir)
2537 {
2538 PDISKENTRY DiskEntry;
2539 PPARTENTRY PartEntry;
2540 ULONGLONG DiskSize;
2541 ULONGLONG PartSize;
2542 PCHAR DiskUnit;
2543 PCHAR PartUnit;
2544 CHAR PartTypeString[32];
2545
2546 DPRINT("SelectFileSystemPage()\n");
2547
2548 if (PartitionList == NULL ||
2549 PartitionList->CurrentDisk == NULL ||
2550 PartitionList->CurrentPartition == NULL)
2551 {
2552 /* FIXME: show an error dialog */
2553 return QUIT_PAGE;
2554 }
2555
2556 /* Find or set the active system partition */
2557 CheckActiveSystemPartition(PartitionList);
2558
2559 if (PartitionList->SystemDisk == NULL ||
2560 PartitionList->SystemPartition == NULL)
2561 {
2562 /* FIXME: show an error dialog */
2563 return QUIT_PAGE;
2564 }
2565
2566 switch (PartitionList->FormatState)
2567 {
2568 case Start:
2569 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2570 {
2571 PartitionList->TempDisk = PartitionList->SystemDisk;
2572 PartitionList->TempPartition = PartitionList->SystemPartition;
2573 PartitionList->TempPartition->NeedsCheck = TRUE;
2574
2575 PartitionList->FormatState = FormatSystemPartition;
2576 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2577 }
2578 else
2579 {
2580 PartitionList->TempDisk = PartitionList->CurrentDisk;
2581 PartitionList->TempPartition = PartitionList->CurrentPartition;
2582 PartitionList->TempPartition->NeedsCheck = TRUE;
2583
2584 PartitionList->FormatState = FormatInstallPartition;
2585 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2586 }
2587 break;
2588
2589 case FormatSystemPartition:
2590 PartitionList->TempDisk = PartitionList->CurrentDisk;
2591 PartitionList->TempPartition = PartitionList->CurrentPartition;
2592 PartitionList->TempPartition->NeedsCheck = TRUE;
2593
2594 PartitionList->FormatState = FormatInstallPartition;
2595 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2596 break;
2597
2598 case FormatInstallPartition:
2599 if (GetNextUnformattedPartition(PartitionList,
2600 &PartitionList->TempDisk,
2601 &PartitionList->TempPartition))
2602 {
2603 PartitionList->FormatState = FormatOtherPartition;
2604 PartitionList->TempPartition->NeedsCheck = TRUE;
2605 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2606 }
2607 else
2608 {
2609 PartitionList->FormatState = FormatDone;
2610 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2611 return CHECK_FILE_SYSTEM_PAGE;
2612 }
2613 break;
2614
2615 case FormatOtherPartition:
2616 if (GetNextUnformattedPartition(PartitionList,
2617 &PartitionList->TempDisk,
2618 &PartitionList->TempPartition))
2619 {
2620 PartitionList->FormatState = FormatOtherPartition;
2621 PartitionList->TempPartition->NeedsCheck = TRUE;
2622 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2623 }
2624 else
2625 {
2626 PartitionList->FormatState = FormatDone;
2627 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2628 return CHECK_FILE_SYSTEM_PAGE;
2629 }
2630 break;
2631
2632 default:
2633 DPRINT1("FormatState: Invalid value %ld\n", PartitionList->FormatState);
2634 /* FIXME: show an error dialog */
2635 return QUIT_PAGE;
2636 }
2637
2638 DiskEntry = PartitionList->TempDisk;
2639 PartEntry = PartitionList->TempPartition;
2640
2641 /* adjust disk size */
2642 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2643 if (DiskSize >= 10737418240) /* 10 GB */
2644 {
2645 DiskSize = DiskSize / 1073741824;
2646 DiskUnit = MUIGetString(STRING_GB);
2647 }
2648 else
2649 {
2650 DiskSize = DiskSize / 1048576;
2651 DiskUnit = MUIGetString(STRING_MB);
2652 }
2653
2654 /* adjust partition size */
2655 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2656 if (PartSize >= 10737418240) /* 10 GB */
2657 {
2658 PartSize = PartSize / 1073741824;
2659 PartUnit = MUIGetString(STRING_GB);
2660 }
2661 else
2662 {
2663 PartSize = PartSize / 1048576;
2664 PartUnit = MUIGetString(STRING_MB);
2665 }
2666
2667 /* adjust partition type */
2668 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, PartTypeString, 30);
2669
2670 if (PartEntry->AutoCreate == TRUE)
2671 {
2672 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2673
2674 #if 0
2675 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2676 PartEntry->PartitionNumber,
2677 PartSize,
2678 PartUnit,
2679 PartType);
2680 #endif
2681
2682 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
2683 DiskEntry->DiskNumber,
2684 DiskSize,
2685 DiskUnit,
2686 DiskEntry->Port,
2687 DiskEntry->Bus,
2688 DiskEntry->Id,
2689 &DiskEntry->DriverName);
2690
2691 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2692
2693
2694 PartEntry->AutoCreate = FALSE;
2695 }
2696 else if (PartEntry->New == TRUE)
2697 {
2698 switch (PartitionList->FormatState)
2699 {
2700 case FormatSystemPartition:
2701 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2702 break;
2703
2704 case FormatInstallPartition:
2705 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2706 break;
2707
2708 case FormatOtherPartition:
2709 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2710 break;
2711
2712 default:
2713 break;
2714 }
2715
2716 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2717 }
2718 else
2719 {
2720 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2721
2722 if (PartTypeString == NULL)
2723 {
2724 CONSOLE_PrintTextXY(8, 10,
2725 MUIGetString(STRING_HDDINFOUNK4),
2726 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2727 (PartEntry->DriveLetter == 0) ? '-' : ':',
2728 PartEntry->PartitionType,
2729 PartSize,
2730 PartUnit);
2731 }
2732 else
2733 {
2734 CONSOLE_PrintTextXY(8, 10,
2735 "%c%c %s %I64u %s",
2736 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2737 (PartEntry->DriveLetter == 0) ? '-' : ':',
2738 PartTypeString,
2739 PartSize,
2740 PartUnit);
2741 }
2742
2743 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
2744 DiskEntry->DiskNumber,
2745 DiskSize,
2746 DiskUnit,
2747 DiskEntry->Port,
2748 DiskEntry->Bus,
2749 DiskEntry->Id,
2750 &DiskEntry->DriverName);
2751 }
2752
2753 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2754
2755 if (FileSystemList == NULL)
2756 {
2757 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2758 if (FileSystemList == NULL)
2759 {
2760 /* FIXME: show an error dialog */
2761 return QUIT_PAGE;
2762 }
2763
2764 /* FIXME: Add file systems to list */
2765 }
2766
2767 DrawFileSystemList(FileSystemList);
2768
2769 if (RepairUpdateFlag)
2770 {
2771 return CHECK_FILE_SYSTEM_PAGE;
2772 //return SELECT_PARTITION_PAGE;
2773 }
2774
2775 if (IsUnattendedSetup)
2776 {
2777 if (UnattendFormatPartition)
2778 {
2779 PartEntry->FileSystem = GetFileSystemByName(FileSystemList, L"FAT");
2780 return FORMAT_PARTITION_PAGE;
2781 }
2782
2783 return CHECK_FILE_SYSTEM_PAGE;
2784 }
2785
2786 while (TRUE)
2787 {
2788 CONSOLE_ConInKey(Ir);
2789
2790 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2791 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2792 {
2793 if (ConfirmQuit(Ir) == TRUE)
2794 return QUIT_PAGE;
2795
2796 break;
2797 }
2798 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2799 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2800 {
2801 return SELECT_PARTITION_PAGE;
2802 }
2803 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2804 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2805 {
2806 ScrollDownFileSystemList(FileSystemList);
2807 }
2808 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2809 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2810 {
2811 ScrollUpFileSystemList(FileSystemList);
2812 }
2813 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2814 {
2815 if (!FileSystemList->Selected->FormatFunc)
2816 {
2817 return SELECT_FILE_SYSTEM_PAGE;
2818 }
2819 else
2820 {
2821 PartEntry->FileSystem = FileSystemList->Selected;
2822 return FORMAT_PARTITION_PAGE;
2823 }
2824 }
2825 }
2826
2827 return SELECT_FILE_SYSTEM_PAGE;
2828 }
2829
2830
2831 /*
2832 * Displays the FormatPartitionPage.
2833 *
2834 * Next pages:
2835 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2836 * SelectPartitionPage (At once)
2837 * QuitPage
2838 *
2839 * SIDEEFFECTS
2840 * Sets PartitionList->CurrentPartition->FormatState
2841 * Sets DestinationRootPath
2842 *
2843 * RETURNS
2844 * Number of the next page.
2845 */
2846 static ULONG
2847 FormatPartitionPage(PINPUT_RECORD Ir)
2848 {
2849 UNICODE_STRING PartitionRootPath;
2850 WCHAR PathBuffer[MAX_PATH];
2851 PDISKENTRY DiskEntry;
2852 PPARTENTRY PartEntry;
2853 NTSTATUS Status;
2854
2855 #ifndef NDEBUG
2856 ULONG Line;
2857 ULONG i;
2858 PLIST_ENTRY Entry;
2859 #endif
2860
2861 DPRINT("FormatPartitionPage()\n");
2862
2863 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2864
2865 if (PartitionList == NULL ||
2866 PartitionList->TempDisk == NULL ||
2867 PartitionList->TempPartition == NULL)
2868 {
2869 /* FIXME: show an error dialog */
2870 return QUIT_PAGE;
2871 }
2872
2873 DiskEntry = PartitionList->TempDisk;
2874 PartEntry = PartitionList->TempPartition;
2875
2876 while (TRUE)
2877 {
2878 if (!IsUnattendedSetup)
2879 {
2880 CONSOLE_ConInKey(Ir);
2881 }
2882
2883 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2884 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2885 {
2886 if (ConfirmQuit(Ir) == TRUE)
2887 return QUIT_PAGE;
2888
2889 break;
2890 }
2891 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2892 {
2893 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2894
2895 if (wcscmp(PartEntry->FileSystem->FileSystemName, L"FAT") == 0)
2896 {
2897 if (PartEntry->SectorCount.QuadPart < 8192)
2898 {
2899 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
2900 PartEntry->PartitionType = PARTITION_FAT_12;
2901 }
2902 else if (PartEntry->StartSector.QuadPart < 1450560)
2903 {
2904 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2905
2906 if (PartEntry->SectorCount.QuadPart < 65536)
2907 {
2908 /* FAT16 CHS partition (partition size < 32MB) */
2909 PartEntry->PartitionType = PARTITION_FAT_16;
2910 }
2911 else if (PartEntry->SectorCount.QuadPart < 1048576)
2912 {
2913 /* FAT16 CHS partition (partition size < 512MB) */
2914 PartEntry->PartitionType = PARTITION_HUGE;
2915 }
2916 else
2917 {
2918 /* FAT32 CHS partition (partition size >= 512MB) */
2919 PartEntry->PartitionType = PARTITION_FAT32;
2920 }
2921 }
2922 else
2923 {
2924 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2925
2926 if (PartEntry->SectorCount.QuadPart < 1048576)
2927 {
2928 /* FAT16 LBA partition (partition size < 512MB) */
2929 PartEntry->PartitionType = PARTITION_XINT13;
2930 }
2931 else
2932 {
2933 /* FAT32 LBA partition (partition size >= 512MB) */
2934 PartEntry->PartitionType = PARTITION_FAT32_XINT13;
2935 }
2936 }
2937
2938 DiskEntry->Dirty = TRUE;
2939 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
2940 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2941 }
2942 #if 0
2943 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"EXT2") == 0)
2944 {
2945 PartEntry->PartitionType = PARTITION_EXT2;
2946
2947 DiskEntry->Dirty = TRUE;
2948 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
2949 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2950 }
2951 else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"NTFS") == 0)
2952 {
2953 PartEntry->PartitionType = PARTITION_IFS;
2954
2955 DiskEntry->Dirty = TRUE;
2956 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
2957 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
2958 }
2959 #endif
2960 else if (!PartEntry->FileSystem->FormatFunc)
2961 {
2962 /* FIXME: show an error dialog */
2963 return QUIT_PAGE;
2964 }
2965
2966 #ifndef NDEBUG
2967 CONSOLE_PrintTextXY(6, 12,
2968 "Disk: %I64u Cylinder: %I64u Track: %I64u",
2969 DiskEntry->DiskSize,
2970 DiskEntry->CylinderSize,
2971 DiskEntry->TrackSize);
2972
2973 Line = 13;
2974 DiskEntry = PartitionList->TempDisk;
2975 Entry = DiskEntry->PartListHead.Flink;
2976
2977 while (Entry != &DiskEntry->PrimaryPartListHead)
2978 {
2979 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2980
2981 if (PartEntry->IsPartitioned == TRUE)
2982 {
2983 CONSOLE_PrintTextXY(6, Line,
2984 "%2u: %2u %c %12I64u %12I64u %2u %c",
2985 i,
2986 PartEntry->PartitionNumber,
2987 PartEntry->BootIndicator ? 'A' : '-',
2988 PartEntry->StartSector.QuadPart,
2989 PartEntry->SectorCount.QuadPart,
2990 PartEntry->PartitionType,
2991 PartEntry->Dirty ? '*' : ' ');
2992 Line++;
2993 }
2994
2995 Entry = Entry->Flink;
2996 }
2997
2998 /* Restore the old entry */
2999 PartEntry = PartitionList->TempPartition;
3000 #endif
3001
3002 if (WritePartitionsToDisk(PartitionList) == FALSE)
3003 {
3004 DPRINT("WritePartitionsToDisk() failed\n");
3005 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3006 return QUIT_PAGE;
3007 }
3008
3009 /* Set PartitionRootPath */
3010 swprintf(PathBuffer,
3011 L"\\Device\\Harddisk%lu\\Partition%lu",
3012 DiskEntry->DiskNumber,
3013 PartEntry->PartitionNumber);
3014 RtlInitUnicodeString(&PartitionRootPath,
3015 PathBuffer);
3016 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3017
3018 if (PartEntry->FileSystem->FormatFunc)
3019 {
3020 Status = FormatPartition(&PartitionRootPath,
3021 PartEntry->FileSystem);
3022 if (!NT_SUCCESS(Status))
3023 {
3024 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3025 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3026 return QUIT_PAGE;
3027 }
3028
3029 PartEntry->New = FALSE;
3030 }
3031
3032 #ifndef NDEBUG
3033 CONSOLE_SetStatusText(" Done. Press any key ...");
3034 CONSOLE_ConInKey(Ir);
3035 #endif
3036
3037 return SELECT_FILE_SYSTEM_PAGE;
3038 }
3039 }
3040
3041 return FORMAT_PARTITION_PAGE;
3042 }
3043
3044
3045 /*
3046 * Displays the CheckFileSystemPage.
3047 *
3048 * Next pages:
3049 * InstallDirectoryPage (At once)
3050 * QuitPage
3051 *
3052 * SIDEEFFECTS
3053 * Inits or reloads FileSystemList
3054 *
3055 * RETURNS
3056 * Number of the next page.
3057 */
3058 static ULONG
3059 CheckFileSystemPage(PINPUT_RECORD Ir)
3060 {
3061 PFILE_SYSTEM_ITEM CurrentFileSystem;
3062 UNICODE_STRING PartitionRootPath;
3063 WCHAR PathBuffer[MAX_PATH];
3064 CHAR Buffer[MAX_PATH];
3065 PDISKENTRY DiskEntry;
3066 PPARTENTRY PartEntry;
3067 NTSTATUS Status;
3068
3069 if (PartitionList == NULL)
3070 {
3071 /* FIXME: show an error dialog */
3072 return QUIT_PAGE;
3073 }
3074
3075 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3076 {
3077 return INSTALL_DIRECTORY_PAGE;
3078 }
3079
3080 /* Set PartitionRootPath */
3081 swprintf(PathBuffer,
3082 L"\\Device\\Harddisk%lu\\Partition%lu",
3083 DiskEntry->DiskNumber,
3084 PartEntry->PartitionNumber);
3085 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3086 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3087
3088 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3089
3090 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3091
3092 CurrentFileSystem = GetFileSystem(FileSystemList, PartEntry);
3093 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3094 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3095
3096 /* HACK: Do not try to check a partition with an unknown filesytem */
3097 if (CurrentFileSystem == NULL)
3098 {
3099 PartEntry->NeedsCheck = FALSE;
3100 return CHECK_FILE_SYSTEM_PAGE;
3101 }
3102
3103 if (CurrentFileSystem->ChkdskFunc == NULL)
3104 {
3105 sprintf(Buffer,
3106 "Setup is currently unable to check a partition formatted in %S.\n"
3107 "\n"
3108 " \x07 Press ENTER to continue Setup.\n"
3109 " \x07 Press F3 to quit Setup.",
3110 CurrentFileSystem->FileSystemName);
3111
3112 PopupError(Buffer,
3113 MUIGetString(STRING_QUITCONTINUE),
3114 NULL, POPUP_WAIT_NONE);
3115
3116 while (TRUE)
3117 {
3118 CONSOLE_ConInKey(Ir);
3119
3120 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3121 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3122 {
3123 if (ConfirmQuit(Ir))
3124 return QUIT_PAGE;
3125 else
3126 return CHECK_FILE_SYSTEM_PAGE;
3127 }
3128 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3129 {
3130 PartEntry->NeedsCheck = FALSE;
3131 return CHECK_FILE_SYSTEM_PAGE;
3132 }
3133 }
3134 }
3135 else
3136 {
3137 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3138 if (!NT_SUCCESS(Status))
3139 {
3140 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3141 sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3142 "(Status 0x%08lx).\n", Status);
3143 PopupError(Buffer,
3144 MUIGetString(STRING_REBOOTCOMPUTER),
3145 Ir, POPUP_WAIT_ENTER);
3146
3147 return QUIT_PAGE;
3148 }
3149
3150 PartEntry->NeedsCheck = FALSE;
3151 return CHECK_FILE_SYSTEM_PAGE;
3152 }
3153 }
3154
3155
3156 /*
3157 * Displays the InstallDirectoryPage1.
3158 *
3159 * Next pages:
3160 * PrepareCopyPage (At once)
3161 *
3162 * SIDEEFFECTS
3163 * Inits DestinationRootPath
3164 * Inits DestinationPath
3165 * Inits DestinationArcPath
3166 *
3167 * RETURNS
3168 * Number of the next page.
3169 */
3170 static PAGE_NUMBER
3171 InstallDirectoryPage1(PWCHAR InstallDir,
3172 PDISKENTRY DiskEntry,
3173 PPARTENTRY PartEntry)
3174 {
3175 WCHAR PathBuffer[MAX_PATH];
3176
3177 /* Create 'InstallPath' string */
3178 RtlFreeUnicodeString(&InstallPath);
3179 RtlCreateUnicodeString(&InstallPath, InstallDir);
3180
3181 /* Create 'DestinationRootPath' string */
3182 RtlFreeUnicodeString(&DestinationRootPath);
3183 swprintf(PathBuffer,
3184 L"\\Device\\Harddisk%lu\\Partition%lu",
3185 DiskEntry->DiskNumber,
3186 PartEntry->PartitionNumber);
3187 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
3188 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
3189
3190 /* Create 'DestinationPath' string */
3191 RtlFreeUnicodeString(&DestinationPath);
3192 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3193
3194 if (InstallDir[0] != L'\\')
3195 wcscat(PathBuffer, L"\\");
3196
3197 wcscat(PathBuffer, InstallDir);
3198 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
3199
3200 /* Create 'DestinationArcPath' */
3201 RtlFreeUnicodeString(&DestinationArcPath);
3202 swprintf(PathBuffer,
3203 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
3204 DiskEntry->BiosDiskNumber,
3205 PartEntry->PartitionNumber);
3206
3207 if (InstallDir[0] != L'\\')
3208 wcscat(PathBuffer, L"\\");
3209
3210 wcscat(PathBuffer, InstallDir);
3211 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
3212
3213 return PREPARE_COPY_PAGE;
3214 }
3215
3216
3217 /*
3218 * Displays the InstallDirectoryPage.
3219 *
3220 * Next pages:
3221 * PrepareCopyPage (As the direct result of InstallDirectoryPage1)
3222 * QuitPage
3223 *
3224 * RETURNS
3225 * Number of the next page.
3226 */
3227 static PAGE_NUMBER
3228 InstallDirectoryPage(PINPUT_RECORD Ir)
3229 {
3230 PDISKENTRY DiskEntry;
3231 PPARTENTRY PartEntry;
3232 WCHAR InstallDir[51];