ReactOS  0.4.15-dev-1636-gf634010
usetup.c
Go to the documentation of this file.
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: base/setup/usetup/usetup.c
23  * PURPOSE: Text-mode setup
24  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25  * HervĂ© Poussineau (hpoussin@reactos.org)
26  */
27 
28 #include <usetup.h>
29 #include <math.h>
30 #include <ntstrsafe.h>
31 
32 #include "bootsup.h"
33 #include "chkdsk.h"
34 #include "cmdcons.h"
35 #include "devinst.h"
36 #include "format.h"
37 
38 #define NDEBUG
39 #include <debug.h>
40 
41 
42 /* GLOBALS & LOCALS *********************************************************/
43 
46 
48 
49 /* The partition where to perform the installation */
51 /*
52  * The system partition we will actually use. It can be different from
53  * PartitionList->SystemPartition in case we don't support it, or we install
54  * on a removable disk.
55  * We may indeed not support the original system partition in case we do not
56  * have write support on it. Please note that this situation is partly a HACK
57  * and MUST NEVER happen on architectures where real system partitions are
58  * mandatory (because then they are formatted in FAT FS and we support write
59  * operation on them).
60  */
62 
63 
64 /* OTHER Stuff *****/
65 
67 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList
68 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList
69 
71 
72 /* Global partition list on the system */
74 
75 /* Currently selected partition entry in the list */
77 
78 /* List of supported file systems for the partition to be formatted */
80 
81 /* Machine state for the formatter */
84 
85 /*****************************************************/
86 
89 
90 #ifdef __REACTOS__ /* HACK */
91 
92 /* FONT SUBSTITUTION WORKAROUND *************************************************/
93 
94 /* For font file check */
95 FONTSUBSTSETTINGS s_SubstSettings = { FALSE };
96 
97 static void
98 DoWatchDestFileName(LPCWSTR FileName)
99 {
100  if (FileName[0] == 'm' || FileName[0] == 'M')
101  {
102  if (wcsicmp(FileName, L"mingliu.ttc") == 0)
103  {
104  DPRINT("mingliu.ttc found\n");
105  s_SubstSettings.bFoundFontMINGLIU = TRUE;
106  }
107  else if (wcsicmp(FileName, L"msgothic.ttc") == 0)
108  {
109  DPRINT("msgothic.ttc found\n");
110  s_SubstSettings.bFoundFontMSGOTHIC = TRUE;
111  }
112  else if (wcsicmp(FileName, L"msmincho.ttc") == 0)
113  {
114  DPRINT("msmincho.ttc found\n");
115  s_SubstSettings.bFoundFontMSMINCHO = TRUE;
116  }
117  else if (wcsicmp(FileName, L"mssong.ttf") == 0)
118  {
119  DPRINT("mssong.ttf found\n");
120  s_SubstSettings.bFoundFontMSSONG = TRUE;
121  }
122  }
123  else
124  {
125  if (wcsicmp(FileName, L"simsun.ttc") == 0)
126  {
127  DPRINT("simsun.ttc found\n");
128  s_SubstSettings.bFoundFontSIMSUN = TRUE;
129  }
130  else if (wcsicmp(FileName, L"gulim.ttc") == 0)
131  {
132  DPRINT("gulim.ttc found\n");
133  s_SubstSettings.bFoundFontGULIM = TRUE;
134  }
135  else if (wcsicmp(FileName, L"batang.ttc") == 0)
136  {
137  DPRINT("batang.ttc found\n");
138  s_SubstSettings.bFoundFontBATANG = TRUE;
139  }
140  }
141 }
142 #endif /* HACK */
143 
144 /* FUNCTIONS ****************************************************************/
145 
146 static VOID
148 {
149  CHAR buffer[512];
150  va_list ap;
153 
154  va_start(ap, fmt);
155  vsprintf(buffer, fmt, ap);
156  va_end(ap);
157 
162 }
163 
164 
165 static VOID
167  IN SHORT yTop,
168  IN SHORT Width,
169  IN SHORT Height)
170 {
171  COORD coPos;
172  DWORD Written;
173 
174  /* Draw upper left corner */
175  coPos.X = xLeft;
176  coPos.Y = yTop;
178  0xDA, // '+',
179  1,
180  coPos,
181  &Written);
182 
183  /* Draw upper edge */
184  coPos.X = xLeft + 1;
185  coPos.Y = yTop;
187  0xC4, // '-',
188  Width - 2,
189  coPos,
190  &Written);
191 
192  /* Draw upper right corner */
193  coPos.X = xLeft + Width - 1;
194  coPos.Y = yTop;
196  0xBF, // '+',
197  1,
198  coPos,
199  &Written);
200 
201  /* Draw right edge, inner space and left edge */
202  for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
203  {
204  coPos.X = xLeft;
206  0xB3, // '|',
207  1,
208  coPos,
209  &Written);
210 
211  coPos.X = xLeft + 1;
213  ' ',
214  Width - 2,
215  coPos,
216  &Written);
217 
218  coPos.X = xLeft + Width - 1;
220  0xB3, // '|',
221  1,
222  coPos,
223  &Written);
224  }
225 
226  /* Draw lower left corner */
227  coPos.X = xLeft;
228  coPos.Y = yTop + Height - 1;
230  0xC0, // '+',
231  1,
232  coPos,
233  &Written);
234 
235  /* Draw lower edge */
236  coPos.X = xLeft + 1;
237  coPos.Y = yTop + Height - 1;
239  0xC4, // '-',
240  Width - 2,
241  coPos,
242  &Written);
243 
244  /* Draw lower right corner */
245  coPos.X = xLeft + Width - 1;
246  coPos.Y = yTop + Height - 1;
248  0xD9, // '+',
249  1,
250  coPos,
251  &Written);
252 }
253 
254 
255 VOID
257  PCCH Status,
258  PINPUT_RECORD Ir,
259  ULONG WaitEvent)
260 {
261  SHORT yTop;
262  SHORT xLeft;
263  COORD coPos;
264  DWORD Written;
265  ULONG Length;
266  ULONG MaxLength;
267  ULONG Lines;
268  PCHAR p;
269  PCCH pnext;
270  BOOLEAN LastLine;
271  SHORT Width;
272  SHORT Height;
273 
274  /* Count text lines and longest line */
275  MaxLength = 0;
276  Lines = 0;
277  pnext = Text;
278 
279  while (TRUE)
280  {
281  p = strchr(pnext, '\n');
282 
283  if (p == NULL)
284  {
285  Length = strlen(pnext);
286  LastLine = TRUE;
287  }
288  else
289  {
290  Length = (ULONG)(p - pnext);
291  LastLine = FALSE;
292  }
293 
294  Lines++;
295 
296  if (Length > MaxLength)
297  MaxLength = Length;
298 
299  if (LastLine)
300  break;
301 
302  pnext = p + 1;
303  }
304 
305  /* Check length of status line */
306  if (Status != NULL)
307  {
308  Length = strlen(Status);
309 
310  if (Length > MaxLength)
311  MaxLength = Length;
312  }
313 
314  Width = MaxLength + 4;
315  Height = Lines + 2;
316 
317  if (Status != NULL)
318  Height += 2;
319 
320  yTop = (yScreen - Height) / 2;
321  xLeft = (xScreen - Width) / 2;
322 
323 
324  /* Set screen attributes */
325  coPos.X = xLeft;
326  for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
327  {
330  Width,
331  coPos,
332  &Written);
333  }
334 
335  DrawBox(xLeft, yTop, Width, Height);
336 
337  /* Print message text */
338  coPos.Y = yTop + 1;
339  pnext = Text;
340  while (TRUE)
341  {
342  p = strchr(pnext, '\n');
343 
344  if (p == NULL)
345  {
346  Length = strlen(pnext);
347  LastLine = TRUE;
348  }
349  else
350  {
351  Length = (ULONG)(p - pnext);
352  LastLine = FALSE;
353  }
354 
355  if (Length != 0)
356  {
357  coPos.X = xLeft + 2;
359  pnext,
360  Length,
361  coPos,
362  &Written);
363  }
364 
365  if (LastLine)
366  break;
367 
368  coPos.Y++;
369  pnext = p + 1;
370  }
371 
372  /* Print separator line and status text */
373  if (Status != NULL)
374  {
375  coPos.Y = yTop + Height - 3;
376  coPos.X = xLeft;
378  0xC3, // '+',
379  1,
380  coPos,
381  &Written);
382 
383  coPos.X = xLeft + 1;
385  0xC4, // '-',
386  Width - 2,
387  coPos,
388  &Written);
389 
390  coPos.X = xLeft + Width - 1;
392  0xB4, // '+',
393  1,
394  coPos,
395  &Written);
396 
397  coPos.Y++;
398  coPos.X = xLeft + 2;
400  Status,
401  min(strlen(Status), (SIZE_T)Width - 4),
402  coPos,
403  &Written);
404  }
405 
406  if (WaitEvent == POPUP_WAIT_NONE)
407  return;
408 
409  while (TRUE)
410  {
411  CONSOLE_ConInKey(Ir);
412 
413  if (WaitEvent == POPUP_WAIT_ANY_KEY ||
414  Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
415  {
416  return;
417  }
418  }
419 }
420 
421 
423 VOID
426  OUT PCSTR* Unit)
427 {
428  ULONGLONG DiskSize = *Size;
429 
430 #if 0
431  if (DiskSize >= 10 * GB) /* 10 GB */
432  {
433  DiskSize = DiskSize / GB;
435  }
436  else
437 #endif
438  {
439  DiskSize = DiskSize / MB;
440  if (DiskSize == 0)
441  DiskSize = 1;
442 
444  }
445 
446  *Size = DiskSize;
447 }
448 
450 VOID
453  OUT PCSTR* Unit)
454 {
455  ULONGLONG PartSize = *Size;
456 
457 #if 0
458  if (PartSize >= 10 * GB) /* 10 GB */
459  {
460  PartSize = PartSize / GB;
462  }
463  else
464 #endif
465  if (PartSize >= 10 * MB) /* 10 MB */
466  {
467  PartSize = PartSize / MB;
469  }
470  else
471  {
472  PartSize = PartSize / KB;
474  }
475 
476  // if (PartSize == 0)
477  // PartSize = 1;
478  *Size = PartSize;
479 }
480 
481 
482 /*
483  * Confirm quit setup
484  * RETURNS
485  * TRUE: Quit setup.
486  * FALSE: Don't quit setup.
487  */
488 static BOOL
490 {
491  BOOL Result = FALSE;
493 
494  while (TRUE)
495  {
496  CONSOLE_ConInKey(Ir);
497 
498  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
499  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
500  {
501  Result = TRUE;
502  break;
503  }
504  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
505  {
506  Result = FALSE;
507  break;
508  }
509  }
510 
511  return Result;
512 }
513 
514 
515 static VOID
517 {
518  PGENERIC_LIST_ENTRY ListEntry;
519  PCWSTR pszNewLayout;
520 
522 
523  if (USetupData.LayoutList == NULL)
524  {
526  if (USetupData.LayoutList == NULL)
527  {
528  /* FIXME: Handle error! */
529  return;
530  }
531  }
532 
533  /* Search for default layout (if provided) */
534  if (pszNewLayout != NULL)
535  {
536  for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
537  ListEntry = GetNextListEntry(ListEntry))
538  {
539  if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
540  {
541  SetCurrentListEntry(USetupData.LayoutList, ListEntry);
542  break;
543  }
544  }
545  }
546 }
547 
548 
549 static NTSTATUS
550 NTAPI
553  OUT PSTR Buffer,
555 {
558 }
559 
560 static NTSTATUS
561 NTAPI
564  OUT PSTR Buffer,
566 {
568  PPARTENTRY PartEntry = NtOsInstall->PartEntry;
569 
570  if (PartEntry && PartEntry->DriveLetter)
571  {
572  /* We have retrieved a partition that is mounted */
574  "%C:%S \"%S\"",
575  PartEntry->DriveLetter,
576  NtOsInstall->PathComponent,
577  NtOsInstall->InstallationName);
578  }
579  else
580  {
581  /* We failed somewhere, just show the NT path */
583  "%wZ \"%S\"",
584  &NtOsInstall->SystemNtPath,
585  NtOsInstall->InstallationName);
586  }
587 }
588 
589 
590 /*
591  * Displays the LanguagePage.
592  *
593  * Next pages: WelcomePage, QuitPage
594  *
595  * SIDEEFFECTS
596  * Init SelectedLanguageId
597  * Init USetupData.LanguageId
598  *
599  * RETURNS
600  * Number of the next page.
601  */
602 static PAGE_NUMBER
604 {
605  GENERIC_LIST_UI ListUi;
606  PCWSTR NewLanguageId;
607  BOOL RefreshPage = FALSE;
608 
609  /* Initialize the computer settings list */
610  if (USetupData.LanguageList == NULL)
611  {
612  USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
613  if (USetupData.LanguageList == NULL)
614  {
615  PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
616  return WELCOME_PAGE;
617  }
618  }
619 
621  USetupData.LanguageId = 0;
622 
623  /* Load the font */
625  UpdateKBLayout();
626 
627  /*
628  * If there is no language or just a single one in the list,
629  * skip the language selection process altogether.
630  */
631  if (GetNumberOfListEntries(USetupData.LanguageList) <= 1)
632  {
633  USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
634  return WELCOME_PAGE;
635  }
636 
637  InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
638  DrawGenericList(&ListUi,
639  2, 18,
640  xScreen - 3,
641  yScreen - 3);
642 
644 
646 
647  while (TRUE)
648  {
649  CONSOLE_ConInKey(Ir);
650 
651  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
652  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
653  {
654  ScrollDownGenericList(&ListUi);
655  RefreshPage = TRUE;
656  }
657  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
658  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
659  {
660  ScrollUpGenericList(&ListUi);
661  RefreshPage = TRUE;
662  }
663  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
664  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
665  {
666  ScrollPageDownGenericList(&ListUi);
667  RefreshPage = TRUE;
668  }
669  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
670  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
671  {
672  ScrollPageUpGenericList(&ListUi);
673  RefreshPage = TRUE;
674  }
675  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
676  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
677  {
678  if (ConfirmQuit(Ir))
679  return QUIT_PAGE;
680  else
681  RedrawGenericList(&ListUi);
682  }
683  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
684  {
685  ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
686 
689 
690  USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
691 
693  {
694  UpdateKBLayout();
695  }
696 
697  /* Load the font */
699 
700  return WELCOME_PAGE;
701  }
702  else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
703  {
704  /* a-z */
706  RefreshPage = TRUE;
707  }
708 
709  if (RefreshPage)
710  {
711  ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
712 
713  NewLanguageId =
715 
716  if (wcscmp(SelectedLanguageId, NewLanguageId))
717  {
718  /* Clear the language page */
720 
721  SelectedLanguageId = NewLanguageId;
722 
723  /* Load the font */
725 
726  /* Redraw language selection page in native language */
728  }
729 
730  RefreshPage = FALSE;
731  }
732  }
733 
734  return WELCOME_PAGE;
735 }
736 
737 
738 /*
739  * Start page
740  *
741  * Next pages:
742  * LanguagePage (at once, default)
743  * InstallIntroPage (at once, if unattended)
744  * QuitPage
745  *
746  * SIDEEFFECTS
747  * Init Sdi
748  * Init USetupData.SourcePath
749  * Init USetupData.SourceRootPath
750  * Init USetupData.SourceRootDir
751  * Init USetupData.SetupInf
752  * Init USetupData.RequiredPartitionDiskSpace
753  * Init IsUnattendedSetup
754  * If unattended, init *List and sets the Codepage
755  * If unattended, init SelectedLanguageId
756  * If unattended, init USetupData.LanguageId
757  *
758  * RETURNS
759  * Number of the next page.
760  */
761 static PAGE_NUMBER
763 {
764  ULONG Error;
765  PGENERIC_LIST_ENTRY ListEntry;
767 
769 
770  /* Initialize Setup, phase 1 */
772  if (Error != ERROR_SUCCESS)
773  {
775  return QUIT_PAGE;
776  }
777 
778  /* Initialize the user-mode PnP manager */
780  DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
781 
782  /* Wait for any immediate pending installations to finish */
784  DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
785 
787 
788  if (IsUnattendedSetup)
789  {
790  // TODO: Read options from inf
791  /* Load the hardware, language and keyboard layout lists */
792 
793  USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
794  USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
795  USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
796 
797  USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
798 
799  /* new part */
801  wcscpy(DefaultLanguage, USetupData.LocaleID);
802  USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
803 
805 
806  /* first we hack LanguageList */
807  for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry;
808  ListEntry = GetNextListEntry(ListEntry))
809  {
810  LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
811  if (!wcsicmp(USetupData.LocaleID, LocaleId))
812  {
813  DPRINT("found %S in LanguageList\n", LocaleId);
814  SetCurrentListEntry(USetupData.LanguageList, ListEntry);
815  break;
816  }
817  }
818 
819  /* now LayoutList */
820  for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
821  ListEntry = GetNextListEntry(ListEntry))
822  {
823  LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
824  if (!wcsicmp(USetupData.LocaleID, LocaleId))
825  {
826  DPRINT("found %S in LayoutList\n", LocaleId);
827  SetCurrentListEntry(USetupData.LayoutList, ListEntry);
828  break;
829  }
830  }
831 
833 
834  return INSTALL_INTRO_PAGE;
835  }
836 
837  return LANGUAGE_PAGE;
838 }
839 
840 
841 /*
842  * Displays the WelcomePage.
843  *
844  * Next pages:
845  * InstallIntroPage (default)
846  * RepairIntroPage
847  * RecoveryPage
848  * LicensePage
849  * QuitPage
850  *
851  * RETURNS
852  * Number of the next page.
853  */
854 static PAGE_NUMBER
856 {
858 
859  while (TRUE)
860  {
861  CONSOLE_ConInKey(Ir);
862 
863  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
864  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
865  {
866  if (ConfirmQuit(Ir))
867  return QUIT_PAGE;
868 
869  break;
870  }
871  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
872  {
873  return INSTALL_INTRO_PAGE;
874  }
875  else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
876  {
877  return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
878  }
879  else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
880  {
881  return LICENSE_PAGE;
882  }
883  }
884 
885  return WELCOME_PAGE;
886 }
887 
888 
889 /*
890  * Displays the License page.
891  *
892  * Next page:
893  * WelcomePage (default)
894  *
895  * RETURNS
896  * Number of the next page.
897  */
898 static PAGE_NUMBER
900 {
902 
903  while (TRUE)
904  {
905  CONSOLE_ConInKey(Ir);
906 
907  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
908  {
909  return WELCOME_PAGE;
910  }
911  }
912 
913  return LICENSE_PAGE;
914 }
915 
916 
917 /*
918  * Displays the RepairIntroPage.
919  *
920  * Next pages:
921  * RebootPage (default)
922  * InstallIntroPage
923  * RecoveryPage
924  * IntroPage
925  *
926  * RETURNS
927  * Number of the next page.
928  */
929 static PAGE_NUMBER
931 {
933 
934  while (TRUE)
935  {
936  CONSOLE_ConInKey(Ir);
937 
938  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
939  {
940  return REBOOT_PAGE;
941  }
942  else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
943  {
945  return INSTALL_INTRO_PAGE;
946  }
947  else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
948  {
949  return RECOVERY_PAGE;
950  }
951  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
952  {
953  return WELCOME_PAGE;
954  }
955  }
956 
957  return REPAIR_INTRO_PAGE;
958 }
959 
960 /*
961  * Displays the UpgradeRepairPage.
962  *
963  * Next pages:
964  * RebootPage (default)
965  * InstallIntroPage
966  * RecoveryPage
967  * WelcomePage
968  *
969  * RETURNS
970  * Number of the next page.
971  */
972 static PAGE_NUMBER
974 {
975  GENERIC_LIST_UI ListUi;
976 
977 /*** HACK!! ***/
978  if (PartitionList == NULL)
979  {
981  if (PartitionList == NULL)
982  {
983  /* FIXME: show an error dialog */
985  return QUIT_PAGE;
986  }
988  {
990  return QUIT_PAGE;
991  }
992 
993  /* Reset the formatter machine state */
995  FormatState = Start;
996  }
997 /**************/
998 
1000  if (!NtOsInstallsList)
1001  DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
1002 
1003  /*
1004  * If there is no available installation (or just a single one??) that can
1005  * be updated in the list, just continue with the regular installation.
1006  */
1008  {
1010 
1011  // return INSTALL_INTRO_PAGE;
1012  return DEVICE_SETTINGS_PAGE;
1013  // return SCSI_CONTROLLER_PAGE;
1014  }
1015 
1017 
1019  DrawGenericList(&ListUi,
1020  2, 23,
1021  xScreen - 3,
1022  yScreen - 3);
1023 
1024  // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1025  while (TRUE)
1026  {
1027  CONSOLE_ConInKey(Ir);
1028 
1029  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
1030  {
1031  switch (Ir->Event.KeyEvent.wVirtualKeyCode)
1032  {
1033  case VK_DOWN: /* DOWN */
1034  ScrollDownGenericList(&ListUi);
1035  break;
1036  case VK_UP: /* UP */
1037  ScrollUpGenericList(&ListUi);
1038  break;
1039  case VK_NEXT: /* PAGE DOWN */
1040  ScrollPageDownGenericList(&ListUi);
1041  break;
1042  case VK_PRIOR: /* PAGE UP */
1043  ScrollPageUpGenericList(&ListUi);
1044  break;
1045  case VK_F3: /* F3 */
1046  {
1047  if (ConfirmQuit(Ir))
1048  return QUIT_PAGE;
1049  else
1050  RedrawGenericList(&ListUi);
1051  break;
1052  }
1053 #if 1
1054 /* TODO: Temporarily kept until correct keyboard layout is in place.
1055  * (Actual AsciiChar of ESCAPE should be 0x1B instead of 0.)
1056  * Addendum to commit 8b94515b.
1057  */
1058  case VK_ESCAPE: /* ESC */
1059  {
1060  RestoreGenericListUiState(&ListUi);
1061  // return nextPage; // prevPage;
1062 
1063  // return INSTALL_INTRO_PAGE;
1064  return DEVICE_SETTINGS_PAGE;
1065  // return SCSI_CONTROLLER_PAGE;
1066  }
1067 
1068 #endif
1069  }
1070  }
1071 #if 0
1072 /* TODO: Restore this once correct keyboard layout is in place. */
1073  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
1074  {
1075  RestoreGenericListUiState(&ListUi);
1076  // return nextPage; // prevPage;
1077 
1078  // return INSTALL_INTRO_PAGE;
1079  return DEVICE_SETTINGS_PAGE;
1080  // return SCSI_CONTROLLER_PAGE;
1081  }
1082 #endif
1083  else
1084  {
1085  // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
1086  // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1087  if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
1088  {
1089  /* Retrieve the current installation */
1091 
1094 
1095  DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
1097 
1099 
1100  // return nextPage;
1101  /***/return INSTALL_INTRO_PAGE;/***/
1102  }
1103  else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
1104  (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */
1105  {
1107  }
1108  }
1109  }
1110 
1111  return UPGRADE_REPAIR_PAGE;
1112 }
1113 
1114 
1115 /*
1116  * Displays the InstallIntroPage.
1117  *
1118  * Next pages:
1119  * DeviceSettingsPage (At once if repair or update is selected)
1120  * SelectPartitionPage (At once if unattended setup)
1121  * DeviceSettingsPage (default)
1122  * QuitPage
1123  *
1124  * RETURNS
1125  * Number of the next page.
1126  */
1127 static PAGE_NUMBER
1129 {
1130  if (RepairUpdateFlag)
1131  {
1132 #if 1 /* Old code that looks good */
1133 
1134  // return SELECT_PARTITION_PAGE;
1135  return DEVICE_SETTINGS_PAGE;
1136 
1137 #else /* Possible new code? */
1138 
1139  return DEVICE_SETTINGS_PAGE;
1140  // return SCSI_CONTROLLER_PAGE;
1141 
1142 #endif
1143  }
1144 
1145  if (IsUnattendedSetup)
1146  return SELECT_PARTITION_PAGE;
1147 
1149 
1150  while (TRUE)
1151  {
1152  CONSOLE_ConInKey(Ir);
1153 
1154  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1155  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1156  {
1157  if (ConfirmQuit(Ir))
1158  return QUIT_PAGE;
1159 
1160  break;
1161  }
1162  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1163  {
1164  return UPGRADE_REPAIR_PAGE;
1165  }
1166  }
1167 
1168  return INSTALL_INTRO_PAGE;
1169 }
1170 
1171 
1172 #if 0
1173 static PAGE_NUMBER
1174 ScsiControllerPage(PINPUT_RECORD Ir)
1175 {
1176  // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1177 
1178  CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1179 
1180  /* FIXME: print loaded mass storage driver descriptions */
1181 #if 0
1182  CONSOLE_SetTextXY(8, 10, "TEST device");
1183 #endif
1184 
1185  CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1186 
1187  while (TRUE)
1188  {
1189  CONSOLE_ConInKey(Ir);
1190 
1191  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1192  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1193  {
1194  if (ConfirmQuit(Ir))
1195  return QUIT_PAGE;
1196 
1197  break;
1198  }
1199  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1200  {
1201  return DEVICE_SETTINGS_PAGE;
1202  }
1203  }
1204 
1205  return SCSI_CONTROLLER_PAGE;
1206 }
1207 
1208 static PAGE_NUMBER
1209 OemDriverPage(PINPUT_RECORD Ir)
1210 {
1211  // MUIDisplayPage(OEM_DRIVER_PAGE);
1212 
1213  CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1214 
1215  /* FIXME: Implement!! */
1216 
1217  CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1218 
1219  while (TRUE)
1220  {
1221  CONSOLE_ConInKey(Ir);
1222 
1223  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1224  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1225  {
1226  if (ConfirmQuit(Ir))
1227  return QUIT_PAGE;
1228 
1229  break;
1230  }
1231  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1232  {
1233  return DEVICE_SETTINGS_PAGE;
1234  }
1235  }
1236 
1237  return OEM_DRIVER_PAGE;
1238 }
1239 #endif
1240 
1241 
1242 /*
1243  * Displays the DeviceSettingsPage.
1244  *
1245  * Next pages:
1246  * SelectPartitionPage (At once if repair or update is selected)
1247  * ComputerSettingsPage
1248  * DisplaySettingsPage
1249  * KeyboardSettingsPage
1250  * LayoutsettingsPage
1251  * SelectPartitionPage
1252  * QuitPage
1253  *
1254  * SIDEEFFECTS
1255  * Init USetupData.ComputerList
1256  * Init USetupData.DisplayList
1257  * Init USetupData.KeyboardList
1258  * Init USetupData.LayoutList
1259  *
1260  * RETURNS
1261  * Number of the next page.
1262  */
1263 static PAGE_NUMBER
1265 {
1266  static ULONG Line = 16;
1267 
1268  /* Initialize the computer settings list */
1269  if (USetupData.ComputerList == NULL)
1270  {
1271  USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
1272  if (USetupData.ComputerList == NULL)
1273  {
1275  return QUIT_PAGE;
1276  }
1277  }
1278 
1279  /* Initialize the display settings list */
1280  if (USetupData.DisplayList == NULL)
1281  {
1282  USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
1283  if (USetupData.DisplayList == NULL)
1284  {
1286  return QUIT_PAGE;
1287  }
1288  }
1289 
1290  /* Initialize the keyboard settings list */
1291  if (USetupData.KeyboardList == NULL)
1292  {
1293  USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
1294  if (USetupData.KeyboardList == NULL)
1295  {
1297  return QUIT_PAGE;
1298  }
1299  }
1300 
1301  /* Initialize the keyboard layout list */
1302  if (USetupData.LayoutList == NULL)
1303  {
1305  if (USetupData.LayoutList == NULL)
1306  {
1307  /* FIXME: report error */
1309  return QUIT_PAGE;
1310  }
1311  }
1312 
1313  if (RepairUpdateFlag)
1314  return SELECT_PARTITION_PAGE;
1315 
1316  // if (IsUnattendedSetup)
1317  // return SELECT_PARTITION_PAGE;
1318 
1320 
1325 
1326  CONSOLE_InvertTextXY(24, Line, 48, 1);
1327 
1328  while (TRUE)
1329  {
1330  CONSOLE_ConInKey(Ir);
1331 
1332  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1333  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1334  {
1335  CONSOLE_NormalTextXY(24, Line, 48, 1);
1336 
1337  if (Line == 14)
1338  Line = 16;
1339  else if (Line == 16)
1340  Line = 11;
1341  else
1342  Line++;
1343 
1344  CONSOLE_InvertTextXY(24, Line, 48, 1);
1345  }
1346  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1347  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1348  {
1349  CONSOLE_NormalTextXY(24, Line, 48, 1);
1350 
1351  if (Line == 11)
1352  Line = 16;
1353  else if (Line == 16)
1354  Line = 14;
1355  else
1356  Line--;
1357 
1358  CONSOLE_InvertTextXY(24, Line, 48, 1);
1359  }
1360  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1361  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1362  {
1363  if (ConfirmQuit(Ir))
1364  return QUIT_PAGE;
1365 
1366  break;
1367  }
1368  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1369  {
1370  if (Line == 11)
1371  return COMPUTER_SETTINGS_PAGE;
1372  else if (Line == 12)
1373  return DISPLAY_SETTINGS_PAGE;
1374  else if (Line == 13)
1375  return KEYBOARD_SETTINGS_PAGE;
1376  else if (Line == 14)
1377  return LAYOUT_SETTINGS_PAGE;
1378  else if (Line == 16)
1379  return SELECT_PARTITION_PAGE;
1380  }
1381  }
1382 
1383  return DEVICE_SETTINGS_PAGE;
1384 }
1385 
1386 
1387 /*
1388  * Handles generic selection lists.
1389  *
1390  * PARAMS
1391  * GenericList: The list to handle.
1392  * nextPage: The page it needs to jump to after this page.
1393  * Ir: The PINPUT_RECORD
1394  */
1395 static PAGE_NUMBER
1397  PAGE_NUMBER nextPage,
1398  PINPUT_RECORD Ir)
1399 {
1400  while (TRUE)
1401  {
1402  CONSOLE_ConInKey(Ir);
1403 
1404  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1405  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1406  {
1407  ScrollDownGenericList(ListUi);
1408  }
1409  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1410  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1411  {
1412  ScrollUpGenericList(ListUi);
1413  }
1414  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1415  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1416  {
1417  ScrollPageDownGenericList(ListUi);
1418  }
1419  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1420  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1421  {
1422  ScrollPageUpGenericList(ListUi);
1423  }
1424  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1425  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1426  {
1427  if (ConfirmQuit(Ir))
1428  return QUIT_PAGE;
1429  else
1430  RedrawGenericList(ListUi);
1431  }
1432  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
1433  {
1434  RestoreGenericListUiState(ListUi);
1435  return nextPage; // Use some "prevPage;" instead?
1436  }
1437  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1438  {
1439  return nextPage;
1440  }
1441  else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1442  {
1443  /* a-z */
1445  }
1446  }
1447 }
1448 
1449 
1450 /*
1451  * Displays the ComputerSettingsPage.
1452  *
1453  * Next pages:
1454  * DeviceSettingsPage
1455  * QuitPage
1456  *
1457  * RETURNS
1458  * Number of the next page.
1459  */
1460 static PAGE_NUMBER
1462 {
1463  GENERIC_LIST_UI ListUi;
1465 
1466  InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription);
1467  DrawGenericList(&ListUi,
1468  2, 18,
1469  xScreen - 3,
1470  yScreen - 3);
1471 
1472  return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1473 }
1474 
1475 
1476 /*
1477  * Displays the DisplaySettingsPage.
1478  *
1479  * Next pages:
1480  * DeviceSettingsPage
1481  * QuitPage
1482  *
1483  * RETURNS
1484  * Number of the next page.
1485  */
1486 static PAGE_NUMBER
1488 {
1489  GENERIC_LIST_UI ListUi;
1491 
1492  InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription);
1493  DrawGenericList(&ListUi,
1494  2, 18,
1495  xScreen - 3,
1496  yScreen - 3);
1497 
1498  return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1499 }
1500 
1501 
1502 /*
1503  * Displays the KeyboardSettingsPage.
1504  *
1505  * Next pages:
1506  * DeviceSettingsPage
1507  * QuitPage
1508  *
1509  * RETURNS
1510  * Number of the next page.
1511  */
1512 static PAGE_NUMBER
1514 {
1515  GENERIC_LIST_UI ListUi;
1517 
1518  InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription);
1519  DrawGenericList(&ListUi,
1520  2, 18,
1521  xScreen - 3,
1522  yScreen - 3);
1523 
1524  return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1525 }
1526 
1527 
1528 /*
1529  * Displays the LayoutSettingsPage.
1530  *
1531  * Next pages:
1532  * DeviceSettingsPage
1533  * QuitPage
1534  *
1535  * RETURNS
1536  * Number of the next page.
1537  */
1538 static PAGE_NUMBER
1540 {
1541  GENERIC_LIST_UI ListUi;
1543 
1544  InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription);
1545  DrawGenericList(&ListUi,
1546  2, 18,
1547  xScreen - 3,
1548  yScreen - 3);
1549 
1550  return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1551 }
1552 
1553 
1554 static BOOL
1556 {
1557  ULONGLONG size;
1558 
1559  size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1560  size = (size + (512 * KB)) / MB; /* in MBytes */
1561 
1562  if (size < USetupData.RequiredPartitionDiskSpace)
1563  {
1564  /* Partition is too small so ask for another one */
1565  DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
1566  return FALSE;
1567  }
1568  else
1569  {
1570  return TRUE;
1571  }
1572 }
1573 
1574 
1575 /*
1576  * Displays the SelectPartitionPage.
1577  *
1578  * Next pages:
1579  * SelectFileSystemPage (At once if unattended)
1580  * SelectFileSystemPage (Default if free space is selected)
1581  * CreatePrimaryPartitionPage
1582  * CreateExtendedPartitionPage
1583  * CreateLogicalPartitionPage
1584  * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1585  * DeletePartitionPage
1586  * QuitPage
1587  *
1588  * SIDEEFFECTS
1589  * Set InstallShortcut (only if not unattended + free space is selected)
1590  *
1591  * RETURNS
1592  * Number of the next page.
1593  */
1594 static PAGE_NUMBER
1596 {
1597  PARTLIST_UI ListUi;
1598  ULONG Error;
1599 
1600  if (PartitionList == NULL)
1601  {
1603  if (PartitionList == NULL)
1604  {
1606  return QUIT_PAGE;
1607  }
1609  {
1611  return QUIT_PAGE;
1612  }
1613 
1614  /* Reset the formatter machine state */
1615  TempPartition = NULL;
1616  FormatState = Start;
1617  }
1618 
1619  if (RepairUpdateFlag)
1620  {
1622 
1623  /* Determine the selected installation disk & partition */
1627  if (!InstallPartition)
1628  {
1629  DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1630  ASSERT(FALSE);
1631  }
1633 
1634  return SELECT_FILE_SYSTEM_PAGE;
1635  }
1636 
1638 
1641  2, 23,
1642  xScreen - 3,
1643  yScreen - 3);
1644  DrawPartitionList(&ListUi);
1645 
1646  if (IsUnattendedSetup)
1647  {
1648  /* Determine the selected installation disk & partition */
1650  USetupData.DestinationDiskNumber,
1651  USetupData.DestinationPartitionNumber);
1652  if (!InstallPartition)
1653  {
1655 
1656  if (USetupData.AutoPartition)
1657  {
1660 
1662  {
1666  TRUE);
1667  }
1668  else
1669  {
1673  TRUE);
1674  }
1675 
1676 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1678  {
1680  USetupData.RequiredPartitionDiskSpace);
1681  return SELECT_PARTITION_PAGE; /* let the user select another partition */
1682  }
1683 
1685  return SELECT_FILE_SYSTEM_PAGE;
1686  }
1687  }
1688  else
1689  {
1691 
1692  DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense...
1693 
1694 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1696  {
1698  USetupData.RequiredPartitionDiskSpace);
1699  return SELECT_PARTITION_PAGE; /* let the user select another partition */
1700  }
1701 
1702  return SELECT_FILE_SYSTEM_PAGE;
1703  }
1704  }
1705 
1706  while (TRUE)
1707  {
1709 
1710  /* Update status text */
1711  if (CurrentPartition == NULL)
1712  {
1714  }
1716  {
1718  {
1720  }
1721  else
1722  {
1724  }
1725  }
1726  else
1727  {
1729  {
1731  {
1733  }
1734  else
1735  {
1737  }
1738  }
1739  else
1740  {
1742  }
1743  }
1744 
1745  CONSOLE_ConInKey(Ir);
1746 
1747  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1748  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1749  {
1750  if (ConfirmQuit(Ir))
1751  {
1753  PartitionList = NULL;
1754  return QUIT_PAGE;
1755  }
1756 
1757  break;
1758  }
1759  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1760  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1761  {
1762  ScrollDownPartitionList(&ListUi);
1763  }
1764  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1765  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1766  {
1767  ScrollUpPartitionList(&ListUi);
1768  }
1769  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1770  {
1772 
1774  continue; // return SELECT_PARTITION_PAGE;
1775 
1776  /*
1777  * Check whether the user wants to install ReactOS on a disk that
1778  * is not recognized by the computer's firmware and if so, display
1779  * a warning since such disks may not be bootable.
1780  */
1781  if (CurrentPartition->DiskEntry->MediaType == FixedMedia &&
1782  !CurrentPartition->DiskEntry->BiosFound)
1783  {
1784  PopupError("The disk you have selected for installing ReactOS\n"
1785  "is not visible by the firmware of your computer,\n"
1786  "and so may not be bootable.\n"
1787  "Press ENTER to continue nonetheless.",
1789  Ir, POPUP_WAIT_ENTER);
1790  // return SELECT_PARTITION_PAGE;
1791  }
1792 
1794  {
1796  {
1798  if (Error != NOT_AN_ERROR)
1799  {
1801  return SELECT_PARTITION_PAGE;
1802  }
1803 
1806  0ULL,
1807  TRUE);
1808  }
1809  else
1810  {
1812  if (Error != NOT_AN_ERROR)
1813  {
1815  return SELECT_PARTITION_PAGE;
1816  }
1817 
1820  0ULL,
1821  TRUE);
1822  }
1823  }
1824 
1826  {
1828  USetupData.RequiredPartitionDiskSpace);
1829  return SELECT_PARTITION_PAGE; /* let the user select another partition */
1830  }
1831 
1833  return SELECT_FILE_SYSTEM_PAGE;
1834  }
1835  else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1836  {
1838 
1840  {
1842  if (Error != NOT_AN_ERROR)
1843  {
1845  return SELECT_PARTITION_PAGE;
1846  }
1847 
1849  }
1850  }
1851  else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1852  {
1854 
1856  {
1858  if (Error != NOT_AN_ERROR)
1859  {
1861  return SELECT_PARTITION_PAGE;
1862  }
1863 
1865  }
1866  }
1867  else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1868  {
1870 
1872  {
1874  if (Error != NOT_AN_ERROR)
1875  {
1877  return SELECT_PARTITION_PAGE;
1878  }
1879 
1881  }
1882  }
1883  else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1884  {
1885  UNICODE_STRING CurrentPartitionU;
1886  WCHAR PathBuffer[MAX_PATH];
1887 
1889 
1891  {
1893  return SELECT_PARTITION_PAGE;
1894  }
1895 
1896 // TODO: Do something similar before trying to format the partition?
1897  if (!CurrentPartition->New &&
1900  {
1902 
1903  RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1904  L"\\Device\\Harddisk%lu\\Partition%lu\\",
1905  CurrentPartition->DiskEntry->DiskNumber,
1907  RtlInitUnicodeString(&CurrentPartitionU, PathBuffer);
1908 
1909  /*
1910  * Check whether the user attempts to delete the partition on which
1911  * the installation source is present. If so, fail with an error.
1912  */
1913  // &USetupData.SourceRootPath
1914  if (RtlPrefixUnicodeString(&CurrentPartitionU, &USetupData.SourcePath, TRUE))
1915  {
1917  return SELECT_PARTITION_PAGE;
1918  }
1919  }
1920 
1923  {
1925  }
1926 
1927  return DELETE_PARTITION_PAGE;
1928  }
1929  }
1930 
1931  return SELECT_PARTITION_PAGE;
1932 }
1933 
1934 
1935 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1936 /* Restriction for MaxSize */
1937 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1938 
1939 static VOID
1941  SHORT Top,
1942  SHORT Right,
1943  SHORT Bottom,
1944  ULONG MaxSize,
1946  PBOOLEAN Quit,
1947  PBOOLEAN Cancel)
1948 {
1949  INPUT_RECORD Ir;
1950  COORD coPos;
1951  DWORD Written;
1952  CHAR Buffer[128];
1953  INT Length, Pos;
1954  WCHAR ch;
1955  SHORT iLeft;
1956  SHORT iTop;
1957 
1958  if (Quit != NULL)
1959  *Quit = FALSE;
1960 
1961  if (Cancel != NULL)
1962  *Cancel = FALSE;
1963 
1964  DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1965 
1966  /* Print message */
1967  coPos.X = Left + 2;
1968  coPos.Y = Top + 2;
1970  iLeft = coPos.X + strlen(Buffer) + 1;
1971  iTop = coPos.Y;
1972 
1974  Buffer,
1975  strlen(Buffer),
1976  coPos,
1977  &Written);
1978 
1980  coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1981  coPos.Y = iTop;
1983  Buffer,
1984  strlen(Buffer),
1985  coPos,
1986  &Written);
1987 
1988  swprintf(InputBuffer, L"%lu", MaxSize);
1990  Pos = Length;
1991  CONSOLE_SetInputTextXY(iLeft,
1992  iTop,
1994  InputBuffer);
1995  CONSOLE_SetCursorXY(iLeft + Length, iTop);
1997 
1998  while (TRUE)
1999  {
2000  CONSOLE_ConInKey(&Ir);
2001 
2002  if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2003  (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2004  {
2005  if (Quit != NULL)
2006  *Quit = TRUE;
2007 
2010  break;
2011  }
2012  else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2013  {
2015  break;
2016  }
2017  else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2018  {
2019  if (Cancel != NULL)
2020  *Cancel = TRUE;
2021 
2024  break;
2025  }
2026  else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2027  (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
2028  {
2029  Pos = 0;
2030  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2031  }
2032  else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2033  (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
2034  {
2035  Pos = Length;
2036  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2037  }
2038  else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2039  (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
2040  {
2041  if (Pos > 0)
2042  {
2043  Pos--;
2044  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2045  }
2046  }
2047  else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2048  (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
2049  {
2050  if (Pos < Length)
2051  {
2052  Pos++;
2053  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2054  }
2055  }
2056  else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2057  (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
2058  {
2059  if (Pos < Length)
2060  {
2062  &InputBuffer[Pos + 1],
2063  (Length - Pos - 1) * sizeof(WCHAR));
2065 
2066  Length--;
2067  CONSOLE_SetInputTextXY(iLeft,
2068  iTop,
2070  InputBuffer);
2071  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2072  }
2073  }
2074  else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
2075  {
2076  if (Pos > 0)
2077  {
2078  if (Pos < Length)
2079  memmove(&InputBuffer[Pos - 1],
2080  &InputBuffer[Pos],
2081  (Length - Pos) * sizeof(WCHAR));
2083 
2084  Pos--;
2085  Length--;
2086  CONSOLE_SetInputTextXY(iLeft,
2087  iTop,
2089  InputBuffer);
2090  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2091  }
2092  }
2093  else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
2094  {
2096  {
2097  ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
2098 
2099  if ((ch >= L'0') && (ch <= L'9'))
2100  {
2101  if (Pos < Length)
2102  memmove(&InputBuffer[Pos + 1],
2103  &InputBuffer[Pos],
2104  (Length - Pos) * sizeof(WCHAR));
2106  InputBuffer[Pos] = ch;
2107 
2108  Pos++;
2109  Length++;
2110  CONSOLE_SetInputTextXY(iLeft,
2111  iTop,
2113  InputBuffer);
2114  CONSOLE_SetCursorXY(iLeft + Pos, iTop);
2115  }
2116  }
2117  }
2118  }
2119 }
2120 
2121 
2122 /*
2123  * Displays the CreatePrimaryPartitionPage.
2124  *
2125  * Next pages:
2126  * SelectPartitionPage
2127  * SelectFileSystemPage (default)
2128  * QuitPage
2129  *
2130  * RETURNS
2131  * Number of the next page.
2132  */
2133 static PAGE_NUMBER
2135 {
2136  PPARTENTRY PartEntry;
2137  PDISKENTRY DiskEntry;
2138  BOOLEAN Quit;
2139  BOOLEAN Cancel;
2140  WCHAR InputBuffer[50];
2141  ULONG MaxSize;
2142  ULONGLONG PartSize;
2143  ULONGLONG DiskSize;
2145  PCSTR Unit;
2146 
2147  if (PartitionList == NULL || CurrentPartition == NULL)
2148  {
2149  /* FIXME: show an error dialog */
2150  return QUIT_PAGE;
2151  }
2152 
2153  PartEntry = CurrentPartition;
2154  DiskEntry = CurrentPartition->DiskEntry;
2155 
2157 
2159 
2160  DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2161  PrettifySize1(&DiskSize, &Unit);
2162 
2163  if (DiskEntry->DriverName.Length > 0)
2164  {
2165  CONSOLE_PrintTextXY(6, 10,
2167  DiskSize,
2168  Unit,
2169  DiskEntry->DiskNumber,
2170  DiskEntry->Port,
2171  DiskEntry->Bus,
2172  DiskEntry->Id,
2173  &DiskEntry->DriverName,
2174  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2175  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2176  "RAW");
2177  }
2178  else
2179  {
2180  CONSOLE_PrintTextXY(6, 10,
2182  DiskSize,
2183  Unit,
2184  DiskEntry->DiskNumber,
2185  DiskEntry->Port,
2186  DiskEntry->Bus,
2187  DiskEntry->Id,
2188  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2189  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2190  "RAW");
2191  }
2192 
2194 
2195 #if 0
2196  CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2197  CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2198 #endif
2199 
2201 
2202  PartEntry = CurrentPartition;
2203  while (TRUE)
2204  {
2205  MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2206 
2207  if (MaxSize > PARTITION_MAXSIZE)
2208  MaxSize = PARTITION_MAXSIZE;
2209 
2210  ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2211  MaxSize, InputBuffer, &Quit, &Cancel);
2212 
2213  if (Quit)
2214  {
2215  if (ConfirmQuit(Ir))
2216  return QUIT_PAGE;
2217 
2218  break;
2219  }
2220  else if (Cancel)
2221  {
2222  return SELECT_PARTITION_PAGE;
2223  }
2224  else
2225  {
2226  PartSize = _wcstoui64(InputBuffer, NULL, 10);
2227 
2228  if (PartSize < 1)
2229  {
2230  /* Too small */
2231  continue;
2232  }
2233 
2234  if (PartSize > MaxSize)
2235  {
2236  /* Too large */
2237  continue;
2238  }
2239 
2240  /* Convert to bytes */
2241  if (PartSize == MaxSize)
2242  {
2243  /* Use all of the unpartitioned disk space */
2244  SectorCount = PartEntry->SectorCount.QuadPart;
2245  }
2246  else
2247  {
2248  /* Calculate the sector count from the size in MB */
2249  SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2250 
2251  /* But never get larger than the unpartitioned disk space */
2252  if (SectorCount > PartEntry->SectorCount.QuadPart)
2253  SectorCount = PartEntry->SectorCount.QuadPart;
2254  }
2255 
2256  DPRINT ("Partition size: %I64u bytes\n", PartSize);
2257 
2260  SectorCount,
2261  FALSE);
2262 
2263  return SELECT_PARTITION_PAGE;
2264  }
2265  }
2266 
2268 }
2269 
2270 
2271 /*
2272  * Displays the CreateExtendedPartitionPage.
2273  *
2274  * Next pages:
2275  * SelectPartitionPage (default)
2276  * QuitPage
2277  *
2278  * RETURNS
2279  * Number of the next page.
2280  */
2281 static PAGE_NUMBER
2283 {
2284  PPARTENTRY PartEntry;
2285  PDISKENTRY DiskEntry;
2286  BOOLEAN Quit;
2287  BOOLEAN Cancel;
2288  WCHAR InputBuffer[50];
2289  ULONG MaxSize;
2290  ULONGLONG PartSize;
2291  ULONGLONG DiskSize;
2293  PCSTR Unit;
2294 
2295  if (PartitionList == NULL || CurrentPartition == NULL)
2296  {
2297  /* FIXME: show an error dialog */
2298  return QUIT_PAGE;
2299  }
2300 
2301  PartEntry = CurrentPartition;
2302  DiskEntry = CurrentPartition->DiskEntry;
2303 
2305 
2307 
2308  DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2309  PrettifySize1(&DiskSize, &Unit);
2310 
2311  if (DiskEntry->DriverName.Length > 0)
2312  {
2313  CONSOLE_PrintTextXY(6, 10,
2315  DiskSize,
2316  Unit,
2317  DiskEntry->DiskNumber,
2318  DiskEntry->Port,
2319  DiskEntry->Bus,
2320  DiskEntry->Id,
2321  &DiskEntry->DriverName,
2322  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2323  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2324  "RAW");
2325  }
2326  else
2327  {
2328  CONSOLE_PrintTextXY(6, 10,
2330  DiskSize,
2331  Unit,
2332  DiskEntry->DiskNumber,
2333  DiskEntry->Port,
2334  DiskEntry->Bus,
2335  DiskEntry->Id,
2336  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2337  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2338  "RAW");
2339  }
2340 
2342 
2343 #if 0
2344  CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2345  CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2346 #endif
2347 
2349 
2350  PartEntry = CurrentPartition;
2351  while (TRUE)
2352  {
2353  MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2354 
2355  if (MaxSize > PARTITION_MAXSIZE)
2356  MaxSize = PARTITION_MAXSIZE;
2357 
2358  ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2359  MaxSize, InputBuffer, &Quit, &Cancel);
2360 
2361  if (Quit)
2362  {
2363  if (ConfirmQuit(Ir))
2364  return QUIT_PAGE;
2365 
2366  break;
2367  }
2368  else if (Cancel)
2369  {
2370  return SELECT_PARTITION_PAGE;
2371  }
2372  else
2373  {
2374  PartSize = _wcstoui64(InputBuffer, NULL, 10);
2375 
2376  if (PartSize < 1)
2377  {
2378  /* Too small */
2379  continue;
2380  }
2381 
2382  if (PartSize > MaxSize)
2383  {
2384  /* Too large */
2385  continue;
2386  }
2387 
2388  /* Convert to bytes */
2389  if (PartSize == MaxSize)
2390  {
2391  /* Use all of the unpartitioned disk space */
2392  SectorCount = PartEntry->SectorCount.QuadPart;
2393  }
2394  else
2395  {
2396  /* Calculate the sector count from the size in MB */
2397  SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2398 
2399  /* But never get larger than the unpartitioned disk space */
2400  if (SectorCount > PartEntry->SectorCount.QuadPart)
2401  SectorCount = PartEntry->SectorCount.QuadPart;
2402  }
2403 
2404  DPRINT ("Partition size: %I64u bytes\n", PartSize);
2405 
2408  SectorCount);
2409 
2410  return SELECT_PARTITION_PAGE;
2411  }
2412  }
2413 
2415 }
2416 
2417 
2418 /*
2419  * Displays the CreateLogicalPartitionPage.
2420  *
2421  * Next pages:
2422  * SelectFileSystemPage (default)
2423  * QuitPage
2424  *
2425  * RETURNS
2426  * Number of the next page.
2427  */
2428 static PAGE_NUMBER
2430 {
2431  PPARTENTRY PartEntry;
2432  PDISKENTRY DiskEntry;
2433  BOOLEAN Quit;
2434  BOOLEAN Cancel;
2435  WCHAR InputBuffer[50];
2436  ULONG MaxSize;
2437  ULONGLONG PartSize;
2438  ULONGLONG DiskSize;
2440  PCSTR Unit;
2441 
2442  if (PartitionList == NULL || CurrentPartition == NULL)
2443  {
2444  /* FIXME: show an error dialog */
2445  return QUIT_PAGE;
2446  }
2447 
2448  PartEntry = CurrentPartition;
2449  DiskEntry = CurrentPartition->DiskEntry;
2450 
2452 
2454 
2455  DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2456  PrettifySize1(&DiskSize, &Unit);
2457 
2458  if (DiskEntry->DriverName.Length > 0)
2459  {
2460  CONSOLE_PrintTextXY(6, 10,
2462  DiskSize,
2463  Unit,
2464  DiskEntry->DiskNumber,
2465  DiskEntry->Port,
2466  DiskEntry->Bus,
2467  DiskEntry->Id,
2468  &DiskEntry->DriverName,
2469  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2470  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2471  "RAW");
2472  }
2473  else
2474  {
2475  CONSOLE_PrintTextXY(6, 10,
2477  DiskSize,
2478  Unit,
2479  DiskEntry->DiskNumber,
2480  DiskEntry->Port,
2481  DiskEntry->Bus,
2482  DiskEntry->Id,
2483  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2484  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2485  "RAW");
2486  }
2487 
2489 
2490 #if 0
2491  CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2492  CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2493 #endif
2494 
2496 
2497  PartEntry = CurrentPartition;
2498  while (TRUE)
2499  {
2500  MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2501 
2502  if (MaxSize > PARTITION_MAXSIZE)
2503  MaxSize = PARTITION_MAXSIZE;
2504 
2505  ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2506  MaxSize, InputBuffer, &Quit, &Cancel);
2507 
2508  if (Quit)
2509  {
2510  if (ConfirmQuit(Ir))
2511  return QUIT_PAGE;
2512 
2513  break;
2514  }
2515  else if (Cancel)
2516  {
2517  return SELECT_PARTITION_PAGE;
2518  }
2519  else
2520  {
2521  PartSize = _wcstoui64(InputBuffer, NULL, 10);
2522 
2523  if (PartSize < 1)
2524  {
2525  /* Too small */
2526  continue;
2527  }
2528 
2529  if (PartSize > MaxSize)
2530  {
2531  /* Too large */
2532  continue;
2533  }
2534 
2535  /* Convert to bytes */
2536  if (PartSize == MaxSize)
2537  {
2538  /* Use all of the unpartitioned disk space */
2539  SectorCount = PartEntry->SectorCount.QuadPart;
2540  }
2541  else
2542  {
2543  /* Calculate the sector count from the size in MB */
2544  SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2545 
2546  /* But never get larger than the unpartitioned disk space */
2547  if (SectorCount > PartEntry->SectorCount.QuadPart)
2548  SectorCount = PartEntry->SectorCount.QuadPart;
2549  }
2550 
2551  DPRINT("Partition size: %I64u bytes\n", PartSize);
2552 
2555  SectorCount,
2556  FALSE);
2557 
2558  return SELECT_PARTITION_PAGE;
2559  }
2560  }
2561 
2563 }
2564 
2565 
2566 /*
2567  * Displays the ConfirmDeleteSystemPartitionPage.
2568  *
2569  * Next pages:
2570  * DeletePartitionPage (default)
2571  * SelectPartitionPage
2572  *
2573  * RETURNS
2574  * Number of the next page.
2575  */
2576 static PAGE_NUMBER
2578 {
2580 
2581  while (TRUE)
2582  {
2583  CONSOLE_ConInKey(Ir);
2584 
2585  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2586  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2587  {
2588  if (ConfirmQuit(Ir))
2589  return QUIT_PAGE;
2590 
2591  break;
2592  }
2593  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2594  {
2595  return DELETE_PARTITION_PAGE;
2596  }
2597  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2598  {
2599  return SELECT_PARTITION_PAGE;
2600  }
2601  }
2602 
2604 }
2605 
2606 
2607 /*
2608  * Displays the DeletePartitionPage.
2609  *
2610  * Next pages:
2611  * SelectPartitionPage (default)
2612  * QuitPage
2613  *
2614  * RETURNS
2615  * Number of the next page.
2616  */
2617 static PAGE_NUMBER
2619 {
2620  PPARTENTRY PartEntry;
2621  PDISKENTRY DiskEntry;
2622  ULONGLONG DiskSize;
2623  ULONGLONG PartSize;
2624  PCSTR Unit;
2625  CHAR PartTypeString[32];
2626 
2627  if (PartitionList == NULL || CurrentPartition == NULL)
2628  {
2629  /* FIXME: show an error dialog */
2630  return QUIT_PAGE;
2631  }
2632 
2633  PartEntry = CurrentPartition;
2634  DiskEntry = CurrentPartition->DiskEntry;
2635 
2637 
2638  /* Adjust partition type */
2640  PartTypeString,
2641  ARRAYSIZE(PartTypeString));
2642 
2643  PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2644  PrettifySize2(&PartSize, &Unit);
2645 
2646  if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2647  {
2648  CONSOLE_PrintTextXY(6, 10,
2650  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2651  (PartEntry->DriveLetter == 0) ? '-' : ':',
2652  PartEntry->PartitionType,
2653  PartSize,
2654  Unit);
2655  }
2656  else
2657  {
2658  CONSOLE_PrintTextXY(6, 10,
2659  " %c%c %s %I64u %s",
2660  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2661  (PartEntry->DriveLetter == 0) ? '-' : ':',
2662  PartTypeString,
2663  PartSize,
2664  Unit);
2665  }
2666 
2667  DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2668  PrettifySize1(&DiskSize, &Unit);
2669 
2670  if (DiskEntry->DriverName.Length > 0)
2671  {
2672  CONSOLE_PrintTextXY(6, 12,
2674  DiskSize,
2675  Unit,
2676  DiskEntry->DiskNumber,
2677  DiskEntry->Port,
2678  DiskEntry->Bus,
2679  DiskEntry->Id,
2680  &DiskEntry->DriverName,
2681  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2682  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2683  "RAW");
2684  }
2685  else
2686  {
2687  CONSOLE_PrintTextXY(6, 12,
2689  DiskSize,
2690  Unit,
2691  DiskEntry->DiskNumber,
2692  DiskEntry->Port,
2693  DiskEntry->Bus,
2694  DiskEntry->Id,
2695  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2696  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2697  "RAW");
2698  }
2699 
2700  while (TRUE)
2701  {
2702  CONSOLE_ConInKey(Ir);
2703 
2704  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2705  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2706  {
2707  if (ConfirmQuit(Ir))
2708  return QUIT_PAGE;
2709 
2710  break;
2711  }
2712  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2713  {
2714  return SELECT_PARTITION_PAGE;
2715  }
2716  else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
2717  {
2720  &CurrentPartition);
2721  return SELECT_PARTITION_PAGE;
2722  }
2723  }
2724 
2725  return DELETE_PARTITION_PAGE;
2726 }
2727 
2728 
2729 static VOID
2731 {
2732  if (!FileSystemList)
2733  return;
2734 
2736  FileSystemList = NULL;
2737 }
2738 
2739 /*
2740  * Displays the SelectFileSystemPage.
2741  *
2742  * Next pages:
2743  * CheckFileSystemPage (At once if RepairUpdate is selected)
2744  * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2745  * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2746  * SelectPartitionPage (If the user aborts)
2747  * FormatPartitionPage (Default)
2748  * QuitPage
2749  *
2750  * SIDEEFFECTS
2751  * Calls UpdatePartitionType()
2752  * Calls FindSupportedSystemPartition()
2753  *
2754  * RETURNS
2755  * Number of the next page.
2756  */
2757 static PAGE_NUMBER
2759 {
2760  PPARTENTRY PartEntry;
2761  PDISKENTRY DiskEntry;
2762  ULONGLONG DiskSize;
2763  ULONGLONG PartSize;
2764  PCSTR DiskUnit;
2765  PCSTR PartUnit;
2766  CHAR PartTypeString[32];
2767  FORMATMACHINESTATE PreviousFormatState;
2768  PCWSTR DefaultFs;
2769 
2770  DPRINT("SelectFileSystemPage()\n");
2771 
2772  if (PartitionList == NULL || InstallPartition == NULL)
2773  {
2774  /* FIXME: show an error dialog */
2775  return QUIT_PAGE;
2776  }
2777 
2778  /* Find or set the active system partition when starting formatting */
2779  if (FormatState == Start)
2780  {
2781  /*
2782  * If we install on a fixed disk, try to find a supported system
2783  * partition on the system. Otherwise if we install on a removable disk
2784  * use the install partition as the system partition.
2785  */
2786  if (InstallPartition->DiskEntry->MediaType == FixedMedia)
2787  {
2789  FALSE,
2792  /* Use the original system partition as the old active partition hint */
2793  PartEntry = PartitionList->SystemPartition;
2794 
2797  {
2798  DPRINT1("We are using a different system partition!!!!\n");
2799 
2801 
2802  {
2803  PPARTENTRY PartEntry; // Shadow variable
2804 
2805  PartEntry = PartitionList->SystemPartition;
2806  DiskEntry = PartEntry->DiskEntry;
2807 
2808  /* Adjust partition size */
2809  PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2810  if (PartSize >= 10 * GB) /* 10 GB */
2811  {
2812  PartSize = PartSize / GB;
2813  PartUnit = MUIGetString(STRING_GB);
2814  }
2815  else
2816  {
2817  PartSize = PartSize / MB;
2818  PartUnit = MUIGetString(STRING_MB);
2819  }
2820 
2821  /* Adjust partition type */
2823  PartTypeString,
2824  ARRAYSIZE(PartTypeString));
2825 
2826  if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2827  {
2828  CONSOLE_PrintTextXY(8, 10,
2830  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2831  (PartEntry->DriveLetter == 0) ? '-' : ':',
2832  PartEntry->PartitionType,
2833  PartSize,
2834  PartUnit);
2835  }
2836  else
2837  {
2838  CONSOLE_PrintTextXY(8, 10,
2839  "%c%c %s %I64u %s",
2840  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2841  (PartEntry->DriveLetter == 0) ? '-' : ':',
2842  PartTypeString,
2843  PartSize,
2844  PartUnit);
2845  }
2846 
2847 
2848  /* Adjust disk size */
2849  DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2850  if (DiskSize >= 10 * GB) /* 10 GB */
2851  {
2852  DiskSize = DiskSize / GB;
2853  DiskUnit = MUIGetString(STRING_GB);
2854  }
2855  else
2856  {
2857  DiskSize = DiskSize / MB;
2858  DiskUnit = MUIGetString(STRING_MB);
2859  }
2860 
2862  DiskEntry->DiskNumber,
2863  DiskSize,
2864  DiskUnit,
2865  DiskEntry->Port,
2866  DiskEntry->Bus,
2867  DiskEntry->Id,
2868  &DiskEntry->DriverName,
2869  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2870  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2871  "RAW");
2872 
2873 
2874  PartEntry = SystemPartition;
2875  DiskEntry = PartEntry->DiskEntry;
2876 
2877  /* Adjust partition size */
2878  PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2879  if (PartSize >= 10 * GB) /* 10 GB */
2880  {
2881  PartSize = PartSize / GB;
2882  PartUnit = MUIGetString(STRING_GB);
2883  }
2884  else
2885  {
2886  PartSize = PartSize / MB;
2887  PartUnit = MUIGetString(STRING_MB);
2888  }
2889 
2890  /* Adjust partition type */
2892  PartTypeString,
2893  ARRAYSIZE(PartTypeString));
2894 
2895  if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2896  {
2897  CONSOLE_PrintTextXY(8, 23,
2899  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2900  (PartEntry->DriveLetter == 0) ? '-' : ':',
2901  PartEntry->PartitionType,
2902  PartSize,
2903  PartUnit);
2904  }
2905  else
2906  {
2907  CONSOLE_PrintTextXY(8, 23,
2908  "%c%c %s %I64u %s",
2909  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2910  (PartEntry->DriveLetter == 0) ? '-' : ':',
2911  PartTypeString,
2912  PartSize,
2913  PartUnit);
2914  }
2915 
2916  }
2917 
2918  while (TRUE)
2919  {
2920  CONSOLE_ConInKey(Ir);
2921 
2922  if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2923  {
2924  break;
2925  }
2926  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2927  {
2928  return SELECT_PARTITION_PAGE;
2929  }
2930  }
2931 
2933  CONSOLE_Flush();
2934  }
2935  }
2936  else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia)
2937  {
2939  /* Don't specify any old active partition hint */
2940  PartEntry = NULL;
2941  }
2942 
2943  if (!SystemPartition)
2944  {
2945  /* FIXME: improve the error dialog */
2946  //
2947  // Error dialog should say that we cannot find a suitable
2948  // system partition and create one on the system. At this point,
2949  // it may be nice to ask the user whether he wants to continue,
2950  // or use an external drive as the system drive/partition
2951  // (e.g. floppy, USB drive, etc...)
2952  //
2953  PopupError("The ReactOS Setup could not find a supported system partition\n"
2954  "on your system or could not create a new one. Without such partition\n"
2955  "the Setup program cannot install ReactOS.\n"
2956  "Press ENTER to return to the partition selection list.",
2958  Ir, POPUP_WAIT_ENTER);
2959  return SELECT_PARTITION_PAGE;
2960  }
2961 
2962  /*
2963  * If the system partition can be created in some
2964  * non-partitioned space, create it now.
2965  */
2967  {
2970  0LL, // SystemPartition->SectorCount.QuadPart,
2971  TRUE);
2973  }
2974 
2975  /* Set it as such */
2977  {
2978  DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition);
2979  ASSERT(FALSE);
2980  }
2981 
2982  /* Commit all partition changes to all the disks */
2984  {
2985  DPRINT("WritePartitionsToDisk() failed\n");
2987  return QUIT_PAGE;
2988  }
2989 
2990  /*
2991  * In all cases, whether or not we are going to perform a formatting,
2992  * we must perform a filesystem check of both the system and the
2993  * installation partitions.
2994  */
2998 
2999  /*
3000  * In case we just repair an existing installation, or make
3001  * an unattended setup without formatting, just go to the
3002  * filesystem check step.
3003  */
3004  if (RepairUpdateFlag)
3005  return CHECK_FILE_SYSTEM_PAGE;
3006 
3007  if (IsUnattendedSetup && !USetupData.FormatPartition)
3008  return CHECK_FILE_SYSTEM_PAGE;
3009  }
3010 
3011  // ASSERT(SystemPartition->IsPartitioned);
3012 
3013  /* Reset the filesystem list for each partition that is to be formatted */
3015 
3016  PreviousFormatState = FormatState;
3017  switch (FormatState)
3018  {
3019  case Start:
3020  {
3021  /*
3022  * We start by formatting the system partition in case it is new
3023  * (it didn't exist before) and is not the same as the installation
3024  * partition. Otherwise we just require a filesystem check on it,
3025  * and start by formatting the installation partition instead.
3026  */
3027 
3029 
3030  if ((SystemPartition != InstallPartition) &&
3032  {
3035 
3036  // TODO: Should we let the user using a custom file-system,
3037  // or should we always use FAT(32) for it?
3038  // For "compatibility", FAT(32) would be best indeed.
3039 
3041  DPRINT1("FormatState: Start --> FormatSystemPartition\n");
3042  }
3043  else
3044  {
3047 
3049  {
3050  /* The system partition is separate, so it had better be formatted! */
3053 
3054  /* Require a filesystem check on the system partition too */
3056  }
3057 
3059  DPRINT1("FormatState: Start --> FormatInstallPartition\n");
3060  }
3061  break;
3062  }
3063 
3064  case FormatSystemPartition:
3065  {
3068 
3070  DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
3071  break;
3072  }
3073 
3075  case FormatOtherPartition:
3076  {
3078  NULL,
3079  &TempPartition))
3080  {
3083 
3085  DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
3086  else
3087  DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
3088  }
3089  else
3090  {
3092 
3094  DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
3095  else
3096  DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
3097 
3098  return CHECK_FILE_SYSTEM_PAGE;
3099  }
3100  break;
3101  }
3102 
3103  case FormatDone:
3104  {
3105  DPRINT1("FormatState: FormatDone\n");
3106  return CHECK_FILE_SYSTEM_PAGE;
3107  }
3108 
3109  default:
3110  {
3111  DPRINT1("FormatState: Invalid value %ld\n", FormatState);
3112  ASSERT(FALSE);
3113  return QUIT_PAGE;
3114  }
3115  }
3116 
3117  PartEntry = TempPartition;
3118  DiskEntry = TempPartition->DiskEntry;
3119 
3120  ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3121 
3122  /* Adjust disk size */
3123  DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
3124  PrettifySize1(&DiskSize, &DiskUnit);
3125 
3126  /* Adjust partition size */
3127  PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
3128  PrettifySize2(&PartSize, &PartUnit);
3129 
3130  /* Adjust partition type */
3132  PartTypeString,
3133  ARRAYSIZE(PartTypeString));
3134 
3136 
3137  if (PartEntry->AutoCreate)
3138  {
3140 
3141 #if 0
3142  CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
3143  PartEntry->PartitionNumber,
3144  PartSize,
3145  PartUnit,
3146  PartTypeString);
3147 #endif
3148 
3150  DiskEntry->DiskNumber,
3151  DiskSize,
3152  DiskUnit,
3153  DiskEntry->Port,
3154  DiskEntry->Bus,
3155  DiskEntry->Id,
3156  &DiskEntry->DriverName,
3157  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
3158  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
3159  "RAW");
3160 
3162 
3163  PartEntry->AutoCreate = FALSE;
3164  }
3165  else if (PartEntry->New)
3166  {
3167  switch (FormatState)
3168  {
3169  case FormatSystemPartition:
3171  break;
3172 
3175  break;
3176 
3177  case FormatOtherPartition:
3179  break;
3180 
3181  default:
3182  ASSERT(FALSE);
3183  break;
3184  }
3185 
3187  DiskEntry->DiskNumber,
3188  DiskSize,
3189  DiskUnit,
3190  DiskEntry->Port,
3191  DiskEntry->Bus,
3192  DiskEntry->Id,
3193  &DiskEntry->DriverName,
3194  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
3195  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
3196  "RAW");
3197 
3199  }
3200  else
3201  {
3203 
3204  if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
3205  {
3206  CONSOLE_PrintTextXY(8, 10,
3208  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
3209  (PartEntry->DriveLetter == 0) ? '-' : ':',
3210  PartEntry->PartitionType,
3211  PartSize,
3212  PartUnit);
3213  }
3214  else
3215  {
3216  CONSOLE_PrintTextXY(8, 10,
3217  "%c%c %s %I64u %s",
3218  (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
3219  (PartEntry->DriveLetter == 0) ? '-' : ':',
3220  PartTypeString,
3221  PartSize,
3222  PartUnit);
3223  }
3224 
3226  DiskEntry->DiskNumber,
3227  DiskSize,
3228  DiskUnit,
3229  DiskEntry->Port,
3230  DiskEntry->Bus,
3231  DiskEntry->Id,
3232  &DiskEntry->DriverName,
3233  DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
3234  DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
3235  "RAW");
3236  }
3237 
3239 
3240  if (IsUnattendedSetup)
3241  {
3242  ASSERT(USetupData.FormatPartition);
3243 
3244  switch (USetupData.FsType)
3245  {
3246  /* 1 is for BtrFS */
3247  case 1:
3248  DefaultFs = L"BTRFS";
3249  break;
3250 
3251  /* If we don't understand input, default to FAT */
3252  default:
3253  DefaultFs = L"FAT";
3254  break;
3255  }
3256  }
3257  else
3258  {
3259  /* By default select the "FAT" file system */
3260  DefaultFs = L"FAT";
3261  }
3262 
3263  /* Create the file system list */
3264  // TODO: Display only the FSes compatible with the selected partition!
3266  PartEntry->New ||
3267  PartEntry->FormatState == Unformatted,
3268  DefaultFs);
3269  if (FileSystemList == NULL)
3270  {
3271  /* FIXME: show an error dialog */
3272  return QUIT_PAGE;
3273  }
3274 
3275  if (IsUnattendedSetup)
3276  {
3277  ASSERT(USetupData.FormatPartition);
3278  return FORMAT_PARTITION_PAGE;
3279  }
3280 
3282 
3283  while (TRUE)
3284  {
3285  CONSOLE_ConInKey(Ir);
3286 
3287  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3288  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3289  {
3290  if (ConfirmQuit(Ir))
3291  {
3292  /* Reset the filesystem list */
3294  return QUIT_PAGE;
3295  }
3296 
3297  break;
3298  }
3299  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
3300  {
3301  /* Reset the formatter machine state */
3302  TempPartition = NULL;
3303  FormatState = Start;
3304 
3305  /* Reset the filesystem list */
3307 
3308  return SELECT_PARTITION_PAGE;
3309  }
3310  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3311  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
3312  {
3314  }
3315  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3316  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
3317  {
3319  }
3320  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
3321  {
3323  {
3325 
3326  /*
3327  * Skip formatting this partition. We will also ignore
3328  * filesystem checks on it, unless it is either the system
3329  * or the installation partition.
3330  */
3331  if (TempPartition != SystemPartition &&
3333  {
3334  PartEntry->NeedsCheck = FALSE;
3335  }
3336 
3337  return SELECT_FILE_SYSTEM_PAGE;
3338  }
3339  else
3340  {
3341  /* Format this partition */
3342  return FORMAT_PARTITION_PAGE;
3343  }
3344  }
3345  }
3346 
3347  FormatState = PreviousFormatState;
3348 
3349  return SELECT_FILE_SYSTEM_PAGE;
3350 }
3351 
3352 
3353 /*
3354  * Displays the FormatPartitionPage.
3355  *
3356  * Next pages:
3357  * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3358  * SelectPartitionPage (At once)
3359  * QuitPage
3360  *
3361  * SIDEEFFECTS
3362  * Sets InstallPartition->FormatState
3363  * Sets USetupData.DestinationRootPath
3364  *
3365  * RETURNS
3366  * Number of the next page.
3367  */
3368 static PAGE_NUMBER
3370 {
3371  NTSTATUS Status;
3372  PPARTENTRY PartEntry;
3373  PDISKENTRY DiskEntry;
3374  PFILE_SYSTEM_ITEM SelectedFileSystem;
3375  WCHAR PathBuffer[MAX_PATH];
3376  CHAR Buffer[MAX_PATH];
3377 
3378  DPRINT("FormatPartitionPage()\n");
3379 
3381 
3382  if (PartitionList == NULL || TempPartition == NULL)
3383  {
3384  /* FIXME: show an error dialog */
3385  return QUIT_PAGE;
3386  }
3387 
3388  PartEntry = TempPartition;
3389  DiskEntry = TempPartition->DiskEntry;
3390 
3391  ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3392 
3393  SelectedFileSystem = FileSystemList->Selected;
3394  ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem);
3395 
3396  while (TRUE)
3397  {
3398  if (!IsUnattendedSetup)
3399  CONSOLE_ConInKey(Ir);
3400 
3401  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3402  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3403  {
3404  if (ConfirmQuit(Ir))
3405  {
3406  /* Reset the filesystem list */
3408  return QUIT_PAGE;
3409  }
3410 
3411  break;
3412  }
3413  else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3414  {
3415  /*
3416  * Remove the "Press ENTER to continue" message prompt when the ENTER
3417  * key is pressed as the user wants to begin the partition formatting.
3418  */
3421 
3422  /* Format the partition */
3423  Status = DoFormat(PartEntry,
3424  SelectedFileSystem->FileSystem,
3425  SelectedFileSystem->QuickFormat);
3427  {
3429 
3430  /* Reset the filesystem list */
3432  return QUIT_PAGE;
3433  }
3434  else if (Status == STATUS_UNRECOGNIZED_VOLUME)
3435  {
3436  /* FIXME: show an error dialog */
3437  // MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3438 
3439  /* Reset the filesystem list */
3441  return QUIT_PAGE;
3442  }
3443  else if (Status == STATUS_NOT_SUPPORTED)
3444  {
3446  sizeof(Buffer),
3447  "Setup is currently unable to format a partition in %S.\n"
3448  "\n"
3449  " \x07 Press ENTER to continue Setup.\n"
3450  " \x07 Press F3 to quit Setup.",
3451  SelectedFileSystem->FileSystem);
3452 
3456 
3457  while (TRUE)
3458  {
3459  CONSOLE_ConInKey(Ir);
3460 
3461  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3462  Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3463  {
3464  if (ConfirmQuit(Ir))
3465  {
3466  /* Reset the filesystem list */
3468  return QUIT_PAGE;
3469  }
3470  else
3471  {
3472  return SELECT_FILE_SYSTEM_PAGE;
3473  }
3474  }
3475  else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3476  {
3477  return SELECT_FILE_SYSTEM_PAGE;
3478  }
3479  }
3480  }
3481  else if (!NT_SUCCESS(Status))
3482  {
3484  RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3485  L"\\Device\\Harddisk%lu\\Partition%lu",
3486  DiskEntry->DiskNumber,
3487  PartEntry->PartitionNumber);
3488 
3489  DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3491 
3492  /* Reset the filesystem list */
3494  return QUIT_PAGE;
3495  }
3496 
3497  return SELECT_FILE_SYSTEM_PAGE;
3498  }
3499  }
3500 
3501  return FORMAT_PARTITION_PAGE;
3502 }
3503 
3504 
3505 /*
3506  * Displays the CheckFileSystemPage.
3507  *
3508  * Next pages:
3509  * InstallDirectoryPage (At once)
3510  * QuitPage
3511  *
3512  * SIDEEFFECTS
3513  * Inits or reloads FileSystemList
3514  *
3515  * RETURNS
3516  * Number of the next page.
3517  */
3518 static PAGE_NUMBER
3520 {
3521  NTSTATUS Status;
3522  PPARTENTRY PartEntry;
3523  CHAR Buffer[MAX_PATH];
3524 
3525  if (PartitionList == NULL)
3526  {
3527  /* FIXME: show an error dialog */
3528  return QUIT_PAGE;
3529  }
3530 
3531  if (!GetNextUncheckedPartition(PartitionList, NULL, &PartEntry))
3532  {
3533  return INSTALL_DIRECTORY_PAGE;
3534  }
3535 
3536  ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3537 
3540 
3541  DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3542  PartEntry->PartitionType, (*PartEntry->FileSystem ? PartEntry->FileSystem : L"n/a"));
3543 
3544  /* Check the partition */
3545  Status = DoChkdsk(PartEntry);
3547  {
3548  /*
3549  * Partition checking is not supported with the current filesystem,
3550  * so disable FS checks on it.
3551  */
3552  PartEntry->NeedsCheck = FALSE;
3553 
3555  sizeof(Buffer),
3556  "Setup is currently unable to check a partition formatted in %S.\n"
3557  "\n"
3558  " \x07 Press ENTER to continue Setup.\n"
3559  " \x07 Press F3 to quit Setup.",
3560  PartEntry->FileSystem);
3561 
3565 
3566  while (TRUE)
3567  {
3568  CONSOLE_ConInKey(Ir);
3569 
3570  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3571  Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3572  {
3573  if (ConfirmQuit(Ir))
3574  return QUIT_PAGE;
3575  else
3576  return CHECK_FILE_SYSTEM_PAGE;
3577  }
3578  else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3579  {
3580  return CHECK_FILE_SYSTEM_PAGE;
3581  }
3582  }
3583  }
3584  else if (!NT_SUCCESS(Status))
3585  {
3586  DPRINT1("ChkdskPartition() failed with status 0x%08lx\n", Status);
3587 
3589  sizeof(Buffer),
3590  "ChkDsk detected some disk errors.\n(Status 0x%08lx).\n",
3591  Status);
3592 
3595  Ir, POPUP_WAIT_ENTER);
3596  }
3597 
3598  PartEntry->NeedsCheck = FALSE;
3599  return CHECK_FILE_SYSTEM_PAGE;
3600 }
3601 
3602 
3603 static BOOLEAN
3605  IN PCWSTR InstallDir)
3606 {
3607  UINT i, Length;
3608 
3609  Length = wcslen(InstallDir);
3610 
3611  // TODO: Add check for 8.3 too.
3612 
3613  /* Path must be at least 2 characters long */
3614 // if (Length < 2)
3615 // return FALSE;
3616 
3617  /* Path must start with a backslash */
3618 // if (InstallDir[0] != L'\\')
3619 // return FALSE;
3620 
3621  /* Path must not end with a backslash */
3622  if (InstallDir[Length - 1] == L'\\')
3623  return FALSE;
3624 
3625  /* Path must not contain whitespace characters */
3626  for (i = 0; i < Length; i++)
3627  {
3628  if (iswspace(InstallDir[i]))
3629  return FALSE;
3630  }
3631 
3632  /* Path component must not end with a dot */
3633  for (i = 0; i < Length; i++)
3634  {
3635  if (InstallDir[i] == L'\\' && i > 0)
3636  {
3637  if (InstallDir[i - 1] == L'.')
3638  return FALSE;
3639  }
3640  }
3641 
3642  if (InstallDir[Length - 1] == L'.')
3643  return FALSE;
3644 
3645  return TRUE;
3646 }
3647 
3648 
3649 /*
3650  * Displays the InstallDirectoryPage.
3651  *
3652  * Next pages:
3653  * PrepareCopyPage
3654  * QuitPage
3655  *
3656  * RETURNS
3657  * Number of the next page.
3658  */
3659 static PAGE_NUMBER
3661 {
3662  NTSTATUS Status;
3663  ULONG Length, Pos;
3664  WCHAR c;
3665  WCHAR InstallDir[MAX_PATH];
3666 
3667  /* We do not need the filesystem list anymore */
3669 
3670  if (PartitionList == NULL || InstallPartition == NULL)
3671  {
3672  /* FIXME: show an error dialog */
3673  return QUIT_PAGE;
3674  }
3675 
3676  // if (IsUnattendedSetup)
3677  if (RepairUpdateFlag)
3678  wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3679  else if (USetupData.InstallationDirectory[0])
3680  wcscpy(InstallDir, USetupData.InstallationDirectory);
3681  else
3682  wcscpy(InstallDir, L"\\ReactOS");
3683 
3684  /*
3685  * Check the validity of the predefined 'InstallDir'. If we are either
3686  * in unattended setup or in update/repair mode, and the installation path
3687  * is valid, just perform the installation. Otherwise (either in the case
3688  * of an invalid path, or we are in regular setup), display the UI and allow
3689  * the user to specify a new installation path.
3690  */
3691  if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3692  {
3694  if (!NT_SUCCESS(Status))
3695  {
3696  DPRINT1("InitDestinationPaths() failed. Status code: 0x%lx", Status);
3698  return QUIT_PAGE;
3699  }
3700 
3701  /*
3702  * Check whether the user attempts to install ReactOS within the
3703  * installation source directory, or in a subdirectory thereof.
3704  * If so, fail with an error.
3705  */
3706  if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3707  {
3709  return INSTALL_DIRECTORY_PAGE;
3710  }
3711 
3712  return PREPARE_COPY_PAGE;
3713  }
3714 
3715  Length = wcslen(InstallDir);
3716  Pos = Length;
3717 
3719  CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3720  CONSOLE_SetCursorXY(8 + Pos, 11);
3722 
3723  while (TRUE)
3724  {
3725  CONSOLE_ConInKey(Ir);
3726 
3727  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3728  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3729  {
3731 
3732  if (ConfirmQuit(Ir))
3733  return QUIT_PAGE;
3734 
3736  break;
3737  }
3738  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3739  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3740  {
3741  if (Pos < Length)
3742  {
3743  memmove(&InstallDir[Pos],
3744  &InstallDir[Pos + 1],
3745  (Length - Pos - 1) * sizeof(WCHAR));
3746  InstallDir[Length - 1] = UNICODE_NULL;
3747 
3748  Length--;
3749  CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3750  CONSOLE_SetCursorXY(8 + Pos, 11);
3751  }
3752  }
3753  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3754  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3755  {
3756  Pos = 0;
3757  CONSOLE_SetCursorXY(8 + Pos, 11);
3758  }
3759  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3760  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3761  {
3762  Pos = Length;
3763  CONSOLE_SetCursorXY(8 + Pos, 11);
3764  }
3765  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3766  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3767  {
3768  if (Pos > 0)
3769  {
3770  Pos--;
3771  CONSOLE_SetCursorXY(8 + Pos, 11);
3772  }
3773  }
3774  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3775  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3776  {
3777  if (Pos < Length)
3778  {
3779  Pos++;
3780  CONSOLE_SetCursorXY(8 + Pos, 11);
3781  }
3782  }
3783  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3784  {
3786 
3787  /*
3788  * Check for the validity of the installation directory and pop up
3789  * an error if it is not the case. Then the user can fix its input.
3790  */
3791  if (!IsValidPath(InstallDir))
3792  {
3794  return INSTALL_DIRECTORY_PAGE;
3795  }
3796 
3798  if (!NT_SUCCESS(Status))
3799  {
3800  DPRINT1("InitDestinationPaths() failed. Status code: 0x%lx", Status);
3802  return QUIT_PAGE;
3803  }
3804 
3805  /*
3806  * Check whether the user attempts to install ReactOS within the
3807  * installation source directory, or in a subdirectory thereof.
3808  * If so, fail with an error.
3809  */
3810  if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3811  {
3813  return INSTALL_DIRECTORY_PAGE;
3814  }
3815 
3816  return PREPARE_COPY_PAGE;
3817  }
3818  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3819  {
3820  if (Pos > 0)
3821  {
3822  if (Pos < Length)
3823  memmove(&InstallDir[Pos - 1],
3824  &InstallDir[Pos],
3825  (Length - Pos) * sizeof(WCHAR));
3826  InstallDir[Length - 1] = UNICODE_NULL;
3827 
3828  Pos--;
3829  Length--;
3830  CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3831  CONSOLE_SetCursorXY(8 + Pos, 11);
3832  }
3833  }
3834  else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3835  {
3836  if (Length < 50)
3837  {
3839  if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3840  {
3841  if (Pos < Length)
3842  memmove(&InstallDir[Pos + 1],
3843  &InstallDir[Pos],
3844  (Length - Pos) * sizeof(WCHAR));
3845  InstallDir[Length + 1] = UNICODE_NULL;
3846  InstallDir[Pos] = c;
3847 
3848  Pos++;
3849  Length++;
3850  CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3851  CONSOLE_SetCursorXY(8 + Pos, 11);
3852  }
3853  }
3854  }
3855  }
3856 
3857  return INSTALL_DIRECTORY_PAGE;
3858 }
3859 
3860 
3861 // PSETUP_ERROR_ROUTINE
3862 static VOID
3863 __cdecl
3865  IN PUSETUP_DATA pSetupData,
3866  ...)
3867 {
3868  INPUT_RECORD Ir;
3869  va_list arg_ptr;
3870 
3871  va_start(arg_ptr, pSetupData);
3872 
3873  if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
3874  pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE)
3875  {
3876  // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3877  MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
3878  }
3879 
3880  va_end(arg_ptr);
3881 }
3882 
3883 /*
3884  * Displays the PrepareCopyPage.
3885  *
3886  * Next pages:
3887  * FileCopyPage(At once)
3888  * QuitPage
3889  *
3890  * SIDEEFFECTS
3891  * Calls PrepareFileCopy
3892  *
3893  * RETURNS
3894  * Number of the next page.
3895  */
3896 static PAGE_NUMBER
3898 {
3899  // ERROR_NUMBER ErrorNumber;
3900  BOOLEAN Success;
3901 
3903 
3904  /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL);
3905  if (/*ErrorNumber != ERROR_SUCCESS*/ !Success)
3906  {
3907  // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3908  return QUIT_PAGE;
3909  }
3910 
3911  return FILE_COPY_PAGE;
3912 }
3913 
3914 typedef struct _COPYCONTEXT
3915 {
3921 
3922 static VOID
3924  IN BOOLEAN First)
3925 {
3927 
3928  /* Get the memory information from the system */
3930  &PerfInfo,
3931  sizeof(PerfInfo),
3932  NULL);
3933 
3934  /* Check if this is initial setup */
3935  if (First)
3936  {
3937  /* Set maximum limits to be total RAM pages */
3938  ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3939  ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3940  ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3941  }
3942 
3943  /* Set current values */
3944  ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3945  ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3946  ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3947 }
3948 
3949 static UINT
3950 CALLBACK
3953  UINT_PTR Param1,
3954  UINT_PTR Param2)
3955 {
3956  PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
3957  PFILEPATHS_W FilePathInfo;
3958  PCWSTR SrcFileName, DstFileName;
3959 
3960  switch (Notification)
3961  {
3963  {
3964  CopyContext->TotalOperations = (ULONG)Param2;
3965  CopyContext->CompletedOperations = 0;
3966  ProgressSetStepCount(CopyContext->ProgressBar,
3967  CopyContext->TotalOperations);
3968  SetupUpdateMemoryInfo(CopyContext, TRUE);
3969  break;
3970  }
3971 
3975  {
3976  FilePathInfo = (PFILEPATHS_W)Param1;
3977 
3979  {
3980  /* Display delete message */
3981  ASSERT(Param2 == FILEOP_DELETE);
3982 
3983  DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3984  if (DstFileName) ++DstFileName;
3985  else DstFileName = FilePathInfo->Target;
3986 
3988  DstFileName);
3989  }
3991  {
3992  /* Display move/rename message */
3993  ASSERT(Param2 == FILEOP_RENAME);
3994 
3995  SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
3996  if (SrcFileName) ++SrcFileName;
3997  else SrcFileName = FilePathInfo->Source;
3998 
3999  DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
4000  if (DstFileName) ++DstFileName;
4001  else DstFileName = FilePathInfo->Target;
4002 
4003  if (!wcsicmp(SrcFileName, DstFileName))
4004  Param2 = STRING_MOVING;
4005  else
4006  Param2 = STRING_RENAMING;
4007 
4009  SrcFileName, DstFileName);
4010  }
4012  {
4013  /* Display copy message */
4014  ASSERT(Param2 == FILEOP_COPY);
4015 
4016  /* NOTE: When extracting from CABs the Source is the CAB name */
4017  DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
4018  if (DstFileName) ++DstFileName;
4019  else DstFileName = FilePathInfo->Target;
4020 
4022  DstFileName);
4023 #ifdef __REACTOS__ /* HACK */
4024  DoWatchDestFileName(DstFileName);
4025 #endif
4026  }
4027 
4028  SetupUpdateMemoryInfo(CopyContext, FALSE);
4029  break;
4030  }
4031 
4033  {
4034  FilePathInfo = (PFILEPATHS_W)Param1;
4035 
4036  DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
4037  FilePathInfo->Target, FilePathInfo->Win32Error);
4038  return FILEOP_SKIP;
4039  }
4040 
4043  case SPFILENOTIFY_ENDCOPY:
4044  {
4045  CopyContext->CompletedOperations++;
4046 
4047  /* SYSREG checkpoint */
4048  if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
4049  DPRINT1("CHECKPOINT:HALF_COPIED\n");
4050 
4051  ProgressNextStep(CopyContext->ProgressBar);
4052  SetupUpdateMemoryInfo(CopyContext, FALSE);
4053  break;
4054  }
4055  }
4056 
4057  return FILEOP_DOIT;
4058 }
4059 
4060 
4061 /*
4062  * Displays the FileCopyPage.
4063  *
4064  * Next pages:
4065  * RegistryPage(At once)
4066  *
4067  * SIDEEFFECTS
4068  * Calls DoFileCopy
4069  *
4070  * RETURNS
4071  * Number of the next page.
4072  */
4073 static PAGE_NUMBER
4075 {
4076  COPYCONTEXT CopyContext;
4077  UINT MemBarWidth;
4078 
4080 
4081  /* Create context for the copy process */
4082  CopyContext.TotalOperations = 0;
4083  CopyContext.CompletedOperations = 0;
4084 
4085  /* Create the progress bar as well */
4086  CopyContext.ProgressBar = CreateProgressBar(13,
4087  26,
4088  xScreen - 13,
4089  yScreen - 20,
4090  10,
4091  24,
4092  TRUE,
4094 
4095  // fit memory bars to screen width, distribute them uniform
4096  MemBarWidth = (xScreen - 26) / 5;
4097  MemBarWidth -= MemBarWidth % 2; // make even
4098  /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
4099  /* Create the paged pool progress bar */
4100  CopyContext.MemoryBars[0] = CreateProgressBar(13,
4101  40,
4102  13 + MemBarWidth,
4103  43,
4104  13,
4105  44,
4106  FALSE,
4107  "Kernel Pool");
4108 
4109  /* Create the non paged pool progress bar */
4110  CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
4111  40,
4112  (xScreen / 2) + (MemBarWidth / 2),
4113  43,
4114  (xScreen / 2)- (MemBarWidth / 2),
4115  44,
4116  FALSE,
4117  "Kernel Cache");
4118 
4119  /* Create the global memory progress bar */
4120  CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
4121  40,
4122  xScreen - 13,
4123  43,
4124  xScreen - 13 - MemBarWidth,
4125  44,
4126  FALSE,
4127  "Free Memory");
4128 
4129  /* Do the file copying */
4130  DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
4131 
4132  /* If we get here, we're done, so cleanup the progress bar */
4133  DestroyProgressBar(CopyContext.ProgressBar);
4134  DestroyProgressBar(CopyContext.MemoryBars[0]);
4135  DestroyProgressBar(CopyContext.MemoryBars[1]);
4136  DestroyProgressBar(CopyContext.MemoryBars[2]);
4137 
4138  /* Create the $winnt$.inf file */
4140 
4141  /* Go display the next page */
4142  return REGISTRY_PAGE;
4143 }
4144 
4145 
4146 static VOID
4147 __cdecl
4149 {
4150  /* WARNING: Please keep this lookup table in sync with the resources! */
4151  static const UINT StringIDs[] =
4152  {
4153  STRING_DONE, /* Success */
4154  STRING_REGHIVEUPDATE, /* RegHiveUpdate */
4155  STRING_IMPORTFILE, /* ImportRegHive */
4156  STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */
4157  STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */
4158  STRING_ADDKBLAYOUTS, /* KeybLayouts */
4159  STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */
4160  STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */
4161  };
4162 
4163  va_list args;
4164 
4165  if (RegStatus < ARRAYSIZE(StringIDs))
4166  {
4167  va_start(args, RegStatus);
4168  CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
4169  va_end(args);
4170  }
4171  else
4172  {
4173  CONSOLE_SetStatusText("Unknown status %d", RegStatus);
4174  }
4175 }
4176 
4177 /*
4178  * Displays the RegistryPage.
4179  *
4180  * Next pages:
4181  * SuccessPage (if RepairUpdate)
4182  * BootLoaderPage (default)
4183  * QuitPage
4184  *
4185  * SIDEEFFECTS
4186  * Calls UpdateRegistry
4187  *
4188  * RETURNS
4189  * Number of the next page.
4190  */
4191 static PAGE_NUMBER
4193 {
4194  ULONG Error;
4195 
4197 
4200  PartitionList,
4204  &s_SubstSettings);
4205  if (Error != ERROR_SUCCESS)
4206  {
4208  return QUIT_PAGE;
4209  }
4210  else
4211  {
4213  return BOOT_LOADER_PAGE;
4214  }
4215 }
4216 
4217 
4218 /*
4219  * Displays the BootLoaderPage.
4220  *
4221  * Next pages:
4222  * SuccessPage (if RepairUpdate)
4223  * BootLoaderHarddiskMbrPage
4224  * BootLoaderHarddiskVbrPage
4225  * BootLoaderFloppyPage
4226  * SuccessPage
4227  * QuitPage
4228  *
4229  * SIDEEFFECTS
4230  * Calls RegInitializeRegistry
4231  * Calls ImportRegistryFile
4232  * Calls SetDefaultPagefile
4233  * Calls SetMountedDeviceValues
4234  *
4235  * RETURNS
4236  * Number of the next page.
4237  */
4238 static PAGE_NUMBER
4240 {
4242  BOOLEAN InstallOnFloppy;
4243  USHORT Line = 12;
4244  WCHAR PathBuffer[MAX_PATH];
4245 
4247 
4248  /* We must have a supported system partition by now */
4250 
4251  RtlFreeUnicodeString(&USetupData.SystemRootPath);
4252  RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
4253  L"\\Device\\Harddisk%lu\\Partition%lu\\",
4254  SystemPartition->DiskEntry->DiskNumber,
4256  RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
4257  DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
4258 
4260 
4261  /* For unattended setup, skip MBR installation or install on floppy if needed */
4262  if (IsUnattendedSetup)
4263  {
4264  if ((USetupData.MBRInstallType == 0) ||
4265  (USetupData.MBRInstallType == 1))
4266  {
4267  goto Quit;
4268  }
4269  }
4270 
4271  /*
4272  * We may install an MBR or VBR, but before that, check whether
4273  * we need to actually install the VBR on floppy.
4274  */
4276  {
4277  DPRINT("Error: system partition invalid (unused)\n");
4278  InstallOnFloppy = TRUE;
4279  }
4280  else if (PartitionType == PARTITION_OS2BOOTMGR)
4281  {
4282  /* OS/2 boot manager partition */
4283  DPRINT("Found OS/2 boot manager partition\n");
4284  InstallOnFloppy = TRUE;
4285  }
4286  else if (PartitionType == PARTITION_LINUX)
4287  {
4288  /* Linux partition */
4289  DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
4290  InstallOnFloppy = FALSE;
4291  }
4292  else if (PartitionType == PARTITION_IFS)
4293  {
4294  /* NTFS partition */
4295  DPRINT("Found NTFS partition\n");
4296 
4297  // FIXME: Make it FALSE when we'll support NTFS installation!
4298  InstallOnFloppy = TRUE;
4299  }
4300  else if ((PartitionType == PARTITION_FAT_12) ||
4306  {
4307  DPRINT("Found FAT partition\n");
4308  InstallOnFloppy = FALSE;
4309  }
4310  else
4311  {
4312  /* Unknown partition */
4313  DPRINT("Unknown partition found\n");
4314  InstallOnFloppy = TRUE;
4315  }
4316 
4317  /* We should install on floppy */
4318  if (InstallOnFloppy)
4319  {
4320  USetupData.MBRInstallType = 1;
4321  goto Quit;
4322  }
4323 
4324  /* Is it an unattended install on hdd? */
4325  if (IsUnattendedSetup)
4326  {
4327  if ((USetupData.MBRInstallType == 2) ||
4328  (USetupData.MBRInstallType == 3))
4329  {
4330  goto Quit;
4331  }
4332  }
4333 
4335  CONSOLE_InvertTextXY(8, Line, 60, 1);
4336 
4337  while (TRUE)
4338  {
4339  CONSOLE_ConInKey(Ir);
4340 
4341  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4342  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
4343  {
4344  CONSOLE_NormalTextXY(8, Line, 60, 1);
4345 
4346  Line++;
4347  if (Line < 12)
4348  Line = 15;
4349 
4350  if (Line > 15)
4351  Line = 12;
4352 
4353  CONSOLE_InvertTextXY(8, Line, 60, 1);
4354  }
4355  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4356  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
4357  {
4358  CONSOLE_NormalTextXY(8, Line, 60, 1);
4359 
4360  Line--;
4361  if (Line < 12)
4362  Line = 15;
4363 
4364  if (Line > 15)
4365  Line = 12;
4366 
4367  CONSOLE_InvertTextXY(8, Line, 60, 1);
4368  }
4369  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4370  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
4371  {
4372  CONSOLE_NormalTextXY(8, Line, 60, 1);
4373 
4374  Line = 12;
4375 
4376  CONSOLE_InvertTextXY(8, Line, 60, 1);
4377  }
4378  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4379  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
4380  {
4381  CONSOLE_NormalTextXY(8, Line, 60, 1);
4382 
4383  Line = 15;
4384 
4385  CONSOLE_InvertTextXY(8, Line, 60, 1);
4386  }
4387  else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4388  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4389  {
4390  if (ConfirmQuit(Ir))
4391  return QUIT_PAGE;
4392 
4393  break;
4394  }
4395  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4396  {
4397  if (Line == 12)
4398  {
4399  /* Install on both MBR and VBR */
4400  USetupData.MBRInstallType = 2;
4401  break;
4402  }
4403  else if (Line == 13)
4404  {
4405  /* Install on VBR only */
4406  USetupData.MBRInstallType = 3;
4407  break;
4408  }
4409  else if (Line == 14)
4410  {
4411  /* Install on floppy */
4412  USetupData.MBRInstallType = 1;
4413  break;
4414  }
4415  else if (Line == 15)
4416  {
4417  /* Skip MBR installation */
4418  USetupData.MBRInstallType = 0;
4419  break;
4420  }
4421 
4422  return BOOT_LOADER_PAGE;
4423  }
4424  }
4425 
4426 Quit:
4427  switch (USetupData.MBRInstallType)
4428  {
4429  /* Skip MBR installation */
4430  case 0:
4431  return SUCCESS_PAGE;
4432 
4433  /* Install on floppy */
4434  case 1:
4435  return BOOT_LOADER_FLOPPY_PAGE;
4436 
4437  /* Install on both MBR and VBR */
4438  case 2:
4440 
4441  /* Install on VBR only */
4442  case 3:
4444  }
4445 
4446  return BOOT_LOADER_PAGE;
4447 }
4448 
4449 
4450 /*
4451  * Displays the BootLoaderFloppyPage.
4452  *
4453  * Next pages:
4454  * SuccessPage (At once)
4455  * QuitPage
4456  *
4457  * SIDEEFFECTS
4458  * Calls InstallFatBootcodeToFloppy()
4459  *
4460  * RETURNS
4461  * Number of the next page.
4462  */
4463 static PAGE_NUMBER
4465 {
4466  NTSTATUS Status;
4467 
4469 
4470 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4471 
4472  while (TRUE)
4473  {
4474  CONSOLE_ConInKey(Ir);
4475 
4476  if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4477  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4478  {
4479  if (ConfirmQuit(Ir))
4480  return QUIT_PAGE;
4481 
4482  break;
4483  }
4484  else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4485  {
4486  Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath,
4487  &USetupData.DestinationArcPath);
4488  if (!NT_SUCCESS(Status))
4489  {
4492 
4493  /* TODO: Print error message */
4494  return BOOT_LOADER_FLOPPY_PAGE;
4495  }
4496 
4497  return SUCCESS_PAGE;
4498  }
4499  }
4500 
4501  return BOOT_LOADER_FLOPPY_PAGE;
4502 }
4503 
4504 
4505 /*
4506  * Displays the BootLoaderHarddiskVbrPage.
4507  *
4508  * Next pages:
4509  * SuccessPage (At once)
4510  * QuitPage
4511  *
4512  * SIDEEFFECTS
4513  * Calls InstallVBRToPartition()
4514  *
4515  * RETURNS
4516  * Number of the next page.
4517  */
4518 static PAGE_NUMBER
4520 {
4521  NTSTATUS Status;
4522 
4523  Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4524  &USetupData.SourceRootPath,
4525  &USetupData.DestinationArcPath,
4527  if (!NT_SUCCESS(Status))
4528  {
4531  return QUIT_PAGE;
4532  }
4533 
4534  return SUCCESS_PAGE;
4535 }
4536 
4537 
4538 /*
4539  * Displays the BootLoaderHarddiskMbrPage.
4540  *
4541  * Next pages:
4542  * SuccessPage (At once)
4543  * QuitPage
4544  *
4545  * SIDEEFFECTS
4546  * Calls InstallVBRToPartition()
4547  * Calls InstallMbrBootCodeToDisk()
4548  *
4549  * RETURNS
4550  * Number of the next page.
4551  */
4552 static PAGE_NUMBER
4554 {
4555  NTSTATUS Status;
4556  WCHAR DestinationDevicePathBuffer[MAX_PATH];
4557 
4558  /* Step 1: Write the VBR */
4559  Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4560  &USetupData.SourceRootPath,
4561  &USetupData.DestinationArcPath,
4563  if (!NT_SUCCESS(Status))
4564  {
4567  return QUIT_PAGE;
4568  }
4569 
4570  /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */
4572  {
4573  RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
4574  L"\\Device\\Harddisk%d\\Partition0",
4575  SystemPartition->DiskEntry->DiskNumber);
4576  Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath,
4577  &USetupData.SourceRootPath,
4578  DestinationDevicePathBuffer);
4579  if (!NT_SUCCESS(Status))
4580  {
4581  DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
4583  return QUIT_PAGE;
4584  }
4585  }
4586 
4587  return SUCCESS_PAGE;
4588 }
4589 
4590 
4613 static
4614 BOOLEAN NTAPI
4618  OUT PSTR Buffer,
4620 {
4621  ULONG OldProgress = Bar->Progress;
4622 
4623  if (Bar->StepCount == 0)
4624  {
4625  Bar->Progress = 0;
4626  }
4627  else
4628  {
4629  Bar->Progress = Bar->StepCount - Bar->CurrentStep;
4630  }
4631 
4632  /* Build the progress string if it has changed */
4633  if (Bar->ProgressFormatText &&
4634  (AlwaysUpdate || (Bar->Progress != OldProgress)))
4635  {
4637  Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
4638 
4639  return TRUE;
4640  }
4641 
4642  return FALSE;
4643 }
4644 
4661 static VOID
4663  IN PINPUT_RECORD Ir,
4664  IN LONG TimeOut)
4665 {
4666  NTSTATUS Status;
4667  ULONG StartTime, BarWidth, TimerDiv;
4668  LONG TimeElapsed;
4669  LONG TimerValue, OldTimerValue;
4671  PPROGRESSBAR ProgressBar;
4672  BOOLEAN RefreshProgress = TRUE;
4673 
4674  /* Bail out if the timeout is already zero */
4675  if (TimeOut <= 0)
4676  return;
4677 
4678  /* Create the timeout progress bar and set it up */
4679  ProgressBar = CreateProgressBarEx(13,
4680  26,
4681  xScreen - 13,
4682  yScreen - 20,
4683  10,
4684  24,
4685  TRUE,
4687  0,
4688  NULL,
4691 
4692  BarWidth = max(1, ProgressBar->Width);
4693  TimerValue = TimeOut * BarWidth;
4694  ProgressSetStepCount(ProgressBar, TimerValue);
4695 
4697  CONSOLE_Flush();
4698 
4699  TimerDiv = 1000 / BarWidth;
4700  TimerDiv = max(1, TimerDiv);
4701  OldTimerValue = TimerValue;
4702  while (TRUE)
4703  {
4704  /* Decrease the timer */
4705 
4706  /*
4707  * Compute how much time the previous operations took.
4708  * This allows us in particular to take account for any time
4709  * elapsed if something slowed down.
4710  */
4711  TimeElapsed = NtGetTickCount() - StartTime;
4712  if (TimeElapsed >= TimerDiv)
4713  {
4714  /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4715  TimeElapsed /= TimerDiv;
4716  StartTime += (TimerDiv * TimeElapsed);
4717 
4718  if (TimeElapsed <= TimerValue)
4719  TimerValue -= TimeElapsed;
4720  else
4721  TimerValue = 0;
4722 
4723  RefreshProgress = TRUE;
4724  }
4725 
4726  if (RefreshProgress)
4727  {
4728  ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
4729  RefreshProgress = FALSE;
4730  }
4731 
4732  /* Stop when the timer reaches zero */
4733  if (TimerValue <= 0)
4734  break;
4735 
4736  /* Check for user key presses */
4737 
4738  /*
4739  * If the timer is used, use a passive wait of maximum 1 second
4740  * while monitoring for incoming console input events, so that
4741  * we are still able to display the timing count.
4742  */
4743 
4744  /* Wait a maximum of 1 second for input events */
4745  TimeElapsed = NtGetTickCount() - StartTime;
4746  if (TimeElapsed < TimerDiv)
4747  {
4748  /* Convert the time to NT format */
4749  Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
4751  }
4752  else
4753  {
4755  }
4756 
4757  /* Check whether the input event has been signaled, or a timeout happened */
4758  if (Status == STATUS_TIMEOUT)
4759  {
4760  continue;
4761  }
4762  if (Status != STATUS_WAIT_0)
4763  {
4764  /* An error happened, bail out */
4765  DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
4766  break;
4767  }
4768 
4769  /* Check for an ENTER key press */
4770  while (CONSOLE_ConInKeyPeek(Ir))
4771  {
4772  if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4773  {
4774  /* Found it, stop waiting */
4775  goto Exit;
4776  }
4777  }
4778  }
4779 
4780 Exit:
4781  /* Destroy the progress bar and quit */
4782  DestroyProgressBar(ProgressBar);
4783 }
4784 
4785 
4786 /*
4787  * Displays the QuitPage.
4788  *
4789  * Next pages:
4790  * FlushPage (At once)
4791  *
4792  * SIDEEFFECTS
4793  * Destroy the Lists
4794  *
4795  * RETURNS
4796  * Number of the next page.
4797  */
4798 static PAGE_NUMBER
4800 {
4802 
4803  /* Destroy the NTOS installations list */
4804  if (NtOsInstallsList != NULL)
4805  {
4808  }
4809 
4810  /* Destroy the partition list */
4811  if (PartitionList != NULL)
4812  {
4814  PartitionList = NULL;
4815  }
4816 
4817  /* Reset the formatter machine state */
4818  TempPartition = NULL;
4819  FormatState = Start;
4820 
4821  /* Destroy the filesystem list */
4823 
4825 
4826  /* Wait for maximum 15 seconds or an ENTER key before quitting */
4827  ProgressCountdown(Ir, 15);
4828  return FLUSH_PAGE;
4829 }
4830 
4831 
4832 /*
4833  * Displays the SuccessPage.
4834  *
4835  * Next pages:
4836  * FlushPage (At once)
4837  *
4838  * SIDEEFFECTS
4839  * Destroy the Lists
4840  *
4841  * RETURNS
4842  * Number of the next page.
4843  */
4844 static PAGE_NUMBER
4846 {
4848 
4849  if (IsUnattendedSetup)
4850  return FLUSH_PAGE;
4851 
4852  /* Wait for maximum 15 seconds or an ENTER key before quitting */
4853  ProgressCountdown(Ir, 15);
4854  return FLUSH_PAGE;
4855 }
4856 
4857 
4858 /*
4859  * Displays the FlushPage.
4860  *
4861  * Next pages:
4862  * RebootPage (At once)
4863  *
4864  * RETURNS
4865  * Number of the next page.
4866  */
4867 static PAGE_NUMBER
4869 {
4871  return REBOOT_PAGE;
4872 }
4873 
4874 
4875 /*
4876  * The start routine and page management
4877  */
4878 NTSTATUS
4880 {
4881  NTSTATUS Status;
4882  INPUT_RECORD Ir;
4883  PAGE_NUMBER Page;
4884  BOOLEAN Old;
4885 
4887 
4888  /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4890  if (!NT_SUCCESS(Status))
4891  DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
4892 
4893  /* Initialize the user-mode PnP manager */
4895  if (!NT_SUCCESS(Status))
4896  {
4897  // PrintString(??);
4898  DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status);
4899  }
4900 
4901  if (!CONSOLE_Init())
4902  {
4906 
4907  /* We failed to initialize the video, just quit the installer */
4908  return STATUS_APP_INIT_FAILURE;
4909  }
4910 
4911  /* Initialize Setup, phase 0 */
4913  USetupData.ErrorRoutine = USetupErrorRoutine;
4914 
4915  /* Hide the cursor and clear the screen and keyboard buffer */
4918  CONSOLE_Flush();
4919 
4920  /* Global Initialization page */
4921  Page = SetupStartPage(&Ir);
4922 
4923  while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
4924  {
4926  CONSOLE_Flush();
4927 
4928  // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4929 
4930  switch (Page)
4931  {
4932  /* Language page */
4933  case LANGUAGE_PAGE:
4934  Page = LanguagePage(&Ir);
4935  break;
4936 
4937  /* Welcome page */
4938  case WELCOME_PAGE:
4939  Page = WelcomePage(&Ir);
4940  break;
4941 
4942  /* License page */
4943  case LICENSE_PAGE:
4944  Page = LicensePage(&Ir);
4945  break;
4946 
4947  /* Install pages */
4948  case INSTALL_INTRO_PAGE:
4949  Page = InstallIntroPage(&Ir);
4950  break;
4951 
4952 #if 0
4953  case SCSI_CONTROLLER_PAGE:
4954  Page = ScsiControllerPage(&Ir);
4955  break;
4956 
4957  case OEM_DRIVER_PAGE:
4958  Page = OemDriverPage(&Ir);
4959  break;
4960 #endif
4961 
4962  case DEVICE_SETTINGS_PAGE:
4963  Page = DeviceSettingsPage(&Ir);
4964  break;
4965 
4967  Page = ComputerSettingsPage(&Ir);
4968  break;
4969 
4970  case DISPLAY_SETTINGS_PAGE:
4971  Page = DisplaySettingsPage(&Ir);
4972  break;
4973 
4975  Page = KeyboardSettingsPage(&Ir);
4976  break;
4977 
4978  case LAYOUT_SETTINGS_PAGE:
4979  Page = LayoutSettingsPage(&Ir);
4980  break;
4981 
4982  /* Partitioning pages */
4983  case SELECT_PARTITION_PAGE:
4984  Page = SelectPartitionPage(&Ir);
4985  break;
4986 
4988  Page = CreatePrimaryPartitionPage(&Ir);
4989  break;
4990 
4992  Page = CreateExtendedPartitionPage(&Ir);
4993  break;
4994 
4996  Page = CreateLogicalPartitionPage(&Ir);
4997  break;
4998 
5001  break;
5002 
5003  case DELETE_PARTITION_PAGE:
5004  Page = DeletePartitionPage(&Ir);
5005  break;
5006 
5007  /* Filesystem partition operations pages */
5009  Page = SelectFileSystemPage(&Ir);
5010  break;
5011 
5012  case FORMAT_PARTITION_PAGE:
5013  Page = FormatPartitionPage(&Ir);
5014  break;
5015 
5017  Page = CheckFileSystemPage(&Ir);
5018  break;
5019 
5020  /* Installation pages */
5022  Page = InstallDirectoryPage(&Ir);
5023  break;
5024 
5025  case PREPARE_COPY_PAGE:
5026  Page = PrepareCopyPage(&Ir);
5027  break;
5028 
5029  case FILE_COPY_PAGE:
5030  Page = FileCopyPage(&Ir);
5031  break;
5032 
5033  case REGISTRY_PAGE:
5034  Page = RegistryPage(&Ir);
5035  break;
5036 
5037  /* Bootloader installation pages */
5038  case BOOT_LOADER_PAGE:
5039  Page = BootLoaderPage(&Ir);
5040  break;
5041 
5043  Page = BootLoaderFloppyPage(&Ir);
5044  break;
5045 
5047  Page = BootLoaderHarddiskMbrPage(&Ir);
5048  break;
5049 
5051  Page = BootLoaderHarddiskVbrPage(&Ir);
5052  break;
5053 
5054  /* Repair pages */
5055  case REPAIR_INTRO_PAGE:
5056  Page = RepairIntroPage(&Ir);
5057  break;
5058 
5059  case UPGRADE_REPAIR_PAGE:
5060  Page = UpgradeRepairPage(&Ir);
5061  break;
5062 
5063  case SUCCESS_PAGE:
5064  Page = SuccessPage(&Ir);
5065  break;
5066 
5067  case FLUSH_PAGE:
5068  Page = FlushPage(&Ir);
5069  break;
5070 
5071  case QUIT_PAGE:
5072  Page = QuitPage(&Ir);
5073  break;
5074 
5075  /* Virtual pages */
5076  case SETUP_INIT_PAGE:
5077  case REBOOT_PAGE:
5078  case RECOVERY_PAGE:
5079  break;
5080 
5081  default:
5082  break;
5083  }
5084  }
5085 
5086  /* Terminate the user-mode PnP manager */
5088 
5089  /* Setup has finished */
5091&#