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