windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/w95upgnt/migmain/migmain.c

3822 lines
99 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
migmain.c
Abstract:
MigMain is called from w95upgnt.dll, which is called from SYSSETUP.DLL.
It is the main migration loop on the NT side of setup. MigMain loops
through all users on the Win95 side of configuration, migrates their
registry, creates their account, and fixes up their profile folders.
Then MigMain migrates all machine-specific settings such as link changes
and file deletion.
Author:
Jim Schmidt (jimschm) 12-Jul-1996
Revision History:
marcw 26-Mar-1999 More boot16 fixes -- hide msdos7 dir, fix to msdos.sys
marcw 18-Mar-1999 fixes for boot16 environment in localized case.
jimschm 23-Sep-1998 Changes for fileops & shell.c
calinn 23-Sep-1998 Changes for memdb fixup
jimschm 02-Jul-1998 Support for progress bar
jimschm 11-Jun-1998 Support for dynamic user profile paths in memdb
jimschm 05-May-1998 Migration of Default User if unattend option is enabled
jimschm 27-Apr-1998 Added icon preservation
jimschm 18-Mar-1998 Added pProcessAutoLogon
calinn 19-Nov-1997 Added pEnable16Boot, will create a 16 bit environment boot entry in boot.ini
jimschm 01-Oct-1997 Localized Everyone group
jimschm 13-Sep-1997 Reg Quota for beta 1 workaround
jimschm 21-Jul-1997 Use of fileops for ConvertWin9xPath (to be moved later)
jimschm 28-May-1997 Cleaned up
marcw 21-Mar-1997 added Pathmapping
jimschm 04-Feb-1997 Moved code into usermig.c and wkstamig.c
jimschm 15-Jan-1997 Plug-in spec modifications (now in migdlls.c)
jimschm 03-Jan-1997 Added g_UserName
jimschm 18-Dec-1996 Extracted code from miginf
mikeco O4-Dec-1996 Enumerate/modify PIF and LNK files
jimschm 23-Oct-1996 Joined ProcessUserInfs and ApplyChanges
jimschm 02-Oct-1996 Added default user migration
--*/
#include "pch.h"
#include "migmainp.h"
#include "fileops.h"
#include "quota.h"
#ifndef UNICODE
#error UNICODE required
#endif
#ifdef DEBUG
BOOL g_NoReloadsAllowed = FALSE;
#define DBG_VALIDNTFILES "NtFiles"
#endif
typedef BOOL (*PROFILE_PATH_PROVIDER)(OUT PTSTR AccountName, OUT PTSTR PathProfile);
//
// Globals for migmain.lib
//
HKEY g_hKeyRoot95, g_hKeyRootNT;
PCTSTR g_DomainUserName;
PCTSTR g_Win9xUserName;
PCTSTR g_FixedUserName;
PVOID g_HiveTable;
POOLHANDLE g_HivePool;
PVOID g_NulSessionTable;
PCTSTR g_EveryoneStr;
PCTSTR g_AdministratorsGroupStr;
PCTSTR g_PowerUsersGroupStr;
PCTSTR g_DomainUsersGroupStr;
PCTSTR g_NoneGroupStr;
TCHAR g_IconBin[MAX_TCHAR_PATH];
TCHAR g_DefaultUserName[MAX_USER_NAME];
TCHAR g_ComputerName[MAX_SERVER_NAME];
BOOL g_BlowAwayTempShellFolders = FALSE;
UINT g_Boot16 = BOOT16_AUTOMATIC;
//
// Buffer for GetString's messages
//
static TCHAR g_MsgBuf[2048];
//
// Flag identifying if the SKU is Personal
//
BOOL g_PersonalSKU = FALSE;
//
// Prototypes for migmain.c only
//
BOOL
pSetWin9xUpgValue (
VOID
);
VOID
pCountUsers (
OUT PDWORD TotalUsersPtr,
OUT PDWORD ActiveUsersPtr
);
BOOL
pMigrateUsers (
VOID
);
VOID
pRaiseRegistryQuota (
PCTSTR Win9xSystemDatSpec
);
VOID
pEnable16Boot (
VOID
);
VOID
pProcessAutoLogon (
BOOL Final
);
VOID
pFixUpMemDb (
VOID
);
BOOL
WINAPI
MigMain_Entry (
IN HINSTANCE hinstDLL,
IN DWORD dwReason,
IN PVOID lpv
)
/*++
Routine Description:
MigMain_Entry is called at DLL initialization time
Arguments:
hinstDLL - (OS-supplied) Instance handle for the DLL
dwReason - (OS-supplied) Type of initialization or termination
lpv - (OS-supplied) Unused
Return Value:
TRUE because LIB always initializes properly.
--*/
{
DWORD Size;
OSVERSIONINFOEX osviex;
switch (dwReason) {
case DLL_PROCESS_ATTACH:
if(!pSetupInitializeUtils()) {
return FALSE;
}
g_hKeyRoot95 = g_hKeyRootNT = NULL;
g_HivePool = PoolMemInitNamedPool ("Hive path pool");
if (!g_HivePool) {
return FALSE;
}
// Alloc string tables
g_HiveTable = pSetupStringTableInitializeEx (MAX_TCHAR_PATH,0);
if (!g_HiveTable) {
return FALSE;
}
g_NulSessionTable = pSetupStringTableInitializeEx (sizeof(PCWSTR), 0);
if (!g_NulSessionTable) {
return FALSE;
}
//
// Determine if upgrading to Personal SKU
//
osviex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
if (!GetVersionEx ((LPOSVERSIONINFO)&osviex)) {
MYASSERT (FALSE);
}
if (osviex.wProductType == VER_NT_WORKSTATION &&
(osviex.wSuiteMask & VER_SUITE_PERSONAL)
) {
g_PersonalSKU = TRUE;
}
#if 0
if (g_PersonalSKU) {
g_EveryoneStr = GetStringResource (MSG_EVERYONE_GROUP);
g_AdministratorsGroupStr = GetStringResource (MSG_OWNERS_GROUP);
g_PowerUsersGroupStr = GetStringResource (MSG_POWER_USERS_GROUP);
g_DomainUsersGroupStr = GetStringResource (MSG_DOMAIN_USERS_GROUP);
g_NoneGroupStr = GetStringResource (MSG_NONE_GROUP);
} else {
#endif
g_EveryoneStr = GetStringResource (MSG_EVERYONE_GROUP);
g_AdministratorsGroupStr = GetStringResource (MSG_ADMINISTRATORS_GROUP);
g_PowerUsersGroupStr = GetStringResource (MSG_POWER_USERS_GROUP);
g_DomainUsersGroupStr = GetStringResource (MSG_DOMAIN_USERS_GROUP);
g_NoneGroupStr = GetStringResource (MSG_NONE_GROUP);
Size = ARRAYSIZE(g_ComputerName);
if (!GetComputerName (g_ComputerName, &Size)) {
g_ComputerName[0] = 0;
}
MYASSERT (
g_ComputerName[0] &&
g_EveryoneStr &&
g_AdministratorsGroupStr &&
g_PowerUsersGroupStr &&
g_DomainUsersGroupStr &&
g_NoneGroupStr
);
FindAccountInit();
break;
case DLL_PROCESS_DETACH:
if (g_HiveTable) {
pSetupStringTableDestroy (g_HiveTable);
}
if (g_NulSessionTable) {
pSetupStringTableDestroy (g_NulSessionTable);
}
if (g_HivePool) {
PoolMemDestroyPool (g_HivePool);
}
FreeStringResource (g_EveryoneStr);
FreeStringResource (g_AdministratorsGroupStr);
FreeStringResource (g_DomainUsersGroupStr);
FindAccountTerminate();
pSetupUninitializeUtils();
break;
}
return TRUE;
}
#ifdef DEBUG
BOOL
pValidateNtFiles (
VOID
)
/*++
Routine Description:
pValidateNtFiles validates the list of files that are supposed to be installed
by NT. We check for the flag set on Win95 side and for each entry we check to
see if the file is realy present (e.g. was installed by NT). If not then we delete
the entry.
Arguments:
none
Return Value:
Always returns TRUE
--*/
{
MEMDB_ENUMW enumFiles;
WCHAR key[MEMDB_MAX];
PWSTR fileName;
TREE_ENUMW enumTree;
DWORD value;
if (MemDbEnumFirstValue (
&enumFiles,
TEXT(MEMDB_CATEGORY_NT_FILESA)TEXT("\\*"),
MEMDB_ALL_SUBLEVELS,
MEMDB_ENDPOINTS_ONLY
)) {
do {
if (MemDbBuildKeyFromOffsetW (enumFiles.dwValue, key, 1, NULL)) {
fileName = JoinPaths (key, enumFiles.szName);
if (!DoesFileExistW (fileName)) {
MemDbSetValueEx (
MEMDB_CATEGORY_NT_FILES_BAD,
enumFiles.szName,
NULL,
NULL,
enumFiles.dwValue,
NULL
);
}
FreePathString (fileName);
}
ELSE_DEBUGMSG ((DBG_WHOOPS, "NT_FILES : cannot find installation directory."));
}
while (MemDbEnumNextValue (&enumFiles));
}
// now we have in MEMDB_CATEGORY_NT_FILES_BAD all files that should be installed
// by NT but are not. Now we are going to scan the file system and see if they are
// installed in a different place.
if (EnumFirstFileInTreeEx (&enumTree, g_WinDrive, TEXT("*.*"), FALSE, FALSE, FILE_ENUM_ALL_LEVELS)) {
do {
MemDbBuildKey (key, MEMDB_CATEGORY_NT_FILES_BAD, enumTree.Name, NULL, NULL);
if (MemDbGetValue (key, &value) && (value != 0)) {
MemDbSetValue (key, 0);
MemDbBuildKeyFromOffsetW (value, key, 1, NULL);
DEBUGMSG ((
DBG_VALIDNTFILES,
"%s listed to be installed in %s but installed in %s",
enumTree.Name,
key,
enumTree.FullPath));
}
} while (EnumNextFileInTree (&enumTree));
}
MemDbBuildKey (key, MEMDB_CATEGORY_NT_FILES_BAD, TEXT("*"), NULL, NULL);
if (MemDbEnumFirstValue (
&enumFiles,
key,
MEMDB_ALL_SUBLEVELS,
MEMDB_ENDPOINTS_ONLY
)) {
do {
if (enumFiles.dwValue) {
MemDbBuildKeyFromOffsetW (enumFiles.dwValue, key, 1, NULL);
DEBUGMSG ((
DBG_VALIDNTFILES,
"%s listed to be installed in %s but never installed",
enumFiles.szName,
key,
enumTree.FullPath));
}
}
while (MemDbEnumNextValue (&enumFiles));
}
return TRUE;
}
#endif
DWORD
pGetState (
IN PCTSTR Item
)
{
DWORD Value;
TCHAR Node[MEMDB_MAX];
MemDbBuildKey (Node, MEMDB_CATEGORY_STATE, Item, NULL, NULL);
if (MemDbGetValue (Node, &Value)) {
return Value;
}
return 0;
}
BOOL
MigMain_Init (
VOID
)
/*++
Routine Description:
MigMain_Init is called for initialization, and has a better opportunity
to fail than MigMain_Entry (which is called during DllMain).
Arguments:
none
Return Value:
TRUE if initialization succeeded, or FALSE if an error occurred.
Call GetLastError() for error code.
--*/
{
DWORD rc; // Temp: return code
TCHAR RelocWinDir[MAX_TCHAR_PATH];
TCHAR SrcResBin[MAX_TCHAR_PATH];
TCHAR IconFile[MAX_TCHAR_PATH];
ICON_EXTRACT_CONTEXT Context;
WORD CodePage;
LCID Locale;
TCHAR Node[MEMDB_MAX];
DWORD minorVersion;
#ifdef DEBUG
HANDLE hFile;
HKEY DebugKey = NULL;
CHAR Buf[32];
DWORD Value;
#endif
#ifdef PRERELEASE
//
// !!! This is for internal use only !!! It is used for auto stress.
//
if (g_ConfigOptions.AutoStress) {
SuppressAllLogPopups (TRUE);
}
#endif
//
// Dev: load c:\windbg.reg if it exists
//
#ifdef DEBUG
__try {
TCHAR WindbgRegPath[MAX_PATH] = TEXT("c:\\windbg.reg");
//
// Intentional hard-coded path!! This is for dev purposes only.
//
WindbgRegPath[0] = g_System32Dir[0];
if (!DoesFileExist (WindbgRegPath)) {
StringCopy (WindbgRegPath, TEXT("d:\\tools\\windbg.reg"));
}
hFile = CreateFile (
WindbgRegPath,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle (hFile);
rc = TrackedRegOpenKey (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windbg"), &DebugKey);
if (rc == ERROR_SUCCESS) {
DEBUGMSG ((DBG_VERBOSE, "Not restoring windbg.reg because it was already restored."));
__leave;
}
else {
rc = TrackedRegCreateKey (HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windbg"), &DebugKey);
if (rc == ERROR_SUCCESS) {
if (!pSetupEnablePrivilege (SE_BACKUP_NAME, TRUE)) {
DEBUGMSG ((DBG_ERROR, "Windbg restore: pSetupEnablePrivilege SE_BACKUP_NAME failed"));
//__leave;
}
if (!pSetupEnablePrivilege (SE_RESTORE_NAME, TRUE)) {
DEBUGMSG ((DBG_ERROR, "Windbg restore: pSetupEnablePrivilege SE_RESTORE_NAME failed"));
//__leave;
}
rc = RegRestoreKey (DebugKey, WindbgRegPath, 0);
if (rc != ERROR_SUCCESS) {
DEBUGMSG ((DBG_WARNING, "Unable to restore windbg.reg, gle=%u", rc));
}
}
}
}
}
__finally {
if (DebugKey) {
CloseRegKey (DebugKey);
}
}
//
// If debug.inf has a line UserEnv=1, then add a registry key to debug userenv.dll
//
if (GetPrivateProfileStringA (
"Debug",
"UserEnv",
"0",
Buf,
sizeof (Buf) / sizeof (Buf[0]),
g_DebugInfPath
)
) {
if (atoi (Buf)) {
rc = TrackedRegCreateKey (
HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
&DebugKey
);
if (rc == ERROR_SUCCESS) {
Value = 0x00010002;
RegSetValueEx (
DebugKey,
TEXT("UserEnvDebugLevel"),
0,
REG_DWORD,
(PBYTE) &Value,
sizeof (DWORD)
);
CloseRegKey (DebugKey);
}
}
}
#endif
//
// Initialize the registry APIs
//
// We look in memdb for the location of .default
//
if (!MemDbLoad (GetMemDbDat())) {
LOG ((LOG_ERROR, "MigMain Init: MemDbLoad could not load %s", GetMemDbDat()));
return FALSE;
}
//
// Get platform name
//
if (!MemDbGetEndpointValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_PLATFORM_NAME,
NULL,
g_Win95Name
)) {
LOG ((LOG_ERROR, "Could not find product name for OS being upgraded."));
StringCopy (g_Win95Name, TEXT("Windows 95"));
}
// Try Paths\Windir first
if (!MemDbGetEndpointValueEx (
MEMDB_CATEGORY_PATHS,
MEMDB_ITEM_RELOC_WINDIR,
NULL,
RelocWinDir
)) {
LOG ((LOG_ERROR, "Could not find relocated windir!"));
return FALSE;
}
//
// if upgrading from Millennium, also map classes.dat
//
MemDbBuildKey (Node, MEMDB_CATEGORY_STATE, MEMDB_ITEM_MINOR_VERSION, NULL, NULL);
if (!MemDbGetValue (Node, &minorVersion)) {
LOG ((LOG_ERROR, "Could not get previous OS version information!"));
minorVersion = 0;
}
rc = Win95RegInit (RelocWinDir, minorVersion == 90);
if (rc != ERROR_SUCCESS) {
SetLastError (rc);
LOG ((LOG_ERROR, "Init Processor: Win95RegInit failed (path: %s)", RelocWinDir));
return FALSE;
}
//
// Update locale
//
CodePage = (WORD) pGetState (MEMDB_ITEM_CODE_PAGE);
Locale = (LCID) pGetState (MEMDB_ITEM_LOCALE);
SetGlobalCodePage (CodePage, Locale);
//
// Prepare path to system.dat, then raise registry quota if necessary
//
StringCopy (AppendWack (RelocWinDir), TEXT("system.dat"));
pRaiseRegistryQuota (RelocWinDir);
//
// Copy migisol.exe to migicons.exe
//
wsprintf (g_IconBin, TEXT("%s\\migicons.exe"), g_System32Dir);
wsprintf (SrcResBin, TEXT("%s\\migisol.exe"), g_TempDir);
if (!CopyFile (SrcResBin, g_IconBin, FALSE)) {
LOG ((LOG_ERROR, "Can't copy %s to %s", SrcResBin, g_IconBin));
}
else {
//
// Insert all icons from migicons.dat into g_IconBin
//
__try {
wsprintf (IconFile, TEXT("%s\\%s"), g_TempDir, S_MIGICONS_DAT);
if (!BeginIconExtraction (&Context, g_IconBin)) {
LOG ((LOG_ERROR, "Can't begin icon extraction"));
__leave;
}
if (!OpenIconImageFile (&Context, IconFile, FALSE)) {
LOG ((LOG_ERROR, "Can't open %s", IconFile));
__leave;
}
while (CopyIcon (&Context, NULL, NULL, 0)) {
// empty
}
}
__finally {
if (!EndIconExtraction (&Context)) {
DEBUGMSG ((DBG_WARNING, "EndIconExtraction failed"));
}
}
}
#ifdef DEBUG
// Validate MEMDB_CATEGORY_NT_FILES category. We need to find if the files
// that were supposed to be installed by NT are really there.
if (g_ConfigOptions.CheckNtFiles) {
pValidateNtFiles ();
}
#endif
return TRUE;
}
BOOL
MigMain_Migrate (
VOID
)
/*++
Routine Description:
MigMain_Migrate is the main migration function in NT GUI mode setup.
w95upgnt.dll calls this function, and it is here that users are migrated,
the local machine settings are migrated, and files are adjusted appropriately.
See the file progress.c for a list of functions that are called.
Arguments:
none
Return Value:
TRUE if migration succeeded, or FALSE if an error occurred. Call
GetLastError() for error code.
--*/
{
BOOL Result;
InitializeProgressBar (
g_ProgressBar,
NULL,
NULL,
NULL
);
PrepareMigrationProgressBar();
pProcessAutoLogon (FALSE);
g_BlowAwayTempShellFolders = TRUE;
Result = CallAllMigrationFunctions();
PushError();
if (Result) {
//
// Save logon prompt settings and set up auto-logon
//
pProcessAutoLogon (TRUE);
} else {
g_BlowAwayTempShellFolders = FALSE;
ClearAdminPassword();
}
//
// All done!
//
TerminateProgressBar();
PopError();
return Result;
}
DWORD
ResolveDomains (
DWORD Request
)
{
DWORD rc = ERROR_SUCCESS;
TCHAR unattendFile[MAX_TCHAR_PATH];
TCHAR buffer[32];
switch (Request) {
case REQUEST_QUERYTICKS:
if (!IsMemberOfDomain()) {
return 1;
}
return TICKS_DOMAIN_SEARCH;
case REQUEST_RUN:
//
// If autologon is enabled, then force classic mode
//
wsprintf (unattendFile, TEXT("%s\\system32\\$winnt$.inf"), g_WinDir);
if (GetPrivateProfileString (
TEXT("GuiUnattended"),
TEXT("AutoLogon"),
TEXT(""),
buffer,
ARRAYSIZE(buffer),
unattendFile
)) {
if (StringIMatch (buffer, TEXT("Yes"))) {
DEBUGMSG ((DBG_VERBOSE, "Found autologon; forcing classic logon type"));
SetClassicLogonType();
}
}
//
// Resolve the domains
//
if (!SearchDomainsForUserAccounts()) {
LOG ((LOG_ERROR, "An error occurred searching for user domains. The upgrade failed."));
rc = GetLastError();
} else {
//
// Fix up memdb for dynamic user profile paths
//
pFixUpMemDb();
}
if (IsMemberOfDomain()) {
TickProgressBarDelta (TICKS_DOMAIN_SEARCH);
} else {
TickProgressBar();
}
break;
}
return rc;
}
DWORD
PrepareEnvironment (
IN DWORD Request
)
{
DWORD rc = ERROR_SUCCESS;
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_INIT;
case REQUEST_RUN:
//
// Disable Win 3.1 migration dialog
//
pSetWin9xUpgValue();
// Enable 16 bit environment boot
pEnable16Boot();
//
// Enable privileges (req'd for several things)
//
if (!pSetupEnablePrivilege (SE_BACKUP_NAME, TRUE)) {
LOG ((LOG_ERROR, "MigMain Migrate: pSetupEnablePrivilege SE_BACKUP_NAME failed"));
//rc = GetLastError();
//break;
}
if (!pSetupEnablePrivilege (SE_RESTORE_NAME, TRUE)) {
LOG ((LOG_ERROR, "MigMain Migrate: pSetupEnablePrivilege SE_RESTORE_NAME failed"));
//rc = GetLastError();
//break;
}
TickProgressBarDelta (TICKS_INIT);
break;
}
return rc;
}
BOOL
MigMain_Cleanup (
VOID
)
/*++
Routine Description:
MigMain_Cleanup is called to perform file removal. We delete everything
that is in the memdb category DelFile, and we also try to clean up after
MSN and other empty Win9x directories. Before exiting we delete our
temporary directory.
This function is called very last in Setup and is part of syssetup's
cleanup.
Arguments:
none
Return Value:
TRUE when all file deletes were successful, FALSE if an error occurred.
Call GetLastError for the reason of failure.
--*/
{
BOOL b = TRUE;
PCTSTR TempDir;
TCHAR normalPath[] = S_SHELL_TEMP_NORMAL_PATH;
TCHAR longPath[] = S_SHELL_TEMP_LONG_PATH;
DRIVELETTERS drives;
UINT u;
#ifdef DEBUG
INT n = 0;
#endif
// Remove everything in memdb's DelFile category
b = DoFileDel();
//
// Clean up any remaining directories that are now empty, including shell
// folder temp dirs
//
InitializeDriveLetterStructure (&drives);
if (!g_BlowAwayTempShellFolders) {
for (u = 0 ; u < NUMDRIVELETTERS ; u++) {
if (drives.ExistsOnSystem[u] && drives.Type[u] == DRIVE_FIXED) {
normalPath[0] = drives.Letter[u];
longPath[0] = drives.Letter[u];
MemDbSetValueEx (MEMDB_CATEGORY_CLEAN_UP_DIR, normalPath, NULL, NULL, 1, NULL);
MemDbSetValueEx (MEMDB_CATEGORY_CLEAN_UP_DIR, longPath, NULL, NULL, 1, NULL);
}
}
}
RemoveEmptyDirs();
if (!g_BlowAwayTempShellFolders) {
//
// Setup failed, clean up temp dir but leave it in place
//
for (u = 0 ; u < NUMDRIVELETTERS ; u++) {
if (drives.ExistsOnSystem[u] && drives.Type[u] == DRIVE_FIXED) {
normalPath[0] = drives.Letter[u];
longPath[0] = drives.Letter[u];
RemoveDirectory (normalPath);
if (DoesFileExist (normalPath)) {
LOG ((LOG_ERROR, (PCSTR) MSG_LEFT_TEMP_SHELL_FOLDERS, normalPath));
}
RemoveDirectory (longPath);
if (DoesFileExist (longPath)) {
LOG ((LOG_ERROR, (PCSTR) MSG_LEFT_TEMP_SHELL_FOLDERS, longPath));
}
}
}
} else {
//
// Setup was successful, blow away entire temp dir regardless of its content
//
for (u = 0 ; u < NUMDRIVELETTERS ; u++) {
if (drives.ExistsOnSystem[u] && drives.Type[u] == DRIVE_FIXED) {
normalPath[0] = drives.Letter[u];
longPath[0] = drives.Letter[u];
RemoveCompleteDirectory (normalPath);
DEBUGMSG_IF ((
DoesFileExist (normalPath),
DBG_ERROR,
"Temp dir cannot be removed: %s",
normalPath
));
RemoveCompleteDirectory (longPath);
DEBUGMSG_IF ((
DoesFileExist (longPath),
DBG_ERROR,
"Temp dir cannot be removed: %s",
longPath
));
}
}
}
#ifdef DEBUG
n = GetPrivateProfileIntA ("debug", "keeptempfiles", n, g_DebugInfPath);
if (n) {
return b;
}
#endif
if (g_ConfigOptions.KeepTempFiles) {
return b;
}
//
// Blow away temp dir
//
TempDir = JoinPaths (g_WinDir, S_SETUP);
b = DeleteDirectoryContents (TempDir);
if (b) {
b = RemoveDirectory (TempDir);
if (!b) {
LOG ((LOG_ERROR, "Could not delete the tree %s.", TempDir));
}
}
else {
LOG ((LOG_ERROR, "Could not delete the contents of %s.", TempDir));
}
FreePathString (TempDir);
return b;
}
PCTSTR
GetMemDbDat (
VOID
)
/*++
Routine Description:
Returns a pointer to the path of the DAT file holding the Win9x memdb tree.
Arguments:
none
Return Value:
Returns a pointer to the Win32 path of ntsetup.dat.
--*/
{
static TCHAR FileName[MAX_TCHAR_PATH];
MYASSERT (!g_NoReloadsAllowed);
StringCopy (FileName, g_TempDir);
StringCopy (AppendWack (FileName), S_NTSETUPDAT);
return FileName;
}
PCTSTR
GetUserDatLocation (
IN PCTSTR User,
OUT PBOOL CreateOnlyFlag OPTIONAL
)
/*++
Routine Description:
Looks in memdb to locate the user.dat file for the specified user. On
Win9x, migapp.lib writes a line to memdb giving the location of user.dat
for each user, and the default user. This function retrieves that
location to guarantee the same file is used on both NT and Win9x.
Arguments:
User - The fixed name of the user to process, or NULL for the default user.
CreateOnlyFlag - Receives the create-only flag specified on the Win9x side
of the upgrade. If this flag is TRUE, then the account
should not be migrated.
Return Value:
Returns a pointer to the Win32 path of user.dat for the given user.
If the entry does not exist, NULL will be returned, and the user
will not be processed.
--*/
{
MEMDB_ENUM e;
static TCHAR UserDatLocation[MAX_TCHAR_PATH];
if (!MemDbGetValueEx (&e, MEMDB_CATEGORY_USER_DAT_LOC, User, NULL)) {
if (!StringIMatch (User, g_AdministratorStr)) {
DEBUGMSG ((DBG_WARNING, "'UserDatLocation' for %s does not exist.", User?User:S_DOT_DEFAULT));
}
return NULL;
}
StringCopy (UserDatLocation, e.szName);
if (CreateOnlyFlag) {
*CreateOnlyFlag = (BOOL) e.dwValue;
}
return UserDatLocation;
}
VOID
pSaveVersionStr (
IN HKEY Key,
IN PCTSTR Name
)
{
TCHAR Data[MEMDB_MAX];
if (MemDbGetEndpointValueEx (MEMDB_CATEGORY_STATE, Name, NULL, Data)) {
RegSetValueEx (
Key,
Name,
0,
REG_SZ,
(PBYTE) Data,
SizeOfString (Data)
);
}
}
VOID
pSaveVersionDword (
IN HKEY Key,
IN PCTSTR Name
)
{
DWORD Data;
TCHAR Node[MEMDB_MAX];
MemDbBuildKey (Node, MEMDB_CATEGORY_STATE, Name, NULL, NULL);
if (MemDbGetValue (Node, &Data)) {
RegSetValueEx (
Key,
Name,
0,
REG_DWORD,
(PBYTE) &Data,
sizeof (Data)
);
}
}
BOOL
pSetWin9xUpgValue (
VOID
)
/*++
Routine Description:
Create the value entry Win9xUpg on
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon
This routine should always be called when setup is installing an NT system
on top of Win9x, otherwise NT will think it has to migrate Win 3.1.
Arguments:
None.
Return Value:
Returns TRUE if the opearation succeeds.
--*/
{
ULONG Error;
HKEY Key;
DWORD Value;
HKEY VersionKey;
Key = OpenRegKeyStr (S_WINLOGON_REGKEY);
if (!Key) {
return FALSE;
}
Value = 1;
Error = RegSetValueEx (
Key,
S_WIN9XUPG_FLAG_VALNAME,
0,
REG_DWORD,
(PBYTE) &Value,
sizeof (DWORD)
);
//
// Save the version info
//
VersionKey = CreateRegKey (Key, TEXT("PrevOsVersion"));
if (VersionKey) {
pSaveVersionStr (VersionKey, MEMDB_ITEM_PLATFORM_NAME);
pSaveVersionStr (VersionKey, MEMDB_ITEM_VERSION_TEXT);
pSaveVersionDword (VersionKey, MEMDB_ITEM_MAJOR_VERSION);
pSaveVersionDword (VersionKey, MEMDB_ITEM_MINOR_VERSION);
pSaveVersionDword (VersionKey, MEMDB_ITEM_BUILD_NUMBER);
pSaveVersionDword (VersionKey, MEMDB_ITEM_PLATFORM_ID);
CloseRegKey (VersionKey);
}
CloseRegKey (Key);
if (Error != ERROR_SUCCESS) {
SetLastError (Error);
return FALSE;
}
return TRUE;
}
PCTSTR
GetString (
WORD wMsg
)
/*++
Routine Description:
Load the string resource given in wMsg and copy it to a global string
buffer. Return the a pointer to the buffer.
Arguments:
wMsg - The identifier of the message to load.
Return Value:
Returns a pointer to the loaded message, or NULL. The message must be
smaller than 2048 characters.
--*/
{
PCTSTR String;
String = GetStringResource (wMsg);
if (!String) {
return TEXT("Error: String resource could not be loaded");
}
_tcssafecpy (g_MsgBuf, String, ARRAYSIZE(g_MsgBuf));
FreeStringResource (String);
return g_MsgBuf;
}
VOID
pCountUsers (
OUT PDWORD TotalUsersPtr,
OUT PDWORD ActiveUsersPtr
)
/*++
Routine Description:
Counts all Win9x users, and determines how many of them are active
for migration. The count includes the Administrator account, the
logon prompt account, and optional default user account.
NOTE: Administrator may be counted twice in ActiveUsersPtr, once for
a real Win9x user named Administrator, and again for the
NT Administrator account that is always migrated. The caller
must handle this special case.
Arguments:
TotalUsersPtr - A DWORD that receives the total number of Win9x users,
including the NT-only users.
ActiveUsersPtr - A DWORD that receives the number of users that require
migration. Migration may or may not be enabled for any
user.
Return Value:
none
--*/
{
USERPOSITION up;
TCHAR User[MAX_TCHAR_PATH];
DWORD rc;
PCTSTR UserDatLocation;
*ActiveUsersPtr = 0;
*TotalUsersPtr = 3; // include logon, default and administrator in the total
rc = Win95RegGetFirstUser (&up, User);
if (rc != ERROR_SUCCESS) {
*TotalUsersPtr = 0;
return;
}
while (Win95RegHaveUser (&up)) {
GetFixedUserName (User);
// see if this user requires migration
UserDatLocation = GetUserDatLocation (User, NULL);
if (UserDatLocation) {
*ActiveUsersPtr += 1;
}
// count all users, migrated and non-migrated
*TotalUsersPtr += 1;
Win95RegGetNextUser (&up, User);
}
// test migration requirement of default user and adminsistrator
UserDatLocation = GetUserDatLocation (g_AdministratorStr, NULL);
if (UserDatLocation) {
*ActiveUsersPtr += 1;
}
UserDatLocation = GetUserDatLocation (S_DOT_DEFAULT, NULL);
if (UserDatLocation) {
*ActiveUsersPtr += 1;
}
if (g_ConfigOptions.MigrateDefaultUser) {
*ActiveUsersPtr += 1;
}
DEBUGMSG ((DBG_VERBOSE, "pCountUsers: %u users, %u require migration", *TotalUsersPtr, *ActiveUsersPtr));
}
CONVERTPATH_RC
ConvertWin9xPath (
PTSTR PathBuf
)
{
TCHAR Buffer[MEMDB_MAX];
DWORD status;
status = GetFileInfoOnNt (PathBuf, Buffer, MEMDB_MAX);
if (status & FILESTATUS_REPLACED) {
if (status & FILESTATUS_MOVED) {
_tcssafecpy (PathBuf, Buffer, MAX_TCHAR_PATH);
return CONVERTPATH_REMAPPED;
}
return CONVERTPATH_NOT_REMAPPED;
}
if (status & FILESTATUS_MOVED) {
_tcssafecpy (PathBuf, Buffer, MAX_TCHAR_PATH);
return CONVERTPATH_REMAPPED;
}
if (status & FILESTATUS_DELETED) {
return CONVERTPATH_DELETED;
}
return CONVERTPATH_NOT_REMAPPED;
}
VOID
pRaiseRegistryQuota (
PCTSTR Win9xSystemDatSpec
)
{
NTSTATUS Status;
SYSTEM_REGISTRY_QUOTA_INFORMATION RegQuotaInfo;
HANDLE FileHandle;
DWORD QuotaNeeded;
ULARGE_INTEGER FreeBytes, dc1, dc2;
LONGLONG FreeBytesNeeded;
HKEY SaveKey;
DWORD rc;
#ifdef PAGED_POOL_INCREASE
SYSTEM_POOL_INFORMATION PoolInfo;
//
// Obtain current system settings
//
Status = NtQuerySystemInformation (
SystemPagedPoolInformation,
(PVOID) &PoolInfo,
sizeof(PoolInfo),
NULL
);
if (Status != ERROR_SUCCESS) {
LOG ((LOG_ERROR, "Cannot obtain PoolInfo"));
return;
}
#endif
pSetupEnablePrivilege (SE_INCREASE_QUOTA_NAME, TRUE);
Status = NtQuerySystemInformation (
SystemRegistryQuotaInformation,
(PVOID) &RegQuotaInfo,
sizeof(RegQuotaInfo),
NULL
);
if (Status != ERROR_SUCCESS) {
LOG ((LOG_ERROR, "Cannot obtain RegQuotaInfo"));
return;
}
//
// Obtain Win9x registry system.dat size
//
FileHandle = CreateFile (
Win9xSystemDatSpec,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // security attributes
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL // template file
);
if (FileHandle == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR, "Cannot open %s; cannot raise registry quota", Win9xSystemDatSpec));
return;
}
QuotaNeeded = GetFileSize (FileHandle, NULL);
CloseHandle (FileHandle);
if (QuotaNeeded > 0x3fffffff) {
LOG ((LOG_ERROR, "Cannot obtain size for %s; cannot raise registry quota", Win9xSystemDatSpec));
return;
}
QuotaNeeded *= 6;
//
// Get free disk space on boot drive
//
if (!GetDiskFreeSpaceEx (
g_WinDir,
&FreeBytes,
&dc1,
&dc2
)) {
LOG ((LOG_ERROR, "Can't get free space on drive holding %s; cannot raise registry quota", g_WinDir));
return;
}
//
// Lots of disk space? Raise paged pool by 5 times the size of system.dat.
// Example: Win9x system.dat is 5M; must have 150M free to raise paged pool.
//
FreeBytesNeeded = (LONGLONG) QuotaNeeded * (LONGLONG) 6;
if (FreeBytes.QuadPart >= (DWORDLONG) FreeBytesNeeded) {
//
// Unimplemented: Raise the paged pool and return
//
DEBUGMSG ((DBG_WARNING, "RegQuota: Really should be raising paged pool -- this machine has %u bytes free", FreeBytes.LowPart));
}
//
// Last resort: raise the registry quota (if necessary)
//
if (RegQuotaInfo.RegistryQuotaAllowed < QuotaNeeded) {
DEBUGMSG ((DBG_VERBOSE, "Raising registry quota from %u to %u", RegQuotaInfo.RegistryQuotaAllowed, QuotaNeeded));
RegQuotaInfo.RegistryQuotaAllowed = QuotaNeeded;
Status = NtSetSystemInformation (
SystemRegistryQuotaInformation,
&RegQuotaInfo,
sizeof (RegQuotaInfo)
);
if (Status != ERROR_SUCCESS) {
LOG ((LOG_ERROR, "Can't set raised registry quota"));
}
//
// Set a permanent value in the registry
//
SaveKey = OpenRegKeyStr (TEXT("HKLM\\System\\CurrentControlSet\\Control"));
if (SaveKey) {
rc = RegSetValueEx (
SaveKey,
TEXT("RegistrySizeLimit"),
0,
REG_DWORD,
(PBYTE) &QuotaNeeded,
sizeof (DWORD)
);
CloseRegKey (SaveKey);
if (rc != ERROR_SUCCESS) {
LOG ((LOG_ERROR, "Could not set HKLM\\System\\CurrentControlSet\\Control [RegistrySizeLimit]"));
}
}
ELSE_DEBUGMSG ((DBG_ERROR, "Can't open HKLM\\System\\CurrentControlSet\\Control"));
}
}
BOOL
pCopyDosFile (
IN PCTSTR FileName,
IN BOOL InRootDir
)
/*++
Routine Description:
Copies a file from %windir%\setup\msdos7 into the designated DOS directory
Arguments:
FileName - file to copy (no path).
Return Value:
TRUE if succeeded, FALSE if not
--*/
{
PTSTR sourcePath;
PTSTR sourceFileName;
PTSTR destPath;
PTSTR destFileName;
BOOL result;
sourcePath = JoinPaths (g_TempDir, S_BOOT16_DOS_DIR);
sourceFileName = JoinPaths (sourcePath, FileName);
if (InRootDir) {
destPath = NULL;
destFileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
FileName);
}
else {
destPath = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_DOS_DIR);
destFileName = JoinPaths (destPath, FileName);
}
SetFileAttributes (destFileName, FILE_ATTRIBUTE_NORMAL);
result = CopyFile (sourceFileName, destFileName, FALSE);
FreePathString (sourcePath);
FreePathString (sourceFileName);
if (destPath != NULL) {
FreePathString (destPath);
}
FreePathString (destFileName);
return result;
}
VOID
pWriteBoot16ConfigLines (
IN HANDLE File,
IN PCTSTR BaseSection,
IN PCTSTR DosPath,
IN BOOL Localized
)
/*++
Routine Description:
pWriteBoot16ConfigLines reads configuration lines from wkstamig.inf and
writes them to the specified file handle. The caller can control wether the
lines should contain first boot only items or not and can control wether to
read in the base dos lines (same for all languages) or special lines used
for specific languages.
Arguments:
File - An opened handle with appropriate access to the file where
the data should be written.
BaseSection - Contains the Base Section name to read from the INF. This
section may be modified with a code page if Localized is TRUE.
DosPath - Contains the full path to the dos boot files (typically
c:\msdos7)
Localized - Controls wether data from the localized section is read. If
this parameter is TRUE, then the code page will be appended to
the BaseSection string for purposes of reading from wkstamig.inf.
Return Value:
none
++*/
{
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
GROWLIST list = GROWLIST_INIT;
PTSTR line;
TCHAR codePageSection[MAX_TCHAR_PATH];
USHORT codePage;
PCTSTR infSection;
//
// Add boot16 line specific environment variables.
//
GrowListAppendString (&list, TEXT("BOOTDRIVE"));
GrowListAppendString (&list, g_BootDrive);
GrowListAppendString (&list, TEXT("BOOT16DIR"));
GrowListAppendString (&list, DosPath);
//
// Terminate the arg list with two NULLs
//
GrowListAppendEmptyItem (&list);
GrowListAppendEmptyItem (&list);
if (Localized) {
//
// Caller wants data from the localized section.
//
GetGlobalCodePage (&codePage, NULL);
wsprintf (codePageSection, TEXT("%s %u"), BaseSection, codePage);
infSection = codePageSection;
}
else {
infSection = BaseSection;
}
//
// Write lines from base section.
//
if (InfFindFirstLine (g_WkstaMigInf, infSection, NULL, &is)) {
do {
//
// Get the line from the section and expand any environment
// variables.
//
line = InfGetLineText (&is);
MYASSERT (line);
line = ExpandEnvironmentTextEx (line,GrowListGetStringPtrArray (&list));
MYASSERT (line);
//
// Write the line to the file.
//
WriteFileString (File, line);
WriteFileString (File, TEXT("\r\n"));
FreeText (line);
} while (InfFindNextLine (&is));
}
FreeGrowList (&list);
InfCleanUpInfStruct (&is);
}
BOOL
pCreateConfigFile(
IN PCTSTR DosPath
)
/*++
Routine Description:
Creates a CONFIG.SYS file containing default settings.
Arguments:
DosPath - Contains the path to the dos files. (e.g. c:\msdos7)
Return Value:
TRUE if file was created, FALSE if not
--*/
{
PTSTR configName = NULL;
HANDLE handle;
configName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_CONFIG_FILE);
SetFileAttributes (configName, FILE_ATTRIBUTE_NORMAL);
handle = CreateFile (
configName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL
,
NULL
);
if (handle == INVALID_HANDLE_VALUE) {
return FALSE;
}
//
// Read lines from wkstamig.inf into this file.
//
pWriteBoot16ConfigLines (handle, S_BOOT16_CONFIGSYS_SECTION, DosPath, FALSE);
pWriteBoot16ConfigLines (handle, S_BOOT16_CONFIGSYS_SECTION, DosPath, TRUE);
CloseHandle (handle);
FreePathString (configName);
return TRUE;
}
BOOL
pCreateStartupFile(
IN PCTSTR DosPath
)
/*++
Routine Description:
Creates an AUTOEXEC.BAT file containing default settings.
Arguments:
DosPath - Contains the path to the dos files. (e.g. c:\msdos7)
Return Value:
TRUE if file was created, FALSE if not
--*/
{
PTSTR startupName = NULL;
PCTSTR comment = NULL;
HANDLE handle;
PCTSTR args[2];
args[0] = DosPath;
args[1] = NULL;
startupName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_STARTUP_FILE);
SetFileAttributes (startupName, FILE_ATTRIBUTE_NORMAL);
handle = CreateFile (
startupName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN,
NULL
);
if (handle == INVALID_HANDLE_VALUE) {
return FALSE;
}
comment = ParseMessageID (MSG_BOOT16_STARTUP_COMMENT, args);
//
// Read lines from wkstamig.inf into this file.
//
pWriteBoot16ConfigLines (handle, S_BOOT16_AUTOEXEC_SECTION, DosPath, FALSE);
pWriteBoot16ConfigLines (handle, S_BOOT16_AUTOEXEC_SECTION, DosPath, TRUE);
//
// Write localized comment.
//
WriteFileString (handle, comment);
WriteFileString (handle, TEXT("\r\n"));
FreeStringResource (comment);
CloseHandle (handle);
FreePathString (startupName);
return TRUE;
}
VOID
pEliminateCollision (
IN PCTSTR FileSpec
)
/*++
Routine Description:
pEliminateCollision checks to see if the specified file spec already
exists. If it does, the file is renamed with a numeric .nnn extension. If
the file can't be renamed, it is removed.
Arguments:
FileSpec - Specifies the file spec that is going to be used for a new file.
If this file already exists, it is renamed.
Return Value:
None.
--*/
{
PTSTR p;
PCTSTR NewFileSpec;
UINT u;
BOOL b;
if (DoesFileExist (FileSpec)) {
NewFileSpec = DuplicatePathString (FileSpec, 0);
p = _tcsrchr (NewFileSpec, TEXT('.'));
if (!p || _tcschr (p, TEXT('\\'))) {
p = GetEndOfString (NewFileSpec);
}
u = 0;
do {
wsprintf (p, TEXT(".%03u"), u);
u++;
} while (DoesFileExist (NewFileSpec));
b = OurMoveFile (FileSpec, NewFileSpec);
LOG_IF ((
!b,
LOG_ERROR,
"Could not rename %s to %s; source file might be lost",
FileSpec,
NewFileSpec
));
if (!b) {
SetFileAttributes (FileSpec, FILE_ATTRIBUTE_NORMAL);
b = DeleteFile (FileSpec);
LOG_IF ((
!b,
LOG_ERROR,
"Could not remove %s to make room for a new file. The new file is lost.",
FileSpec
));
}
FreePathString (NewFileSpec);
}
}
BOOL
pRenameCfgFiles (
IN PCTSTR DosDrive
)
/*++
Routine Description:
Renames old CONFIG.SYS and AUTOEXEC.BAT to make room for automatically generated ones.
Arguments:
DosDirectory - Contains the directory where the msdos files live (typeically c:\msdos7)
Return Value:
TRUE if rename succeeded, FALSE if not
--*/
{
PTSTR fileName1 = NULL;
PTSTR fileName2 = NULL;
fileName1 = JoinPaths (
ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_CONFIG_FILE
);
fileName2 = JoinPaths (
DosDrive,
S_BOOT16_CONFIGUPG_FILE
);
OurMoveFile (fileName1, fileName2);
SetFileAttributes (fileName2, FILE_ATTRIBUTE_NORMAL);
FreePathString (fileName1);
FreePathString (fileName2);
fileName1 = JoinPaths (
ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_STARTUP_FILE
);
fileName2 = JoinPaths (
DosDrive,
S_BOOT16_STARTUPUPG_FILE
);
OurMoveFile (fileName1, fileName2);
SetFileAttributes (fileName2, FILE_ATTRIBUTE_NORMAL);
FreePathString (fileName1);
FreePathString (fileName2);
return TRUE;
}
VOID
pCleanRootDir (
VOID
)
/*++
Routine Description:
Blows away dos files in root directory.
Arguments:
none
Return Value:
none
--*/
{
PTSTR fileName = NULL;
fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_SYSMAIN_FILE);
MarkFileForDelete (fileName);
FreePathString (fileName);
fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_DOSINI_FILE);
MarkFileForDelete (fileName);
FreePathString (fileName);
}
#define IoFile TEXT("IO.SYS")
VOID
pEnable16Boot (
VOID
)
/*++
Routine Description:
Creates a 16 bit environment boot option.
First we will check to see if everything is OK, we have all the files we need etc.
Then create DOS directory, rename old AUTOEXEC and CONFIG, create new ones and
add an entry in BOOT.INI
Arguments:
none
Return Value:
TRUE if file was created, FALSE if not
--*/
{
PTSTR fileName = NULL;
PTSTR dosPath = NULL;
INFCONTEXT infContext;
DWORD oldFileAttr;
BOOL result = TRUE;
HANDLE fileHandle = INVALID_HANDLE_VALUE;
if (g_Boot16 == BOOT16_NO) {
pCleanRootDir ();
return;
}
__try {
//
// first thing. Copy IO.SYS in root directory (BOOTSECT.DOS should be there)
//
pCopyDosFile (IoFile, TRUE);
fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
IoFile);
SetFileAttributes (fileName, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM);
FreePathString (fileName);
//
// Create DOS7 directory and copy dos files there
//
dosPath = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_DOS_DIR);
if (!CreateDirectory (dosPath, NULL) && (GetLastError()!=ERROR_ALREADY_EXISTS)) {
LOG ((LOG_ERROR,"BOOT16 : Unable to create DOS directory %s",dosPath));
__leave;
}
//
// If we find autoexec.bat and config.sys rename them as *.upg
//
if (!pRenameCfgFiles (dosPath)) {
__leave;
}
if (g_WkstaMigInf == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR,"BOOT16 : WKSTAMIG.INF is not opened"));
__leave;
}
//
// Read the section, for every file, we are trying to read it from our temp dir
// and copy it to the new DOS7 location
//
fileName = AllocPathString (MAX_TCHAR_PATH);
if (!SetupFindFirstLine (
g_WkstaMigInf,
S_BOOT16_SECTION,
NULL,
&infContext
)) {
LOG ((LOG_ERROR,"BOOT16 : Cannot read from %s section (WKSTAMIG.INF)",S_BOOT16_SECTION));
__leave;
}
do {
if (SetupGetStringField (
&infContext,
0,
fileName,
MAX_TCHAR_PATH/sizeof(fileName[0]),
NULL
)) {
pCopyDosFile (fileName, FALSE);
}
}
while (SetupFindNextLine (&infContext, &infContext));
//
// Hide the msdos7 directory (not our idea...)
//
SetFileAttributes (dosPath, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
FreePathString (fileName);
fileName = NULL;
//
// Next step, build MSDOS.SYS file.
//
fileName = JoinPaths (ISPC98() ? g_Win9xBootDrivePath : g_BootDrivePath,
S_BOOT16_DOSINI_FILE);
if (SetFileAttributes (fileName, FILE_ATTRIBUTE_NORMAL)) {
if (!DeleteFile (fileName)) {
LOG ((LOG_ERROR, "BOOT16 : Unable to delete %s",fileName));
__leave;
}
}
result &= WritePrivateProfileString (TEXT("Paths"), TEXT("WinDir"), dosPath, fileName);
result &= WritePrivateProfileString (TEXT("Paths"), TEXT("WinBootDir"), dosPath, fileName);
result &= WritePrivateProfileString (TEXT("Options"), TEXT("LOGO"), TEXT("0"), fileName);
result &= WritePrivateProfileString (TEXT("Options"), TEXT("BootGUI"), TEXT("0"), fileName);
if (!result) {
LOG((LOG_ERROR,"Unable to write to %s",fileName));
__leave;
}
FreePathString (fileName);
fileName = NULL;
//
// Generate config.sys and autoexec.bat files.
//
if (!pCreateConfigFile (dosPath)) {
LOG ((LOG_ERROR, "BOOT16 : Unable to create %s",S_BOOT16_CONFIG_FILE));
__leave;
}
if (!pCreateStartupFile (dosPath)) {
LOG ((LOG_ERROR, "BOOT16 : Unable to create %s",S_BOOT16_STARTUP_FILE));
__leave;
}
if ((!ISPC98()) || (g_BootDrivePath[0] == g_Win9xBootDrivePath[0])) {
//
// If boot16 is set to BOOT16_AUTOMATIC, we create a boot.dos file,
// but don't actually modify boot.ini. If it is BOOT16_YES, then
// we modify boot.ini
//
// The result is that DOS will not show up as a boot option unless
// there was a specific reason it was turned on originally. However,
// there will be a way to enable it if needed.
//
if (g_Boot16 == BOOT16_AUTOMATIC) {
fileName = JoinPaths (g_BootDrivePath, S_BOOT16_BOOTDOS_FILE);
fileHandle = CreateFile (
fileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE,
NULL
);
if (fileHandle != INVALID_HANDLE_VALUE) {
WriteFileString (fileHandle, ISPC98() ? L"C:\\" : g_BootDrivePath);
WriteFileString (fileHandle, TEXT("="));
WriteFileString (fileHandle, S_BOOT16_OS_ENTRY);
}
}
else {
fileName = JoinPaths (g_BootDrivePath, S_BOOT16_BOOTINI_FILE);
oldFileAttr = GetFileAttributes (fileName);
SetFileAttributes (fileName, FILE_ATTRIBUTE_NORMAL);
if (!WritePrivateProfileString (
S_BOOT16_OS_SECTION,
ISPC98() ? L"C:\\" : g_BootDrivePath,
S_BOOT16_OS_ENTRY,
fileName
)) {
LOG((LOG_ERROR,"Unable to write to %s",fileName));
SetFileAttributes (fileName, oldFileAttr);
__leave;
}
SetFileAttributes (fileName, oldFileAttr);
}
}
}
__finally {
if (fileName != NULL) {
FreePathString (fileName);
fileName = NULL;
}
if (dosPath != NULL) {
FreePathString (dosPath);
dosPath = NULL;
}
}
}
VOID
pCopyRegString (
IN HKEY DestKey,
IN HKEY SrcKey,
IN PCTSTR SrcValue
)
{
PCTSTR Data;
Data = GetRegValueString (SrcKey, SrcValue);
if (Data) {
RegSetValueEx (DestKey, SrcValue, 0, REG_SZ, (PBYTE) Data, SizeOfString (Data));
MemFree (g_hHeap, 0, Data);
}
}
#ifdef PRERELEASE
//
// !!! This is for internal use only !!! It is used for auto stress.
//
VOID
pTransferAutoStressVal (
IN HKEY StressKey,
IN PCTSTR ValueName
)
{
TCHAR Data[MEMDB_MAX];
LONG rc;
if (!MemDbGetEndpointValueEx (
MEMDB_CATEGORY_STATE,
ValueName,
NULL, // no field
Data
)) {
return;
}
rc = RegSetValueEx (
StressKey,
ValueName,
0,
REG_SZ,
(PBYTE) Data,
SizeOfString (Data)
);
DEBUGMSG_IF ((rc == ERROR_SUCCESS, DBG_VERBOSE, "Transferred autostress value %s", ValueName));
}
#endif
VOID
pProcessAutoLogon (
BOOL Final
)
/*++
Routine Description:
pProcessAutoLogon copies the logon defaults to a special key, so the
migpwd.exe tool can restore them if it runs. Then, the function calls
AutoStartProcessing to set up RunOnce and AutoAdminLogon.
This function is called early in migration to save the clean install
autologon, and then again at the end to prepare migpwd.exe.
Arguments:
Final - Specifies FALSE if this is the early call, TRUE if it is the
final call.
Return Value:
None.
--*/
{
HKEY SrcKey, DestKey;
PCTSTR Data;
BOOL copyNow = FALSE;
static BOOL alreadyCopied = FALSE;
//
// If autologon is enabled, preserve it in Win9xUpg key, so that
// migpwd.exe will restore it.
//
SrcKey = OpenRegKeyStr (S_WINLOGON_REGKEY);
if (SrcKey) {
if (!Final) {
//
// Early in migration, we get the clean install autologon values.
// If autologon is enabled, preserve the settings.
//
Data = GetRegValueString (SrcKey, S_AUTOADMIN_LOGON_VALUE);
if (Data) {
if (_ttoi (Data)) {
//
// on PER, don't want to preserve this value;
// instead, we need to preserve the name of
// the Win9x username as migrated via wkstamig.inf (see below)
//
copyNow = !g_PersonalSKU;
}
MemFree (g_hHeap, 0, Data);
}
} else if (!alreadyCopied) {
//
// Near the end of migration, we get the default logon prompt
// settings via wkstamig.inf migration. We want the attended case
// to work properly (preserving default user name & password).
//
// But if we've already preserved autologon, then we don't get
// here.
//
copyNow = TRUE;
}
if (copyNow) {
MYASSERT (!alreadyCopied);
alreadyCopied = TRUE;
DestKey = CreateRegKeyStr (S_WIN9XUPG_KEY);
if (DestKey) {
pCopyRegString (DestKey, SrcKey, S_AUTOADMIN_LOGON_VALUE);
pCopyRegString (DestKey, SrcKey, S_DEFAULT_PASSWORD_VALUE);
pCopyRegString (DestKey, SrcKey, S_DEFAULT_USER_NAME_VALUE);
pCopyRegString (DestKey, SrcKey, S_DEFAULT_DOMAIN_NAME_VALUE);
CloseRegKey (DestKey);
}
}
CloseRegKey (SrcKey);
}
if (!Final) {
return;
}
AutoStartProcessing();
#ifdef PRERELEASE
//
// !!! This is for internal use only !!! It is used for auto stress.
//
if (g_ConfigOptions.AutoStress) {
HKEY StressKey;
StressKey = CreateRegKeyStr (S_AUTOSTRESS_KEY);
MYASSERT (StressKey);
pTransferAutoStressVal (StressKey, S_AUTOSTRESS_USER);
pTransferAutoStressVal (StressKey, S_AUTOSTRESS_PASSWORD);
pTransferAutoStressVal (StressKey, S_AUTOSTRESS_OFFICE);
pTransferAutoStressVal (StressKey, S_AUTOSTRESS_DBG);
pTransferAutoStressVal (StressKey, S_AUTOSTRESS_FLAGS);
CloseRegKey (StressKey);
}
#endif
}
PCTSTR
GetProfilePathForAllUsers (
VOID
)
{
PTSTR result = NULL;
DWORD size = 0;
if (!GetAllUsersProfileDirectory (NULL, &size) &&
ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
return NULL;
}
result = AllocPathString (size + 1);
if (!GetAllUsersProfileDirectory (result, &size)) {
FreePathString (result);
return NULL;
}
return result;
}
PCTSTR
pGetDefaultShellFolderLocationFromInf (
IN PCTSTR FolderName,
IN PCTSTR ProfilePath
)
{
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
PCTSTR data;
PCTSTR result = NULL;
MYASSERT (g_WkstaMigInf && g_WkstaMigInf != INVALID_HANDLE_VALUE);
if (InfFindFirstLine (g_WkstaMigInf, TEXT("ShellFolders.DefaultNtLocation"), FolderName, &is)) {
data = InfGetStringField (&is, 1);
if (data) {
result = StringSearchAndReplace (data, S_USERPROFILE_ENV, ProfilePath);
if (!result) {
result = DuplicatePathString (data, 0);
}
}
}
InfCleanUpInfStruct (&is);
return result;
}
VOID
pFixUpDynamicPaths (
PCTSTR Category
)
{
MEMDB_ENUM e;
TCHAR Pattern[MEMDB_MAX];
PTSTR p;
GROWBUFFER Roots = GROWBUF_INIT;
MULTISZ_ENUM e2;
TCHAR NewRoot[MEMDB_MAX];
TCHAR AllProfilePath[MAX_TCHAR_PATH];
PCTSTR ProfilePath;
DWORD Size;
PTSTR UserName;
HKEY sfKey = NULL;
PCTSTR sfPath = NULL;
PTSTR NtLocation;
PCTSTR tempExpand;
BOOL regFolder;
BOOL mkDir;
//
// Collect all the roots that need to be renamed
//
StringCopy (Pattern, Category);
p = AppendWack (Pattern);
StringCopy (p, TEXT("*"));
if (MemDbEnumFirstValue (&e, Pattern, MEMDB_THIS_LEVEL_ONLY, MEMDB_ALL_BUT_PROXY)) {
do {
if ((_tcsnextc (e.szName) == TEXT('>')) ||
(_tcsnextc (e.szName) == TEXT('<'))
) {
StringCopy (p, e.szName);
MultiSzAppend (&Roots, Pattern);
}
} while (MemDbEnumNextValue (&e));
}
//
// Now change each root
//
if (EnumFirstMultiSz (&e2, (PCTSTR) Roots.Buf)) {
do {
//
// Compute NewRoot
//
StringCopy (NewRoot, e2.CurrentString);
p = _tcschr (NewRoot, TEXT('<'));
if (p) {
UserName = _tcschr (p, TEXT('>'));
MYASSERT (UserName);
StringCopyAB (Pattern, _tcsinc (p), UserName);
UserName = _tcsinc (UserName);
regFolder = TRUE;
if (StringIMatch (Pattern, TEXT("Profiles"))) {
regFolder = FALSE;
}
if (StringIMatch (Pattern, TEXT("Common Profiles"))) {
regFolder = FALSE;
}
//
// Get the profile root
//
if (StringIMatch (UserName, S_DOT_ALLUSERS)) {
Size = MAX_TCHAR_PATH;
if (regFolder) {
if (!GetAllUsersProfileDirectory (AllProfilePath, &Size)) {
DEBUGMSG ((DBG_WHOOPS, "Cannot get All Users profile path."));
continue;
}
sfKey = OpenRegKeyStr (S_USHELL_FOLDERS_KEY_SYSTEM);
} else {
if (!GetProfilesDirectory (AllProfilePath, &Size)) {
DEBUGMSG ((DBG_WHOOPS, "Cannot get All Users profile path."));
continue;
}
}
} else if (StringMatch (UserName, S_DEFAULT_USER)) {
Size = MAX_TCHAR_PATH;
if (regFolder) {
if (!GetDefaultUserProfileDirectory (AllProfilePath, &Size)) {
DEBUGMSG ((DBG_WHOOPS, "Cannot get Default User profile path."));
continue;
}
sfKey = OpenRegKey (HKEY_CURRENT_USER, S_USHELL_FOLDERS_KEY_USER);
} else {
if (!GetProfilesDirectory (AllProfilePath, &Size)) {
DEBUGMSG ((DBG_WHOOPS, "Cannot get All Users profile path."));
continue;
}
}
} else {
ProfilePath = GetProfilePathForUser (UserName);
if (!ProfilePath) {
DEBUGMSG ((DBG_WHOOPS, "Cannot get profile path for user:%s", UserName));
continue;
}
StringCopy (AllProfilePath, ProfilePath);
if (regFolder) {
sfKey = OpenRegKey (HKEY_CURRENT_USER, S_USHELL_FOLDERS_KEY_USER);
}
}
//
// If a specific reg folder is specified, get its path
//
mkDir = FALSE;
if (regFolder) {
if (!sfKey) {
DEBUGMSG ((DBG_ERROR, "Could not open Shell folders key."));
continue;
}
sfPath = GetRegValueString (sfKey, Pattern);
CloseRegKey (sfKey);
if (!sfPath || *sfPath == 0) {
DEBUGMSG ((DBG_WARNING, "Could not get Shell Folder path for: %s", Pattern));
tempExpand = pGetDefaultShellFolderLocationFromInf (Pattern, AllProfilePath);
if (!tempExpand) {
DEBUGMSG ((
DBG_WHOOPS,
"Shell folder %s is not in registry nor is it in [ShellFolders.DefaultNtLocation] of wkstamig.inf",
Pattern
));
continue;
}
//
// Special case: Shell wants read-only on this folder. Create it now.
//
mkDir = TRUE;
} else {
tempExpand = StringSearchAndReplace (
sfPath,
S_USERPROFILE_ENV,
AllProfilePath
);
if (!tempExpand) {
tempExpand = DuplicatePathString (sfPath, 0);
}
}
if (sfPath) {
MemFree (g_hHeap, 0, sfPath);
}
} else {
tempExpand = DuplicatePathString (AllProfilePath, 0);
}
//
// Move symbolic name to full path
//
NtLocation = ExpandEnvironmentText (tempExpand);
if (mkDir) {
MakeSurePathExists (NtLocation, TRUE);
SetFileAttributes (NtLocation, FILE_ATTRIBUTE_READONLY);
}
StringCopy (p, NtLocation);
MemDbMoveTree (e2.CurrentString, NewRoot);
FreeText (NtLocation);
FreePathString (tempExpand);
} else {
p = _tcschr (NewRoot, TEXT('>'));
MYASSERT (p);
if (StringIMatch (_tcsinc (p), S_DOT_ALLUSERS)) {
Size = MAX_TCHAR_PATH;
if (!GetAllUsersProfileDirectory (AllProfilePath, &Size)) {
DEBUGMSG ((DBG_WARNING, "Dynamic path for %s could not be resolved", e2.CurrentString));
}
else {
StringCopy (p, AllProfilePath);
MemDbMoveTree (e2.CurrentString, NewRoot);
}
} else if (StringMatch (_tcsinc (p), S_DEFAULT_USER)) {
Size = MAX_TCHAR_PATH;
if (!GetDefaultUserProfileDirectory (AllProfilePath, &Size)) {
DEBUGMSG ((DBG_WARNING, "Dynamic path for %s could not be resolved", e2.CurrentString));
}
else {
StringCopy (p, AllProfilePath);
MemDbMoveTree (e2.CurrentString, NewRoot);
}
} else {
ProfilePath = GetProfilePathForUser (_tcsinc (p));
if (ProfilePath) {
StringCopy (p, ProfilePath);
MemDbMoveTree (e2.CurrentString, NewRoot);
}
else {
DEBUGMSG ((DBG_WARNING, "Dynamic path for %s could not be resolved", e2.CurrentString));
}
}
}
} while (EnumNextMultiSz (&e2));
}
FreeGrowBuffer (&Roots);
}
VOID
pFixUpMemDb (
VOID
)
{
MEMDB_ENUM e;
TCHAR node[MEMDB_MAX];
pFixUpDynamicPaths (MEMDB_CATEGORY_PATHROOT);
//pFixUpDynamicPaths (MEMDB_CATEGORY_DATA); OPTIMIZATION -- Data overlaps PathRoot
pFixUpDynamicPaths (MEMDB_CATEGORY_USERFILEMOVE_DEST);
pFixUpDynamicPaths (MEMDB_CATEGORY_SHELLFOLDERS_DEST);
pFixUpDynamicPaths (MEMDB_CATEGORY_SHELLFOLDERS_SRC);
pFixUpDynamicPaths (MEMDB_CATEGORY_LINKEDIT_TARGET);
pFixUpDynamicPaths (MEMDB_CATEGORY_LINKEDIT_WORKDIR);
pFixUpDynamicPaths (MEMDB_CATEGORY_LINKEDIT_ICONPATH);
pFixUpDynamicPaths (MEMDB_CATEGORY_LINKSTUB_TARGET);
pFixUpDynamicPaths (MEMDB_CATEGORY_LINKSTUB_WORKDIR);
pFixUpDynamicPaths (MEMDB_CATEGORY_LINKSTUB_ICONPATH);
//
// Enumerate each user in MyDocsMoveWarning, then update dynamic paths
//
// MyDocsMoveWarning\<user>\<path>
MemDbBuildKey (
node,
MEMDB_CATEGORY_MYDOCS_WARNING,
TEXT("*"),
NULL,
NULL
);
if (MemDbEnumFirstValue (&e, node, MEMDB_THIS_LEVEL_ONLY, MEMDB_ALL_MATCHES)) {
do {
MemDbBuildKey (
node,
MEMDB_CATEGORY_MYDOCS_WARNING,
e.szName, // <user>
NULL,
NULL
);
pFixUpDynamicPaths (node);
} while (MemDbEnumNextValue (&e));
}
}
BOOL
EnumFirstUserToMigrate (
OUT PMIGRATE_USER_ENUM e,
IN DWORD Flags
)
{
ZeroMemory (e, sizeof (MIGRATE_USER_ENUM));
e->Flags = Flags;
pCountUsers (&e->TotalUsers, &e->ActiveUsers);
e->UserNumber = e->TotalUsers;
Win95RegGetFirstUser (&e->up, e->Win95RegName);
return EnumNextUserToMigrate (e);
}
BOOL
EnumNextUserToMigrate (
IN OUT PMIGRATE_USER_ENUM e
)
{
LONG rc;
PCTSTR Domain;
TCHAR Win9xAccount[MEMDB_MAX];
TCHAR EnumAccount[MAX_TCHAR_PATH];
USERPOSITION *AdminPosPtr;
USERPOSITION AdminPos;
BOOL Loop = TRUE;
PCTSTR UserDatLocation;
while (Loop) {
if (e->UserNumber == 0) {
return FALSE;
}
Loop = FALSE;
e->UserNumber--;
__try {
e->UserDoingTheUpgrade = FALSE;
if (e->UserNumber == INDEX_ADMINISTRATOR) {
_tcssafecpy (e->FixedUserName, g_AdministratorStr, MAX_USER_NAME);
StringCopy (e->Win9xUserName, e->FixedUserName);
e->AccountType = ADMINISTRATOR_ACCOUNT;
} else if (e->UserNumber == INDEX_LOGON_PROMPT) {
StringCopy (e->FixedUserName, S_DOT_DEFAULT);
StringCopy (e->Win9xUserName, e->FixedUserName);
e->AccountType = LOGON_USER_SETTINGS;
} else if (e->UserNumber == INDEX_DEFAULT_USER) {
//
// Do not process unless default user migration is enabled
//
if (!g_ConfigOptions.MigrateDefaultUser) {
Loop = (e->Flags & ENUM_ALL_USERS) == 0;
__leave;
}
StringCopy (e->FixedUserName, S_DEFAULT_USER);
StringCopy (e->Win9xUserName, e->FixedUserName);
e->AccountType = DEFAULT_USER_ACCOUNT;
} else {
_tcssafecpy (e->Win9xUserName, e->Win95RegName, MAX_USER_NAME);
StringCopy (e->FixedUserName, e->Win95RegName);
GetFixedUserName (e->FixedUserName);
e->AccountType = WIN9X_USER_ACCOUNT;
//
// Special case: Account named Administrator exists. In this
// case, we'd have two Administrator users unless
// one was skipped. So here is the test to skip
// if the user is named Administrator.
//
if (StringIMatch (e->Win9xUserName, g_AdministratorStr)) {
Loop = TRUE;
__leave;
}
}
StringCopy (e->FixedDomainName, e->FixedUserName);
//
// See if we are to migrate this user, and if so, perpare
// the Win95 registry and call ProcessUser.
//
UserDatLocation = GetUserDatLocation (e->FixedUserName, &e->CreateOnly);
if (UserDatLocation && DoesFileExist (UserDatLocation)) {
e->Valid = TRUE;
StringCopy (e->UserDatLocation, UserDatLocation);
} else {
e->Valid = FALSE;
e->UserDatLocation[0] = 0;
}
if (e->Flags & ENUM_SET_WIN9X_HKR) {
//
// Make HKCU equal to the enumerated user
//
g_hKeyRoot95 = HKEY_CURRENT_USER;
}
if (e->Valid) {
//
// Is this user the user doing migration?
//
if (MemDbGetEndpointValueEx (
MEMDB_CATEGORY_ADMINISTRATOR_INFO,
MEMDB_ITEM_AI_USER_DOING_MIG,
NULL, // no field
Win9xAccount
)) {
//
// Win9xAccount is unfixed name, convert to fixed name then
// compare with the current enumerated user.
//
GetFixedUserName (Win9xAccount);
DEBUGMSG ((DBG_NAUSEA, "Comparing %s to %s", e->FixedUserName, Win9xAccount));
if (StringIMatch (e->FixedUserName, Win9xAccount)) {
e->UserDoingTheUpgrade = TRUE;
}
}
//
// Perform special init depending on the user type
//
if (e->AccountType == WIN9X_USER_ACCOUNT) {
if (e->Flags & ENUM_SET_WIN9X_HKR) {
//
// Map HKCU on Win95 to current user
//
rc = Win95RegSetCurrentUserNt (&e->up, e->UserDatLocation);
if (rc != ERROR_SUCCESS) {
SetLastError (rc);
LOG ((
LOG_ERROR,
"Migrate Users: Win95RegSetCurrentUserNt could not set user "
"to %s (user path %s)",
e->FixedUserName,
e->UserDatLocation
));
LOG ((LOG_ERROR, "Could not load %s", e->UserDatLocation));
Loop = (e->Flags & ENUM_ALL_USERS) == 0;
__leave;
}
}
// Obtain the full user name
Domain = GetDomainForUser (e->FixedUserName);
if (Domain) {
StringCopy (e->FixedDomainName, Domain);
StringCopy (AppendWack (e->FixedDomainName), e->FixedUserName);
}
}
else if (e->AccountType == ADMINISTRATOR_ACCOUNT) {
//
// Map Win9x registry appropriate for the Administrator hive
//
if (e->Flags & ENUM_SET_WIN9X_HKR) {
AdminPosPtr = NULL;
// Obtain user account from memdb and find USERPOSITION for it
if (MemDbGetEndpointValueEx (
MEMDB_CATEGORY_ADMINISTRATOR_INFO,
MEMDB_ITEM_AI_ACCOUNT,
NULL, // no field
Win9xAccount
)) {
// Search Win9x user list for user
Win95RegGetFirstUser (&AdminPos, EnumAccount);
while (Win95RegHaveUser (&AdminPos)) {
GetFixedUserName (EnumAccount);
if (StringIMatch (Win9xAccount, EnumAccount)) {
AdminPosPtr = &AdminPos;
break;
}
Win95RegGetNextUser (&AdminPos, EnumAccount);
}
if (!AdminPosPtr) {
DEBUGMSG ((
DBG_WARNING,
"pMigrateUsers: Account %s not found",
Win9xAccount
));
}
}
//
// Map HKCU on Win95 to match, or default user if no match or
// no memdb entry
//
rc = Win95RegSetCurrentUserNt (AdminPosPtr, e->UserDatLocation);
if (rc != ERROR_SUCCESS) {
SetLastError (rc);
LOG ((LOG_ERROR, "Could not load %s for Administrator", e->UserDatLocation));
Loop = (e->Flags & ENUM_ALL_USERS) == 0;
__leave;
}
}
}
else if (e->AccountType == LOGON_USER_SETTINGS || e->AccountType == DEFAULT_USER_ACCOUNT) {
//
// Map HKCU on Win95 to default user
//
if (e->Flags & ENUM_SET_WIN9X_HKR) {
rc = Win95RegSetCurrentUserNt (NULL, e->UserDatLocation);
if (rc != ERROR_SUCCESS) {
SetLastError (rc);
LOG ((LOG_ERROR, "Could not load default user hive"));
Loop = (e->Flags & ENUM_ALL_USERS) == 0;
__leave;
}
}
}
} /* if (e->Valid) */
else {
Loop = (e->Flags & ENUM_ALL_USERS) == 0;
}
} /* try */
__finally {
//
// Get the next user for next time through loop, ignore errors
//
if (e->AccountType == WIN9X_USER_ACCOUNT) {
Win95RegGetNextUser (&e->up, e->Win95RegName);
}
}
} /* while (Loop) */
DEBUGMSG_IF ((
e->Flags & ENUM_SET_WIN9X_HKR,
DBG_VERBOSE,
"--- User Info ---\n"
" User Name: %s (%s)\n"
" Domain User Name: %s\n"
" Win95Reg Name: %s\n"
" User Hive: %s\n"
" Account Type: %s\n"
" Create Only: %s\n"
" Valid: %s\n"
" UserDoingTheUpgrade: %s\n",
e->Win9xUserName,
e->FixedUserName,
e->FixedDomainName,
e->Win95RegName,
e->UserDatLocation,
e->AccountType == WIN9X_USER_ACCOUNT ? TEXT("User") :
e->AccountType == ADMINISTRATOR_ACCOUNT ? TEXT("Administrator") :
e->AccountType == LOGON_USER_SETTINGS ? TEXT("Logon User") :
e->AccountType == DEFAULT_USER_ACCOUNT ? TEXT("Default User") : TEXT("Unknown"),
e->CreateOnly ? TEXT("Yes") : TEXT("No"),
e->Valid ? TEXT("Yes") : TEXT("No"),
e->UserDoingTheUpgrade ? TEXT("Yes") : TEXT("No")
));
return TRUE;
}
VOID
RunExternalProcesses (
IN HINF Inf,
IN PMIGRATE_USER_ENUM EnumPtr OPTIONAL
)
{
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
GROWLIST List = GROWLIST_INIT;
PCTSTR RawCmdLine;
PCTSTR ExpandedCmdLine;
BOOL ProcessResult;
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD rc;
GrowListAppendString (&List, TEXT("SYSTEMDIR"));
GrowListAppendString (&List, g_System32Dir);
if (EnumPtr) {
GrowListAppendString (&List, TEXT("USERNAME"));
GrowListAppendString (&List, EnumPtr->FixedUserName);
GrowListAppendString (&List, TEXT("USERNAMEWITHDOMAIN"));
GrowListAppendString (&List, EnumPtr->FixedDomainName);
GrowListAppendString (&List, TEXT("PREVOS_USERNAME"));
GrowListAppendString (&List, EnumPtr->Win9xUserName);
if (EnumPtr->AccountType != LOGON_USER_SETTINGS) {
GrowListAppendString (&List, TEXT("USERHIVEROOT"));
GrowListAppendString (&List, S_FULL_TEMP_USER_KEY);
} else {
GrowListAppendString (&List, TEXT("USERHIVEROOT"));
GrowListAppendString (&List, S_DEFAULT_USER_KEY);
}
if (EnumPtr->ExtraData) {
GrowListAppendString (&List, TEXT("USERPROFILE"));
GrowListAppendString (&List, EnumPtr->ExtraData->TempProfile);
}
}
//
// Terminate the arg list with two NULLs
//
GrowListAppendEmptyItem (&List);
GrowListAppendEmptyItem (&List);
if (InfFindFirstLine (Inf, S_EXTERNAL_PROCESSES, NULL, (&is))) {
do {
//
// Get the command line
//
RawCmdLine = InfGetLineText (&is);
//
// Expand environment variables
//
ExpandedCmdLine = ExpandEnvironmentTextEx (
RawCmdLine,
GrowListGetStringPtrArray (&List)
);
//
// Launch the process
//
ZeroMemory (&si, sizeof (si));
si.cb = sizeof (si);
si.dwFlags = STARTF_FORCEOFFFEEDBACK;
ProcessResult = CreateProcess (
NULL,
(PTSTR) ExpandedCmdLine,
NULL,
NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE,
NULL,
NULL,
&si,
&pi
);
if (ProcessResult) {
CloseHandle (pi.hThread);
//
// Wait 60 seconds for the process to complete
//
rc = WaitForSingleObject (pi.hProcess, 60000);
if (rc != WAIT_OBJECT_0) {
TerminateProcess (pi.hProcess, 0);
DEBUGMSG ((DBG_ERROR, "Process %s timed out and was aborted", ExpandedCmdLine));
}
ELSE_DEBUGMSG ((DBG_VERBOSE, "External process completed: %s", ExpandedCmdLine));
CloseHandle (pi.hProcess);
}
ELSE_DEBUGMSG ((DBG_ERROR, "Cannot launch %s", ExpandedCmdLine));
FreeText (ExpandedCmdLine);
} while (InfFindNextLine (&is));
}
FreeGrowList (&List);
InfCleanUpInfStruct (&is);
}
DWORD
MigrateGhostSystemFiles (
IN DWORD Request
)
{
/*
TREE_ENUM e;
PCTSTR systemName;
DWORD status;
*/
if (Request == REQUEST_QUERYTICKS) {
return TICKS_GHOST_SYSTEM_MIGRATION;
} else if (Request != REQUEST_RUN) {
return ERROR_SUCCESS;
}
/*
if (EnumFirstFileInTreeEx (&e, g_System32Dir, NULL, FALSE, FALSE, FILE_ENUM_THIS_LEVEL)) {
do {
systemName = JoinPaths (g_SystemDir, e.Name);
status = GetFileStatusOnNt (systemName);
if ((status & FILESTATUS_NTINSTALLED) &&
!(status & FILESTATUS_MOVED)
) {
if (!DoesFileExist (systemName)) {
MarkFileForMove (systemName, e.FullPath);
}
}
FreePathString (systemName);
} while (EnumNextFileInTree (&e));
}
*/
return ERROR_SUCCESS;
}
typedef struct _KNOWN_DIRS {
PCTSTR DirId;
PCTSTR Translation;
}
KNOWN_DIRS, *PKNOWN_DIRS;
KNOWN_DIRS g_KnownDirs [] = {
{TEXT("10"), g_WinDir},
{NULL, NULL}
};
typedef struct {
PCTSTR ShellFolderName;
PCTSTR DirId;
PCTSTR ShellFolderNameDefault;
BOOL bUsed;
} SHELL_TO_DIRS, *PSHELL_TO_DIRS;
SHELL_TO_DIRS g_ShellToDirs[] = {
{TEXT("Administrative Tools"), TEXT("7501"), TEXT("7517\\Administrative Tools")},
{TEXT("Common Administrative Tools"), TEXT("7501"), TEXT("7517\\Administrative Tools")},
{TEXT("AppData"), TEXT("7502"), TEXT("Application Data")},
{TEXT("Common AppData"), TEXT("7502"), TEXT("Application Data")},
{TEXT("Cache"), TEXT("7503"), NULL},
{TEXT("Cookies"), TEXT("7504"), NULL},
{TEXT("Desktop"), TEXT("7505"), NULL},
{TEXT("Common Desktop"), TEXT("7505"), TEXT("Desktop")},
{TEXT("Favorites"), TEXT("7506"), NULL},
{TEXT("Common Favorites"), TEXT("7506"), TEXT("Favorites")},
{TEXT("Local Settings"), TEXT("7510"), NULL},
{TEXT("History"), TEXT("7508"), TEXT("7510\\History")},
{TEXT("Local AppData"), TEXT("7509"), TEXT("7510\\Application Data")},
{TEXT("Personal"), TEXT("7515"), TEXT("My Documents")},
{TEXT("Common Documents"), TEXT("7515"), TEXT("My Documents")},
{TEXT("My Music"), TEXT("7511"), TEXT("7515\\My Music")},
{TEXT("CommonMusic"), TEXT("7511"), TEXT("7515\\My Music")},
{TEXT("My Pictures"), TEXT("7512"), TEXT("7515\\My Pictures")},
{TEXT("CommonPictures"), TEXT("7512"), TEXT("7515\\My Pictures")},
{TEXT("My Video"), TEXT("7513"), TEXT("7515\\My Video")},
{TEXT("CommonVideo"), TEXT("7513"), TEXT("7515\\My Video")},
{TEXT("NetHood"), TEXT("7514"), NULL},
{TEXT("PrintHood"), TEXT("7516"), NULL},
{TEXT("Start Menu"), TEXT("7520"), NULL},
{TEXT("Common Start Menu"), TEXT("7520"), TEXT("Start Menu")},
{TEXT("Programs"), TEXT("7517"), TEXT("7520\\Programs")},
{TEXT("Common Programs"), TEXT("7517"), TEXT("7520\\Programs")},
{TEXT("Recent"), TEXT("7518"), NULL},
{TEXT("SendTo"), TEXT("7519"), NULL},
{TEXT("Startup"), TEXT("7521"), TEXT("7517\\Startup")},
{TEXT("Common Startup"), TEXT("7521"), TEXT("7517\\Startup")},
{TEXT("Templates"), TEXT("7522"), NULL},
{TEXT("Common Templates"), TEXT("7522"), TEXT("Templates")},
{TEXT("Fonts"), TEXT("7507"), TEXT("10\\Fonts")},
{NULL, NULL, NULL, FALSE}
};
GROWLIST g_KnownDirIds = GROWLIST_INIT;
GROWLIST g_KnownDirPaths = GROWLIST_INIT;
VOID
pAddKnownShellFolder (
IN PCTSTR ShellFolderName,
IN PCTSTR SrcPath
)
{
PSHELL_TO_DIRS p;
for (p = g_ShellToDirs ; p->ShellFolderName ; p++) {
if (StringIMatch (ShellFolderName, p->ShellFolderName)) {
break;
}
}
if (!p->ShellFolderName) {
DEBUGMSG ((DBG_ERROR, "This system has an unsupported shell folder tag: %s", ShellFolderName));
return;
}
p->bUsed = TRUE;
GrowListAppendString (&g_KnownDirIds, p->DirId);
GrowListAppendString (&g_KnownDirPaths, SrcPath);
}
typedef struct {
PCTSTR sfName;
PCTSTR sfPath;
HKEY SfKey;
REGVALUE_ENUM SfKeyEnum;
BOOL UserSf;
} SF_ENUM, *PSF_ENUM;
BOOL
EnumFirstRegShellFolder (
IN OUT PSF_ENUM e,
IN BOOL UserSf
);
BOOL
EnumNextRegShellFolder (
IN OUT PSF_ENUM e
);
BOOL
pConvertDirName (
PCTSTR OldDirName,
PTSTR NewDirName,
PINT NameNumber
);
VOID
pInitKnownDirs (
IN BOOL bUser
)
{
SF_ENUM e;
PCTSTR profileForAllUsers;
PCTSTR profileForAllUsersVar = TEXT("%ALLUSERSPROFILE%");
PCTSTR sfPathPtr;
TCHAR shellPartialPath[MAX_PATH];
UINT charCount;
UINT charCountProfileVar;
UINT charCountProfile;
PSHELL_TO_DIRS p;
KNOWN_DIRS * pKnownDirs;
INT nameNumber;
for (p = g_ShellToDirs ; p->ShellFolderName; p++){
p->bUsed = FALSE;
}
if(bUser){
if (EnumFirstRegShellFolder(&e, TRUE)) {
do {
pAddKnownShellFolder(e.sfName, e.sfPath);
DEBUGMSG((DBG_VERBOSE, "USER: ShellFolderPath=%s\nCutedFolderPath=%s", e.sfPath, e.sfPath));
} while (EnumNextRegShellFolder(&e));
}
}
else{
profileForAllUsers = GetProfilePathForAllUsers();
MYASSERT(profileForAllUsers);
if(profileForAllUsers){
charCountProfile = TcharCount(profileForAllUsers);
}
charCountProfileVar = TcharCount(profileForAllUsersVar);
if (EnumFirstRegShellFolder(&e, FALSE)) {
do {
if(profileForAllUsers){
charCount = 0;
if(StringIMatchCharCount(e.sfPath, profileForAllUsers, charCountProfile)){
charCount = charCountProfile;
}
else{
if(StringIMatchCharCount(e.sfPath, profileForAllUsersVar, charCountProfileVar)){
charCount = charCountProfileVar;
}
}
StringCopy(shellPartialPath, TEXT("%USERPROFILE%"));
StringCat(shellPartialPath, &e.sfPath[charCount]);
sfPathPtr = shellPartialPath;
}
else{
sfPathPtr = e.sfPath;
}
DEBUGMSG((DBG_VERBOSE, "SYSTEM: ShellFolderPath=%s\r\nCutedFolderPath=%s", e.sfPath, shellPartialPath));
pAddKnownShellFolder(e.sfName, sfPathPtr);
} while (EnumNextRegShellFolder(&e));
}
FreePathString (profileForAllUsers);
}
for (pKnownDirs = g_KnownDirs ; pKnownDirs->DirId ; pKnownDirs++) {
GrowListAppendString (&g_KnownDirIds, pKnownDirs->DirId);
GrowListAppendString (&g_KnownDirPaths, pKnownDirs->Translation);
}
for (p = g_ShellToDirs ; p->ShellFolderName; p++){
if(p->bUsed){
continue;
}
shellPartialPath[0] = '\0';
nameNumber = 0;
pConvertDirName(p->DirId, shellPartialPath, &nameNumber);
if(!StringMatch (p->DirId, shellPartialPath)){
p->bUsed = TRUE;
continue;
}
if(p->ShellFolderNameDefault){
if(_istdigit(p->ShellFolderNameDefault[0])){
nameNumber = 0;
pConvertDirName(
p->ShellFolderNameDefault,
shellPartialPath,
&nameNumber);
}
else{
StringCopy(shellPartialPath, TEXT("%USERPROFILE%\\"));
StringCat(shellPartialPath, p->ShellFolderNameDefault);
}
}
else{
StringCopy(shellPartialPath, TEXT("%USERPROFILE%\\"));
StringCat(shellPartialPath, p->ShellFolderName);
}
pAddKnownShellFolder(p->ShellFolderName, shellPartialPath);
DEBUGMSG((DBG_VERBOSE, "REST: ShellFolderPath=%s\nCutedFolderPath=%s", p->ShellFolderName, shellPartialPath));
}
}
VOID
pCleanUpKnownDirs (
VOID
)
{
FreeGrowList (&g_KnownDirPaths);
FreeGrowList (&g_KnownDirIds);
}
BOOL
pConvertDirName (
PCTSTR OldDirName,
PTSTR NewDirName,
PINT NameNumber
)
{
PCTSTR OldDirCurr = OldDirName;
PCTSTR OldDirNext;
BOOL match = FALSE;
INT index;
PCTSTR listStr;
if (*NameNumber == -1) {
return FALSE;
}
//
// Extract the dir id, keeping a pointer to the subdir
//
NewDirName[0] = 0;
OldDirNext = _tcschr (OldDirCurr, '\\');
if (OldDirNext == NULL) {
OldDirNext = GetEndOfString (OldDirCurr);
}
StringCopyAB (NewDirName, OldDirCurr, OldDirNext);
//
// Find the next match in the known dir ID list
//
listStr = GrowListGetString (&g_KnownDirIds, *NameNumber);
while (listStr) {
*NameNumber += 1;
if (StringMatch (NewDirName, listStr)) {
listStr = GrowListGetString (&g_KnownDirPaths, (*NameNumber) - 1);
MYASSERT (listStr);
StringCopy (NewDirName, listStr);
break;
}
listStr = GrowListGetString (&g_KnownDirIds, *NameNumber);
}
//
// Cat the subpath to the output string and return
//
StringCat (NewDirName, OldDirNext);
if (!listStr) {
*NameNumber = -1;
return FALSE;
}
return TRUE;
}
VOID
pUninstallUserProfileCleanupPreparation (
IN HINF Inf,
IN PTSTR UserNamePtr,
IN PCTSTR PathProfileRootPtr,
IN PCTSTR DocsAndSettingsRoot,
IN GROWLIST * ListOfLogicalPathsPtr,
IN OUT GROWLIST * ListOfPaths
)
{
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
GROWLIST List = GROWLIST_INIT;
PTSTR rawDir;
TCHAR rawPath[MAX_PATH];
PTSTR ExpandedPath;
PTSTR fileName;
TCHAR shellPath[MAX_PATH];
INT nameNumber;
INT i;
INT listSize;
PCTSTR pathLogicalPath;
GrowListAppendString (&List, TEXT("USERPROFILE"));
GrowListAppendString (&List, PathProfileRootPtr);
GrowListAppendString (&List, TEXT("PROFILES"));
GrowListAppendString (&List, DocsAndSettingsRoot);
GrowListAppendString (&List, TEXT("USERNAME"));
GrowListAppendString (&List, UserNamePtr);
GrowListAppendEmptyItem (&List);
GrowListAppendEmptyItem (&List);
DEBUGMSG ((DBG_VERBOSE, "USERPROFILE.pathProfileRoot=%s\n", PathProfileRootPtr));
if (InfFindFirstLine (Inf, S_UNINSTALL_PROFILE_CLEAN_OUT, NULL, (&is))) {
do{
rawDir = InfGetStringField (&is, 1);
if(!rawDir || *rawDir == 0){
DEBUGMSG ((DBG_VERBOSE, "rawDir == NULL"));
continue;
}
StringCopy (rawPath, rawDir);
fileName = InfGetStringField (&is, 2);
if (fileName && *fileName) {
StringCopy (AppendWack(rawPath), fileName);
}
nameNumber = 0;
pConvertDirName(rawPath, shellPath, &nameNumber);
ExpandedPath = ExpandEnvironmentTextEx (
shellPath,
GrowListGetStringPtrArray (&List)
);
DEBUGMSG ((DBG_VERBOSE, "rawPath=%s\nExpandedPath=%s\nShellPath=%s", rawPath, ExpandedPath, shellPath));
GrowListAppendString (ListOfPaths, ExpandedPath);
FreeText (ExpandedPath);
} while (InfFindNextLine (&is));
}
if(ListOfLogicalPathsPtr){
for(i = 0, listSize = GrowListGetSize (ListOfLogicalPathsPtr); i < listSize; i++) {
pathLogicalPath = GrowListGetString(ListOfLogicalPathsPtr, i);
if(!pathLogicalPath){
continue;
}
nameNumber = 0;
pConvertDirName(pathLogicalPath, shellPath, &nameNumber);
ExpandedPath = ExpandEnvironmentTextEx (
shellPath,
GrowListGetStringPtrArray (&List)
);
GrowListAppendString (ListOfPaths, ExpandedPath);
FreeText (ExpandedPath);
}
}
FreeGrowList (&List);
InfCleanUpInfStruct (&is);
DEBUGMSG ((DBG_VERBOSE, "UninstallUserProfileCleanupPreparation end"));
}
BOOL
pGetProfilePathForAllUsers(
OUT PTSTR AccountName,
OUT PTSTR PathProfile
)
{
PCTSTR pathProfileForAllUser;
MYASSERT(AccountName && PathProfile);
if(!AccountName || !PathProfile){
MYASSERT(FALSE);
return FALSE;
}
pathProfileForAllUser = GetProfilePathForAllUsers();
if(!pathProfileForAllUser) {
return FALSE;
}
StringCopy (AccountName, S_ALL_USERS);
StringCopy (PathProfile, pathProfileForAllUser);
return TRUE;
}
BOOL
pGetProfilePathForDefaultUser(
OUT PTSTR AccountName,
OUT PTSTR PathProfile
)
{
DWORD bufferSize;
MYASSERT(AccountName && PathProfile);
if(!AccountName || !PathProfile){
MYASSERT(FALSE);
return FALSE;
}
bufferSize = MAX_PATH;
if(!GetDefaultUserProfileDirectory(PathProfile, &bufferSize) ||
!PathProfile[0]) {
return FALSE;
}
StringCopy (AccountName, S_DEFAULT_USER);
return TRUE;
}
BOOL
pGetProfilePathForUser(
IN PCTSTR UserName,
OUT PTSTR AccountName,
OUT PTSTR PathProfile
)
{
DWORD bufferSize;
MYASSERT(UserName && UserName[0] && AccountName && PathProfile);
if(!UserName || !UserName[0] || !AccountName || !PathProfile){
MYASSERT(FALSE);
return FALSE;
}
bufferSize = MAX_PATH;
if(!GetProfilesDirectory(PathProfile, &bufferSize) ||
!PathProfile[0]) {
MYASSERT(FALSE);
return FALSE;
}
StringCat(AppendWack(PathProfile), UserName);
StringCopy (AccountName, UserName);
return TRUE;
}
BOOL
pGetProfilePathForLocalService(
OUT PTSTR AccountName,
OUT PTSTR PathProfile
)
{
return pGetProfilePathForUser(S_LOCALSERVICE_USER, AccountName, PathProfile);
}
BOOL
pGetProfilePathForNetworkService(
OUT PTSTR AccountName,
OUT PTSTR PathProfile
)
{
return pGetProfilePathForUser(S_NETWORKSERVICE_USER, AccountName, PathProfile);
}
BOOL
pGetProfilePathForMachineName(
OUT PTSTR AccountName,
OUT PTSTR PathProfile
)
{
TCHAR machineName[MAX_COMPUTERNAME_LENGTH + 2];
PTSTR machineNamePtr = ExpandEnvironmentTextEx (TEXT("%COMPUTERNAME%"), NULL);
BOOL bResult;
if(!machineNamePtr || machineNamePtr[0] == '%'){
MYASSERT(FALSE);
DEBUGMSG((DBG_VERBOSE, "ComputerName is NULL"));
return FALSE;
}
DEBUGMSG ((DBG_VERBOSE, "machineName=%s", machineNamePtr? machineNamePtr: TEXT("NULL")));
StringCopy(machineName, machineNamePtr);
StringCat(machineName, TEXT("$"));
return pGetProfilePathForUser(machineName, AccountName, PathProfile);
}
VOID
UninstallUserProfileCleanupPreparation (
IN HINF Inf,
IN PMIGRATE_USER_ENUM EnumPtr,
IN BOOL Playback
)
{
static GROWLIST listOfPaths = GROWLIST_INIT;
static PROFILE_PATH_PROVIDER profilePathProviders[] =
{
pGetProfilePathForAllUsers,
pGetProfilePathForDefaultUser,
pGetProfilePathForLocalService,
pGetProfilePathForNetworkService,
pGetProfilePathForMachineName
};
TCHAR accountName[MAX_PATH];
TCHAR pathProfile[MAX_PATH];
TCHAR docsAndSettingsRoot[MAX_PATH];
PCTSTR pathProfileRootPtr;
UINT i;
UINT listSize;
DWORD bufferSize;
INT stringLen;
INT cleanOutType;
TCHAR pathDir[MAX_PATH];
bufferSize = ARRAYSIZE (docsAndSettingsRoot);
if (!GetProfilesDirectory (docsAndSettingsRoot, &bufferSize)) {
DEBUGMSG ((DBG_ERROR, "Can't get Documents and Settings root"));
*docsAndSettingsRoot = 0;
}
if (EnumPtr) {
pathProfileRootPtr = GetProfilePathForUser(EnumPtr->FixedUserName);
if(pathProfileRootPtr) {
pInitKnownDirs(TRUE);
pUninstallUserProfileCleanupPreparation(
Inf,
EnumPtr->FixedUserName,
pathProfileRootPtr,
docsAndSettingsRoot,
&g_StartMenuItemsForCleanUpPrivate,
&listOfPaths
);
pCleanUpKnownDirs();
}
} else {
pInitKnownDirs(FALSE);
for(i = 0; i < ARRAYSIZE(profilePathProviders); i++){
if(profilePathProviders[i](accountName, pathProfile)){
pUninstallUserProfileCleanupPreparation(
Inf,
accountName,
pathProfile,
docsAndSettingsRoot,
&g_StartMenuItemsForCleanUpCommon,
&listOfPaths
);
}
}
pCleanUpKnownDirs();
}
if (Playback) {
for(i = 0, listSize = GrowListGetSize (&listOfPaths); i < listSize; i++) {
pathProfileRootPtr = GrowListGetString(&listOfPaths, i);
if (pathProfileRootPtr){
stringLen = TcharCount(pathProfileRootPtr);
if(stringLen > 2 && '*' == pathProfileRootPtr[stringLen - 1]){
MYASSERT('\\' == pathProfileRootPtr[stringLen - 2] || '/' == pathProfileRootPtr[stringLen - 2]);
StringCopyTcharCount(pathDir, pathProfileRootPtr, stringLen - 1);
pathProfileRootPtr = pathDir;
cleanOutType = BACKUP_AND_CLEAN_TREE;
}
else{
cleanOutType = BACKUP_FILE;
}
if (!MemDbSetValueEx (
MEMDB_CATEGORY_CLEAN_OUT,
pathProfileRootPtr,
NULL,
NULL,
cleanOutType,
NULL
)){
DEBUGMSG ((DBG_VERBOSE, "MemDbSetValueEx - failed"));
}
}
}
FreeGrowList (&listOfPaths);
FreeGrowList (&g_StartMenuItemsForCleanUpCommon);
FreeGrowList (&g_StartMenuItemsForCleanUpPrivate);
}
}
VOID
SetClassicLogonType (
VOID
)
{
static BOOL logonTypeChanged = FALSE;
DWORD d;
HKEY key;
LONG regResult;
if (!logonTypeChanged) {
key = OpenRegKeyStr (S_WINLOGON_REGKEY);
if (key) {
d = 0; // classic logon style
regResult = RegSetValueEx (
key,
TEXT("LogonType"),
0,
REG_DWORD,
(PCBYTE)(&d),
sizeof (d)
);
if (regResult == ERROR_SUCCESS) {
logonTypeChanged = TRUE;
LOG ((LOG_INFORMATION, "Logon type set to classic style because of MigrateUserAs answer file settings"));
}
CloseRegKey (key);
}
if (!logonTypeChanged) {
LOG ((LOG_ERROR, "Failed to set logon type to classic style; users will not appear in the logon menu"));
logonTypeChanged = TRUE;
}
}
}