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