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