* Sync with recent trunk (r52637).
[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 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 m1, m2;
1405
1406 /* check for unpartitioned space */
1407 m1 = PartEntry->UnpartitionedLength;
1408 m1 = (m1 + (1 << 19)) >> 20; /* in MBytes (rounded) */
1409
1410 if( m1 > RequiredPartitionDiskSpace)
1411 {
1412 return TRUE;
1413 }
1414
1415 /* check for partitioned space */
1416 m2 = PartEntry->PartInfo[0].PartitionLength.QuadPart;
1417 m2 = (m2 + (1 << 19)) >> 20; /* in MBytes (rounded) */
1418 if (m2 < RequiredPartitionDiskSpace)
1419 {
1420 /* partition is too small so ask for another partion */
1421 DPRINT1("Partition is too small(unpartitioned: %I64u MB, partitioned: %I64u MB), required disk space is %lu MB\n", m1, m2, 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 #ifndef NDEBUG
2454 CONSOLE_SetStatusText(" Done. Press any key ...");
2455 CONSOLE_ConInKey(Ir);
2456 #endif
2457
2458 DestroyFileSystemList(FileSystemList);
2459 FileSystemList = NULL;
2460 return INSTALL_DIRECTORY_PAGE;
2461 }
2462 }
2463
2464 return FORMAT_PARTITION_PAGE;
2465 }
2466
2467
2468 static ULONG
2469 CheckFileSystemPage(PINPUT_RECORD Ir)
2470 {
2471 PFILE_SYSTEM_ITEM CurrentFileSystem;
2472 WCHAR PathBuffer[MAX_PATH];
2473 CHAR Buffer[MAX_PATH];
2474 NTSTATUS Status;
2475 UCHAR PartNum = PartitionList->CurrentPartitionNumber;
2476
2477 /* FIXME: code duplicated in FormatPartitionPage */
2478 /* Set DestinationRootPath */
2479 RtlFreeUnicodeString(&DestinationRootPath);
2480 swprintf(PathBuffer,
2481 L"\\Device\\Harddisk%lu\\Partition%lu",
2482 PartitionList->CurrentDisk->DiskNumber,
2483 PartitionList->CurrentPartition->PartInfo[PartNum].PartitionNumber);
2484 RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
2485 DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
2486
2487 /* Set SystemRootPath */
2488 RtlFreeUnicodeString(&SystemRootPath);
2489 swprintf(PathBuffer,
2490 L"\\Device\\Harddisk%lu\\Partition%lu",
2491 PartitionList->ActiveBootDisk->DiskNumber,
2492 PartitionList->ActiveBootPartition->PartInfo[PartNum].PartitionNumber);
2493 RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
2494 DPRINT("SystemRootPath: %wZ\n", &SystemRootPath);
2495
2496 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
2497
2498 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2499
2500 /* WRONG: first filesystem is not necesseraly the one of the current partition! */
2501 CurrentFileSystem = CONTAINING_RECORD(FileSystemList->ListHead.Flink, FILE_SYSTEM_ITEM, ListEntry);
2502
2503 if (!CurrentFileSystem->ChkdskFunc)
2504 {
2505 sprintf(Buffer,
2506 "Setup is currently unable to check a partition formatted in %S.\n"
2507 "\n"
2508 " \x07 Press ENTER to continue Setup.\n"
2509 " \x07 Press F3 to quit Setup.",
2510 CurrentFileSystem->FileSystem);
2511
2512 PopupError(Buffer,
2513 MUIGetString(STRING_QUITCONTINUE),
2514 NULL, POPUP_WAIT_NONE);
2515
2516 while (TRUE)
2517 {
2518 CONSOLE_ConInKey(Ir);
2519
2520 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
2521 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
2522 {
2523 if (ConfirmQuit(Ir))
2524 return QUIT_PAGE;
2525 else
2526 return CHECK_FILE_SYSTEM_PAGE;
2527 }
2528 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
2529 {
2530 return INSTALL_DIRECTORY_PAGE;
2531 }
2532 }
2533 }
2534 else
2535 {
2536 Status = ChkdskPartition(&DestinationRootPath, CurrentFileSystem);
2537 if (!NT_SUCCESS(Status))
2538 {
2539 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
2540 sprintf(Buffer, "Setup failed to verify the selected partition.\n"
2541 "(Status 0x%08lx).\n", Status);
2542
2543 PopupError(Buffer,
2544 MUIGetString(STRING_REBOOTCOMPUTER),
2545 Ir, POPUP_WAIT_ENTER);
2546
2547 return QUIT_PAGE;
2548 }
2549
2550 return INSTALL_DIRECTORY_PAGE;
2551 }
2552 }
2553
2554
2555 static PAGE_NUMBER
2556 InstallDirectoryPage1(PWCHAR InstallDir,
2557 PDISKENTRY DiskEntry,
2558 PPARTENTRY PartEntry,
2559 UCHAR PartNum)
2560 {
2561 WCHAR PathBuffer[MAX_PATH];
2562
2563 /* Create 'InstallPath' string */
2564 RtlFreeUnicodeString(&InstallPath);
2565 RtlCreateUnicodeString(&InstallPath,
2566 InstallDir);
2567
2568 /* Create 'DestinationPath' string */
2569 RtlFreeUnicodeString(&DestinationPath);
2570 wcscpy(PathBuffer, DestinationRootPath.Buffer);
2571
2572 if (InstallDir[0] != L'\\')
2573 wcscat(PathBuffer, L"\\");
2574
2575 wcscat(PathBuffer, InstallDir);
2576 RtlCreateUnicodeString(&DestinationPath, PathBuffer);
2577
2578 /* Create 'DestinationArcPath' */
2579 RtlFreeUnicodeString(&DestinationArcPath);
2580 swprintf(PathBuffer,
2581 L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
2582 DiskEntry->BiosDiskNumber,
2583 PartEntry->PartInfo[PartNum].PartitionNumber);
2584
2585 if (InstallDir[0] != L'\\')
2586 wcscat(PathBuffer, L"\\");
2587
2588 wcscat(PathBuffer, InstallDir);
2589 RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
2590
2591 return PREPARE_COPY_PAGE;
2592 }
2593
2594
2595 static PAGE_NUMBER
2596 InstallDirectoryPage(PINPUT_RECORD Ir)
2597 {
2598 PDISKENTRY DiskEntry;
2599 PPARTENTRY PartEntry;
2600 WCHAR InstallDir[51];
2601 PWCHAR DefaultPath;
2602 INFCONTEXT Context;
2603 ULONG Length;
2604
2605 if (PartitionList == NULL ||
2606 PartitionList->CurrentDisk == NULL ||
2607 PartitionList->CurrentPartition == NULL)
2608 {
2609 /* FIXME: show an error dialog */
2610 return QUIT_PAGE;
2611 }
2612
2613 DiskEntry = PartitionList->CurrentDisk;
2614 PartEntry = PartitionList->CurrentPartition;
2615
2616 /* Search for 'DefaultPath' in the 'SetupData' section */
2617 if (!SetupFindFirstLineW(SetupInf, L"SetupData", L"DefaultPath", &Context))
2618 {
2619 MUIDisplayError(ERROR_FIND_SETUPDATA, Ir, POPUP_WAIT_ENTER);
2620 return QUIT_PAGE;
2621 }
2622
2623 /* Read the 'DefaultPath' data */
2624 if (INF_GetData(&Context, NULL, &DefaultPath))
2625 {
2626 wcscpy(InstallDir, DefaultPath);
2627 }
2628 else
2629 {
2630 wcscpy(InstallDir, L"\\ReactOS");
2631 }
2632
2633 Length = wcslen(InstallDir);
2634 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
2635 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
2636
2637 if (IsUnattendedSetup)
2638 {
2639 return InstallDirectoryPage1(InstallDir,
2640 DiskEntry,
2641 PartEntry,
2642 PartitionList->CurrentPartitionNumber);
2643 }
2644
2645 while (TRUE)
2646 {
2647 CONSOLE_ConInKey(Ir);
2648
2649 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2650 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2651 {
2652 if (ConfirmQuit(Ir) == TRUE)
2653 return QUIT_PAGE;
2654
2655 break;
2656 }
2657 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
2658 {
2659 return InstallDirectoryPage1(InstallDir,
2660 DiskEntry,
2661 PartEntry,
2662 PartitionList->CurrentPartitionNumber);
2663 }
2664 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
2665 {
2666 if (Length > 0)
2667 {
2668 Length--;
2669 InstallDir[Length] = 0;
2670 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
2671 }
2672 }
2673 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
2674 {
2675 if (Length < 50)
2676 {
2677 InstallDir[Length] = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
2678 Length++;
2679 InstallDir[Length] = 0;
2680 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
2681 }
2682 }
2683 }
2684
2685 return INSTALL_DIRECTORY_PAGE;
2686 }
2687
2688
2689 static BOOLEAN
2690 AddSectionToCopyQueueCab(HINF InfFile,
2691 PWCHAR SectionName,
2692 PWCHAR SourceCabinet,
2693 PCUNICODE_STRING DestinationPath,
2694 PINPUT_RECORD Ir)
2695 {
2696 INFCONTEXT FilesContext;
2697 INFCONTEXT DirContext;
2698 PWCHAR FileKeyName;
2699 PWCHAR FileKeyValue;
2700 PWCHAR DirKeyValue;
2701 PWCHAR TargetFileName;
2702
2703 /* Search for the SectionName section */
2704 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
2705 {
2706 char Buffer[128];
2707 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
2708 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
2709 return FALSE;
2710 }
2711
2712 /*
2713 * Enumerate the files in the section
2714 * and add them to the file queue.
2715 */
2716 do
2717 {
2718 /* Get source file name and target directory id */
2719 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
2720 {
2721 /* FIXME: Handle error! */
2722 DPRINT1("INF_GetData() failed\n");
2723 break;
2724 }
2725
2726 /* Get optional target file name */
2727 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
2728 TargetFileName = NULL;
2729
2730 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
2731
2732 /* Lookup target directory */
2733 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
2734 {
2735 /* FIXME: Handle error! */
2736 DPRINT1("SetupFindFirstLine() failed\n");
2737 break;
2738 }
2739
2740 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
2741 {
2742 /* FIXME: Handle error! */
2743 DPRINT1("INF_GetData() failed\n");
2744 break;
2745 }
2746
2747 if (!SetupQueueCopy(SetupFileQueue,
2748 SourceCabinet,
2749 SourceRootPath.Buffer,
2750 SourceRootDir.Buffer,
2751 FileKeyName,
2752 DirKeyValue,
2753 TargetFileName))
2754 {
2755 /* FIXME: Handle error! */
2756 DPRINT1("SetupQueueCopy() failed\n");
2757 }
2758 } while (SetupFindNextLine(&FilesContext, &FilesContext));
2759
2760 return TRUE;
2761 }
2762
2763
2764 static BOOLEAN
2765 AddSectionToCopyQueue(HINF InfFile,
2766 PWCHAR SectionName,
2767 PWCHAR SourceCabinet,
2768 PCUNICODE_STRING DestinationPath,
2769 PINPUT_RECORD Ir)
2770 {
2771 INFCONTEXT FilesContext;
2772 INFCONTEXT DirContext;
2773 PWCHAR FileKeyName;
2774 PWCHAR FileKeyValue;
2775 PWCHAR DirKeyValue;
2776 PWCHAR TargetFileName;
2777 WCHAR CompleteOrigFileName[512];
2778
2779 if (SourceCabinet)
2780 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
2781
2782 /* Search for the SectionName section */
2783 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
2784 {
2785 char Buffer[128];
2786 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
2787 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
2788 return FALSE;
2789 }
2790
2791 /*
2792 * Enumerate the files in the section
2793 * and add them to the file queue.
2794 */
2795 do
2796 {
2797 /* Get source file name and target directory id */
2798 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
2799 {
2800 /* FIXME: Handle error! */
2801 DPRINT1("INF_GetData() failed\n");
2802 break;
2803 }
2804
2805 /* Get target directory id */
2806 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
2807 {
2808 /* FIXME: Handle error! */
2809 DPRINT1("INF_GetData() failed\n");
2810 break;
2811 }
2812
2813 /* Get optional target file name */
2814 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
2815 TargetFileName = NULL;
2816 else if (!*TargetFileName)
2817 TargetFileName = NULL;
2818
2819 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
2820
2821 /* Lookup target directory */
2822 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
2823 {
2824 /* FIXME: Handle error! */
2825 DPRINT1("SetupFindFirstLine() failed\n");
2826 break;
2827 }
2828
2829 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
2830 {
2831 /* FIXME: Handle error! */
2832 DPRINT1("INF_GetData() failed\n");
2833 break;
2834 }
2835
2836 wcscpy(CompleteOrigFileName, SourceRootDir.Buffer);
2837 wcscat(CompleteOrigFileName, L"\\");
2838 wcscat(CompleteOrigFileName, DirKeyValue);
2839
2840 if (!SetupQueueCopy(SetupFileQueue,
2841 SourceCabinet,
2842 SourceRootPath.Buffer,
2843 CompleteOrigFileName,
2844 FileKeyName,
2845 DirKeyValue,
2846 TargetFileName))
2847 {
2848 /* FIXME: Handle error! */
2849 DPRINT1("SetupQueueCopy() failed\n");
2850 }
2851 } while (SetupFindNextLine(&FilesContext, &FilesContext));
2852
2853 return TRUE;
2854 }
2855
2856
2857 static BOOLEAN
2858 PrepareCopyPageInfFile(HINF InfFile,
2859 PWCHAR SourceCabinet,
2860 PINPUT_RECORD Ir)
2861 {
2862 WCHAR PathBuffer[MAX_PATH];
2863 INFCONTEXT DirContext;
2864 PWCHAR AdditionalSectionName = NULL;
2865 PWCHAR KeyValue;
2866 ULONG Length;
2867 NTSTATUS Status;
2868
2869 /* Add common files */
2870 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
2871 return FALSE;
2872
2873 /* Add specific files depending of computer type */
2874 if (SourceCabinet == NULL)
2875 {
2876 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
2877 return FALSE;
2878
2879 if (AdditionalSectionName)
2880 {
2881 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
2882 return FALSE;
2883 }
2884 }
2885
2886 /* Create directories */
2887
2888 /*
2889 * FIXME:
2890 * Install directories like '\reactos\test' are not handled yet.
2891 */
2892
2893 /* Get destination path */
2894 wcscpy(PathBuffer, DestinationPath.Buffer);
2895
2896 /* Remove trailing backslash */
2897 Length = wcslen(PathBuffer);
2898 if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
2899 {
2900 PathBuffer[Length - 1] = 0;
2901 }
2902
2903 /* Create the install directory */
2904 Status = SetupCreateDirectory(PathBuffer);
2905 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
2906 {
2907 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
2908 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
2909 return FALSE;
2910 }
2911
2912 /* Search for the 'Directories' section */
2913 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
2914 {
2915 if (SourceCabinet)
2916 {
2917 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
2918 }
2919 else
2920 {
2921 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
2922 }
2923
2924 return FALSE;
2925 }
2926
2927 /* Enumerate the directory values and create the subdirectories */
2928 do
2929 {
2930 if (!INF_GetData(&DirContext, NULL, &KeyValue))
2931 {
2932 DPRINT1("break\n");
2933 break;
2934 }
2935
2936 if (KeyValue[0] == L'\\' && KeyValue[1] != 0)
2937 {
2938 DPRINT("Absolute Path: '%S'\n", KeyValue);
2939
2940 wcscpy(PathBuffer, DestinationRootPath.Buffer);
2941 wcscat(PathBuffer, KeyValue);
2942
2943 DPRINT("FullPath: '%S'\n", PathBuffer);
2944 }
2945 else if (KeyValue[0] != L'\\')
2946 {
2947 DPRINT("RelativePath: '%S'\n", KeyValue);
2948 wcscpy(PathBuffer, DestinationPath.Buffer);
2949 wcscat(PathBuffer, L"\\");
2950 wcscat(PathBuffer, KeyValue);
2951
2952 DPRINT("FullPath: '%S'\n", PathBuffer);
2953
2954 Status = SetupCreateDirectory(PathBuffer);
2955 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
2956 {
2957 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
2958 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
2959 return FALSE;
2960 }
2961 }
2962 } while (SetupFindNextLine (&DirContext, &DirContext));
2963
2964 return TRUE;
2965 }
2966
2967
2968 static PAGE_NUMBER
2969 PrepareCopyPage(PINPUT_RECORD Ir)
2970 {
2971 HINF InfHandle;
2972 WCHAR PathBuffer[MAX_PATH];
2973 INFCONTEXT CabinetsContext;
2974 ULONG InfFileSize;
2975 PWCHAR KeyValue;
2976 UINT ErrorLine;
2977 PVOID InfFileData;
2978
2979 MUIDisplayPage(PREPARE_COPY_PAGE);
2980
2981 /* Create the file queue */
2982 SetupFileQueue = SetupOpenFileQueue();
2983 if (SetupFileQueue == NULL)
2984 {
2985 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
2986 return(QUIT_PAGE);
2987 }
2988
2989 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
2990 {
2991 return QUIT_PAGE;
2992 }
2993
2994 /* Search for the 'Cabinets' section */
2995 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
2996 {
2997 return FILE_COPY_PAGE;
2998 }
2999
3000 /*
3001 * Enumerate the directory values in the 'Cabinets'
3002 * section and parse their inf files.
3003 */
3004 do
3005 {
3006 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3007 break;
3008
3009 wcscpy(PathBuffer, SourcePath.Buffer);
3010 wcscat(PathBuffer, L"\\");
3011 wcscat(PathBuffer, KeyValue);
3012
3013 #ifdef __REACTOS__
3014 CabinetInitialize();
3015 CabinetSetEventHandlers(NULL, NULL, NULL);
3016 CabinetSetCabinetName(PathBuffer);
3017
3018 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3019 {
3020 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3021
3022 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3023 if (InfFileData == NULL)
3024 {
3025 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3026 return QUIT_PAGE;
3027 }
3028 }
3029 else
3030 {
3031 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3032 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3033 return QUIT_PAGE;
3034 }
3035
3036 InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
3037 InfFileSize,
3038 (const CHAR*) NULL,
3039 INF_STYLE_WIN4,
3040 LanguageId,
3041 &ErrorLine);
3042
3043 if (InfHandle == INVALID_HANDLE_VALUE)
3044 {
3045 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3046 return QUIT_PAGE;
3047 }
3048
3049 CabinetCleanup();
3050
3051 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3052 {
3053 return QUIT_PAGE;
3054 }
3055 #endif
3056 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3057
3058 return FILE_COPY_PAGE;
3059 }
3060
3061
3062 VOID
3063 NTAPI
3064 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3065 IN BOOLEAN First)
3066 {
3067 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3068
3069 /* Get the memory information from the system */
3070 NtQuerySystemInformation(SystemPerformanceInformation,
3071 &PerfInfo,
3072 sizeof(PerfInfo),
3073 NULL);
3074
3075 /* Check if this is initial setup */
3076 if (First)
3077 {
3078 /* Set maximum limits to be total RAM pages */
3079 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3080 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3081 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3082 }
3083
3084 /* Set current values */
3085 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3086 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3087 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3088 }
3089
3090
3091 static UINT
3092 CALLBACK
3093 FileCopyCallback(PVOID Context,
3094 UINT Notification,
3095 UINT_PTR Param1,
3096 UINT_PTR Param2)
3097 {
3098 PCOPYCONTEXT CopyContext;
3099
3100 CopyContext = (PCOPYCONTEXT)Context;
3101
3102 switch (Notification)
3103 {
3104 case SPFILENOTIFY_STARTSUBQUEUE:
3105 CopyContext->TotalOperations = (ULONG)Param2;
3106 ProgressSetStepCount(CopyContext->ProgressBar,
3107 CopyContext->TotalOperations);
3108 SetupUpdateMemoryInfo(CopyContext, TRUE);
3109 break;
3110
3111 case SPFILENOTIFY_STARTCOPY:
3112 /* Display copy message */
3113 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
3114 SetupUpdateMemoryInfo(CopyContext, FALSE);
3115 break;
3116
3117 case SPFILENOTIFY_ENDCOPY:
3118 CopyContext->CompletedOperations++;
3119 ProgressNextStep(CopyContext->ProgressBar);
3120 SetupUpdateMemoryInfo(CopyContext, FALSE);
3121 break;
3122 }
3123
3124 return 0;
3125 }
3126
3127
3128 static
3129 PAGE_NUMBER
3130 FileCopyPage(PINPUT_RECORD Ir)
3131 {
3132 COPYCONTEXT CopyContext;
3133 unsigned int mem_bar_width;
3134
3135 MUIDisplayPage(FILE_COPY_PAGE);
3136
3137 /* Create context for the copy process */
3138 CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
3139 CopyContext.InstallPath = InstallPath.Buffer;
3140 CopyContext.TotalOperations = 0;
3141 CopyContext.CompletedOperations = 0;
3142
3143 /* Create the progress bar as well */
3144 CopyContext.ProgressBar = CreateProgressBar(13,
3145 26,
3146 xScreen - 13,
3147 yScreen - 20,
3148 10,
3149 24,
3150 TRUE,
3151 MUIGetString(STRING_SETUPCOPYINGFILES));
3152
3153 // fit memory bars to screen width, distribute them uniform
3154 mem_bar_width = (xScreen - 26) / 5;
3155 mem_bar_width -= mem_bar_width % 2; // make even
3156 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3157 /* Create the paged pool progress bar */
3158 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3159 40,
3160 13 + mem_bar_width,
3161 43,
3162 13,
3163 44,
3164 FALSE,
3165 "Kernel Pool");
3166
3167 /* Create the non paged pool progress bar */
3168 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
3169 40,
3170 (xScreen / 2) + (mem_bar_width / 2),
3171 43,
3172 (xScreen / 2)- (mem_bar_width / 2),
3173 44,
3174 FALSE,
3175 "Kernel Cache");
3176
3177 /* Create the global memory progress bar */
3178 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
3179 40,
3180 xScreen - 13,
3181 43,
3182 xScreen - 13 - mem_bar_width,
3183 44,
3184 FALSE,
3185 "Free Memory");
3186
3187 /* Do the file copying */
3188 SetupCommitFileQueueW(NULL,
3189 SetupFileQueue,
3190 FileCopyCallback,
3191 &CopyContext);
3192
3193 /* If we get here, we're done, so cleanup the queue and progress bar */
3194 SetupCloseFileQueue(SetupFileQueue);
3195 DestroyProgressBar(CopyContext.ProgressBar);
3196 DestroyProgressBar(CopyContext.MemoryBars[0]);
3197 DestroyProgressBar(CopyContext.MemoryBars[1]);
3198 DestroyProgressBar(CopyContext.MemoryBars[2]);
3199
3200 /* Go display the next page */
3201 return REGISTRY_PAGE;
3202 }
3203
3204
3205 static PAGE_NUMBER
3206 RegistryPage(PINPUT_RECORD Ir)
3207 {
3208 INFCONTEXT InfContext;
3209 PWSTR Action;
3210 PWSTR File;
3211 PWSTR Section;
3212 BOOLEAN Delete;
3213 NTSTATUS Status;
3214
3215 MUIDisplayPage(REGISTRY_PAGE);
3216
3217 if (RepairUpdateFlag)
3218 {
3219 return SUCCESS_PAGE;
3220 }
3221
3222 if (!SetInstallPathValue(&DestinationPath))
3223 {
3224 DPRINT("SetInstallPathValue() failed\n");
3225 MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
3226 return QUIT_PAGE;
3227 }
3228
3229 /* Create the default hives */
3230 #ifdef __REACTOS__
3231 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
3232 if (!NT_SUCCESS(Status))
3233 {
3234 DPRINT("NtInitializeRegistry() failed (Status %lx)\n", Status);
3235 MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
3236 return QUIT_PAGE;
3237 }
3238 #else
3239 RegInitializeRegistry();
3240 #endif
3241
3242 /* Update registry */
3243 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));