Sync with trunk head (r48654)
[reactos.git] / 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: subsys/system/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 #define NDEBUG
32 #include <debug.h>
33
34
35 /* GLOBALS ******************************************************************/
36
37 HANDLE ProcessHeap;
38 UNICODE_STRING SourceRootPath;
39 UNICODE_STRING SourceRootDir;
40 UNICODE_STRING SourcePath;
41 BOOLEAN IsUnattendedSetup = FALSE;
42 LONG UnattendDestinationDiskNumber;
43 LONG UnattendDestinationPartitionNumber;
44 LONG UnattendMBRInstallType = -1;
45 LONG UnattendFormatPartition = 0;
46 LONG AutoPartition = 0;
47 WCHAR UnattendInstallationDirectory[MAX_PATH];
48 PWCHAR SelectedLanguageId;
49 WCHAR LocaleID[9];
50 WCHAR DefaultLanguage[20];
51 WCHAR DefaultKBLayout[20];
52 BOOLEAN RepairUpdateFlag = FALSE;
53 HANDLE hPnpThread = INVALID_HANDLE_VALUE;
54
55 /* LOCALS *******************************************************************/
56
57 static PPARTLIST PartitionList = NULL;
58
59 static PFILE_SYSTEM_LIST FileSystemList = NULL;
60
61 static UNICODE_STRING InstallPath;
62
63 /* Path to the install directory */
64 static UNICODE_STRING DestinationPath;
65 static UNICODE_STRING DestinationArcPath;
66 static UNICODE_STRING DestinationRootPath;
67
68 /* Path to the active partition (boot manager) */
69 static UNICODE_STRING SystemRootPath;
70
71 static HINF SetupInf;
72
73 static HSPFILEQ SetupFileQueue = NULL;
74
75 static BOOLEAN WarnLinuxPartitions = TRUE;
76
77 static PGENERIC_LIST ComputerList = NULL;
78 static PGENERIC_LIST DisplayList = NULL;
79 static PGENERIC_LIST KeyboardList = NULL;
80 static PGENERIC_LIST LayoutList = NULL;
81 static PGENERIC_LIST LanguageList = NULL;
82
83 static LANGID LanguageId = 0;
84
85 static ULONG RequiredPartitionDiskSpace = ~0;
86
87 /* FUNCTIONS ****************************************************************/
88
89 static VOID
90 PrintString(char* fmt,...)
91 {
92 char buffer[512];
93 va_list ap;
94 UNICODE_STRING UnicodeString;
95 ANSI_STRING AnsiString;
96
97 va_start(ap, fmt);
98 vsprintf(buffer, fmt, ap);
99 va_end(ap);
100
101 RtlInitAnsiString(&AnsiString, buffer);
102 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
103 NtDisplayString(&UnicodeString);
104 RtlFreeUnicodeString(&UnicodeString);
105 }
106
107
108 static VOID
109 DrawBox(IN SHORT xLeft,
110 IN SHORT yTop,
111 IN SHORT Width,
112 IN SHORT Height)
113 {
114 COORD coPos;
115 DWORD Written;
116
117 /* draw upper left corner */
118 coPos.X = xLeft;
119 coPos.Y = yTop;
120 FillConsoleOutputCharacterA(StdOutput,
121 0xDA, // '+',
122 1,
123 coPos,
124 &Written);
125
126 /* draw upper edge */
127 coPos.X = xLeft + 1;
128 coPos.Y = yTop;
129 FillConsoleOutputCharacterA(StdOutput,
130 0xC4, // '-',
131 Width - 2,
132 coPos,
133 &Written);
134
135 /* draw upper right corner */
136 coPos.X = xLeft + Width - 1;
137 coPos.Y = yTop;
138 FillConsoleOutputCharacterA(StdOutput,
139 0xBF, // '+',
140 1,
141 coPos,
142 &Written);
143
144 /* Draw right edge, inner space and left edge */
145 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
146 {
147 coPos.X = xLeft;
148 FillConsoleOutputCharacterA(StdOutput,
149 0xB3, // '|',
150 1,
151 coPos,
152 &Written);
153
154 coPos.X = xLeft + 1;
155 FillConsoleOutputCharacterA(StdOutput,
156 ' ',
157 Width - 2,
158 coPos,
159 &Written);
160
161 coPos.X = xLeft + Width - 1;
162 FillConsoleOutputCharacterA(StdOutput,
163 0xB3, // '|',
164 1,
165 coPos,
166 &Written);
167 }
168
169 /* draw lower left corner */
170 coPos.X = xLeft;
171 coPos.Y = yTop + Height - 1;
172 FillConsoleOutputCharacterA(StdOutput,
173 0xC0, // '+',
174 1,
175 coPos,
176 &Written);
177
178 /* draw lower edge */
179 coPos.X = xLeft + 1;
180 coPos.Y = yTop + Height - 1;
181 FillConsoleOutputCharacterA(StdOutput,
182 0xC4, // '-',
183 Width - 2,
184 coPos,
185 &Written);
186
187 /* draw lower right corner */
188 coPos.X = xLeft + Width - 1;
189 coPos.Y = yTop + Height - 1;
190 FillConsoleOutputCharacterA(StdOutput,
191 0xD9, // '+',
192 1,
193 coPos,
194 &Written);
195 }
196
197
198 VOID
199 PopupError(PCCH Text,
200 PCCH Status,
201 PINPUT_RECORD Ir,
202 ULONG WaitEvent)
203 {
204 SHORT yTop;
205 SHORT xLeft;
206 COORD coPos;
207 DWORD Written;
208 ULONG Length;
209 ULONG MaxLength;
210 ULONG Lines;
211 PCHAR p;
212 PCCH pnext;
213 BOOLEAN LastLine;
214 SHORT Width;
215 SHORT Height;
216
217 /* Count text lines and longest line */
218 MaxLength = 0;
219 Lines = 0;
220 pnext = Text;
221
222 while (TRUE)
223 {
224 p = strchr(pnext, '\n');
225
226 if (p == NULL)
227 {
228 Length = strlen(pnext);
229 LastLine = TRUE;
230 }
231 else
232 {
233 Length = (ULONG)(p - pnext);
234 LastLine = FALSE;
235 }
236
237 Lines++;
238
239 if (Length > MaxLength)
240 MaxLength = Length;
241
242 if (LastLine == TRUE)
243 break;
244
245 pnext = p + 1;
246 }
247
248 /* Check length of status line */
249 if (Status != NULL)
250 {
251 Length = strlen(Status);
252
253 if (Length > MaxLength)
254 MaxLength = Length;
255 }
256
257 Width = MaxLength + 4;
258 Height = Lines + 2;
259
260 if (Status != NULL)
261 Height += 2;
262
263 yTop = (yScreen - Height) / 2;
264 xLeft = (xScreen - Width) / 2;
265
266
267 /* Set screen attributes */
268 coPos.X = xLeft;
269 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
270 {
271 FillConsoleOutputAttribute(StdOutput,
272 FOREGROUND_RED | BACKGROUND_WHITE,
273 Width,
274 coPos,
275 &Written);
276 }
277
278 DrawBox(xLeft, yTop, Width, Height);
279
280 /* Print message text */
281 coPos.Y = yTop + 1;
282 pnext = Text;
283 while (TRUE)
284 {
285 p = strchr(pnext, '\n');
286
287 if (p == NULL)
288 {
289 Length = strlen(pnext);
290 LastLine = TRUE;
291 }
292 else
293 {
294 Length = (ULONG)(p - pnext);
295 LastLine = FALSE;
296 }
297
298 if (Length != 0)
299 {
300 coPos.X = xLeft + 2;
301 WriteConsoleOutputCharacterA(StdOutput,
302 pnext,
303 Length,
304 coPos,
305 &Written);
306 }
307
308 if (LastLine == TRUE)
309 break;
310
311 coPos.Y++;
312 pnext = p + 1;
313 }
314
315 /* Print separator line and status text */
316 if (Status != NULL)
317 {
318 coPos.Y = yTop + Height - 3;
319 coPos.X = xLeft;
320 FillConsoleOutputCharacterA(StdOutput,
321 0xC3, // '+',
322 1,
323 coPos,
324 &Written);
325
326 coPos.X = xLeft + 1;
327 FillConsoleOutputCharacterA(StdOutput,
328 0xC4, // '-',
329 Width - 2,
330 coPos,
331 &Written);
332
333 coPos.X = xLeft + Width - 1;
334 FillConsoleOutputCharacterA(StdOutput,
335 0xB4, // '+',
336 1,
337 coPos,
338 &Written);
339
340 coPos.Y++;
341 coPos.X = xLeft + 2;
342 WriteConsoleOutputCharacterA(StdOutput,
343 Status,
344 min(strlen(Status), (SIZE_T)Width - 4),
345 coPos,
346 &Written);
347 }
348
349 if (WaitEvent == POPUP_WAIT_NONE)
350 return;
351
352 while (TRUE)
353 {
354 CONSOLE_ConInKey(Ir);
355
356 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
357 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
358 {
359 return;
360 }
361 }
362 }
363
364
365 /*
366 * Confirm quit setup
367 * RETURNS
368 * TRUE: Quit setup.
369 * FALSE: Don't quit setup.
370 */
371 static BOOL
372 ConfirmQuit(PINPUT_RECORD Ir)
373 {
374 BOOL Result = FALSE;
375 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
376
377 while (TRUE)
378 {
379 CONSOLE_ConInKey(Ir);
380
381 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
382 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
383 {
384 Result = TRUE;
385 break;
386 }
387 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
388 {
389 Result = FALSE;
390 break;
391 }
392 }
393
394 return Result;
395 }
396
397
398 VOID
399 CheckUnattendedSetup(VOID)
400 {
401 WCHAR UnattendInfPath[MAX_PATH];
402 INFCONTEXT Context;
403 HINF UnattendInf;
404 UINT ErrorLine;
405 INT IntValue;
406 PWCHAR Value;
407
408 if (DoesFileExist(SourcePath.Buffer, L"unattend.inf") == FALSE)
409 {
410 DPRINT("Does not exist: %S\\%S\n", SourcePath.Buffer, L"unattend.inf");
411 return;
412 }
413
414 wcscpy(UnattendInfPath, SourcePath.Buffer);
415 wcscat(UnattendInfPath, L"\\unattend.inf");
416
417 /* Load 'unattend.inf' from install media. */
418 UnattendInf = SetupOpenInfFileW(UnattendInfPath,
419 NULL,
420 INF_STYLE_WIN4,
421 LanguageId,
422 &ErrorLine);
423
424 if (UnattendInf == INVALID_HANDLE_VALUE)
425 {
426 DPRINT("SetupOpenInfFileW() failed\n");
427 return;
428 }
429
430 /* Open 'Unattend' section */
431 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"Signature", &Context))
432 {
433 DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
434 SetupCloseInfFile(UnattendInf);
435 return;
436 }
437
438 /* Get pointer 'Signature' key */
439 if (!INF_GetData(&Context, NULL, &Value))
440 {
441 DPRINT("INF_GetData() failed for key 'Signature'\n");
442 SetupCloseInfFile(UnattendInf);
443 return;
444 }
445
446 /* Check 'Signature' string */
447 if (_wcsicmp(Value, L"$ReactOS$") != 0)
448 {
449 DPRINT("Signature not $ReactOS$\n");
450 SetupCloseInfFile(UnattendInf);
451 return;
452 }
453
454 /* Check if Unattend setup is enabled */
455 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
456 {
457 DPRINT("Can't find key 'UnattendSetupEnabled'\n");
458 SetupCloseInfFile(UnattendInf);
459 return;
460 }
461
462 if (!INF_GetData(&Context, NULL, &Value))
463 {
464 DPRINT("Can't read key 'UnattendSetupEnabled'\n");
465 SetupCloseInfFile(UnattendInf);
466 return;
467 }
468
469 if (_wcsicmp(Value, L"yes") != 0)
470 {
471 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
472 SetupCloseInfFile(UnattendInf);
473 return;
474 }
475
476 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
477 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
478 {
479 DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
480 SetupCloseInfFile(UnattendInf);
481 return;
482 }
483
484 if (!SetupGetIntField(&Context, 1, &IntValue))
485 {
486 DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
487 SetupCloseInfFile(UnattendInf);
488 return;
489 }
490
491 UnattendDestinationDiskNumber = (LONG)IntValue;
492
493 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
494 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
495 {
496 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
497 SetupCloseInfFile(UnattendInf);
498 return;
499 }
500
501 if (!SetupGetIntField(&Context, 1, &IntValue))
502 {
503 DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
504 SetupCloseInfFile(UnattendInf);
505 return;
506 }
507
508 UnattendDestinationPartitionNumber = IntValue;
509
510 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
511 if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
512 {
513 DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
514 SetupCloseInfFile(UnattendInf);
515 return;
516 }
517
518 /* Get pointer 'InstallationDirectory' key */
519 if (!INF_GetData(&Context, NULL, &Value))
520 {
521 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
522 SetupCloseInfFile(UnattendInf);
523 return;
524 }
525
526 wcscpy(UnattendInstallationDirectory, Value);
527
528 IsUnattendedSetup = TRUE;
529
530 /* Search for 'MBRInstallType' in the 'Unattend' section */
531 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
532 {
533 if (SetupGetIntField(&Context, 1, &IntValue))
534 {
535 UnattendMBRInstallType = IntValue;
536 }
537 }
538
539 /* Search for 'FormatPartition' in the 'Unattend' section */
540 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
541 {
542 if (SetupGetIntField(&Context, 1, &IntValue))
543 {
544 UnattendFormatPartition = IntValue;
545 }
546 }
547
548 if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
549 {
550 if (SetupGetIntField(&Context, 1, &IntValue))
551 {
552 AutoPartition = IntValue;
553 }
554 }
555
556 /* search for LocaleID in the 'Unattend' section*/
557 if (SetupFindFirstLineW (UnattendInf, L"Unattend", L"LocaleID", &Context))
558 {
559 if (INF_GetData (&Context, NULL, &Value))
560 {
561 LONG Id = wcstol(Value, NULL, 16);
562 swprintf(LocaleID,L"%08lx", Id);
563 }
564 }
565
566 SetupCloseInfFile(UnattendInf);
567
568 DPRINT("Running unattended setup\n");
569 }
570
571
572 VOID
573 UpdateKBLayout(VOID)
574 {
575 PGENERIC_LIST_ENTRY ListEntry;
576 LPCWSTR pszNewLayout;
577
578 pszNewLayout = MUIDefaultKeyboardLayout();
579
580 if (LayoutList == NULL)
581 {
582 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
583 if (LayoutList == NULL)
584 {
585 /* FIXME: Handle error! */
586 return;
587 }
588 }
589
590 ListEntry = GetFirstListEntry(LayoutList);
591
592 /* Search for default layout (if provided) */
593 if (pszNewLayout != NULL)
594 {
595 while (ListEntry != NULL)
596 {
597 if (!wcscmp(pszNewLayout, GetListEntryUserData(ListEntry)))
598 {
599 SetCurrentListEntry(LayoutList, ListEntry);
600 break;
601 }
602
603 ListEntry = GetNextListEntry(ListEntry);
604 }
605 }
606 }
607
608
609 static PAGE_NUMBER
610 LanguagePage(PINPUT_RECORD Ir)
611 {
612 /* Initialize the computer settings list */
613 if (LanguageList == NULL)
614 {
615 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
616
617 if (LanguageList == NULL)
618 {
619 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
620 return INTRO_PAGE;
621 }
622 }
623
624 DrawGenericList(LanguageList,
625 2,
626 18,
627 xScreen - 3,
628 yScreen - 3);
629
630 ScrollToPositionGenericList (LanguageList, GetDefaultLanguageIndex());
631
632 MUIDisplayPage(LANGUAGE_PAGE);
633
634 while (TRUE)
635 {
636 CONSOLE_ConInKey(Ir);
637
638 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
639 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
640 {
641 #if 0
642 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
643
644 /* Redraw language selection page in native language */
645 MUIDisplayPage(LANGUAGE_PAGE);
646 #endif
647
648 ScrollDownGenericList (LanguageList);
649 }
650 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
651 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
652 {
653 #if 0
654 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
655
656 /* Redraw language selection page in native language */
657 MUIDisplayPage(LANGUAGE_PAGE);
658 #endif
659
660 ScrollUpGenericList(LanguageList);
661 }
662 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
663 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
664 {
665 ScrollPageDownGenericList(LanguageList);
666 }
667 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
668 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
669 {
670 ScrollPageUpGenericList(LanguageList);
671 }
672 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
673 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
674 {
675 if (ConfirmQuit(Ir) == TRUE)
676 return QUIT_PAGE;
677 }
678 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
679 {
680 SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
681
682 LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
683
684 if (wcscmp(SelectedLanguageId, DefaultLanguage))
685 {
686 UpdateKBLayout();
687 }
688
689 // Load the font
690 SetConsoleCodePage();
691
692 return INTRO_PAGE;
693 }
694 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
695 {
696 /* a-z */
697 GenericListKeyPress (LanguageList, Ir->Event.KeyEvent.uChar.AsciiChar);
698 }
699 }
700
701 return INTRO_PAGE;
702 }
703
704
705 /*
706 * Start page
707 * RETURNS
708 * Number of the next page.
709 */
710 static PAGE_NUMBER
711 SetupStartPage(PINPUT_RECORD Ir)
712 {
713 SYSTEM_DEVICE_INFORMATION Sdi;
714 NTSTATUS Status;
715 WCHAR FileNameBuffer[MAX_PATH];
716 INFCONTEXT Context;
717 PWCHAR Value;
718 UINT ErrorLine;
719 ULONG ReturnSize;
720 PGENERIC_LIST_ENTRY ListEntry;
721 INT IntValue;
722
723 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
724
725
726 /* Check whether a harddisk is available */
727 Status = NtQuerySystemInformation(SystemDeviceInformation,
728 &Sdi,
729 sizeof(SYSTEM_DEVICE_INFORMATION),
730 &ReturnSize);
731
732 if (!NT_SUCCESS(Status))
733 {
734 CONSOLE_PrintTextXY(6, 15, "NtQuerySystemInformation() failed (Status 0x%08lx)", Status);
735 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
736 return QUIT_PAGE;
737 }
738
739 if (Sdi.NumberOfDisks == 0)
740 {
741 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
742 return QUIT_PAGE;
743 }
744
745 /* Get the source path and source root path */
746 Status = GetSourcePaths(&SourcePath,
747 &SourceRootPath,
748 &SourceRootDir);
749
750 if (!NT_SUCCESS(Status))
751 {
752 CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
753 MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
754 return QUIT_PAGE;
755 }
756 #if 0
757 else
758 {
759 CONSOLE_PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
760 CONSOLE_PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
761 CONSOLE_PrintTextXY(6, 17, "SourceRootDir: '%wZ'", &SourceRootDir);
762 }
763 #endif
764
765 /* Load txtsetup.sif from install media. */
766 wcscpy(FileNameBuffer, SourcePath.Buffer);
767 wcscat(FileNameBuffer, L"\\txtsetup.sif");
768
769 SetupInf = SetupOpenInfFileW(FileNameBuffer,
770 NULL,
771 INF_STYLE_WIN4,
772 LanguageId,
773 &ErrorLine);
774
775 if (SetupInf == INVALID_HANDLE_VALUE)
776 {
777 MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
778 return QUIT_PAGE;
779 }
780
781 /* Open 'Version' section */
782 if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
783 {
784 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
785 return QUIT_PAGE;
786 }
787
788 /* Get pointer 'Signature' key */
789 if (!INF_GetData(&Context, NULL, &Value))
790 {
791 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
792 return QUIT_PAGE;
793 }
794
795 /* Check 'Signature' string */
796 if (_wcsicmp(Value, L"$ReactOS$") != 0)
797 {
798 MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
799 return QUIT_PAGE;
800 }
801
802 /* Open 'DiskSpaceRequirements' section */
803 if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
804 {
805 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
806 return QUIT_PAGE;
807 }
808
809 /* Get the 'FreeSysPartDiskSpace' value */
810 if (!SetupGetIntField(&Context, 1, &IntValue))
811 {
812 MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
813 return QUIT_PAGE;
814 }
815
816 RequiredPartitionDiskSpace = (ULONG)IntValue;
817
818 /* Start PnP thread */
819 if (hPnpThread != INVALID_HANDLE_VALUE)
820 {
821 NtResumeThread(hPnpThread, NULL);
822 hPnpThread = INVALID_HANDLE_VALUE;
823 }
824
825 CheckUnattendedSetup();
826
827 if (IsUnattendedSetup)
828 {
829 //TODO
830 //read options from inf
831 ComputerList = CreateComputerTypeList(SetupInf);
832 DisplayList = CreateDisplayDriverList(SetupInf);
833 KeyboardList = CreateKeyboardDriverList(SetupInf);
834 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
835 LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
836
837 /* new part */
838 wcscpy(SelectedLanguageId,LocaleID);
839
840 /* first we hack LanguageList */
841 ListEntry = GetFirstListEntry(LanguageList);
842
843 while (ListEntry != NULL)
844 {
845 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
846 {
847 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
848 SetCurrentListEntry(LanguageList, ListEntry);
849 break;
850 }
851
852 ListEntry = GetNextListEntry(ListEntry);
853 }
854
855 /* now LayoutList */
856 ListEntry = GetFirstListEntry(LayoutList);
857
858 while (ListEntry != NULL)
859 {
860 if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
861 {
862 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
863 SetCurrentListEntry(LayoutList, ListEntry);
864 break;
865 }
866
867 ListEntry = GetNextListEntry(ListEntry);
868 }
869
870 SetConsoleCodePage();
871
872 return INSTALL_INTRO_PAGE;
873 }
874
875 return LANGUAGE_PAGE;
876 }
877
878
879 /*
880 * First setup page
881 * RETURNS
882 * Next page number.
883 */
884 static PAGE_NUMBER
885 IntroPage(PINPUT_RECORD Ir)
886 {
887 MUIDisplayPage(START_PAGE);
888
889 while (TRUE)
890 {
891 CONSOLE_ConInKey(Ir);
892
893 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
894 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
895 {
896 if (ConfirmQuit(Ir) == TRUE)
897 return QUIT_PAGE;
898
899 break;
900 }
901 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
902 {
903 return INSTALL_INTRO_PAGE;
904 break;
905 }
906 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
907 {
908 return REPAIR_INTRO_PAGE;
909 break;
910 }
911 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* R */
912 {
913 return LICENSE_PAGE;
914 break;
915 }
916 }
917
918 return INTRO_PAGE;
919 }
920
921
922 /*
923 * License Page
924 * RETURNS
925 * Back to main setup page.
926 */
927 static PAGE_NUMBER
928 LicensePage(PINPUT_RECORD Ir)
929 {
930 MUIDisplayPage(LICENSE_PAGE);
931
932 while (TRUE)
933 {
934 CONSOLE_ConInKey(Ir);
935
936 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
937 {
938 return INTRO_PAGE;
939 break;
940 }
941 }
942
943 return LICENSE_PAGE;
944 }
945
946
947 static PAGE_NUMBER
948 RepairIntroPage(PINPUT_RECORD Ir)
949 {
950 MUIDisplayPage(REPAIR_INTRO_PAGE);
951
952 while(TRUE)
953 {
954 CONSOLE_ConInKey(Ir);
955
956 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
957 {
958 return REBOOT_PAGE;
959 }
960 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
961 {
962 RepairUpdateFlag = TRUE;
963 return INSTALL_INTRO_PAGE;
964 }
965 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
966 {
967 return INTRO_PAGE;
968 }
969 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
970 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
971 {
972 return INTRO_PAGE;
973 }
974 }
975
976 return REPAIR_INTRO_PAGE;
977 }
978
979
980 static PAGE_NUMBER
981 InstallIntroPage(PINPUT_RECORD Ir)
982 {
983 MUIDisplayPage(INSTALL_INTRO_PAGE);
984
985 if (RepairUpdateFlag)
986 {
987 //return SELECT_PARTITION_PAGE;
988 return DEVICE_SETTINGS_PAGE;
989 }
990
991 if (IsUnattendedSetup)
992 {
993 return SELECT_PARTITION_PAGE;
994 }
995
996 while (TRUE)
997 {
998 CONSOLE_ConInKey(Ir);
999
1000 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1001 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1002 {
1003 if (ConfirmQuit(Ir) == TRUE)
1004 return QUIT_PAGE;
1005
1006 break;
1007 }
1008 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1009 {
1010 return DEVICE_SETTINGS_PAGE;
1011 // return SCSI_CONTROLLER_PAGE;
1012 }
1013 }
1014
1015 return INSTALL_INTRO_PAGE;
1016 }
1017
1018
1019 #if 0
1020 static PAGE_NUMBER
1021 ScsiControllerPage(PINPUT_RECORD Ir)
1022 {
1023 SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1024
1025 /* FIXME: print loaded mass storage driver descriptions */
1026 #if 0
1027 SetTextXY(8, 10, "TEST device");
1028 #endif
1029
1030
1031 SetStatusText(" ENTER = Continue F3 = Quit");
1032
1033 while (TRUE)
1034 {
1035 ConInKey(Ir);
1036
1037 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1038 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1039 {
1040 if (ConfirmQuit(Ir) == TRUE)
1041 return QUIT_PAGE;
1042
1043 break;
1044 }
1045 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1046 {
1047 return DEVICE_SETTINGS_PAGE;
1048 }
1049 }
1050
1051 return SCSI_CONTROLLER_PAGE;
1052 }
1053 #endif
1054
1055
1056 static PAGE_NUMBER
1057 DeviceSettingsPage(PINPUT_RECORD Ir)
1058 {
1059 static ULONG Line = 16;
1060 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1061
1062 /* Initialize the computer settings list */
1063 if (ComputerList == NULL)
1064 {
1065 ComputerList = CreateComputerTypeList(SetupInf);
1066 if (ComputerList == NULL)
1067 {
1068 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1069 return QUIT_PAGE;
1070 }
1071 }
1072
1073 /* Initialize the display settings list */
1074 if (DisplayList == NULL)
1075 {
1076 DisplayList = CreateDisplayDriverList(SetupInf);
1077 if (DisplayList == NULL)
1078 {
1079 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1080 return QUIT_PAGE;
1081 }
1082 }
1083
1084 /* Initialize the keyboard settings list */
1085 if (KeyboardList == NULL)
1086 {
1087 KeyboardList = CreateKeyboardDriverList(SetupInf);
1088 if (KeyboardList == NULL)
1089 {
1090 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1091 return QUIT_PAGE;
1092 }
1093 }
1094
1095 /* Initialize the keyboard layout list */
1096 if (LayoutList == NULL)
1097 {
1098 LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
1099 if (LayoutList == NULL)
1100 {
1101 /* FIXME: report error */
1102 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1103 return QUIT_PAGE;
1104 }
1105 }
1106
1107 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1108
1109
1110 CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry((ComputerList))));
1111 CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry((DisplayList))));
1112 CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry((KeyboardList))));
1113 CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry((LayoutList))));
1114
1115 CONSOLE_InvertTextXY(24, Line, 48, 1);
1116
1117 if (RepairUpdateFlag)
1118 {
1119 return SELECT_PARTITION_PAGE;
1120 }
1121
1122 while (TRUE)
1123 {
1124 CONSOLE_ConInKey(Ir);
1125
1126 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1127 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1128 {
1129 CONSOLE_NormalTextXY(24, Line, 48, 1);
1130
1131 if (Line == 14)
1132 Line = 16;
1133 else if (Line == 16)
1134 Line = 11;
1135 else
1136 Line++;
1137
1138 CONSOLE_InvertTextXY(24, Line, 48, 1);
1139 }
1140 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1141 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1142 {
1143 CONSOLE_NormalTextXY(24, Line, 48, 1);
1144
1145 if (Line == 11)
1146 Line = 16;
1147 else if (Line == 16)
1148 Line = 14;
1149 else
1150 Line--;
1151
1152 CONSOLE_InvertTextXY(24, Line, 48, 1);
1153 }
1154 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1155 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1156 {
1157 if (ConfirmQuit(Ir) == TRUE)
1158 return QUIT_PAGE;
1159
1160 break;
1161 }
1162 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1163 {
1164 if (Line == 11)
1165 return COMPUTER_SETTINGS_PAGE;
1166 else if (Line == 12)
1167 return DISPLAY_SETTINGS_PAGE;
1168 else if (Line == 13)
1169 return KEYBOARD_SETTINGS_PAGE;
1170 else if (Line == 14)
1171 return LAYOUT_SETTINGS_PAGE;
1172 else if (Line == 16)
1173 return SELECT_PARTITION_PAGE;
1174 }
1175 }
1176
1177 return DEVICE_SETTINGS_PAGE;
1178 }
1179
1180
1181 static PAGE_NUMBER
1182 ComputerSettingsPage(PINPUT_RECORD Ir)
1183 {
1184 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1185
1186 DrawGenericList(ComputerList,
1187 2,
1188 18,
1189 xScreen - 3,
1190 yScreen - 3);
1191
1192 SaveGenericListState(ComputerList);
1193
1194 while (TRUE)
1195 {
1196 CONSOLE_ConInKey(Ir);
1197
1198 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1199 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1200 {
1201 ScrollDownGenericList(ComputerList);
1202 }
1203 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1204 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1205 {
1206 ScrollUpGenericList(ComputerList);
1207 }
1208 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1209 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1210 {
1211 if (ConfirmQuit(Ir) == TRUE)
1212 return QUIT_PAGE;
1213
1214 break;
1215 }
1216 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1217 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1218 {
1219 RestoreGenericListState(ComputerList);
1220 return DEVICE_SETTINGS_PAGE;
1221 }
1222 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1223 {
1224 return DEVICE_SETTINGS_PAGE;
1225 }
1226 }
1227
1228 return COMPUTER_SETTINGS_PAGE;
1229 }
1230
1231
1232 static PAGE_NUMBER
1233 DisplaySettingsPage(PINPUT_RECORD Ir)
1234 {
1235 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1236
1237 DrawGenericList(DisplayList,
1238 2,
1239 18,
1240 xScreen - 3,
1241 yScreen - 3);
1242
1243 SaveGenericListState(DisplayList);
1244
1245 while (TRUE)
1246 {
1247 CONSOLE_ConInKey(Ir);
1248
1249 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1250 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1251 {
1252 ScrollDownGenericList(DisplayList);
1253 }
1254 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1255 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1256 {
1257 ScrollUpGenericList(DisplayList);
1258 }
1259 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1260 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1261 {
1262 if (ConfirmQuit(Ir) == TRUE)
1263 {
1264 return QUIT_PAGE;
1265 }
1266
1267 break;
1268 }
1269 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1270 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1271 {
1272 RestoreGenericListState(DisplayList);
1273 return DEVICE_SETTINGS_PAGE;
1274 }
1275 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1276 {
1277 return DEVICE_SETTINGS_PAGE;
1278 }
1279 }
1280
1281 return DISPLAY_SETTINGS_PAGE;
1282 }
1283
1284
1285 static PAGE_NUMBER
1286 KeyboardSettingsPage(PINPUT_RECORD Ir)
1287 {
1288 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1289
1290 DrawGenericList(KeyboardList,
1291 2,
1292 18,
1293 xScreen - 3,
1294 yScreen - 3);
1295
1296 SaveGenericListState(KeyboardList);
1297
1298 while (TRUE)
1299 {
1300 CONSOLE_ConInKey(Ir);
1301
1302 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1303 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1304 {
1305 ScrollDownGenericList(KeyboardList);
1306 }
1307 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1308 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1309 {
1310 ScrollUpGenericList(KeyboardList);
1311 }
1312 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1313 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1314 {
1315 if (ConfirmQuit(Ir) == TRUE)
1316 return QUIT_PAGE;
1317
1318 break;
1319 }
1320 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1321 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1322 {
1323 RestoreGenericListState(KeyboardList);
1324 return DEVICE_SETTINGS_PAGE;
1325 }
1326 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1327 {
1328 return DEVICE_SETTINGS_PAGE;
1329 }
1330 }
1331
1332 return DISPLAY_SETTINGS_PAGE;
1333 }
1334
1335
1336 static PAGE_NUMBER
1337 LayoutSettingsPage(PINPUT_RECORD Ir)
1338 {
1339 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1340
1341 DrawGenericList(LayoutList,
1342 2,
1343 18,
1344 xScreen - 3,
1345 yScreen - 3);
1346
1347 SaveGenericListState(LayoutList);
1348
1349 while (TRUE)
1350 {
1351 CONSOLE_ConInKey(Ir);
1352
1353 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1354 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1355 {
1356 ScrollDownGenericList(LayoutList);
1357 }
1358 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1359 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1360 {
1361 ScrollUpGenericList(LayoutList);
1362 }
1363 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1364 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1365 {
1366 ScrollPageDownGenericList(LayoutList);
1367 }
1368 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1369 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1370 {
1371 ScrollPageUpGenericList(LayoutList);
1372 }
1373 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1374 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1375 {
1376 if (ConfirmQuit(Ir) == TRUE)
1377 return QUIT_PAGE;
1378
1379 break;
1380 }
1381 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1382 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1383 {
1384 RestoreGenericListState(LayoutList);
1385 return DEVICE_SETTINGS_PAGE;
1386 }
1387 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1388 {
1389 return DEVICE_SETTINGS_PAGE;
1390 }
1391 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1392 {
1393 /* a-z */
1394 GenericListKeyPress(LayoutList , Ir->Event.KeyEvent.uChar.AsciiChar);
1395 }
1396 }
1397
1398 return DISPLAY_SETTINGS_PAGE;
1399 }
1400
1401
1402 static BOOL
1403 IsDiskSizeValid(PPARTENTRY PartEntry)
1404 {
1405 ULONGLONG m;
1406
1407 /* check for unpartitioned space */
1408 m = PartEntry->UnpartitionedLength;
1409 m = (m + (1 << 19)) >> 20; /* in MBytes (rounded) */
1410 if( m > RequiredPartitionDiskSpace)
1411 {
1412 return TRUE;
1413 }
1414
1415 /* check for partitioned space */
1416 m = PartEntry->PartInfo[0].PartitionLength.QuadPart;
1417 m = (m + (1 << 19)) >> 20; /* in MBytes (rounded) */
1418 if (m < RequiredPartitionDiskSpace)
1419 {
1420 /* partition is too small so ask for another partion */
1421 DPRINT1("Partition is too small, required disk space is %lu MB\n", RequiredPartitionDiskSpace);
1422 return FALSE;
1423 }
1424 else
1425 {
1426 return TRUE;
1427 }
1428 }
1429
1430
1431 static PAGE_NUMBER
1432 SelectPartitionPage(PINPUT_RECORD Ir)
1433 {
1434 MUIDisplayPage(SELECT_PARTITION_PAGE);
1435
1436 if (PartitionList == NULL)
1437 {
1438 PartitionList = CreatePartitionList(2,
1439 19,
1440 xScreen - 3,
1441 yScreen - 3);
1442 if (PartitionList == NULL)
1443 {
1444 /* FIXME: show an error dialog */
1445 return QUIT_PAGE;
1446 }
1447 }
1448
1449 CheckActiveBootPartition(PartitionList);
1450
1451 DrawPartitionList(PartitionList);
1452
1453 /* Warn about partitions created by Linux Fdisk */
1454 if (WarnLinuxPartitions == TRUE &&
1455 CheckForLinuxFdiskPartitions(PartitionList) == TRUE)
1456 {
1457 MUIDisplayError(ERROR_WARN_PARTITION, NULL, POPUP_WAIT_NONE);
1458
1459 while (TRUE)
1460 {
1461 CONSOLE_ConInKey(Ir);
1462
1463 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1464 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1465 {
1466 return QUIT_PAGE;
1467 }
1468 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1469 {
1470 WarnLinuxPartitions = FALSE;
1471 return SELECT_PARTITION_PAGE;
1472 }
1473 }
1474 }
1475
1476 if (IsUnattendedSetup)
1477 {
1478 if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
1479 {
1480 if (AutoPartition)
1481 {
1482 PPARTENTRY PartEntry = PartitionList->CurrentPartition;
1483 ULONG MaxSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20; /* in MBytes (rounded) */
1484 if(!IsDiskSizeValid(PartitionList->CurrentPartition))
1485 {
1486 MUIDisplayError(ERROR_INSUFFICIENT_DISKSPACE, Ir, POPUP_WAIT_ANY_KEY);
1487 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1488 }
1489
1490 CreateNewPartition(PartitionList,
1491 MaxSize,
1492 TRUE);
1493
1494 return SELECT_FILE_SYSTEM_PAGE;
1495 }
1496 }
1497 else
1498 {
1499 if(!IsDiskSizeValid(PartitionList->CurrentPartition))
1500 {
1501 MUIDisplayError(ERROR_INSUFFICIENT_DISKSPACE, Ir, POPUP_WAIT_ANY_KEY);
1502 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1503 }
1504
1505 return SELECT_FILE_SYSTEM_PAGE;
1506 }
1507 }
1508
1509 while (TRUE)
1510 {
1511 /* Update status text */
1512 if (PartitionList->CurrentPartition == NULL ||
1513 PartitionList->CurrentPartition->Unpartitioned == TRUE)
1514 {
1515 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1516 }
1517 else
1518 {
1519 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1520 }
1521
1522 CONSOLE_ConInKey(Ir);
1523
1524 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1525 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1526 {
1527 if (ConfirmQuit(Ir) == TRUE)
1528 {
1529 DestroyPartitionList(PartitionList);
1530 PartitionList = NULL;
1531 return QUIT_PAGE;
1532 }
1533
1534 break;
1535 }
1536 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1537 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1538 {
1539 ScrollDownPartitionList(PartitionList);
1540 }
1541 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1542 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1543 {
1544 ScrollUpPartitionList(PartitionList);
1545 }
1546 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1547 {
1548 if(!IsDiskSizeValid(PartitionList->CurrentPartition))
1549 {
1550 MUIDisplayError(ERROR_INSUFFICIENT_DISKSPACE, Ir, POPUP_WAIT_ANY_KEY);
1551 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1552 }
1553 if (PartitionList->CurrentPartition == NULL ||
1554 PartitionList->CurrentPartition->Unpartitioned == TRUE)
1555 {
1556 CreateNewPartition(PartitionList,
1557 0ULL,
1558 TRUE);
1559 }
1560
1561 return SELECT_FILE_SYSTEM_PAGE;
1562 }
1563 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'C') /* C */
1564 {
1565 if (PartitionList->CurrentPartition->Unpartitioned == FALSE)
1566 {
1567 MUIDisplayError(ERROR_NEW_PARTITION, Ir, POPUP_WAIT_ANY_KEY);
1568 return SELECT_PARTITION_PAGE;
1569 }
1570
1571 return CREATE_PARTITION_PAGE;
1572 }
1573 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1574 {
1575 if (PartitionList->CurrentPartition->Unpartitioned == TRUE)
1576 {
1577 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1578 return SELECT_PARTITION_PAGE;
1579 }
1580
1581 return DELETE_PARTITION_PAGE;
1582 }
1583 }
1584
1585 return SELECT_PARTITION_PAGE;
1586 }
1587
1588
1589 static VOID
1590 DrawInputField(ULONG FieldLength,
1591 SHORT Left,
1592 SHORT Top,
1593 PCHAR FieldContent)
1594 {
1595 CHAR buf[100];
1596 COORD coPos;
1597 DWORD Written;
1598
1599 coPos.X = Left;
1600 coPos.Y = Top;
1601 memset(buf, '_', sizeof(buf));
1602 buf[FieldLength - strlen(FieldContent)] = 0;
1603 strcat(buf, FieldContent);
1604
1605 WriteConsoleOutputCharacterA(StdOutput,
1606 buf,
1607 strlen(buf),
1608 coPos,
1609 &Written);
1610 }
1611
1612
1613 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 6
1614 /* Restriction for MaxSize: pow(10, PARTITION_SIZE_INPUT_FIELD_LENGTH)-1 */
1615 #define PARTITION_MAXSIZE 999999
1616
1617 static VOID
1618 ShowPartitionSizeInputBox(SHORT Left,
1619 SHORT Top,
1620 SHORT Right,
1621 SHORT Bottom,
1622 ULONG MaxSize,
1623 PCHAR InputBuffer,
1624 PBOOLEAN Quit,
1625 PBOOLEAN Cancel)
1626 {
1627 INPUT_RECORD Ir;
1628 COORD coPos;
1629 DWORD Written;
1630 CHAR Buffer[100];
1631 ULONG Index;
1632 CHAR ch;
1633 SHORT iLeft;
1634 SHORT iTop;
1635
1636 if (Quit != NULL)
1637 *Quit = FALSE;
1638
1639 if (Cancel != NULL)
1640 *Cancel = FALSE;
1641
1642 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1643
1644 /* Print message */
1645 coPos.X = Left + 2;
1646 coPos.Y = Top + 2;
1647 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1648 iLeft = coPos.X + strlen(Buffer) + 1;
1649 iTop = coPos.Y;
1650
1651 WriteConsoleOutputCharacterA(StdOutput,
1652 Buffer,
1653 strlen (Buffer),
1654 coPos,
1655 &Written);
1656
1657 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1658 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1659 coPos.Y = iTop;
1660 WriteConsoleOutputCharacterA(StdOutput,
1661 Buffer,
1662 strlen (Buffer),
1663 coPos,
1664 &Written);
1665
1666 sprintf(Buffer, "%lu", MaxSize);
1667 Index = strlen(Buffer);
1668 DrawInputField(PARTITION_SIZE_INPUT_FIELD_LENGTH,
1669 iLeft,
1670 iTop,
1671 Buffer);
1672
1673 while (TRUE)
1674 {
1675 CONSOLE_ConInKey(&Ir);
1676
1677 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1678 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1679 {
1680 if (Quit != NULL)
1681 *Quit = TRUE;
1682
1683 Buffer[0] = 0;
1684 break;
1685 }
1686 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1687 {
1688 break;
1689 }
1690 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1691 {
1692 if (Cancel != NULL)
1693 *Cancel = TRUE;
1694
1695 Buffer[0] = 0;
1696 break;
1697 }
1698 else if ((Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) && /* BACKSPACE */
1699 (Index > 0))
1700 {
1701 Index--;
1702 Buffer[Index] = 0;
1703
1704 DrawInputField(PARTITION_SIZE_INPUT_FIELD_LENGTH,
1705 iLeft,
1706 iTop,
1707 Buffer);
1708 }
1709 else if ((Ir.Event.KeyEvent.uChar.AsciiChar != 0x00) &&
1710 (Index < PARTITION_SIZE_INPUT_FIELD_LENGTH))
1711 {
1712 ch = Ir.Event.KeyEvent.uChar.AsciiChar;
1713
1714 if ((ch >= '0') && (ch <= '9'))
1715 {
1716 Buffer[Index] = ch;
1717 Index++;
1718 Buffer[Index] = 0;
1719
1720 DrawInputField(PARTITION_SIZE_INPUT_FIELD_LENGTH,
1721 iLeft,
1722 iTop,
1723 Buffer);
1724 }
1725 }
1726 }
1727
1728 strcpy(InputBuffer, Buffer);
1729 }
1730
1731
1732 static PAGE_NUMBER
1733 CreatePartitionPage(PINPUT_RECORD Ir)
1734 {
1735 PDISKENTRY DiskEntry;
1736 PPARTENTRY PartEntry;
1737 BOOLEAN Quit;
1738 BOOLEAN Cancel;
1739 CHAR InputBuffer[50];
1740 ULONG MaxSize;
1741 ULONGLONG PartSize;
1742 ULONGLONG DiskSize;
1743 PCHAR Unit;
1744
1745 if (PartitionList == NULL ||
1746 PartitionList->CurrentDisk == NULL ||
1747 PartitionList->CurrentPartition == NULL)
1748 {
1749 /* FIXME: show an error dialog */
1750 return QUIT_PAGE;
1751 }
1752
1753 DiskEntry = PartitionList->CurrentDisk;
1754 PartEntry = PartitionList->CurrentPartition;
1755
1756 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1757
1758 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1759
1760 #if 0
1761 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1762 {
1763 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1764 Unit = MUIGetString(STRING_GB);
1765 }
1766 else
1767 #endif
1768 {
1769 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1770
1771 if (DiskSize == 0)
1772 DiskSize = 1;
1773
1774 Unit = MUIGetString(STRING_MB);
1775 }
1776
1777 if (DiskEntry->DriverName.Length > 0)
1778 {
1779 CONSOLE_PrintTextXY(6, 10,
1780 MUIGetString(STRING_HDINFOPARTCREATE),
1781 DiskSize,
1782 Unit,
1783 DiskEntry->DiskNumber,
1784 DiskEntry->Port,
1785 DiskEntry->Bus,
1786 DiskEntry->Id,
1787 &DiskEntry->DriverName);
1788 }
1789 else
1790 {
1791 CONSOLE_PrintTextXY(6, 10,
1792 MUIGetString(STRING_HDDINFOUNK1),
1793 DiskSize,
1794 Unit,
1795 DiskEntry->DiskNumber,
1796 DiskEntry->Port,
1797 DiskEntry->Bus,
1798 DiskEntry->Id);
1799 }
1800
1801 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
1802
1803 #if 0
1804 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
1805 PartitionList->CurrentPartition->UnpartitionedLength / (1024*1024));
1806 #endif
1807
1808 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
1809
1810 PartEntry = PartitionList->CurrentPartition;
1811 while (TRUE)
1812 {
1813 MaxSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20; /* in MBytes (rounded) */
1814
1815 if (MaxSize > PARTITION_MAXSIZE) MaxSize = PARTITION_MAXSIZE;
1816
1817 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
1818 MaxSize, InputBuffer, &Quit, &Cancel);
1819
1820 if (Quit == TRUE)
1821 {
1822 if (ConfirmQuit (Ir) == TRUE)
1823 {
1824 return QUIT_PAGE;
1825 }
1826 }
1827 else if (Cancel == TRUE)
1828 {
1829 return SELECT_PARTITION_PAGE;
1830 }
1831 else
1832 {
1833 PartSize = atoi(InputBuffer);
1834
1835 if (PartSize < 1)
1836 {
1837 /* Too small */
1838 continue;
1839 }
1840
1841 if (PartSize > MaxSize)
1842 {
1843 /* Too large */
1844 continue;
1845 }
1846
1847 /* Convert to bytes */
1848 if (PartSize == MaxSize)
1849 {
1850 /* Use all of the unpartitioned disk space */
1851 PartSize = PartEntry->UnpartitionedLength;
1852 }
1853 else
1854 {
1855 /* Round-up by cylinder size */
1856 PartSize = (PartSize * 1024 * 1024 + DiskEntry->CylinderSize - 1) /
1857 DiskEntry->CylinderSize * DiskEntry->CylinderSize;
1858
1859 /* But never get larger than the unpartitioned disk space */
1860 if (PartSize > PartEntry->UnpartitionedLength)
1861 PartSize = PartEntry->UnpartitionedLength;
1862 }
1863
1864 DPRINT ("Partition size: %I64u bytes\n", PartSize);
1865
1866 CreateNewPartition(PartitionList,
1867 PartSize,
1868 FALSE);
1869
1870 return SELECT_PARTITION_PAGE;
1871 }
1872 }
1873
1874 return CREATE_PARTITION_PAGE;
1875 }
1876
1877
1878 static PAGE_NUMBER
1879 DeletePartitionPage(PINPUT_RECORD Ir)
1880 {
1881 PDISKENTRY DiskEntry;
1882 PPARTENTRY PartEntry;
1883 ULONGLONG DiskSize;
1884 ULONGLONG PartSize;
1885 PCHAR Unit;
1886 PCHAR PartType;
1887 UCHAR PartNumber;
1888
1889 if (PartitionList == NULL ||
1890 PartitionList->CurrentDisk == NULL ||
1891 PartitionList->CurrentPartition == NULL)
1892 {
1893 /* FIXME: show an error dialog */
1894 return QUIT_PAGE;
1895 }
1896
1897 DiskEntry = PartitionList->CurrentDisk;
1898 PartEntry = PartitionList->CurrentPartition;
1899 PartNumber = PartitionList->CurrentPartitionNumber;
1900
1901 MUIDisplayPage(DELETE_PARTITION_PAGE);
1902
1903 /* Determine partition type */
1904 PartType = NULL;
1905 if (PartEntry->New == TRUE)
1906 {
1907 PartType = MUIGetString(STRING_UNFORMATTED);
1908 }
1909 else if (PartEntry->Unpartitioned == FALSE)
1910 {
1911 if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_12) ||
1912 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_16) ||
1913 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_HUGE) ||
1914 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_XINT13))
1915 {
1916 PartType = "FAT";
1917 }
1918 else if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32) ||
1919 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32_XINT13))
1920 {
1921 PartType = "FAT32";
1922 }
1923 else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_EXT2)
1924 {
1925 PartType = "EXT2";
1926 }
1927 else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_IFS)
1928 {
1929 PartType = "NTFS"; /* FIXME: Not quite correct! */
1930 }
1931 }
1932
1933 #if 0
1934 if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
1935 {
1936 PartSize = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 29)) >> 30;
1937 Unit = MUIGetString(STRING_GB);
1938 }
1939 else
1940 #endif
1941 if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
1942 {
1943 PartSize = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 19)) >> 20;
1944 Unit = MUIGetString(STRING_MB);
1945 }
1946 else
1947 {
1948 PartSize = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 9)) >> 10;
1949 Unit = MUIGetString(STRING_KB);
1950 }
1951
1952 if (PartType == NULL)
1953 {
1954 CONSOLE_PrintTextXY(6, 10,
1955 MUIGetString(STRING_HDDINFOUNK2),
1956 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
1957 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
1958 PartEntry->PartInfo[PartNumber].PartitionType,
1959 PartSize,
1960 Unit);
1961 }
1962 else
1963 {
1964 CONSOLE_PrintTextXY(6, 10,
1965 " %c%c %s %I64u %s",
1966 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
1967 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
1968 PartType,
1969 PartSize,
1970 Unit);
1971 }
1972
1973 #if 0
1974 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1975 {
1976 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1977 Unit = MUIGetString(STRING_GB);
1978 }
1979 else
1980 #endif
1981 {
1982 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1983
1984 if (DiskSize == 0)
1985 DiskSize = 1;
1986
1987 Unit = MUIGetString(STRING_MB);
1988 }
1989
1990 if (DiskEntry->DriverName.Length > 0)
1991 {
1992 CONSOLE_PrintTextXY(6, 12,
1993 MUIGetString(STRING_HDINFOPARTDELETE),
1994 DiskSize,
1995 Unit,
1996 DiskEntry->DiskNumber,
1997 DiskEntry->Port,
1998 DiskEntry->Bus,
1999 DiskEntry->Id,
2000 &DiskEntry->DriverName);
2001 }
2002 else
2003 {
2004 CONSOLE_PrintTextXY(6, 12,
2005 MUIGetString(STRING_HDDINFOUNK3),
2006 DiskSize,
2007 Unit,
2008 DiskEntry->DiskNumber,
2009 DiskEntry->Port,
2010 DiskEntry->Bus,
2011 DiskEntry->Id);
2012 }
2013
2014 while (TRUE)
2015 {
2016 CONSOLE_ConInKey(Ir);
2017
2018 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2019 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2020 {
2021 if (ConfirmQuit(Ir) == TRUE)
2022 {
2023 return QUIT_PAGE;
2024 }
2025
2026 break;
2027 }
2028 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2029 {
2030 return SELECT_PARTITION_PAGE;
2031 }
2032 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2033 {
2034 DeleteCurrentPartition(PartitionList);
2035
2036 return SELECT_PARTITION_PAGE;
2037 }
2038 }
2039
2040 return DELETE_PARTITION_PAGE;
2041 }
2042
2043
2044 static PAGE_NUMBER
2045 SelectFileSystemPage(PINPUT_RECORD Ir)
2046 {
2047 PDISKENTRY DiskEntry;
2048 PPARTENTRY PartEntry;
2049 UCHAR PartNumber;
2050 ULONGLONG DiskSize;
2051 ULONGLONG PartSize;
2052 PCHAR DiskUnit;
2053 PCHAR PartUnit;
2054 PCHAR PartType;
2055
2056 if (PartitionList == NULL ||
2057 PartitionList->CurrentDisk == NULL ||
2058 PartitionList->CurrentPartition == NULL)
2059 {
2060 /* FIXME: show an error dialog */
2061 return QUIT_PAGE;
2062 }
2063
2064 DiskEntry = PartitionList->CurrentDisk;
2065 PartEntry = PartitionList->CurrentPartition;
2066 PartNumber = PartitionList->CurrentPartitionNumber;
2067
2068 /* adjust disk size */
2069 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
2070 {
2071 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
2072 DiskUnit = MUIGetString(STRING_GB);
2073 }
2074 else
2075 {
2076 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
2077 DiskUnit = MUIGetString(STRING_MB);
2078 }
2079
2080 /* adjust partition size */
2081 if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
2082 {
2083 PartSize = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 29)) >> 30;
2084 PartUnit = MUIGetString(STRING_GB);
2085 }
2086 else
2087 {
2088 PartSize = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 19)) >> 20;
2089 PartUnit = MUIGetString(STRING_MB);
2090 }
2091
2092 /* adjust partition type */
2093 if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_12) ||
2094 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_16) ||
2095 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_HUGE) ||
2096 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_XINT13))
2097 {
2098 PartType = "FAT";
2099 }
2100 else if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32) ||
2101 (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32_XINT13))
2102 {
2103 PartType = "FAT32";
2104 }
2105 else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_EXT2)
2106 {
2107 PartType = "EXT2";
2108 }
2109 else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_IFS)
2110 {
2111 PartType = "NTFS"; /* FIXME: Not quite correct! */
2112 }
2113 else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_ENTRY_UNUSED)
2114 {
2115 PartType = MUIGetString(STRING_FORMATUNUSED);
2116 }
2117 else
2118 {
2119 PartType = MUIGetString(STRING_FORMATUNKNOWN);
2120 }
2121
2122 if (PartEntry->AutoCreate == TRUE)
2123 {
2124 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2125
2126 #if 0
2127 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2128 PartEntry->PartInfo[PartNumber].PartitionNumber,
2129 PartSize,
2130 PartUnit,
2131 PartType);
2132 #endif
2133
2134 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
2135 DiskEntry->DiskNumber,
2136 DiskSize,
2137 DiskUnit,
2138 DiskEntry->Port,
2139 DiskEntry->Bus,
2140 DiskEntry->Id,
2141 &DiskEntry->DriverName);
2142
2143 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2144
2145
2146 PartEntry->AutoCreate = FALSE;
2147 }
2148 else if (PartEntry->New == TRUE)
2149 {
2150 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2151 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2152 }
2153 else
2154 {
2155 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2156
2157 if (PartType == NULL)
2158 {
2159 CONSOLE_PrintTextXY(8, 10,
2160 MUIGetString(STRING_HDDINFOUNK4),
2161 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
2162 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
2163 PartEntry->PartInfo[PartNumber].PartitionType,
2164 PartSize,
2165 PartUnit);
2166 }
2167 else
2168 {
2169 CONSOLE_PrintTextXY(8, 10,
2170 "%c%c %s %I64u %s",
2171 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
2172 (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
2173 PartType,
2174 PartSize,
2175 PartUnit);
2176 }
2177
2178 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
2179 DiskEntry->DiskNumber,
2180 DiskSize,
2181 DiskUnit,
2182 DiskEntry->Port,
2183 DiskEntry->Bus,
2184 DiskEntry->Id,
2185 &DiskEntry->DriverName);
2186 }
2187
2188 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2189
2190 if (FileSystemList == NULL)
2191 {
2192 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2193 if (FileSystemList == NULL)
2194 {
2195 /* FIXME: show an error dialog */
2196 return QUIT_PAGE;
2197 }
2198
2199 /* FIXME: Add file systems to list */
2200 }
2201 DrawFileSystemList(FileSystemList);
2202
2203 if (RepairUpdateFlag)
2204 {
2205 return CHECK_FILE_SYSTEM_PAGE;
2206 //return SELECT_PARTITION_PAGE;
2207 }
2208
2209 if (IsUnattendedSetup)
2210 {
2211 if (UnattendFormatPartition)
2212 {
2213 return FORMAT_PARTITION_PAGE;
2214 }
2215
2216 return CHECK_FILE_SYSTEM_PAGE;
2217 }
2218
2219 while (TRUE)
2220 {
2221 CONSOLE_ConInKey(Ir);
2222
2223 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2224 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2225 {
2226 if (ConfirmQuit(Ir) == TRUE)
2227 {
2228 return QUIT_PAGE;
2229 }
2230
2231 break;
2232 }
2233 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2234 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2235 {
2236 return SELECT_PARTITION_PAGE;
2237 }
2238 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2239 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2240 {
2241 ScrollDownFileSystemList(FileSystemList);
2242 }
2243 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2244 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2245 {
2246 ScrollUpFileSystemList(FileSystemList);
2247 }
2248 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2249 {
2250 if (!FileSystemList->Selected->FormatFunc)
2251 {
2252 return CHECK_FILE_SYSTEM_PAGE;
2253 }
2254 else
2255 {
2256 return FORMAT_PARTITION_PAGE;
2257 }
2258 }
2259 }
2260
2261 return SELECT_FILE_SYSTEM_PAGE;
2262 }
2263
2264
2265 static ULONG
2266 FormatPartitionPage(PINPUT_RECORD Ir)
2267 {
2268 WCHAR PathBuffer[MAX_PATH];
2269 PDISKENTRY DiskEntry;
2270 PPARTENTRY PartEntry;
2271 UCHAR PartNum;
2272 NTSTATUS Status;
2273
2274 #ifndef NDEBUG
2275 ULONG Line;
2276 ULONG i;
2277 PLIST_ENTRY Entry;
2278 #endif
2279
2280 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2281
2282 if (PartitionList == NULL ||
2283 PartitionList->CurrentDisk == NULL ||
2284 PartitionList->CurrentPartition == NULL)
2285 {
2286 /* FIXME: show an error dialog */
2287 return QUIT_PAGE;
2288 }
2289
2290 DiskEntry = PartitionList->CurrentDisk;
2291 PartEntry = PartitionList->CurrentPartition;
2292 PartNum = PartitionList->CurrentPartitionNumber;
2293
2294 while (TRUE)
2295 {
2296 if (!IsUnattendedSetup)
2297 {
2298 CONSOLE_ConInKey(Ir);
2299 }
2300
2301 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2302 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2303 {
2304 if (ConfirmQuit(Ir) == TRUE)
2305 {
2306 return QUIT_PAGE;
2307 }
2308
2309 break;
2310 }
2311 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2312 {
2313 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2314
2315 if (wcscmp(FileSystemList->Selected->FileSystem, L"FAT") == 0)
2316 {
2317 if (PartEntry->PartInfo[PartNum].PartitionLength.QuadPart < (4200LL * 1024LL))
2318 {
2319 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
2320 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_FAT_12;
2321 }
2322 else if (PartEntry->PartInfo[PartNum].StartingOffset.QuadPart < (1024LL * 255LL * 63LL * 512LL))
2323 {
2324 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2325
2326 if (PartEntry->PartInfo[PartNum].PartitionLength.QuadPart < (32LL * 1024LL * 1024LL))
2327 {
2328 /* FAT16 CHS partition (partiton size < 32MB) */
2329 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_FAT_16;
2330 }
2331 else if (PartEntry->PartInfo[PartNum].PartitionLength.QuadPart < (512LL * 1024LL * 1024LL))
2332 {
2333 /* FAT16 CHS partition (partition size < 512MB) */
2334 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_HUGE;
2335 }
2336 else
2337 {
2338 /* FAT32 CHS partition (partition size >= 512MB) */
2339 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_FAT32;
2340 }
2341 }
2342 else
2343 {
2344 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2345
2346 if (PartEntry->PartInfo[PartNum].PartitionLength.QuadPart < (512LL * 1024LL * 1024LL))
2347 {
2348 /* FAT16 LBA partition (partition size < 512MB) */
2349 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_XINT13;
2350 }
2351 else
2352 {
2353 /* FAT32 LBA partition (partition size >= 512MB) */
2354 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_FAT32_XINT13;
2355 }
2356 }
2357 }
2358 else if (wcscmp(FileSystemList->Selected->FileSystem, L"EXT2") == 0)
2359 PartEntry->PartInfo[PartNum].PartitionType = PARTITION_EXT2;
2360 else if (!FileSystemList->Selected->FormatFunc)
2361 return QUIT_PAGE;
2362
2363 CheckActiveBootPartition(PartitionList);
2364
2365 #ifndef NDEBUG
2366 CONSOLE_PrintTextXY(6, 12,
2367 "Disk: %I64u Cylinder: %I64u Track: %I64u",
2368 DiskEntry->DiskSize,
2369 DiskEntry->CylinderSize,
2370 DiskEntry->TrackSize);
2371
2372 Line = 13;
2373 DiskEntry = PartitionList->CurrentDisk;
2374 Entry = DiskEntry->PartListHead.Flink;
2375
2376 while (Entry != &DiskEntry->PartListHead)
2377 {
2378 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2379
2380 if (PartEntry->Unpartitioned == FALSE)
2381 {
2382 for (i = 0; i < 4; i++)
2383 {
2384 CONSOLE_PrintTextXY(6, Line,
2385 "%2u: %2u %c %12I64u %12I64u %2u %c",
2386 i,
2387 PartEntry->PartInfo[i].PartitionNumber,
2388 PartEntry->PartInfo[i].BootIndicator ? 'A' : '-',
2389 PartEntry->PartInfo[i].StartingOffset.QuadPart,
2390 PartEntry->PartInfo[i].PartitionLength.QuadPart,
2391 PartEntry->PartInfo[i].PartitionType,
2392 PartEntry->PartInfo[i].RewritePartition ? '*' : ' ');
2393
2394 Line++;
2395 }
2396
2397 Line++;
2398 }
2399
2400 Entry = Entry->Flink;
2401 }
2402
2403 /* Restore the old entry */
2404 PartEntry = PartitionList->CurrentPartition;
2405 #endif
2406
2407 if (WritePartitionsToDisk(PartitionList) == FALSE)
2408 {
2409 DPRINT("WritePartitionsToDisk() failed\n");
2410 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
2411 return QUIT_PAGE;
2412 }
2413
2414 /* Set DestinationRootPath */
2415 RtlFreeUnicodeString(&DestinationRootPath);
2416 swprintf(PathBuffer,
2417 L"\\Device\\Harddisk%lu\\Partition%lu",
2418 PartitionList->CurrentDisk->DiskNumber,
2419 PartitionList->CurrentPartition->PartInfo[PartNum].PartitionNumber);
2420 RtlCreateUnicodeString(&DestinationRootPath,
2421 PathBuffer);
2422 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
2423
2424
2425 /* Set SystemRootPath */
2426 RtlFreeUnicodeString(&SystemRootPath);
2427 swprintf(PathBuffer,
2428 L"\\Device\\Harddisk%lu\\Partition%lu",
2429 PartitionList->ActiveBootDisk->DiskNumber,
2430 PartitionList->ActiveBootPartition->
2431 PartInfo[PartitionList->ActiveBootPartitionNumber].PartitionNumber);
2432 RtlCreateUnicodeString(&SystemRootPath,
2433 PathBuffer);
2434 DPRINT("SystemRootPath: %wZ\n", &SystemRootPath);
2435
2436
2437 if (FileSystemList->Selected->FormatFunc)
2438 {
2439 Status = FormatPartition(&DestinationRootPath,
2440 FileSystemList->Selected);
2441 if (!NT_SUCCESS(Status))
2442 {
2443 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
2444 /* FIXME: show an error dialog */
2445 return QUIT_PAGE;
2446 }
2447
2448 PartEntry->New = FALSE;
2449
2450 CheckActiveBootPartition(PartitionList);
2451 }
2452
2453 /* Install MBR if necessary */
2454 if (DiskEntry->NoMbr &&
2455 DiskEntry->BiosDiskNumber == 0)
2456 {
2457 wcscpy(PathBuffer, SourceRootPath.Buffer);
2458 wcscat(PathBuffer, L"\\loader\\dosmbr.bin");
2459
2460 DPRINT("Install MBR bootcode: %S ==> %S\n",
2461 PathBuffer, DestinationRootPath.Buffer);
2462
2463 /* Install MBR bootcode */
2464 Status = InstallMbrBootCodeToDisk(PathBuffer,
2465 DestinationRootPath.Buffer);
2466 if (!NT_SUCCESS (Status))
2467 {
2468 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
2469 Status);
2470 return FALSE;
2471 }
2472
2473 DiskEntry->NoMbr = FALSE;
2474 }
2475
2476 if (wcscmp(FileSystemList->Selected->FileSystem, L"FAT") == 0)
2477 {
2478 /* FIXME: Install boot code. This is a hack! */
2479 if ((PartEntry->PartInfo[PartNum].PartitionType == PARTITION_FAT32_XINT13) ||
2480 (PartEntry->PartInfo[PartNum].PartitionType == PARTITION_FAT32))
2481 {
2482 wcscpy(PathBuffer, SourceRootPath.Buffer);
2483 wcscat(PathBuffer, L"\\loader\\fat32.bin");
2484
2485 DPRINT("Install FAT32 bootcode: %S ==> %S\n", PathBuffer,
2486 DestinationRootPath.Buffer);
2487
2488 Status = InstallFat32BootCodeToDisk(PathBuffer,
2489 DestinationRootPath.Buffer);
2490 if (!NT_SUCCESS(Status))
2491 {
2492 DPRINT1("InstallFat32BootCodeToDisk() failed with status 0x%08lx\n", Status);
2493 /* FIXME: show an error dialog */
2494 DestroyFileSystemList(FileSystemList);
2495 FileSystemList = NULL;
2496 return QUIT_PAGE;
2497 }
2498 }
2499 else
2500 {
2501 wcscpy(PathBuffer, SourceRootPath.Buffer);
2502 wcscat(PathBuffer, L"\\loader\\fat.bin");
2503
2504 DPRINT("Install FAT bootcode: %S ==> %S\n", PathBuffer,
2505 DestinationRootPath.Buffer);
2506
2507 Status = InstallFat16BootCodeToDisk(PathBuffer,
2508 DestinationRootPath.Buffer);
2509 if (!NT_SUCCESS(Status))
2510 {
2511 DPRINT1("InstallFat16BootCodeToDisk() failed with status 0x%.08x\n", Status);
2512 /* FIXME: show an error dialog */
2513 DestroyFileSystemList(FileSystemList);
2514 FileSystemList = NULL;
2515 return QUIT_PAGE;
2516 }
2517 }
2518 }
2519 else if (wcscmp(FileSystemList->Selected->FileSystem, L"EXT2") == 0)
2520 {
2521 wcscpy(PathBuffer, SourceRootPath.Buffer);
2522 wcscat(PathBuffer, L"\\loader\\ext2.bin");
2523
2524 DPRINT("Install EXT2 bootcode: %S ==> %S\n", PathBuffer,
2525 DestinationRootPath.Buffer);
2526
2527 Status = InstallFat32BootCodeToDisk(PathBuffer,
2528 DestinationRootPath.Buffer);
2529 if (!NT_SUCCESS(Status))
2530 {
2531 DPRINT1("InstallFat32BootCodeToDisk() failed with status 0x%08lx\n", Status);
2532 /* FIXME: show an error dialog */
2533 DestroyFileSystemList(FileSystemList);
2534 FileSystemList = NULL;
2535 return QUIT_PAGE;
2536 }
2537 }
2538 else if (FileSystemList->Selected->FormatFunc)
2539 {
2540 DestroyFileSystemList(FileSystemList);
2541 FileSystemList = NULL;
2542 return QUIT_PAGE;
2543 }
2544
2545 #ifndef NDEBUG
2546 CONSOLE_SetStatusText(" Done. Press any key ...");
2547 CONSOLE_ConInKey(Ir);
2548 #endif
2549
2550 DestroyFileSystemList(FileSystemList);
2551 FileSystemList = NULL;
2552 return INSTALL_DIRECTORY_PAGE;
2553 }
2554 }
2555
2556 return FORMAT_PARTITION_PAGE;
2557 }
2558
2559
2560 static ULONG
2561 CheckFileSystemPage(PINPUT_RECORD Ir)
2562 {
2563 PFILE_SYSTEM_ITEM CurrentFileSystem;
2564 WCHAR PathBuffer[MAX_PATH];
2565 CHAR Buffer[MAX_PATH];
2566 NTSTATUS Status;
2567 UCHAR PartNum = PartitionList->CurrentPartitionNumber;
2568
2569 /* FIXME: code duplicated in FormatPartitionPage */
2570 /* Set DestinationRootPath */
2571 RtlFreeUnicodeString(&DestinationRootPath);
2572 swprintf(PathBuffer,
2573 L"\\Device\\Harddisk%lu\\Partition%lu",
2574 PartitionList->CurrentDisk->DiskNumber,
2575 PartitionList->CurrentPartition->PartInfo[PartNum].PartitionNumber);
2576 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
2577 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
2578
2579 /* Set SystemRootPath */
2580 RtlFreeUnicodeString(&SystemRootPath);
2581 swprintf(PathBuffer,
2582 L"\\Device\\Harddisk%lu\\Partition%lu",
2583 PartitionList->ActiveBootDisk->DiskNumber,
2584 PartitionList->ActiveBootPartition->PartInfo[PartNum].PartitionNumber);
2585 RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
2586 DPRINT("SystemRootPath: %wZ\n", &SystemRootPath);
2587
2588 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
2589
2590 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2591
2592 /* WRONG: first filesystem is not necesseraly the one of the current partition! */
2593 CurrentFileSystem = CONTAINING_RECORD(FileSystemList->ListHead.Flink, FILE_SYSTEM_ITEM, ListEntry);
2594
2595 if (!CurrentFileSystem->ChkdskFunc)
2596 {
2597 sprintf(Buffer,
2598 "Setup is currently unable to check a partition formatted in %S.\n"
2599 "\n"
2600 " \x07 Press ENTER to continue Setup.\n"
2601 " \x07 Press F3 to quit Setup.",
2602 CurrentFileSystem->FileSystem);
2603
2604 PopupError(Buffer,
2605 MUIGetString(STRING_QUITCONTINUE),
2606 NULL, POPUP_WAIT_NONE);
2607
2608 while (TRUE)
2609 {
2610 CONSOLE_ConInKey(Ir);
2611
2612 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
2613 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
2614 {
2615 if (ConfirmQuit(Ir))
2616 return QUIT_PAGE;
2617 else
2618 return CHECK_FILE_SYSTEM_PAGE;
2619 }
2620 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
2621 {
2622 return INSTALL_DIRECTORY_PAGE;
2623 }
2624 }
2625 }
2626 else
2627 {
2628 Status = ChkdskPartition(&DestinationRootPath, CurrentFileSystem);
2629 if (!NT_SUCCESS(Status))
2630 {
2631 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
2632 sprintf(Buffer, "Setup failed to verify the selected partition.\n"
2633 "(Status 0x%08lx).\n", Status);
2634
2635 PopupError(Buffer,
2636 MUIGetString(STRING_REBOOTCOMPUTER),
2637 Ir, POPUP_WAIT_ENTER);
2638
2639 return QUIT_PAGE;
2640 }
2641
2642 return INSTALL_DIRECTORY_PAGE;
2643 }
2644 }
2645
2646
2647 static PAGE_NUMBER
2648 InstallDirectoryPage1(PWCHAR InstallDir,
2649 PDISKENTRY DiskEntry,
2650 PPARTENTRY PartEntry,
2651 UCHAR PartNum)
2652 {
2653 WCHAR PathBuffer[MAX_PATH];
2654
2655 /* Create 'InstallPath' string */
2656 RtlFreeUnicodeString(&InstallPath);
2657 RtlCreateUnicodeString(&InstallPath,
2658 InstallDir);
2659
2660 /* Create 'DestinationPath' string */
2661 RtlFreeUnicodeString(&DestinationPath);
2662 wcscpy(PathBuffer, DestinationRootPath.Buffer);
2663
2664 if (InstallDir[0] != L'\\')
2665 wcscat(PathBuffer, L"\\");
2666
2667 wcscat(PathBuffer, InstallDir);
2668 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
2669
2670 /* Create 'DestinationArcPath' */
2671 RtlFreeUnicodeString(&DestinationArcPath);
2672 swprintf(PathBuffer,
2673 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
2674 DiskEntry->BiosDiskNumber,
2675 PartEntry->PartInfo[PartNum].PartitionNumber);
2676
2677 if (InstallDir[0] != L'\\')
2678 wcscat(PathBuffer, L"\\");
2679
2680 wcscat(PathBuffer, InstallDir);
2681 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
2682
2683 return PREPARE_COPY_PAGE;
2684 }
2685
2686
2687 static PAGE_NUMBER
2688 InstallDirectoryPage(PINPUT_RECORD Ir)
2689 {
2690 PDISKENTRY DiskEntry;
2691 PPARTENTRY PartEntry;
2692 WCHAR InstallDir[51];
2693 PWCHAR DefaultPath;
2694 INFCONTEXT Context;
2695 ULONG Length;
2696
2697 if (PartitionList == NULL ||
2698 PartitionList->CurrentDisk == NULL ||
2699 PartitionList->CurrentPartition == NULL)
2700 {
2701 /* FIXME: show an error dialog */
2702 return QUIT_PAGE;
2703 }
2704
2705 DiskEntry = PartitionList->CurrentDisk;
2706 PartEntry = PartitionList->CurrentPartition;
2707
2708 /* Search for 'DefaultPath' in the 'SetupData' section */
2709 if (!SetupFindFirstLineW(SetupInf, L"SetupData", L"DefaultPath", &Context))
2710 {
2711 MUIDisplayError(ERROR_FIND_SETUPDATA, Ir, POPUP_WAIT_ENTER);
2712 return QUIT_PAGE;
2713 }
2714
2715 /* Read the 'DefaultPath' data */
2716 if (INF_GetData(&Context, NULL, &DefaultPath))
2717 {
2718 wcscpy(InstallDir, DefaultPath);
2719 }
2720 else
2721 {
2722 wcscpy(InstallDir, L"\\ReactOS");
2723 }
2724
2725 Length = wcslen(InstallDir);
2726 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
2727 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
2728
2729 if (IsUnattendedSetup)
2730 {
2731 return InstallDirectoryPage1(InstallDir,
2732 DiskEntry,
2733 PartEntry,
2734 PartitionList->CurrentPartitionNumber);
2735 }
2736
2737 while (TRUE)
2738 {
2739 CONSOLE_ConInKey(Ir);
2740
2741 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2742 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2743 {
2744 if (ConfirmQuit(Ir) == TRUE)
2745 return QUIT_PAGE;
2746
2747 break;
2748 }
2749 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
2750 {
2751 return InstallDirectoryPage1(InstallDir,
2752 DiskEntry,
2753 PartEntry,
2754 PartitionList->CurrentPartitionNumber);
2755 }
2756 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
2757 {
2758 if (Length > 0)
2759 {
2760 Length--;
2761 InstallDir[Length] = 0;
2762 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
2763 }
2764 }
2765 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
2766 {
2767 if (Length < 50)
2768 {
2769 InstallDir[Length] = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
2770 Length++;
2771 InstallDir[Length] = 0;
2772 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
2773 }
2774 }
2775 }
2776
2777 return INSTALL_DIRECTORY_PAGE;
2778 }
2779
2780
2781 static BOOLEAN
2782 AddSectionToCopyQueueCab(HINF InfFile,
2783 PWCHAR SectionName,
2784 PWCHAR SourceCabinet,
2785 PCUNICODE_STRING DestinationPath,
2786 PINPUT_RECORD Ir)
2787 {
2788 INFCONTEXT FilesContext;
2789 INFCONTEXT DirContext;
2790 PWCHAR FileKeyName;
2791 PWCHAR FileKeyValue;
2792 PWCHAR DirKeyValue;
2793 PWCHAR TargetFileName;
2794
2795 /* Search for the SectionName section */
2796 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
2797 {
2798 char Buffer[128];
2799 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
2800 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
2801 return FALSE;
2802 }
2803
2804 /*
2805 * Enumerate the files in the section
2806 * and add them to the file queue.
2807 */
2808 do
2809 {
2810 /* Get source file name and target directory id */
2811 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
2812 {
2813 /* FIXME: Handle error! */
2814 DPRINT1("INF_GetData() failed\n");
2815 break;
2816 }
2817
2818 /* Get optional target file name */
2819 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
2820 TargetFileName = NULL;
2821
2822 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
2823
2824 /* Lookup target directory */
2825 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
2826 {
2827 /* FIXME: Handle error! */
2828 DPRINT1("SetupFindFirstLine() failed\n");
2829 break;
2830 }
2831
2832 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
2833 {
2834 /* FIXME: Handle error! */
2835 DPRINT1("INF_GetData() failed\n");
2836 break;
2837 }
2838
2839 if (!SetupQueueCopy(SetupFileQueue,
2840 SourceCabinet,
2841 SourceRootPath.Buffer,
2842 SourceRootDir.Buffer,
2843 FileKeyName,
2844 DirKeyValue,
2845 TargetFileName))
2846 {
2847 /* FIXME: Handle error! */
2848 DPRINT1("SetupQueueCopy() failed\n");
2849 }
2850 } while (SetupFindNextLine(&FilesContext, &FilesContext));
2851
2852 return TRUE;
2853 }
2854
2855
2856 static BOOLEAN
2857 AddSectionToCopyQueue(HINF InfFile,
2858 PWCHAR SectionName,
2859 PWCHAR SourceCabinet,
2860 PCUNICODE_STRING DestinationPath,
2861 PINPUT_RECORD Ir)
2862 {
2863 INFCONTEXT FilesContext;
2864 INFCONTEXT DirContext;
2865 PWCHAR FileKeyName;
2866 PWCHAR FileKeyValue;
2867 PWCHAR DirKeyValue;
2868 PWCHAR TargetFileName;
2869
2870 if (SourceCabinet)
2871 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
2872
2873 /* Search for the SectionName section */
2874 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
2875 {
2876 char Buffer[128];
2877 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
2878 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
2879 return FALSE;
2880 }
2881
2882 /*
2883 * Enumerate the files in the section
2884 * and add them to the file queue.
2885 */
2886 do
2887 {
2888 /* Get source file name and target directory id */
2889 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
2890 {
2891 /* FIXME: Handle error! */
2892 DPRINT1("INF_GetData() failed\n");
2893 break;
2894 }
2895
2896 /* Get target directory id */
2897 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
2898 {
2899 /* FIXME: Handle error! */
2900 DPRINT1("INF_GetData() failed\n");
2901 break;
2902 }
2903
2904 /* Get optional target file name */
2905 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
2906 TargetFileName = NULL;
2907 else if (!*TargetFileName)
2908 TargetFileName = NULL;
2909
2910 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
2911
2912 /* Lookup target directory */
2913 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
2914 {
2915 /* FIXME: Handle error! */
2916 DPRINT1("SetupFindFirstLine() failed\n");
2917 break;
2918 }
2919
2920 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
2921 {
2922 /* FIXME: Handle error! */
2923 DPRINT1("INF_GetData() failed\n");
2924 break;
2925 }
2926
2927 if (!SetupQueueCopy(SetupFileQueue,
2928 SourceCabinet,
2929 SourceRootPath.Buffer,
2930 SourceRootDir.Buffer,
2931 FileKeyName,
2932 DirKeyValue,
2933 TargetFileName))
2934 {
2935 /* FIXME: Handle error! */
2936 DPRINT1("SetupQueueCopy() failed\n");
2937 }
2938 } while (SetupFindNextLine(&FilesContext, &FilesContext));
2939
2940 return TRUE;
2941 }
2942
2943
2944 static BOOLEAN
2945 PrepareCopyPageInfFile(HINF InfFile,
2946 PWCHAR SourceCabinet,
2947 PINPUT_RECORD Ir)
2948 {
2949 WCHAR PathBuffer[MAX_PATH];
2950 INFCONTEXT DirContext;
2951 PWCHAR AdditionalSectionName = NULL;
2952 PWCHAR KeyValue;
2953 ULONG Length;
2954 NTSTATUS Status;
2955
2956 /* Add common files */
2957 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
2958 return FALSE;
2959
2960 /* Add specific files depending of computer type */
2961 if (SourceCabinet == NULL)
2962 {
2963 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
2964 return FALSE;
2965
2966 if (AdditionalSectionName)
2967 {
2968 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
2969 return FALSE;
2970 }
2971 }
2972
2973 /* Create directories */
2974
2975 /*
2976 * FIXME:
2977 * Install directories like '\reactos\test' are not handled yet.
2978 */
2979
2980 /* Get destination path */
2981 wcscpy(PathBuffer, DestinationPath.Buffer);
2982
2983 /* Remove trailing backslash */
2984 Length = wcslen(PathBuffer);
2985 if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
2986 {
2987 PathBuffer[Length - 1] = 0;
2988 }
2989
2990 /* Create the install directory */
2991 Status = SetupCreateDirectory(PathBuffer);
2992 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
2993 {
2994 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
2995 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
2996 return FALSE;
2997 }
2998
2999 /* Search for the 'Directories' section */
3000 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3001 {
3002 if (SourceCabinet)
3003 {
3004 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
3005 }
3006 else
3007 {
3008 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
3009 }
3010
3011 return FALSE;
3012 }
3013
3014 /* Enumerate the directory values and create the subdirectories */
3015 do
3016 {
3017 if (!INF_GetData(&DirContext, NULL, &KeyValue))
3018 {
3019 DPRINT1("break\n");
3020 break;
3021 }
3022
3023 if (KeyValue[0] == L'\\' && KeyValue[1] != 0)
3024 {
3025 DPRINT("Absolute Path: '%S'\n", KeyValue);
3026
3027 wcscpy(PathBuffer, DestinationRootPath.Buffer);
3028 wcscat(PathBuffer, KeyValue);
3029
3030 DPRINT("FullPath: '%S'\n", PathBuffer);
3031 }
3032 else if (KeyValue[0] != L'\\')
3033 {
3034 DPRINT("RelativePath: '%S'\n", KeyValue);
3035 wcscpy(PathBuffer, DestinationPath.Buffer);
3036 wcscat(PathBuffer, L"\\");
3037 wcscat(PathBuffer, KeyValue);
3038
3039 DPRINT("FullPath: '%S'\n", PathBuffer);
3040
3041 Status = SetupCreateDirectory(PathBuffer);
3042 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3043 {
3044 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3045 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3046 return FALSE;
3047 }
3048 }
3049 } while (SetupFindNextLine (&DirContext, &DirContext));
3050
3051 return TRUE;
3052 }
3053
3054
3055 static PAGE_NUMBER
3056 PrepareCopyPage(PINPUT_RECORD Ir)
3057 {
3058 HINF InfHandle;
3059 WCHAR PathBuffer[MAX_PATH];
3060 INFCONTEXT CabinetsContext;
3061 ULONG InfFileSize;
3062 PWCHAR KeyValue;
3063 UINT ErrorLine;
3064 PVOID InfFileData;
3065
3066 MUIDisplayPage(PREPARE_COPY_PAGE);
3067
3068 /* Create the file queue */
3069 SetupFileQueue = SetupOpenFileQueue();
3070 if (SetupFileQueue == NULL)
3071 {
3072 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
3073 return(QUIT_PAGE);
3074 }
3075
3076 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
3077 {
3078 return QUIT_PAGE;
3079 }
3080
3081 /* Search for the 'Cabinets' section */
3082 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
3083 {
3084 return FILE_COPY_PAGE;
3085 }
3086
3087 /*
3088 * Enumerate the directory values in the 'Cabinets'
3089 * section and parse their inf files.
3090 */
3091 do
3092 {
3093 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3094 break;
3095
3096 wcscpy(PathBuffer, SourcePath.Buffer);
3097 wcscat(PathBuffer, L"\\");
3098 wcscat(PathBuffer, KeyValue);
3099
3100 #ifdef __REACTOS__
3101 CabinetInitialize();
3102 CabinetSetEventHandlers(NULL, NULL, NULL);
3103 CabinetSetCabinetName(PathBuffer);
3104
3105 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3106 {
3107 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3108
3109 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3110 if (InfFileData == NULL)
3111 {
3112 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3113 return QUIT_PAGE;
3114 }
3115 }
3116 else
3117 {
3118 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3119 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3120 return QUIT_PAGE;
3121 }
3122
3123 InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
3124 InfFileSize,
3125 (const CHAR*) NULL,
3126 INF_STYLE_WIN4,
3127 LanguageId,
3128 &ErrorLine);
3129
3130 if (InfHandle == INVALID_HANDLE_VALUE)
3131 {
3132 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3133 return QUIT_PAGE;
3134 }
3135
3136 CabinetCleanup();
3137
3138 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3139 {
3140 return QUIT_PAGE;
3141 }
3142 #endif
3143 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3144
3145 return FILE_COPY_PAGE;
3146 }
3147
3148
3149 VOID
3150 NTAPI
3151 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3152 IN BOOLEAN First)
3153 {
3154 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3155
3156 /* Get the memory information from the system */
3157 NtQuerySystemInformation(SystemPerformanceInformation,
3158 &PerfInfo,
3159 sizeof(PerfInfo),
3160 NULL);
3161
3162 /* Check if this is initial setup */
3163 if (First)
3164 {
3165 /* Set maximum limits to be total RAM pages */
3166 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3167 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3168 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3169 }
3170
3171 /* Set current values */
3172 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3173 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3174 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3175 }
3176
3177
3178 static UINT
3179 CALLBACK
3180 FileCopyCallback(PVOID Context,
3181 UINT Notification,
3182 UINT_PTR Param1,
3183 UINT_PTR Param2)
3184 {
3185 PCOPYCONTEXT CopyContext;
3186
3187 CopyContext = (PCOPYCONTEXT)Context;
3188
3189 switch (Notification)
3190 {
3191 case SPFILENOTIFY_STARTSUBQUEUE:
3192 CopyContext->TotalOperations = (ULONG)Param2;
3193 ProgressSetStepCount(CopyContext->ProgressBar,
3194 CopyContext->TotalOperations);
3195 SetupUpdateMemoryInfo(CopyContext, TRUE);
3196 break;
3197
3198 case SPFILENOTIFY_STARTCOPY:
3199 /* Display copy message */
3200 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
3201 SetupUpdateMemoryInfo(CopyContext, FALSE);
3202 break;
3203
3204 case SPFILENOTIFY_ENDCOPY:
3205 CopyContext->CompletedOperations++;
3206 ProgressNextStep(CopyContext->ProgressBar);
3207 SetupUpdateMemoryInfo(CopyContext, FALSE);
3208 break;
3209 }
3210
3211 return 0;
3212 }
3213
3214
3215 static
3216 PAGE_NUMBER
3217 FileCopyPage(PINPUT_RECORD Ir)
3218 {
3219 COPYCONTEXT CopyContext;
3220 unsigned int mem_bar_width;
3221
3222 MUIDisplayPage(FILE_COPY_PAGE);
3223
3224 /* Create context for the copy process */
3225 CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
3226 CopyContext.InstallPath = InstallPath.Buffer;
3227 CopyContext.TotalOperations = 0;
3228 CopyContext.CompletedOperations = 0;
3229
3230 /* Create the progress bar as well */
3231 CopyContext.ProgressBar = CreateProgressBar(13,
3232 26,
3233 xScreen - 13,
3234 yScreen - 20,
3235 10,
3236 24,
3237 TRUE,