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

5552 lines
172 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
dynupdt.c
Abstract:
The Dynamic Update feature of WINNT32.
Author:
Ovidiu Temereanca (ovidiut) 02-Jul-2000
Revision History:
<alias> <date> <comment>
--*/
#include "precomp.h"
//
// BUGBUG - comment functions
//
#define GUIDRVS_FIELD_CABNAME 1
#define GUIDRVS_FIELD_INFNAME 2
#define GUIDRVS_FIELD_DRIVERVER 3
#define GUIDRVS_FIELD_HARDWAREID 4
#define MAX_UPGCHK_ELAPSED_SECONDS (30 * 60)
PDYNUPDT_STATUS g_DynUpdtStatus;
static WORD g_MapProductTypeToSuite[] = {
0, // pro
VER_SUITE_SMALLBUSINESS, // srv
VER_SUITE_ENTERPRISE, // ads
VER_SUITE_DATACENTER, // dtc
VER_SUITE_PERSONAL, // per
VER_SUITE_BLADE, // bla
};
static BYTE g_MapProductTypeToPT[] = {
VER_NT_WORKSTATION,
VER_NT_SERVER,
VER_NT_SERVER,
VER_NT_SERVER,
VER_NT_WORKSTATION,
VER_NT_SERVER,
};
typedef
BOOL
(*PCOMPLOADFN) (
IN PCTSTR LibraryPath
);
BOOL
DynUpdtDebugLog(
IN Winnt32DebugLevel Level,
IN LPCTSTR Text,
IN UINT MessageId,
...
)
{
va_list arglist;
BOOL b;
TCHAR bigBuffer[1024];
PCTSTR prefix;
DWORD rc = GetLastError ();
//
// this param is never used momentarily
//
MYASSERT (Text);
if (!Text) {
return FALSE;
}
MYASSERT (!MessageId);
if (Level <= Winnt32LogError) {
prefix = TEXT("DUError: ");
} else if (Level == Winnt32LogWarning) {
prefix = TEXT("DUWarning: ");
} else {
prefix = TEXT("DUInfo: ");
}
_sntprintf (bigBuffer, sizeof (bigBuffer) / sizeof (TCHAR), TEXT("%s%s"), prefix, Text);
va_start(arglist,MessageId);
b = DebugLog2 (Level, bigBuffer, MessageId, arglist);
va_end(arglist);
SetLastError (rc);
return b;
}
BOOL
pDoesFileExist (
IN PCTSTR FilePath
)
{
WIN32_FIND_DATA fd;
return FileExists (FilePath, &fd) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
BOOL
pDoesDirectoryExist (
IN PCTSTR DirPath
)
{
WIN32_FIND_DATA fd;
return FileExists (DirPath, &fd) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
BOOL
pNonemptyFilePresent (
IN PCTSTR FilePath
)
{
WIN32_FIND_DATA fd;
return FileExists (FilePath, &fd) &&
fd.nFileSizeLow > 0 &&
!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
BOOL
pGetTargetInfo (
OUT POSVERSIONINFOEX TargetVersion, OPTIONAL
OUT PTSTR TargetPlatform, OPTIONAL
IN DWORD TargetPlatformChars, OPTIONAL
OUT PLCID LocaleID OPTIONAL
)
{
TCHAR buffer[256];
UINT productType;
//
// get some data from the main inf
//
if (!FullInfName[0]) {
if (!FindPathToWinnt32File (InfName, FullInfName, MAX_PATH)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pGetTargetInfo: FindPathToWinnt32File failed"),
0
);
return FALSE;
}
}
if (TargetVersion) {
if (!GetPrivateProfileString (
TEXT("Miscellaneous"),
TEXT("ProductType"),
TEXT(""),
buffer,
256,
FullInfName
)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("%1 key in [%2] section is missing from %3; aborting operation"),
0,
TEXT("ProductType"),
TEXT("Miscellaneous"),
FullInfName
);
return FALSE;
}
if (buffer[0] < TEXT('0') || buffer[0] > TEXT('5') || buffer[1]) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Invalid %1 value (%2) in %3"),
0,
TEXT("ProductType"),
buffer,
FullInfName
);
return FALSE;
}
productType = buffer[0] - TEXT('0');
if (!GetPrivateProfileString (
TEXT("Miscellaneous"),
TEXT("ServicePack"),
TEXT(""),
buffer,
256,
FullInfName
)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("%1 key in [%2] section is missing from %3; aborting operation"),
0,
TEXT("ServicePack"),
TEXT("Miscellaneous"),
FullInfName
);
return FALSE;
}
if (_stscanf (
buffer,
TEXT("%hu.%hu"),
&TargetVersion->wServicePackMajor,
&TargetVersion->wServicePackMinor
) != 2) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Invalid %1 value (%2) in %3"),
0,
TEXT("ServicePack"),
buffer,
FullInfName
);
return FALSE;
}
TargetVersion->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
TargetVersion->dwMajorVersion = VER_PRODUCTMAJORVERSION;
TargetVersion->dwMinorVersion = VER_PRODUCTMINORVERSION;
TargetVersion->dwBuildNumber = VER_PRODUCTBUILD;
TargetVersion->dwPlatformId = VER_PLATFORM_WIN32_NT;
TargetVersion->wSuiteMask = g_MapProductTypeToSuite[productType];
TargetVersion->wProductType = g_MapProductTypeToPT[productType];
}
if (TargetPlatform) {
if (!GetPrivateProfileString (
TEXT("Miscellaneous"),
TEXT("DestinationPlatform"),
TEXT(""),
TargetPlatform,
TargetPlatformChars,
FullInfName
)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("%1 key in [%2] section is missing from %3; aborting operation"),
0,
TEXT("DestinationPlatform"),
TEXT("Miscellaneous"),
FullInfName
);
return FALSE;
}
}
if (LocaleID) {
MYASSERT (SourceNativeLangID);
*LocaleID = SourceNativeLangID;
}
return TRUE;
}
BOOL
pInitializeSupport (
IN PCTSTR ComponentName,
IN PCOMPLOADFN LoadFn,
IN BOOL UseRegistryReplacement
)
{
TCHAR pathSupportLib[MAX_PATH];
if (UseRegistryReplacement) {
HKEY key;
DWORD rc;
BOOL b = FALSE;
rc = RegOpenKey (
HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\Winnt32\\5.1"),
&key
);
if (rc == ERROR_SUCCESS) {
DWORD size = 0;
rc = RegQueryValueEx (key, ComponentName, NULL, NULL, NULL, &size);
if (rc == ERROR_SUCCESS && size > 0) {
PTSTR buf = MALLOC (size);
if (buf) {
rc = RegQueryValueEx (key, ComponentName, NULL, NULL, (LPBYTE)buf, &size);
if (rc == ERROR_SUCCESS && (*LoadFn) (buf)) {
DynUpdtDebugLog (
Winnt32LogInformation,
TEXT("pInitializeSupport: using registry specified replacement file <%1>"),
0,
buf
);
b = TRUE;
}
FREE (buf);
}
}
RegCloseKey (key);
}
if (b) {
return TRUE;
}
}
if (FindPathToWinnt32File (ComponentName, pathSupportLib, MAX_PATH)) {
if ((*LoadFn) (pathSupportLib)) {
return TRUE;
}
}
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pInitializeSupport: %1 could not be loaded or is corrupt"),
0,
ComponentName
);
return FALSE;
}
BOOL
pLoadHwdbLib (
IN PCTSTR LibraryPath
)
{
DWORD rc;
//
// Use WinVerifyTrust first?
//
g_DynUpdtStatus->HwdbLib = LoadLibraryEx (LibraryPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!g_DynUpdtStatus->HwdbLib) {
return FALSE;
}
g_DynUpdtStatus->HwdbInitialize = (PHWDBINITIALIZE) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBINITIALIZE);
g_DynUpdtStatus->HwdbTerminate = (PHWDBTERMINATE) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBTERMINATE);
g_DynUpdtStatus->HwdbOpen = (PHWDBOPEN) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBOPEN);
g_DynUpdtStatus->HwdbClose = (PHWDBCLOSE) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBCLOSE);
g_DynUpdtStatus->HwdbAppendInfs = (PHWDBAPPENDINFS) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBAPPENDINFS);
g_DynUpdtStatus->HwdbFlush = (PHWDBFLUSH) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBFLUSH);
g_DynUpdtStatus->HwdbHasDriver = (PHWDBHASDRIVER) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBHASDRIVER);
g_DynUpdtStatus->HwdbHasAnyDriver = (PHWDBHASANYDRIVER) GetProcAddress (g_DynUpdtStatus->HwdbLib, S_HWDBAPI_HWDBHASANYDRIVER);
if (!g_DynUpdtStatus->HwdbInitialize ||
!g_DynUpdtStatus->HwdbTerminate ||
!g_DynUpdtStatus->HwdbOpen ||
!g_DynUpdtStatus->HwdbClose ||
!g_DynUpdtStatus->HwdbAppendInfs ||
!g_DynUpdtStatus->HwdbFlush ||
!g_DynUpdtStatus->HwdbHasDriver ||
!g_DynUpdtStatus->HwdbHasAnyDriver
) {
g_DynUpdtStatus->HwdbInitialize = NULL;
g_DynUpdtStatus->HwdbTerminate = NULL;
g_DynUpdtStatus->HwdbOpen = NULL;
g_DynUpdtStatus->HwdbClose = NULL;
g_DynUpdtStatus->HwdbAppendInfs = NULL;
g_DynUpdtStatus->HwdbFlush = NULL;
g_DynUpdtStatus->HwdbHasDriver = NULL;
g_DynUpdtStatus->HwdbHasAnyDriver = NULL;
rc = GetLastError ();
FreeLibrary (g_DynUpdtStatus->HwdbLib);
g_DynUpdtStatus->HwdbLib = NULL;
SetLastError (rc);
return FALSE;
}
return TRUE;
}
BOOL
pLoadDuLib (
IN PCTSTR LibraryPath
)
{
DWORD rc;
//
// BUGBUG - Use WinVerifyTrust first?
//
g_DynUpdtStatus->DuLib = LoadLibraryEx (LibraryPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!g_DynUpdtStatus->DuLib) {
return FALSE;
}
g_DynUpdtStatus->DuIsSupported = (PDUISSUPPORTED) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_ISSUPPORTED);
g_DynUpdtStatus->DuInitialize = (PDUINITIALIZE) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_INITIALIZE);
g_DynUpdtStatus->DuDoDetection = (PDUDODETECTION) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_DODETECTION);
g_DynUpdtStatus->DuQueryUnsupDrvs = (PDUQUERYUNSUPDRVS) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_QUERYUNSUPDRVS);
g_DynUpdtStatus->DuBeginDownload = (PDUBEGINDOWNLOAD) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_BEGINDOWNLOAD);
g_DynUpdtStatus->DuAbortDownload = (PDUABORTDOWNLOAD) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_ABORTDOWNLOAD);
g_DynUpdtStatus->DuUninitialize = (PDUUNINITIALIZE) GetProcAddress (g_DynUpdtStatus->DuLib, API_DU_UNINITIALIZE);
if (!g_DynUpdtStatus->DuIsSupported ||
!g_DynUpdtStatus->DuInitialize ||
!g_DynUpdtStatus->DuDoDetection ||
!g_DynUpdtStatus->DuQueryUnsupDrvs ||
!g_DynUpdtStatus->DuBeginDownload ||
!g_DynUpdtStatus->DuAbortDownload ||
!g_DynUpdtStatus->DuUninitialize
) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pLoadDuLib: %1 is missing one or more required entry points"),
0,
LibraryPath
);
g_DynUpdtStatus->DuIsSupported = NULL;
g_DynUpdtStatus->DuInitialize = NULL;
g_DynUpdtStatus->DuDoDetection = NULL;
g_DynUpdtStatus->DuQueryUnsupDrvs = NULL;
g_DynUpdtStatus->DuBeginDownload = NULL;
g_DynUpdtStatus->DuAbortDownload = NULL;
g_DynUpdtStatus->DuUninitialize = NULL;
rc = GetLastError ();
FreeLibrary (g_DynUpdtStatus->DuLib);
g_DynUpdtStatus->DuLib = NULL;
SetLastError (rc);
return FALSE;
}
return TRUE;
}
#ifndef UNICODE
BOOL
pLoadWin9xDuSupport (
VOID
)
{
if (!UpgradeSupport.DllModuleHandle) {
return FALSE;
}
g_DynUpdtStatus->Win9xGetIncompDrvs = (PWIN9XGETINCOMPDRVS)
GetProcAddress (UpgradeSupport.DllModuleHandle, "Win9xGetIncompDrvs");
g_DynUpdtStatus->Win9xReleaseIncompDrvs = (PWIN9XRELEASEINCOMPDRVS)
GetProcAddress (UpgradeSupport.DllModuleHandle, "Win9xReleaseIncompDrvs");
if (!g_DynUpdtStatus->Win9xGetIncompDrvs) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Winnt32DuIsSupported: %1 is missing in the upgrade support module"),
0,
"Win9xGetIncompDrvs"
);
return FALSE;
}
return TRUE;
}
#endif
BOOL
pInitSupportLibs (
VOID
)
{
return (Winnt32Restarted () || pInitializeSupport (S_DUCTRL_DLL, pLoadDuLib, TRUE)) &&
pInitializeSupport (S_HWDB_DLL, pLoadHwdbLib, FALSE) &&
g_DynUpdtStatus->HwdbInitialize (g_DynUpdtStatus->TempDir);
}
BOOL
pInitNtPnpDb (
IN BOOL AllowRebuild
)
{
TCHAR hwdbPath[MAX_PATH];
BOOL b = TRUE;
if (!FindPathToWinnt32File (S_HWCOMP_DAT, hwdbPath, MAX_PATH)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pInitNtPnpDb: %1 not found"), 0, S_HWCOMP_DAT);
b = FALSE;
}
MYASSERT (g_DynUpdtStatus->HwdbInitialize);
if (b && !g_DynUpdtStatus->HwdbInitialize (g_DynUpdtStatus->TempDir)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pInitNtPnpDb: HwdbInitialize(%1) FAILED"), 0, g_DynUpdtStatus->TempDir);
b = FALSE;
}
MYASSERT (g_DynUpdtStatus->HwdbOpen);
if (b) {
g_DynUpdtStatus->HwdbDatabase = g_DynUpdtStatus->HwdbOpen (hwdbPath);
if (!g_DynUpdtStatus->HwdbDatabase) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pInitNtPnpDb: HwdbOpen(%1) FAILED"), 0, hwdbPath);
b = FALSE;
}
}
if (!b && AllowRebuild) {
//
// just rebuild the database in memory
//
g_DynUpdtStatus->HwdbDatabase = g_DynUpdtStatus->HwdbOpen (NULL);
if (g_DynUpdtStatus->HwdbDatabase) {
b = g_DynUpdtStatus->HwdbAppendInfs (g_DynUpdtStatus->HwdbDatabase, NativeSourcePaths[0], NULL, NULL);
if (b) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("pInitNtPnpDb: PnP database was successfully rebuilt"), 0);
//
// also try to save the database
//
if (g_DynUpdtStatus->HwdbFlush) {
BuildPath (hwdbPath, NativeSourcePaths[0], S_HWCOMP_DAT);
g_DynUpdtStatus->HwdbFlush (g_DynUpdtStatus->HwdbDatabase, hwdbPath);
}
}
}
}
return b;
}
BOOL
IsNetConnectivityAvailable (
VOID
)
{
#ifdef UNICODE
return TRUE;
#else
BOOL (*pfnWin9xAnyNetDevicePresent) (VOID);
if (UpgradeSupport.DllModuleHandle) {
(FARPROC)pfnWin9xAnyNetDevicePresent = GetProcAddress (UpgradeSupport.DllModuleHandle, "Win9xAnyNetDevicePresent");
if (pfnWin9xAnyNetDevicePresent) {
return pfnWin9xAnyNetDevicePresent();
}
}
return TRUE;
#endif
}
BOOL
DynamicUpdateIsSupported (
IN HWND ParentWnd
)
{
DWORD rc;
if (g_DynUpdtStatus->Disabled) {
return FALSE;
}
//
// disable this for DTC
//
if (ProductFlavor == DATACENTER_PRODUCTTYPE) {
return FALSE;
}
if (AnyBlockingCompatibilityItems ()) {
//
// no point in supporting DU; setup will stop anyway
//
return FALSE;
}
CleanUpOldLocalSources (ParentWnd);
if (!InspectFilesystems (ParentWnd)) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("InspectFilesystems blocks DU"), 0);
return FALSE;
}
if (!EnoughMemory (ParentWnd, TRUE)) {
return FALSE;
}
if (!FindLocalSourceAndCheckSpace (ParentWnd, TRUE, DYN_DISKSPACE_PADDING)) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("Not enough disk space blocks DU"), 0);
return FALSE;
}
if (!g_DynUpdtStatus->SupportQueried) {
g_DynUpdtStatus->SupportQueried = TRUE;
if (g_DynUpdtStatus->DynamicUpdatesSource[0]) {
g_DynUpdtStatus->SupportPresent = TRUE;
} else {
g_DynUpdtStatus->SupportPresent =
Winnt32DuIsSupported () &&
IsNetConnectivityAvailable ();
if (!g_DynUpdtStatus->SupportPresent) {
rc = GetLastError ();
DynamicUpdateUninitialize ();
SetLastError (rc);
}
}
}
return g_DynUpdtStatus->SupportPresent;
}
BOOL
DynamicUpdateInitDownload (
IN HWND hNotifyWnd
)
{
DYNUPDT_INIT dynUpdtInit;
MYASSERT (!g_DynUpdtStatus->Disabled);
MYASSERT (!Winnt32Restarted ());
MyDelnode (g_DynUpdtStatus->WorkingDir);
BuildPath (g_DynUpdtStatus->TempDir, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_TEMP);
if (CreateMultiLevelDirectory (g_DynUpdtStatus->TempDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("DynamicUpdateInitDownload: CreateMultiLevelDirectory failed"),
0
);
return FALSE;
}
if (!pGetTargetInfo (
&g_DynUpdtStatus->TargetOsVersion,
NULL,
0,
&g_DynUpdtStatus->TargetLCID
)) {
return FALSE;
}
dynUpdtInit.TargetOsVersion = &g_DynUpdtStatus->TargetOsVersion;
dynUpdtInit.TargetPlatform = g_DynUpdtStatus->TargetPlatform;
dynUpdtInit.TargetLCID = g_DynUpdtStatus->TargetLCID;
dynUpdtInit.Upgrade = Upgrade;
dynUpdtInit.SourceDirs = info.SourceDirectories;
dynUpdtInit.SourceDirsCount = SourceCount;
dynUpdtInit.Unattend = UnattendSwitchSpecified;
dynUpdtInit.AnswerFile = UnattendedScriptFile;
dynUpdtInit.ProgressWindow = hNotifyWnd;
dynUpdtInit.DownloadRoot = g_DynUpdtStatus->WorkingDir;
dynUpdtInit.TempDir = g_DynUpdtStatus->TempDir;
return Winnt32DuInitialize (&dynUpdtInit);
}
BOOL
DynamicUpdateStart (
OUT PDWORD TotalEstimatedTime,
OUT PDWORD TotalEstimatedSize
)
{
if (g_DynUpdtStatus->Disabled) {
return FALSE;
}
return Winnt32DuInitiateGetUpdates (TotalEstimatedTime, TotalEstimatedSize);
}
VOID
DynamicUpdateCancel (
VOID
)
{
if (g_DynUpdtStatus->Disabled) {
return;
}
Winnt32DuCancel ();
}
BOOL
DynamicUpdateProcessFiles (
OUT PBOOL StopSetup
)
{
if (g_DynUpdtStatus->Disabled) {
return TRUE;
}
return Winnt32DuProcessFiles (StopSetup);
}
BOOL
DynamicUpdateWriteParams (
IN PCTSTR ParamsFile
)
{
return Winnt32DuWriteParams (ParamsFile);
}
VOID
DynamicUpdateUninitialize (
VOID
)
{
if (g_DynUpdtStatus->Disabled) {
return;
}
Winnt32DuUninitialize ();
}
BOOL
DynamicUpdatePrepareRestart (
VOID
)
{
PCTSTR prevCmdLine;
DWORD size;
#ifdef _X86_
TCHAR reportNum[16];
#endif
if (g_DynUpdtStatus->Disabled) {
return FALSE;
}
#define S_ARG_RESTART TEXT("Restart")
if (!UnattendedOperation) {
//
// build the restart answer file
//
BuildPath (g_DynUpdtStatus->RestartAnswerFile, g_DynUpdtStatus->WorkingDir, S_RESTART_TXT);
#ifdef _X86_
wsprintf (reportNum, TEXT("%u"), g_UpgradeReportMode);
#endif
//
// write data to the restart answer file
//
if (!WritePrivateProfileString (
WINNT_UNATTENDED,
ISNT() ? WINNT_D_NTUPGRADE : WINNT_D_WIN95UPGRADE,
Upgrade ? WINNT_A_YES : WINNT_A_NO,
g_DynUpdtStatus->RestartAnswerFile
) ||
ProductId[0] && !WritePrivateProfileString (
WINNT_USERDATA,
WINNT_US_PRODUCTKEY,
ProductId,
g_DynUpdtStatus->RestartAnswerFile
) ||
!WritePrivateProfileString (
WINNT_UNATTENDED,
WINNT_U_DYNAMICUPDATESHARE,
g_DynUpdtStatus->DynamicUpdatesSource,
g_DynUpdtStatus->RestartAnswerFile
) ||
#ifdef _X86_
!WritePrivateProfileString (
WINNT_UNATTENDED,
WINNT_D_REPORTMODE,
reportNum,
g_DynUpdtStatus->RestartAnswerFile
) ||
#endif
(ForceNTFSConversion &&
!WritePrivateProfileString (
WINNT_UNATTENDED,
TEXT("ForceNTFSConversion"),
WINNT_A_YES,
g_DynUpdtStatus->RestartAnswerFile
)) ||
!SaveAdvancedOptions (
g_DynUpdtStatus->RestartAnswerFile
) ||
!SaveLanguageOptions (
g_DynUpdtStatus->RestartAnswerFile
) ||
!SaveAccessibilityOptions (
g_DynUpdtStatus->RestartAnswerFile
)
) {
return FALSE;
}
}
prevCmdLine = GetCommandLine ();
size = (lstrlen (prevCmdLine) + 1 + 1) * sizeof (TCHAR) + sizeof (S_ARG_RESTART) +
(UnattendedOperation ? 0 : (1 + lstrlen (g_DynUpdtStatus->RestartAnswerFile)) * sizeof (TCHAR));
g_DynUpdtStatus->RestartCmdLine = HeapAlloc (GetProcessHeap (), 0, size);
if (!g_DynUpdtStatus->RestartCmdLine) {
return FALSE;
}
wsprintf (
g_DynUpdtStatus->RestartCmdLine,
UnattendedOperation ? TEXT("%s /%s") : TEXT("%s /%s:%s"),
prevCmdLine,
S_ARG_RESTART,
g_DynUpdtStatus->RestartAnswerFile
);
return TRUE;
}
BOOL
pComputeChecksum (
IN PCTSTR FileName,
OUT PDWORD Chksum
)
{
DWORD chksum, size, dwords, bytes;
HANDLE hFile, hMap;
PVOID viewBase;
PDWORD base, limit;
PBYTE base2;
DWORD rc;
rc = MapFileForRead (FileName, &size, &hFile, &hMap, &viewBase);
if (rc != ERROR_SUCCESS) {
SetLastError (rc);
return FALSE;
}
dwords = size / sizeof (DWORD);
base = (PDWORD)viewBase;
limit = base + dwords;
chksum = 0;
while (base < limit) {
chksum += *base;
base++;
}
bytes = size % sizeof (DWORD);
base2 = (PBYTE)base;
while (bytes) {
chksum += *base2;
base2++;
bytes--;
}
UnmapFile (hMap, viewBase);
CloseHandle (hFile);
*Chksum = chksum;
return TRUE;
}
BOOL
pGetFiletimeStamps (
IN PCTSTR FileName,
OUT PFILETIME CreationTime,
OUT PFILETIME LastWriteTime
)
{
WIN32_FIND_DATA fd;
HANDLE h;
h = FindFirstFile (FileName, &fd);
if (h == INVALID_HANDLE_VALUE) {
return FALSE;
}
FindClose (h);
*CreationTime = fd.ftCreationTime;
*LastWriteTime = fd.ftLastWriteTime;
return TRUE;
}
BOOL
pSaveLastDownloadInfo (
VOID
)
{
SYSTEMTIME currentTime;
DWORD chksum;
FILETIME ftCreationTime;
FILETIME ftLastWriteTime;
ULONGLONG data[2];
DWORD rc;
HKEY key;
TCHAR keyName[MAX_PATH];
TCHAR filePath[MAX_PATH];
PTSTR p;
//
// we always want to get to the CD dosnet.inf (in the same directory as winnt32.exe)
//
if (!GetModuleFileName (NULL, filePath, MAX_PATH)) {
return FALSE;
}
p = _tcsrchr (filePath, TEXT('\\'));
if (!p) {
return FALSE;
}
lstrcpy (p + 1, InfName);
GetCurrentWinnt32RegKey (keyName, MAX_PATH);
ConcatenatePaths (keyName, WINNT_U_DYNAMICUPDATESHARE, MAX_PATH);
rc = RegCreateKey (HKEY_LOCAL_MACHINE, keyName, &key);
if (rc == ERROR_SUCCESS) {
GetSystemTime (&currentTime);
rc = RegSetValueEx (
key,
TEXT("LastDownloadTime"),
0,
REG_BINARY,
(CONST BYTE *) (&currentTime),
sizeof (currentTime)
);
if (rc == ERROR_SUCCESS) {
rc = RegSetValueEx (
key,
TEXT(""),
0,
REG_SZ,
(CONST BYTE *) g_DynUpdtStatus->DynamicUpdatesSource,
(lstrlen (g_DynUpdtStatus->DynamicUpdatesSource) + 1) * sizeof (TCHAR)
);
}
if (rc == ERROR_SUCCESS) {
if (pComputeChecksum (filePath, &chksum)) {
rc = RegSetValueEx (
key,
TEXT("Checksum"),
0,
REG_DWORD,
(CONST BYTE *) (&chksum),
sizeof (chksum)
);
}
}
if (rc == ERROR_SUCCESS) {
if (pGetFiletimeStamps (filePath, &ftCreationTime, &ftLastWriteTime)) {
data[0] = ((ULONGLONG)ftCreationTime.dwHighDateTime << 32) | (ULONGLONG)ftCreationTime.dwLowDateTime;
data[1] = ((ULONGLONG)ftLastWriteTime.dwHighDateTime << 32 ) | (ULONGLONG)ftLastWriteTime.dwLowDateTime;
rc = RegSetValueEx (
key,
TEXT("TimeStamp"),
0,
REG_BINARY,
(CONST BYTE *)data,
sizeof (data)
);
}
}
RegCloseKey (key);
}
if (rc != ERROR_SUCCESS) {
SetLastError (rc);
}
return rc == ERROR_SUCCESS;
}
BOOL
pGetRecentDUShare (
IN DWORD MaxElapsedSeconds
)
{
SYSTEMTIME lastDownload, currentTime;
ULONGLONG lastDownloadIn100Ns, currentTimeIn100Ns;
ULONGLONG difference;
DWORD rc, size, type;
HKEY key = NULL;
BOOL b = FALSE;
PTSTR duShare = NULL;
TCHAR keyName[MAX_PATH];
FILETIME ftCreationTime;
FILETIME ftLastWriteTime;
ULONGLONG data[2], storedData[2];
DWORD chksum, storedChksum;
TCHAR filePath[MAX_PATH];
PTSTR p;
if (!GetModuleFileName (NULL, filePath, MAX_PATH)) {
return FALSE;
}
p = _tcsrchr (filePath, TEXT('\\'));
if (!p) {
return FALSE;
}
lstrcpy (p + 1, InfName);
GetCurrentWinnt32RegKey (keyName, MAX_PATH);
ConcatenatePaths (keyName, WINNT_U_DYNAMICUPDATESHARE, MAX_PATH);
rc = RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
keyName,
0,
KEY_READ,
&key
);
if (rc == ERROR_SUCCESS) {
size = sizeof (lastDownload);
rc = RegQueryValueEx (
key,
TEXT("LastDownloadTime"),
NULL,
&type,
(PBYTE) (&lastDownload),
&size
);
}
if (rc == ERROR_SUCCESS && type == REG_BINARY && size == sizeof (lastDownload)) {
//
// Compare current time to report time
//
GetSystemTime (&currentTime);
lastDownloadIn100Ns = SystemTimeToFileTime64 (&lastDownload);
currentTimeIn100Ns = SystemTimeToFileTime64 (&currentTime);
if (currentTimeIn100Ns > lastDownloadIn100Ns) {
//
// Compute difference in seconds
//
difference = currentTimeIn100Ns - lastDownloadIn100Ns;
difference /= (10 * 1000 * 1000);
if (difference < MaxElapsedSeconds) {
b = TRUE;
}
}
}
if (b) {
b = FALSE;
rc = RegQueryValueEx (
key,
TEXT(""),
NULL,
&type,
NULL,
&size
);
if (rc == ERROR_SUCCESS && type == REG_SZ && size > 0 && size <= sizeof (g_DynUpdtStatus->DynamicUpdatesSource)) {
duShare = MALLOC (size);
if (duShare) {
rc = RegQueryValueEx (
key,
TEXT(""),
NULL,
NULL,
(LPBYTE)duShare,
&size
);
if (rc == ERROR_SUCCESS && pDoesDirectoryExist (duShare)) {
b = TRUE;
} else {
FREE (duShare);
duShare = NULL;
}
}
}
}
if (b) {
b = FALSE;
if (pGetFiletimeStamps (filePath, &ftCreationTime, &ftLastWriteTime)) {
rc = RegQueryValueEx (
key,
TEXT("TimeStamp"),
0,
&type,
(LPBYTE)storedData,
&size
);
if (rc == ERROR_SUCCESS && type == REG_BINARY) {
data[0] = ((ULONGLONG)ftCreationTime.dwHighDateTime << 32) | (ULONGLONG)ftCreationTime.dwLowDateTime;
data[1] = ((ULONGLONG)ftLastWriteTime.dwHighDateTime << 32 ) | (ULONGLONG)ftLastWriteTime.dwLowDateTime;
if (data[0] == storedData[0] && data[1] == storedData[1]) {
b = TRUE;
}
}
}
}
if (b) {
b = FALSE;
if (pComputeChecksum (filePath, &chksum)) {
rc = RegQueryValueEx (
key,
TEXT("Checksum"),
NULL,
&type,
(LPBYTE)&storedChksum,
&size
);
if (rc == ERROR_SUCCESS && type == REG_DWORD && storedChksum == chksum) {
b = TRUE;
}
}
}
if (!b && duShare) {
FREE (duShare);
duShare = NULL;
}
if (duShare) {
MYASSERT (b);
MYASSERT (!g_DynUpdtStatus->DynamicUpdatesSource[0]);
lstrcpy (g_DynUpdtStatus->DynamicUpdatesSource, duShare);
RemoveTrailingWack (g_DynUpdtStatus->DynamicUpdatesSource);
g_DynUpdtStatus->UserSpecifiedUpdates = TRUE;
}
if (key) {
RegCloseKey (key);
}
return b;
}
BOOL
DynamicUpdateInitialize (
VOID
)
{
if (g_DynUpdtStatus->Disabled) {
return TRUE;
}
if (!MyGetWindowsDirectory (g_DynUpdtStatus->WorkingDir, MAX_PATH)) {
return FALSE;
}
ConcatenatePaths (g_DynUpdtStatus->WorkingDir, S_DOWNLOAD_ROOT, MAX_PATH);
BuildPath (g_DynUpdtStatus->TempDir, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_TEMP);
if (!CheckUpgradeOnly && !g_DynUpdtStatus->UserSpecifiedUpdates) {
if (pGetRecentDUShare (MAX_UPGCHK_ELAPSED_SECONDS)) {
g_DynUpdtStatus->PreserveWorkingDir = TRUE;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Using recent share %1"), 0, g_DynUpdtStatus->DynamicUpdatesSource);
}
}
if (!g_DynUpdtStatus->PreserveWorkingDir && !Winnt32Restarted ()) {
MyDelnode (g_DynUpdtStatus->WorkingDir);
}
if (g_DynUpdtStatus->UserSpecifiedUpdates) {
BuildPath (g_DynUpdtStatus->DriversSource, g_DynUpdtStatus->DynamicUpdatesSource, S_SUBDIRNAME_DRIVERS);
} else {
BuildPath (g_DynUpdtStatus->DriversSource, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_DRIVERS);
}
BuildPath (g_DynUpdtStatus->SelectedDrivers, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_DRIVERS);
if (Winnt32Restarted ()) {
BuildPath (g_DynUpdtStatus->Winnt32Path, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_WINNT32);
} else {
BuildPath (
g_DynUpdtStatus->Winnt32Path,
g_DynUpdtStatus->UserSpecifiedUpdates ?
g_DynUpdtStatus->DynamicUpdatesSource :
g_DynUpdtStatus->WorkingDir,
S_SUBDIRNAME_WINNT32
);
}
if (!pGetTargetInfo (
NULL,
g_DynUpdtStatus->TargetPlatform,
sizeof (g_DynUpdtStatus->TargetPlatform) / sizeof (TCHAR),
NULL
)) {
return FALSE;
}
return TRUE;
}
PTSTR
GetFileExtension (
IN PCTSTR FileSpec
)
{
PTSTR p;
p = _tcsrchr (FileSpec, TEXT('.'));
if (p && _tcschr (p, TEXT('\\'))) {
p = NULL;
}
return p;
}
VOID
BuildSifName (
IN PCTSTR CabName,
OUT PTSTR SifName
)
{
PTSTR p;
lstrcpy (SifName, CabName);
p = GetFileExtension (SifName);
if (!p) {
p = _tcschr (SifName, 0);
}
lstrcpy (p, TEXT(".sif"));
}
BOOL
WINAPI
Winnt32QueryCallback (
IN DWORD SetupQueryId,
IN PVOID InData,
IN DWORD InDataSize,
IN OUT PVOID OutData, OPTIONAL
IN OUT PDWORD OutDataSize
)
{
BOOL b = FALSE;
BOOL bException = FALSE;
switch (SetupQueryId) {
case SETUPQUERYID_PNPID:
{
PPNPID_INFO p;
PTSTR listPnpIds = NULL;
if (!OutData ||
!OutDataSize ||
*OutDataSize < sizeof (PNPID_INFO)
) {
SetLastError (ERROR_INVALID_PARAMETER);
break;
}
if (!g_DynUpdtStatus->HwdbHasAnyDriver) {
SetLastError (ERROR_INVALID_FUNCTION);
break;
}
__try {
p = (PPNPID_INFO)OutData;
if (g_DynUpdtStatus->HwdbDatabase) {
#ifdef UNICODE
listPnpIds = MultiSzAnsiToUnicode ((PCSTR)InData);
#else
listPnpIds = (PSTR)InData;
#endif
p->Handled = (*g_DynUpdtStatus->HwdbHasAnyDriver) (
g_DynUpdtStatus->HwdbDatabase,
listPnpIds,
&p->Unsupported
);
} else {
//
// disable all driver downloads by doing this
//
p->Handled = TRUE;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (GetExceptionCode());
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32QueryCallback: HwdbHasAnyDriver threw an exception"), 0);
bException = TRUE;
p->Handled = TRUE;
}
if (bException) {
__try {
//
// bad string passed back, or some internal error
// try to print the string
//
if (listPnpIds) {
PTSTR multisz = CreatePrintableString (listPnpIds);
DynUpdtDebugLog (Winnt32LogError, TEXT(" - The string was %1"), 0, multisz);
FREE (multisz);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DynUpdtDebugLog (Winnt32LogError, TEXT(" - Bad string"), 0);
}
}
#ifdef UNICODE
if (listPnpIds) {
FREE (listPnpIds);
}
#endif
b = TRUE;
}
break;
case SETUPQUERYID_DOWNLOADDRIVER:
{
if (!OutData ||
!OutDataSize ||
*OutDataSize < sizeof (BOOL)
) {
SetLastError (ERROR_INVALID_PARAMETER);
break;
}
b = TRUE;
}
break;
}
return b;
}
BOOL
WINAPI
Winnt32DuIsSupported (
VOID
)
{
BOOL b;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuIsSupported"), 0);
#ifndef UNICODE
if (!pLoadWin9xDuSupport ()) {
DynUpdtDebugLog (
Winnt32LogWarning,
TEXT("Winnt32DuIsSupported: %1 support module not loaded; no drivers will be downloaded"),
0,
"w95upg.dll"
);
}
#endif
TRY {
b = pInitSupportLibs () &&
(Winnt32Restarted () || g_DynUpdtStatus->DuIsSupported ());
}
EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (_exception_code ());
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32DuIsSupported: an exception occured"), 0);
}
END_EXCEPT
#ifndef UNICODE
if (!b) {
g_DynUpdtStatus->Win9xGetIncompDrvs = NULL;
g_DynUpdtStatus->Win9xReleaseIncompDrvs = NULL;
}
#endif
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuIsSupported (%1!d!)"), 0, b);
return b;
}
BOOL
WINAPI
Winnt32DuInitialize (
IN PDYNUPDT_INIT InitData
)
{
DWORD rc;
BOOL b = FALSE;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuInitialize"), 0);
__try {
MYASSERT (InitData);
MYASSERT (InitData->TempDir);
MYASSERT (g_DynUpdtStatus->DuInitialize);
MYASSERT (!Winnt32Restarted ());
if (CreateMultiLevelDirectory (InitData->TempDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32DuInitialize: CreateDirectory(%1) FAILED"), 0, InitData->TempDir);
__leave;
}
//
// initialize the Whistler PNP database
//
if (!g_DynUpdtStatus->HwdbDatabase) {
//
// ignore db load error
//
pInitNtPnpDb (FALSE);
}
TRY {
//
// if a download source already exists, no need to initialize the control
// since no download will be really necessary
//
MYASSERT (!g_DynUpdtStatus->DynamicUpdatesSource[0]);
g_DynUpdtStatus->Connection = (*g_DynUpdtStatus->DuInitialize) (
InitData->DownloadRoot,
InitData->TempDir,
InitData->TargetOsVersion,
InitData->TargetPlatform,
InitData->TargetLCID,
InitData->Unattend,
InitData->Upgrade,
Winnt32QueryCallback
);
if (g_DynUpdtStatus->Connection == INVALID_HANDLE_VALUE) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("DuInitialize FAILED"),
0
);
__leave;
}
g_DynUpdtStatus->ProgressWindow = InitData->ProgressWindow;
b = TRUE;
}
EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (_exception_code ());
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32DuInitialize: an exception occured"), 0);
}
END_EXCEPT
}
__finally {
if (!b) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32DuInitialize FAILED"), 0);
}
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuInitialize (%1!d!)"), 0, b);
return b;
}
BOOL
WINAPI
Winnt32DuInitiateGetUpdates (
OUT PDWORD TotalEstimatedTime,
OUT PDWORD TotalEstimatedSize
)
{
BOOL b = FALSE;
#ifndef UNICODE
PSTR* incompWin9xDrivers;
PSTRINGLIST listEntry;
PCSTR* q;
#endif
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuInitiateGetUpdates"), 0);
if (g_DynUpdtStatus->Connection != INVALID_HANDLE_VALUE &&
g_DynUpdtStatus->DuDoDetection &&
g_DynUpdtStatus->DuBeginDownload
) {
TRY {
#ifdef UNICODE
b = (*g_DynUpdtStatus->DuDoDetection) (g_DynUpdtStatus->Connection, TotalEstimatedTime, TotalEstimatedSize);
if (!b) {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("DuDoDetection returned FALSE; no files will be downloaded"),
0
);
}
#else
b = TRUE;
g_DynUpdtStatus->IncompatibleDriversCount = 0;
if (g_DynUpdtStatus->Win9xGetIncompDrvs) {
//
// let the upgrade module do detection on Win95
//
b = (*g_DynUpdtStatus->Win9xGetIncompDrvs) (&incompWin9xDrivers);
if (b) {
b = (*g_DynUpdtStatus->DuQueryUnsupDrvs) (
g_DynUpdtStatus->Connection,
incompWin9xDrivers,
TotalEstimatedTime,
TotalEstimatedSize
);
if (incompWin9xDrivers) {
for (q = incompWin9xDrivers; *q; q++) {
g_DynUpdtStatus->IncompatibleDriversCount++;
}
}
if (g_DynUpdtStatus->Win9xReleaseIncompDrvs) {
(*g_DynUpdtStatus->Win9xReleaseIncompDrvs) (incompWin9xDrivers);
}
if (!b) {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("DuQueryUnsupportedDrivers returned FALSE; no files will be downloaded"),
0
);
}
} else {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Win9xGetIncompDrvs returned FALSE; no files will be downloaded"),
0
);
}
}
#endif
if (b) {
b = (*g_DynUpdtStatus->DuBeginDownload) (g_DynUpdtStatus->Connection, g_DynUpdtStatus->ProgressWindow);
if (!b) {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("DuBeginDownload returned FALSE; no files will be downloaded"),
0
);
}
}
}
EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (_exception_code ());
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Winnt32DuInitiateGetUpdates: an exception occured; no files will be downloaded"),
0
);
}
END_EXCEPT
} else {
SetLastError (ERROR_INVALID_FUNCTION);
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuInitiateGetUpdates (%1!d!)"), 0, b);
return b;
}
VOID
WINAPI
Winnt32DuCancel (
VOID
)
{
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuCancel"), 0);
TRY {
if (g_DynUpdtStatus->Connection != INVALID_HANDLE_VALUE &&
g_DynUpdtStatus->DuAbortDownload
) {
(*g_DynUpdtStatus->DuAbortDownload) (g_DynUpdtStatus->Connection);
}
//
// BUGBUG - is this definitive?
//
}
EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (_exception_code ());
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32DuCancel: an exception occured"), 0);
}
END_EXCEPT
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuCancel"), 0);
}
BOOL
WINAPI
Winnt32DuProcessFiles (
OUT PBOOL StopSetup
)
{
BOOL b;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuProcessFiles"), 0);
b = ProcessDownloadedFiles (StopSetup);
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuProcessFiles (%1!d!)"), 0, b);
return b;
}
BOOL
WINAPI
Winnt32DuWriteParams (
IN PCTSTR ParamsFile
)
{
PSDLIST p;
PSTRINGLIST q;
DWORD len1, len2;
PTSTR pathList1 = NULL, pathList2 = NULL;
PTSTR append1, append2;
BOOL b = TRUE;
if (!DynamicUpdateSuccessful ()) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Winnt32DuWriteParams: disabled because DU did not succeed"), 0);
return TRUE;
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuWriteParams"), 0);
//
// store paths to all downloaded drivers in a key in the answer file,
// so later on Textmode Setup (or GUI setup) will append this list to the OemPnPDriversPath
//
if (g_DynUpdtStatus->NewDriversList) {
len1 = len2 = 0;
for (p = g_DynUpdtStatus->NewDriversList; p; p = p->Next) {
if (p->Data) {
len1 += lstrlen (p->String) + 1;
} else {
len2 += lstrlen (p->String) + 1;
}
}
if (len1) {
pathList1 = (PTSTR) MALLOC (len1 * sizeof (TCHAR));
if (!pathList1) {
b = FALSE;
goto exit;
}
*pathList1 = 0;
append1 = pathList1;
}
if (len2) {
pathList2 = (PTSTR) MALLOC (len2 * sizeof (TCHAR));
if (!pathList2) {
FREE (pathList1);
b = FALSE;
goto exit;
}
*pathList2 = 0;
append2 = pathList2;
}
for (p = g_DynUpdtStatus->NewDriversList; p; p = p->Next) {
if (p->Data) {
if (append1 != pathList1) {
*append1++ = TEXT(',');
}
lstrcpy (append1, p->String);
append1 = _tcschr (append1, 0);
} else {
if (append2 != pathList2) {
*append2++ = TEXT(',');
}
lstrcpy (append2, p->String);
append2 = _tcschr (append2, 0);
}
}
if (len1) {
if (!WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTADDITIONALGUIDRIVERS,
pathList1,
ParamsFile
)) {
b = FALSE;
}
}
if (b && len2) {
if (!WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTADDITIONALPOSTGUIDRIVERS,
pathList2,
ParamsFile
)) {
b = FALSE;
}
}
if (pathList1) {
FREE (pathList1);
}
if (pathList2) {
FREE (pathList2);
}
if (b && g_DynUpdtStatus->GuidrvsInfSource[0]) {
if (!WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTDRIVERINFOFILE,
g_DynUpdtStatus->GuidrvsInfSource,
ParamsFile
)) {
b = FALSE;
}
}
}
//
// store paths to all downloaded BOOT drivers in a key in the answer file,
// so later on Textmode Setup will append this to the boot drivers list
//
if (b && g_DynUpdtStatus->BootDriverPathList) {
len1 = 0;
for (q = g_DynUpdtStatus->BootDriverPathList; q; q = q->Next) {
len1 += lstrlen (q->String) + 1;
}
pathList1 = (PTSTR) MALLOC (len1 * sizeof (TCHAR));
if (!pathList1) {
b = FALSE;
goto exit;
}
*pathList1 = 0;
append1 = pathList1;
for (q = g_DynUpdtStatus->BootDriverPathList; q; q = q->Next) {
if (append1 != pathList1) {
*append1++ = TEXT(',');
}
lstrcpy (append1, q->String);
append1 = _tcschr (append1, 0);
}
if (!WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTBOOTDRIVERPRESENT,
WINNT_A_YES,
ParamsFile
) ||
!WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTBOOTDRIVERROOT,
S_SUBDIRNAME_DRIVERS,
ParamsFile
) ||
!WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTBOOTDRIVERS,
pathList1,
ParamsFile
)) {
b = FALSE;
}
FREE (pathList1);
}
if (b && g_DynUpdtStatus->UpdatesCabTarget[0]) {
TCHAR buffer[4*MAX_PATH];
wsprintf (
buffer,
TEXT("\"%s\""),
g_DynUpdtStatus->UpdatesCabTarget
);
b = WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_UPDATEDSOURCES,
buffer,
ParamsFile
);
}
//
// new assemblies to be installed during GUI setup
//
if (b && g_DynUpdtStatus->DuasmsTarget[0]) {
b = WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_UPDATEDDUASMS,
g_DynUpdtStatus->DuasmsTarget,
ParamsFile
);
}
#ifdef _X86_
//
// last but not least, replace the Win9xupg NT side migration dll (w95upgnt.dll)
// if a new one is available
//
if (b && Upgrade && !ISNT() && g_DynUpdtStatus->Winnt32Path[0]) {
TCHAR source[MAX_PATH];
TCHAR target[MAX_PATH];
BuildPath (target, g_DynUpdtStatus->Winnt32Path, TEXT("w95upgnt.dll"));
if (pDoesFileExist (target)) {
//
// check file versions first
//
BuildPath (source, NativeSourcePaths[0], TEXT("w95upgnt.dll"));
if (!IsFileVersionLesser (target, source)) {
if (_tcsnicmp (
g_DynUpdtStatus->Winnt32Path,
g_DynUpdtStatus->WorkingDir,
lstrlen (g_DynUpdtStatus->WorkingDir)
)) {
//
// copy the file in a local directory first
//
BuildPath (source, g_DynUpdtStatus->WorkingDir, TEXT("w95upgnt.dll"));
if (CopyFile (target, source, FALSE)) {
lstrcpy (target, source);
} else {
//
// failed to copy the NT-side upgrade module!
// fail the upgrade
//
DynUpdtDebugLog (
Winnt32LogSevereError,
TEXT("Failed to copy replacement %1 to %2; upgrade aborted"),
0,
target,
source
);
b = FALSE;
}
}
if (b) {
b = WritePrivateProfileString (
WINNT_WIN95UPG_95_DIR,
WINNT_WIN95UPG_NTKEY,
target,
ParamsFile
);
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Will use replacement %1 on the NT side of migration"), 0, target);
}
}
}
}
#endif
if (b) {
if (g_DynUpdtStatus->WorkingDir[0]) {
b = WritePrivateProfileString (
WINNT_SETUPPARAMS,
WINNT_SP_DYNUPDTWORKINGDIR,
g_DynUpdtStatus->WorkingDir,
ParamsFile
);
}
}
if (b) {
//
// flush it to disk
//
WritePrivateProfileString (NULL, NULL, NULL, ParamsFile);
}
exit:
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuWriteParams (%1!d!)"), 0, b);
return b;
}
VOID
WINAPI
Winnt32DuUninitialize (
VOID
)
{
DWORD i;
TCHAR pathPss[MAX_PATH];
PTSTR p;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Enter Winnt32DuUninitialize"), 0);
TRY {
if (g_DynUpdtStatus->Connection != INVALID_HANDLE_VALUE) {
if (g_DynUpdtStatus->DuUninitialize) {
(*g_DynUpdtStatus->DuUninitialize) (g_DynUpdtStatus->Connection);
}
g_DynUpdtStatus->Connection = INVALID_HANDLE_VALUE;
}
g_DynUpdtStatus->DuIsSupported = NULL;
g_DynUpdtStatus->ProgressWindow = NULL;
g_DynUpdtStatus->DuInitialize = NULL;
g_DynUpdtStatus->DuDoDetection = NULL;
g_DynUpdtStatus->DuQueryUnsupDrvs = NULL;
g_DynUpdtStatus->DuBeginDownload = NULL;
g_DynUpdtStatus->DuAbortDownload = NULL;
g_DynUpdtStatus->DuUninitialize = NULL;
if (g_DynUpdtStatus->DuLib) {
FreeLibrary (g_DynUpdtStatus->DuLib);
g_DynUpdtStatus->DuLib = NULL;
}
if (g_DynUpdtStatus->HwdbDatabase) {
g_DynUpdtStatus->HwdbClose (g_DynUpdtStatus->HwdbDatabase);
g_DynUpdtStatus->HwdbDatabase = NULL;
}
if (g_DynUpdtStatus->HwdbTerminate) {
(*g_DynUpdtStatus->HwdbTerminate) ();
}
g_DynUpdtStatus->HwdbInitialize = NULL;
g_DynUpdtStatus->HwdbTerminate = NULL;
g_DynUpdtStatus->HwdbOpen = NULL;
g_DynUpdtStatus->HwdbClose = NULL;
g_DynUpdtStatus->HwdbAppendInfs = NULL;
g_DynUpdtStatus->HwdbFlush = NULL;
g_DynUpdtStatus->HwdbHasDriver = NULL;
g_DynUpdtStatus->HwdbHasAnyDriver = NULL;
if (g_DynUpdtStatus->HwdbLib) {
FreeLibrary (g_DynUpdtStatus->HwdbLib);
g_DynUpdtStatus->HwdbLib = NULL;
}
#ifndef UNICODE
g_DynUpdtStatus->Win9xGetIncompDrvs = NULL;
g_DynUpdtStatus->Win9xReleaseIncompDrvs = NULL;
#endif
if (g_DynUpdtStatus->WorkingDir[0]) {
p = _tcsrchr (g_DynUpdtStatus->WorkingDir, TEXT('\\'));
if (!p) {
p = g_DynUpdtStatus->WorkingDir;
}
lstrcpyn (pathPss, g_DynUpdtStatus->WorkingDir, (INT)(p - g_DynUpdtStatus->WorkingDir + 2));
lstrcat (pathPss, TEXT("setup.pss"));
CreateMultiLevelDirectory (pathPss);
lstrcat (pathPss, p);
MyDelnode (pathPss);
}
if (!DynamicUpdateSuccessful ()) {
if (g_DynUpdtStatus->WorkingDir[0]) {
//
// rename this directory to make sure no module uses any DU files
//
MYASSERT (pathPss[0]);
if (!MoveFile (g_DynUpdtStatus->WorkingDir, pathPss)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Winnt32DuUninitialize: MoveFile %1 -> %2 failed"),
0,
g_DynUpdtStatus->WorkingDir,
pathPss
);
MyDelnode (g_DynUpdtStatus->WorkingDir);
}
}
}
}
EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (_exception_code ());
DynUpdtDebugLog (Winnt32LogError, TEXT("Winnt32DuUninitialize: an exception occured"), 0);
}
END_EXCEPT
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Leave Winnt32DuUninitialize"), 0);
}
BOOL
pAddMissingPrinterDrivers (
IN OUT PSTRINGLIST* List
)
{
DWORD nBytesNeeded = 0;
DWORD nDriverRetrieved = 0;
DWORD rc;
PDRIVER_INFO_6 buffer = NULL;
DWORD index;
PCTSTR printerPnpId;
PSTRINGLIST p;
BOOL unsupported;
BOOL b = FALSE;
if (!EnumPrinterDrivers (
NULL,
NULL,
6,
NULL,
0,
&nBytesNeeded,
&nDriverRetrieved
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto exit;
}
}
if (nBytesNeeded) {
buffer = (PDRIVER_INFO_6) MALLOC (nBytesNeeded);
if (!buffer) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
//
// get printer driver information
//
if (!EnumPrinterDrivers (
NULL,
NULL,
6,
(LPBYTE)buffer,
nBytesNeeded,
&nBytesNeeded,
&nDriverRetrieved
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto exit;
}
}
for (index = 0; index < nDriverRetrieved; index++) {
printerPnpId = buffer[index].pszHardwareID;
if (!printerPnpId) {
continue;
}
if (g_DynUpdtStatus->HwdbHasDriver (
g_DynUpdtStatus->HwdbDatabase,
printerPnpId,
&unsupported
)) {
continue;
}
//
// not an in-box driver
//
p = (PSTRINGLIST) MALLOC (sizeof (STRINGLIST));
if (!p) {
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
p->String = MALLOC ((lstrlen (printerPnpId) + 2) * sizeof (TCHAR));
if (!p->String) {
FREE (p);
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
wsprintf (p->String, TEXT("%s%c"), printerPnpId, TEXT('\0'));
p->Next = NULL;
if (!InsertList ((PGENERIC_LIST*)List, (PGENERIC_LIST)p)) {
DeleteStringCell (p);
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
}
}
b = TRUE;
exit:
rc = GetLastError();
if (buffer) {
FREE (buffer);
}
SetLastError(rc);
return b;
}
HDEVINFO
(WINAPI* SetupapiDiGetClassDevs) (
IN CONST GUID *ClassGuid, OPTIONAL
IN PCWSTR Enumerator, OPTIONAL
IN HWND hwndParent, OPTIONAL
IN DWORD Flags
);
BOOL
(WINAPI* SetupapiDiGetDeviceRegistryProperty) (
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN DWORD Property,
OUT PDWORD PropertyRegDataType, OPTIONAL
OUT PBYTE PropertyBuffer,
IN DWORD PropertyBufferSize,
OUT PDWORD RequiredSize OPTIONAL
);
BOOL
(WINAPI* SetupapiDiEnumDeviceInfo) (
IN HDEVINFO DeviceInfoSet,
IN DWORD MemberIndex,
OUT PSP_DEVINFO_DATA DeviceInfoData
);
BOOL
(WINAPI* SetupapiDiDestroyDeviceInfoList) (
IN HDEVINFO DeviceInfoSet
);
#ifdef UNICODE
PSTRINGLIST
BuildMissingPnpIdList (
VOID
)
{
HDEVINFO hDeviceInfoSet;
INT nIndex = 0;
SP_DEVINFO_DATA DeviceInfoData;
PTSTR buffer = NULL;
ULONG uHwidSize, uCompatidSize;
DWORD rc;
BOOL unsupported;
PSTRINGLIST p;
PSTRINGLIST list = NULL;
HMODULE hSetupapi;
BOOL b;
BOOL bException;
if (OsVersion.dwMajorVersion <= 4) {
return list;
}
hSetupapi = LoadLibrary (TEXT("setupapi.dll"));
if (!hSetupapi) {
return list;
}
//
// get the entry points
//
(FARPROC)SetupapiDiEnumDeviceInfo = GetProcAddress (hSetupapi, "SetupDiEnumDeviceInfo");
(FARPROC)SetupapiDiDestroyDeviceInfoList = GetProcAddress (hSetupapi, "SetupDiDestroyDeviceInfoList");
(FARPROC)SetupapiDiGetClassDevs = GetProcAddress (hSetupapi, "SetupDiGetClassDevsW");
(FARPROC)SetupapiDiGetDeviceRegistryProperty = GetProcAddress (hSetupapi, "SetupDiGetDeviceRegistryPropertyW");
if (!SetupapiDiEnumDeviceInfo ||
!SetupapiDiDestroyDeviceInfoList ||
!SetupapiDiGetClassDevs ||
!SetupapiDiGetDeviceRegistryProperty
) {
FreeLibrary (hSetupapi);
return list;
}
hDeviceInfoSet = SetupapiDiGetClassDevs (NULL, NULL, NULL, DIGCF_ALLCLASSES);
if (hDeviceInfoSet == INVALID_HANDLE_VALUE) {
return list;
}
DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
while (SetupapiDiEnumDeviceInfo (hDeviceInfoSet, nIndex++, &DeviceInfoData)) {
uHwidSize = uCompatidSize = 0;
if (!SetupapiDiGetDeviceRegistryProperty (
hDeviceInfoSet,
&DeviceInfoData,
SPDRP_HARDWAREID,
NULL,
NULL,
0,
&uHwidSize
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER &&
GetLastError() != ERROR_INVALID_DATA
) {
goto exit;
}
}
if (!SetupapiDiGetDeviceRegistryProperty (
hDeviceInfoSet,
&DeviceInfoData,
SPDRP_COMPATIBLEIDS,
NULL,
NULL,
0,
&uCompatidSize
)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER &&
GetLastError() != ERROR_INVALID_DATA
) {
goto exit;
}
}
//
// allocate memory for the multi-sz buffer
//
if (!uHwidSize && !uCompatidSize) {
continue;
}
buffer = (PTSTR) MALLOC ((uHwidSize + uCompatidSize) * sizeof (TCHAR));
if (!buffer) {
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
//
// get the hardware id and compatible id
//
if (uHwidSize) {
if (!SetupapiDiGetDeviceRegistryProperty(
hDeviceInfoSet,
&DeviceInfoData,
SPDRP_HARDWAREID,
NULL,
(PBYTE)buffer,
uHwidSize,
NULL
)) {
goto exit;
}
}
if (uCompatidSize) {
if (!SetupapiDiGetDeviceRegistryProperty(
hDeviceInfoSet,
&DeviceInfoData,
SPDRP_COMPATIBLEIDS,
NULL,
(PBYTE)&buffer[uHwidSize / sizeof (TCHAR) - 1],
uCompatidSize,
NULL
)) {
goto exit;
}
}
//
// check if there is an inbox driver for this device
//
bException = FALSE;
__try {
b = g_DynUpdtStatus->HwdbHasAnyDriver (
g_DynUpdtStatus->HwdbDatabase,
buffer,
&unsupported
);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (GetExceptionCode());
DynUpdtDebugLog (Winnt32LogError, TEXT("BuildMissingPnpIdList: HwdbHasAnyDriver threw an exception"), 0);
bException = TRUE;
b = TRUE;
}
if (bException) {
__try {
//
// bad string passed back, or some internal error
// try to print the string
//
PTSTR multisz = CreatePrintableString (buffer);
DynUpdtDebugLog (Winnt32LogError, TEXT(" - The string was %1"), 0, multisz);
FREE (multisz);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DynUpdtDebugLog (Winnt32LogError, TEXT(" - Bad string"), 0);
}
}
if (b) {
FREE (buffer);
buffer = NULL;
continue;
}
//
// no inbox driver - add it to the list
//
p = (PSTRINGLIST) MALLOC (sizeof (STRINGLIST));
if (!p) {
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
p->String = buffer;
p->Next = NULL;
buffer = NULL;
if (!InsertList ((PGENERIC_LIST*)&list, (PGENERIC_LIST)p)) {
DeleteStringCell (p);
DeleteStringList (list);
list = NULL;
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
goto exit;
}
}
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
SetLastError (ERROR_SUCCESS);
}
exit:
rc = GetLastError();
SetupapiDiDestroyDeviceInfoList(hDeviceInfoSet);
FreeLibrary (hSetupapi);
if (buffer) {
FREE (buffer);
}
if (rc == ERROR_SUCCESS) {
//
// get printer drivers
//
if (ISNT()) {
if (!pAddMissingPrinterDrivers (&list)) {
rc = GetLastError();
DeleteStringList (list);
list = NULL;
}
}
}
SetLastError(rc);
return list;
}
#endif
BOOL
pHwdbHasAnyMissingDrivers (
IN HANDLE Hwdb,
IN PSTRINGLIST MissingPnpIds
)
{
PSTRINGLIST p;
BOOL unsupported;
BOOL b = FALSE;
for (p = MissingPnpIds; p; p = p->Next) {
BOOL bException = FALSE;
__try {
if (g_DynUpdtStatus->HwdbHasAnyDriver (Hwdb, p->String, &unsupported)) {
b = TRUE;
break;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (GetExceptionCode());
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pHwdbHasAnyMissingDrivers: HwdbHasAnyDriver threw an exception"),
0
);
bException = TRUE;
}
if (bException) {
__try {
//
// bad string passed back, or some internal error
// try to print the string
//
PTSTR multisz = CreatePrintableString (p->String);
DynUpdtDebugLog (Winnt32LogError, TEXT(" - The string was %1"), 0, multisz);
FREE (multisz);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DynUpdtDebugLog (Winnt32LogError, TEXT(" - Bad string"), 0);
}
}
}
return b;
}
typedef struct {
PCTSTR BaseDir;
PCTSTR Filename;
} CONTEXT_EXTRACTFILEINDIR, *PCONTEXT_EXTRACTFILEINDIR;
UINT
pExtractFileInDir (
IN PVOID Context,
IN UINT Code,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
{
if (g_DynUpdtStatus->Cancelled) {
return ERROR_CANCELLED;
}
switch (Code) {
case SPFILENOTIFY_FILEINCABINET:
{
PFILE_IN_CABINET_INFO FileInCabInfo = (PFILE_IN_CABINET_INFO)Param1;
PCONTEXT_EXTRACTFILEINDIR ctx = (PCONTEXT_EXTRACTFILEINDIR)Context;
PTSTR p;
if (lstrcmpi (FileInCabInfo->NameInCabinet, ctx->Filename)) {
return FILEOP_SKIP;
}
BuildPath (FileInCabInfo->FullTargetName, ctx->BaseDir, FileInCabInfo->NameInCabinet);
if (_tcschr (FileInCabInfo->NameInCabinet, TEXT('\\'))) {
//
// target file is in a subdir; first create it
//
p = _tcsrchr (FileInCabInfo->FullTargetName, TEXT('\\'));
if (p) {
*p = 0;
}
if (CreateMultiLevelDirectory (FileInCabInfo->FullTargetName) != ERROR_SUCCESS) {
return FILEOP_ABORT;
}
if (p) {
*p = TEXT('\\');
}
}
return FILEOP_DOIT;
}
case SPFILENOTIFY_NEEDNEWCABINET:
{
PCABINET_INFO CabInfo = (PCABINET_INFO)Param1;
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pExtractFileInDir: NeedNewCabinet %1\\%2 on %3 (SetId=%4!u!;CabinetNumber=%5!u!)"),
0,
CabInfo->CabinetPath,
CabInfo->CabinetFile,
CabInfo->DiskName,
CabInfo->SetId,
CabInfo->CabinetNumber
);
return ERROR_FILE_NOT_FOUND;
}
}
return NO_ERROR;
}
UINT
pExpandCabInDir (
IN PVOID Context,
IN UINT Code,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
{
if (g_DynUpdtStatus->Cancelled) {
return ERROR_CANCELLED;
}
switch (Code) {
case SPFILENOTIFY_FILEINCABINET:
{
PFILE_IN_CABINET_INFO FileInCabInfo = (PFILE_IN_CABINET_INFO)Param1;
PTSTR p;
BuildPath (FileInCabInfo->FullTargetName, (PCTSTR)Context, FileInCabInfo->NameInCabinet);
if (_tcschr (FileInCabInfo->NameInCabinet, TEXT('\\'))) {
//
// target file is in a subdir; first create it
//
p = _tcsrchr (FileInCabInfo->FullTargetName, TEXT('\\'));
if (p) {
*p = 0;
}
if (CreateMultiLevelDirectory (FileInCabInfo->FullTargetName) != ERROR_SUCCESS) {
return FILEOP_ABORT;
}
if (p) {
*p = TEXT('\\');
}
}
return FILEOP_DOIT;
}
case SPFILENOTIFY_NEEDNEWCABINET:
{
PCABINET_INFO CabInfo = (PCABINET_INFO)Param1;
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pExpandCabInDir: NeedNewCabinet %1\\%2 on %3 (SetId=%4!u!;CabinetNumber=%5!u!)"),
0,
CabInfo->CabinetPath,
CabInfo->CabinetFile,
CabInfo->DiskName,
CabInfo->SetId,
CabInfo->CabinetNumber
);
return ERROR_FILE_NOT_FOUND;
}
}
return NO_ERROR;
}
BOOL
pGetAutoSubdirName (
IN PCTSTR FilePath,
OUT PTSTR DirName
)
{
PTSTR p, q;
lstrcpy (DirName, FilePath);
p = _tcsrchr (DirName, TEXT('.'));
q = _tcsrchr (DirName, TEXT('\\'));
if (!p || (q && p < q)) {
return FALSE;
}
*p = 0;
return TRUE;
}
BOOL
pAddLibrariesForCompToCopyQueue (
IN PCTSTR ModuleName,
IN PCTSTR Subdir,
IN PCTSTR BaseDir,
IN HSPFILEQ SetupQueue
)
{
static struct {
PCTSTR SubDir;
PCTSTR LibsMultiSz;
} g_SubdirReqLibs [] = {
TEXT("win9xupg"), TEXT("setupapi.dll\0cfgmgr32.dll\0msvcrt.dll\0cabinet.dll\0imagehlp.dll\0"),
TEXT("winntupg"), TEXT("setupapi.dll\0cfgmgr32.dll\0msvcrt.dll\0"),
};
INT i;
TCHAR dst[MAX_PATH];
TCHAR src[MAX_PATH];
TCHAR sourceFile[MAX_PATH];
PTSTR p, q;
PCTSTR fileName;
for (i = 0; i < SIZEOFARRAY (g_SubdirReqLibs); i++) {
if (Subdir == g_SubdirReqLibs[i].SubDir ||
Subdir && !lstrcmpi (Subdir, g_SubdirReqLibs[i].SubDir)
) {
break;
}
}
if (i >= SIZEOFARRAY (g_SubdirReqLibs)) {
return TRUE;
}
//
// prepare src and dest path
//
if (!GetModuleFileName (NULL, src, MAX_PATH)) {
return FALSE;
}
p = _tcsrchr (src, TEXT('\\'));
if (!p) {
return FALSE;
}
*p = 0;
q = dst + wsprintf (dst, TEXT("%s"), BaseDir);
if (Subdir) {
p = p + wsprintf (p, TEXT("\\%s"), Subdir);
q = q + wsprintf (q, TEXT("\\%s"), Subdir);
}
//
// copy each source file
//
for (fileName = g_SubdirReqLibs[i].LibsMultiSz;
*fileName;
fileName = _tcschr (fileName, 0) + 1) {
wsprintf (q, TEXT("\\%s"), fileName);
//
// check if file already exists at dest
//
if (!pDoesFileExist (dst)) {
//
// check if the source file actually exists
//
BuildPath (sourceFile, src, fileName);
if (!pDoesFileExist (sourceFile)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Source file %1 not found"), 0, sourceFile);
return FALSE;
}
//
// prepare source path and copy file
//
*q = 0;
if (!SetupapiQueueCopy (
SetupQueue,
src,
NULL,
fileName,
NULL,
NULL,
dst,
NULL,
SP_COPY_SOURCEPATH_ABSOLUTE
)) {
return FALSE;
}
}
}
return TRUE;
}
BOOL
pIsBootDriver (
IN PCTSTR DriverFilesDir
)
{
FILEPATTERN_ENUM e;
BOOL b = FALSE;
if (EnumFirstFilePattern (&e, DriverFilesDir, TEXT("txtsetup.oem"))) {
b = !(e.FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
AbortEnumFilePattern (&e);
}
return b;
}
BOOL
pIsExcluded (
IN HINF GuiDrvsInf,
IN PCTSTR PnPId,
IN PCTSTR ActualInfFilename,
IN PCTSTR SourceDir,
IN PCTSTR FullInfPath
)
{
TCHAR buffer[MAX_PATH];
PTSTR packageName;
INFCONTEXT ic;
TCHAR field[MAX_PATH];
TCHAR driverVer[MAX_PATH];
if (!((GuiDrvsInf != INVALID_HANDLE_VALUE && PnPId && ActualInfFilename && SourceDir && FullInfPath))) {
MYASSERT (FALSE);
return FALSE;
}
lstrcpy (buffer, SourceDir);
packageName = _tcsrchr (buffer, TEXT('\\'));
if (!packageName) {
return FALSE;
}
packageName++;
if (SetupapiFindFirstLine (GuiDrvsInf, TEXT("ExcludedDrivers"), NULL, &ic)) {
do {
if (!SetupapiGetStringField (&ic, GUIDRVS_FIELD_CABNAME, field, MAX_PATH, NULL)) {
continue;
}
if (lstrcmpi (field, packageName)) {
continue;
}
if (!SetupapiGetStringField (&ic, GUIDRVS_FIELD_INFNAME, field, MAX_PATH, NULL)) {
return TRUE;
}
if (lstrcmpi (field, ActualInfFilename)) {
continue;
}
if (SetupapiGetStringField (&ic, GUIDRVS_FIELD_DRIVERVER, field, MAX_PATH, NULL)) {
if (field[0] != TEXT('*')) {
//
// read the DriverVer value out of this INF
//
GetPrivateProfileString (
TEXT("Version"),
TEXT("DriverVer"),
TEXT(""),
driverVer,
MAX_PATH,
FullInfPath
);
if (lstrcmpi (field, driverVer)) {
continue;
}
}
}
if (SetupapiGetStringField (&ic, GUIDRVS_FIELD_HARDWAREID, field, MAX_PATH, NULL) &&
lstrcmpi (field, PnPId)
) {
continue;
}
return TRUE;
} while (SetupapiFindNextLine (&ic, &ic));
}
return FALSE;
}
BOOL
Winnt32HwdbAppendInfsCallback (
IN PVOID Context,
IN PCTSTR PnpId,
IN PCTSTR ActualInfFilename,
IN PCTSTR SourceDir,
IN PCTSTR FullInfPath
)
{
HINF hGuiDrvs = (HINF)Context;
MYASSERT (hGuiDrvs != INVALID_HANDLE_VALUE);
return !pIsExcluded (hGuiDrvs, PnpId, ActualInfFilename, SourceDir, FullInfPath);
}
BOOL
pBuildHwcompDat (
IN PCTSTR DriverDir,
IN HINF GuidrvsInf, OPTIONAL
IN BOOL AlwaysRebuild,
IN BOOL AllowUI
)
{
HANDLE hDB;
TCHAR datFile[MAX_PATH];
BOOL b = TRUE;
BuildPath (datFile, DriverDir, S_HWCOMP_DAT);
if (AlwaysRebuild) {
SetFileAttributes (datFile, FILE_ATTRIBUTE_NORMAL);
DeleteFile (datFile);
}
if (pDoesFileExist (datFile)) {
return TRUE;
}
hDB = g_DynUpdtStatus->HwdbOpen (NULL);
if (!hDB) {
return FALSE;
}
if (g_DynUpdtStatus->HwdbAppendInfs (
hDB,
DriverDir,
GuidrvsInf != INVALID_HANDLE_VALUE ? Winnt32HwdbAppendInfsCallback : NULL,
(PVOID)GuidrvsInf
)) {
if (g_DynUpdtStatus->HwdbFlush (hDB, datFile)) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Successfully built precompiled hardware database %1"), 0, datFile);
} else {
if (AllowUI) {
MessageBoxFromMessage (
g_DynUpdtStatus->ProgressWindow,
MSG_ERROR_WRITING_FILE,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
GetLastError (),
datFile
);
}
b = FALSE;
}
} else {
if (AllowUI) {
MessageBoxFromMessage (
g_DynUpdtStatus->ProgressWindow,
MSG_ERROR_PROCESSING_DRIVER,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
DriverDir
);
}
b = FALSE;
}
g_DynUpdtStatus->HwdbClose (hDB);
return b;
}
UINT
pWriteAnsiFilelistToFile (
IN PVOID Context,
IN UINT Code,
IN UINT_PTR Param1,
IN UINT_PTR Param2
)
{
if (g_DynUpdtStatus->Cancelled) {
return ERROR_CANCELLED;
}
switch (Code) {
case SPFILENOTIFY_FILEINCABINET:
{
PFILE_IN_CABINET_INFO FileInCabInfo = (PFILE_IN_CABINET_INFO)Param1;
CHAR ansi[MAX_PATH];
DWORD size;
DWORD bytes;
PCTSTR p;
MYASSERT (!_tcschr (FileInCabInfo->NameInCabinet, TEXT('\\')));
#ifdef UNICODE
size = wsprintfA (ansi, "%ls\r\n", FileInCabInfo->NameInCabinet);
#else
size = wsprintfA (ansi, "%s\r\n", FileInCabInfo->NameInCabinet);
#endif
if (!WriteFile ((HANDLE)Context, ansi, size, &bytes, NULL) || bytes != size) {
return FILEOP_ABORT;
}
return FILEOP_SKIP;
}
}
return NO_ERROR;
}
BOOL
CreateFileListSif (
IN PCTSTR SifPath,
IN PCTSTR SectionName,
IN PCTSTR CabinetToScan
)
{
HANDLE sif;
CHAR ansi[MAX_PATH];
DWORD size;
DWORD bytes;
BOOL b = TRUE;
sif = CreateFile (
SifPath,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (sif == INVALID_HANDLE_VALUE) {
return FALSE;
}
#ifdef UNICODE
size = wsprintfA (ansi, "[%ls]\r\n", SectionName);
#else
size = wsprintfA (ansi, "[%s]\r\n", SectionName);
#endif
if (!WriteFile (sif, ansi, size, &bytes, NULL) || bytes != size) {
b = FALSE;
goto exit;
}
b = SetupapiCabinetRoutine (CabinetToScan, 0, pWriteAnsiFilelistToFile, (PVOID)sif);
exit:
CloseHandle (sif);
if (!b) {
DeleteFile (SifPath);
}
return b;
}
BOOL
pIsExecutableModule (
IN PCTSTR ModulePath
)
{
PCTSTR p;
p = GetFileExtension (ModulePath);
return p && !lstrcmpi (p, TEXT(".dll"));
}
UINT
pCopyFilesCallback (
IN PVOID Context, //context used by the callback routine
IN UINT Notification, //notification sent to callback routine
IN UINT_PTR Param1, //additional notification information
IN UINT_PTR Param2 //additional notification information
)
{
switch (Notification) {
case SPFILENOTIFY_COPYERROR:
return FILEOP_ABORT;
case SPFILENOTIFY_STARTCOPY:
//
// try to avoid unnecessary setupapi warnings that the files are not signed
// or even blocked because of this; try to copy the file ourselves first
//
{
PFILEPATHS paths = (PFILEPATHS)Param1;
if (CopyFile (paths->Source, paths->Target, FALSE)) {
return FILEOP_SKIP;
}
}
break;
case SPFILENOTIFY_STARTQUEUE:
case SPFILENOTIFY_STARTSUBQUEUE:
case SPFILENOTIFY_ENDSUBQUEUE:
case SPFILENOTIFY_ENDQUEUE:
return !g_DynUpdtStatus->Cancelled;
}
return SetupapiDefaultQueueCallback (Context, Notification, Param1, Param2);
}
BOOL
pProcessWinnt32Files (
IN PCTSTR Winnt32Cab,
IN BOOL ClientInstall,
OUT PBOOL StopSetup
)
{
FILEPATTERNREC_ENUM e;
TCHAR winnt32WorkingDir[MAX_PATH];
TCHAR dst[MAX_PATH];
PTSTR p, subdir;
HSPFILEQ hq;
BOOL bLoaded;
BOOL bRestartRequired;
BOOL bReloadMainInf = FALSE;
TCHAR buffer[MAX_PATH];
TCHAR origSubPath[MAX_PATH];
TCHAR origSubPathCompressed[MAX_PATH];
TCHAR origFileName[MAX_PATH];
TCHAR origFilePath[MAX_PATH];
TCHAR destFilePath[MAX_PATH];
TCHAR version[100];
DWORD i;
DWORD attr;
BOOL b = TRUE;
*StopSetup = FALSE;
if (!pNonemptyFilePresent (Winnt32Cab)) {
if (!ClientInstall) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Package %1 is not present"), 0, Winnt32Cab);
}
return TRUE;
} else {
//
// don't process the cabinet in client installation mode; just warn about that
//
if (ClientInstall) {
//
// user specified updates location, but they didn't run winnt32 /prepare now or before
//
MessageBoxFromMessage (
g_DynUpdtStatus->ProgressWindow,
MSG_MUST_PREPARE_SHARE,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONSTOP | MB_TASKMODAL,
g_DynUpdtStatus->DynamicUpdatesSource
);
*StopSetup = TRUE;
return FALSE;
}
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Analyzing package %1..."),
0,
Winnt32Cab
);
//
// expand it in the corresponding subdir
//
BuildPath (
winnt32WorkingDir,
g_DynUpdtStatus->PrepareWinnt32 ?
g_DynUpdtStatus->DynamicUpdatesSource :
g_DynUpdtStatus->WorkingDir,
S_SUBDIRNAME_WINNT32
);
//
// expand CAB in this dir
//
if (CreateMultiLevelDirectory (winnt32WorkingDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1"), 0, winnt32WorkingDir);
return FALSE;
}
if (!(*SetupapiCabinetRoutine) (Winnt32Cab, 0, pExpandCabInDir, (PVOID)winnt32WorkingDir)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1"), 0, Winnt32Cab);
return FALSE;
}
//
// ISSUE: the patching support is currently not available for platforms other than x86
//
#ifdef _X86_
//
// now let's look for any patches
//
if (EnumFirstFilePatternRecursive (&e, winnt32WorkingDir, S_PATCH_FILE_EXT, 0)) {
do {
BOOL bDeleteTempFile = FALSE;
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessWinnt32Files: found patch %1"),
0,
e.FullPath
);
//
// get the original file from the sources location
// the filename is obtained cutting the ._p1 extension
//
lstrcpy (origFileName, e.FileName);
p = GetFileExtension (origFileName);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
lstrcpy (origSubPath, e.SubPath);
p = GetFileExtension (origSubPath);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
if (!GetModuleFileName (NULL, origFilePath, MAX_PATH) ||
!(p = _tcsrchr (origFilePath, TEXT('\\')))) {
b = FALSE;
break;
}
*p = 0;
ConcatenatePaths (origFilePath, origSubPath, MAX_PATH);
//
// now check if this file (in it's compressed form or not) actually exists
//
if (!pDoesFileExist (origFilePath)) {
//
// try the compressed form
//
p = _tcschr (origFilePath, 0);
MYASSERT (p);
if (!p) {
continue;
}
p = _tcsdec (origFilePath, p);
MYASSERT (p);
if (!p) {
continue;
}
*p = TEXT('_');
if (!pDoesFileExist (origFilePath)) {
//
// the file might exist on the original installation share (like w95upgnt.dll etc)
// generate compressed form of the file
//
lstrcpy (origSubPathCompressed, origSubPath);
p = _tcschr (origSubPathCompressed, 0);
MYASSERT (p);
if (!p) {
continue;
}
p = _tcsdec (origSubPathCompressed, p);
MYASSERT (p);
if (!p) {
continue;
}
*p = TEXT('_');
//
// now search for it
//
b = FALSE;
for (i = 0; i < SourceCount; i++) {
lstrcpyn (origFilePath, NativeSourcePaths[i], SIZEOFARRAY(origFilePath));
ConcatenatePaths (origFilePath, origSubPathCompressed, SIZEOFARRAY(origFilePath));
attr = GetFileAttributes (origFilePath);
if (attr != (DWORD)-1 && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
b = TRUE;
break;
}
}
if (!b) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessWinnt32Files: Unable to find original file %1 to apply the patch"),
0,
origSubPath
);
break;
}
}
//
// expand the file to the temp dir
//
BuildPath (buffer, g_DynUpdtStatus->TempDir, origSubPath);
p = _tcsrchr (buffer, TEXT('\\'));
MYASSERT (p);
if (!p) {
continue;
}
*p = 0;
if (CreateMultiLevelDirectory (buffer) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessWinnt32Files: Unable to create dir %1"), 0, buffer);
b = FALSE;
break;
}
if (!(*SetupapiCabinetRoutine) (origFilePath, 0, pExpandCabInDir, buffer)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessWinnt32Files: Unable to expand original file %1 to dir %2"),
0,
origFilePath,
buffer
);
b = FALSE;
break;
}
*p = TEXT('\\');
lstrcpy (origFilePath, buffer);
bDeleteTempFile = TRUE;
}
BuildPath (destFilePath, winnt32WorkingDir, TEXT("$$temp$$.~~~"));
//
// now really apply the patch
//
if (!ApplyPatchToFile (e.FullPath, origFilePath, destFilePath, 0)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessWinnt32Files: ApplyPatchToFile failed to apply patch %1 to file %2"),
0,
e.FullPath,
origFilePath
);
b = FALSE;
break;
}
//
// success! now move the file to the real destination
//
BuildPath (buffer, winnt32WorkingDir, origSubPath);
p = _tcsrchr (buffer, TEXT('\\'));
MYASSERT (p);
if (!p) {
continue;
}
*p = 0;
if (CreateMultiLevelDirectory (buffer) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessWinnt32Files: Unable to create dir %1"), 0, buffer);
b = FALSE;
break;
}
*p = TEXT('\\');
SetFileAttributes (buffer, FILE_ATTRIBUTE_NORMAL);
DeleteFile (buffer);
if (!MoveFile (destFilePath, buffer)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessWinnt32Files: Unable to move file %1 to final dest %2"), 0, destFilePath, buffer);
b = FALSE;
break;
}
if (!GetFileVersion (buffer, version)) {
lstrcpy (version, TEXT("<unknown>"));
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessWinnt32Files: successfully applied patch %1 to file %2; the new file %3 has version %4"),
0,
e.FullPath,
origFilePath,
buffer,
version
);
//
// now remove the patch file
//
SetFileAttributes (e.FullPath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (e.FullPath);
if (bDeleteTempFile) {
SetFileAttributes (origFilePath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (origFilePath);
}
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
}
#endif
if (!b) {
goto exit;
}
//
// process new Winnt32 components
//
hq = SetupapiOpenFileQueue ();
if (hq == INVALID_HANDLE_VALUE) {
return FALSE;
}
if (EnumFirstFilePatternRecursive (&e, winnt32WorkingDir, TEXT("*"), 0)) {
do {
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
if (!GetModuleFileName (NULL, dst, MAX_PATH) ||
!(p = _tcsrchr (dst, TEXT('\\')))) {
b = FALSE;
break;
}
*p = 0;
ConcatenatePaths (dst, e.SubPath, MAX_PATH);
//
// check file versions first
//
if (IsFileVersionLesser (e.FullPath, dst)) {
continue;
}
//
// if there's a file named winnt32.rst, force restart
//
if (!lstrcmpi (e.FileName, S_RESTART_FILENAME)) {
if (!g_DynUpdtStatus->PrepareWinnt32) {
g_DynUpdtStatus->RestartWinnt32 = TRUE;
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("File %1 present; winnt32 will restart"),
0,
e.FileName
);
}
} else {
//
// check if dosnet.inf is present; if it is, reset the global variables
//
if (!lstrcmpi (e.FileName, InfName) && FullInfName[0]) {
FullInfName[0] = 0;
bReloadMainInf = TRUE;
}
bLoaded = FALSE;
bRestartRequired = Upgrade || !_tcschr (e.SubPath, TEXT('\\'));
if (GetModuleHandle (e.FileName) != NULL) {
bLoaded = TRUE;
if (!g_DynUpdtStatus->PrepareWinnt32) {
//
// do NOT restart if it's NOT an upgrade and this is one of the upgrade modules
//
if (bRestartRequired) {
//
// need to restart winnt32 so the newly registered component can be used instead
//
g_DynUpdtStatus->RestartWinnt32 = TRUE;
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("A newer version is available for %1; winnt32 will restart"),
0,
e.SubPath
);
}
}
}
if ((bLoaded || pIsExecutableModule (e.FullPath)) &&
(bRestartRequired || g_DynUpdtStatus->PrepareWinnt32)
) {
//
// make all required libraries available for this module
//
p = _tcsrchr (e.SubPath, TEXT('\\'));
if (p) {
*p = 0;
subdir = e.SubPath;
} else {
subdir = NULL;
}
if (!pAddLibrariesForCompToCopyQueue (e.FileName, subdir, winnt32WorkingDir, hq)) {
b = FALSE;
break;
}
if (p) {
*p = TEXT('\\');
}
}
}
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
if (b) {
PVOID ctx;
ctx = SetupapiInitDefaultQueueCallback (NULL);
b = SetupapiCommitFileQueue (NULL, hq, pCopyFilesCallback, ctx);
SetupapiTermDefaultQueueCallback (ctx);
if (!b) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessWinnt32Files: SetupapiCommitFileQueue failed"), 0);
}
}
}
SetupapiCloseFileQueue (hq);
if (b) {
SetFileAttributes (Winnt32Cab, FILE_ATTRIBUTE_NORMAL);
if (!DeleteFile (Winnt32Cab)) {
DynUpdtDebugLog (Winnt32LogSevereError, TEXT("pProcessWinnt32Files: unable to delete file %1"), 0, Winnt32Cab);
b = FALSE;
}
}
if (b && bReloadMainInf) {
b = FindPathToWinnt32File (InfName, FullInfName, MAX_PATH);
MYASSERT (b);
if (MainInf) {
UnloadInfFile (MainInf);
MainInf = NULL;
b = LoadInfFile (FullInfName, TRUE, &MainInf) == NO_ERROR;
}
}
exit:
return b;
}
BOOL
pProcessUpdates (
IN PCTSTR UpdatesCab,
IN BOOL ClientInstall,
OUT PBOOL StopSetup
)
{
TCHAR updatesSourceDir[MAX_PATH];
TCHAR buffer[MAX_PATH];
FILEPATTERNREC_ENUM e;
TCHAR origSubPath[MAX_PATH];
TCHAR origFileName[MAX_PATH];
TCHAR origFilePath[MAX_PATH];
TCHAR destFilePath[MAX_PATH];
TCHAR version[100];
PTSTR p;
TCHAR updatesCabPath[MAX_PATH];
HANDLE hCabContext;
BOOL result;
BOOL bPatchApplied = FALSE;
HANDLE hCab;
PSTRINGLIST listUpdatesFiles = NULL;
PCTSTR cabPath;
BOOL bCatalogFileFound;
HANDLE hDiamond = NULL;
BOOL b = TRUE;
*StopSetup = FALSE;
if (!pNonemptyFilePresent (UpdatesCab)) {
if (!ClientInstall) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Package %1 is not present"), 0, UpdatesCab);
}
return TRUE;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Analyzing package %1..."),
0,
UpdatesCab
);
if (ClientInstall) {
BOOL bMustPrepare = FALSE;
BuildSifName (UpdatesCab, destFilePath);
if (!pDoesFileExist (destFilePath)) {
bMustPrepare = TRUE;
} else {
BuildPath (updatesSourceDir, g_DynUpdtStatus->DynamicUpdatesSource, S_SUBDIRNAME_UPDATES);
if (!DoesDirectoryExist (updatesSourceDir)) {
bMustPrepare = TRUE;
}
}
if (bMustPrepare) {
//
// user specified updates location, but they didn't run winnt32 /prepare now or before
//
MessageBoxFromMessage (
g_DynUpdtStatus->ProgressWindow,
MSG_MUST_PREPARE_SHARE,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONSTOP | MB_TASKMODAL,
g_DynUpdtStatus->DynamicUpdatesSource
);
*StopSetup = TRUE;
return FALSE;
}
} else {
if (g_DynUpdtStatus->PrepareWinnt32) {
BuildPath (updatesSourceDir, g_DynUpdtStatus->DynamicUpdatesSource, S_SUBDIRNAME_UPDATES);
} else {
BuildPath (updatesSourceDir, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_UPDATES);
}
//
// expand CAB in this dir
// make sure dir is initially empty
//
MyDelnode (updatesSourceDir);
if (CreateMultiLevelDirectory (updatesSourceDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1"), 0, updatesSourceDir);
return FALSE;
}
if (!(*SetupapiCabinetRoutine) (UpdatesCab, 0, pExpandCabInDir, (PVOID)updatesSourceDir)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1"), 0, UpdatesCab);
return FALSE;
}
hDiamond = DiamondInitialize (g_DynUpdtStatus->TempDir);
if (!hDiamond) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to initialize compression/decompression engine"), 0);
return FALSE;
}
//
// ISSUE: the patching support is currently not available for platforms other than x86
//
#ifdef _X86_
//
// now let's look for any patches
//
if (EnumFirstFilePatternRecursive (&e, updatesSourceDir, S_PATCH_FILE_EXT, 0)) {
//
// load drvindex.inf in advance
//
TCHAR driverInfName[MAX_PATH];
PVOID driverInfHandle;
TCHAR driverCabName[MAX_PATH];
TCHAR driverCabPath[MAX_PATH];
if (!FindPathToInstallationFile (DRVINDEX_INF, driverInfName, MAX_PATH)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: Unable to find %1"),
0,
DRVINDEX_INF
);
AbortEnumFilePatternRecursive (&e);
b = FALSE;
goto exit;
}
if (LoadInfFile (driverInfName, FALSE, &driverInfHandle) != NO_ERROR) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: Unable to load %1"),
0,
driverInfName
);
AbortEnumFilePatternRecursive (&e);
b = FALSE;
goto exit;
}
do {
BOOL bDeleteTempFile = FALSE;
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessUpdates: found patch %1"),
0,
e.FullPath
);
//
// get the original file from the sources location
// the filename is obtained cutting the ._p1 extension
//
lstrcpy (origFileName, e.FileName);
p = GetFileExtension (origFileName);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
lstrcpy (origSubPath, e.SubPath);
p = GetFileExtension (origSubPath);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
BuildPath (origFilePath, SourcePaths[0], origSubPath);
//
// now check if this file (in it's compressed form or not) actually exists
// note that the file may exist in driver.cab
//
if (InDriverCacheInf (driverInfHandle, origFileName, driverCabName, MAX_PATH)) {
CONTEXT_EXTRACTFILEINDIR ctx;
//
// extract the file to the temp dir
//
if (!driverCabName[0]) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: cab name not found for %1 in %2"),
0,
origFileName,
driverInfName
);
b = FALSE;
break;
}
BuildPath (buffer, g_DynUpdtStatus->TempDir, origSubPath);
p = _tcsrchr (buffer, TEXT('\\'));
MYASSERT (p);
if (!p) {
continue;
}
*p = 0;
if (CreateMultiLevelDirectory (buffer) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: Unable to create dir %1"), 0, buffer);
b = FALSE;
break;
}
ctx.BaseDir = buffer;
ctx.Filename = origFileName;
if (!FindPathToInstallationFile (driverCabName, driverCabPath, MAX_PATH)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: Unable to find cabinet %1"),
0,
driverCabName
);
b = FALSE;
break;
}
if (!(*SetupapiCabinetRoutine) (driverCabPath, 0, pExtractFileInDir, &ctx)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: Unable to extract file %1 from %2 to %3"),
0,
origFileName,
driverCabName,
buffer
);
b = FALSE;
break;
}
*p = TEXT('\\');
lstrcpy (origFilePath, buffer);
bDeleteTempFile = TRUE;
} else {
if (!pDoesFileExist (origFilePath)) {
//
// try the compressed form
//
p = _tcschr (origFilePath, 0);
MYASSERT (p);
if (!p) {
continue;
}
p = _tcsdec (origFilePath, p);
MYASSERT (p);
if (!p) {
continue;
}
*p = TEXT('_');
if (!pDoesFileExist (origFilePath)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: Unable to find original file %1 to apply the patch"),
0,
origSubPath
);
b = FALSE;
break;
}
//
// expand the file to the temp dir
//
BuildPath (buffer, g_DynUpdtStatus->TempDir, origSubPath);
p = _tcsrchr (buffer, TEXT('\\'));
MYASSERT (p);
if (!p) {
continue;
}
*p = 0;
if (CreateMultiLevelDirectory (buffer) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: Unable to create dir %1"), 0, buffer);
b = FALSE;
break;
}
if (!(*SetupapiCabinetRoutine) (origFilePath, 0, pExpandCabInDir, buffer)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: Unable to expand original file %1 to dir %2"),
0,
origFilePath,
buffer
);
b = FALSE;
break;
}
*p = TEXT('\\');
lstrcpy (origFilePath, buffer);
bDeleteTempFile = TRUE;
}
}
BuildPath (destFilePath, updatesSourceDir, TEXT("$$temp$$.~~~"));
//
// now really apply the patch
//
if (!ApplyPatchToFile (e.FullPath, origFilePath, destFilePath, 0)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: ApplyPatchToFile failed to apply patch %1 to file %2"),
0,
e.FullPath,
origFilePath
);
b = FALSE;
break;
}
//
// success! now move the file to the real destination
//
BuildPath (buffer, updatesSourceDir, origSubPath);
p = _tcsrchr (buffer, TEXT('\\'));
MYASSERT (p);
if (!p) {
continue;
}
*p = 0;
if (CreateMultiLevelDirectory (buffer) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: Unable to create dir %1"), 0, buffer);
b = FALSE;
break;
}
*p = TEXT('\\');
SetFileAttributes (buffer, FILE_ATTRIBUTE_NORMAL);
DeleteFile (buffer);
if (!MoveFile (destFilePath, buffer)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: Unable to move file %1 to final dest %2"), 0, destFilePath, buffer);
b = FALSE;
break;
}
if (!GetFileVersion (buffer, version)) {
lstrcpy (version, TEXT("<unknown>"));
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessUpdates: successfully applied patch %1 to file %2; the new file %3 has version %4"),
0,
e.FullPath,
origFilePath,
buffer,
version
);
//
// now remove the patch file
//
SetFileAttributes (e.FullPath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (e.FullPath);
bPatchApplied = TRUE;
if (bDeleteTempFile) {
SetFileAttributes (origFilePath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (origFilePath);
}
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
UnloadInfFile (driverInfHandle);
if (!b) {
goto exit;
}
}
#endif
//
// build a new updates.cab that will contain the patched versions of files
// and no relative paths
//
BuildPath (updatesCabPath, g_DynUpdtStatus->TempDir, S_CABNAME_UPDATES);
SetFileAttributes (updatesCabPath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (updatesCabPath);
hCabContext = DiamondStartNewCabinet (updatesCabPath);
if (!hCabContext) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: DiamondStartNewCabinet failed"), 0);
b = FALSE;
goto exit;
}
bCatalogFileFound = FALSE;
if (EnumFirstFilePatternRecursive (&e, updatesSourceDir, TEXT("*"), 0)) {
do {
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
hCab = hCabContext;
cabPath = updatesCabPath;
//
// search for a previous file with the same name
//
if (FindStringCell (listUpdatesFiles, e.FileName, FALSE)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: found duplicate filename %1; aborting operation"),
0,
updatesCabPath
);
b = FALSE;
break;
}
if (!InsertList (
(PGENERIC_LIST*)&listUpdatesFiles,
(PGENERIC_LIST)CreateStringCell (e.FileName))
) {
b = FALSE;
break;
}
b = DiamondAddFileToCabinet (hCab, e.FullPath, e.FileName);
if (!b) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpdates: DiamondAddFileToCabinet(%1,%2) failed"),
0,
e.FullPath,
cabPath
);
break;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT(" ... successfully added file %1 to %2"),
0,
e.FullPath,
cabPath
);
p = GetFileExtension (e.FileName);
if (p && !lstrcmpi (p, TEXT(".cat"))) {
bCatalogFileFound = TRUE;
}
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
if (!b) {
goto exit;
}
}
result = DiamondTerminateCabinet (hCabContext);
if (!b) {
DiamondTerminateCabinet (hCabContext);
goto exit;
}
if (!result) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: DiamondTerminateCabinet(%1) failed"), 0, updatesCabPath);
b = FALSE;
goto exit;
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT(" ... done"), 0);
if (!bCatalogFileFound) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("pProcessUpdates: no catalog found in package %1"), 0, UpdatesCab);
}
BuildPath (
buffer,
g_DynUpdtStatus->PrepareWinnt32 ? g_DynUpdtStatus->DynamicUpdatesSource : g_DynUpdtStatus->WorkingDir,
S_CABNAME_UPDATES
);
if (!SetFileAttributes (buffer, FILE_ATTRIBUTE_NORMAL) ||
!DeleteFile (buffer)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: Unable to remove file %1 in order to replace it"), 0, buffer);
b = FALSE;
goto exit;
}
SetFileAttributes (buffer, FILE_ATTRIBUTE_NORMAL);
DeleteFile (buffer);
if (!MoveFile (updatesCabPath, buffer)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpdates: Unable to move file %1 to %2"), 0, updatesCabPath, buffer);
b = FALSE;
goto exit;
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("pProcessUpdates: moved file %1 to %2"), 0, updatesCabPath, buffer);
lstrcpy (updatesCabPath, buffer);
BuildSifName (updatesCabPath, destFilePath);
if (!CreateFileListSif (destFilePath, S_SECTIONNAME_UPDATES, updatesCabPath)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to build file %1"), 0, destFilePath);
b = FALSE;
goto exit;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessUpdates: created %1 containing the list of files in %2"),
0,
destFilePath,
updatesCabPath
);
}
if (!g_DynUpdtStatus->PrepareWinnt32) {
//
// build the default path to updates.cab used by the rest of setup
//
MYASSERT (IsArc() ? LocalSourceWithPlatform[0] : LocalBootDirectory[0]);
BuildPath (
g_DynUpdtStatus->UpdatesCabTarget,
IsArc() ? LocalSourceWithPlatform : LocalBootDirectory,
S_CABNAME_UPDATES
);
//
// remember current location of updates.cab
//
lstrcpy (g_DynUpdtStatus->UpdatesCabSource, UpdatesCab);
//
// the location of updated files for replacement
//
lstrcpy (g_DynUpdtStatus->UpdatesPath, updatesSourceDir);
//
// also check for the presence of a file that will cause winnt32 to build the ~LS directory
//
BuildPath (destFilePath, updatesSourceDir, S_MAKE_LS_FILENAME);
if (pDoesFileExist (destFilePath)) {
MakeLocalSource = TRUE;
}
}
exit:
if (hDiamond) {
DiamondTerminate (hDiamond);
}
if (listUpdatesFiles) {
DeleteStringList (listUpdatesFiles);
}
if (!b && UpgradeAdvisorMode) {
//
// in UpgradeAdvisor mode we expect failures
//
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Unable to process %1 in UpgradeAdvisor mode; ignoring error"), 0, UpdatesCab);
g_DynUpdtStatus->ForceRemoveWorkingDir = TRUE;
b = TRUE;
}
return b;
}
BOOL
pProcessDuasms (
IN PCTSTR DuasmsCab,
IN BOOL ClientInstall
)
{
FILEPATTERN_ENUM e;
TCHAR duasmsLocalDir[MAX_PATH];
TCHAR dirName[MAX_PATH];
DWORD rc;
HKEY key;
PCTSTR strDuasmsRegKey;
BOOL duasms = FALSE;
BOOL b = TRUE;
if (!pNonemptyFilePresent (DuasmsCab)) {
if (!ClientInstall) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Package %1 is not present"), 0, DuasmsCab);
}
return TRUE;
}
if (g_DynUpdtStatus->PrepareWinnt32) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("pProcessDuasms: Skipping it due to /%1 switch"), 0, WINNT_U_DYNAMICUPDATESPREPARE);
return TRUE;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Analyzing package %1..."),
0,
DuasmsCab
);
BuildPath (duasmsLocalDir, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_DUASMS);
//
// expand CAB in this dir
//
MyDelnode (duasmsLocalDir);
if (CreateMultiLevelDirectory (duasmsLocalDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1"), 0, duasmsLocalDir);
return FALSE;
}
if (!(*SetupapiCabinetRoutine) (DuasmsCab, 0, pExpandCabInDir, (PVOID)duasmsLocalDir)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1"), 0, DuasmsCab);
return FALSE;
}
MYASSERT (IsArc() ? LocalSourceWithPlatform[0] : LocalBootDirectory[0]);
BuildPath (
g_DynUpdtStatus->DuasmsTarget,
IsArc() ? LocalSourceWithPlatform : LocalBootDirectory,
S_SUBDIRNAME_DUASMS
);
//
// remember current location of duasms folder
//
lstrcpy (g_DynUpdtStatus->DuasmsSource, duasmsLocalDir);
return TRUE;
}
BOOL
pFindPackage (
IN HINF InfHandle,
IN PCTSTR Section,
IN PCTSTR CabName,
OUT PBOOL Partial
)
{
INFCONTEXT ic;
TCHAR value[MAX_PATH];
if (SetupapiFindFirstLine (InfHandle, Section, NULL, &ic)) {
do {
if (SetupapiGetStringField (&ic, GUIDRVS_FIELD_CABNAME, value, MAX_PATH, NULL) &&
!lstrcmpi (value, CabName)
) {
if (Partial) {
*Partial = SetupapiGetStringField (&ic, GUIDRVS_FIELD_INFNAME, value, MAX_PATH, NULL);
}
return TRUE;
}
} while (SetupapiFindNextLine (&ic, &ic));
}
return FALSE;
}
VOID
pSanitizeDriverCabName (
IN PTSTR CabName
)
{
#define CRC_SUFFIX_LENGTH 40
PTSTR p, q;
DWORD len;
//
// cut an extension like _B842485F4D3B024E675653929B247BE9C685BBD7 from the cab name
//
p = GetFileExtension (CabName);
if (p) {
MYASSERT (*p == TEXT('.'));
*p = 0;
q = _tcsrchr (CabName, TEXT('_'));
if (q) {
q++;
len = lstrlen (q);
if (len == CRC_SUFFIX_LENGTH) {
PTSTR s = q;
TCHAR ch;
while (ch = (TCHAR)_totlower (*s++)) {
if (!((ch >= TEXT('0') && ch <= TEXT('9')) ||
(ch >= TEXT('a') && ch <= TEXT('f')))
) {
break;
}
}
if (!ch) {
//
// we found what we expect
//
*(q - 1) = TEXT('.');
lstrcpy (q, p + 1);
p = NULL;
}
}
}
if (p) {
*p = TEXT('.');
}
}
}
BOOL
pIsDriverExcluded (
IN HINF InfHandle,
IN PCTSTR CabName
)
{
BOOL bPartial;
if (!pFindPackage (InfHandle, S_SECTION_EXCLUDED_DRVS, CabName, &bPartial)) {
return FALSE;
}
return !bPartial;
}
BOOL
pIsPrivateCabinet (
IN PCTSTR Filename
)
{
static PCTSTR privateCabNames[] = {
S_CABNAME_IDENT,
S_CABNAME_WSDUENG,
S_CABNAME_UPDATES,
S_CABNAME_UPGINFS,
S_CABNAME_WINNT32,
S_CABNAME_MIGDLLS,
S_CABNAME_DUASMS,
};
INT i;
for (i = 0; i < sizeof (privateCabNames) / sizeof (privateCabNames[0]); i++) {
if (!lstrcmpi (Filename, privateCabNames[i])) {
return TRUE;
}
}
return FALSE;
}
BOOL
pIsPrivateSubdir (
IN PCTSTR Subdir
)
{
static PCTSTR privateSubDirNames[] = {
S_SUBDIRNAME_TEMP,
S_SUBDIRNAME_DRIVERS,
S_SUBDIRNAME_WINNT32,
S_SUBDIRNAME_UPDATES,
S_SUBDIRNAME_UPGINFS,
S_SUBDIRNAME_MIGDLLS,
S_SUBDIRNAME_DUASMS,
};
INT i;
for (i = 0; i < sizeof (privateSubDirNames) / sizeof (privateSubDirNames[0]); i++) {
if (!lstrcmpi (Subdir, privateSubDirNames[i])) {
return TRUE;
}
}
return FALSE;
}
BOOL
pFindValueInSectionAtFieldIndex (
IN HINF InfHandle,
IN PCTSTR Section,
IN DWORD FieldIndex,
IN PCTSTR FieldValue
)
{
INFCONTEXT ic;
TCHAR value[MAX_PATH];
if (SetupapiFindFirstLine (InfHandle, Section, NULL, &ic)) {
do {
if (SetupapiGetStringField (&ic, FieldIndex, value, MAX_PATH, NULL)) {
if (lstrcmpi (FieldValue, value) == 0) {
return TRUE;
}
}
} while (SetupapiFindNextLine (&ic, &ic));
}
return FALSE;
}
BOOL
pProcessNewdrvs (
IN PCTSTR NewdrvDir,
IN BOOL ClientInstall
)
/*++
All CABs in this dir except pIsPrivateCabinet() files are considered
as containing new drivers. Each cab will be expanded in its own subdir (derived from cab filename)
--*/
{
FILEPATTERN_ENUM e;
FILEPATTERNREC_ENUM er;
TCHAR dirName[MAX_PATH];
TCHAR datFile[MAX_PATH];
TCHAR relocDriverPath[MAX_PATH];
PTSTR p;
PSDLIST entry;
HANDLE hDB;
BOOL bCreateHwdb;
BOOL bDriverNeeded;
HINF infHandle;
enum {
CT_UNKNOWN,
CT_GUI_APPROVED,
CT_GUI_NOT_APPROVED
} eContentType;
BOOL bDriverIsGuiApproved;
PSTRINGLIST missingPnpIds = NULL;
PSTRINGLIST listEntry;
BOOL bEntryFound;
INFCONTEXT ic;
TCHAR value[MAX_PATH];
TCHAR sanitizedName[MAX_PATH];
BOOL b = TRUE;
__try {
//
// first open guidrvs.inf
//
BuildPath (datFile, g_DynUpdtStatus->DynamicUpdatesSource, S_GUI_DRIVERS_INF);
infHandle = SetupapiOpenInfFile (datFile, NULL, INF_STYLE_WIN4, NULL);
if (infHandle != INVALID_HANDLE_VALUE) {
//
// copy this file together with the drivers packages (if any)
//
lstrcpy (g_DynUpdtStatus->GuidrvsInfSource, datFile);
} else {
DynUpdtDebugLog (
Winnt32LogWarning,
TEXT("Could not open INF file %1 (rc=%2!u!)"),
0,
datFile,
GetLastError ()
);
}
//
// look for CAB files and expand each one in its own subdir
//
if (!ClientInstall) {
if (EnumFirstFilePatternRecursive (&er, NewdrvDir, TEXT("*.cab"), ECF_ENUM_SUBDIRS)) {
do {
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (er.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (pIsPrivateSubdir (er.SubPath)) {
er.ControlFlags |= ECF_ABORT_ENUM_DIR;
}
continue;
}
if (!er.FindData->nFileSizeLow) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("File %1 has size 0 and will be ignored"), 0, er.FullPath);
continue;
}
lstrcpy (sanitizedName, er.FileName);
pSanitizeDriverCabName (sanitizedName);
if (pIsPrivateCabinet (sanitizedName)) {
continue;
}
BuildPath (dirName, g_DynUpdtStatus->DriversSource, sanitizedName);
p = GetFileExtension (dirName);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
//
// is this an excluded driver?
//
lstrcpy (datFile, sanitizedName);
p = GetFileExtension (datFile);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
if (pIsDriverExcluded (infHandle, datFile)) {
DynUpdtDebugLog (
Winnt32LogWarning,
TEXT("Driver %1 is excluded from processing via %2"),
0,
sanitizedName,
g_DynUpdtStatus->GuidrvsInfSource
);
if (DoesDirectoryExist (dirName)) {
//
// make sure there's no hwcomp.dat in this folder
//
BuildPath (datFile, dirName, S_HWCOMP_DAT);
if (pDoesFileExist (datFile)) {
SetFileAttributes (datFile, FILE_ATTRIBUTE_NORMAL);
DeleteFile (datFile);
}
}
continue;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Analyzing driver package %1..."),
0,
er.FullPath
);
if (DoesDirectoryExist (dirName)) {
DynUpdtDebugLog (
Winnt32LogWarning,
TEXT("Recreating existing driver %1"),
0,
dirName
);
MyDelnode (dirName);
}
if (CreateMultiLevelDirectory (dirName) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1"), 0, dirName);
continue;
}
//
// expand CAB in this dir
//
if (!(*SetupapiCabinetRoutine) (er.FullPath, 0, pExpandCabInDir, dirName)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1"), 0, er.FullPath);
if (GetLastError () == ERROR_DISK_FULL) {
DynUpdtDebugLog (Winnt32LogSevereError, TEXT("Disk is full; aborting operation"), 0);
b = FALSE;
break;
}
continue;
}
if (g_DynUpdtStatus->PrepareWinnt32) {
//
// just rebuild the hardware database
//
if (!pBuildHwcompDat (dirName, infHandle, TRUE, TRUE)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Unable to build %1 (pBuildHwcompDat failed)"),
0,
dirName
);
continue;
}
}
} while (EnumNextFilePatternRecursive (&er));
AbortEnumFilePatternRecursive (&er);
}
}
if (!b) {
__leave;
}
if (!g_DynUpdtStatus->PrepareWinnt32 &&
(!ISNT() || OsVersion.dwMajorVersion > 4)
) {
//
// look for driver dirs and analyze them
//
if (infHandle != INVALID_HANDLE_VALUE) {
//
// read the value of "DriversAreGuiApproved" key
// 1. if set to "Yes" that means all drivers listed in the [Drivers] section are approved
// for installation in GUI setup; any other driver is not approved for installation in GUI setup
// 2. if set to "No" all drivers listed are NOT good for installation in GUI setup; their install
// will be deferred post setup; any driver not listed in that section is good for GUI
// 3. if not present or set to any other value, it is ignored and the section [Drivers] is ignored;
// all drivers will be installed post GUI setup
//
eContentType = CT_UNKNOWN;
if (SetupapiFindFirstLine (infHandle, S_SECTION_VERSION, S_DRIVER_TYPE_KEY, &ic) &&
SetupapiGetStringField (&ic, 1, value, MAX_PATH, NULL)
) {
if (!lstrcmpi (value, WINNT_A_YES)) {
eContentType = CT_GUI_APPROVED;
} else if (!lstrcmpi (value, WINNT_A_NO)) {
eContentType = CT_GUI_NOT_APPROVED;
}
}
if (eContentType != CT_UNKNOWN) {
DynUpdtDebugLog (
Winnt32LogInformation,
TEXT("Entries in section [%1] of %2 will be treated as drivers to %3 be installed during GUI setup"),
0,
S_SECTION_DRIVERS,
g_DynUpdtStatus->GuidrvsInfSource,
eContentType == CT_GUI_APPROVED ? TEXT("") : TEXT("NOT")
);
} else {
DynUpdtDebugLog (
Winnt32LogWarning,
TEXT("Key %1 %5 in file %2 section [%3];")
TEXT(" entries in section [%4] will be ignored and all drivers will be installed post setup"),
0,
S_DRIVER_TYPE_KEY,
g_DynUpdtStatus->GuidrvsInfSource,
S_SECTION_VERSION,
S_SECTION_DRIVERS,
value ? TEXT("has an invalid value") : TEXT("is not present")
);
}
}
if (EnumFirstFilePattern (&e, g_DynUpdtStatus->DriversSource, TEXT("*"))) {
//
// initialize the Whistler PNP database
//
if (!g_DynUpdtStatus->HwdbDatabase) {
//
// ignore db load error
//
pInitNtPnpDb (TRUE);
}
do {
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (!(e.FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("File %1 is NOT a directory and will be ignored"), 0, e.FullPath);
continue;
}
//
// is this a needed driver?
//
bDriverNeeded = TRUE;
if (g_DynUpdtStatus->UserSpecifiedUpdates) {
//
// first build the list of missing drivers
//
if (!missingPnpIds) {
#ifdef UNICODE
missingPnpIds = BuildMissingPnpIdList ();
if (!missingPnpIds) {
DynUpdtDebugLog (
Winnt32LogInformation,
TEXT("No PNP device drivers are needed"),
0
);
}
#else
//
// let the upgrade module do driver detection on Win9x
//
if (pLoadWin9xDuSupport ()) {
PSTR* incompWin9xDrivers;
PCSTR* q;
if (g_DynUpdtStatus->Win9xGetIncompDrvs (&incompWin9xDrivers)) {
//
// convert the array returned by this function to a list style
//
g_DynUpdtStatus->IncompatibleDriversCount = 0;
if (incompWin9xDrivers) {
for (q = incompWin9xDrivers; *q; q++) {
listEntry = (PSTRINGLIST) MALLOC (sizeof (STRINGLIST));
if (listEntry) {
listEntry->String = DupMultiSz (*q);
if (!listEntry->String) {
break;
}
listEntry->Next = NULL;
if (!InsertList ((PGENERIC_LIST*)&missingPnpIds, (PGENERIC_LIST)listEntry)) {
DeleteStringCell (listEntry);
break;
}
g_DynUpdtStatus->IncompatibleDriversCount++;
}
}
}
if (g_DynUpdtStatus->Win9xReleaseIncompDrvs) {
g_DynUpdtStatus->Win9xReleaseIncompDrvs (incompWin9xDrivers);
}
} else {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Win9xGetIncompDrvs returned FALSE; no drivers will be analyzed"),
0
);
}
}
#endif
if (!missingPnpIds) {
break;
}
}
bCreateHwdb = FALSE;
//
// use the existing hardware database
//
BuildPath (datFile, e.FullPath, S_HWCOMP_DAT);
if (!pDoesFileExist (datFile)) {
bCreateHwdb = TRUE;
}
hDB = g_DynUpdtStatus->HwdbOpen (bCreateHwdb ? NULL : datFile);
if (!hDB) {
if (bCreateHwdb) {
b = FALSE;
break;
}
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Hardware database %1 is corrupt; contact your system administrator"),
0,
datFile
);
continue;
}
if (bCreateHwdb) {
if (!g_DynUpdtStatus->HwdbAppendInfs (
hDB,
e.FullPath,
infHandle != INVALID_HANDLE_VALUE ? Winnt32HwdbAppendInfsCallback : NULL,
(PVOID)infHandle
)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Unable to build %1; contact your system administrator"),
0,
datFile
);
g_DynUpdtStatus->HwdbClose (hDB);
continue;
}
//
// rebuild the default HW precompiled database
//
BuildPath (datFile, e.FullPath, S_HWCOMP_DAT);
SetFileAttributes (datFile, FILE_ATTRIBUTE_NORMAL);
DeleteFile (datFile);
if (!g_DynUpdtStatus->HwdbFlush (hDB, datFile)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Unable to build %1; contact your system administrator"),
0,
datFile
);
g_DynUpdtStatus->HwdbClose (hDB);
continue;
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Successfully built precompiled hardware database %1"), 0, datFile);
}
//
// check if this particular driver is among the ones that are needed
//
if (!pHwdbHasAnyMissingDrivers (hDB, missingPnpIds)) {
//
// this driver is not needed
//
bDriverNeeded = FALSE;
}
g_DynUpdtStatus->HwdbClose (hDB);
}
if (!bDriverNeeded) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("No needed drivers found in package %1"), 0, e.FullPath);
continue;
}
//
// is this a boot driver or a regular one?
//
if (pIsBootDriver (e.FullPath)) {
//
// add this driver to the list of boot drivers
//
if (!InsertList (
(PGENERIC_LIST*)&g_DynUpdtStatus->BootDriverPathList,
(PGENERIC_LIST)CreateStringCell (e.FileName))
) {
b = FALSE;
break;
}
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Added driver %1 to the list of BOOT drivers"), 0, e.FullPath);
}
//
// all needed drivers will be copied under LocalBootDir to be protected
// from being deleted if user decides to remove the current OS partition
//
BuildPath (relocDriverPath, IsArc() ? LocalSourceWithPlatform : LocalBootDirectory, S_SUBDIRNAME_DRIVERS);
ConcatenatePaths (relocDriverPath, e.FileName, MAX_PATH);
//
// is this a GUI driver or not?
//
if (eContentType == CT_UNKNOWN) {
bDriverIsGuiApproved = FALSE;
} else {
if (pFindValueInSectionAtFieldIndex (infHandle, S_SECTION_EXCLUDED_DRVS, GUIDRVS_FIELD_CABNAME, e.FileName)) {
//
// we don't support "partially excluded" packages for the device install
// phase of GUI setup
//
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Driver %1 is partially excluded; it will be installed at the end of GUI setup"),
0,
e.FullPath
);
bDriverIsGuiApproved = FALSE;
} else {
BOOL bPartial;
bEntryFound = pFindPackage (infHandle, S_SECTION_DRIVERS, e.FileName, &bPartial);
bDriverIsGuiApproved = eContentType == CT_GUI_APPROVED && bEntryFound && !bPartial ||
eContentType == CT_GUI_NOT_APPROVED && !bEntryFound;
}
}
//
// always make sure there's a precompiled database hwcomp.dat
// to be used at the time setup will install these additional drivers
//
if (!pBuildHwcompDat (e.FullPath, infHandle, FALSE, FALSE)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Unable to build %1 (pBuildHwcompDat failed)"),
0,
datFile
);
continue;
}
entry = MALLOC (sizeof (SDLIST));
if (!entry) {
b = FALSE;
break;
}
entry->String = DupString (relocDriverPath);
if (!entry->String) {
FREE (entry);
b = FALSE;
break;
}
entry->Data = (DWORD_PTR)bDriverIsGuiApproved;
entry->Next = NULL;
if (!InsertList (
(PGENERIC_LIST*)&g_DynUpdtStatus->NewDriversList,
(PGENERIC_LIST)entry
)) {
FREE (entry);
b = FALSE;
break;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
bDriverIsGuiApproved ?
TEXT("Driver %1 is approved for installation during GUI setup") :
TEXT("Driver %1 is NOT approved for installation during GUI setup; installation will be deferred post-setup"),
0,
e.FullPath
);
//
// copy locally this driver package (if from a share)
//
BuildPath (relocDriverPath, g_DynUpdtStatus->SelectedDrivers, e.FileName);
if (lstrcmpi (e.FullPath, relocDriverPath)) {
if (!CopyTree (e.FullPath, relocDriverPath)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Unable to copy driver %1 to %2"),
0,
e.FullPath,
relocDriverPath
);
b = FALSE;
break;
}
DynUpdtDebugLog (
Winnt32LogInformation,
TEXT("Driver %1 successfully copied to %2"),
0,
e.FullPath,
relocDriverPath
);
}
} while (EnumNextFilePattern (&e));
AbortEnumFilePattern (&e);
} else {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("No drivers found in %1"),
0,
g_DynUpdtStatus->DriversSource
);
}
if (!b) {
__leave;
}
//
// copy guidrvs.inf if present and any driver package that will be migrated over
//
if (g_DynUpdtStatus->GuidrvsInfSource[0] && g_DynUpdtStatus->NewDriversList) {
BuildPath (datFile, g_DynUpdtStatus->SelectedDrivers, S_GUI_DRIVERS_INF);
if (lstrcmpi (g_DynUpdtStatus->GuidrvsInfSource, datFile)) {
if (!CopyFile (g_DynUpdtStatus->GuidrvsInfSource, datFile, FALSE)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("Failed to copy %1 to %2"),
0,
g_DynUpdtStatus->GuidrvsInfSource,
datFile
);
b = FALSE;
}
}
if (b) {
//
// update the location of guidrvs.inf after file copy will have been done
//
BuildPath (
g_DynUpdtStatus->GuidrvsInfSource,
IsArc() ? LocalSourceWithPlatform : LocalBootDirectory,
S_SUBDIRNAME_DRIVERS
);
ConcatenatePaths (g_DynUpdtStatus->GuidrvsInfSource, S_GUI_DRIVERS_INF, MAX_PATH);
}
}
}
}
__finally {
if (missingPnpIds) {
DeleteStringList (missingPnpIds);
}
if (infHandle != INVALID_HANDLE_VALUE) {
SetupapiCloseInfFile (infHandle);
}
}
return b;
}
BOOL
pProcessUpginfs (
IN PCTSTR UpginfsCab,
IN BOOL ClientInstall
)
{
FILEPATTERNREC_ENUM e;
TCHAR upginfsSourceDir[MAX_PATH];
TCHAR upginfsDir[MAX_PATH];
TCHAR upginfsFile[MAX_PATH];
TCHAR origSubPath[MAX_PATH];
TCHAR origFileName[MAX_PATH];
TCHAR origFilePath[MAX_PATH];
TCHAR destFilePath[MAX_PATH];
TCHAR buffer[MAX_PATH];
PTSTR p;
BOOL b = TRUE;
BuildPath (upginfsSourceDir, g_DynUpdtStatus->DynamicUpdatesSource, S_SUBDIRNAME_UPGINFS);
if (ClientInstall) {
if (!DoesDirectoryExist (upginfsSourceDir)) {
return TRUE;
}
} else {
//
// expand it in the corresponding subdir
//
if (!pNonemptyFilePresent (UpginfsCab)) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("Package %1 is not present"), 0, UpginfsCab);
return TRUE;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Analyzing package %1..."),
0,
UpginfsCab
);
//
// expand CAB in this dir
// make sure dir is initially empty
//
MyDelnode (upginfsSourceDir);
if (CreateMultiLevelDirectory (upginfsSourceDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1"), 0, upginfsSourceDir);
return FALSE;
}
if (!(*SetupapiCabinetRoutine) (UpginfsCab, 0, pExpandCabInDir, (PVOID)upginfsSourceDir)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1"), 0, UpginfsCab);
return FALSE;
}
//
// ISSUE: the patching support is currently not available for platforms other than x86
//
#ifdef _X86_
//
// now let's look for any patches
//
if (EnumFirstFilePatternRecursive (&e, upginfsSourceDir, S_PATCH_FILE_EXT, 0)) {
do {
BOOL bDeleteTempFile = FALSE;
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessUpginfs: found patch %1"),
0,
e.FullPath
);
//
// get the original file from the sources location
// the filename is obtained cutting the ._p1 extension
//
lstrcpy (origFileName, e.FileName);
p = GetFileExtension (origFileName);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
lstrcpy (origSubPath, e.SubPath);
p = GetFileExtension (origSubPath);
if (!p) {
MYASSERT (FALSE);
continue;
}
*p = 0;
BuildPath (origFilePath, NativeSourcePaths[0], origSubPath);
//
// now check if this file (in it's compressed form or not) actually exists
//
if (!pDoesFileExist (origFilePath)) {
//
// try the compressed form
//
p = _tcschr (origFilePath, 0);
MYASSERT (p);
if (!p) {
continue;
}
p = _tcsdec (origFilePath, p);
MYASSERT (p);
if (!p) {
continue;
}
*p = TEXT('_');
if (!pDoesFileExist (origFilePath)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpginfs: Unable to find original file %1 to apply the patch"),
0,
origSubPath
);
b = FALSE;
break;
}
//
// expand the file to the temp dir
//
BuildPath (buffer, g_DynUpdtStatus->TempDir, origSubPath);
p = _tcsrchr (buffer, TEXT('\\'));
MYASSERT (p);
if (!p) {
continue;
}
*p = 0;
if (CreateMultiLevelDirectory (buffer) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpginfs: Unable to create dir %1"), 0, buffer);
b = FALSE;
break;
}
if (!(*SetupapiCabinetRoutine) (origFilePath, 0, pExpandCabInDir, buffer)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpginfs: Unable to expand original file %1 to dir %2"),
0,
origFilePath,
buffer
);
b = FALSE;
break;
}
*p = TEXT('\\');
lstrcpy (origFilePath, buffer);
bDeleteTempFile = TRUE;
}
BuildPath (destFilePath, upginfsSourceDir, TEXT("$$temp$$.~~~"));
//
// now really apply the patch
//
if (!ApplyPatchToFile (e.FullPath, origFilePath, destFilePath, 0)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("pProcessUpginfs: ApplyPatchToFile failed to apply patch %1 to file %2"),
0,
e.FullPath,
origFilePath
);
b = FALSE;
break;
}
//
// success! now move the file to the real destination
//
BuildPath (buffer, upginfsSourceDir, origFileName);
if (pDoesFileExist (buffer)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpginfs: duplicate file found %1"), 0, origFileName);
b = FALSE;
break;
}
//
// all patches MUST be .rep files; change extension from .inf to .rep
//
p = GetFileExtension (buffer);
if (!p || lstrcmpi (p, TEXT(".inf"))) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpginfs: Unexpected file extension in %1"), 0, buffer);
b = FALSE;
break;
}
lstrcpy (p, TEXT(".rep"));
SetFileAttributes (buffer, FILE_ATTRIBUTE_NORMAL);
DeleteFile (buffer);
if (!MoveFile (destFilePath, buffer)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpginfs: Unable to move file %1 to final dest %2"), 0, destFilePath, buffer);
b = FALSE;
break;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("pProcessUpginfs: successfully applied patch %1 to file %2; the new file was renamed %3"),
0,
e.FullPath,
origFilePath,
buffer
);
//
// now remove the patch file
//
SetFileAttributes (e.FullPath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (e.FullPath);
if (bDeleteTempFile) {
SetFileAttributes (origFilePath, FILE_ATTRIBUTE_NORMAL);
DeleteFile (origFilePath);
}
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
if (!b) {
goto exit;
}
}
SetFileAttributes (UpginfsCab, FILE_ATTRIBUTE_NORMAL);
DeleteFile (UpginfsCab);
#endif
}
if (!b) {
goto exit;
}
if (!g_DynUpdtStatus->PrepareWinnt32) {
//
// only do file installation on Win9x platforms
//
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof (vi);
GetVersionEx (&vi);
if (vi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Package %1 ignored on NT platforms"),
0,
UpginfsCab
);
return TRUE;
}
//
// prepare the target directory (%windir%\upginfs)
//
if (!MyGetWindowsDirectory (upginfsDir, MAX_PATH)) {
return FALSE;
}
ConcatenatePaths (upginfsDir, S_SUBDIRNAME_UPGINFS, MAX_PATH);
if (!CreateDir (upginfsDir)) {
return FALSE;
}
//
// copy relevant files to %windir%\Upginfs
//
if (EnumFirstFilePatternRecursive (&e, upginfsSourceDir, TEXT("*.add"), 0)) {
do {
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
if (!e.FindData->nFileSizeLow) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("File %1 has size 0 and will be ignored"), 0, e.FullPath);
continue;
}
BuildPath (upginfsFile, upginfsDir, e.FileName);
SetFileAttributes (upginfsFile, FILE_ATTRIBUTE_NORMAL);
if (!CopyFile (e.FullPath, upginfsFile, FALSE)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpginfs: Error copying %1 to %2"), 0, e.FullPath, upginfsFile);
b = FALSE;
break;
}
//
// let w95upg.dll know about the new files
//
UpginfsUpdated = TRUE;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("pProcessUpginfs: INF %1 successfully copied to %2"), 0, e.FullPath, upginfsFile);
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
}
if (b) {
if (EnumFirstFilePatternRecursive (&e, upginfsSourceDir, TEXT("*.rep"), 0)) {
do {
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
if (!e.FindData->nFileSizeLow) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("File %1 has size 0 and will be ignored"), 0, e.FullPath);
continue;
}
BuildPath (upginfsFile, upginfsDir, e.FileName);
SetFileAttributes (upginfsFile, FILE_ATTRIBUTE_NORMAL);
if (!CopyFile (e.FullPath, upginfsFile, FALSE)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("pProcessUpginfs: Error copying %1 to %2"), 0, e.FullPath, upginfsFile);
b = FALSE;
break;
}
//
// let w95upg.dll know about the new files
//
UpginfsUpdated = TRUE;
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("pProcessUpginfs: INF %1 successfully copied to %2"), 0, e.FullPath, upginfsFile);
} while (EnumNextFilePatternRecursive (&e));
AbortEnumFilePatternRecursive (&e);
}
}
}
exit:
return b;
}
#ifdef _X86_
BOOL
pProcessMigdlls (
IN PCTSTR MigdllsCab,
IN BOOL ClientInstall
)
{
FILEPATTERN_ENUM e;
TCHAR migdllsLocalDir[MAX_PATH];
TCHAR dirName[MAX_PATH];
DWORD rc;
HKEY key;
PCTSTR strMigdllsRegKey;
BOOL migdlls = FALSE;
BOOL b = TRUE;
if (!pNonemptyFilePresent (MigdllsCab)) {
return TRUE;
}
if (g_DynUpdtStatus->PrepareWinnt32) {
DynUpdtDebugLog (DynUpdtLogLevel, TEXT("pProcessMigdlls: Skipping it due to /%1 switch"), 0, WINNT_U_DYNAMICUPDATESPREPARE);
return TRUE;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Analyzing package %1..."),
0,
MigdllsCab
);
BuildPath (migdllsLocalDir, g_DynUpdtStatus->WorkingDir, S_SUBDIRNAME_MIGDLLS);
//
// expand CAB in this dir
//
MyDelnode (migdllsLocalDir);
if (CreateMultiLevelDirectory (migdllsLocalDir) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1"), 0, migdllsLocalDir);
return FALSE;
}
if (!(*SetupapiCabinetRoutine) (MigdllsCab, 0, pExpandCabInDir, (PVOID)migdllsLocalDir)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1"), 0, MigdllsCab);
return FALSE;
}
//
// look for CAB files and expand each one in its own subdir
//
if (EnumFirstFilePattern (&e, migdllsLocalDir, TEXT("*.cab"))) {
do {
if (g_DynUpdtStatus->Cancelled) {
SetLastError (ERROR_CANCELLED);
b = FALSE;
break;
}
if (e.FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
continue;
}
if (!e.FindData.nFileSizeLow) {
DynUpdtDebugLog (Winnt32LogWarning, TEXT("File %1 has size 0 and will be ignored"), 0, e.FullPath);
continue;
}
pGetAutoSubdirName (e.FullPath, dirName);
if (CreateMultiLevelDirectory (dirName) != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to create dir %1; skipping it"), 0, dirName);
continue;
}
//
// expand CAB in this dir
//
if (!(*SetupapiCabinetRoutine) (e.FullPath, 0, pExpandCabInDir, (PVOID)dirName)) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to expand cabinet %1; skipping it"), 0, e.FullPath);
continue;
}
migdlls = TRUE;
} while (EnumNextFilePattern (&e));
}
if (b && migdlls) {
//
// register them
//
strMigdllsRegKey = ISNT () ? S_REGKEY_MIGRATION_DLLS_WINNT : S_REGKEY_MIGRATION_DLLS_WIN9X;
rc = RegCreateKey (HKEY_LOCAL_MACHINE, strMigdllsRegKey, &key);
if (rc == ERROR_SUCCESS) {
rc = RegSetValueEx (key, S_REGVALUE_DYNUPDT, 0, REG_SZ, (CONST BYTE*)migdllsLocalDir, (lstrlen (migdllsLocalDir) + 1) * sizeof (TCHAR));
}
if (rc != ERROR_SUCCESS) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Unable to register downloaded migdlls (rc=%1!u!)"), 0, rc);
b = FALSE;
}
}
return b;
}
#endif
BOOL
ProcessDownloadedFiles (
OUT PBOOL StopSetup
)
{
TCHAR cabName[MAX_PATH];
BOOL bClientInstall = FALSE;
if (g_DynUpdtStatus->UserSpecifiedUpdates && !g_DynUpdtStatus->PrepareWinnt32) {
bClientInstall = TRUE;
}
DynUpdtDebugLog (
DynUpdtLogLevel,
TEXT("Source=%1"),
0,
g_DynUpdtStatus->UserSpecifiedUpdates ? g_DynUpdtStatus->DynamicUpdatesSource : TEXT("Windows Update")
);
if (!g_DynUpdtStatus->HwdbInitialize) {
if (CreateMultiLevelDirectory (g_DynUpdtStatus->TempDir) != ERROR_SUCCESS ||
!pInitializeSupport (S_HWDB_DLL, pLoadHwdbLib, FALSE) ||
!g_DynUpdtStatus->HwdbInitialize (g_DynUpdtStatus->TempDir)
) {
return FALSE;
}
}
if (!Winnt32Restarted ()) {
BuildPath (cabName, g_DynUpdtStatus->DynamicUpdatesSource, S_CABNAME_WINNT32);
if (!pProcessWinnt32Files (cabName, bClientInstall, StopSetup)) {
return FALSE;
}
if (g_DynUpdtStatus->RestartWinnt32) {
MYASSERT (!g_DynUpdtStatus->PrepareWinnt32);
return TRUE;
}
}
BuildPath (cabName, g_DynUpdtStatus->DynamicUpdatesSource, S_CABNAME_UPDATES);
if (!pProcessUpdates (cabName, bClientInstall, StopSetup)) {
if (g_DynUpdtStatus->PrepareWinnt32) {
MessageBoxFromMessage (
g_DynUpdtStatus->ProgressWindow,
MSG_ERROR_PROCESSING_UPDATES,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
GetLastError (),
cabName
);
}
return FALSE;
}
//
// process New Assemblies on WU
//
BuildPath (cabName, g_DynUpdtStatus->DynamicUpdatesSource, S_CABNAME_DUASMS);
if (!pProcessDuasms (cabName, bClientInstall)) {
//
// don't fail DU if we didn't install them
//
}
BuildPath (cabName, g_DynUpdtStatus->DynamicUpdatesSource, S_CABNAME_UPGINFS);
if (!pProcessUpginfs (cabName, bClientInstall)) {
return FALSE;
}
#ifdef _X86_
BuildPath (cabName, g_DynUpdtStatus->DynamicUpdatesSource, S_CABNAME_MIGDLLS);
if (!pProcessMigdlls (cabName, bClientInstall)) {
return FALSE;
}
#endif
if (!pProcessNewdrvs (g_DynUpdtStatus->DynamicUpdatesSource, bClientInstall)) {
return FALSE;
}
return TRUE;
}
BOOL
Winnt32Restarted (
VOID
)
{
return g_DynUpdtStatus->Winnt32Restarted;
}
BOOL
Winnt32RestartedWithAF (
VOID
)
{
return g_DynUpdtStatus->RestartAnswerFile[0];
}
VOID
pLogWininetError (
IN DWORD Error
)
{
HMODULE hWinInet = LoadLibrary (TEXT("wininet.dll"));
if (hWinInet) {
HLOCAL msg = NULL;
FormatMessage (
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
hWinInet,
Error,
0,
(LPTSTR)&msg,
0,
NULL
);
if (msg) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Failure with wininet error code %1!u!: \"%2\""), 0, Error, msg);
LocalFree (msg);
}
FreeLibrary (hWinInet);
}
}
VOID
pLogStandardError (
IN DWORD Error
)
{
HLOCAL msg = NULL;
FormatMessage (
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
Error,
0,
(LPTSTR)&msg,
0,
NULL
);
if (msg) {
DynUpdtDebugLog (Winnt32LogError, TEXT("Failure with standard error code %1!u!:\r\n%2"), 0, Error, msg);
LocalFree (msg);
}
}
VOID
pUpdateDUStatus (
IN DWORD Error
)
{
MYASSERT (Error != ERROR_SUCCESS);
if (Error == ERROR_SUCCESS) {
g_DynUpdtStatus->DUStatus = DUS_ERROR;
return;
}
switch (Error) {
case ERROR_CONNECTION_UNAVAIL:
//
// ask for manual connection
//
MYASSERT (g_DynUpdtStatus->DUStatus == DUS_PREPARING);
g_DynUpdtStatus->DUStatus = DUS_PREPARING_CONNECTIONUNAVAILABLE;
break;
case ERROR_INTERNET_INVALID_URL:
case ERROR_INTERNET_NAME_NOT_RESOLVED:
//
// site not available; ask user if they want to retry
//
MYASSERT (g_DynUpdtStatus->DUStatus == DUS_PREPARING);
g_DynUpdtStatus->DUStatus = DUS_PREPARING_INVALIDURL;
break;
case ERROR_INVALID_PARAMETER:
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OLD_WIN_VERSION:
case ERROR_OUTOFMEMORY:
case ERROR_NO_MORE_ITEMS:
case ERROR_FILE_NOT_FOUND:
case ERROR_INVALID_DATA:
case ERROR_UNSUPPORTED_TYPE:
case ERROR_INVALID_HANDLE:
pLogStandardError (Error);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
break;
case DU_ERROR_MISSING_DLL:
case DU_NOT_INITIALIZED:
DynUpdtDebugLog (Winnt32LogError, TEXT("Failure with custom error code %1!u!"), 0, Error);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
break;
case ERROR_INTERNET_NO_CONTEXT:
pLogWininetError (Error);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
break;
default:
if (Error > INTERNET_ERROR_BASE) {
pLogWininetError (Error);
} else {
pLogStandardError (Error);
}
}
}
DWORD
WINAPI
DoDynamicUpdate (
LPVOID Parameter
)
{
#define MIN_INTERVAL_BETWEEN_TASKS 3000
HWND hUIWindow = (HWND)Parameter;
DWORD rc = ERROR_SUCCESS;
LONG ticks;
LONG sleep;
DWORD estTime, estSize;
TCHAR drive[4];
DWORD sectorsPerCluster;
DWORD bytesPerSector;
ULARGE_INTEGER freeClusters = {0, 0};
ULARGE_INTEGER totalClusters = {0, 0};
DWORD clusterSize;
ULONGLONG availableBytes;
HANDLE hEvent;
BOOL bStopSetup;
BOOL bContinue = TRUE;
hEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE, S_DU_SYNC_EVENT_NAME);
if (!hEvent) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("OpenEvent(%1) failed"),
0,
S_DU_SYNC_EVENT_NAME
);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
goto exit;
}
while (bContinue) {
if (g_DynUpdtStatus->Cancelled) {
g_DynUpdtStatus->DUStatus = DUS_CANCELLED;
rc = ERROR_CANCELLED;
DynamicUpdateUninitialize ();
break;
}
switch (g_DynUpdtStatus->DUStatus) {
case DUS_INITIAL:
if (Winnt32Restarted () || g_DynUpdtStatus->UserSpecifiedUpdates) {
g_DynUpdtStatus->DUStatus = DUS_PROCESSING;
break;
}
g_DynUpdtStatus->DUStatus = DUS_PREPARING;
SendMessage (hUIWindow, WMX_SETUPUPDATE_PREPARING, 0, 0);
break;
case DUS_PREPARING:
ticks = GetTickCount ();
if (!DynamicUpdateInitDownload (hUIWindow)) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("DynamicUpdateInitDownload failed"),
0
);
pUpdateDUStatus (GetLastError ());
if (g_DynUpdtStatus->DUStatus != DUS_SKIP &&
g_DynUpdtStatus->DUStatus != DUS_ERROR) {
//
// the UI thread will decide what the next state will be
// based on user's selection
//
PostMessage (hUIWindow, WMX_SETUPUPDATE_INIT_RETRY, 0, 0);
rc = WaitForSingleObject (hEvent, INFINITE);
if (rc != WAIT_OBJECT_0) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("WaitForSingleObject failed (%1!u!)"),
0,
rc
);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
break;
}
}
break;
}
sleep = ticks + MIN_INTERVAL_BETWEEN_TASKS - (LONG)GetTickCount ();
if (sleep > 0 && sleep <= MIN_INTERVAL_BETWEEN_TASKS) {
Sleep (sleep);
}
g_DynUpdtStatus->DUStatus = DUS_DOWNLOADING;
break;
case DUS_DOWNLOADING:
ticks = GetTickCount ();
estSize = estTime = 0;
if (!DynamicUpdateStart (&estTime, &estSize)) {
g_DynUpdtStatus->DUStatus = DUS_ERROR;
break;
}
//
// check if there is enough disk space available for this operation
//
lstrcpyn (drive, g_DynUpdtStatus->WorkingDir, 3);
if (GetDiskFreeSpaceNew (
drive,
&sectorsPerCluster,
&bytesPerSector,
&freeClusters,
&totalClusters
)) {
clusterSize = bytesPerSector * sectorsPerCluster;
availableBytes = (ULONGLONG)clusterSize * freeClusters.QuadPart;
//
// assume the average-worst case where each file occupies 1/2 cluster
// then the space required is the double of estimated space
//
if (availableBytes < (ULONGLONG)estSize * 2) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("DoDynamicUpdate: not enough free space on drive %1 to perform download (available=%2!u! MB, needed=%3!u! MB)"),
0,
drive,
(DWORD)(availableBytes >> 20),
(DWORD)(estSize >> 20)
);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
DynamicUpdateCancel ();
//
// wait for the UI thread to signal the event, no more than about a minute
//
rc = WaitForSingleObject (hEvent, 66000);
if (rc == WAIT_TIMEOUT) {
//
// why?
//
MYASSERT (FALSE);
} else if (rc != WAIT_OBJECT_0) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("WaitForSingleObject failed (%1!u!)"),
0,
rc
);
}
break;
}
}
SendMessage (hUIWindow, WMX_SETUPUPDATE_DOWNLOADING, estTime, estSize);
rc = WaitForSingleObject (hEvent, INFINITE);
if (rc != WAIT_OBJECT_0) {
DynUpdtDebugLog (
Winnt32LogError,
TEXT("WaitForSingleObject failed (%1!u!)"),
0,
rc
);
g_DynUpdtStatus->DUStatus = DUS_ERROR;
break;
}
sleep = ticks + MIN_INTERVAL_BETWEEN_TASKS - (LONG)GetTickCount ();
if (sleep > 0 && sleep <= MIN_INTERVAL_BETWEEN_TASKS) {
Sleep (sleep);
}
//
// the UI thread has already set the next state,
// based on the result of download
//
break;
case DUS_PROCESSING:
ticks = GetTickCount ();
SendMessage (hUIWindow, WMX_SETUPUPDATE_PROCESSING, 0, 0);
if (!g_DynUpdtStatus->UserSpecifiedUpdates) {
lstrcpy (g_DynUpdtStatus->DynamicUpdatesSource, g_DynUpdtStatus->WorkingDir);
}
bStopSetup = FALSE;
if (!DynamicUpdateProcessFiles (&bStopSetup)) {
g_DynUpdtStatus->DUStatus = bStopSetup ? DUS_FATALERROR : DUS_ERROR;
break;
}
sleep = ticks + MIN_INTERVAL_BETWEEN_TASKS - (LONG)GetTickCount ();
if (sleep > 0 && sleep <= MIN_INTERVAL_BETWEEN_TASKS) {
Sleep (sleep);
}
g_DynUpdtStatus->DUStatus = DUS_SUCCESSFUL;
break;
case DUS_SUCCESSFUL:
if (CheckUpgradeOnly && !g_DynUpdtStatus->RestartWinnt32 && !g_DynUpdtStatus->UserSpecifiedUpdates) {
if (pSaveLastDownloadInfo ()) {
g_DynUpdtStatus->PreserveWorkingDir = TRUE;
}
}
//
// fall through
//
case DUS_ERROR:
case DUS_FATALERROR:
case DUS_SKIP:
//
// always make sure to uninitialize DU
// if the user had a modem connection active, this should close
// the connection
// DynamicUpdateUninitialize () will not reset any DU data
// in case the processing was successful
//
DynamicUpdateUninitialize ();
bContinue = FALSE;
break;
default:
MYASSERT (FALSE);
}
}
CloseHandle (hEvent);
exit:
//
// always notify the UI thread before exiting
//
PostMessage (hUIWindow, WMX_SETUPUPDATE_THREAD_DONE, 0, 0);
return rc;
}