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