mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3131 lines
90 KiB
3131 lines
90 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Spntfix.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code to repair winnt installations.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) 27-Jan-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Path to the ntuser.dat hive
|
|
//
|
|
#define DEFAULT_USER_PATH L"Users\\Default User"
|
|
|
|
|
|
//
|
|
// Global variables control which repair options should be performed.
|
|
// Initialized to ALL options. We explicitly use 1 and 0 for true and false.
|
|
//
|
|
|
|
#ifdef _X86_
|
|
ULONG RepairItems[RepairItemMax] = { 0, 0, 0}; // BCL - Seagate - removed one.
|
|
#else
|
|
ULONG RepairItems[RepairItemMax] = { 0, 0}; // BCL
|
|
#endif
|
|
|
|
PVOID RepairGauge = NULL;
|
|
|
|
//
|
|
// global variables for delayed driver CAB opening during
|
|
// repair
|
|
//
|
|
extern PWSTR gszDrvInfDeviceName;
|
|
extern PWSTR gszDrvInfDirName;
|
|
extern HANDLE ghSif;
|
|
|
|
|
|
#define ATTR_RHS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
|
|
|
|
//**************************************************************
|
|
// S E L E C T I N G N T T O REPAIR S T U F F
|
|
//**************************************************************
|
|
|
|
#define MENU_LEFT_X 3
|
|
#define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
|
|
#define LIST_BOX_WIDTH 50
|
|
#define LIST_BOX_HEIGHT RepairItemMax+1
|
|
#define HIVE_LIST_BOX_WIDTH 45
|
|
#define HIVE_LIST_BOX_HEIGHT RepairHiveMax+1
|
|
#define MENU_INDENT 4
|
|
|
|
VOID
|
|
SppGetRepairPathInformation(
|
|
IN PVOID LogFileHandle,
|
|
OUT PWSTR *SystemPartition,
|
|
OUT PWSTR *SystemPartitionDirectory,
|
|
OUT PWSTR *WinntPartition,
|
|
OUT PWSTR *WinntPartitionDirectory
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This goes through the list of NTs on the system and finds out which are
|
|
repairable. Presents the information to the user.
|
|
|
|
|
|
Arguments:
|
|
|
|
SifHandle - Handle the txtsetup.sif
|
|
|
|
SystemPartition - Supplies a variable to receive the name of System
|
|
partition.
|
|
|
|
SystemPartitionDirectory - Supplies a variable to receive the name of
|
|
the osloader directory on the system partition.
|
|
|
|
WinntPartition - Supplies a variable to receive the name of winnt
|
|
partition.
|
|
|
|
WinntPartitionDirectory - Supplies a variable to receive the winnt
|
|
directory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR KeyName = NULL;
|
|
|
|
*SystemPartition = SpGetSectionKeyIndex (LogFileHandle,
|
|
SIF_NEW_REPAIR_PATHS,
|
|
SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE,
|
|
0);
|
|
if (*SystemPartition == NULL) {
|
|
KeyName = SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE;
|
|
goto ReportError;
|
|
}
|
|
*SystemPartitionDirectory = SpGetSectionKeyIndex (LogFileHandle,
|
|
SIF_NEW_REPAIR_PATHS,
|
|
SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DIRECTORY,
|
|
0);
|
|
if (*SystemPartitionDirectory == NULL) {
|
|
KeyName = SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DIRECTORY;
|
|
goto ReportError;
|
|
}
|
|
|
|
*WinntPartition = SpGetSectionKeyIndex ( LogFileHandle,
|
|
SIF_NEW_REPAIR_PATHS,
|
|
SIF_NEW_REPAIR_PATHS_TARGET_DEVICE,
|
|
0);
|
|
|
|
if (*WinntPartition == NULL) {
|
|
KeyName = SIF_NEW_REPAIR_PATHS_TARGET_DEVICE;
|
|
goto ReportError;
|
|
}
|
|
*WinntPartitionDirectory = SpGetSectionKeyIndex (LogFileHandle,
|
|
SIF_NEW_REPAIR_PATHS,
|
|
SIF_NEW_REPAIR_PATHS_TARGET_DIRECTORY,
|
|
0);
|
|
|
|
if (*WinntPartitionDirectory == NULL) {
|
|
KeyName = SIF_NEW_REPAIR_PATHS_TARGET_DIRECTORY;
|
|
goto ReportError;
|
|
}
|
|
ReportError:
|
|
|
|
if (KeyName) {
|
|
|
|
//
|
|
// Unable to find path information. This indicates the setup.log
|
|
// is bad. Inform user and exit.
|
|
//
|
|
|
|
SpFatalSifError(LogFileHandle,SIF_NEW_REPAIR_PATHS,KeyName,0,0);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
SpFindNtToRepair(
|
|
IN PVOID SifHandle,
|
|
OUT PDISK_REGION *TargetRegion,
|
|
OUT PWSTR *TargetPath,
|
|
OUT PDISK_REGION *SystemPartitionRegion,
|
|
OUT PWSTR *SystemPartitionDirectory,
|
|
OUT PBOOLEAN RepairableBootSetsFound
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This goes through the list of NTs on the system and finds out which are
|
|
repairable. Presents the information to the user.
|
|
|
|
|
|
Arguments:
|
|
|
|
SifHandle: Handle the txtsetup.sif
|
|
|
|
TargetRegion: Variable to receive the partition of the Windows NT to install
|
|
NULL if not chosen.
|
|
|
|
TargetPath: Variable to receive the target path of Windows NT. NULL if
|
|
not decided.
|
|
|
|
SystemPartitionRegion:
|
|
Variable to receive the system partition of the Windows NT
|
|
|
|
SystemPartitionDirectory:
|
|
Variable to receive the osloader directory of the system
|
|
partition.
|
|
|
|
RepairableBootSetsFound:
|
|
Indicates whether a repairable boot set was found. This
|
|
information can be used by the caller when the function
|
|
returns FALSE, so that the caller can determine if no
|
|
repairable disk was found, or if the user didn't select
|
|
any of the repairable systems found.
|
|
|
|
Return Value:
|
|
|
|
A boolean value to indicate if selection has been made.
|
|
|
|
--*/
|
|
{
|
|
NT_PRODUCT_TYPE ProductType;
|
|
BOOLEAN GoRepair = FALSE;
|
|
NTSTATUS NtStatus;
|
|
|
|
ULONG j, RepairBootSets = 0, MajorVersion, MinorVersion, BuildNumber, ProductSuiteMask;
|
|
PSP_BOOT_ENTRY BootEntry;
|
|
PSP_BOOT_ENTRY ChosenBootEntry;
|
|
LCID LangId;
|
|
|
|
UPG_PROGRESS_TYPE UpgradeProgressValue;
|
|
|
|
//
|
|
// Find all upgradeable boot entries. These are entries that are unique in
|
|
// the boot entry list and are present on disk.
|
|
//
|
|
|
|
SpDetermineUniqueAndPresentBootEntries();
|
|
|
|
for ( BootEntry = SpBootEntries; BootEntry != NULL ; BootEntry = BootEntry->Next ) {
|
|
|
|
if (!BootEntry->Processable) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Reinitialize
|
|
//
|
|
|
|
BootEntry->Processable = FALSE;
|
|
LangId = -1;
|
|
|
|
//
|
|
// try loading the registry and getting the following information
|
|
// out of it:
|
|
//
|
|
// 1) Product type: WINNT | LANMANNT
|
|
// 2) Major and Minor Version Number
|
|
//
|
|
// Based on the information, we will update the RepairableList.
|
|
//
|
|
|
|
NtStatus = SpDetermineProduct(
|
|
BootEntry->OsPartitionDiskRegion,
|
|
BootEntry->OsDirectory,
|
|
&ProductType,
|
|
&MajorVersion,
|
|
&MinorVersion,
|
|
&BuildNumber,
|
|
&ProductSuiteMask,
|
|
&UpgradeProgressValue,
|
|
NULL,
|
|
NULL, // Pid is not needed
|
|
NULL, // ignore eval variation flag
|
|
&LangId, // Language Id
|
|
NULL // service pack not needed?
|
|
);
|
|
|
|
if(NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// make sure we only try to repair a build that matches the CD we have inserted
|
|
//
|
|
BootEntry->Processable = SpDoBuildsMatch(
|
|
SifHandle,
|
|
BuildNumber,
|
|
ProductType,
|
|
ProductSuiteMask,
|
|
AdvancedServer,
|
|
SuiteType,
|
|
LangId
|
|
);
|
|
if( BootEntry->Processable ) {
|
|
RepairBootSets++;
|
|
ChosenBootEntry = BootEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find out how many valid boot sets there are which we can repair
|
|
//
|
|
|
|
*RepairableBootSetsFound = (RepairBootSets != 0);
|
|
|
|
if ( RepairBootSets == 1 ) {
|
|
|
|
//
|
|
// If it is a fresh attempt at upgrade ask the user if he
|
|
// wants to upgrade or not
|
|
//
|
|
|
|
GoRepair = SppSelectNTSingleRepair(
|
|
ChosenBootEntry->OsPartitionDiskRegion,
|
|
ChosenBootEntry->OsDirectory,
|
|
ChosenBootEntry->FriendlyName
|
|
);
|
|
|
|
} else if (RepairBootSets > 1) {
|
|
|
|
//
|
|
// Find out if the user wants to upgrade one of the Windows
|
|
// NT found
|
|
//
|
|
|
|
GoRepair = SppSelectNTMultiRepair(
|
|
&ChosenBootEntry
|
|
);
|
|
}
|
|
|
|
//
|
|
// Depending on upgrade selection made do the setup needed before
|
|
// we do the upgrade
|
|
//
|
|
|
|
if (GoRepair) {
|
|
|
|
PWSTR p1,p2,p3;
|
|
ULONG u;
|
|
|
|
//
|
|
// Return the region we are goint to repair
|
|
//
|
|
|
|
*TargetRegion = ChosenBootEntry->OsPartitionDiskRegion;
|
|
*TargetPath = SpDupStringW(ChosenBootEntry->OsDirectory);
|
|
*SystemPartitionRegion = ChosenBootEntry->LoaderPartitionDiskRegion;
|
|
|
|
//
|
|
// Process the osloader variable to extract the system partition path.
|
|
// The var vould be of the form ...partition(1)\os\nt\... or
|
|
// ...partition(1)os\nt\...
|
|
// So we search forward for the first \ and then backwards for
|
|
// the closest ) to find the start of the directory. We then
|
|
// search backwards in the resulting string for the last \ to find
|
|
// the end of the directory.
|
|
//
|
|
p1 = ChosenBootEntry->LoaderFile;
|
|
p2 = wcsrchr(p1, L'\\');
|
|
if (p2 == NULL) {
|
|
p2 = p1;
|
|
}
|
|
u = (ULONG)(p2 - p1);
|
|
|
|
if(u == 0) {
|
|
*SystemPartitionDirectory = SpDupStringW(L"");
|
|
} else {
|
|
p2 = p3 = SpMemAlloc((u+2)*sizeof(WCHAR));
|
|
ASSERT(p3);
|
|
if(*p1 != L'\\') {
|
|
*p3++ = L'\\';
|
|
}
|
|
wcsncpy(p3, p1, u);
|
|
p3[u] = 0;
|
|
*SystemPartitionDirectory = p2;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do cleanup
|
|
//
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
return (GoRepair);
|
|
}
|
|
|
|
BOOLEAN
|
|
SppSelectNTSingleRepair(
|
|
IN PDISK_REGION Region,
|
|
IN PWSTR OsLoadFileName,
|
|
IN PWSTR LoadIdentifier
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inform a user that Setup has found a previous Windows NT installation.
|
|
The user has the option to repair this or cancel.
|
|
|
|
Arguments:
|
|
|
|
Region - Region descriptor for the NT found
|
|
|
|
OsLoadFileName - Directory for the NT found
|
|
|
|
LoadIdentifier - Multi boot load identifier used for this NT.
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ValidKeys[] = { KEY_F3,ASCI_CR, ASCI_ESC, 0 };
|
|
ULONG c;
|
|
PWSTR TmpString = NULL;
|
|
|
|
ASSERT(Region->PartitionedSpace);
|
|
ASSERT(wcslen(OsLoadFileName) >= 2);
|
|
|
|
if( Region->DriveLetter ) {
|
|
swprintf( TemporaryBuffer,
|
|
L"%wc:%ws",
|
|
Region->DriveLetter,
|
|
OsLoadFileName );
|
|
TmpString = SpDupStringW( TemporaryBuffer );
|
|
}
|
|
|
|
while(1) {
|
|
|
|
SpStartScreen(
|
|
SP_SCRN_WINNT_REPAIR,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
(Region->DriveLetter)? TmpString : OsLoadFileName,
|
|
LoadIdentifier
|
|
);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
SP_STAT_ENTER_EQUALS_REPAIR,
|
|
0
|
|
);
|
|
|
|
if( TmpString != NULL ) {
|
|
SpMemFree( TmpString );
|
|
}
|
|
|
|
switch(c=SpWaitValidKey(ValidKeys,NULL,NULL)) {
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
case ASCI_CR:
|
|
return(TRUE);
|
|
default:
|
|
//
|
|
// must have entered ESC
|
|
//
|
|
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
SppSelectNTMultiRepair(
|
|
OUT PSP_BOOT_ENTRY *BootEntryChosen
|
|
)
|
|
{
|
|
PVOID Menu;
|
|
ULONG MenuTopY;
|
|
ULONG ValidKeys[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
|
|
ULONG Keypress;
|
|
PSP_BOOT_ENTRY BootEntry,FirstRepairSet;
|
|
|
|
while(1) {
|
|
|
|
//
|
|
// Display the text that goes above the menu on the partitioning screen.
|
|
//
|
|
SpDisplayScreen(SP_SCRN_WINNT_REPAIR_LIST,3,CLIENT_TOP+1);
|
|
|
|
//
|
|
// Calculate menu placement. Leave one blank line
|
|
// and one line for a frame.
|
|
//
|
|
|
|
MenuTopY = NextMessageTopLine + (SplangQueryMinimizeExtraSpacing() ? 2 : 5);
|
|
|
|
//
|
|
// Create a menu.
|
|
//
|
|
|
|
Menu = SpMnCreate(
|
|
MENU_LEFT_X,
|
|
MenuTopY,
|
|
MENU_WIDTH,
|
|
VideoVars.ScreenHeight-MenuTopY-2-STATUS_HEIGHT
|
|
);
|
|
|
|
ASSERT(Menu);
|
|
|
|
//
|
|
// Build up a menu of partitions and free spaces.
|
|
//
|
|
|
|
FirstRepairSet = NULL;
|
|
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next ) {
|
|
if( BootEntry->Processable ) {
|
|
if( BootEntry->OsPartitionDiskRegion->DriveLetter ) {
|
|
swprintf(
|
|
TemporaryBuffer,
|
|
L"%wc:%ws %ws",
|
|
BootEntry->OsPartitionDiskRegion->DriveLetter,
|
|
BootEntry->OsDirectory,
|
|
BootEntry->FriendlyName
|
|
);
|
|
} else {
|
|
swprintf(
|
|
TemporaryBuffer,
|
|
L"%ws %ws",
|
|
BootEntry->OsDirectory,
|
|
BootEntry->FriendlyName
|
|
);
|
|
}
|
|
|
|
|
|
SpMnAddItem(Menu,
|
|
TemporaryBuffer,
|
|
MENU_LEFT_X+MENU_INDENT,
|
|
MENU_WIDTH-(2*MENU_INDENT),
|
|
TRUE,
|
|
(ULONG_PTR)BootEntry
|
|
);
|
|
if(FirstRepairSet == NULL) {
|
|
FirstRepairSet = BootEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the status line.
|
|
//
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
SP_STAT_ENTER_EQUALS_REPAIR,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Display the menu
|
|
//
|
|
|
|
SpMnDisplay(
|
|
Menu,
|
|
(ULONG_PTR)FirstRepairSet,
|
|
TRUE,
|
|
ValidKeys,
|
|
NULL,
|
|
NULL,
|
|
&Keypress,
|
|
(PULONG_PTR)BootEntryChosen
|
|
);
|
|
|
|
//
|
|
// Now act on the user's selection.
|
|
//
|
|
|
|
switch(Keypress) {
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
case ASCI_CR:
|
|
SpMnDestroy(Menu);
|
|
return( TRUE );
|
|
|
|
default:
|
|
SpMnDestroy(Menu);
|
|
return(FALSE);
|
|
}
|
|
SpMnDestroy(Menu);
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SppRepairScreenRepaint(
|
|
IN PWSTR FullSourcename, OPTIONAL
|
|
IN PWSTR FullTargetname, OPTIONAL
|
|
IN BOOLEAN RepaintEntireScreen
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(FullTargetname);
|
|
UNREFERENCED_PARAMETER(FullSourcename);
|
|
|
|
//
|
|
// Repaint the entire screen if necessary.
|
|
//
|
|
|
|
if(RepaintEntireScreen) {
|
|
if( SpDrEnabled() ) {
|
|
SpStartScreen( SP_SCRN_ASR_IS_EXAMINING, 0, 6, TRUE, FALSE, DEFAULT_ATTRIBUTE );
|
|
}
|
|
else {
|
|
SpStartScreen( SP_SCRN_SETUP_IS_EXAMINING,0, 6, TRUE, FALSE, DEFAULT_ATTRIBUTE );
|
|
}
|
|
|
|
if(RepairGauge) {
|
|
SpDrawGauge(RepairGauge);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpErDiskScreen(
|
|
BOOLEAN *HasErDisk
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ask user if user has emergency repair disk.
|
|
|
|
Arguments:
|
|
|
|
*HasErDisk - Indicates whether diskette will be used.
|
|
|
|
Return Value:
|
|
|
|
TRUE - User chose disk or diskless.
|
|
|
|
FALSE - User wants to return to previous screen.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ValidKeys[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
|
|
ULONG MnemonicKeys[] = { MnemonicLocate, 0 };
|
|
BOOLEAN Choosing;
|
|
ULONG c;
|
|
|
|
for (Choosing = TRUE; Choosing; ) {
|
|
|
|
SpDisplayScreen(SP_SCRN_REPAIR_ASK_REPAIR_DISK,3,4);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_L_EQUALS_LOCATE,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Wait for keypress. Valid keys:
|
|
//
|
|
// L = Do not use ER diskette, locate on hard disk
|
|
// F3 = exit
|
|
// ENTER = Use ER diskette
|
|
// ESC = cancel, return to previous screen
|
|
//
|
|
|
|
SpInputDrain();
|
|
|
|
switch(c=SpWaitValidKey(ValidKeys,NULL,MnemonicKeys)) {
|
|
|
|
case ASCI_CR:
|
|
|
|
//
|
|
// User wants express setup.
|
|
//
|
|
|
|
*HasErDisk = TRUE;
|
|
Choosing = FALSE;
|
|
break;
|
|
|
|
case (MnemonicLocate | KEY_MNEMONIC):
|
|
|
|
//
|
|
// User wants repair without diskette.
|
|
//
|
|
|
|
*HasErDisk = FALSE;
|
|
Choosing = FALSE;
|
|
break;
|
|
|
|
case KEY_F3:
|
|
|
|
//
|
|
// User wants to exit.
|
|
//
|
|
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// must be ESC
|
|
//
|
|
|
|
*HasErDisk = FALSE;
|
|
Choosing = FALSE;
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN
|
|
SppRepairReportError(
|
|
IN BOOLEAN AllowEsc,
|
|
IN ULONG ErrorScreenId,
|
|
IN ULONG SubErrorId,
|
|
IN PWSTR SectionName,
|
|
IN ULONG LineNumber,
|
|
IN PBOOLEAN DoNotPromptAgain
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inform a user that repair has encountered some kind of error.
|
|
The user has the option to continue or exit.
|
|
|
|
Arguments:
|
|
|
|
AllowEsc - Supplies a BOOLEAN to indicate if ESC is allowed.
|
|
|
|
ErrorScreenId - The SCREEN error message number.
|
|
|
|
SubErrorId - the sub error number
|
|
|
|
SectionName - the name of the section which error occured.
|
|
|
|
LineNumber - the error line number within the specified section.
|
|
|
|
Return Value:
|
|
|
|
FALSE if ESC was pressed.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ValidKeys0[] = { KEY_F3, ASCI_CR, 0 };
|
|
ULONG ValidKeys1[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
|
|
ULONG MnemonicKeys[] = { MnemonicRepairAll, 0 };
|
|
PULONG ValidKeys;
|
|
PULONG Mnemonics;
|
|
ULONG c;
|
|
PWSTR SubError;
|
|
BOOLEAN rc;
|
|
|
|
SubError = SpMemAlloc(512);
|
|
|
|
//
|
|
// Line numbers are 0-based. Want to display to user as 1-based.
|
|
//
|
|
|
|
LineNumber++;
|
|
|
|
//
|
|
// Fetch/format the suberror.
|
|
//
|
|
|
|
SpFormatMessage(SubError, 512, SubErrorId, SectionName, LineNumber);
|
|
|
|
//
|
|
// Display the error screen.
|
|
//
|
|
|
|
SpStartScreen(
|
|
ErrorScreenId,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
SubError
|
|
);
|
|
|
|
SpMemFree(SubError);
|
|
|
|
//
|
|
// Display status options: enter to continue.
|
|
//
|
|
|
|
if (AllowEsc) {
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_A_EQUALS_REPAIR_ALL,
|
|
SP_STAT_ESC_EQUALS_SKIP_FILE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0);
|
|
ValidKeys = ValidKeys1;
|
|
Mnemonics = MnemonicKeys;
|
|
if( DoNotPromptAgain != NULL ) {
|
|
*DoNotPromptAgain = FALSE;
|
|
}
|
|
} else {
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0);
|
|
ValidKeys = ValidKeys0;
|
|
Mnemonics = NULL;
|
|
}
|
|
|
|
//
|
|
// Wait for the user to press enter.
|
|
//
|
|
|
|
switch(c=SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
case ASCI_CR:
|
|
rc = TRUE;
|
|
break;
|
|
case ASCI_ESC:
|
|
rc = FALSE;
|
|
break;
|
|
default:
|
|
//
|
|
// must be repair all mnemonic
|
|
//
|
|
ASSERT(c == (MnemonicRepairAll | KEY_MNEMONIC));
|
|
if( DoNotPromptAgain != NULL ) {
|
|
*DoNotPromptAgain = TRUE;
|
|
}
|
|
rc = TRUE;
|
|
break;
|
|
|
|
}
|
|
CLEAR_CLIENT_SCREEN();
|
|
return(rc);
|
|
}
|
|
|
|
BOOLEAN
|
|
SpLoadRepairLogFile(
|
|
IN PWCHAR Filename,
|
|
OUT PVOID *Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load repair text file (setup.log) into memory.
|
|
|
|
Arguments:
|
|
|
|
Filename - Supplies full filename (in NT namespace) of the file to
|
|
be loaded.
|
|
|
|
Handle - receives handle to loaded file, which can be
|
|
used in subsequent calls to other text file services.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN value to indicate if the setup.log is processed.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR Version;
|
|
ULONG ErrorSubId;
|
|
ULONG ErrorLine;
|
|
|
|
//
|
|
// Load setup.log
|
|
//
|
|
|
|
Status = SpLoadSetupTextFile(
|
|
Filename,
|
|
NULL, // No image already in memory
|
|
0, // Image size is empty
|
|
Handle,
|
|
&ErrorLine,
|
|
TRUE,
|
|
FALSE
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
if(Status == STATUS_UNSUCCESSFUL) {
|
|
|
|
//
|
|
// Syntax error in setup.log file
|
|
//
|
|
|
|
ErrorSubId = SP_TEXT_REPAIR_INF_ERROR_1;
|
|
} else {
|
|
|
|
//
|
|
// Unable to load setup.log file
|
|
//
|
|
|
|
ErrorLine = 0;
|
|
ErrorSubId = SP_TEXT_REPAIR_INF_ERROR_0;
|
|
}
|
|
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR,
|
|
ErrorSubId,
|
|
NULL,
|
|
ErrorLine,
|
|
NULL );
|
|
|
|
*Handle = NULL;
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Check if this setup.log file is for Winnt 3.5
|
|
//
|
|
|
|
Version = SpGetSectionKeyIndex(*Handle,
|
|
SIF_NEW_REPAIR_SIGNATURE,
|
|
SIF_NEW_REPAIR_VERSION_KEY,
|
|
0); // should be moved to spsif.c
|
|
if(Version == NULL) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR,
|
|
SP_TEXT_REPAIR_INF_ERROR_2,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
} else {
|
|
if(!_wcsicmp(Version,SIF_NEW_REPAIR_NT_VERSION)) {
|
|
return(TRUE);
|
|
} else {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR,
|
|
SP_TEXT_REPAIR_INF_ERROR_5,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Control comes here only when error occurs ...
|
|
//
|
|
|
|
SpFreeTextFile(*Handle);
|
|
*Handle = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
VOID
|
|
SpRepairDiskette(
|
|
OUT PVOID *SifHandle,
|
|
OUT PDISK_REGION *TargetRegion,
|
|
OUT PWSTR *TargetPath,
|
|
OUT PDISK_REGION *SystemPartitionRegion,
|
|
OUT PWSTR *SystemPartitionDirectory
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks if there is a floppy drive. If no, it returns
|
|
silently. Otherwise, it prompts user for Emergency Repair Disk.
|
|
|
|
Arguments:
|
|
|
|
SifHandle - Supplies a variable to receive the setup.log file handle.
|
|
|
|
TargetRegion - Supplies a variable to receive the pointer to the target
|
|
installation region.
|
|
|
|
TargetPath - Supplies a variable to receive the nt name of target path.
|
|
|
|
SystemPartitionRegion - Supplies a variable to receive the pointer of the
|
|
system partition region.
|
|
|
|
SystemPartitionDirectory - Supplies a variable to receive the osloader
|
|
directory name on the system partition.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR szDiskName;
|
|
BOOLEAN b, rc = FALSE;
|
|
PWSTR FullLogFilename, p, FloppyDevicePath = L"\\device\\floppy0";
|
|
PWSTR SystemPartition, WinntPartition;
|
|
|
|
//
|
|
// Assume failure.
|
|
//
|
|
|
|
*SifHandle = NULL;
|
|
|
|
//
|
|
// Always want to prompt for the disk in A:.
|
|
// First, check if there is an A:. If no floppy drive,
|
|
// simply skip the request for ER diskette.
|
|
//
|
|
|
|
if(SpGetFloppyDriveType(0) == FloppyTypeNone) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Fetch the generic repair disk name.
|
|
//
|
|
|
|
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_REPAIR_DISK_NAME);
|
|
szDiskName = SpDupStringW(TemporaryBuffer);
|
|
p = TemporaryBuffer;
|
|
*p = 0;
|
|
SpConcatenatePaths(p, FloppyDevicePath);
|
|
SpConcatenatePaths(p, SETUP_LOG_FILENAME);
|
|
FullLogFilename = SpDupStringW(p);
|
|
|
|
while (rc == FALSE) {
|
|
|
|
//
|
|
// Prompt for the disk -- ignore what may be in the drive already,
|
|
// and allow escape.
|
|
//
|
|
|
|
b = SpPromptForDisk(
|
|
szDiskName,
|
|
FloppyDevicePath,
|
|
SETUP_LOG_FILENAME,
|
|
TRUE, // Always prompt for at least once
|
|
TRUE, // Allow user to cancel
|
|
FALSE, // No multiple prompts
|
|
NULL // don't care about redraw flag
|
|
);
|
|
|
|
|
|
//
|
|
// If the user pressed escape at the disk prompt, bail out now.
|
|
//
|
|
|
|
if(!b) {
|
|
rc = TRUE; // User canceled. Skip repair floppy
|
|
} else {
|
|
rc = SpLoadRepairLogFile(FullLogFilename, SifHandle);
|
|
if (rc) {
|
|
|
|
//
|
|
// Now we need to figure out the partition, path information
|
|
// to update boot.ini.
|
|
//
|
|
|
|
SppGetRepairPathInformation(*SifHandle,
|
|
&SystemPartition,
|
|
SystemPartitionDirectory,
|
|
&WinntPartition,
|
|
TargetPath
|
|
);
|
|
|
|
*SystemPartitionRegion = SpRegionFromNtName(
|
|
SystemPartition,
|
|
PartitionOrdinalCurrent);
|
|
if (*SystemPartitionRegion == NULL) {
|
|
SpFatalSifError(*SifHandle,
|
|
SIF_NEW_REPAIR_PATHS,
|
|
SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE,0,0);
|
|
}
|
|
*TargetRegion = SpRegionFromNtName(WinntPartition, PartitionOrdinalCurrent);
|
|
if (*TargetRegion == NULL) {
|
|
SpFatalSifError(*SifHandle,
|
|
SIF_NEW_REPAIR_PATHS,
|
|
SIF_NEW_REPAIR_PATHS_TARGET_DEVICE,0,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SpMemFree(szDiskName);
|
|
SpMemFree(FullLogFilename);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SppRepairWinntFiles(
|
|
IN PVOID LogFileHandle,
|
|
IN PVOID MasterSifHandle,
|
|
IN PWSTR SourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice,
|
|
IN PWSTR SystemPartition,
|
|
IN PWSTR SystemPartitionDirectory,
|
|
IN PWSTR WinntPartition,
|
|
IN PWSTR WinntPartitionDirectory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine goes through the system partition files and winnt files
|
|
listed in the setup.log file and checks their validity.
|
|
|
|
Arguments:
|
|
|
|
LogFileHandle - Handle of the setup.log
|
|
|
|
MasterSifHandle - Handle of the txtsetup.sif
|
|
|
|
SourceDevicePath - supplies the NT name of the source device
|
|
|
|
DirectoryOnSourceDevice - supplies the directory on the source device
|
|
which contains source file.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR SystemPartitionFiles = L"system partition files";
|
|
PWSTR WinntFiles = L"WinNt files";
|
|
ULONG TotalFileCount;
|
|
BOOLEAN RepairWithoutConfirming;
|
|
|
|
//
|
|
// Create file repair gauge
|
|
//
|
|
|
|
TotalFileCount = SpCountLinesInSection(LogFileHandle,SIF_NEW_REPAIR_SYSPARTFILES);
|
|
TotalFileCount += SpCountLinesInSection(LogFileHandle,SIF_NEW_REPAIR_WINNTFILES);
|
|
TotalFileCount += SpCountLinesInSection(LogFileHandle,SIF_NEW_REPAIR_FILES_IN_REPAIR_DIR);
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_SETUP_IS_EXAMINING);
|
|
RepairGauge = SpCreateAndDisplayGauge(TotalFileCount,0,15,TemporaryBuffer,NULL,GF_PERCENTAGE,0);
|
|
ASSERT(RepairGauge);
|
|
|
|
//
|
|
// delay opening of driver inf and cab file till required
|
|
//
|
|
ghSif = MasterSifHandle;
|
|
gszDrvInfDeviceName = SourceDevicePath;
|
|
gszDrvInfDirName = DirectoryOnSourceDevice;
|
|
|
|
|
|
SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
|
|
SppRepairScreenRepaint(NULL, NULL, TRUE);
|
|
|
|
|
|
//
|
|
// first recreate all of the directories we copy into
|
|
//
|
|
if (SystemPartition != NULL) {
|
|
SpCreateDirectory(SystemPartition,NULL,SystemPartitionDirectory,0,0);
|
|
}
|
|
|
|
//
|
|
// Create the nt tree.
|
|
//
|
|
SpCreateDirectoryStructureFromSif(MasterSifHandle,
|
|
SIF_NTDIRECTORIES,
|
|
WinntPartition,
|
|
WinntPartitionDirectory);
|
|
|
|
//
|
|
// Verify and repair the files in [Files.InRepairDirectory]. If textmode
|
|
// setup is executing a disaster recovery, do not prompt the user for the
|
|
// files to repair. Just go ahead and repair 'em.
|
|
//
|
|
|
|
RepairWithoutConfirming = SpDrEnabled() && SpDrIsRepairFast();
|
|
|
|
SppVerifyAndRepairVdmFiles(LogFileHandle,
|
|
WinntPartition,
|
|
NULL,
|
|
&RepairWithoutConfirming);
|
|
|
|
//
|
|
// Verify and repair the files in [FIles.SystemPartition]
|
|
//
|
|
|
|
SppVerifyAndRepairFiles(LogFileHandle,
|
|
MasterSifHandle,
|
|
SIF_NEW_REPAIR_SYSPARTFILES,
|
|
SourceDevicePath,
|
|
DirectoryOnSourceDevice,
|
|
SystemPartition,
|
|
SystemPartitionDirectory,
|
|
TRUE,
|
|
&RepairWithoutConfirming);
|
|
|
|
|
|
//
|
|
// Verify and repair the files in [Files.WinNt]
|
|
//
|
|
|
|
SppVerifyAndRepairFiles(LogFileHandle,
|
|
MasterSifHandle,
|
|
SIF_NEW_REPAIR_WINNTFILES,
|
|
SourceDevicePath,
|
|
DirectoryOnSourceDevice,
|
|
WinntPartition,
|
|
NULL,
|
|
FALSE,
|
|
&RepairWithoutConfirming);
|
|
|
|
SpDestroyGauge(RepairGauge);
|
|
RepairGauge = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
SppVerifyAndRepairFiles(
|
|
IN PVOID LogFileHandle,
|
|
IN PVOID MasterSifHandle,
|
|
IN PWSTR SectionName,
|
|
IN PWSTR SourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice,
|
|
IN PWSTR TargetDevicePath,
|
|
IN PWSTR DirectoryOnTargetDevice,
|
|
IN BOOLEAN SystemPartitionFiles,
|
|
IN OUT PBOOLEAN RepairWithoutConfirming
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine goes through the files listed in the specified section of
|
|
setup.log file and checks their validity. If a file's checksum does
|
|
not match the checksum listed in the setup.log file, we will prompt
|
|
the user and recopy the file from original installation sources.
|
|
|
|
Arguments:
|
|
|
|
LogFileHandle - Handle of the setup.log
|
|
|
|
MasterSifHandle - Handle of the txtsetup.sif
|
|
|
|
SectionName - Section in setup.log to be examined
|
|
|
|
SourceDevicePath - supplies the NT name of the source device
|
|
|
|
DirectoryOnSourceDevice - supplies the directory on the source device
|
|
which contains source file.
|
|
|
|
TargetDevicePath - supplies the nt name of the target device
|
|
|
|
DirectoryOnTargetDevice - the name of the winnt directory on target
|
|
device
|
|
|
|
SystemPartitionFile - supplies a boolean value to indicate if the target
|
|
file is on system partition
|
|
|
|
RepairWithoutConfirming - Pointer to a flag that indicates whether or not
|
|
setup should repair a damaged file without
|
|
asking the user to confirm.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR FullTargetName, ChecksumString;
|
|
PWSTR TargetDirectory, TargetFileName;
|
|
PWSTR SourceFileName;
|
|
ULONG Checksum, FileChecksum, PrefixLength, Length, Count, i;
|
|
BOOLEAN IsNtImage, IsValid, RepairFile, SysPartNTFS = FALSE;
|
|
BOOLEAN RedrawGauge = TRUE, ForceNoComp;
|
|
FILE_TO_COPY FileToCopy;
|
|
PWSTR OemDiskDescription, OemDiskTag, OemSourceDirectory;
|
|
PWSTR DevicePath, Directory, q;
|
|
PWSTR MediaShortName, PreviousMediaName = L"";
|
|
PWSTR MediaDir;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Allocate a SMALL buffer for local use and init FileToCopy struct
|
|
//
|
|
|
|
TargetDirectory = NULL;
|
|
FullTargetName = SpMemAlloc(1024);
|
|
*FullTargetName = 0;
|
|
FileToCopy.Next = NULL;
|
|
FileToCopy.AbsoluteTargetDirectory = TRUE;
|
|
|
|
FileToCopy.TargetDevicePath = TargetDevicePath;
|
|
SpConcatenatePaths(FullTargetName,TargetDevicePath);
|
|
|
|
if(SystemPartitionFiles) {
|
|
|
|
PDISK_REGION SystemPartitionRegion;
|
|
|
|
//
|
|
// We must find out whether the system partition is NTFS, because
|
|
// if it is, then we might want to make sure it's not compressed.
|
|
//
|
|
if(SystemPartitionRegion = SpRegionFromNtName(TargetDevicePath,
|
|
PartitionOrdinalCurrent)) {
|
|
SysPartNTFS = (SystemPartitionRegion->Filesystem == FilesystemNtfs);
|
|
}
|
|
|
|
//
|
|
// For system partition files, we need to concatenate target
|
|
// directory to FullTargetName. Because the target filename
|
|
// of system partition files do not have target directory.
|
|
//
|
|
|
|
FileToCopy.TargetDirectory = DirectoryOnTargetDevice;
|
|
SpConcatenatePaths(FullTargetName,FileToCopy.TargetDirectory);
|
|
}
|
|
|
|
PrefixLength = wcslen(FullTargetName);
|
|
|
|
Count = SpCountLinesInSection(LogFileHandle,SectionName);
|
|
for (i = 0; i < Count; i++) {
|
|
if (RedrawGauge) {
|
|
SppRepairScreenRepaint(NULL, NULL, TRUE);
|
|
RedrawGauge = FALSE;
|
|
}
|
|
SpTickGauge(RepairGauge);
|
|
|
|
//
|
|
// Initialize the 'ForceNoComp' flag to FALSE, thus allowing the
|
|
// file to use NTFS compression.
|
|
//
|
|
ForceNoComp = FALSE;
|
|
|
|
//
|
|
// Initialize target fullname to be DevicePath+Directory for
|
|
// system partition file or DevicePath for Winnt files
|
|
//
|
|
|
|
FullTargetName[PrefixLength] = (WCHAR)NULL;
|
|
|
|
//
|
|
// If we allocate space for TargetDirectory we must free it.
|
|
//
|
|
|
|
if (TargetDirectory) {
|
|
SpMemFree(TargetDirectory);
|
|
TargetDirectory = NULL;
|
|
}
|
|
TargetFileName = SpGetKeyName(LogFileHandle,SectionName,i);
|
|
if(!TargetFileName) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If the target file name contains \system32\config\, it is
|
|
// hive related file. We simply ignore it.
|
|
//
|
|
|
|
q = SpDupStringW(TargetFileName);
|
|
SpStringToUpper(q);
|
|
if (wcsstr(q,L"\\SYSTEM32\\CONFIG\\")) {
|
|
SpMemFree(q);
|
|
continue;
|
|
}
|
|
SpMemFree(q);
|
|
|
|
SpConcatenatePaths(FullTargetName,TargetFileName);
|
|
SpDisplayStatusText(SP_STAT_EXAMINING_WINNT,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
TargetFileName);
|
|
|
|
ChecksumString = SpGetSectionLineIndex(LogFileHandle,SectionName,i,1);
|
|
if(!ChecksumString) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
|
|
Checksum = (ULONG)SpStringToLong(ChecksumString, NULL, 16);
|
|
|
|
//
|
|
// Validate the security set on the file.
|
|
// Note that we do not check the files in the system partition
|
|
// on non-x86 systems since it is always FAT
|
|
//
|
|
#ifndef _X86_
|
|
if(!SystemPartitionFiles) {
|
|
#endif
|
|
Status = SpVerifyFileAccess( FullTargetName,
|
|
STANDARD_RIGHTS_READ |
|
|
FILE_READ_ATTRIBUTES |
|
|
FILE_WRITE_ATTRIBUTES |
|
|
DELETE |
|
|
WRITE_DAC |
|
|
SYNCHRONIZE );
|
|
|
|
|
|
if( !NT_SUCCESS( Status ) &&
|
|
((Status == STATUS_ACCESS_DENIED)||(Status == STATUS_PRIVILEGE_NOT_HELD)) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Security of %ls, must be fixed. Status = %x\n", FullTargetName, Status ));
|
|
Status = SpSetDefaultFileSecurity( FullTargetName );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to change security of %ls. Status = %x\n", FullTargetName, Status ));
|
|
|
|
}
|
|
}
|
|
|
|
#ifndef _X86_ // end of block started by "if(!SystemPartitionFiles) {" above
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If this is a system partition file and the system partition is NTFS,
|
|
// then check to see whether this file can use NTFS compression, and
|
|
// if not, force it to be uncompressed.
|
|
//
|
|
if((SysPartNTFS) &&
|
|
IsFileFlagSet(MasterSifHandle,TargetFileName,FILEFLG_FORCENOCOMP))
|
|
{
|
|
ForceNoComp = TRUE;
|
|
SpVerifyNoCompression(FullTargetName);
|
|
}
|
|
|
|
SpValidateAndChecksumFile(NULL,FullTargetName,&IsNtImage,&FileChecksum,&IsValid);
|
|
|
|
//
|
|
// If the image is invalid or the file on the target is not the
|
|
// original file copied by setup, we will recopy it.
|
|
//
|
|
|
|
if (!IsValid || FileChecksum != Checksum) {
|
|
|
|
//
|
|
// Ask user if he wants to repair the file
|
|
//
|
|
if(*RepairWithoutConfirming) {
|
|
RepairFile = TRUE;
|
|
} else {
|
|
RepairFile = SppRepairReportError(
|
|
TRUE,
|
|
SP_SCRN_REPAIR_FILE_MISMATCH,
|
|
SP_TEXT_REPAIR_INF_ERROR_4,
|
|
TargetFileName,
|
|
i,
|
|
RepairWithoutConfirming);
|
|
RedrawGauge = TRUE;
|
|
}
|
|
|
|
if (!RepairFile) {
|
|
continue;
|
|
}
|
|
SpDisplayStatusText(SP_STAT_REPAIR_WINNT,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
TargetFileName);
|
|
|
|
if (SystemPartitionFiles) {
|
|
FileToCopy.TargetFilename = TargetFileName;
|
|
} else {
|
|
|
|
//
|
|
// For Winnt files, the TargetName contains path and filename.
|
|
// We need to seperate them.
|
|
//
|
|
|
|
TargetDirectory = SpDupStringW(TargetFileName);
|
|
Length = wcslen(TargetDirectory);
|
|
while (Length) {
|
|
if (TargetDirectory[Length] == L'\\') {
|
|
TargetDirectory[Length] = 0;
|
|
TargetFileName = &TargetDirectory[Length + 1];
|
|
break;
|
|
} else {
|
|
Length--;
|
|
}
|
|
}
|
|
if (Length == 0) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
FileToCopy.TargetFilename = TargetFileName;
|
|
FileToCopy.TargetDirectory = TargetDirectory;
|
|
}
|
|
SourceFileName = SpGetSectionLineIndex(LogFileHandle,SectionName,i,0);
|
|
if (!SourceFileName) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
|
|
|
|
FileToCopy.SourceFilename = NULL;
|
|
q = SpDupStringW(SourceFileName);
|
|
SpStringToUpper(q);
|
|
if (wcsstr(q,L"DRIVER.CAB")) {
|
|
SpMemFree(q);
|
|
q = SpDupStringW(TargetFileName);
|
|
SpStringToUpper(q);
|
|
if (!wcsstr(q,L"DRIVER.CAB")) {
|
|
FileToCopy.SourceFilename = TargetFileName;
|
|
}
|
|
}
|
|
SpMemFree(q);
|
|
|
|
FileToCopy.SourceFilename = FileToCopy.SourceFilename
|
|
? FileToCopy.SourceFilename
|
|
: SourceFileName;
|
|
FileToCopy.Flags = COPY_ALWAYS | COPY_NOVERSIONCHECK | (ForceNoComp ? COPY_FORCENOCOMP : 0);
|
|
|
|
|
|
//
|
|
// The file may come from OEM diskette. We need to check if the
|
|
// sources device is listed in log file. If not, it must be
|
|
// from MS setup sources.
|
|
//
|
|
|
|
OemSourceDirectory = SpGetSectionLineIndex(LogFileHandle,SectionName,i,2);
|
|
OemDiskTag = NULL;
|
|
if (OemSourceDirectory) {
|
|
OemDiskDescription = SpGetSectionLineIndex(LogFileHandle,SectionName,i,3);
|
|
if (OemDiskDescription) {
|
|
OemDiskTag = SpGetSectionLineIndex(LogFileHandle,SectionName,i,4);
|
|
if((OemDiskTag != NULL) &&
|
|
(wcslen(OemDiskTag) == 0)){
|
|
OemDiskTag = SourceFileName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OemDiskTag) {
|
|
BOOLEAN rs;
|
|
PWSTR szDevicePath = SpDupStringW(L"\\device\\floppy0");
|
|
|
|
//
|
|
// Prompt for the disk, based on the setup media type.
|
|
//
|
|
|
|
rs = SpPromptForDisk(
|
|
OemDiskDescription,
|
|
szDevicePath,
|
|
OemDiskTag,
|
|
FALSE, // don't ignore disk in drive
|
|
TRUE, // allow escape
|
|
TRUE, // warn about multiple prompts for same disk
|
|
NULL // don't care redraw flag
|
|
);
|
|
|
|
SpMemFree(szDevicePath);
|
|
RedrawGauge = TRUE;
|
|
|
|
if (rs == FALSE) {
|
|
continue;
|
|
}
|
|
|
|
DevicePath = L"\\device\\floppy0";
|
|
Directory = OemSourceDirectory;
|
|
MediaDir = NULL;
|
|
} else {
|
|
PWSTR szDescription = 0, szTagFileName = 0;
|
|
BOOLEAN bDiskFound = FALSE;
|
|
|
|
//
|
|
// Search SourceFileName against txtsetup.sif to figure out its
|
|
// media name.
|
|
//
|
|
MediaShortName = SpLookUpValueForFile(
|
|
MasterSifHandle,
|
|
SourceFileName,
|
|
INDEX_WHICHMEDIA,
|
|
FALSE
|
|
);
|
|
|
|
if(MediaShortName) {
|
|
SpGetSourceMediaInfo(MasterSifHandle,MediaShortName,NULL,NULL,&MediaDir);
|
|
} else {
|
|
SpNonFatalSifError(
|
|
MasterSifHandle,
|
|
SIF_FILESONSETUPMEDIA,
|
|
SourceFileName,
|
|
0,
|
|
INDEX_WHICHMEDIA,
|
|
SourceFileName
|
|
);
|
|
//
|
|
// If we returned from SpNonFatalSifError, then the user wants to
|
|
// skip the file.
|
|
//
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Prompt user to insert the source media, if changed.
|
|
//
|
|
SpGetSourceMediaInfo(MasterSifHandle, MediaShortName,
|
|
&szDescription, &szTagFileName, NULL);
|
|
|
|
//
|
|
// Prompt for the disk, based on the setup media type.
|
|
//
|
|
bDiskFound = SpPromptForDisk(
|
|
szDescription,
|
|
SourceDevicePath,
|
|
szTagFileName,
|
|
FALSE, // don't ignore disk in drive
|
|
TRUE, // don't allow escape
|
|
TRUE, // warn about multiple prompts for same disk
|
|
NULL // don't care redraw flag
|
|
);
|
|
|
|
RedrawGauge = TRUE;
|
|
|
|
//
|
|
// user might have wanted to skip the file
|
|
//
|
|
if (!bDiskFound)
|
|
continue;
|
|
|
|
DevicePath = SourceDevicePath;
|
|
Directory = DirectoryOnSourceDevice;
|
|
}
|
|
|
|
//
|
|
// Copy the file.
|
|
//
|
|
// If the file is listed for lock smashing then we need to smash it
|
|
// if installing UP on x86 (we don't bother with the latter
|
|
// qualifications here).
|
|
//
|
|
|
|
SpCopyFileWithRetry(
|
|
&FileToCopy,
|
|
DevicePath,
|
|
Directory,
|
|
MediaDir,
|
|
NULL, // TargetRoot -> NULL
|
|
SystemPartitionFiles ? ATTR_RHS : 0,
|
|
SppRepairScreenRepaint,
|
|
NULL, // Do not want checksum
|
|
NULL, // Do not want to know if file was skipped
|
|
IsFileFlagSet(
|
|
MasterSifHandle,
|
|
FileToCopy.TargetFilename,
|
|
FILEFLG_SMASHLOCKS) ? COPY_SMASHLOCKS : 0
|
|
);
|
|
}
|
|
}
|
|
|
|
SpMemFree(FullTargetName);
|
|
if (RedrawGauge) {
|
|
SppRepairScreenRepaint(NULL, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpDisplayRepairMenu(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine presents a list of repairable items to user and
|
|
let user choose the items to be fixed among the list.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None. Some global repare variables are set or cleared.
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID Menu;
|
|
ULONG MenuTopY;
|
|
ULONG ValidKeys[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
|
|
ULONG Keypress, MessageIds[RepairItemMax];
|
|
ULONG i;
|
|
ULONG_PTR OptionChosen, InitialHighlight;
|
|
PWSTR MenuItem;
|
|
ULONG ListBoxWidth, curLBEntryWidth;
|
|
|
|
//
|
|
// Initialize repair options to repair ALL.
|
|
// Initialize repair menu item message id.
|
|
//
|
|
|
|
for (i = 0; i < RepairItemMax; i++) {
|
|
RepairItems[i] = 1;
|
|
if (i == 0) {
|
|
MessageIds[i] = SP_REPAIR_MENU_ITEM_1;
|
|
} else {
|
|
MessageIds[i] = MessageIds[i - 1] + 1;
|
|
}
|
|
}
|
|
|
|
while(1) {
|
|
|
|
//
|
|
// Display the text that goes above the menu on the partitioning screen.
|
|
//
|
|
|
|
SpDisplayScreen(SP_SCRN_REPAIR_MENU,3,CLIENT_TOP+1);
|
|
|
|
//
|
|
// Calculate menu placement. Leave one blank line
|
|
// and one line for a frame.
|
|
//
|
|
|
|
MenuTopY = NextMessageTopLine + (SplangQueryMinimizeExtraSpacing() ? 2 : 5);
|
|
|
|
//
|
|
// Create a menu.
|
|
// First, find the longest string, so we can size the listbox accordingly
|
|
//
|
|
ListBoxWidth = LIST_BOX_WIDTH; // It will be at least this wide
|
|
for (i = 0; i <= RepairItemMax; i++ ) {
|
|
if (i == RepairItemMax) {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
SP_REPAIR_MENU_ITEM_CONTINUE);
|
|
} else {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
MessageIds[i]);
|
|
}
|
|
if((curLBEntryWidth = SplangGetColumnCount(TemporaryBuffer)+(2*MENU_INDENT)) > ListBoxWidth) {
|
|
ListBoxWidth = min(curLBEntryWidth, MENU_WIDTH);
|
|
}
|
|
}
|
|
|
|
Menu = SpMnCreate(
|
|
MENU_LEFT_X,
|
|
MenuTopY,
|
|
ListBoxWidth,
|
|
LIST_BOX_HEIGHT
|
|
);
|
|
|
|
if( !Menu )
|
|
return FALSE;
|
|
|
|
ASSERT(Menu);
|
|
|
|
for (i = 0; i <= RepairItemMax; i++ ) {
|
|
if (i == RepairItemMax) {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
SP_REPAIR_MENU_ITEM_CONTINUE);
|
|
} else {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
MessageIds[i]);
|
|
|
|
(TemporaryBuffer)[1] = RepairItems[i] ? L'X' : L' ';
|
|
}
|
|
SpMnAddItem(Menu,
|
|
TemporaryBuffer,
|
|
MENU_LEFT_X+MENU_INDENT,
|
|
ListBoxWidth-(2*MENU_INDENT),
|
|
TRUE,
|
|
i
|
|
);
|
|
}
|
|
InitialHighlight = RepairItemMax;
|
|
|
|
//
|
|
// Initialize the status line.
|
|
//
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
SP_STAT_ENTER_EQUALS_CHANGE,
|
|
0
|
|
);
|
|
|
|
DisplayMenu:
|
|
|
|
//
|
|
// Display the menu
|
|
//
|
|
|
|
SpMnDisplay(
|
|
Menu,
|
|
InitialHighlight,
|
|
TRUE,
|
|
ValidKeys,
|
|
NULL,
|
|
NULL,
|
|
&Keypress,
|
|
&OptionChosen
|
|
);
|
|
|
|
//
|
|
// Now act on the user's selection.
|
|
//
|
|
|
|
switch(Keypress) {
|
|
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
case ASCI_CR:
|
|
if (OptionChosen == RepairItemMax) {
|
|
SpMnDestroy(Menu);
|
|
return( TRUE );
|
|
} else {
|
|
MenuItem = SpMnGetText(Menu, OptionChosen);
|
|
if( !MenuItem )
|
|
goto DisplayMenu;
|
|
RepairItems[OptionChosen] ^= 1;
|
|
if (RepairItems[OptionChosen]) {
|
|
MenuItem[1] = L'X';
|
|
} else {
|
|
MenuItem[1] = L' ';
|
|
}
|
|
InitialHighlight = OptionChosen;
|
|
goto DisplayMenu;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
SpMnDestroy(Menu);
|
|
return(FALSE);
|
|
}
|
|
SpMnDestroy(Menu);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SppRepairFile(
|
|
IN PVOID MasterSifHandle,
|
|
IN PWSTR TargetPath,
|
|
IN PWSTR TargetFilename,
|
|
IN PWSTR SourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice,
|
|
IN PWSTR SourceFilename,
|
|
IN BOOLEAN SystemPartitionFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine repairs ONE file and the source of the file MUST be on
|
|
emergency repair diskette or on the repair directory of the winnt
|
|
being repaired.
|
|
|
|
Arguments:
|
|
|
|
MasterSifHandle - Hanle of the txtsetup.sif
|
|
|
|
TargetPath - Supplies the target file path
|
|
|
|
TargetFilename - supplies the name of the target file
|
|
|
|
SourceDevicePath - supplies the NT name of the source device
|
|
|
|
DirectoryOnSourceDevice - supplies the directory on the source device
|
|
which contains source file.
|
|
|
|
SourceFilename - supplies the name of the source file
|
|
|
|
SystemPartitionFile - supplies a boolean value to indicate if the target
|
|
file is on system partition
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS of the file copy.
|
|
|
|
--*/
|
|
{
|
|
PWSTR szDiskName;
|
|
PWSTR FullSourceFilename, FullTargetFilename;
|
|
NTSTATUS Status;
|
|
|
|
if (RepairFromErDisk) {
|
|
|
|
//
|
|
// Fetch the generic repair disk name.
|
|
//
|
|
|
|
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),
|
|
SP_TEXT_REPAIR_DISK_NAME);
|
|
szDiskName = SpDupStringW(TemporaryBuffer);
|
|
|
|
//
|
|
// Prompt for the disk -- do not ignore what may be in the drive
|
|
// already, and dont allow escape.
|
|
//
|
|
|
|
SpPromptForDisk(
|
|
szDiskName,
|
|
SourceDevicePath,
|
|
SETUP_LOG_FILENAME,
|
|
FALSE, // if disk is in already dont prompt
|
|
FALSE, // Do not allow user to cancel
|
|
TRUE, // warn for multiple prompts
|
|
NULL // don't care about redraw flag
|
|
);
|
|
|
|
|
|
SpMemFree(szDiskName);
|
|
}
|
|
|
|
//
|
|
// Form the name of the source and target fullname.
|
|
//
|
|
|
|
wcscpy(TemporaryBuffer, TargetPath);
|
|
SpConcatenatePaths(TemporaryBuffer, TargetFilename);
|
|
FullTargetFilename = SpDupStringW(TemporaryBuffer);
|
|
|
|
wcscpy(TemporaryBuffer, SourceDevicePath);
|
|
SpConcatenatePaths(TemporaryBuffer, DirectoryOnSourceDevice);
|
|
SpConcatenatePaths(TemporaryBuffer, SourceFilename);
|
|
FullSourceFilename = SpDupStringW(TemporaryBuffer);
|
|
|
|
//
|
|
// Copy the file.
|
|
//
|
|
// If the file is listed for lock smashing then we need to smash it
|
|
// if installing UP on x86 (we don't bother with the latter
|
|
// qualifications here).
|
|
//
|
|
|
|
Status = SpCopyFileUsingNames(
|
|
FullSourceFilename,
|
|
FullTargetFilename,
|
|
SystemPartitionFile ? ATTR_RHS : 0,
|
|
IsFileFlagSet(MasterSifHandle,TargetFilename,FILEFLG_SMASHLOCKS) ? COPY_SMASHLOCKS : 0
|
|
);
|
|
|
|
SpMemFree(FullSourceFilename);
|
|
SpMemFree(FullTargetFilename);
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
SppRepairStartMenuGroupsAndItems(
|
|
IN PWSTR WinntPartition,
|
|
IN PWSTR WinntDirectory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the software hive, and set a value on Winlogon key
|
|
to indicate to Winlogon that it should recreate the Start Menu groups
|
|
and items for the Default User.
|
|
|
|
Arguments:
|
|
|
|
WinntPartition - supplies the NT name of the Winnt partition.
|
|
|
|
WinntDirectory - Supplies the name of the Winnt directory.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR p,q;
|
|
PWSTR LOCAL_MACHINE_KEY_NAME = L"\\registry\\machine";
|
|
ULONG Repair = 1;
|
|
PWSTR WINLOGON_KEY_NAME = L"Microsoft\\Windows NT\\CurrentVersion\\Winlogon";
|
|
PWSTR REPAIR_VALUE_NAME = L"Repair";
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE SoftwareKey;
|
|
|
|
//
|
|
// Put up a screen telling the user what we are doing.
|
|
//
|
|
|
|
// SpStartScreen(SP_SCRN_REPAIR_CHECK_HIVES,
|
|
// 0,
|
|
// 8,
|
|
// TRUE,
|
|
// FALSE,
|
|
// DEFAULT_ATTRIBUTE
|
|
// );
|
|
//
|
|
// SpDisplayStatusText(SP_STAT_REG_LOADING_HIVES,DEFAULT_STATUS_ATTRIBUTE);
|
|
|
|
//
|
|
// Load the software hive
|
|
//
|
|
|
|
//
|
|
// Form the name of the hive file.
|
|
// This is WinntPartition + WinntDirectory + system32\config + the hive name.
|
|
//
|
|
p = NULL;
|
|
q = NULL;
|
|
wcscpy(TemporaryBuffer,WinntPartition);
|
|
SpConcatenatePaths(TemporaryBuffer,WinntDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer,L"system32\\config\\software");
|
|
p = SpDupStringW( TemporaryBuffer );
|
|
|
|
//
|
|
// Form the path of the key into which we will
|
|
// load the hive. We'll use the convention that
|
|
// a hive will be loaded into \registry\machine\x<hivename>.
|
|
//
|
|
|
|
wcscpy(TemporaryBuffer,LOCAL_MACHINE_KEY_NAME);
|
|
SpConcatenatePaths(TemporaryBuffer,L"x");
|
|
wcscat(TemporaryBuffer,L"software");
|
|
q = SpDupStringW( TemporaryBuffer );
|
|
|
|
if( (p == NULL) || (q == NULL) ) {
|
|
goto fix_strtmenu_cleanup_1;
|
|
}
|
|
|
|
//
|
|
// Attempt to load the hive.
|
|
//
|
|
|
|
Status = SpLoadUnloadKey(NULL,NULL,q,p);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to load hive %ws to key %ws (%lx)\n",p,q,Status));
|
|
goto fix_strtmenu_cleanup_1;
|
|
}
|
|
|
|
INIT_OBJA(&Obja,&UnicodeString,q);
|
|
Status = ZwOpenKey(&SoftwareKey,KEY_ALL_ACCESS,&Obja);
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws (%lx)\n",q,Status));
|
|
goto fix_strtmenu_cleanup_2;
|
|
}
|
|
|
|
Status = SpOpenSetValueAndClose(
|
|
SoftwareKey,
|
|
WINLOGON_KEY_NAME,
|
|
REPAIR_VALUE_NAME,
|
|
REG_DWORD,
|
|
&Repair,
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set value %ws on key %ws. Status = %lx\n",REPAIR_VALUE_NAME,REPAIR_VALUE_NAME,Status));
|
|
goto fix_strtmenu_cleanup_3;
|
|
}
|
|
Status = ZwFlushKey(SoftwareKey );
|
|
|
|
fix_strtmenu_cleanup_3:
|
|
|
|
Status = ZwClose( SoftwareKey );
|
|
|
|
fix_strtmenu_cleanup_2:
|
|
|
|
Status = SpLoadUnloadKey(NULL,NULL,q,NULL);
|
|
|
|
fix_strtmenu_cleanup_1:
|
|
if( p != NULL ) {
|
|
SpMemFree( p );
|
|
}
|
|
if( q != NULL ) {
|
|
SpMemFree( q );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SppInspectHives(
|
|
IN PWSTR PartitionPath,
|
|
IN PWSTR SystemRoot,
|
|
OUT PULONG HiveLoaded,
|
|
IN PWSTR *HiveNames
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine inspects setup hives by loading and unloading them and
|
|
returns the loadable information in HiveLoaded[].
|
|
|
|
Arguments:
|
|
|
|
PartitionPath - supplies the NT name of the Winnt partition.
|
|
|
|
SystemRoot - Supplies the name of the Winnt System root.
|
|
|
|
HiveLoaded - Supplies a pointer to a ULONG array to receive the
|
|
loadable information for each hive inspected.
|
|
|
|
HIveNames - Supplies a pointer to a PWSTR array to receive the
|
|
name of hives to inspect.
|
|
|
|
Return Value:
|
|
|
|
None. HiveLoaded array initialized.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR pwstrTemp1,pwstrTemp2;
|
|
int h;
|
|
PWSTR LOCAL_MACHINE_KEY_NAME = L"\\registry\\machine";
|
|
|
|
//
|
|
// Put up a screen telling the user what we are doing.
|
|
//
|
|
|
|
SpStartScreen(SP_SCRN_REPAIR_CHECK_HIVES,
|
|
0,
|
|
8,
|
|
TRUE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE
|
|
);
|
|
|
|
SpDisplayStatusText(SP_STAT_REG_LOADING_HIVES,DEFAULT_STATUS_ATTRIBUTE);
|
|
|
|
//
|
|
// Load each template hive we care about from the target tree.
|
|
//
|
|
|
|
for (h = 0; h < RepairHiveMax; h++) {
|
|
|
|
pwstrTemp1 = TemporaryBuffer;
|
|
pwstrTemp2 = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
|
|
|
|
if( h != RepairHiveUser ) {
|
|
//
|
|
// Form the name of the hive file.
|
|
// This is partitionpath + sysroot + system32\config + the hive name.
|
|
//
|
|
|
|
wcscpy(pwstrTemp1,PartitionPath);
|
|
SpConcatenatePaths(pwstrTemp1,SystemRoot);
|
|
SpConcatenatePaths(pwstrTemp1,L"system32\\config");
|
|
SpConcatenatePaths(pwstrTemp1,HiveNames[h]);
|
|
|
|
} else {
|
|
wcscpy(pwstrTemp1,PartitionPath);
|
|
SpConcatenatePaths(pwstrTemp1,DEFAULT_USER_PATH);
|
|
SpConcatenatePaths(pwstrTemp1,HiveNames[h]);
|
|
}
|
|
|
|
//
|
|
// First we must verify that the hive file exists. We have to do
|
|
// this because loading a hive will create one if it didn't already
|
|
// exist!
|
|
//
|
|
if(!SpFileExists(pwstrTemp1, FALSE)) {
|
|
HiveLoaded[h] = 0;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Form the path of the key into which we will
|
|
// load the hive. We'll use the convention that
|
|
// a hive will be loaded into \registry\machine\x<hivename>.
|
|
//
|
|
|
|
wcscpy(pwstrTemp2,LOCAL_MACHINE_KEY_NAME);
|
|
SpConcatenatePaths(pwstrTemp2,L"x");
|
|
wcscat(pwstrTemp2,HiveNames[h]);
|
|
|
|
//
|
|
// Attempt to load the hive.
|
|
//
|
|
|
|
HiveLoaded[h] = 0;
|
|
Status = SpLoadUnloadKey(NULL,NULL,pwstrTemp2,pwstrTemp1);
|
|
|
|
if (NT_SUCCESS(Status) || Status == STATUS_NO_MEMORY) {
|
|
|
|
//
|
|
// If the reason the hive did not load is because of not
|
|
// enough memory. We assume the hive is OK.
|
|
//
|
|
|
|
HiveLoaded[h] = 1;
|
|
|
|
//
|
|
// Unload the hive.
|
|
//
|
|
|
|
SpLoadUnloadKey(NULL,NULL,pwstrTemp2,NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sam and security hives must be updated together. If any one of
|
|
// them failed to load, we must update both.
|
|
//
|
|
|
|
if ((HiveLoaded[RepairHiveSecurity] == 0) ||
|
|
(HiveLoaded[RepairHiveSam] == 0)) {
|
|
HiveLoaded[RepairHiveSam] = 0;
|
|
HiveLoaded[RepairHiveSecurity] = 0;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SppRepairHives(
|
|
PVOID MasterSifHandle,
|
|
PWSTR WinntPartition,
|
|
PWSTR WinntPartitionDirectory,
|
|
PWSTR SourceDevicePath,
|
|
PWSTR DirectoryOnSourceDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine inspects hives and let user choose the hives which he
|
|
wants to repair.
|
|
|
|
Arguments:
|
|
|
|
MasterSifHandle - The handle of textsetup.sif
|
|
|
|
WinntPartition - The nt name of Winnt partition
|
|
|
|
WinntPartitionDirectory - The directory name of winnt installation
|
|
|
|
SourceDevicePath - The NT name of source device which contains hives
|
|
|
|
DirectoryOnSourceDevice - The directory name of source device
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Do not change the order of the files in 'HiveNames' array.
|
|
// If you do that, you also need to change the order of the
|
|
// enum 'RepairHive' in spntfix.h
|
|
//
|
|
PWSTR HiveNames[RepairHiveMax] = { L"system",L"software",L"default",L"ntuser.dat",L"security",L"sam"};
|
|
ULONG HiveLoaded[RepairHiveMax];
|
|
PVOID Menu;
|
|
ULONG MenuTopY;
|
|
ULONG ValidKeys[] = { KEY_F3, ASCI_CR, 0 };
|
|
ULONG ValidKeys1[] = { KEY_F3, ASCI_CR, 0 };
|
|
ULONG i;
|
|
ULONG_PTR InitialHighlight, OptionChosen;
|
|
PWSTR MenuItem, TargetPath, p;
|
|
ULONG Keypress, MessageIds[RepairHiveMax];
|
|
BOOLEAN Selectable;
|
|
NTSTATUS Status;
|
|
ULONG ListBoxWidth, curLBEntryWidth;
|
|
BOOLEAN DetermineHivesToRepair;
|
|
|
|
//
|
|
// Inspect hives by loading hives to determine which hives need to be
|
|
// fixed.
|
|
//
|
|
|
|
SppInspectHives(WinntPartition,
|
|
WinntPartitionDirectory,
|
|
HiveLoaded,
|
|
HiveNames);
|
|
|
|
// BCL - Seagate: If doing ASR, don't do the menu.
|
|
if ( SpDrEnabled() ) {
|
|
goto UpdateTheHives;
|
|
}
|
|
|
|
//
|
|
// Initialize hive menu item message id.
|
|
//
|
|
|
|
for (i = 0; i < RepairHiveMax; i++) {
|
|
if (i == 0) {
|
|
MessageIds[i] = SP_REPAIR_HIVE_ITEM_1;
|
|
} else {
|
|
MessageIds[i] = MessageIds[i - 1] + 1;
|
|
}
|
|
}
|
|
|
|
|
|
DetermineHivesToRepair = TRUE;
|
|
while(DetermineHivesToRepair) {
|
|
//
|
|
// Display the text that goes above the menu on the partitioning screen.
|
|
//
|
|
|
|
SpDisplayScreen(SP_SCRN_REPAIR_HIVE_MENU,3,CLIENT_TOP+1);
|
|
|
|
//
|
|
// Calculate menu placement. Leave one blank line
|
|
// and one line for a frame.
|
|
//
|
|
|
|
MenuTopY = NextMessageTopLine + (SplangQueryMinimizeExtraSpacing() ? 2 : 5);
|
|
|
|
//
|
|
// Create a menu.
|
|
// First, find the longest string, so we can size the listbox accordingly
|
|
//
|
|
ListBoxWidth = HIVE_LIST_BOX_WIDTH; // It will be at least this wide
|
|
for (i = 0; i <= RepairHiveMax; i++ ) {
|
|
if (i == RepairHiveMax) {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
SP_REPAIR_MENU_ITEM_CONTINUE);
|
|
} else {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
MessageIds[i]);
|
|
}
|
|
if((curLBEntryWidth = SplangGetColumnCount(TemporaryBuffer)+(2*MENU_INDENT)) > ListBoxWidth) {
|
|
ListBoxWidth = min(curLBEntryWidth, MENU_WIDTH);
|
|
}
|
|
}
|
|
|
|
Menu = SpMnCreate(
|
|
MENU_LEFT_X,
|
|
MenuTopY,
|
|
ListBoxWidth,
|
|
HIVE_LIST_BOX_HEIGHT
|
|
);
|
|
|
|
ASSERT(Menu);
|
|
|
|
//
|
|
// Build up a menu of hives
|
|
//
|
|
|
|
for (i = 0; i <= RepairHiveMax; i++ ) {
|
|
if (i == RepairHiveSam) {
|
|
Selectable = FALSE;
|
|
} else {
|
|
Selectable = TRUE;
|
|
}
|
|
if (i == RepairHiveMax) {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
SP_REPAIR_MENU_ITEM_CONTINUE);
|
|
} else {
|
|
SpFormatMessage(TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
MessageIds[i]);
|
|
p = TemporaryBuffer;
|
|
if (HiveLoaded[i] || ( i == RepairHiveSam )) {
|
|
p[1] = L' ';
|
|
} else {
|
|
p[1] = L'X';
|
|
}
|
|
}
|
|
SpMnAddItem(Menu,
|
|
TemporaryBuffer,
|
|
MENU_LEFT_X+MENU_INDENT,
|
|
ListBoxWidth-(2*MENU_INDENT),
|
|
Selectable,
|
|
i
|
|
);
|
|
}
|
|
InitialHighlight = RepairHiveMax;
|
|
|
|
//
|
|
// Initialize the status line.
|
|
//
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CHANGE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
DisplayMenu:
|
|
|
|
//
|
|
// Display the menu
|
|
//
|
|
|
|
SpMnDisplay(
|
|
Menu,
|
|
InitialHighlight,
|
|
TRUE,
|
|
ValidKeys,
|
|
NULL,
|
|
NULL,
|
|
&Keypress,
|
|
&OptionChosen
|
|
);
|
|
|
|
//
|
|
// Now act on the user's selection.
|
|
//
|
|
|
|
switch(Keypress) {
|
|
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
case ASCI_CR:
|
|
if (OptionChosen == RepairHiveMax) {
|
|
SpMnDestroy(Menu);
|
|
DetermineHivesToRepair = FALSE;
|
|
} else {
|
|
HiveLoaded[OptionChosen] ^= 1;
|
|
MenuItem = SpMnGetText(Menu, OptionChosen);
|
|
if ((HiveLoaded[OptionChosen] != 0) ||
|
|
(OptionChosen == RepairHiveSam)){
|
|
MenuItem[1] = L' ';
|
|
} else {
|
|
MenuItem[1] = L'X';
|
|
}
|
|
|
|
//
|
|
// Security and sam must go together.
|
|
//
|
|
|
|
HiveLoaded[RepairHiveSam] = HiveLoaded[RepairHiveSecurity];
|
|
InitialHighlight = OptionChosen;
|
|
goto DisplayMenu;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
UpdateTheHives:
|
|
|
|
//
|
|
// At this point user has decided which hives to repair.
|
|
// We will copy the hives from repair disk to
|
|
// Winnt\system32\config directory.
|
|
//
|
|
|
|
for (i = 0; i < RepairHiveMax; i++ ) {
|
|
|
|
// BCL - Seagate: Don't do ntuser.dat. As of 4/17/98, there is no
|
|
// copy of this file to copy from.
|
|
if ( SpDrEnabled() && i == RepairHiveUser ) {
|
|
continue;
|
|
}
|
|
|
|
if (HiveLoaded[i] == 0) {
|
|
|
|
//
|
|
// Form Target path
|
|
//
|
|
|
|
if( i != RepairHiveUser ) {
|
|
wcscpy(TemporaryBuffer, WinntPartition);
|
|
SpConcatenatePaths(TemporaryBuffer, WinntPartitionDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer, L"\\SYSTEM32\\CONFIG");
|
|
TargetPath = SpDupStringW(TemporaryBuffer);
|
|
} else {
|
|
wcscpy(TemporaryBuffer, WinntPartition);
|
|
SpConcatenatePaths(TemporaryBuffer, WinntPartitionDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer, DEFAULT_USER_PATH);
|
|
TargetPath = SpDupStringW(TemporaryBuffer);
|
|
}
|
|
|
|
Status = SppRepairFile(MasterSifHandle,
|
|
TargetPath,
|
|
HiveNames[i],
|
|
SourceDevicePath,
|
|
DirectoryOnSourceDevice,
|
|
HiveNames[i],
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Tell user we couldn't do it. Options are to continue or exit.
|
|
//
|
|
|
|
SpStartScreen(
|
|
SP_SCRN_REPAIR_HIVE_FAIL,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE
|
|
);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
switch(SpWaitValidKey(ValidKeys1,NULL,NULL)) {
|
|
case ASCI_CR:
|
|
return;
|
|
break;
|
|
|
|
case KEY_F3:
|
|
SpConfirmExit();
|
|
break;
|
|
}
|
|
}
|
|
SpMemFree(TargetPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SpRepairWinnt(
|
|
IN PVOID LogFileHandle,
|
|
IN PVOID MasterSifHandle,
|
|
IN PWSTR SourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a the top level repair rutine. It calls worker routines
|
|
for each repair options that user selected.
|
|
|
|
Arguments:
|
|
|
|
LogFileHandle - Handle of the setup.log
|
|
|
|
MasterSifHandle - Handle of the txtsetup.sif
|
|
|
|
SourceDevicePath - The NT name for the repair source device.
|
|
|
|
DirectoryOnSourceDevice - The directory name on the repair source
|
|
device which contains the source files.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
PWSTR SystemPartition, SystemPartitionDirectory;
|
|
PWSTR WinntPartition, WinntPartitionDirectory;
|
|
PWSTR HiveRepairSourceDevice, DirectoryOnHiveRepairSource;
|
|
|
|
//
|
|
// Initialize the diamond decompression engine.
|
|
//
|
|
SpdInitialize();
|
|
|
|
//
|
|
// Determine SystemPartition, SystemPartitionDirectory.
|
|
// WinntParition and WinntPartitionDirectory of the WINNT
|
|
// installation to be repaired.
|
|
//
|
|
|
|
SppGetRepairPathInformation(LogFileHandle,
|
|
&SystemPartition,
|
|
&SystemPartitionDirectory,
|
|
&WinntPartition,
|
|
&WinntPartitionDirectory
|
|
);
|
|
|
|
//
|
|
// If repair involves disk access, then run autochk on Nt and system
|
|
// partitions.
|
|
//
|
|
if( RepairItems[RepairFiles]
|
|
#ifdef _X86_
|
|
||
|
|
RepairItems[RepairNvram]
|
|
#endif
|
|
) {
|
|
PDISK_REGION SystemPartitionRegion;
|
|
PDISK_REGION WinntPartitionRegion;
|
|
|
|
WinntPartitionRegion = SpRegionFromNtName( WinntPartition,
|
|
PartitionOrdinalCurrent);
|
|
|
|
SystemPartitionRegion = SpRegionFromNtName( SystemPartition,
|
|
PartitionOrdinalCurrent);
|
|
|
|
if( !RepairNoCDROMDrive ) {
|
|
//
|
|
// If we know that the system doesn't have a CD-ROM drive,
|
|
// then don't even attempt to run autochk.
|
|
//
|
|
SpRunAutochkOnNtAndSystemPartitions( MasterSifHandle,
|
|
WinntPartitionRegion,
|
|
SystemPartitionRegion,
|
|
SourceDevicePath,
|
|
DirectoryOnSourceDevice,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify and repair security of the directories that form the NT tree
|
|
// This needs to be done before repairing the hives because the
|
|
// system32\config directory might not be there anymore!
|
|
//
|
|
SppVerifyAndRepairNtTreeAccess(MasterSifHandle,
|
|
WinntPartition,
|
|
WinntPartitionDirectory,
|
|
SystemPartition,
|
|
SystemPartitionDirectory
|
|
);
|
|
|
|
#if 0
|
|
// BCL - Seagate - the RepairHives member has been removed from the
|
|
// struct
|
|
|
|
if (RepairItems[RepairHives]) {
|
|
|
|
//
|
|
// User has selected to repair hives. If user has provided the
|
|
// ER disk, we will copy the hive from ER disk to repair damaged
|
|
// hives. Otherwise we copy the hive from the directory where
|
|
// setup.log was loaded.
|
|
//
|
|
|
|
if (RepairFromErDisk) {
|
|
HiveRepairSourceDevice = L"\\device\\floppy0";
|
|
DirectoryOnHiveRepairSource = L"";
|
|
} else {
|
|
HiveRepairSourceDevice = WinntPartition;
|
|
wcscpy(TemporaryBuffer, WinntPartitionDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
|
|
DirectoryOnHiveRepairSource = SpDupStringW(TemporaryBuffer);
|
|
}
|
|
SppRepairHives(MasterSifHandle,
|
|
WinntPartition,
|
|
WinntPartitionDirectory,
|
|
HiveRepairSourceDevice,
|
|
DirectoryOnHiveRepairSource
|
|
);
|
|
if (!RepairFromErDisk) {
|
|
SpMemFree(DirectoryOnHiveRepairSource);
|
|
}
|
|
}
|
|
if (RepairItems[RepairFiles]) {
|
|
SppRepairWinntFiles(LogFileHandle,
|
|
MasterSifHandle,
|
|
SourceDevicePath,
|
|
DirectoryOnSourceDevice,
|
|
SystemPartition,
|
|
SystemPartitionDirectory,
|
|
WinntPartition,
|
|
WinntPartitionDirectory
|
|
);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// The code to repair nvram variables and boot sector is
|
|
// incorporated into SpStartSetup.
|
|
//
|
|
|
|
//
|
|
// Load the software hive, and and set the repair flag under Winlogon,
|
|
// so that winlogon can recreate the start menu groups and items for
|
|
// the default user.
|
|
//
|
|
SppRepairStartMenuGroupsAndItems( WinntPartition,
|
|
WinntPartitionDirectory );
|
|
|
|
//
|
|
// Terminate diamond.
|
|
//
|
|
SpdTerminate();
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SppVerifyAndRepairNtTreeAccess(
|
|
IN PVOID MasterSifHandle,
|
|
IN PWSTR TargetDevicePath,
|
|
IN PWSTR DirectoryOnTargetDevice,
|
|
IN PWSTR SystemPartition,
|
|
IN PWSTR SystemPartitionDirectory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine examines whether or not the directories that form the
|
|
NT tree are accessible, and set the appropriate security descriptor
|
|
in each directory, when necessary.
|
|
|
|
Arguments:
|
|
|
|
MasterSifHandle - Hanle of the txtsetup.sif
|
|
|
|
TargetDevicePath - supplies the nt name of the target device
|
|
|
|
DirectoryOnTargetDevice - the name of the winnt directory on target
|
|
device
|
|
|
|
SystemPartition - supplies the nt name of the target device (non-x86 platforms)
|
|
|
|
SystemPartitionDirectory - the name of the winnt directory on target
|
|
device (non-x86 platforms)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG Count, i;
|
|
PWSTR SectionName = L"WinntDirectories";
|
|
PWSTR DirectoryName;
|
|
PWSTR TargetPath;
|
|
PWSTR WinNtDirectory;
|
|
NTSTATUS Status;
|
|
|
|
SpDisplayStatusText(SP_STAT_SETUP_IS_EXAMINING_DIRS, DEFAULT_STATUS_ATTRIBUTE);
|
|
if(SpIsArc()){
|
|
//
|
|
// Make sure that on ARC platforms, the system partition directory
|
|
// exists (re-create it if it doesn't exist)
|
|
//
|
|
SpCreateDirectory(SystemPartition,NULL,SystemPartitionDirectory,0,0);
|
|
}
|
|
|
|
WinNtDirectory = ( PWSTR )SpMemAlloc( ( wcslen( TargetDevicePath ) + 1 +
|
|
wcslen( DirectoryOnTargetDevice ) + 1 +
|
|
1 )*sizeof( WCHAR ) );
|
|
TargetPath = ( PWSTR )SpMemAlloc( 1024 );
|
|
if( ( WinNtDirectory == NULL ) ||
|
|
( TargetPath == NULL ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to allocate memory for WinNtDirectory \n"));
|
|
if( WinNtDirectory != NULL ) {
|
|
SpMemFree( WinNtDirectory );
|
|
}
|
|
if( TargetPath != NULL ) {
|
|
SpMemFree( TargetPath );
|
|
}
|
|
return;
|
|
}
|
|
wcscpy( WinNtDirectory, TargetDevicePath );
|
|
SpConcatenatePaths( WinNtDirectory, DirectoryOnTargetDevice );
|
|
|
|
Count = SpCountLinesInSection(MasterSifHandle, SectionName);
|
|
//
|
|
// Note that in the loop below, the maximum value for 'i' is 'Count'
|
|
// instead of 'Count-1'. This is because we need to create the directory
|
|
// 'Profiles\\Default User' which cannot be listed in txtsetup.sif.
|
|
// This is due to pre-install requirements, and DOS limitation regarding
|
|
// long file names.
|
|
//
|
|
for (i = 0; i <= Count; i++) {
|
|
if( i != Count ) {
|
|
DirectoryName = SpGetSectionLineIndex(MasterSifHandle,SectionName,i,0);
|
|
} else {
|
|
//
|
|
// Due to pre-installation requirements, and DOS limitation
|
|
// regarding long file names, the "Default User" directory
|
|
// is not specified on txtsetup.sif, as the other directories.
|
|
// This directory is treated as a special case in the
|
|
// repair process.
|
|
//
|
|
DirectoryName = DEFAULT_USER_PATH;
|
|
}
|
|
if(!DirectoryName) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
continue;
|
|
}
|
|
wcscpy( TargetPath, WinNtDirectory );
|
|
//
|
|
// Make sure that TargetPath doesn't contain '\' as the last character
|
|
//
|
|
if(!((DirectoryName[0] == L'\\') && (DirectoryName[1] == 0))) {
|
|
SpConcatenatePaths( TargetPath, DirectoryName );
|
|
}
|
|
|
|
Status = SpVerifyFileAccess( TargetPath,
|
|
STANDARD_RIGHTS_READ |
|
|
FILE_READ_ATTRIBUTES |
|
|
FILE_LIST_DIRECTORY |
|
|
FILE_ADD_FILE |
|
|
FILE_ADD_SUBDIRECTORY |
|
|
FILE_TRAVERSE |
|
|
WRITE_DAC |
|
|
SYNCHRONIZE );
|
|
|
|
//
|
|
// If unable to access the directory, try to determine why.
|
|
// If it is because of access denied, change the directory security.
|
|
// If it is because the directory doesn't exist, then create it.
|
|
//
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
if ((Status == STATUS_ACCESS_DENIED)||(Status == STATUS_PRIVILEGE_NOT_HELD) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Security of %ls, must be fixed. Status = %x\n", TargetPath, Status ));
|
|
Status = SpSetDefaultFileSecurity( TargetPath );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to change security of %ls. Status = %x\n", TargetPath, Status ));
|
|
}
|
|
} else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
if(((DirectoryName[0] == L'\\') && (DirectoryName[1] == 0))) {
|
|
//
|
|
// Create the target directory
|
|
//
|
|
SpCreateDirectory( TargetDevicePath,
|
|
NULL,
|
|
DirectoryOnTargetDevice,
|
|
0,
|
|
0);
|
|
} else {
|
|
SpCreateDirectory( TargetDevicePath,
|
|
DirectoryOnTargetDevice,
|
|
DirectoryName,
|
|
0,
|
|
0);
|
|
}
|
|
} else {
|
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to access directory %ls. Status = %x\n", TargetPath, Status ));
|
|
}
|
|
}
|
|
}
|
|
|
|
if( WinNtDirectory != NULL ) {
|
|
SpMemFree( WinNtDirectory );
|
|
}
|
|
if( TargetPath != NULL ) {
|
|
SpMemFree( TargetPath );
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SppVerifyAndRepairVdmFiles(
|
|
IN PVOID LogFileHandle,
|
|
IN PWSTR TargetDevicePath,
|
|
IN PWSTR DirectoryOnTargetDevice,
|
|
IN PBOOLEAN RepairWithoutConfirming
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine repairs the Vdm configuration files listed on
|
|
'Files.InRepairDirectory' of setup.log. Currently, such files are:
|
|
autoexec.nt and config.nt. It is assumed that files in this section
|
|
will be copied from the emergency repair disk, or from the repair
|
|
directory.
|
|
|
|
Arguments:
|
|
|
|
LogFileHandle - Handle of the setup.log
|
|
|
|
TargetDevicePath - supplies the nt name of the target device
|
|
|
|
DirectoryOnTargetDevice - the name of the winnt directory on target
|
|
device
|
|
|
|
RepairWithoutConfirming - Pointer to a flag that indicates whether or not
|
|
setup should repair files without confirming
|
|
with the user.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PWSTR FullTargetName, ChecksumString;
|
|
PWSTR TargetDirectory, TargetFileName;
|
|
PWSTR SourceFileName;
|
|
ULONG Checksum, FileChecksum, PrefixLength, Length, Count, i;
|
|
BOOLEAN IsNtImage, IsValid, RepairFile;
|
|
BOOLEAN RedrawGauge = TRUE;
|
|
FILE_TO_COPY FileToCopy;
|
|
PWSTR DevicePath, Directory;
|
|
PWSTR SectionName = SIF_NEW_REPAIR_FILES_IN_REPAIR_DIR;
|
|
|
|
//
|
|
// Allocate a SMALL buffer for local use and init FileToCopy struct
|
|
//
|
|
|
|
TargetDirectory = NULL;
|
|
FullTargetName = SpMemAlloc(1024);
|
|
*FullTargetName = 0;
|
|
FileToCopy.Next = NULL;
|
|
FileToCopy.Flags = COPY_ALWAYS;
|
|
FileToCopy.AbsoluteTargetDirectory = TRUE;
|
|
|
|
FileToCopy.TargetDevicePath = TargetDevicePath;
|
|
SpConcatenatePaths(FullTargetName,TargetDevicePath);
|
|
|
|
PrefixLength = wcslen(FullTargetName);
|
|
|
|
Count = SpCountLinesInSection(LogFileHandle,SectionName);
|
|
for (i = 0; i < Count; i++) {
|
|
if (RedrawGauge) {
|
|
SppRepairScreenRepaint(NULL, NULL, TRUE);
|
|
RedrawGauge = FALSE;
|
|
}
|
|
SpTickGauge(RepairGauge);
|
|
|
|
//
|
|
// Initialize target fullname to be DevicePath+Directory for
|
|
// system partition file or DevicePath for Winnt files
|
|
//
|
|
|
|
FullTargetName[PrefixLength] = (WCHAR)NULL;
|
|
|
|
//
|
|
// If we allocate space for TargetDirectory we must free it.
|
|
//
|
|
|
|
if (TargetDirectory) {
|
|
SpMemFree(TargetDirectory);
|
|
TargetDirectory = NULL;
|
|
}
|
|
TargetFileName = SpGetKeyName(LogFileHandle,SectionName,i);
|
|
if(!TargetFileName) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
|
|
SpConcatenatePaths(FullTargetName,TargetFileName);
|
|
SpDisplayStatusText(SP_STAT_EXAMINING_WINNT,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
TargetFileName);
|
|
|
|
ChecksumString = SpGetSectionLineIndex(LogFileHandle,SectionName,i,1);
|
|
if(!ChecksumString) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
|
|
Checksum = (ULONG)SpStringToLong(ChecksumString, NULL, 16);
|
|
|
|
SpValidateAndChecksumFile(NULL,FullTargetName,&IsNtImage,&FileChecksum,&IsValid);
|
|
|
|
//
|
|
// If the image is invalid or the file on the target is not the
|
|
// original file copied by setup, we will recopy it.
|
|
//
|
|
|
|
if (!IsValid || FileChecksum != Checksum) {
|
|
|
|
//
|
|
// Ask user if he wants to repair the file
|
|
//
|
|
|
|
RepairFile = ( *RepairWithoutConfirming )?
|
|
TRUE :
|
|
SppRepairReportError(
|
|
TRUE,
|
|
SP_SCRN_REPAIR_FILE_MISMATCH,
|
|
SP_TEXT_REPAIR_INF_ERROR_4,
|
|
TargetFileName,
|
|
i,
|
|
RepairWithoutConfirming);
|
|
|
|
RedrawGauge = TRUE;
|
|
if (!RepairFile) {
|
|
continue;
|
|
}
|
|
SpDisplayStatusText(SP_STAT_REPAIR_WINNT,
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
TargetFileName);
|
|
|
|
|
|
//
|
|
// TargetName contains path and filename.
|
|
// We need to seperate them.
|
|
//
|
|
|
|
TargetDirectory = SpDupStringW(TargetFileName);
|
|
Length = wcslen(TargetDirectory);
|
|
while (Length) {
|
|
if (TargetDirectory[Length] == L'\\') {
|
|
TargetDirectory[Length] = 0;
|
|
TargetFileName = &TargetDirectory[Length + 1];
|
|
break;
|
|
} else {
|
|
Length--;
|
|
}
|
|
}
|
|
if (Length == 0) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
FileToCopy.TargetFilename = TargetFileName;
|
|
FileToCopy.TargetDirectory = TargetDirectory;
|
|
|
|
SourceFileName = SpGetSectionLineIndex(LogFileHandle,SectionName,i,0);
|
|
if (!SourceFileName) {
|
|
SppRepairReportError(FALSE,
|
|
SP_SCRN_REPAIR_INF_ERROR_0,
|
|
SP_TEXT_REPAIR_INF_ERROR_1,
|
|
SectionName,
|
|
i,
|
|
NULL);
|
|
RedrawGauge = TRUE;
|
|
continue;
|
|
}
|
|
FileToCopy.SourceFilename = SourceFileName;
|
|
|
|
//
|
|
// Find out whether the source file should come from the
|
|
// Emergency Repair Disk or the Repair directory
|
|
//
|
|
|
|
if (RepairFromErDisk) {
|
|
BOOLEAN rs;
|
|
PWSTR szDiskName;
|
|
PWSTR szDevicePath = SpDupStringW(L"\\device\\floppy0");
|
|
|
|
//
|
|
// Fetch the generic repair disk name.
|
|
//
|
|
|
|
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),
|
|
SP_TEXT_REPAIR_DISK_NAME);
|
|
szDiskName = SpDupStringW(TemporaryBuffer);
|
|
|
|
//
|
|
// Prompt for the disk, based on the setup media type.
|
|
//
|
|
|
|
rs = SpPromptForDisk(
|
|
szDiskName,
|
|
szDevicePath,
|
|
SETUP_LOG_FILENAME,
|
|
FALSE, // if disk is in already dont prompt
|
|
FALSE, // allow escape
|
|
TRUE, // warn for multiple prompts
|
|
NULL // don't care about redraw flag
|
|
);
|
|
|
|
SpMemFree(szDiskName);
|
|
SpMemFree(szDevicePath);
|
|
|
|
RedrawGauge = TRUE;
|
|
if (rs == FALSE) {
|
|
continue;
|
|
}
|
|
DevicePath = L"\\device\\floppy0";
|
|
wcscpy( TemporaryBuffer, L"\\" );
|
|
Directory = SpDupStringW(TemporaryBuffer); // OemSourceDirectory;
|
|
} else {
|
|
|
|
RedrawGauge = TRUE;
|
|
DevicePath = TargetDevicePath;
|
|
wcscpy( TemporaryBuffer, DirectoryOnTargetDevice );
|
|
SpConcatenatePaths( TemporaryBuffer, SETUP_REPAIR_DIRECTORY );
|
|
Directory = SpDupStringW(TemporaryBuffer);
|
|
}
|
|
|
|
//
|
|
// Copy the file.
|
|
//
|
|
|
|
SpCopyFileWithRetry(
|
|
&FileToCopy,
|
|
DevicePath,
|
|
Directory,
|
|
NULL,
|
|
NULL, // TargetRoot -> NULL
|
|
0, // SystemPartitionFiles ? ATTR_RHS : 0,
|
|
SppRepairScreenRepaint,
|
|
NULL, // Do not want checksum
|
|
NULL, // Do not want to know if file was skipped
|
|
0
|
|
);
|
|
|
|
SpMemFree( Directory );
|
|
}
|
|
}
|
|
|
|
SpMemFree(FullTargetName);
|
|
if (RedrawGauge) {
|
|
SppRepairScreenRepaint(NULL, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
|