From a7a7e6a09cd5c8812d54b3202d013ba3907f2839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Mon, 23 Nov 2020 04:38:51 +0100 Subject: [PATCH] [SETUPLIB][USETUP] Isolate and decouple the filesystem operations code from the UI (#7049) The idea is reminiscent of the SetupCommitFileQueue() function: filesystem volume operations are "queued" and processed via a "commit queue". The commit queue uses a user-specified callback, that is used to interact with the user whenever an operation (filesystem formatting, checking) is started, ended, or fails, for example by displaying appropriate UI screens and choices, etc. --- base/setup/lib/fsutil.c | 569 +++++++++++++++-- base/setup/lib/fsutil.h | 170 +++-- base/setup/lib/setuplib.c | 93 +++ base/setup/lib/setuplib.h | 10 + base/setup/lib/utils/partlist.c | 118 ---- base/setup/lib/utils/partlist.h | 12 - base/setup/usetup/CMakeLists.txt | 3 +- base/setup/usetup/chkdsk.c | 89 --- base/setup/usetup/chkdsk.h | 33 - base/setup/usetup/fmtchk.c | 159 +++++ base/setup/usetup/fmtchk.h | 29 + base/setup/usetup/format.c | 127 ---- base/setup/usetup/format.h | 35 - base/setup/usetup/partlist.h | 13 - base/setup/usetup/usetup.c | 1024 +++++++++++++----------------- base/setup/usetup/usetup.h | 5 +- 16 files changed, 1377 insertions(+), 1112 deletions(-) delete mode 100644 base/setup/usetup/chkdsk.c delete mode 100644 base/setup/usetup/chkdsk.h create mode 100644 base/setup/usetup/fmtchk.c create mode 100644 base/setup/usetup/fmtchk.h delete mode 100644 base/setup/usetup/format.c delete mode 100644 base/setup/usetup/format.h diff --git a/base/setup/lib/fsutil.c b/base/setup/lib/fsutil.c index b58633e2df2..bd0422b8467 100644 --- a/base/setup/lib/fsutil.c +++ b/base/setup/lib/fsutil.c @@ -1,9 +1,9 @@ /* * PROJECT: ReactOS Setup Library - * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) - * PURPOSE: Filesystem Format and ChkDsk support functions. - * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net) - * Copyright 2017-2020 Hermes Belusca-Maito + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Filesystem Format and ChkDsk support functions + * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup + * Copyright 2017-2024 Hermès Bélusca-Maïto */ // @@ -242,13 +242,13 @@ GetFileSystemByName( /** ChkdskEx() **/ NTSTATUS ChkdskFileSystem_UStr( - IN PUNICODE_STRING DriveRoot, - IN PCWSTR FileSystemName, - IN BOOLEAN FixErrors, - IN BOOLEAN Verbose, - IN BOOLEAN CheckOnlyIfDirty, - IN BOOLEAN ScanDrive, - IN PFMIFSCALLBACK Callback) + _In_ PUNICODE_STRING DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN CheckOnlyIfDirty, + _In_ BOOLEAN ScanDrive, + _In_opt_ PFMIFSCALLBACK Callback) { PFILE_SYSTEM FileSystem; NTSTATUS Status; @@ -285,13 +285,13 @@ ChkdskFileSystem_UStr( NTSTATUS ChkdskFileSystem( - IN PCWSTR DriveRoot, - IN PCWSTR FileSystemName, - IN BOOLEAN FixErrors, - IN BOOLEAN Verbose, - IN BOOLEAN CheckOnlyIfDirty, - IN BOOLEAN ScanDrive, - IN PFMIFSCALLBACK Callback) + _In_ PCWSTR DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN CheckOnlyIfDirty, + _In_ BOOLEAN ScanDrive, + _In_opt_ PFMIFSCALLBACK Callback) { UNICODE_STRING DriveRootU; @@ -309,13 +309,13 @@ ChkdskFileSystem( /** FormatEx() **/ NTSTATUS FormatFileSystem_UStr( - IN PUNICODE_STRING DriveRoot, - IN PCWSTR FileSystemName, - IN FMIFS_MEDIA_FLAG MediaFlag, - IN PUNICODE_STRING Label, - IN BOOLEAN QuickFormat, - IN ULONG ClusterSize, - IN PFMIFSCALLBACK Callback) + _In_ PUNICODE_STRING DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ FMIFS_MEDIA_FLAG MediaFlag, + _In_opt_ PUNICODE_STRING Label, + _In_ BOOLEAN QuickFormat, + _In_ ULONG ClusterSize, + _In_opt_ PFMIFSCALLBACK Callback) { PFILE_SYSTEM FileSystem; BOOLEAN Success; @@ -374,13 +374,13 @@ FormatFileSystem_UStr( NTSTATUS FormatFileSystem( - IN PCWSTR DriveRoot, - IN PCWSTR FileSystemName, - IN FMIFS_MEDIA_FLAG MediaFlag, - IN PCWSTR Label, - IN BOOLEAN QuickFormat, - IN ULONG ClusterSize, - IN PFMIFSCALLBACK Callback) + _In_ PCWSTR DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ FMIFS_MEDIA_FLAG MediaFlag, + _In_opt_ PCWSTR Label, + _In_ BOOLEAN QuickFormat, + _In_ ULONG ClusterSize, + _In_opt_ PFMIFSCALLBACK Callback) { UNICODE_STRING DriveRootU; UNICODE_STRING LabelU; @@ -755,26 +755,22 @@ Quit: NTSTATUS ChkdskPartition( - IN PPARTENTRY PartEntry, - IN BOOLEAN FixErrors, - IN BOOLEAN Verbose, - IN BOOLEAN CheckOnlyIfDirty, - IN BOOLEAN ScanDrive, - IN PFMIFSCALLBACK Callback) + _In_ PPARTENTRY PartEntry, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN CheckOnlyIfDirty, + _In_ BOOLEAN ScanDrive, + _In_opt_ PFMIFSCALLBACK Callback) { - NTSTATUS Status; PDISKENTRY DiskEntry = PartEntry->DiskEntry; // UNICODE_STRING PartitionRootPath; WCHAR PartitionRootPath[MAX_PATH]; // PathBuffer ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); - /* HACK: Do not try to check a partition with an unknown filesystem */ + /* Do not check a partition with an unknown file system */ if (!*PartEntry->FileSystem) - { - PartEntry->NeedsCheck = FALSE; - return STATUS_SUCCESS; - } + return STATUS_UNRECOGNIZED_VOLUME; // STATUS_NOT_SUPPORTED; /* Set PartitionRootPath */ RtlStringCchPrintfW(PartitionRootPath, ARRAYSIZE(PartitionRootPath), @@ -784,29 +780,24 @@ ChkdskPartition( DPRINT("PartitionRootPath: %S\n", PartitionRootPath); /* Check the partition */ - Status = ChkdskFileSystem(PartitionRootPath, - PartEntry->FileSystem, - FixErrors, - Verbose, - CheckOnlyIfDirty, - ScanDrive, - Callback); - if (!NT_SUCCESS(Status)) - return Status; - - PartEntry->NeedsCheck = FALSE; - return STATUS_SUCCESS; + return ChkdskFileSystem(PartitionRootPath, + PartEntry->FileSystem, + FixErrors, + Verbose, + CheckOnlyIfDirty, + ScanDrive, + Callback); } NTSTATUS FormatPartition( - IN PPARTENTRY PartEntry, - IN PCWSTR FileSystemName, - IN FMIFS_MEDIA_FLAG MediaFlag, - IN PCWSTR Label, - IN BOOLEAN QuickFormat, - IN ULONG ClusterSize, - IN PFMIFSCALLBACK Callback) + _In_ PPARTENTRY PartEntry, + _In_ PCWSTR FileSystemName, + _In_ FMIFS_MEDIA_FLAG MediaFlag, + _In_opt_ PCWSTR Label, + _In_ BOOLEAN QuickFormat, + _In_ ULONG ClusterSize, + _In_opt_ PFMIFSCALLBACK Callback) { NTSTATUS Status; PDISKENTRY DiskEntry = PartEntry->DiskEntry; @@ -824,7 +815,7 @@ FormatPartition( /* * Prepare the partition for formatting (for MBR disks, reset the - * partition type), and adjust the filesystem name in case of FAT + * partition type), and adjust the file system name in case of FAT * vs. FAT32, depending on the geometry of the partition. */ @@ -832,7 +823,7 @@ FormatPartition( /* * Retrieve a partition type as a hint only. It will be used to determine - * whether to actually use FAT12/16 or FAT32 filesystem, depending on the + * whether to actually use FAT12/16 or FAT32 file system, depending on the * geometry of the partition. If the partition resides on an MBR disk, * the partition style will be reset to this value as well, unless the * partition is OEM. @@ -855,7 +846,7 @@ FormatPartition( } /* - * Adjust the filesystem name in case of FAT vs. FAT32, according to + * Adjust the file system name in case of FAT vs. FAT32, according to * the type of partition returned by FileSystemToMBRPartitionType(). */ if (wcsicmp(FileSystemName, L"FAT") == 0) @@ -910,4 +901,450 @@ FormatPartition( return STATUS_SUCCESS; } + +// +// FileSystem Volume Operations Queue +// + +static FSVOL_OP +DoFormatting( + _In_ PPARTENTRY PartEntry, + _In_opt_ PVOID Context, + _In_opt_ PFSVOL_CALLBACK FsVolCallback) +{ + FSVOL_OP Result; + NTSTATUS Status = STATUS_SUCCESS; + FORMAT_VOLUME_INFO FmtInfo = {0}; + + ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); + + FmtInfo.PartEntry = PartEntry; + +RetryFormat: + Result = FsVolCallback(Context, + FSVOLNOTIFY_STARTFORMAT, + (ULONG_PTR)&FmtInfo, + FSVOL_FORMAT); + if (Result != FSVOL_DOIT) + goto EndFormat; + + ASSERT(FmtInfo.FileSystemName && *FmtInfo.FileSystemName); + + /* Format the partition */ + Status = FormatPartition(PartEntry, + FmtInfo.FileSystemName, + FmtInfo.MediaFlag, + FmtInfo.Label, + FmtInfo.QuickFormat, + FmtInfo.ClusterSize, + FmtInfo.Callback); + if (!NT_SUCCESS(Status)) + { + // FmtInfo.NtPathPartition = PathBuffer; + FmtInfo.ErrorStatus = Status; + + Result = FsVolCallback(Context, + FSVOLNOTIFY_FORMATERROR, + (ULONG_PTR)&FmtInfo, + 0); + if (Result == FSVOL_RETRY) + goto RetryFormat; + // else if (Result == FSVOL_ABORT || Result == FSVOL_SKIP), stop. + } + +EndFormat: + /* This notification is always sent, even in case of error or abort */ + FmtInfo.ErrorStatus = Status; + FsVolCallback(Context, + FSVOLNOTIFY_ENDFORMAT, + (ULONG_PTR)&FmtInfo, + 0); + return Result; +} + +static FSVOL_OP +DoChecking( + _In_ PPARTENTRY PartEntry, + _In_opt_ PVOID Context, + _In_opt_ PFSVOL_CALLBACK FsVolCallback) +{ + FSVOL_OP Result; + NTSTATUS Status = STATUS_SUCCESS; + CHECK_VOLUME_INFO ChkInfo = {0}; + + ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); + + ASSERT(*PartEntry->FileSystem); + + ChkInfo.PartEntry = PartEntry; + +RetryCheck: + Result = FsVolCallback(Context, + FSVOLNOTIFY_STARTCHECK, + (ULONG_PTR)&ChkInfo, + FSVOL_CHECK); + if (Result != FSVOL_DOIT) + goto EndCheck; + + /* Check the partition */ + Status = ChkdskPartition(PartEntry, + ChkInfo.FixErrors, + ChkInfo.Verbose, + ChkInfo.CheckOnlyIfDirty, + ChkInfo.ScanDrive, + ChkInfo.Callback); + + /* If volume checking succeeded, or if it is not supported + * with the current file system, disable checks on the volume */ + if (NT_SUCCESS(Status) || (Status == STATUS_NOT_SUPPORTED)) + PartEntry->NeedsCheck = FALSE; + + if (!NT_SUCCESS(Status)) + { + // ChkInfo.NtPathPartition = PathBuffer; + ChkInfo.ErrorStatus = Status; + + Result = FsVolCallback(Context, + FSVOLNOTIFY_CHECKERROR, + (ULONG_PTR)&ChkInfo, + 0); + if (Result == FSVOL_RETRY) + goto RetryCheck; + // else if (Result == FSVOL_ABORT || Result == FSVOL_SKIP), stop. + + // PartEntry->NeedsCheck = FALSE; + } + +EndCheck: + /* This notification is always sent, even in case of error or abort */ + ChkInfo.ErrorStatus = Status; + FsVolCallback(Context, + FSVOLNOTIFY_ENDCHECK, + (ULONG_PTR)&ChkInfo, + 0); + return Result; +} + +static BOOLEAN +GetNextUnformattedPartition( + IN PPARTLIST List, + OUT PPARTENTRY *pPartEntry) +{ + PLIST_ENTRY Entry1, Entry2; + PDISKENTRY DiskEntry; + PPARTENTRY PartEntry; + + for (Entry1 = List->DiskListHead.Flink; + Entry1 != &List->DiskListHead; + Entry1 = Entry1->Flink) + { + DiskEntry = CONTAINING_RECORD(Entry1, + DISKENTRY, + ListEntry); + + if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) + { + DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); + continue; + } + + for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; + Entry2 != &DiskEntry->PrimaryPartListHead; + Entry2 = Entry2->Flink) + { + PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); + if (PartEntry->IsPartitioned && PartEntry->New) + { + ASSERT(DiskEntry == PartEntry->DiskEntry); + *pPartEntry = PartEntry; + return TRUE; + } + } + + for (Entry2 = DiskEntry->LogicalPartListHead.Flink; + Entry2 != &DiskEntry->LogicalPartListHead; + Entry2 = Entry2->Flink) + { + PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); + if (PartEntry->IsPartitioned && PartEntry->New) + { + ASSERT(DiskEntry == PartEntry->DiskEntry); + *pPartEntry = PartEntry; + return TRUE; + } + } + } + + *pPartEntry = NULL; + return FALSE; +} + +static BOOLEAN +GetNextUncheckedPartition( + IN PPARTLIST List, + OUT PPARTENTRY *pPartEntry) +{ + PLIST_ENTRY Entry1, Entry2; + PDISKENTRY DiskEntry; + PPARTENTRY PartEntry; + + for (Entry1 = List->DiskListHead.Flink; + Entry1 != &List->DiskListHead; + Entry1 = Entry1->Flink) + { + DiskEntry = CONTAINING_RECORD(Entry1, + DISKENTRY, + ListEntry); + + if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) + { + DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); + continue; + } + + for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; + Entry2 != &DiskEntry->PrimaryPartListHead; + Entry2 = Entry2->Flink) + { + PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); + if (PartEntry->IsPartitioned && PartEntry->NeedsCheck) + { + ASSERT(DiskEntry == PartEntry->DiskEntry); + *pPartEntry = PartEntry; + return TRUE; + } + } + + for (Entry2 = DiskEntry->LogicalPartListHead.Flink; + Entry2 != &DiskEntry->LogicalPartListHead; + Entry2 = Entry2->Flink) + { + PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); + if (PartEntry->IsPartitioned && PartEntry->NeedsCheck) + { + ASSERT(DiskEntry == PartEntry->DiskEntry); + *pPartEntry = PartEntry; + return TRUE; + } + } + } + + *pPartEntry = NULL; + return FALSE; +} + +BOOLEAN +FsVolCommitOpsQueue( + _In_ PPARTLIST PartitionList, + _In_ PPARTENTRY SystemPartition, + _In_ PPARTENTRY InstallPartition, + _In_opt_ PFSVOL_CALLBACK FsVolCallback, + _In_opt_ PVOID Context) +{ + BOOLEAN Success = TRUE; // Suppose success originally. + FSVOL_OP Result; + PPARTENTRY PartEntry; + + /* Machine state for the format step */ + typedef enum _FORMATMACHINESTATE + { + Start, + FormatSystemVolume, + FormatInstallVolume, + FormatOtherVolume, + FormatDone + } FORMATMACHINESTATE; + FORMATMACHINESTATE FormatState, OldFormatState; + static const PCSTR FormatStateNames[] = { + "Start", + "FormatSystemVolume", + "FormatInstallVolume", + "FormatOtherVolume", + "FormatDone" + }; + + ASSERT(PartitionList && InstallPartition && SystemPartition); + + /* Commit all partition changes to all the disks */ + if (!WritePartitionsToDisk(PartitionList)) + { + DPRINT("WritePartitionsToDisk() failed\n"); + /* Result = */ FsVolCallback(Context, + FSVOLNOTIFY_PARTITIONERROR, + STATUS_PARTITION_FAILURE, // FIXME + 0); + return FALSE; + } + +// +// FIXME: Should we do the following here, or in the caller? +// + /* + * In all cases, whether or not we are going to perform a formatting, + * we must perform a file system check of both the system and the + * installation volumes. + */ + SystemPartition->NeedsCheck = TRUE; + InstallPartition->NeedsCheck = TRUE; + + Result = FsVolCallback(Context, + FSVOLNOTIFY_STARTQUEUE, + 0, 0); + if (Result == FSVOL_ABORT) + return FALSE; + + /* + * Commit the Format queue + */ + + Result = FsVolCallback(Context, + FSVOLNOTIFY_STARTSUBQUEUE, + FSVOL_FORMAT, + 0); + if (Result == FSVOL_ABORT) + return FALSE; + /** HACK!! **/ + if (Result == FSVOL_SKIP) + goto StartCheckQueue; + /** END HACK!! **/ + + /* Reset the formatter machine state */ + FormatState = Start; +NextFormat: + PartEntry = NULL; + OldFormatState = FormatState; + switch (FormatState) + { + case Start: + { + /* + * We start by formatting the system volume in case it is new + * (it didn't exist before) and is not the same as the installation + * volume. Otherwise we just require a file system check on it, + * and start by formatting the installation volume instead. + */ + ASSERT(SystemPartition->IsPartitioned); + if (SystemPartition != InstallPartition) + { + PartEntry = SystemPartition; + + if (PartEntry->FormatState == Unformatted) + { + // TODO: Should we let the user use a custom file system, + // or should we always use FAT(32) for it? + // For "compatibility", FAT(32) would be best indeed. + + FormatState = FormatSystemVolume; + DPRINT1("FormatState: %s --> %s\n", + FormatStateNames[OldFormatState], FormatStateNames[FormatState]); + break; + } + + /* The system volume is separate, so it had better be formatted! */ + ASSERT((PartEntry->FormatState == Preformatted) || + (PartEntry->FormatState == Formatted)); + + /* Require a file system check on the system volume too */ + PartEntry->NeedsCheck = TRUE; + } + __fallthrough; + } + + case FormatSystemVolume: + { + PartEntry = InstallPartition; + + FormatState = FormatInstallVolume; + DPRINT1("FormatState: %s --> %s\n", + FormatStateNames[OldFormatState], FormatStateNames[FormatState]); + break; + } + + case FormatInstallVolume: + case FormatOtherVolume: + { + BOOLEAN Found = GetNextUnformattedPartition(PartitionList, &PartEntry); + if (Found) ASSERT(PartEntry); + + FormatState = (PartEntry ? FormatOtherVolume : FormatDone); + DPRINT1("FormatState: %s --> %s\n", + FormatStateNames[OldFormatState], FormatStateNames[FormatState]); + if (Found) + break; + __fallthrough; + } + + case FormatDone: + { + DPRINT1("FormatState: FormatDone\n"); + Success = TRUE; + goto EndFormat; + } + DEFAULT_UNREACHABLE; + } + + ASSERT(PartEntry); + Result = DoFormatting(PartEntry, Context, FsVolCallback); + if (Result == FSVOL_ABORT) + { + Success = FALSE; + goto Quit; + } + /* Schedule a check for this volume */ + PartEntry->NeedsCheck = TRUE; + /* Go to the next volume to be formatted */ + goto NextFormat; + +EndFormat: + FsVolCallback(Context, + FSVOLNOTIFY_ENDSUBQUEUE, + FSVOL_FORMAT, + 0); + + + /* + * Commit the CheckFS queue + */ + +StartCheckQueue: + Result = FsVolCallback(Context, + FSVOLNOTIFY_STARTSUBQUEUE, + FSVOL_CHECK, + 0); + if (Result == FSVOL_ABORT) + return FALSE; + +NextCheck: + if (!GetNextUncheckedPartition(PartitionList, &PartEntry)) + { + Success = TRUE; + goto EndCheck; + } + + ASSERT(PartEntry); + Result = DoChecking(PartEntry, Context, FsVolCallback); + if (Result == FSVOL_ABORT) + { + Success = FALSE; + goto Quit; + } + /* Go to the next volume to be checked */ + goto NextCheck; + +EndCheck: + FsVolCallback(Context, + FSVOLNOTIFY_ENDSUBQUEUE, + FSVOL_CHECK, + 0); + + +Quit: + /* All the queues have been committed */ + FsVolCallback(Context, + FSVOLNOTIFY_ENDQUEUE, + Success, + 0); + return Success; +} + /* EOF */ diff --git a/base/setup/lib/fsutil.h b/base/setup/lib/fsutil.h index 51877faa0fd..b132148a1f2 100644 --- a/base/setup/lib/fsutil.h +++ b/base/setup/lib/fsutil.h @@ -1,9 +1,9 @@ /* * PROJECT: ReactOS Setup Library - * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) - * PURPOSE: Filesystem Format and ChkDsk support functions. - * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net) - * Copyright 2017-2020 Hermes Belusca-Maito + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Filesystem Format and ChkDsk support functions + * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup + * Copyright 2017-2024 Hermès Bélusca-Maïto */ #pragma once @@ -20,45 +20,45 @@ GetRegisteredFileSystems( /** ChkdskEx() **/ NTSTATUS ChkdskFileSystem_UStr( - IN PUNICODE_STRING DriveRoot, - IN PCWSTR FileSystemName, - IN BOOLEAN FixErrors, - IN BOOLEAN Verbose, - IN BOOLEAN CheckOnlyIfDirty, - IN BOOLEAN ScanDrive, - IN PFMIFSCALLBACK Callback); + _In_ PUNICODE_STRING DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN CheckOnlyIfDirty, + _In_ BOOLEAN ScanDrive, + _In_opt_ PFMIFSCALLBACK Callback); NTSTATUS ChkdskFileSystem( - IN PCWSTR DriveRoot, - IN PCWSTR FileSystemName, - IN BOOLEAN FixErrors, - IN BOOLEAN Verbose, - IN BOOLEAN CheckOnlyIfDirty, - IN BOOLEAN ScanDrive, - IN PFMIFSCALLBACK Callback); + _In_ PCWSTR DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN CheckOnlyIfDirty, + _In_ BOOLEAN ScanDrive, + _In_opt_ PFMIFSCALLBACK Callback); /** FormatEx() **/ NTSTATUS FormatFileSystem_UStr( - IN PUNICODE_STRING DriveRoot, - IN PCWSTR FileSystemName, - IN FMIFS_MEDIA_FLAG MediaFlag, - IN PUNICODE_STRING Label, - IN BOOLEAN QuickFormat, - IN ULONG ClusterSize, - IN PFMIFSCALLBACK Callback); + _In_ PUNICODE_STRING DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ FMIFS_MEDIA_FLAG MediaFlag, + _In_opt_ PUNICODE_STRING Label, + _In_ BOOLEAN QuickFormat, + _In_ ULONG ClusterSize, + _In_opt_ PFMIFSCALLBACK Callback); NTSTATUS FormatFileSystem( - IN PCWSTR DriveRoot, - IN PCWSTR FileSystemName, - IN FMIFS_MEDIA_FLAG MediaFlag, - IN PCWSTR Label, - IN BOOLEAN QuickFormat, - IN ULONG ClusterSize, - IN PFMIFSCALLBACK Callback); + _In_ PCWSTR DriveRoot, + _In_ PCWSTR FileSystemName, + _In_ FMIFS_MEDIA_FLAG MediaFlag, + _In_opt_ PCWSTR Label, + _In_ BOOLEAN QuickFormat, + _In_ ULONG ClusterSize, + _In_opt_ PFMIFSCALLBACK Callback); // @@ -110,21 +110,101 @@ InstallNtfsBootCode( NTSTATUS ChkdskPartition( - IN PPARTENTRY PartEntry, - IN BOOLEAN FixErrors, - IN BOOLEAN Verbose, - IN BOOLEAN CheckOnlyIfDirty, - IN BOOLEAN ScanDrive, - IN PFMIFSCALLBACK Callback); + _In_ PPARTENTRY PartEntry, + _In_ BOOLEAN FixErrors, + _In_ BOOLEAN Verbose, + _In_ BOOLEAN CheckOnlyIfDirty, + _In_ BOOLEAN ScanDrive, + _In_opt_ PFMIFSCALLBACK Callback); NTSTATUS FormatPartition( - IN PPARTENTRY PartEntry, - IN PCWSTR FileSystemName, - IN FMIFS_MEDIA_FLAG MediaFlag, - IN PCWSTR Label, - IN BOOLEAN QuickFormat, - IN ULONG ClusterSize, - IN PFMIFSCALLBACK Callback); + _In_ PPARTENTRY PartEntry, + _In_ PCWSTR FileSystemName, + _In_ FMIFS_MEDIA_FLAG MediaFlag, + _In_opt_ PCWSTR Label, + _In_ BOOLEAN QuickFormat, + _In_ ULONG ClusterSize, + _In_opt_ PFMIFSCALLBACK Callback); + + +// +// FileSystem Volume Operations Queue +// + +typedef enum _FSVOLNOTIFY +{ + FSVOLNOTIFY_STARTQUEUE = 0, + FSVOLNOTIFY_ENDQUEUE, + FSVOLNOTIFY_STARTSUBQUEUE, + FSVOLNOTIFY_ENDSUBQUEUE, +// FSVOLNOTIFY_STARTPARTITION, FSVOLNOTIFY_ENDPARTITION, + FSVOLNOTIFY_PARTITIONERROR, + FSVOLNOTIFY_STARTFORMAT, + FSVOLNOTIFY_ENDFORMAT, + FSVOLNOTIFY_FORMATERROR, + FSVOLNOTIFY_STARTCHECK, + FSVOLNOTIFY_ENDCHECK, + FSVOLNOTIFY_CHECKERROR, + /**/ChangeSystemPartition/**/ // FIXME: Deprecate! +} FSVOLNOTIFY; + +typedef enum _FSVOL_OP +{ +/* Operations ****/ + FSVOL_FORMAT = 0, + FSVOL_CHECK, +/* Response actions ****/ + FSVOL_ABORT = 0, + FSVOL_DOIT, + FSVOL_RETRY = FSVOL_DOIT, + FSVOL_SKIP, +} FSVOL_OP; + +typedef struct _FORMAT_VOLUME_INFO +{ + PPARTENTRY PartEntry; + // PCWSTR NtPathPartition; + NTSTATUS ErrorStatus; + +/* Input information given by the 'FSVOLNOTIFY_STARTFORMAT' step ****/ + PCWSTR FileSystemName; + FMIFS_MEDIA_FLAG MediaFlag; + PCWSTR Label; + BOOLEAN QuickFormat; + ULONG ClusterSize; + PFMIFSCALLBACK Callback; + +} FORMAT_VOLUME_INFO, *PFORMAT_VOLUME_INFO; + +typedef struct _CHECK_VOLUME_INFO +{ + PPARTENTRY PartEntry; + // PCWSTR NtPathPartition; + NTSTATUS ErrorStatus; + +/* Input information given by the 'FSVOLNOTIFY_STARTCHECK' step ****/ + BOOLEAN FixErrors; + BOOLEAN Verbose; + BOOLEAN CheckOnlyIfDirty; + BOOLEAN ScanDrive; + PFMIFSCALLBACK Callback; + +} CHECK_VOLUME_INFO, *PCHECK_VOLUME_INFO; + +typedef FSVOL_OP +(CALLBACK *PFSVOL_CALLBACK)( + _In_opt_ PVOID Context, + _In_ FSVOLNOTIFY FormatStatus, + _In_ ULONG_PTR Param1, + _In_ ULONG_PTR Param2); + +BOOLEAN +FsVolCommitOpsQueue( + _In_ PPARTLIST PartitionList, + _In_ PPARTENTRY SystemPartition, + _In_ PPARTENTRY InstallPartition, + _In_opt_ PFSVOL_CALLBACK FsVolCallback, + _In_opt_ PVOID Context); /* EOF */ diff --git a/base/setup/lib/setuplib.c b/base/setup/lib/setuplib.c index c17293c99d2..2e915c52580 100644 --- a/base/setup/lib/setuplib.c +++ b/base/setup/lib/setuplib.c @@ -619,6 +619,99 @@ LoadSetupInf( return ERROR_SUCCESS; } +/** + * @brief Find or set the active system partition. + **/ +BOOLEAN +InitSystemPartition( + /**/_In_ PPARTLIST PartitionList, /* HACK HACK! */ + /**/_In_ PPARTENTRY InstallPartition, /* HACK HACK! */ + /**/_Out_ PPARTENTRY* pSystemPartition, /* HACK HACK! */ + _In_opt_ PFSVOL_CALLBACK FsVolCallback, + _In_opt_ PVOID Context) +{ + FSVOL_OP Result; + PPARTENTRY SystemPartition; + PPARTENTRY OldActivePart; + + /* + * If we install on a fixed disk, try to find a supported system + * partition on the system. Otherwise if we install on a removable disk + * use the install partition as the system partition. + */ + if (InstallPartition->DiskEntry->MediaType == FixedMedia) + { + SystemPartition = FindSupportedSystemPartition(PartitionList, + FALSE, + InstallPartition->DiskEntry, + InstallPartition); + /* Use the original system partition as the old active partition hint */ + OldActivePart = PartitionList->SystemPartition; + + if ( SystemPartition && PartitionList->SystemPartition && + (SystemPartition != PartitionList->SystemPartition) ) + { + DPRINT1("We are using a different system partition!!\n"); + + Result = FsVolCallback(Context, + ChangeSystemPartition, + (ULONG_PTR)SystemPartition, + 0); + if (Result != FSVOL_DOIT) + return FALSE; + } + } + else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia) + { + SystemPartition = InstallPartition; + /* Don't specify any old active partition hint */ + OldActivePart = NULL; + } + + if (!SystemPartition) + { + FsVolCallback(Context, + FSVOLNOTIFY_PARTITIONERROR, + ERROR_SYSTEM_PARTITION_NOT_FOUND, + 0); + return FALSE; + } + + *pSystemPartition = SystemPartition; + + /* + * If the system partition can be created in some + * non-partitioned space, create it now. + */ + if (!SystemPartition->IsPartitioned) + { + /* Automatically create the partition; it will be + * formatted later with default parameters */ + // FIXME: Don't use the whole empty space, but a minimal size + // specified from the TXTSETUP.SIF or unattended setup. + CreatePartition(PartitionList, + SystemPartition, + 0ULL, + 0); + ASSERT(SystemPartition->IsPartitioned); + } + + /* Set it as such */ + if (!SetActivePartition(PartitionList, SystemPartition, OldActivePart)) + { + DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition); + ASSERT(FALSE); + } + + /* + * In all cases, whether or not we are going to perform a formatting, + * we must perform a filesystem check of the system partition. + */ + SystemPartition->NeedsCheck = TRUE; + + return TRUE; +} + NTSTATUS InitDestinationPaths( IN OUT PUSETUP_DATA pSetupData, diff --git a/base/setup/lib/setuplib.h b/base/setup/lib/setuplib.h index 8988035f37d..411b810232a 100644 --- a/base/setup/lib/setuplib.h +++ b/base/setup/lib/setuplib.h @@ -167,6 +167,16 @@ ERROR_NUMBER LoadSetupInf( IN OUT PUSETUP_DATA pSetupData); +#define ERROR_SYSTEM_PARTITION_NOT_FOUND (ERROR_LAST_ERROR_CODE + 1) + +BOOLEAN +InitSystemPartition( + /**/_In_ PPARTLIST PartitionList, /* HACK HACK! */ + /**/_In_ PPARTENTRY InstallPartition, /* HACK HACK! */ + /**/_Out_ PPARTENTRY* pSystemPartition, /* HACK HACK! */ + _In_opt_ PFSVOL_CALLBACK FsVolCallback, + _In_opt_ PVOID Context); + NTSTATUS InitDestinationPaths( IN OUT PUSETUP_DATA pSetupData, diff --git a/base/setup/lib/utils/partlist.c b/base/setup/lib/utils/partlist.c index 1ccaf97d363..f8f530958d9 100644 --- a/base/setup/lib/utils/partlist.c +++ b/base/setup/lib/utils/partlist.c @@ -3946,122 +3946,4 @@ SetMBRPartitionType( DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE; } -BOOLEAN -GetNextUnformattedPartition( - IN PPARTLIST List, - OUT PDISKENTRY *pDiskEntry OPTIONAL, - OUT PPARTENTRY *pPartEntry) -{ - PLIST_ENTRY Entry1, Entry2; - PDISKENTRY DiskEntry; - PPARTENTRY PartEntry; - - for (Entry1 = List->DiskListHead.Flink; - Entry1 != &List->DiskListHead; - Entry1 = Entry1->Flink) - { - DiskEntry = CONTAINING_RECORD(Entry1, - DISKENTRY, - ListEntry); - - if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) - { - DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); - continue; - } - - for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; - Entry2 != &DiskEntry->PrimaryPartListHead; - Entry2 = Entry2->Flink) - { - PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); - if (PartEntry->IsPartitioned && PartEntry->New) - { - ASSERT(DiskEntry == PartEntry->DiskEntry); - if (pDiskEntry) *pDiskEntry = DiskEntry; - *pPartEntry = PartEntry; - return TRUE; - } - } - - for (Entry2 = DiskEntry->LogicalPartListHead.Flink; - Entry2 != &DiskEntry->LogicalPartListHead; - Entry2 = Entry2->Flink) - { - PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); - if (PartEntry->IsPartitioned && PartEntry->New) - { - ASSERT(DiskEntry == PartEntry->DiskEntry); - if (pDiskEntry) *pDiskEntry = DiskEntry; - *pPartEntry = PartEntry; - return TRUE; - } - } - } - - if (pDiskEntry) *pDiskEntry = NULL; - *pPartEntry = NULL; - - return FALSE; -} - -BOOLEAN -GetNextUncheckedPartition( - IN PPARTLIST List, - OUT PDISKENTRY *pDiskEntry OPTIONAL, - OUT PPARTENTRY *pPartEntry) -{ - PLIST_ENTRY Entry1, Entry2; - PDISKENTRY DiskEntry; - PPARTENTRY PartEntry; - - for (Entry1 = List->DiskListHead.Flink; - Entry1 != &List->DiskListHead; - Entry1 = Entry1->Flink) - { - DiskEntry = CONTAINING_RECORD(Entry1, - DISKENTRY, - ListEntry); - - if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT) - { - DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n"); - continue; - } - - for (Entry2 = DiskEntry->PrimaryPartListHead.Flink; - Entry2 != &DiskEntry->PrimaryPartListHead; - Entry2 = Entry2->Flink) - { - PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); - if (PartEntry->IsPartitioned && PartEntry->NeedsCheck) - { - ASSERT(DiskEntry == PartEntry->DiskEntry); - if (pDiskEntry) *pDiskEntry = DiskEntry; - *pPartEntry = PartEntry; - return TRUE; - } - } - - for (Entry2 = DiskEntry->LogicalPartListHead.Flink; - Entry2 != &DiskEntry->LogicalPartListHead; - Entry2 = Entry2->Flink) - { - PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry); - if (PartEntry->IsPartitioned && PartEntry->NeedsCheck) - { - ASSERT(DiskEntry == PartEntry->DiskEntry); - if (pDiskEntry) *pDiskEntry = DiskEntry; - *pPartEntry = PartEntry; - return TRUE; - } - } - } - - if (pDiskEntry) *pDiskEntry = NULL; - *pPartEntry = NULL; - - return FALSE; -} - /* EOF */ diff --git a/base/setup/lib/utils/partlist.h b/base/setup/lib/utils/partlist.h index d6be1a3032f..9654baf3839 100644 --- a/base/setup/lib/utils/partlist.h +++ b/base/setup/lib/utils/partlist.h @@ -353,16 +353,4 @@ SetMBRPartitionType( IN PPARTENTRY PartEntry, IN UCHAR PartitionType); -BOOLEAN -GetNextUnformattedPartition( - IN PPARTLIST List, - OUT PDISKENTRY *pDiskEntry OPTIONAL, - OUT PPARTENTRY *pPartEntry); - -BOOLEAN -GetNextUncheckedPartition( - IN PPARTLIST List, - OUT PDISKENTRY *pDiskEntry OPTIONAL, - OUT PPARTENTRY *pPartEntry); - /* EOF */ diff --git a/base/setup/usetup/CMakeLists.txt b/base/setup/usetup/CMakeLists.txt index 1ef57a42082..94ef7cffd14 100644 --- a/base/setup/usetup/CMakeLists.txt +++ b/base/setup/usetup/CMakeLists.txt @@ -13,12 +13,11 @@ list(APPEND SOURCE spapisup/cabinet.c spapisup/fileqsup.c spapisup/infsupp.c - chkdsk.c cmdcons.c console.c consup.c devinst.c - format.c + fmtchk.c fslist.c genlist.c keytrans.c diff --git a/base/setup/usetup/chkdsk.c b/base/setup/usetup/chkdsk.c deleted file mode 100644 index b302dc94581..00000000000 --- a/base/setup/usetup/chkdsk.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ReactOS kernel - * Copyright (C) 2006 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS text-mode setup - * FILE: base/setup/usetup/chkdsk.c - * PURPOSE: Filesystem chkdsk support functions - * PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org) - */ - -/* INCLUDES *****************************************************************/ - -#include "usetup.h" - -#define NDEBUG -#include - -static PPROGRESSBAR ChkdskProgressBar = NULL; - -/* FUNCTIONS ****************************************************************/ - -static -BOOLEAN -NTAPI -ChkdskCallback( - IN CALLBACKCOMMAND Command, - IN ULONG Modifier, - IN PVOID Argument) -{ - switch (Command) - { - default: - DPRINT("Unknown callback %lu\n", (ULONG)Command); - break; - } - - return TRUE; -} - -NTSTATUS -DoChkdsk( - IN PPARTENTRY PartEntry) -{ - NTSTATUS Status; - - ChkdskProgressBar = CreateProgressBar(6, - yScreen - 14, - xScreen - 7, - yScreen - 10, - 10, - 24, - TRUE, - MUIGetString(STRING_CHECKINGDISK)); - - ProgressSetStepCount(ChkdskProgressBar, 100); - - // TODO: Think about which values could be defaulted... - Status = ChkdskPartition(PartEntry, - TRUE, /* FixErrors */ - FALSE, /* Verbose */ - TRUE, /* CheckOnlyIfDirty */ - FALSE, /* ScanDrive */ - ChkdskCallback); /* Callback */ - - DestroyProgressBar(ChkdskProgressBar); - ChkdskProgressBar = NULL; - - DPRINT("ChkdskPartition() finished with status 0x%08lx\n", Status); - - return Status; -} - -/* EOF */ diff --git a/base/setup/usetup/chkdsk.h b/base/setup/usetup/chkdsk.h deleted file mode 100644 index 594c9b13b61..00000000000 --- a/base/setup/usetup/chkdsk.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * ReactOS kernel - * Copyright (C) 2006 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS text-mode setup - * FILE: base/setup/usetup/chkdsk.h - * PURPOSE: Filesystem chkdsk support functions - * PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org) - */ - -#pragma once - -NTSTATUS -DoChkdsk( - IN PPARTENTRY PartEntry); - -/* EOF */ diff --git a/base/setup/usetup/fmtchk.c b/base/setup/usetup/fmtchk.c new file mode 100644 index 00000000000..83271043794 --- /dev/null +++ b/base/setup/usetup/fmtchk.c @@ -0,0 +1,159 @@ +/* + * PROJECT: ReactOS text-mode setup + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Filesystem Format and ChkDsk support functions + * COPYRIGHT: Copyright 2003 Casper S. Hornstrup + * Copyright 2006 Hervé Poussineau + * Copyright 2024 Hermès Bélusca-Maïto + */ + +/* INCLUDES ******************************************************************/ + +#include "usetup.h" + +#define NDEBUG +#include + +static PPROGRESSBAR ProgressBar = NULL; + +/* FORMAT FUNCTIONS **********************************************************/ + +static +BOOLEAN +NTAPI +FormatCallback( + _In_ CALLBACKCOMMAND Command, + _In_ ULONG Modifier, + _In_ PVOID Argument) +{ + switch (Command) + { + case PROGRESS: + { + PULONG Percent = (PULONG)Argument; + DPRINT("%lu percent completed\n", *Percent); + ProgressSetStep(ProgressBar, *Percent); + break; + } + +#if 0 + case OUTPUT: + { + PTEXTOUTPUT output = (PTEXTOUTPUT)Argument; + DPRINT("%s\n", output->Output); + break; + } +#endif + + case DONE: + { +#if 0 + PBOOLEAN Success = (PBOOLEAN)Argument; + if (*Success == FALSE) + { + DPRINT("FormatEx was unable to complete successfully.\n\n"); + } +#endif + DPRINT("Done\n"); + break; + } + + default: + DPRINT("Unknown callback %lu\n", (ULONG)Command); + break; + } + + return TRUE; +} + +VOID +StartFormat( + _Inout_ PFORMAT_VOLUME_INFO FmtInfo, + _In_ PFILE_SYSTEM_ITEM SelectedFileSystem) +{ + ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem); + + // TODO: Think about which values could be defaulted... + FmtInfo->FileSystemName = SelectedFileSystem->FileSystem; + FmtInfo->MediaFlag = FMIFS_HARDDISK; + FmtInfo->Label = NULL; + FmtInfo->QuickFormat = SelectedFileSystem->QuickFormat; + FmtInfo->ClusterSize = 0; + FmtInfo->Callback = FormatCallback; + + ProgressBar = CreateProgressBar(6, + yScreen - 14, + xScreen - 7, + yScreen - 10, + 10, + 24, + TRUE, + MUIGetString(STRING_FORMATTINGPART)); + + ProgressSetStepCount(ProgressBar, 100); +} + +VOID +EndFormat( + _In_ NTSTATUS Status) +{ + DestroyProgressBar(ProgressBar); + ProgressBar = NULL; + + DPRINT("FormatPartition() finished with status 0x%08lx\n", Status); +} + +/* CHKDSK FUNCTIONS **********************************************************/ + +static +BOOLEAN +NTAPI +ChkdskCallback( + _In_ CALLBACKCOMMAND Command, + _In_ ULONG Modifier, + _In_ PVOID Argument) +{ + switch (Command) + { + default: + DPRINT("Unknown callback %lu\n", (ULONG)Command); + break; + } + + return TRUE; +} + +VOID +StartCheck( + _Inout_ PCHECK_VOLUME_INFO ChkInfo) +{ + // TODO: Think about which values could be defaulted... + ChkInfo->FixErrors = TRUE; + ChkInfo->Verbose = FALSE; + ChkInfo->CheckOnlyIfDirty = TRUE; + ChkInfo->ScanDrive = FALSE; + ChkInfo->Callback = ChkdskCallback; + + ProgressBar = CreateProgressBar(6, + yScreen - 14, + xScreen - 7, + yScreen - 10, + 10, + 24, + TRUE, + MUIGetString(STRING_CHECKINGDISK)); + + ProgressSetStepCount(ProgressBar, 100); +} + +VOID +EndCheck( + _In_ NTSTATUS Status) +{ + DestroyProgressBar(ProgressBar); + ProgressBar = NULL; + + DPRINT("ChkdskPartition() finished with status 0x%08lx\n", Status); +} + +/* EOF */ diff --git a/base/setup/usetup/fmtchk.h b/base/setup/usetup/fmtchk.h new file mode 100644 index 00000000000..4b0a1851411 --- /dev/null +++ b/base/setup/usetup/fmtchk.h @@ -0,0 +1,29 @@ +/* + * PROJECT: ReactOS text-mode setup + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Filesystem Format and ChkDsk support functions + * COPYRIGHT: Copyright 2003 Casper S. Hornstrup + * Copyright 2006 Hervé Poussineau + * Copyright 2024 Hermès Bélusca-Maïto + */ + +#pragma once + +VOID +StartFormat( + _Inout_ PFORMAT_VOLUME_INFO FmtInfo, + _In_ PFILE_SYSTEM_ITEM SelectedFileSystem); + +VOID +EndFormat( + _In_ NTSTATUS Status); + +VOID +StartCheck( + _Inout_ PCHECK_VOLUME_INFO ChkInfo); + +VOID +EndCheck( + _In_ NTSTATUS Status); + +/* EOF */ diff --git a/base/setup/usetup/format.c b/base/setup/usetup/format.c deleted file mode 100644 index 21d4d1f87d5..00000000000 --- a/base/setup/usetup/format.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ReactOS kernel - * Copyright (C) 2003 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS text-mode setup - * FILE: base/setup/usetup/format.c - * PURPOSE: Filesystem format support functions - * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - */ - -/* INCLUDES *****************************************************************/ - -#include "usetup.h" - -#define NDEBUG -#include - -static PPROGRESSBAR FormatProgressBar = NULL; - -/* FUNCTIONS ****************************************************************/ - -static -BOOLEAN -NTAPI -FormatCallback( - IN CALLBACKCOMMAND Command, - IN ULONG Modifier, - IN PVOID Argument) -{ - switch (Command) - { - case PROGRESS: - { - PULONG Percent; - - Percent = (PULONG)Argument; - DPRINT("%lu percent completed\n", *Percent); - - ProgressSetStep(FormatProgressBar, *Percent); - break; - } - -#if 0 - case OUTPUT: - { - PTEXTOUTPUT Output; - output = (PTEXTOUTPUT) Argument; - DPRINT("%s\n", output->Output); - break; - } -#endif - - case DONE: - { - // PBOOLEAN Success; - DPRINT("Done\n"); -#if 0 - Success = (PBOOLEAN)Argument; - if (*Success == FALSE) - { - DPRINT("FormatEx was unable to complete successfully.\n\n"); - } -#endif - break; - } - - default: - DPRINT("Unknown callback %lu\n", (ULONG)Command); - break; - } - - return TRUE; -} - -NTSTATUS -DoFormat( - IN PPARTENTRY PartEntry, - IN PCWSTR FileSystemName, - IN BOOLEAN QuickFormat) -{ - NTSTATUS Status; - - FormatProgressBar = CreateProgressBar(6, - yScreen - 14, - xScreen - 7, - yScreen - 10, - 10, - 24, - TRUE, - MUIGetString(STRING_FORMATTINGPART)); - - ProgressSetStepCount(FormatProgressBar, 100); - - // TODO: Think about which values could be defaulted... - Status = FormatPartition(PartEntry, - FileSystemName, - FMIFS_HARDDISK, /* MediaFlag */ - NULL, /* Label */ - QuickFormat, /* QuickFormat */ - 0, /* ClusterSize */ - FormatCallback); /* Callback */ - - DestroyProgressBar(FormatProgressBar); - FormatProgressBar = NULL; - - DPRINT("FormatPartition() finished with status 0x%08lx\n", Status); - - return Status; -} - -/* EOF */ diff --git a/base/setup/usetup/format.h b/base/setup/usetup/format.h deleted file mode 100644 index 80c5a85039c..00000000000 --- a/base/setup/usetup/format.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ReactOS kernel - * Copyright (C) 2003 ReactOS Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS text-mode setup - * FILE: base/setup/usetup/format.h - * PURPOSE: Filesystem format support functions - * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - */ - -#pragma once - -NTSTATUS -DoFormat( - IN PPARTENTRY PartEntry, - IN PCWSTR FileSystemName, - IN BOOLEAN QuickFormat); - -/* EOF */ diff --git a/base/setup/usetup/partlist.h b/base/setup/usetup/partlist.h index 02972fd8f55..df459c141d9 100644 --- a/base/setup/usetup/partlist.h +++ b/base/setup/usetup/partlist.h @@ -28,19 +28,6 @@ // #include "../lib/utils/partlist.h" -typedef enum _FORMATMACHINESTATE -{ - Start, - FormatSystemPartition, - FormatInstallPartition, - FormatOtherPartition, - FormatDone, - // CheckSystemPartition, - // CheckInstallPartition, - // CheckOtherPartition, - // CheckDone -} FORMATMACHINESTATE, *PFORMATMACHINESTATE; - typedef struct _PARTLIST_UI { PPARTLIST List; diff --git a/base/setup/usetup/usetup.c b/base/setup/usetup/usetup.c index 1d85b356ea0..3e11cda1658 100644 --- a/base/setup/usetup/usetup.c +++ b/base/setup/usetup/usetup.c @@ -29,11 +29,9 @@ #include #include -#include "bootsup.h" -#include "chkdsk.h" #include "cmdcons.h" #include "devinst.h" -#include "format.h" +#include "fmtchk.h" #define NDEBUG #include @@ -85,10 +83,6 @@ static enum { /* List of supported file systems for the partition to be formatted */ static PFILE_SYSTEM_LIST FileSystemList = NULL; -/* Machine state for the formatter */ -static PPARTENTRY TempPartition = NULL; -static FORMATMACHINESTATE FormatState = Start; - /*****************************************************/ static PNTOS_INSTALLATION CurrentInstallation = NULL; @@ -944,10 +938,6 @@ UpgradeRepairPage(PINPUT_RECORD Ir) MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER); return QUIT_PAGE; } - - /* Reset the formatter machine state */ - TempPartition = NULL; - FormatState = Start; } /**************/ @@ -1563,10 +1553,6 @@ SelectPartitionPage(PINPUT_RECORD Ir) MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER); return QUIT_PAGE; } - - /* Reset the formatter machine state */ - TempPartition = NULL; - FormatState = Start; } if (RepairUpdateFlag) @@ -1584,7 +1570,7 @@ SelectPartitionPage(PINPUT_RECORD Ir) } ASSERT(!IsContainerPartition(InstallPartition->PartitionType)); - return SELECT_FILE_SYSTEM_PAGE; + return START_PARTITION_OPERATIONS_PAGE; } MUIDisplayPage(SELECT_PARTITION_PAGE); @@ -1628,7 +1614,7 @@ SelectPartitionPage(PINPUT_RECORD Ir) } InstallPartition = CurrentPartition; - return SELECT_FILE_SYSTEM_PAGE; + return START_PARTITION_OPERATIONS_PAGE; } } else @@ -1645,7 +1631,7 @@ SelectPartitionPage(PINPUT_RECORD Ir) return SELECT_PARTITION_PAGE; /* let the user select another partition */ } - return SELECT_FILE_SYSTEM_PAGE; + return START_PARTITION_OPERATIONS_PAGE; } } @@ -1760,7 +1746,7 @@ SelectPartitionPage(PINPUT_RECORD Ir) } InstallPartition = CurrentPartition; - return SELECT_FILE_SYSTEM_PAGE; + return START_PARTITION_OPERATIONS_PAGE; } else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'C') /* C */ { @@ -2247,6 +2233,119 @@ DeletePartitionPage(PINPUT_RECORD Ir) } +/* + * Displays the SelectFileSystemPage. + * + * Next pages: + * CheckFileSystemPage (At once if RepairUpdate is selected) + * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition) + * FormatPartitionPage (Default, at once if Unattended and USetupData.FormatPartition) + * SelectPartitionPage (If the user aborts) + * QuitPage + * + * RETURNS + * Number of the next page. + */ +// PFSVOL_CALLBACK +static FSVOL_OP +CALLBACK +FsVolCallback( + _In_opt_ PVOID Context, + _In_ FSVOLNOTIFY FormatStatus, + _In_ ULONG_PTR Param1, + _In_ ULONG_PTR Param2); + +typedef struct _FSVOL_CONTEXT +{ + PINPUT_RECORD Ir; + PAGE_NUMBER NextPageOnAbort; +} FSVOL_CONTEXT, *PFSVOL_CONTEXT; + +static PAGE_NUMBER +StartPartitionOperationsPage(PINPUT_RECORD Ir) +{ + FSVOL_CONTEXT FsVolContext = {Ir, QUIT_PAGE}; + BOOLEAN Success; + + if (PartitionList == NULL || InstallPartition == NULL) + { + /* FIXME: show an error dialog */ + return QUIT_PAGE; + } + + /* Find or set the active system partition before starting formatting */ + Success = InitSystemPartition(PartitionList, + InstallPartition, + &SystemPartition, + FsVolCallback, + &FsVolContext); + if (!Success) + return FsVolContext.NextPageOnAbort; + // + // FIXME?? If cannot use any system partition, install FreeLdr on floppy / removable media?? + // + + /* Set the AUTOCREATE flag if the system partition was automatically created */ + if (SystemPartition->New) + SystemPartition->New |= PARTITION_NEW_AUTOCREATE; + + CONSOLE_ClearScreen(); + CONSOLE_Flush(); + + /* Apply all pending operations on partitions: formatting and checking */ + Success = FsVolCommitOpsQueue(PartitionList, + SystemPartition, + InstallPartition, + FsVolCallback, + &FsVolContext); + if (!Success) + return FsVolContext.NextPageOnAbort; + return BOOTLOADER_SELECT_PAGE; +} + +static BOOLEAN +ChangeSystemPartitionPage( + IN PINPUT_RECORD Ir, + IN PPARTENTRY SystemPartition) +{ + PPARTENTRY PartEntry; + PDISKENTRY DiskEntry; + CHAR LineBuffer[100]; + + // CONSOLE_ClearScreen(); + // CONSOLE_Flush(); + MUIDisplayPage(CHANGE_SYSTEM_PARTITION); + + PartEntry = PartitionList->SystemPartition; + DiskEntry = PartEntry->DiskEntry; + + PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); + CONSOLE_SetTextXY(8, 10, LineBuffer); + + DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); + CONSOLE_PrintTextXY(8, 14, MUIGetString(STRING_HDDISK1), + LineBuffer); + + + PartEntry = SystemPartition; + DiskEntry = PartEntry->DiskEntry; + + PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); + CONSOLE_SetTextXY(8, 23, LineBuffer); + + while (TRUE) + { + CONSOLE_ConInKey(Ir); + + if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ + break; + else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ + return FALSE; + } + + return TRUE; +} + static VOID ResetFileSystemList(VOID) { @@ -2257,295 +2356,26 @@ ResetFileSystemList(VOID) FileSystemList = NULL; } -/* - * Displays the SelectFileSystemPage. - * - * Next pages: - * CheckFileSystemPage (At once if RepairUpdate is selected) - * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition) - * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition) - * SelectPartitionPage (If the user aborts) - * FormatPartitionPage (Default) - * QuitPage - * - * SIDEEFFECTS - * Calls UpdatePartitionType() - * Calls FindSupportedSystemPartition() - * - * RETURNS - * Number of the next page. - */ -static PAGE_NUMBER -SelectFileSystemPage(PINPUT_RECORD Ir) +static FSVOL_OP +SelectFileSystemPage( + IN PFSVOL_CONTEXT FsVolContext, + IN PPARTENTRY PartEntry) { - PPARTENTRY PartEntry; - PDISKENTRY DiskEntry; - FORMATMACHINESTATE PreviousFormatState; + PINPUT_RECORD Ir = FsVolContext->Ir; + PDISKENTRY DiskEntry = PartEntry->DiskEntry; PCWSTR DefaultFs; CHAR LineBuffer[100]; DPRINT("SelectFileSystemPage()\n"); - if (PartitionList == NULL || InstallPartition == NULL) - { - /* FIXME: show an error dialog */ - return QUIT_PAGE; - } - - /* Find or set the active system partition when starting formatting */ - if (FormatState == Start) - { - /* - * If we install on a fixed disk, try to find a supported system - * partition on the system. Otherwise if we install on a removable disk - * use the install partition as the system partition. - */ - if (InstallPartition->DiskEntry->MediaType == FixedMedia) - { - SystemPartition = FindSupportedSystemPartition(PartitionList, - FALSE, - InstallPartition->DiskEntry, - InstallPartition); - /* Use the original system partition as the old active partition hint */ - PartEntry = PartitionList->SystemPartition; - - if ( SystemPartition && PartitionList->SystemPartition && - (SystemPartition != PartitionList->SystemPartition) ) - { - DPRINT1("We are using a different system partition!!!!\n"); - - MUIDisplayPage(CHANGE_SYSTEM_PARTITION); - - { - PPARTENTRY PartEntry; // Shadow variable - - PartEntry = PartitionList->SystemPartition; - DiskEntry = PartEntry->DiskEntry; - - PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); - CONSOLE_SetTextXY(8, 10, LineBuffer); - - DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); - CONSOLE_PrintTextXY(8, 14, MUIGetString(STRING_HDDISK1), - LineBuffer); - - - PartEntry = SystemPartition; - DiskEntry = PartEntry->DiskEntry; - - PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); - CONSOLE_SetTextXY(8, 23, LineBuffer); - } - - while (TRUE) - { - CONSOLE_ConInKey(Ir); - - if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ - { - break; - } - else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ - { - return SELECT_PARTITION_PAGE; - } - } - - CONSOLE_ClearScreen(); - CONSOLE_Flush(); - } - } - else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia) - { - SystemPartition = InstallPartition; - /* Don't specify any old active partition hint */ - PartEntry = NULL; - } - - if (!SystemPartition) - { - /* FIXME: improve the error dialog */ - // - // Error dialog should say that we cannot find a suitable - // system partition and create one on the system. At this point, - // it may be nice to ask the user whether he wants to continue, - // or use an external drive as the system drive/partition - // (e.g. floppy, USB drive, etc...) - // - PopupError("The ReactOS Setup could not find a supported system partition\n" - "on your system or could not create a new one. Without such partition\n" - "the Setup program cannot install ReactOS.\n" - "Press ENTER to return to the partition selection list.", - MUIGetString(STRING_CONTINUE), - Ir, POPUP_WAIT_ENTER); - return SELECT_PARTITION_PAGE; - } - - /* - * If the system partition can be created in some - * non-partitioned space, create it now. - */ - if (!SystemPartition->IsPartitioned) - { - /* Automatically create the partition; it will be - * formatted later with default parameters */ - // FIXME: Don't use the whole empty space, but a minimal size - // specified from the TXTSETUP.SIF or unattended setup. - CreatePartition(PartitionList, - SystemPartition, - 0ULL, - 0); - SystemPartition->New |= PARTITION_NEW_AUTOCREATE; - ASSERT(SystemPartition->IsPartitioned); - } - - /* Set it as such */ - if (!SetActivePartition(PartitionList, SystemPartition, PartEntry)) - { - DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition); - ASSERT(FALSE); - } - - /* Commit all partition changes to all the disks */ - if (!WritePartitionsToDisk(PartitionList)) - { - DPRINT("WritePartitionsToDisk() failed\n"); - MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); - return QUIT_PAGE; - } - - /* - * In all cases, whether or not we are going to perform a formatting, - * we must perform a filesystem check of both the system and the - * installation partitions. - */ - InstallPartition->NeedsCheck = TRUE; - if (SystemPartition != InstallPartition) - SystemPartition->NeedsCheck = TRUE; - - /* - * In case we just repair an existing installation, or make - * an unattended setup without formatting, just go to the - * filesystem check step. - */ - if (RepairUpdateFlag) - return CHECK_FILE_SYSTEM_PAGE; - - if (IsUnattendedSetup && !USetupData.FormatPartition) - return CHECK_FILE_SYSTEM_PAGE; - } - - // ASSERT(SystemPartition->IsPartitioned); - - /* Reset the filesystem list for each partition that is to be formatted */ - ResetFileSystemList(); - - PreviousFormatState = FormatState; - switch (FormatState) - { - case Start: - { - /* - * We start by formatting the system partition in case it is new - * (it didn't exist before) and is not the same as the installation - * partition. Otherwise we just require a filesystem check on it, - * and start by formatting the installation partition instead. - */ - - ASSERT(SystemPartition->IsPartitioned); - - if ((SystemPartition != InstallPartition) && - (SystemPartition->FormatState == Unformatted)) - { - TempPartition = SystemPartition; - TempPartition->NeedsCheck = TRUE; - - // TODO: Should we let the user using a custom file-system, - // or should we always use FAT(32) for it? - // For "compatibility", FAT(32) would be best indeed. - - FormatState = FormatSystemPartition; - DPRINT1("FormatState: Start --> FormatSystemPartition\n"); - } - else - { - TempPartition = InstallPartition; - TempPartition->NeedsCheck = TRUE; - - if (SystemPartition != InstallPartition) - { - /* The system partition is separate, so it had better be formatted! */ - ASSERT((SystemPartition->FormatState == Preformatted) || - (SystemPartition->FormatState == Formatted)); - - /* Require a filesystem check on the system partition too */ - SystemPartition->NeedsCheck = TRUE; - } - - FormatState = FormatInstallPartition; - DPRINT1("FormatState: Start --> FormatInstallPartition\n"); - } - break; - } - - case FormatSystemPartition: - { - TempPartition = InstallPartition; - TempPartition->NeedsCheck = TRUE; - - FormatState = FormatInstallPartition; - DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n"); - break; - } - - case FormatInstallPartition: - case FormatOtherPartition: - { - if (GetNextUnformattedPartition(PartitionList, - NULL, - &TempPartition)) - { - FormatState = FormatOtherPartition; - TempPartition->NeedsCheck = TRUE; - - if (FormatState == FormatInstallPartition) - DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n"); - else - DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n"); - } - else - { - FormatState = FormatDone; - - if (FormatState == FormatInstallPartition) - DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n"); - else - DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n"); - - return CHECK_FILE_SYSTEM_PAGE; - } - break; - } - - case FormatDone: - { - DPRINT1("FormatState: FormatDone\n"); - return CHECK_FILE_SYSTEM_PAGE; - } - - default: - { - DPRINT1("FormatState: Invalid value %ld\n", FormatState); - ASSERT(FALSE); - return QUIT_PAGE; - } - } - - PartEntry = TempPartition; - DiskEntry = TempPartition->DiskEntry; - ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); +Restart: + /* Reset the file system list for each partition that is to be formatted */ + ResetFileSystemList(); + + CONSOLE_ClearScreen(); + CONSOLE_Flush(); MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE); if (PartEntry->New & PARTITION_NEW_AUTOCREATE) @@ -2556,24 +2386,16 @@ SelectFileSystemPage(PINPUT_RECORD Ir) } else if (PartEntry->New) { - switch (FormatState) - { - case FormatSystemPartition: - CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART)); - break; + ULONG uID; - case FormatInstallPartition: - CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART)); - break; + if (PartEntry == SystemPartition) // FormatSystemPartition + uID = STRING_NONFORMATTEDSYSTEMPART; + else if (PartEntry == InstallPartition) // FormatInstallPartition + uID = STRING_NONFORMATTEDPART; + else // FormatOtherPartition + uID = STRING_NONFORMATTEDOTHERPART; - case FormatOtherPartition: - CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART)); - break; - - default: - ASSERT(FALSE); - break; - } + CONSOLE_SetTextXY(6, 8, MUIGetString(uID)); } else { @@ -2591,7 +2413,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir) if (PartEntry->New || PartEntry->FormatState == Unformatted) CONSOLE_SetTextXY(6, 14, MUIGetString(STRING_PARTFORMAT)); - ASSERT(FileSystemList == NULL); + ASSERT(!FileSystemList); if (IsUnattendedSetup) { @@ -2622,16 +2444,17 @@ SelectFileSystemPage(PINPUT_RECORD Ir) PartEntry->New || PartEntry->FormatState == Unformatted, DefaultFs); - if (FileSystemList == NULL) + if (!FileSystemList) { /* FIXME: show an error dialog */ - return QUIT_PAGE; + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; } if (IsUnattendedSetup) { ASSERT(USetupData.FormatPartition); - return FORMAT_PARTITION_PAGE; + return FSVOL_DOIT; } DrawFileSystemList(FileSystemList); @@ -2645,23 +2468,16 @@ SelectFileSystemPage(PINPUT_RECORD Ir) { if (ConfirmQuit(Ir)) { - /* Reset the filesystem list */ - ResetFileSystemList(); - return QUIT_PAGE; + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; } break; } else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ { - /* Reset the formatter machine state */ - TempPartition = NULL; - FormatState = Start; - - /* Reset the filesystem list */ - ResetFileSystemList(); - - return SELECT_PARTITION_PAGE; + FsVolContext->NextPageOnAbort = SELECT_PARTITION_PAGE; + return FSVOL_ABORT; } else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ @@ -2677,84 +2493,51 @@ SelectFileSystemPage(PINPUT_RECORD Ir) { if (!FileSystemList->Selected->FileSystem) { - ASSERT(!TempPartition->New && TempPartition->FormatState != Unformatted); + ASSERT(!PartEntry->New && PartEntry->FormatState != Unformatted); /* * Skip formatting this partition. We will also ignore - * filesystem checks on it, unless it is either the system - * or the installation partition. + * file system checks on it, unless it is either the + * system or the installation partition. */ - if (TempPartition != SystemPartition && - TempPartition != InstallPartition) + if (PartEntry != SystemPartition && + PartEntry != InstallPartition) { PartEntry->NeedsCheck = FALSE; } - - return SELECT_FILE_SYSTEM_PAGE; + return FSVOL_SKIP; } else { /* Format this partition */ - return FORMAT_PARTITION_PAGE; + return FSVOL_DOIT; } } } - FormatState = PreviousFormatState; - - return SELECT_FILE_SYSTEM_PAGE; + goto Restart; } - -/* - * Displays the FormatPartitionPage. - * - * Next pages: - * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut) - * SelectPartitionPage (At once) - * QuitPage - * - * SIDEEFFECTS - * Sets InstallPartition->FormatState - * Sets USetupData.DestinationRootPath - * - * RETURNS - * Number of the next page. - */ -static PAGE_NUMBER -FormatPartitionPage(PINPUT_RECORD Ir) +static FSVOL_OP +FormatPartitionPage( + IN PFSVOL_CONTEXT FsVolContext, + IN PPARTENTRY PartEntry) { - NTSTATUS Status; - PPARTENTRY PartEntry; - PDISKENTRY DiskEntry; - PFILE_SYSTEM_ITEM SelectedFileSystem; - WCHAR PathBuffer[MAX_PATH]; - CHAR Buffer[MAX_PATH]; - - DPRINT("FormatPartitionPage()\n"); - - if (PartitionList == NULL || TempPartition == NULL) - { - /* FIXME: show an error dialog */ - return QUIT_PAGE; - } - - PartEntry = TempPartition; - DiskEntry = TempPartition->DiskEntry; - - ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); - - SelectedFileSystem = FileSystemList->Selected; - ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem); + PINPUT_RECORD Ir = FsVolContext->Ir; + PDISKENTRY DiskEntry = PartEntry->DiskEntry; + CHAR LineBuffer[100]; +Restart: + CONSOLE_ClearScreen(); + CONSOLE_Flush(); MUIDisplayPage(FORMAT_PARTITION_PAGE); - PartitionDescription(PartEntry, Buffer, ARRAYSIZE(Buffer)); - CONSOLE_SetTextXY(6, 10, Buffer); + PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); + CONSOLE_SetTextXY(6, 10, LineBuffer); - DiskDescription(DiskEntry, Buffer, ARRAYSIZE(Buffer)); + DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDDISK2), - Buffer); + LineBuffer); while (TRUE) { @@ -2766,12 +2549,11 @@ FormatPartitionPage(PINPUT_RECORD Ir) { if (ConfirmQuit(Ir)) { - /* Reset the filesystem list */ - ResetFileSystemList(); - return QUIT_PAGE; + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; } - break; + goto Restart; } else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */ { @@ -2782,190 +2564,305 @@ FormatPartitionPage(PINPUT_RECORD Ir) MUIClearStyledText(FORMAT_PARTITION_PAGE, TEXT_ID_FORMAT_PROMPT, TEXT_TYPE_REGULAR); CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); - /* Format the partition */ - Status = DoFormat(PartEntry, - SelectedFileSystem->FileSystem, - SelectedFileSystem->QuickFormat); - if (Status == STATUS_PARTITION_FAILURE) - { - MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); - - /* Reset the filesystem list */ - ResetFileSystemList(); - return QUIT_PAGE; - } - else if (Status == STATUS_UNRECOGNIZED_VOLUME) - { - /* FIXME: show an error dialog */ - // MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); - - /* Reset the filesystem list */ - ResetFileSystemList(); - return QUIT_PAGE; - } - else if (Status == STATUS_NOT_SUPPORTED) - { - RtlStringCbPrintfA(Buffer, - sizeof(Buffer), - "Setup is currently unable to format a partition in %S.\n" - "\n" - " \x07 Press ENTER to continue Setup.\n" - " \x07 Press F3 to quit Setup.", - SelectedFileSystem->FileSystem); - - PopupError(Buffer, - MUIGetString(STRING_QUITCONTINUE), - NULL, POPUP_WAIT_NONE); - - while (TRUE) - { - CONSOLE_ConInKey(Ir); - - if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && - Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ - { - if (ConfirmQuit(Ir)) - { - /* Reset the filesystem list */ - ResetFileSystemList(); - return QUIT_PAGE; - } - else - { - return SELECT_FILE_SYSTEM_PAGE; - } - } - else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ - { - return SELECT_FILE_SYSTEM_PAGE; - } - } - } - else if (!NT_SUCCESS(Status)) - { - /** HACK!! **/ - RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), - L"\\Device\\Harddisk%lu\\Partition%lu", - DiskEntry->DiskNumber, - PartEntry->PartitionNumber); - - DPRINT1("DoFormat() failed: Status 0x%08lx\n", Status); - MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); - - /* Reset the filesystem list */ - ResetFileSystemList(); - return QUIT_PAGE; - } - - return SELECT_FILE_SYSTEM_PAGE; + return FSVOL_DOIT; } } - - return FORMAT_PARTITION_PAGE; } - -/* - * Displays the CheckFileSystemPage. - * - * Next pages: - * InstallDirectoryPage (At once) - * QuitPage - * - * SIDEEFFECTS - * Inits or reloads FileSystemList - * - * RETURNS - * Number of the next page. - */ -static PAGE_NUMBER -CheckFileSystemPage(PINPUT_RECORD Ir) +static VOID +CheckFileSystemPage( + IN PPARTENTRY PartEntry) { - NTSTATUS Status; - PPARTENTRY PartEntry; - CHAR Buffer[MAX_PATH]; - - if (PartitionList == NULL) - { - /* FIXME: show an error dialog */ - return QUIT_PAGE; - } - - if (!GetNextUncheckedPartition(PartitionList, NULL, &PartEntry)) - { - return BOOTLOADER_SELECT_PAGE; - } - - ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); - - DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n", - PartEntry->PartitionType, (*PartEntry->FileSystem ? PartEntry->FileSystem : L"n/a")); + PDISKENTRY DiskEntry = PartEntry->DiskEntry; + CHAR LineBuffer[100]; + CONSOLE_ClearScreen(); + CONSOLE_Flush(); MUIDisplayPage(CHECK_FILE_SYSTEM_PAGE); - PartitionDescription(PartEntry, Buffer, ARRAYSIZE(Buffer)); - CONSOLE_SetTextXY(6, 10, Buffer); + PartitionDescription(PartEntry, LineBuffer, ARRAYSIZE(LineBuffer)); + CONSOLE_SetTextXY(6, 10, LineBuffer); - DiskDescription(PartEntry->DiskEntry, Buffer, ARRAYSIZE(Buffer)); + DiskDescription(DiskEntry, LineBuffer, ARRAYSIZE(LineBuffer)); CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDDISK2), - Buffer); + LineBuffer); +} - /* Check the partition */ - Status = DoChkdsk(PartEntry); - if (Status == STATUS_NOT_SUPPORTED) +// PFSVOL_CALLBACK +static FSVOL_OP +CALLBACK +FsVolCallback( + _In_opt_ PVOID Context, + _In_ FSVOLNOTIFY FormatStatus, + _In_ ULONG_PTR Param1, + _In_ ULONG_PTR Param2) +{ + PFSVOL_CONTEXT FsVolContext = (PFSVOL_CONTEXT)Context; + PINPUT_RECORD Ir = FsVolContext->Ir; + + switch (FormatStatus) { - /* - * Partition checking is not supported with the current filesystem, - * so disable FS checks on it. - */ - PartEntry->NeedsCheck = FALSE; + // FIXME: Deprecate! + case ChangeSystemPartition: + { + PPARTENTRY SystemPartition = (PPARTENTRY)Param1; - RtlStringCbPrintfA(Buffer, - sizeof(Buffer), - "Setup is currently unable to check a partition formatted in %S.\n" - "\n" - " \x07 Press ENTER to continue Setup.\n" - " \x07 Press F3 to quit Setup.", - PartEntry->FileSystem); + FsVolContext->NextPageOnAbort = SELECT_PARTITION_PAGE; + if (ChangeSystemPartitionPage(Ir, SystemPartition)) + return FSVOL_DOIT; + return FSVOL_ABORT; + } - PopupError(Buffer, - MUIGetString(STRING_QUITCONTINUE), - NULL, POPUP_WAIT_NONE); - - while (TRUE) + case FSVOLNOTIFY_PARTITIONERROR: + { + switch (Param1) { - CONSOLE_ConInKey(Ir); + case STATUS_PARTITION_FAILURE: + { + MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); + FsVolContext->NextPageOnAbort = QUIT_PAGE; + break; + } - if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && - Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ + case ERROR_SYSTEM_PARTITION_NOT_FOUND: + { + /* FIXME: improve the error dialog */ + // + // Error dialog should say that we cannot find a suitable + // system partition and create one on the system. At this point, + // it may be nice to ask the user whether he wants to continue, + // or use an external drive as the system drive/partition + // (e.g. floppy, USB drive, etc...) + // + PopupError("The ReactOS Setup could not find a supported system partition\n" + "on your system or could not create a new one. Without such partition\n" + "the Setup program cannot install ReactOS.\n" + "Press ENTER to return to the partition selection list.", + MUIGetString(STRING_CONTINUE), + Ir, POPUP_WAIT_ENTER); + + FsVolContext->NextPageOnAbort = SELECT_PARTITION_PAGE; + break; + } + + default: + break; + } + return FSVOL_ABORT; + } + + case FSVOLNOTIFY_STARTQUEUE: + case FSVOLNOTIFY_ENDQUEUE: + // NOTE: If needed, clear screen and flush input. + return FSVOL_DOIT; + + case FSVOLNOTIFY_STARTSUBQUEUE: + { + if ((FSVOL_OP)Param1 == FSVOL_FORMAT) + { + /* + * In case we just repair an existing installation, or make + * an unattended setup without formatting, just go to the + * file system check step. + */ + if (RepairUpdateFlag) + return FSVOL_SKIP; /** HACK!! **/ + + if (IsUnattendedSetup && !USetupData.FormatPartition) + return FSVOL_SKIP; /** HACK!! **/ + } + return FSVOL_DOIT; + } + + case FSVOLNOTIFY_ENDSUBQUEUE: + return 0; + + case FSVOLNOTIFY_FORMATERROR: + { + PFORMAT_VOLUME_INFO FmtInfo = (PFORMAT_VOLUME_INFO)Param1; + CHAR Buffer[MAX_PATH]; + + // FIXME: See also FSVOLNOTIFY_PARTITIONERROR + if (FmtInfo->ErrorStatus == STATUS_PARTITION_FAILURE) + { + MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; + } + else + if (FmtInfo->ErrorStatus == STATUS_UNRECOGNIZED_VOLUME) + { + /* FIXME: show an error dialog */ + // MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; + } + else + if (FmtInfo->ErrorStatus == STATUS_NOT_SUPPORTED) + { + RtlStringCbPrintfA(Buffer, + sizeof(Buffer), + "Setup is currently unable to format a partition in %S.\n" + "\n" + " \x07 Press ENTER to continue Setup.\n" + " \x07 Press F3 to quit Setup.", + FmtInfo->FileSystemName); + + PopupError(Buffer, + MUIGetString(STRING_QUITCONTINUE), + NULL, POPUP_WAIT_NONE); + + while (TRUE) { - if (ConfirmQuit(Ir)) - return QUIT_PAGE; - else - return CHECK_FILE_SYSTEM_PAGE; - } - else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ - { - return CHECK_FILE_SYSTEM_PAGE; + CONSOLE_ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && + Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ + { + if (ConfirmQuit(Ir)) + { + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; + } + else + { + return FSVOL_RETRY; + } + } + else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ + { + return FSVOL_RETRY; + } } } + else if (!NT_SUCCESS(FmtInfo->ErrorStatus)) + { + WCHAR PathBuffer[MAX_PATH]; + + /** HACK!! **/ + RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), + L"\\Device\\Harddisk%lu\\Partition%lu", + FmtInfo->PartEntry->DiskEntry->DiskNumber, + FmtInfo->PartEntry->PartitionNumber); + + DPRINT1("FormatPartition() failed: Status 0x%08lx\n", FmtInfo->ErrorStatus); + MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; + } + return FSVOL_RETRY; } - else if (!NT_SUCCESS(Status)) + + case FSVOLNOTIFY_CHECKERROR: { - DPRINT1("DoChkdsk() failed: Status 0x%08lx\n", Status); + PCHECK_VOLUME_INFO ChkInfo = (PCHECK_VOLUME_INFO)Param1; + CHAR Buffer[MAX_PATH]; - RtlStringCbPrintfA(Buffer, - sizeof(Buffer), - "ChkDsk detected some disk errors.\n(Status 0x%08lx).\n", - Status); + if (ChkInfo->ErrorStatus == STATUS_NOT_SUPPORTED) + { + RtlStringCbPrintfA(Buffer, + sizeof(Buffer), + "Setup is currently unable to check a partition formatted in %S.\n" + "\n" + " \x07 Press ENTER to continue Setup.\n" + " \x07 Press F3 to quit Setup.", + ChkInfo->PartEntry->FileSystem); - PopupError(Buffer, - MUIGetString(STRING_CONTINUE), - Ir, POPUP_WAIT_ENTER); + PopupError(Buffer, + MUIGetString(STRING_QUITCONTINUE), + NULL, POPUP_WAIT_NONE); + + while (TRUE) + { + CONSOLE_ConInKey(Ir); + + if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && + Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ + { + if (ConfirmQuit(Ir)) + { + FsVolContext->NextPageOnAbort = QUIT_PAGE; + return FSVOL_ABORT; + } + else + { + return FSVOL_SKIP; + } + } + else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ + { + return FSVOL_SKIP; + } + } + } + else if (!NT_SUCCESS(ChkInfo->ErrorStatus)) + { + DPRINT1("ChkdskPartition() failed: Status 0x%08lx\n", ChkInfo->ErrorStatus); + + RtlStringCbPrintfA(Buffer, + sizeof(Buffer), + "ChkDsk detected some disk errors.\n(Status 0x%08lx).\n", + ChkInfo->ErrorStatus); + + PopupError(Buffer, + MUIGetString(STRING_CONTINUE), + Ir, POPUP_WAIT_ENTER); + return FSVOL_SKIP; + } + return FSVOL_SKIP; } - PartEntry->NeedsCheck = FALSE; - return CHECK_FILE_SYSTEM_PAGE; + case FSVOLNOTIFY_STARTFORMAT: + { + PFORMAT_VOLUME_INFO FmtInfo = (PFORMAT_VOLUME_INFO)Param1; + FSVOL_OP Result; + + ASSERT((FSVOL_OP)Param2 == FSVOL_FORMAT); + + /* Select the file system */ + Result = SelectFileSystemPage(FsVolContext, FmtInfo->PartEntry); + if (Result != FSVOL_DOIT) + return Result; + + /* Display the formatting page */ + Result = FormatPartitionPage(FsVolContext, FmtInfo->PartEntry); + if (Result != FSVOL_DOIT) + return Result; + + StartFormat(FmtInfo, FileSystemList->Selected); + return FSVOL_DOIT; + } + + case FSVOLNOTIFY_ENDFORMAT: + { + PFORMAT_VOLUME_INFO FmtInfo = (PFORMAT_VOLUME_INFO)Param1; + EndFormat(FmtInfo->ErrorStatus); + + /* Reset the file system list */ + ResetFileSystemList(); + return 0; + } + + case FSVOLNOTIFY_STARTCHECK: + { + PCHECK_VOLUME_INFO ChkInfo = (PCHECK_VOLUME_INFO)Param1; + + ASSERT((FSVOL_OP)Param2 == FSVOL_CHECK); + + CheckFileSystemPage(ChkInfo->PartEntry); + StartCheck(ChkInfo); + return FSVOL_DOIT; + } + + case FSVOLNOTIFY_ENDCHECK: + { + PCHECK_VOLUME_INFO ChkInfo = (PCHECK_VOLUME_INFO)Param1; + EndCheck(ChkInfo->ErrorStatus); + return 0; + } + } + + return 0; } @@ -3033,9 +2930,6 @@ InstallDirectoryPage(PINPUT_RECORD Ir) WCHAR c; WCHAR InstallDir[MAX_PATH]; - /* We do not need the filesystem list anymore */ - ResetFileSystemList(); - if (PartitionList == NULL || InstallPartition == NULL) { /* FIXME: show an error dialog */ @@ -3627,6 +3521,7 @@ BootLoaderSelectPage(PINPUT_RECORD Ir) } } +#if 0 // Deprecated code, whose global logic may need to be moved elsewhere... /* * We may install an MBR or VBR, but before that, check whether * we need to actually install the VBR on removable disk if the @@ -3638,6 +3533,7 @@ BootLoaderSelectPage(PINPUT_RECORD Ir) USetupData.MBRInstallType = 1; goto Quit; } +#endif /* Is it an unattended install on hdd? */ if (IsUnattendedSetup) @@ -4128,13 +4024,6 @@ QuitPage(PINPUT_RECORD Ir) PartitionList = NULL; } - /* Reset the formatter machine state */ - TempPartition = NULL; - FormatState = Start; - - /* Destroy the filesystem list */ - ResetFileSystemList(); - CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2)); /* Wait for maximum 15 seconds or an ENTER key before quitting */ @@ -4310,17 +4199,9 @@ RunUSetup(VOID) Page = DeletePartitionPage(&Ir); break; - /* Filesystem partition operations pages */ - case SELECT_FILE_SYSTEM_PAGE: - Page = SelectFileSystemPage(&Ir); - break; - - case FORMAT_PARTITION_PAGE: - Page = FormatPartitionPage(&Ir); - break; - - case CHECK_FILE_SYSTEM_PAGE: - Page = CheckFileSystemPage(&Ir); + /* File system partition operations pages */ + case START_PARTITION_OPERATIONS_PAGE: + Page = StartPartitionOperationsPage(&Ir); break; /* Bootloader selection page */ @@ -4374,6 +4255,9 @@ RunUSetup(VOID) /* Virtual pages */ case SETUP_INIT_PAGE: + case SELECT_FILE_SYSTEM_PAGE: + case FORMAT_PARTITION_PAGE: + // case CHECK_FILE_SYSTEM_PAGE: case REBOOT_PAGE: case RECOVERY_PAGE: break; diff --git a/base/setup/usetup/usetup.h b/base/setup/usetup/usetup.h index 54f3ba771e3..91b94ac9699 100644 --- a/base/setup/usetup/usetup.h +++ b/base/setup/usetup/usetup.h @@ -99,8 +99,9 @@ typedef enum _PAGE_NUMBER CONFIRM_DELETE_SYSTEM_PARTITION_PAGE, DELETE_PARTITION_PAGE, - SELECT_FILE_SYSTEM_PAGE, - FORMAT_PARTITION_PAGE, + START_PARTITION_OPERATIONS_PAGE, /* Virtual page */ + SELECT_FILE_SYSTEM_PAGE, /* Virtual page */ + FORMAT_PARTITION_PAGE, /* Virtual page */ CHECK_FILE_SYSTEM_PAGE, BOOTLOADER_SELECT_PAGE,