windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/copy.c
2020-09-26 16:20:57 +08:00

643 lines
20 KiB
C

#include "setupp.h"
#pragma hdrstop
#if 0 // This function appears to never be used.
BOOL
EnqueueFileCopies(
IN HINF hInf,
IN HSPFILEQ FileQ,
IN PCWSTR Section,
IN PCWSTR TargetRoot
)
{
INFCONTEXT InfContext;
BOOL LineExists;
WCHAR System32Dir[MAX_PATH];
PCWSTR SourceFilename,TargetFilename;
BOOL b;
GetSystemDirectory(System32Dir,MAX_PATH);
LineExists = SetupFindFirstLine(hInf,Section,NULL,&InfContext);
while(LineExists) {
//
// Fetch source and target filenames.
//
TargetFilename = pSetupGetField(&InfContext,1);
if(!TargetFilename) {
return(FALSE);
}
SourceFilename = pSetupGetField(&InfContext,2);
if(!SourceFilename) {
SourceFilename = TargetFilename;
}
//
// Enqueue the file for copy.
//
b = SetupQueueCopy(
FileQ,
System32Dir,
NULL,
SourceFilename,
NULL,
NULL,
TargetRoot,
TargetFilename,
BaseCopyStyle
);
if(!b) {
return(FALSE);
}
LineExists = SetupFindNextLine(&InfContext,&InfContext);
}
return(TRUE);
}
#endif
BOOL
SideBySidePopulateCopyQueue(
SIDE_BY_SIDE* Sxs,
HSPFILEQ FileQ, OPTIONAL
PCWSTR AssembliesRootSource OPTIONAL
)
{
BOOL Success = FALSE;
UINT SourceId = 0;
WCHAR DiskNameBuffer[MAX_PATH];
WCHAR PromptForSetupPath[MAX_PATH];
WCHAR AssembliesRootDirectoryFound[MAX_PATH];
DWORD cchAssembliesRootDirectoryFound = sizeof(AssembliesRootDirectoryFound);
DWORD Err;
WCHAR AssembliesRootDirectory[MAX_PATH];
PCWSTR InfField = NULL;
INFCONTEXT InfContext = {0};
BOOL LineExists = FALSE;
SXS_INSTALLW InstallData;
SXS_INSTALL_REFERENCEW InstallReference;
ASSERT(Sxs != NULL);
//
// we depend on these having been initialized, and we are not supposed to
// be called in MiniSetup or OobeSetup
//
ASSERT(SourcePath[0] != 0);
ASSERT(SyssetupInf != NULL);
ASSERT(SyssetupInf != INVALID_HANDLE_VALUE);
ASSERT(!MiniSetup);
ASSERT(!OobeSetup);
//
// first, don't fail to give safe values, since we always try to cleanup
//
Sxs->Dll = NULL;
Sxs->BeginAssemblyInstall = NULL;
Sxs->EndAssemblyInstall = NULL;
Sxs->InstallW = NULL;
Sxs->Context = NULL;
//
// then commence with initialization that can fail
//
if (!(Sxs->Dll = LoadLibraryW(SXS_DLL_NAME_W))) {
goto Exit;
}
if (!(Sxs->BeginAssemblyInstall = (PSXS_BEGIN_ASSEMBLY_INSTALL)GetProcAddress(Sxs->Dll, SXS_BEGIN_ASSEMBLY_INSTALL))) {
goto Exit;
}
if (!(Sxs->EndAssemblyInstall = (PSXS_END_ASSEMBLY_INSTALL)GetProcAddress(Sxs->Dll, SXS_END_ASSEMBLY_INSTALL))) {
goto Exit;
}
if (!(Sxs->InstallW = (PSXS_INSTALL_W)GetProcAddress(Sxs->Dll, SXS_INSTALL_W))) {
goto Exit;
}
if (!Sxs->BeginAssemblyInstall(
SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NOT_TRANSACTIONAL
| SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NO_VERIFY
| SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_REPLACE_EXISTING,
(FileQ != NULL) ? SXS_INSTALLATION_FILE_COPY_CALLBACK_SETUP_COPY_QUEUE : NULL,
FileQ, // callback context
NULL, // impersonation callback
NULL, // impersonation context
&Sxs->Context
)) {
goto Exit;
}
//
// Set up the reference data to indicate that all of these are OS-installed
// assemblies.
//
ZeroMemory(&InstallReference, sizeof(InstallReference));
InstallReference.cbSize = sizeof(InstallReference);
InstallReference.dwFlags = 0;
InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
//
// Let's get the source disk name of this assembly - we'll need it to
// pass around as the prompt.
//
if ( !SetupGetSourceFileLocation(
SyssetupInf,
NULL,
L"shell32.dll",
&SourceId,
NULL,
0,
NULL
) )
goto Exit;
if ( !SetupGetSourceInfo(
SyssetupInf,
SourceId,
SRCINFO_DESCRIPTION,
DiskNameBuffer,
sizeof(DiskNameBuffer),
NULL
) )
goto Exit;
if (AssembliesRootSource) {
//
// Set up the structure to call off to the installer
//
memset(&InstallData, 0, sizeof(InstallData));
InstallData.cbSize = sizeof(InstallData);
InstallData.dwFlags = SXS_INSTALL_FLAG_FROM_DIRECTORY |
SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
SXS_INSTALL_FLAG_REFERENCE_VALID |
SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID |
SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID |
SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
SXS_INSTALL_FLAG_CODEBASE_URL_VALID;
InstallData.lpReference = &InstallReference;
InstallData.lpRefreshPrompt = DiskNameBuffer;
InstallData.pvInstallCookie = Sxs->Context;
InstallData.lpCodebaseURL = AssembliesRootSource;
InstallData.lpManifestPath = AssembliesRootSource;
if (!Sxs->InstallW(&InstallData)) {
// abort call will be made in SideBySideFinish
goto Exit;
}
} else {
LineExists = SetupFindFirstLine(SyssetupInf, SXS_INF_ASSEMBLY_DIRECTORIES_SECTION_NAME_W, NULL, &InfContext);
while(LineExists) {
DWORD FileAttributes = 0;
//
// convention introduced specifically for side by side, so that
// x86 files on ia64 might come from \i386\asms instead of \ia64\asms\i386,
// depending on what dosnet.inf and syssetup.inf say:
// a path that does not start with a slash is appended to \$win_nt$.~ls\processor;
// a path that does start with a slash is appended to \$win_nt$.~ls
//
InfField = pSetupGetField(&InfContext, 0);
if(InfField == NULL) {
break;
}
// c:\$win_nt$.~ls
lstrcpyn(AssembliesRootDirectory, SourcePath, MAX_PATH);
if (InfField[0] == '\\' || InfField[0] == '/') {
InfField += 1;
} else {
// c:\$win_nt$.~ls\i386
if (!pSetupConcatenatePaths(AssembliesRootDirectory, PlatformName, MAX_PATH, NULL)) {
goto Exit;
}
}
// stash this away for a little bit
lstrcpyn( PromptForSetupPath, AssembliesRootDirectory, MAX_PATH );
//
// For now, while "staging", we allow the directory to not exist, and to be
// empty (emptiness is silently handled elsewhere by common code), but
// comctl32 will be in an assembly, so assemblies will be mandatory
// for the system to boot to Explorer.exe.
//
// 11/09/2000 (jonwis) If we can't find the assemblies root directory, prompt
// for the installation media. This is ripped straight from the headlines
// of crypto.c and cmdline.c.
//
for (;;) {
Err = SetupPromptForDisk(
MainWindowHandle, // Main window handle
NULL, // Dialog title (defaulted)
DiskNameBuffer, // Name of the disk to request
PromptForSetupPath, // Full path of the asms root
InfField, // We look to see if the dir is there
NULL, // No tag file
IDF_CHECKFIRST | IDF_NOSKIP | IDF_NODETAILS | IDF_NOBROWSE,
AssembliesRootDirectoryFound, // What we'll use to install
cchAssembliesRootDirectoryFound, // How long is that buffer?
NULL
);
// See if what we got back from the prompt is success - if so, is the directory
// really there? We might assume that it is if we get back _SUCCESS...
if ( Err == DPROMPT_SUCCESS ) {
FileAttributes = GetFileAttributes(AssembliesRootDirectoryFound);
if ((FileAttributes != 0xFFFFFFFF) && (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
// copy out the asms directory location that was found, and
// stop looking.
lstrcpyn(AssembliesRootDirectory, AssembliesRootDirectoryFound, MAX_PATH);
break;
}
} else {
break;
}
};
// c:\$win_nt$.~ls\i386\asms
if (!pSetupConcatenatePaths(AssembliesRootDirectory, InfField, MAX_PATH, NULL)) {
goto Exit;
}
//
// If we didn't get a success (ie: we broke out of the loop), fail the
// installation. Heinous, but MarianT (setup dev) suggests this is the
// best method.
//
if ( Err != DPROMPT_SUCCESS )
goto Exit;
//
// Set up this structure to call off into SXS to do the installation
// for us.
//
ZeroMemory(&InstallData, sizeof(InstallData));
InstallData.cbSize = sizeof(InstallData);
InstallData.dwFlags = SXS_INSTALL_FLAG_FROM_DIRECTORY |
SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE |
SXS_INSTALL_FLAG_REFERENCE_VALID |
SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID |
SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID |
SXS_INSTALL_FLAG_INSTALLED_BY_OSSETUP |
SXS_INSTALL_FLAG_CODEBASE_URL_VALID;
InstallData.lpManifestPath = AssembliesRootDirectory;
InstallData.lpReference = &InstallReference;
InstallData.lpRefreshPrompt = DiskNameBuffer;
InstallData.pvInstallCookie = Sxs->Context;
InstallData.lpCodebaseURL = SourcePath;
if (!Sxs->InstallW( &InstallData )) {
// abort call will be made in SideBySideFinish
goto Exit;
}
LineExists = SetupFindNextLine(&InfContext, &InfContext);
}
}
Success = TRUE;
Exit:
return Success;
}
BOOL
SideBySideFinish(
SIDE_BY_SIDE* Sxs,
BOOL fSuccess
)
{
#define FUNCTION L"SideBySideFinish"
DWORD dwLastError = NO_ERROR;
ASSERT(Sxs != NULL);
//
// failure to load the .dll or get entry points implies lack of success
//
ASSERT(Sxs->Dll != NULL || !fSuccess);
ASSERT(Sxs->EndAssemblyInstall != NULL || !fSuccess);
if (!fSuccess) {
dwLastError = GetLastError();
}
if (Sxs->Context != NULL) {
if (Sxs->EndAssemblyInstall != NULL) {
if (!Sxs->EndAssemblyInstall(
Sxs->Context,
fSuccess ? SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT : SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT,
NULL // reserved out DWORD
)) {
if (fSuccess) {
fSuccess = FALSE;
dwLastError = GetLastError();
}
}
}
Sxs->Context = NULL;
}
if (Sxs->Dll != NULL) {
if (!FreeLibrary(Sxs->Dll)) {
if (fSuccess) {
fSuccess = FALSE;
dwLastError = GetLastError();
}
}
Sxs->Dll = NULL;
}
if (!fSuccess) {
SetLastError(dwLastError);
}
return fSuccess;
#undef FUNCTION
}
BOOL
SideBySideCreateSyssetupContext(
VOID
)
{
#define FUNCTION L"SideBySideCreateSyssetupContext"
BOOL fSuccess = FALSE;
const PPEB Peb = NtCurrentPeb();
ACTCTXW CreateActCtxParams;
HANDLE ActCtxHandle;
ASSERT(Peb->ActivationContextData == NULL);
ASSERT(Peb->ProcessAssemblyStorageMap == NULL);
ASSERT(Peb->SystemAssemblyStorageMap == NULL);
CreateActCtxParams.cbSize = sizeof(CreateActCtxParams);
CreateActCtxParams.dwFlags = (ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_SET_PROCESS_DEFAULT);
CreateActCtxParams.lpResourceName = SXS_MANIFEST_RESOURCE_ID;
ASSERT(MyModuleFileName[0] != 0);
CreateActCtxParams.lpSource = MyModuleFileName;
//
// The error value is INVALID_HANDLE_VALUE.
// ACTCTX_FLAG_SET_PROCESS_DEFAULT has nothing to return upon success, so it returns NULL.
// There is nothing to cleanup upon ACTCTX_FLAG_SET_PROCESS_DEFAULT success, the data
// is referenced in the PEB, and lasts till process shutdown.
//
ActCtxHandle = CreateActCtxW(&CreateActCtxParams);
if (ActCtxHandle == INVALID_HANDLE_VALUE) {
fSuccess = FALSE;
SetupDebugPrint1(L"SETUP: CreateActCtxW failed in " FUNCTION L", LastError is %d\n", GetLastError());
goto Exit;
}
ASSERT(ActCtxHandle == NULL);
fSuccess = TRUE;
Exit:
return fSuccess;
#undef FUNCTION
}
BOOL
CopySystemFiles(
VOID
)
{
BOOL b;
HINF hInf;
HSPFILEQ FileQ;
PVOID Context;
WCHAR Dir[MAX_PATH];
DWORD ScanQueueResult;
b = FALSE;
//hInf = SetupOpenInfFile(L"filelist.inf",NULL,INF_STYLE_WIN4,NULL);
hInf = SyssetupInf;
if(hInf != INVALID_HANDLE_VALUE) {
FileQ = SetupOpenFileQueue();
if(FileQ != INVALID_HANDLE_VALUE) {
b = SetupInstallFilesFromInfSection(
SyssetupInf,
NULL,
FileQ,
Win31Upgrade
? L"Files.Install.CleanInstall.Win31"
: L"Files.Install.CleanInstall",
NULL,
BaseCopyStyle
);
//
// Do the installation of class installers
// We do this here because the installation of class intallers may involve
// file copy. And in this case we can use the existing progress bar.
//
InstallPnpClassInstallers( MainWindowHandle,
hInf,
FileQ );
#if 0
//
// This feature is going away, because we're going to
// build the delete file list using rules
//
if(Win95Upgrade) {
b = b && SetupQueueDeleteSectionW(
FileQ,
hInf,
0,
L"Files.DeleteWin9x.System"
);
b = b && SetupQueueDeleteSectionW(
FileQ,
hInf,
0,
L"Files.DeleteWin9x.Sysroot"
);
}
#endif
if(b) {
b = FALSE;
if(Context = InitSysSetupQueueCallbackEx(MainWindowHandle,
INVALID_HANDLE_VALUE,0,0,NULL)) {
if(!SetupScanFileQueue(
FileQ,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
MainWindowHandle,
NULL,
NULL,
&ScanQueueResult)) {
//
// SetupScanFileQueue should really never
// fail when you don't ask it to call a
// callback routine, but if it does, just
// go ahead and commit the queue.
//
ScanQueueResult = 0;
}
if( ScanQueueResult != 1 ){
b = SetupCommitFileQueue(MainWindowHandle,FileQ,SysSetupQueueCallback,Context);
}
TermSysSetupQueueCallback(Context);
}
}
SetupCloseFileQueue(FileQ);
}
//SetupCloseInfFile(hInf);
}
return(b);
}
BOOL
UpgradeSystemFiles(
VOID
)
{
BOOL b;
HINF hInf;
HSPFILEQ FileQ;
PVOID Context;
WCHAR Dir[MAX_PATH];
DWORD ScanQueueResult;
b = FALSE;
//hInf = SetupOpenInfFile(L"filelist.inf",NULL,INF_STYLE_WIN4,NULL);
hInf = SyssetupInf;
if(hInf != INVALID_HANDLE_VALUE) {
FileQ = SetupOpenFileQueue();
if(FileQ != INVALID_HANDLE_VALUE) {
b = SetupInstallFilesFromInfSection(
SyssetupInf,
NULL,
FileQ,
Win31Upgrade
? L"Files.Install.Upgrade.Win31"
: L"Files.Install.Upgrade",
NULL,
BaseCopyStyle
);
//
// Do the installation of class installers
// We do this here because the installation of class intallers may involve
// file copy. And in this case we can use the existing progress bar.
//
InstallPnpClassInstallers( MainWindowHandle,
hInf,
FileQ );
if(b) {
b = FALSE;
if(Context = InitSysSetupQueueCallbackEx(MainWindowHandle,
INVALID_HANDLE_VALUE,0,0,NULL)) {
if(!SetupScanFileQueue(
FileQ,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
MainWindowHandle,
NULL,
NULL,
&ScanQueueResult)) {
//
// SetupScanFileQueue should really never
// fail when you don't ask it to call a
// callback routine, but if it does, just
// go ahead and commit the queue.
//
ScanQueueResult = 0;
}
if( ScanQueueResult != 1 ){
b = SetupCommitFileQueue(MainWindowHandle,FileQ,SysSetupQueueCallback,Context);
}
TermSysSetupQueueCallback(Context);
}
}
SetupCloseFileQueue(FileQ);
}
//SetupCloseInfFile(hInf);
}
return(b);
}
VOID
MarkFilesReadOnly(
VOID
)
{
WCHAR OldCurrentDir[MAX_PATH];
WCHAR System32Dir[MAX_PATH];
LPCTSTR SectionName;
LONG LineCount;
LONG ItemNo;
INFCONTEXT InfContext;
BOOL b;
ASSERT( SyssetupInf != INVALID_HANDLE_VALUE );
//
// Set current directory to system32.
// Preserve current directory to minimize side-effects.
//
if(!GetCurrentDirectory(MAX_PATH,OldCurrentDir)) {
OldCurrentDir[0] = 0;
}
GetSystemDirectory(System32Dir,MAX_PATH);
SetCurrentDirectory(System32Dir);
//
// Now go through the list of files.
//
SectionName = L"Files.MarkReadOnly";
LineCount = SetupGetLineCount( SyssetupInf, SectionName );
for( ItemNo=0; ItemNo<LineCount; ItemNo++ ) {
if( SetupGetLineByIndex( SyssetupInf, SectionName, ItemNo, &InfContext )) {
b = SetFileAttributes(
pSetupGetField( &InfContext, 0 ),
FILE_ATTRIBUTE_READONLY );
if (b) {
SetupDebugPrint1( L"SETUP: Marked file %ls read-only",
pSetupGetField( &InfContext, 0 ) );
} else {
SetupDebugPrint1( L"SETUP: Could not mark file %ls read-only",
pSetupGetField( &InfContext, 0 ) );
}
}
}
//
// Reset current directory and return.
//
if(OldCurrentDir[0]) {
SetCurrentDirectory(OldCurrentDir);
}
}