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