2904 lines
82 KiB
C
2904 lines
82 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
inifiles.c
|
|
|
|
Abstract:
|
|
|
|
There are two major actions that are performed in this module.
|
|
1. Migration of settings from the INI files to the registry according to
|
|
subkeys from HKLM\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping.
|
|
Entry point : ProcessIniFileMapping
|
|
|
|
2. Processing of INI files not listed in the above key, changing paths to
|
|
files that we moved during upgrade.
|
|
Entry point : ConvertIniFiles
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 11-Sept-1997
|
|
|
|
Revision History:
|
|
|
|
jimschm 23-Sep-1998 Changed to use new fileops
|
|
calinn 29-Jan-1998 Added lookup for Win95 registry
|
|
calinn 19-Jan-1998 added support for Shell settings processing
|
|
calinn 06-Oct-1997 rewrote the whole source
|
|
calinn 11-May-1998 Added MergeIniSettings, various fixes
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "migmainp.h"
|
|
#include "..\merge\mergep.h"
|
|
|
|
#define DBG_INIFILES "IniFiles"
|
|
#define DBG_MOVEINISETTINGS "IniFileMove"
|
|
|
|
#define BufferIncrement 1024
|
|
|
|
BOOL
|
|
pLoadIniFileBuffer (
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR SectName,
|
|
IN PCTSTR KeyName,
|
|
OUT PTSTR *OutBuff
|
|
);
|
|
|
|
BOOL
|
|
pCopyIniFileToRegistry (
|
|
IN HKEY KeyHandle,
|
|
IN PCTSTR FileName,
|
|
IN BOOL UserMode
|
|
);
|
|
|
|
BOOL
|
|
pTransferSectionByKey (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR Section,
|
|
IN HKEY SectionKey,
|
|
IN OUT BOOL *IniFileChanged,
|
|
IN BOOL UserMode
|
|
);
|
|
|
|
BOOL
|
|
pTransferSectionByValue (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR Section,
|
|
IN PCTSTR SectionValue,
|
|
IN OUT BOOL *IniFileChanged,
|
|
IN BOOL UserMode
|
|
);
|
|
|
|
BOOL
|
|
pSaveMappedValue (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR Section,
|
|
IN PCTSTR ValueName,
|
|
IN PCTSTR RegPath,
|
|
IN PCTSTR Value,
|
|
IN OUT BOOL *ReverseMapping,
|
|
OUT PTSTR *ReverseMapValue,
|
|
IN BOOL UserMode
|
|
);
|
|
|
|
BOOL
|
|
pBuildSuppressionTable (
|
|
IN BOOL UserMode
|
|
);
|
|
|
|
VOID
|
|
pFreeSuppressionTable (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pIncompatibleShell (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pIncompatibleSCR (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
ProcessIniFileMapping (
|
|
IN BOOL UserMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ProcessIniFileMapping reads in the INI files, copying data to specific
|
|
locations in the registry. This copy is based on the IniFileMapping key in
|
|
Software\Microsoft\Windows NT\CurrentVersion.
|
|
|
|
These mappings can be overridden based upon the content of the [Suppress Ini File Mappings] section.
|
|
|
|
Arguments:
|
|
|
|
UserMode - Specifies TRUE if per-user sections are to be processed, or
|
|
FALSE if local machine sections are to be processed.
|
|
|
|
Return Value:
|
|
|
|
Always returns TRUE. If some error occured while processing, then there will be a log entry
|
|
specifying that.
|
|
|
|
--*/
|
|
|
|
{
|
|
REGKEY_ENUM e;
|
|
HKEY IniMappingKey;
|
|
HKEY OldRegRoot=NULL;
|
|
|
|
BOOL Result = TRUE;
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "Processing INI file mapping - START"));
|
|
|
|
if (UserMode) {
|
|
OldRegRoot = GetRegRoot();
|
|
SetRegRoot (g_hKeyRootNT);
|
|
}
|
|
|
|
__try {
|
|
if (!EnumFirstRegKeyStr (&e, S_INIFILEMAPPING_KEY)) {
|
|
|
|
//
|
|
// nothing to do here
|
|
//
|
|
__leave;
|
|
|
|
}
|
|
|
|
//
|
|
// There is at least one file mapping to process.
|
|
// Fill the table of ini file suppression table.
|
|
//
|
|
__try {
|
|
|
|
//
|
|
// Trying to load the suppression table, recording the eventual error
|
|
// but going on with the stuff
|
|
//
|
|
if (!pBuildSuppressionTable(UserMode)) {
|
|
Result = FALSE;
|
|
}
|
|
|
|
// Special case : SHELL= line from SYSTEM.INI
|
|
// We try to see if the current shell is supported on NT.
|
|
// If not then we will add SHELL to this suppression table
|
|
// ensuring that the NT registry setting will get mapped into
|
|
// the INI file
|
|
if ((!UserMode) &&
|
|
(pIncompatibleShell())
|
|
) {
|
|
MemDbSetValueEx (
|
|
MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
|
|
TEXT("SYSTEM.INI"),
|
|
TEXT("BOOT"),
|
|
TEXT("SHELL"),
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
if ((UserMode) &&
|
|
(pIncompatibleSCR())) {
|
|
MemDbSetValueEx (
|
|
MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
|
|
TEXT("SYSTEM.INI"),
|
|
TEXT("BOOT"),
|
|
TEXT("SCRNSAVE.EXE"),
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now processing keys
|
|
//
|
|
do {
|
|
|
|
IniMappingKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
|
|
if (IniMappingKey) {
|
|
|
|
//
|
|
// Process the file mapping
|
|
//
|
|
|
|
if (!pCopyIniFileToRegistry (
|
|
IniMappingKey,
|
|
e.SubKeyName,
|
|
UserMode
|
|
)) {
|
|
Result = FALSE;
|
|
}
|
|
|
|
CloseRegKey(IniMappingKey);
|
|
|
|
}
|
|
else {
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "IniFileMapping : Could not open %s", e.SubKeyName));
|
|
Result = FALSE;
|
|
}
|
|
|
|
} while (EnumNextRegKey (&e));
|
|
|
|
pFreeSuppressionTable();
|
|
|
|
}
|
|
__finally {
|
|
AbortRegKeyEnum (&e);
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
if (UserMode) {
|
|
SetRegRoot (OldRegRoot);
|
|
}
|
|
}
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "Processing INI file mapping - STOP"));
|
|
|
|
if (!Result) {
|
|
//
|
|
// we are going to log that at least one error occured while processing IniFileMapping
|
|
//
|
|
DEBUGMSG ((DBG_ERROR, (PCSTR)MSG_INI_FILE_MAPPING_LOG));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pIncompatibleShell (
|
|
VOID
|
|
)
|
|
{
|
|
TCHAR key [MEMDB_MAX];
|
|
TCHAR shellVal[MEMDB_MAX] = TEXT("");
|
|
PCTSTR fileName;
|
|
PCTSTR newName;
|
|
DWORD result;
|
|
|
|
fileName = JoinPaths (g_WinDir, TEXT("SYSTEM.INI"));
|
|
newName = GetTemporaryLocationForFile (fileName);
|
|
|
|
if (newName) {
|
|
DEBUGMSG ((DBG_INIFILES, "pIncompatibleShell: Using %s for %s", newName, fileName));
|
|
FreePathString (fileName);
|
|
fileName = newName;
|
|
}
|
|
|
|
if (!DoesFileExist (fileName)) {
|
|
DEBUGMSG ((DBG_INIFILES, "pIncompatibleShell: %s not found", fileName));
|
|
}
|
|
|
|
result = GetPrivateProfileString (
|
|
TEXT("boot"),
|
|
TEXT("shell"),
|
|
TEXT("explorer.exe"),
|
|
shellVal,
|
|
MEMDB_MAX,
|
|
fileName);
|
|
|
|
FreePathString (fileName);
|
|
|
|
if ((result == 0) ||
|
|
(result + 1 == MEMDB_MAX)
|
|
) {
|
|
return FALSE;
|
|
}
|
|
MemDbBuildKey (key, MEMDB_CATEGORY_COMPATIBLE_SHELL_NT, shellVal, NULL, NULL);
|
|
return (!MemDbGetValue (key, NULL));
|
|
}
|
|
|
|
BOOL
|
|
pIncompatibleSCR (
|
|
VOID
|
|
)
|
|
{
|
|
TCHAR scrVal [MEMDB_MAX] = TEXT("");
|
|
PCTSTR fileName;
|
|
PCTSTR newName;
|
|
DWORD result;
|
|
|
|
fileName = JoinPaths (g_WinDir, TEXT("SYSTEM.INI"));
|
|
newName = GetTemporaryLocationForFile (fileName);
|
|
|
|
if (newName) {
|
|
DEBUGMSG ((DBG_INIFILES, "pIncompatibleSCR: Using %s for %s", newName, fileName));
|
|
FreePathString (fileName);
|
|
fileName = newName;
|
|
}
|
|
|
|
if (!DoesFileExist (fileName)) {
|
|
DEBUGMSG ((DBG_INIFILES, "pIncompatibleSCR: %s not found", fileName));
|
|
}
|
|
|
|
result = GetPrivateProfileString (
|
|
TEXT("boot"),
|
|
TEXT("SCRNSAVE.EXE"),
|
|
TEXT(""),
|
|
scrVal,
|
|
MEMDB_MAX,
|
|
fileName);
|
|
|
|
FreePathString (fileName);
|
|
|
|
if ((result == 0) ||
|
|
(result + 1 == MEMDB_MAX)
|
|
) {
|
|
return FALSE;
|
|
}
|
|
|
|
return IsFileMarkedForDelete (scrVal);
|
|
}
|
|
|
|
BOOL
|
|
pLoadIniFileBuffer (
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR SectName,
|
|
IN PCTSTR KeyName,
|
|
OUT PTSTR *OutBuff
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uses GetPrivateProfileString routine trying to load a section buffer, a key buffer or
|
|
a key value (depends on the arguments). The reason why there is such a routine is to be sure that
|
|
we are able to load stuff from INI file while not allocating a lot of memory. This routine incrementaly
|
|
allocates memory, returning when there is enough memory to load stuff from INI file.
|
|
|
|
Arguments:
|
|
|
|
FileName - Specifies INI file to be processed
|
|
SectName - Specifies section to be processed. If NULL the whole section buffer will be loaded
|
|
KeyName - Specifies the key to be processed. If NULL the whole key buffer will be loaded.
|
|
OutBuff - Output buffer holding the result.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD OutBuffSize;
|
|
DWORD ReadSize;
|
|
BOOL Done;
|
|
|
|
OutBuffSize = 0;
|
|
*OutBuff = NULL;
|
|
do {
|
|
if (*OutBuff) {
|
|
MemFree (g_hHeap, 0, *OutBuff);
|
|
}
|
|
OutBuffSize += BufferIncrement;
|
|
*OutBuff = MemAlloc (g_hHeap, 0, OutBuffSize * sizeof (TCHAR));
|
|
if (!(*OutBuff)) {
|
|
return FALSE;
|
|
}
|
|
|
|
ReadSize = GetPrivateProfileString (
|
|
SectName,
|
|
KeyName,
|
|
TEXT(""),
|
|
*OutBuff,
|
|
OutBuffSize,
|
|
FileName
|
|
);
|
|
if (SectName && KeyName) {
|
|
Done = (ReadSize < OutBuffSize - 1);
|
|
} else {
|
|
Done = (ReadSize < OutBuffSize - 2);
|
|
}
|
|
} while (!Done);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCopyIniFileToRegistry (
|
|
IN HKEY KeyHandle,
|
|
IN PCTSTR FileName,
|
|
IN BOOL UserMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine transports settings from the INI file into registry or from the registry to
|
|
the INI file.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - IniFileMapping key associated with this INI file.
|
|
FileName - Specifies INI file to be processed
|
|
UserMode - Specifies TRUE if per-user sections are to be processed, or
|
|
FALSE if local machine sections are to be processed.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if at least one error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR NewName = NULL;
|
|
PCTSTR FullPath = NULL;
|
|
TCHAR TempPath[MEMDB_MAX];
|
|
PTSTR Section, SectionBuf;
|
|
HKEY SectionKey;
|
|
PCTSTR SectionValue;
|
|
DWORD Attribs = -1;
|
|
BOOL IniFileChanged = FALSE;
|
|
BOOL mapToIniFile = FALSE;
|
|
BOOL Result = TRUE;
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "Processing %s - START", FileName));
|
|
|
|
//
|
|
// now we have the full path for the INI file
|
|
// Since we are going to use Ini file API we have to copy every file to some other name
|
|
// to avoid mapping requests into registry
|
|
//
|
|
if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, TempPath)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot create a temporary file"));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
|
|
FullPath = JoinPaths (g_WinDir, FileName);
|
|
NewName = GetTemporaryLocationForFile (FullPath);
|
|
if (NewName) {
|
|
DEBUGMSG ((DBG_INIFILES, "Using %s for %s", NewName, FullPath));
|
|
FreePathString (FullPath);
|
|
FullPath = NewName;
|
|
}
|
|
|
|
Attribs = GetFileAttributes (FullPath);
|
|
if (Attribs == (DWORD)-1) {
|
|
DEBUGMSG ((DBG_INIFILES, "pCopyIniFileToRegistry: %s not found", FullPath));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// now trying to copy file
|
|
//
|
|
if (!CopyFile (FullPath, TempPath, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot copy %s to %s", FullPath, TempPath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
__try {
|
|
|
|
//
|
|
// Next thing we are going to do is to load the sections in a buffer
|
|
//
|
|
|
|
if (!pLoadIniFileBuffer (TempPath, NULL, NULL, &SectionBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load section buffer for %s", TempPath));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// now we have all sections of the INI file and proceeding
|
|
//
|
|
|
|
Section = SectionBuf;
|
|
|
|
//
|
|
// there is a loop here for every section in the buffer
|
|
//
|
|
while (*Section) {
|
|
|
|
//
|
|
// now trying to see if there is a subkey matching section name.
|
|
//
|
|
SectionKey = OpenRegKey (KeyHandle, Section);
|
|
|
|
if (SectionKey) {
|
|
|
|
if (!pTransferSectionByKey (
|
|
FileName,
|
|
TempPath,
|
|
Section,
|
|
SectionKey,
|
|
&IniFileChanged,
|
|
UserMode
|
|
)) {
|
|
Result = FALSE;
|
|
}
|
|
CloseRegKey (SectionKey);
|
|
}
|
|
else {
|
|
|
|
SectionValue = GetRegValueString (KeyHandle, Section);
|
|
|
|
if (!SectionValue) {
|
|
SectionValue = GetRegValueString (KeyHandle, S_EMPTY);
|
|
}
|
|
|
|
if (SectionValue && (*SectionValue)) {
|
|
if (!pTransferSectionByValue (
|
|
FileName,
|
|
TempPath,
|
|
Section,
|
|
SectionValue,
|
|
&IniFileChanged,
|
|
UserMode
|
|
)) {
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
|
|
if (SectionValue) {
|
|
MemFree (g_hHeap, 0, SectionValue);
|
|
}
|
|
|
|
}
|
|
|
|
Section = GetEndOfString (Section) + 1;
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
if (SectionBuf) {
|
|
MemFree (g_hHeap, 0 , SectionBuf);
|
|
}
|
|
}
|
|
|
|
//
|
|
// finally, if we made any changes then we will copy the INI file back
|
|
//
|
|
if (IniFileChanged) {
|
|
|
|
// flushing the INI file
|
|
WritePrivateProfileString (
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
TempPath
|
|
);
|
|
|
|
if (!CopyFile (TempPath, FullPath, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot copy %s to %s", TempPath, FullPath));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (TempPath);
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
if (Attribs != (DWORD)-1) {
|
|
SetFileAttributes (FullPath, Attribs);
|
|
}
|
|
|
|
if (FullPath) {
|
|
FreePathString (FullPath);
|
|
}
|
|
|
|
SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (TempPath);
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "Processing %s - STOP", FileName));
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pTransferSectionByKey (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR Section,
|
|
IN HKEY SectionKey,
|
|
IN OUT BOOL *IniFileChanged,
|
|
IN BOOL UserMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine transports settings from a specified section of an INI file
|
|
into registry or from the registry to the INI file. If there is a case when
|
|
the settings go from registry to INI file then IniFileChanged is set to TRUE
|
|
|
|
Arguments:
|
|
|
|
FileName - Specifies INI file to be processed
|
|
Section - Specifies section to be processed
|
|
SectionKey - key associated with this section
|
|
IniFileChanged - Tells the caller that at least one setting was from registry to the INI file
|
|
UserMode - Specifies TRUE if per-user sections are to be processed, or
|
|
FALSE if local machine sections are to be processed.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if at least one error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
PTSTR Key, KeyBuf;
|
|
PTSTR KeyValue;
|
|
PCTSTR SectionValue;
|
|
BOOL ReverseMapping;
|
|
PTSTR ReverseMapValue;
|
|
|
|
BOOL Result = TRUE;
|
|
|
|
if (!pLoadIniFileBuffer (FileName, Section, NULL, &KeyBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key buffer for %s in %s", Section, FileName));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// now we have all keys of the section and proceeding
|
|
//
|
|
|
|
Key = KeyBuf;
|
|
|
|
//
|
|
// there is a loop here for every key in the buffer
|
|
//
|
|
while (*Key) {
|
|
|
|
//
|
|
// trying to read the value for the key
|
|
//
|
|
if (!pLoadIniFileBuffer (FileName, Section, Key, &KeyValue)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key %s in %s in %s", Key, Section, FileName));
|
|
Result = FALSE;
|
|
continue;
|
|
}
|
|
|
|
__try {
|
|
|
|
SectionValue = GetRegValueString (SectionKey, Key);
|
|
|
|
if (!SectionValue) {
|
|
SectionValue = GetRegValueString (SectionKey, S_EMPTY);
|
|
}
|
|
|
|
if (SectionValue && (*SectionValue)) {
|
|
|
|
if (!pSaveMappedValue (
|
|
OrigFileName,
|
|
Section,
|
|
Key,
|
|
SectionValue,
|
|
KeyValue,
|
|
&ReverseMapping,
|
|
&ReverseMapValue,
|
|
UserMode
|
|
)) {
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (UserMode && ReverseMapping) {
|
|
if (!WritePrivateProfileString (
|
|
Section,
|
|
Key,
|
|
NULL,
|
|
FileName
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot erase key %s from %s from %s", Key, Section, OrigFileName));
|
|
Result = FALSE;
|
|
}
|
|
else {
|
|
*IniFileChanged = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if ((ReverseMapping) && (ReverseMapValue)) {
|
|
|
|
// writing the new value
|
|
if (!WritePrivateProfileString (
|
|
Section,
|
|
Key,
|
|
ReverseMapValue,
|
|
FileName
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot write line %s=%s in %s in %s", Key, ReverseMapValue, Section, FileName));
|
|
Result = FALSE;
|
|
}
|
|
else {
|
|
*IniFileChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ReverseMapValue) {
|
|
MemFree (g_hHeap, 0, ReverseMapValue);
|
|
}
|
|
}
|
|
|
|
if (SectionValue) {
|
|
MemFree (g_hHeap, 0, SectionValue);
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
if (KeyValue) {
|
|
MemFree (g_hHeap, 0, KeyValue);
|
|
}
|
|
}
|
|
|
|
Key = GetEndOfString (Key) + 1;
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
if (KeyBuf) {
|
|
MemFree (g_hHeap, 0, KeyBuf);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pTransferSectionByValue (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR Section,
|
|
IN PCTSTR SectionValue,
|
|
IN OUT BOOL *IniFileChanged,
|
|
IN BOOL UserMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine transports settings from a specified section of an INI file
|
|
into registry or from the registry to the INI file. If there is a case when
|
|
the settings go from registry to INI file then IniFileChanged is set to TRUE
|
|
|
|
Arguments:
|
|
|
|
FileName - Specifies INI file to be processed
|
|
Section - Specifies section to be processed
|
|
SectionValue - ValueName associated with this section
|
|
IniFileChanged - Tells the caller that at least one setting was from registry to the INI file
|
|
UserMode - Specifies TRUE if per-user sections are to be processed, or
|
|
FALSE if local machine sections are to be processed.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if at least one error occured
|
|
|
|
--*/
|
|
|
|
{
|
|
PTSTR Key, KeyBuf;
|
|
PTSTR KeyValue;
|
|
BOOL ReverseMapping;
|
|
PTSTR ReverseMapValue;
|
|
|
|
BOOL Result = TRUE;
|
|
|
|
if (!pLoadIniFileBuffer (FileName, Section, NULL, &KeyBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key buffer for %s in %s", Section, FileName));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// now we have all keys of the section and proceeding
|
|
//
|
|
|
|
Key = KeyBuf;
|
|
|
|
//
|
|
// there is a loop here for every key in the buffer
|
|
//
|
|
while (*Key) {
|
|
|
|
//
|
|
// trying to read the value for the key
|
|
//
|
|
if (!pLoadIniFileBuffer (FileName, Section, Key, &KeyValue)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key %s in %s in %s", Key, Section, FileName));
|
|
Result = FALSE;
|
|
continue;
|
|
}
|
|
|
|
__try {
|
|
|
|
if (!pSaveMappedValue (
|
|
OrigFileName,
|
|
Section,
|
|
Key,
|
|
SectionValue,
|
|
KeyValue,
|
|
&ReverseMapping,
|
|
&ReverseMapValue,
|
|
UserMode
|
|
)) {
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (UserMode && ReverseMapping) {
|
|
if (!WritePrivateProfileString (
|
|
Section,
|
|
Key,
|
|
NULL,
|
|
FileName
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot erase key %s from %s from %s", Key, Section, OrigFileName));
|
|
Result = FALSE;
|
|
}
|
|
else {
|
|
*IniFileChanged = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if ((ReverseMapping) &&(ReverseMapValue)) {
|
|
|
|
// writing the new value
|
|
if (!WritePrivateProfileString (
|
|
Section,
|
|
Key,
|
|
ReverseMapValue,
|
|
FileName
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot write line %s=%s in %s in %s", Key, ReverseMapValue, Section, FileName));
|
|
Result = FALSE;
|
|
}
|
|
else {
|
|
*IniFileChanged = TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (ReverseMapValue) {
|
|
MemFree (g_hHeap, 0, ReverseMapValue);
|
|
}
|
|
}
|
|
__finally {
|
|
if (KeyValue) {
|
|
MemFree (g_hHeap, 0, KeyValue);
|
|
}
|
|
}
|
|
|
|
Key = GetEndOfString (Key) + 1;
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
MemFree (g_hHeap, 0, KeyBuf);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pDoesStrHavePrefix (
|
|
IN OUT PCTSTR *String,
|
|
IN PCTSTR Prefix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Simple routine that checks if a specified string has a specified prefix and if so
|
|
advances the string pointer to point exactly after the prefix.
|
|
|
|
Arguments:
|
|
|
|
String - String to be processed
|
|
Prefix - Prefix to be processed
|
|
|
|
Return Value:
|
|
|
|
TRUE if String has Prefix, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT Len;
|
|
|
|
Len = CharCount (Prefix);
|
|
if (StringIMatchCharCount (*String, Prefix, Len)) {
|
|
*String = CharCountToPointer (*String, Len);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pShouldSaveKey (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR Section,
|
|
IN PCTSTR ValueName,
|
|
IN PCTSTR RegKey, OPTIONAL
|
|
IN OUT BOOL *ReverseMapping,
|
|
IN BOOL UserMode,
|
|
IN BOOL ExclusionsOnly
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Simple routine that checks if a setting should go from INI file to registry.
|
|
If the setting is globally suppressed or it's in suppression table returns FALSE
|
|
|
|
Arguments:
|
|
|
|
OrigFileName - Specifies the original Win9x INI file name (not the current one)
|
|
|
|
Section - Specifies the section within the INI file
|
|
|
|
ValueName - Specifies the key within the INI file section
|
|
|
|
RegKey - Specifies the registry key destination, from the IniFileMapping key;
|
|
optional only if ExclusionsOnly is TRUE
|
|
|
|
ReverseMapping - Receives TRUE if the direction of data copy is to go from the
|
|
NT registry to the INI file; receives FALSE if the direction
|
|
is from the INI file to the registry
|
|
|
|
UserMode - Specifies TRUE to do per-user processing
|
|
|
|
ExclusionsOnly - Specifies TRUE if only exclusions should be tested
|
|
|
|
Return Value:
|
|
|
|
TRUE if direction is from INI file to registry, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY key;
|
|
HKEY OldRegRoot = NULL;
|
|
BOOL b = TRUE;
|
|
TCHAR ekey[MEMDB_MAX];
|
|
LONG rc;
|
|
|
|
*ReverseMapping = FALSE;
|
|
if (RegKey && IsNtRegObjectSuppressed (RegKey, NULL)) {
|
|
DEBUGMSG ((DBG_NAUSEA, "INI destination is suppressed: %s", RegKey));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Let's see if this mapping is suppressed
|
|
//
|
|
MemDbBuildKey (
|
|
ekey,
|
|
MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
|
|
OrigFileName,
|
|
Section,
|
|
ValueName
|
|
);
|
|
|
|
if (MemDbGetStoredEndPatternValue (ekey, NULL)) {
|
|
DEBUGMSG ((
|
|
DBG_NAUSEA,
|
|
"INI destination is suppressed: %s\\%s\\%s",
|
|
OrigFileName,
|
|
Section,
|
|
ValueName
|
|
));
|
|
*ReverseMapping = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If the NT key exists and we don't want to overwrite NT values, reverse
|
|
// the mapping.
|
|
//
|
|
|
|
MemDbBuildKey (
|
|
ekey,
|
|
MEMDB_CATEGORY_NO_OVERWRITE_INI_MAPPINGSW,
|
|
OrigFileName,
|
|
Section,
|
|
ValueName
|
|
);
|
|
|
|
if (MemDbGetStoredEndPatternValue (ekey, NULL)) {
|
|
|
|
if (ExclusionsOnly) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (UserMode) {
|
|
OldRegRoot = GetRegRoot();
|
|
SetRegRoot (g_hKeyRootNT);
|
|
}
|
|
|
|
key = OpenRegKeyStr (RegKey);
|
|
|
|
if (key) {
|
|
|
|
rc = RegQueryValueEx (key, ValueName, NULL, NULL, NULL, NULL);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
//
|
|
// The NT registry value exists, do not overwrite it.
|
|
// Instead, reverse the mapping so that the INI file
|
|
// gets the NT value.
|
|
//
|
|
|
|
DEBUGMSG ((
|
|
DBG_NAUSEA,
|
|
"NT value exists; reversing mapping: %s [%s]",
|
|
RegKey,
|
|
ValueName
|
|
));
|
|
|
|
*ReverseMapping = TRUE;
|
|
|
|
//
|
|
// don't write the key on return, instead write in INI file
|
|
//
|
|
b = FALSE;
|
|
}
|
|
|
|
CloseRegKey (key);
|
|
}
|
|
|
|
if (UserMode) {
|
|
SetRegRoot (OldRegRoot);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
if (ExclusionsOnly) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// If Win9x key exists, reverse the mapping (so the Win9x registry setting
|
|
// is used instead of the potentially stale INI file setting)
|
|
//
|
|
|
|
if (UserMode) {
|
|
OldRegRoot = GetRegRoot();
|
|
SetRegRoot (g_hKeyRoot95);
|
|
}
|
|
|
|
key = OpenRegKeyStr95 (RegKey);
|
|
|
|
if (UserMode) {
|
|
SetRegRoot (OldRegRoot);
|
|
}
|
|
|
|
if (key != NULL) {
|
|
if (Win95RegQueryValueEx (key, ValueName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
*ReverseMapping = TRUE;
|
|
DEBUGMSG ((DBG_NAUSEA, "INI destination is suppressed: %s", RegKey));
|
|
b = FALSE;
|
|
}
|
|
|
|
CloseRegKey95 (key);
|
|
}
|
|
|
|
DEBUGMSG_IF ((b, DBG_NAUSEA, "INI destination is not suppressed: %s", RegKey));
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pSaveMappedValue (
|
|
IN PCTSTR OrigFileName,
|
|
IN PCTSTR Section,
|
|
IN PCTSTR ValueName,
|
|
IN PCTSTR RegPath,
|
|
IN PCTSTR Value,
|
|
IN OUT BOOL *ReverseMapping,
|
|
OUT PTSTR *ReverseMapValue,
|
|
IN BOOL UserMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine has a valuename and a value that should be saved in a key indicated by RegPath.
|
|
|
|
Arguments:
|
|
|
|
RegPath - Key where setting should be saved
|
|
ValueName - ValueName for the key
|
|
Value - Value for the key
|
|
ReverseMapping - tells the caller that the setting should be saved from registry to INI file
|
|
ReverseMapValue - if ReverseMapping is TRUE that we have the value of the key here
|
|
UserMode - Specifies TRUE if per-user sections are to be processed, or
|
|
FALSE if local machine sections are to be processed.
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
CHARTYPE ch;
|
|
TCHAR RegKey[MAX_REGISTRY_KEY];
|
|
DWORD rc;
|
|
HKEY SaveKey;
|
|
PCTSTR newValue;
|
|
PTSTR p;
|
|
|
|
BOOL Result = TRUE;
|
|
|
|
*ReverseMapping = FALSE;
|
|
*ReverseMapValue = NULL;
|
|
|
|
//
|
|
// Parse the string
|
|
//
|
|
|
|
//
|
|
// Skip past special chars
|
|
//
|
|
|
|
while (TRUE) {
|
|
ch = (CHARTYPE)_tcsnextc (RegPath);
|
|
if (ch == TEXT('!') ||
|
|
ch == TEXT('#') ||
|
|
ch == TEXT('@')
|
|
) {
|
|
RegPath = _tcsinc (RegPath);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If SYS:, USR: or \Registry\Machine\ then replace appropriately
|
|
//
|
|
|
|
RegKey[0] = 0;
|
|
|
|
if (pDoesStrHavePrefix (&RegPath, TEXT("SYS:"))) {
|
|
if (UserMode) {
|
|
return TRUE;
|
|
}
|
|
|
|
p = TEXT("HKLM\\SOFTWARE");
|
|
} else if (pDoesStrHavePrefix (&RegPath, TEXT("USR:"))) {
|
|
if (!UserMode) {
|
|
return TRUE;
|
|
}
|
|
|
|
p = TEXT("HKR");
|
|
} else if (pDoesStrHavePrefix (&RegPath, TEXT("\\Registry\\Machine\\"))) {
|
|
if (UserMode) {
|
|
return TRUE;
|
|
}
|
|
|
|
p = TEXT("HKLM");
|
|
}
|
|
|
|
_sntprintf (RegKey, MAX_REGISTRY_KEY, TEXT("%s\\%s"), p, RegPath);
|
|
|
|
if (pShouldSaveKey(OrigFileName, Section, ValueName, RegKey, ReverseMapping, UserMode, FALSE)) {
|
|
|
|
|
|
SaveKey = CreateRegKeyStr (RegKey);
|
|
if (SaveKey) {
|
|
newValue = GetPathStringOnNt (Value);
|
|
rc = RegSetValueEx (
|
|
SaveKey,
|
|
ValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE) newValue,
|
|
SizeOfString (newValue)
|
|
);
|
|
CloseRegKey (SaveKey);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError (rc);
|
|
|
|
Result = FALSE;
|
|
|
|
DEBUGMSG ((
|
|
DBG_ERROR,
|
|
"Process Ini File Mapping: Could not save %s=%s to %s",
|
|
ValueName,
|
|
newValue,
|
|
RegKey
|
|
));
|
|
}
|
|
|
|
FreePathString (newValue);
|
|
}
|
|
else {
|
|
DEBUGMSG ((DBG_ERROR, "Process Ini File Mapping: Could not create %s", RegKey));
|
|
}
|
|
}
|
|
else {
|
|
if (*ReverseMapping) {
|
|
|
|
// trying to open key
|
|
SaveKey = OpenRegKeyStr (RegKey);
|
|
|
|
if (SaveKey) {
|
|
|
|
*ReverseMapValue = (PTSTR)GetRegValueString (SaveKey, ValueName);
|
|
|
|
CloseRegKey (SaveKey);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pBuildSuppressionTable (
|
|
IN BOOL UserMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loads the "Suppress INI File Mappings" section from "wkstamig.inf" or from "usermig.inf"
|
|
into a stringtable.
|
|
|
|
Arguments:
|
|
|
|
UserMode - Specifies TRUE if section is loaded from usermig.inf
|
|
FALSE if section is loaded from wkstamig.inf
|
|
UserMode
|
|
|
|
Return Value:
|
|
|
|
Always returns TRUE. In case of an error, we are going to log it but returning TRUE
|
|
trying to go on.
|
|
|
|
--*/
|
|
|
|
{
|
|
HINF InfHandle;
|
|
TCHAR field[MEMDB_MAX];
|
|
INFCONTEXT context;
|
|
|
|
if (UserMode) {
|
|
InfHandle = g_UserMigInf;
|
|
}
|
|
else {
|
|
InfHandle = g_WkstaMigInf;
|
|
}
|
|
|
|
if (InfHandle == INVALID_HANDLE_VALUE) {
|
|
|
|
DEBUGMSG((DBG_ERROR,"Ini File Mapping : wkstamig.inf or usermig.inf is not loaded"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (SetupFindFirstLine (InfHandle, S_SUPPRESS_INI_FILE_MAPPINGS, NULL, &context)) {
|
|
do {
|
|
if (SetupGetStringField (&context, 0, field, MEMDB_MAX, NULL)) {
|
|
MemDbSetValueEx (
|
|
MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
|
|
field,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
} while (SetupFindNextLine (&context, &context));
|
|
}
|
|
|
|
if (SetupFindFirstLine (InfHandle, S_NO_OVERWRITE_INI_FILE_MAPPINGS, NULL, &context)) {
|
|
do {
|
|
if (SetupGetStringField (&context, 0, field, MEMDB_MAX, NULL)) {
|
|
MemDbSetValueEx (
|
|
MEMDB_CATEGORY_NO_OVERWRITE_INI_MAPPINGSW,
|
|
field,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
} while (SetupFindNextLine (&context, &context));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
pFreeSuppressionTable (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Simple routine that free the string table if it exists
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
MemDbDeleteTree (MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW);
|
|
MemDbDeleteTree (MEMDB_CATEGORY_NO_OVERWRITE_INI_MAPPINGSW);
|
|
}
|
|
|
|
|
|
|
|
enum Separators {
|
|
tab = TEXT('\t'),
|
|
space = TEXT(' '),
|
|
comma = TEXT(','),
|
|
quote = TEXT('\"')
|
|
};
|
|
|
|
|
|
BOOL
|
|
pAddValue(
|
|
IN OUT TCHAR **Buffer,
|
|
IN OUT TCHAR *Value,
|
|
IN UINT BufChars
|
|
);
|
|
|
|
BOOL
|
|
pProcessStrValue (
|
|
IN TCHAR *InBuf,
|
|
OUT TCHAR *OutBuf,
|
|
IN UINT BufChars
|
|
);
|
|
|
|
|
|
BOOL
|
|
ConvertIniFile (
|
|
IN PCTSTR IniFilePath
|
|
);
|
|
|
|
|
|
BOOL
|
|
pIsDosFullPathPattern (
|
|
IN PCTSTR String
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pIsDosFullPathPattern checks if a string may be a valid DOS full path, i.e.
|
|
a drive letter folowed by a colon and a backslash.
|
|
|
|
Arguments:
|
|
|
|
String - Specifies the string to be tested
|
|
|
|
Return Value:
|
|
|
|
TRUE if the string may represent a valid full DOS path, FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
return String && *String && String[1] == TEXT(':') && String[2] == TEXT('\\');
|
|
}
|
|
|
|
|
|
BOOL
|
|
ConvertIniFiles (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ConvertIniFiles reads in the INI files not listed in IniFileMapping key, and converts every
|
|
full path file name to it's new value if it has been moved during instalation. Calls ConvertIniFile
|
|
for each INI file from Windows directory not listed in IniFileMapping.
|
|
|
|
This function is mainly for compatibility with older programs using INI files instead of registry
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if at least one error occured while processing.
|
|
The function will continue even if an error occures while processing a particular ini file
|
|
trying to get the job done as much as possible.
|
|
|
|
--*/
|
|
|
|
{
|
|
FILEOP_ENUM fe;
|
|
FILEOP_PROP_ENUM eOpProp;
|
|
MEMDB_ENUM e;
|
|
PCTSTR NtPath;
|
|
PCTSTR filePtr = NULL;
|
|
PCTSTR extPtr = NULL;
|
|
PCTSTR winDirWack = NULL;
|
|
BOOL result = TRUE;
|
|
|
|
winDirWack = JoinPaths (g_WinDir, TEXT(""));
|
|
|
|
if (EnumFirstPathInOperation (&fe, OPERATION_TEMP_PATH)) {
|
|
do {
|
|
|
|
filePtr = GetFileNameFromPath (fe.Path);
|
|
if (!filePtr) {
|
|
continue;
|
|
}
|
|
extPtr = GetFileExtensionFromPath (fe.Path);
|
|
if (!extPtr) {
|
|
continue;
|
|
}
|
|
if (StringIMatch (extPtr, TEXT("INI"))) {
|
|
|
|
// this is an INI file that was relocated. Let's process it.
|
|
|
|
if (EnumFirstFileOpProperty (&eOpProp, fe.Sequencer, OPERATION_TEMP_PATH)) {
|
|
|
|
// even if Result is false we keep trying to update the file
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "ConvertIniFile: %s (temp=%s)", fe.Path, eOpProp.Property));
|
|
//
|
|
// see comments at the beginning of MergeIniFile
|
|
//
|
|
if (DoesFileExist (eOpProp.Property)) {
|
|
if (!ConvertIniFile(eOpProp.Property)) {
|
|
result = FALSE;
|
|
}
|
|
} else {
|
|
if (EnumNextFileOpProperty (&eOpProp)) {
|
|
if (!ConvertIniFile(eOpProp.Property)) {
|
|
result = FALSE;
|
|
}
|
|
}
|
|
ELSE_DEBUGMSG ((
|
|
DBG_WHOOPS,
|
|
"ConvertIniFiles: Couldn't get final destination for %s",
|
|
fe.Path
|
|
));
|
|
}
|
|
}
|
|
}
|
|
} while (EnumNextPathInOperation (&fe));
|
|
}
|
|
|
|
FreePathString (winDirWack);
|
|
|
|
//
|
|
// also convert all INI files listed in MEMDB_CATEGORY_INIFILES_CONVERT
|
|
//
|
|
if (MemDbGetValueEx (&e, MEMDB_CATEGORY_INIFILES_CONVERT, NULL, NULL)) {
|
|
do {
|
|
|
|
NtPath = GetPathStringOnNt (e.szName);
|
|
|
|
DEBUGMSG ((DBG_INIFILES, "ConvertIniFile: Nt=%s (Win9x=%s)", NtPath, e.szName));
|
|
if (!ConvertIniFile (NtPath)) {
|
|
result = FALSE;
|
|
}
|
|
|
|
FreePathString (NtPath);
|
|
|
|
} while (MemDbEnumNextValue (&e));
|
|
}
|
|
|
|
|
|
if (!result) {
|
|
//
|
|
// we are going to log that at least one error occured while processing IniFileConversion
|
|
//
|
|
DEBUGMSG ((DBG_ERROR, (PCSTR)MSG_INI_FILE_CONVERSION_LOG));
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ConvertIniFile (
|
|
IN PCTSTR IniFilePath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ConvertIniFile reads in the INI file received and converts every full path file name
|
|
to it's new value if it has been moved during instalation.
|
|
It also applies all string substitutions specified in [String Map] section of wkstamig.inf
|
|
|
|
This function is called from ConvertIniFiles.
|
|
|
|
Arguments:
|
|
|
|
IniFilePath - Specifies INI file that is to be processed
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if at least one error occured while processing.
|
|
The function will continue even if an error occures while processing a particular ini file
|
|
trying to get the job done as much as possible.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTSTR Section = NULL;
|
|
PTSTR SectionBuf = NULL;
|
|
PTSTR SectionDest = NULL;
|
|
PTSTR Key = NULL;
|
|
PTSTR KeyBuf = NULL;
|
|
PTSTR KeyDest = NULL;
|
|
BOOL IniFileChanged = FALSE;
|
|
BOOL Result = TRUE;
|
|
DWORD status;
|
|
TCHAR InValueBuf[MEMDB_MAX];
|
|
TCHAR OutValueBuf[MEMDB_MAX];
|
|
TCHAR TempPath[MEMDB_MAX];
|
|
DWORD Attribs;
|
|
|
|
//
|
|
// we want to have ready two full paths:
|
|
// 1. full path to ini file that we are processing (Ex: c:\windows\setup\tmp00001)
|
|
// 2. full path to ini file temporary name while processing (system generated)
|
|
//
|
|
|
|
if (!DoesFileExist (IniFilePath)) {
|
|
DEBUGMSG ((DBG_INIFILES, "ConvertIniFile: %s not found", IniFilePath));
|
|
return TRUE;
|
|
}
|
|
|
|
if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, TempPath)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot create a temporary file"));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
|
|
//
|
|
// first of all we copy this INI file to be sure that GetPrivateProfileString function
|
|
// does not map our requests into registry
|
|
//
|
|
if (!CopyFile (IniFilePath, TempPath, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot copy %s to %s", IniFilePath, TempPath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
Attribs = GetFileAttributes (TempPath);
|
|
MYASSERT (Attribs != (DWORD)-1);
|
|
|
|
SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
//
|
|
// now trying to get section buffer from the INI file
|
|
// We will try to get section buffer in a 1024 bytes buffer. If this is not enough then
|
|
// we will increase buffer size with 1024 and so on.
|
|
//
|
|
if (!pLoadIniFileBuffer (IniFilePath, NULL, NULL, &SectionBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot load section buffer for %s", IniFilePath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// now we have all sections of the INI file and proceeding
|
|
//
|
|
Section = SectionBuf;
|
|
//
|
|
// there is a loop here for every section in the buffer
|
|
//
|
|
while (*Section) {
|
|
//
|
|
// section name can also contain paths
|
|
//
|
|
if (pIsDosFullPathPattern (Section)) {
|
|
status = GetFileStatusOnNt (Section);
|
|
} else {
|
|
status = FILESTATUS_UNCHANGED;
|
|
}
|
|
if (status & FILESTATUS_DELETED) {
|
|
//
|
|
// delete the whole section
|
|
//
|
|
if (!WritePrivateProfileString (Section, NULL, NULL, TempPath)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete section %s in %s", Section, IniFilePath));
|
|
Result = FALSE;
|
|
}
|
|
IniFileChanged = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// now trying to get key buffer for this section
|
|
//
|
|
KeyBuf = NULL;
|
|
if (!pLoadIniFileBuffer (IniFilePath, Section, NULL, &KeyBuf)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot load key buffer for %s in %s", Section, IniFilePath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// section name may contain paths
|
|
//
|
|
SectionDest = Section;
|
|
|
|
if (pProcessStrValue (Section, OutValueBuf, MEMDB_MAX)) {
|
|
//
|
|
// use this new section name
|
|
//
|
|
SectionDest = DuplicateText (OutValueBuf);
|
|
MYASSERT (SectionDest);
|
|
IniFileChanged = TRUE;
|
|
//
|
|
// delete the whole old section before continuing
|
|
//
|
|
if (!WritePrivateProfileString (Section, NULL, NULL, TempPath)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete section %s in %s", Section, IniFilePath));
|
|
Result = FALSE;
|
|
}
|
|
IniFileChanged = TRUE;
|
|
}
|
|
|
|
//
|
|
// now we have all keys from this section and proceeding
|
|
//
|
|
Key = KeyBuf;
|
|
//
|
|
// there is a loop here for every key in the section
|
|
//
|
|
while (*Key) {
|
|
//
|
|
// key name can also contain paths
|
|
//
|
|
if (pIsDosFullPathPattern (Key)) {
|
|
status = GetFileStatusOnNt (Key);
|
|
} else {
|
|
status = FILESTATUS_UNCHANGED;
|
|
}
|
|
if (status & FILESTATUS_DELETED) {
|
|
//
|
|
// delete the key
|
|
//
|
|
if (!WritePrivateProfileString (SectionDest, Key, NULL, TempPath)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete key %s in section %s in %s", Key, SectionDest, IniFilePath));
|
|
Result = FALSE;
|
|
}
|
|
IniFileChanged = TRUE;
|
|
|
|
} else {
|
|
|
|
KeyDest = Key;
|
|
|
|
if (pProcessStrValue (Key, OutValueBuf, MEMDB_MAX)) {
|
|
//
|
|
// use this new key name
|
|
//
|
|
KeyDest = DuplicateText (OutValueBuf);
|
|
MYASSERT (KeyDest);
|
|
IniFileChanged = TRUE;
|
|
//
|
|
// deleting the previous key
|
|
//
|
|
if (!WritePrivateProfileString (
|
|
SectionDest,
|
|
Key,
|
|
NULL,
|
|
TempPath
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete line %s in %s in %s", Key, SectionDest, IniFilePath));
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
|
|
GetPrivateProfileString(
|
|
Section,
|
|
Key,
|
|
TEXT(""),
|
|
InValueBuf,
|
|
MEMDB_MAX,
|
|
IniFilePath
|
|
);
|
|
|
|
//
|
|
// let's see if the key value is a deleted file.
|
|
// If so, we will simply delete the key.
|
|
//
|
|
if (pIsDosFullPathPattern (InValueBuf)) {
|
|
status = GetFileStatusOnNt (InValueBuf);
|
|
} else {
|
|
status = FILESTATUS_UNCHANGED;
|
|
}
|
|
if (status & FILESTATUS_DELETED) {
|
|
//
|
|
// deleting the old key
|
|
//
|
|
if (!WritePrivateProfileString (
|
|
SectionDest,
|
|
KeyDest,
|
|
NULL,
|
|
TempPath
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete line %s in %s in %s", KeyDest, SectionDest, IniFilePath));
|
|
Result = FALSE;
|
|
}
|
|
IniFileChanged = TRUE;
|
|
} else {
|
|
//
|
|
// now we are going to make a lexical analysis of this value string
|
|
// to see if there are some candidates (e.g. full path file names)
|
|
// To find out if there is a full file name we will just see if the second
|
|
// and the third characters are : respectively \
|
|
//
|
|
if (pProcessStrValue (InValueBuf, OutValueBuf, MEMDB_MAX) ||
|
|
KeyDest != Key ||
|
|
SectionDest != Section
|
|
) {
|
|
//
|
|
// writing the new value
|
|
//
|
|
if (!WritePrivateProfileString (
|
|
SectionDest,
|
|
KeyDest,
|
|
OutValueBuf,
|
|
TempPath
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot write line %s=%s in %s in %s", KeyDest, OutValueBuf, SectionDest, IniFilePath));
|
|
Result = FALSE;
|
|
}
|
|
IniFileChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
if (KeyDest != Key) {
|
|
FreeText (KeyDest);
|
|
KeyDest = NULL;
|
|
}
|
|
}
|
|
|
|
Key = GetEndOfString (Key) + 1;
|
|
KeyDest = NULL;
|
|
}
|
|
|
|
if (SectionDest != Section) {
|
|
FreeText (SectionDest);
|
|
SectionDest = NULL;
|
|
}
|
|
if (KeyBuf) {
|
|
MemFree (g_hHeap, 0, KeyBuf);
|
|
KeyBuf = NULL;
|
|
}
|
|
}
|
|
|
|
Section = GetEndOfString (Section) + 1;
|
|
SectionDest = NULL;
|
|
}
|
|
|
|
if (SectionBuf) {
|
|
MemFree (g_hHeap, 0, SectionBuf);
|
|
SectionBuf = NULL;
|
|
}
|
|
|
|
//
|
|
// finally, if we made any changes then we will copy the INI file back
|
|
//
|
|
if (IniFileChanged) {
|
|
//
|
|
// flushing the INI file
|
|
//
|
|
WritePrivateProfileString (NULL, NULL, NULL, TempPath);
|
|
|
|
SetFileAttributes (TempPath, Attribs);
|
|
SetFileAttributes (IniFilePath, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
if (!CopyFile (TempPath, IniFilePath, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot copy %s to %s", TempPath, IniFilePath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (TempPath);
|
|
|
|
if (KeyDest && KeyDest != Key) {
|
|
FreeText (KeyDest);
|
|
KeyDest = NULL;
|
|
}
|
|
|
|
if (SectionDest && SectionDest != Section) {
|
|
FreeText (SectionDest);
|
|
SectionDest = NULL;
|
|
}
|
|
|
|
if (KeyBuf) {
|
|
MemFree (g_hHeap, 0, KeyBuf);
|
|
KeyBuf = NULL;
|
|
}
|
|
|
|
if (SectionBuf) {
|
|
MemFree (g_hHeap, 0, SectionBuf);
|
|
SectionBuf = NULL;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pLookupStrValue (
|
|
IN PCTSTR Value,
|
|
OUT PTSTR OutBuffer,
|
|
OUT PINT OutBytes,
|
|
IN UINT OutBufferSize
|
|
)
|
|
{
|
|
if (MappingSearchAndReplaceEx (
|
|
g_CompleteMatchMap,
|
|
Value,
|
|
OutBuffer,
|
|
0,
|
|
OutBytes,
|
|
OutBufferSize,
|
|
STRMAP_COMPLETE_MATCH_ONLY,
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return MappingSearchAndReplaceEx (
|
|
g_SubStringMap,
|
|
Value,
|
|
OutBuffer,
|
|
0,
|
|
OutBytes,
|
|
OutBufferSize,
|
|
STRMAP_ANY_MATCH,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pProcessStrValue (
|
|
IN TCHAR *InBuf,
|
|
OUT TCHAR *OutBuf,
|
|
IN UINT BufChars
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Simple lex that identifies lexems separated by comma, space, tab and quote.
|
|
For each lexem calls a function that can change the value of the lexem.
|
|
OBS: When between quote's comma,space and tab are not considered separators
|
|
|
|
This function is called from ConvertIniFile.
|
|
|
|
Arguments:
|
|
|
|
InBuf - Specifies buffer to be processed
|
|
OutBuf - Specifies buffer to hold the result
|
|
BufChars - Specifies the size of OutBuf in chars
|
|
|
|
Return Value:
|
|
|
|
TRUE if there was any change.
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR OrgLexem[MEMDB_MAX];
|
|
TCHAR *Lexem;
|
|
|
|
// Status = 0 - initial state
|
|
// Status = 1 - processing a string between quotes
|
|
// Status = 2 - processing a normal string
|
|
INT Status;
|
|
|
|
BOOL Result = FALSE;
|
|
|
|
//
|
|
// first check to see if the whole string should be replaced;
|
|
// some paths contain spaces, even if they are not between quotes
|
|
//
|
|
Lexem = OutBuf;
|
|
if (pAddValue (&Lexem, InBuf, BufChars)) {
|
|
*Lexem = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
Lexem = OrgLexem;
|
|
|
|
Status = 0;
|
|
for (;;) {
|
|
*Lexem = 0;
|
|
*OutBuf = 0;
|
|
switch (*InBuf) {
|
|
case 0:
|
|
|
|
Result |= pAddValue(&OutBuf, OrgLexem, MEMDB_MAX);
|
|
*OutBuf = 0;
|
|
return Result;
|
|
|
|
case quote:
|
|
|
|
if (Status == 0) {
|
|
Status = 1;
|
|
*OutBuf = *InBuf;
|
|
InBuf++;
|
|
OutBuf++;
|
|
break;
|
|
}
|
|
|
|
Result |= pAddValue(&OutBuf, OrgLexem, MEMDB_MAX);
|
|
Lexem = OrgLexem;
|
|
if (Status == 1) {
|
|
*OutBuf = *InBuf;
|
|
InBuf++;
|
|
OutBuf++;
|
|
}
|
|
Status = 0;
|
|
break;
|
|
|
|
case space:
|
|
case comma:
|
|
case tab:
|
|
|
|
if (Status == 1) {
|
|
*Lexem = *InBuf;
|
|
Lexem++;
|
|
InBuf++;
|
|
break;
|
|
};
|
|
|
|
if (Status == 0) {
|
|
*OutBuf = *InBuf;
|
|
InBuf++;
|
|
OutBuf++;
|
|
break;
|
|
};
|
|
|
|
Result |= pAddValue(&OutBuf, OrgLexem, MEMDB_MAX);
|
|
Lexem = OrgLexem;
|
|
*OutBuf = *InBuf;
|
|
InBuf++;
|
|
OutBuf++;
|
|
Status = 0;
|
|
break;
|
|
|
|
default:
|
|
if (Status ==0) {
|
|
Status = 2;
|
|
};
|
|
|
|
*Lexem = *InBuf;
|
|
Lexem++;
|
|
InBuf++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pAddValue(
|
|
IN OUT TCHAR **Buffer,
|
|
IN OUT TCHAR *Value,
|
|
IN UINT BufChars
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Simple routine that takes a string value, modifies it (or not) and that adds it
|
|
to a buffer.
|
|
|
|
This function is called from pProcessStrValue
|
|
|
|
Arguments:
|
|
|
|
Buffer - Specifies buffer to hold the value
|
|
Value - Specifies the string value to be processed
|
|
|
|
Return Value:
|
|
|
|
TRUE if there was any change.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD fileStatus;
|
|
PTSTR newValue, Source;
|
|
INT OutBytes;
|
|
|
|
BOOL Result = FALSE;
|
|
|
|
//
|
|
// replaced (Value[0]) && (!_tcsncmp (Value + 1, TEXT(":\\"), 2)) with the call below
|
|
// for consistency
|
|
//
|
|
if (pIsDosFullPathPattern (Value)) {
|
|
fileStatus = GetFileStatusOnNt (Value);
|
|
if ((fileStatus & FILESTATUS_MOVED) == FILESTATUS_MOVED) {
|
|
Result = TRUE;
|
|
newValue = GetPathStringOnNt (Value);
|
|
//
|
|
// advance outbound pointer
|
|
//
|
|
Source = newValue;
|
|
while (*Source) {
|
|
**Buffer = *Source;
|
|
(*Buffer)++;
|
|
Source++;
|
|
}
|
|
FreePathString (newValue);
|
|
}
|
|
}
|
|
|
|
if (!Result) {
|
|
//
|
|
// try to map this sub-string
|
|
//
|
|
if (pLookupStrValue (
|
|
Value,
|
|
*Buffer,
|
|
&OutBytes,
|
|
BufChars * sizeof (TCHAR)
|
|
)) {
|
|
Result = TRUE;
|
|
MYASSERT (OutBytes % sizeof (TCHAR) == 0);
|
|
*Buffer += OutBytes / sizeof (TCHAR);
|
|
}
|
|
}
|
|
|
|
if (!Result) {
|
|
while (*Value) {
|
|
**Buffer = *Value;
|
|
(*Buffer)++;
|
|
Value++;
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pMoveIniSettingsBySection (
|
|
IN PCWSTR Section
|
|
)
|
|
{
|
|
INFCONTEXT context;
|
|
WCHAR srcData [MEMDB_MAX];
|
|
WCHAR destData [MEMDB_MAX];
|
|
WCHAR destValue[MEMDB_MAX];
|
|
WCHAR tempPathS[MEMDB_MAX];
|
|
WCHAR tempPathD[MEMDB_MAX];
|
|
INT adnlData = 0;
|
|
LONG value;
|
|
PWSTR valuePtr;
|
|
PCWSTR srcFile;
|
|
PCWSTR srcSect;
|
|
PCWSTR srcKey;
|
|
PCWSTR destFile;
|
|
PCWSTR destSect;
|
|
PCWSTR destKey;
|
|
PWSTR tempPtr;
|
|
PCWSTR srcFullPath = NULL;
|
|
PCWSTR destFullPath = NULL;
|
|
PCWSTR newPath = NULL;
|
|
PTSTR sect, sectionBuf;
|
|
PTSTR key, keyBuf;
|
|
PCWSTR destSectFull;
|
|
PCWSTR destKeyFull;
|
|
BOOL iniFileChanged;
|
|
DWORD result;
|
|
|
|
if (SetupFindFirstLine (g_WkstaMigInf, Section, NULL, &context)) {
|
|
do {
|
|
if ((SetupGetStringField (&context, 0, srcData, MEMDB_MAX, NULL)) &&
|
|
(SetupGetStringField (&context, 1, destData, MEMDB_MAX, NULL))
|
|
) {
|
|
//
|
|
// We now have a line like : <src INI file>\<src section>\<src key> = <dest INI file>\<dest section>\<dest key>
|
|
//
|
|
__try {
|
|
*tempPathS = 0;
|
|
*tempPathD = 0;
|
|
|
|
iniFileChanged = FALSE;
|
|
|
|
srcFile = srcData;
|
|
|
|
tempPtr = wcschr (srcData, L'\\');
|
|
if (!tempPtr) {
|
|
__leave;
|
|
}
|
|
srcSect = tempPtr + 1;
|
|
*tempPtr = 0;
|
|
|
|
tempPtr = wcschr (srcSect, L'\\');
|
|
if (!tempPtr) {
|
|
__leave;
|
|
}
|
|
srcKey = tempPtr + 1;
|
|
*tempPtr = 0;
|
|
|
|
destFile = destData;
|
|
|
|
tempPtr = wcschr (destData, L'\\');
|
|
if (!tempPtr) {
|
|
__leave;
|
|
}
|
|
destSect = tempPtr + 1;
|
|
*tempPtr = 0;
|
|
|
|
tempPtr = wcschr (destSect, L'\\');
|
|
if (!tempPtr) {
|
|
__leave;
|
|
}
|
|
destKey = tempPtr + 1;
|
|
*tempPtr = 0;
|
|
|
|
srcFullPath = JoinPaths (g_WinDir, srcFile);
|
|
|
|
newPath = GetTemporaryLocationForFile (srcFullPath);
|
|
if (newPath) {
|
|
DEBUGMSG ((DBG_MOVEINISETTINGS, "Using %s for %s", newPath, srcFullPath));
|
|
FreePathString (srcFullPath);
|
|
srcFullPath = newPath;
|
|
}
|
|
|
|
if (!DoesFileExist (srcFullPath)) {
|
|
DEBUGMSG ((DBG_INIFILES, "pMoveIniSettingsBySection: %s not found", srcFullPath));
|
|
__leave;
|
|
}
|
|
|
|
destFullPath = JoinPaths (g_WinDir, destFile);
|
|
|
|
newPath = GetTemporaryLocationForFile (destFullPath);
|
|
if (newPath) {
|
|
DEBUGMSG ((DBG_MOVEINISETTINGS, "pMoveIniSettingsBySection: Using %s for %s", newPath, destFullPath));
|
|
FreePathString (destFullPath);
|
|
destFullPath = newPath;
|
|
}
|
|
|
|
// Copy Source File to a temporary location to avoid registry mapping
|
|
if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, tempPathS)) {
|
|
DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot create a temporary file"));
|
|
__leave;
|
|
}
|
|
if (!CopyFile (srcFullPath, tempPathS, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot copy %s to %s", srcFullPath, tempPathS));
|
|
__leave;
|
|
}
|
|
|
|
// Copy Destination File to a temporary location to avoid registry mapping
|
|
if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, tempPathD)) {
|
|
DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot create a temporary file"));
|
|
__leave;
|
|
}
|
|
if (!CopyFile (destFullPath, tempPathD, FALSE)) {
|
|
DEBUGMSG ((DBG_INIFILES,"pMoveIniSettingsBySection: Cannot copy %s to %s", destFullPath, tempPathD));
|
|
}
|
|
|
|
// if we have an additional field we use it for dividing the key values (if they are numbers)
|
|
if (!SetupGetIntField (&context, 3, &adnlData)) {
|
|
adnlData = 0;
|
|
}
|
|
//
|
|
// Next thing we are going to do is to load the sections in a buffer
|
|
//
|
|
|
|
if (!pLoadIniFileBuffer (tempPathS, NULL, NULL, §ionBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot load section buffer for %s (%s)", tempPathS, srcFullPath));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// now walk through each section
|
|
//
|
|
__try {
|
|
sect = sectionBuf;
|
|
|
|
//
|
|
// there is a loop here for every section in the buffer
|
|
//
|
|
while (*sect) {
|
|
if (IsPatternMatch (srcSect, sect)) {
|
|
|
|
//
|
|
// Next thing we are going to do is to load the keys in a buffer
|
|
//
|
|
|
|
if (!pLoadIniFileBuffer (tempPathS, sect, NULL, &keyBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot load key buffer for %s in %s (%s)", sect, tempPathS, srcFullPath));
|
|
__leave;
|
|
}
|
|
|
|
__try {
|
|
//
|
|
// now we have all keys of the section and proceeding
|
|
//
|
|
|
|
key = keyBuf;
|
|
|
|
//
|
|
// there is a loop here for every key in the buffer
|
|
//
|
|
while (*key) {
|
|
|
|
if (IsPatternMatch (srcKey, key)) {
|
|
|
|
result = GetPrivateProfileString (
|
|
sect,
|
|
key,
|
|
TEXT(""),
|
|
destValue,
|
|
MEMDB_MAX,
|
|
tempPathS);
|
|
if ((result == 0) ||
|
|
(result + 1 == MEMDB_MAX)
|
|
) {
|
|
DEBUGMSG ((
|
|
DBG_MOVEINISETTINGS,
|
|
"pMoveIniSettingsBySection: Cannot read value for %s in %s in %s (%s)",
|
|
key,
|
|
sect,
|
|
tempPathS,
|
|
srcFullPath
|
|
));
|
|
} else {
|
|
if (adnlData) {
|
|
value = wcstol (destValue, &valuePtr, 10);
|
|
if (*valuePtr == 0) {
|
|
value = value / adnlData;
|
|
wsprintf (destValue, L"%d", value);
|
|
}
|
|
}
|
|
|
|
destSectFull = StringSearchAndReplace (destSect, L"*", sect);
|
|
if (!destSectFull) {
|
|
destSectFull = DuplicatePathString (destSect,0);
|
|
}
|
|
destKeyFull = StringSearchAndReplace (destKey, L"*", key);
|
|
if (!destKeyFull) {
|
|
destKeyFull = DuplicatePathString (destKey,0);
|
|
}
|
|
|
|
iniFileChanged = TRUE;
|
|
|
|
// writing the new value
|
|
if (!WritePrivateProfileString (
|
|
destSectFull,
|
|
destKeyFull,
|
|
destValue,
|
|
tempPathD
|
|
)) {
|
|
DEBUGMSG ((
|
|
DBG_ERROR,
|
|
"Ini File Move : Cannot write line %s=%s in %s in %s (%s)",
|
|
destKeyFull,
|
|
destValue,
|
|
destSectFull,
|
|
tempPathD,
|
|
destFullPath
|
|
));
|
|
FreePathString (destSectFull);
|
|
FreePathString (destKeyFull);
|
|
__leave;
|
|
}
|
|
FreePathString (destSectFull);
|
|
FreePathString (destKeyFull);
|
|
}
|
|
}
|
|
|
|
key = GetEndOfString (key) + 1;
|
|
}
|
|
}
|
|
__finally {
|
|
if (keyBuf) {
|
|
MemFree (g_hHeap, 0 , keyBuf);
|
|
}
|
|
}
|
|
}
|
|
sect = GetEndOfString (sect) + 1;
|
|
}
|
|
}
|
|
__finally {
|
|
if (sectionBuf) {
|
|
MemFree (g_hHeap, 0 , sectionBuf);
|
|
}
|
|
}
|
|
if (iniFileChanged) {
|
|
// flushing the INI file
|
|
WritePrivateProfileString (
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
tempPathD
|
|
);
|
|
|
|
if (!CopyFile (tempPathD, destFullPath, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"Ini File Move : Cannot copy %s to %s", tempPathD, destFullPath));
|
|
__leave;
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
if (srcFullPath) {
|
|
FreePathString (srcFullPath);
|
|
srcFullPath = NULL;
|
|
}
|
|
|
|
if (destFullPath) {
|
|
FreePathString (destFullPath);
|
|
destFullPath = NULL;
|
|
}
|
|
|
|
if (*tempPathS) {
|
|
SetFileAttributes (tempPathS, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (tempPathS);
|
|
}
|
|
if (*tempPathD) {
|
|
SetFileAttributes (tempPathD, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (tempPathD);
|
|
}
|
|
}
|
|
}
|
|
} while (SetupFindNextLine (&context, &context));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MoveIniSettings (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
There are a number of settings that needs to be moved from one INI file to another during setup.
|
|
There is a section called "MoveIniSettings" in wkstamig.inf that lists those settings.
|
|
The format is <INI file (in %WinDir%)>\section\key = <INI file (in %winDir%)>\section\key
|
|
You can use pattern matching is section and key (INI file must be specified in full).
|
|
The only wild character supported in right term is * and is going to be replaced by the equivalent
|
|
left term. For example if you specify:
|
|
foo.ini\FooSect\FooKey = bar.ini\*\*
|
|
then the FooKey key from FooSect section from foo.ini is going to be moved to bar.ini. This is useful
|
|
to move a whole section :
|
|
foo.ini\FooSect\* = bar.ini\*\*
|
|
|
|
We are going to use Get/WritePrivateProfileString because we want that all the settings to be mapped
|
|
into the registry is it's the case (this routine is called after IniFileMapping routine).
|
|
|
|
This routine is called before IniFileConversion routine so the moved settings are Win95 ones.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
FALSE if any error occured.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR codePageStr [20] = L"";
|
|
PWSTR codePageSection = NULL;
|
|
|
|
MYASSERT (g_WkstaMigInf != INVALID_HANDLE_VALUE);
|
|
|
|
pMoveIniSettingsBySection (S_MOVEINISETTINGS);
|
|
|
|
_itow (OurGetACP (), codePageStr, 10);
|
|
|
|
codePageSection = JoinTextEx (NULL, S_MOVEINISETTINGS, codePageStr, L".", 0, NULL);
|
|
|
|
pMoveIniSettingsBySection (codePageSection);
|
|
|
|
FreeText (codePageSection);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MergeIniSettings (
|
|
VOID
|
|
)
|
|
{
|
|
FILEOP_ENUM fe;
|
|
FILEOP_PROP_ENUM eOpProp;
|
|
PCTSTR filePtr;
|
|
PCTSTR extPtr;
|
|
PCTSTR winDirWack;
|
|
PCTSTR NtPath;
|
|
BOOL Win9xPriority;
|
|
BOOL result = TRUE;
|
|
|
|
//
|
|
// Process INI files that were moved to temporary dir
|
|
//
|
|
|
|
winDirWack = JoinPaths (g_WinDir, TEXT(""));
|
|
|
|
if (EnumFirstPathInOperation (&fe, OPERATION_TEMP_PATH)) {
|
|
do {
|
|
|
|
if (!pBuildSuppressionTable(FALSE)) {
|
|
result = FALSE;
|
|
}
|
|
|
|
// Special case : SHELL= line from SYSTEM.INI
|
|
// We try to see if the current shell is supported on NT.
|
|
// If not then we will add SHELL to this suppression table
|
|
// ensuring that the NT registry setting will get mapped into
|
|
// the INI file
|
|
if (pIncompatibleShell()) {
|
|
MemDbSetValueEx (
|
|
MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
|
|
TEXT("SYSTEM.INI"),
|
|
TEXT("BOOT"),
|
|
TEXT("SHELL"),
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
filePtr = GetFileNameFromPath (fe.Path);
|
|
if (!filePtr) {
|
|
continue;
|
|
}
|
|
extPtr = GetFileExtensionFromPath (fe.Path);
|
|
if (!extPtr) {
|
|
continue;
|
|
}
|
|
if (StringIMatch (extPtr, TEXT("INI"))) {
|
|
|
|
// this is an INI file that was relocated. Let's process it.
|
|
|
|
if (EnumFirstFileOpProperty (&eOpProp, fe.Sequencer, OPERATION_TEMP_PATH)) {
|
|
|
|
if (StringIMatch (filePtr, TEXT("desktop.ini"))) {
|
|
Win9xPriority = FALSE;
|
|
} else {
|
|
Win9xPriority = !StringIMatchAB (winDirWack, fe.Path, filePtr);
|
|
}
|
|
|
|
NtPath = GetPathStringOnNt (fe.Path);
|
|
|
|
if (!MergeIniFile(NtPath, eOpProp.Property, Win9xPriority)) {
|
|
result = FALSE;
|
|
}
|
|
|
|
FreePathString (NtPath);
|
|
}
|
|
}
|
|
} while (EnumNextPathInOperation (&fe));
|
|
|
|
pFreeSuppressionTable();
|
|
|
|
}
|
|
|
|
FreePathString (winDirWack);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PTSTR
|
|
pMapIniSectionKeyToRegistryKey (
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR Section,
|
|
IN PCTSTR Key
|
|
)
|
|
{
|
|
CHARTYPE ch;
|
|
TCHAR RegKey[MAX_REGISTRY_KEY] = S_EMPTY;
|
|
DWORD rc;
|
|
HKEY key, sectKey;
|
|
PTSTR keyStr;
|
|
PTSTR regPath;
|
|
PTSTR data = NULL;
|
|
PTSTR p;
|
|
|
|
keyStr = JoinPaths (S_INIFILEMAPPING_KEY, FileName);
|
|
|
|
__try {
|
|
|
|
key = OpenRegKeyStr (keyStr);
|
|
if (!key) {
|
|
__leave;
|
|
}
|
|
|
|
sectKey = OpenRegKey (key, Section);
|
|
|
|
if (sectKey) {
|
|
data = GetRegValueString (sectKey, Key);
|
|
if (!data) {
|
|
data = GetRegValueString (sectKey, S_EMPTY);
|
|
}
|
|
CloseRegKey (sectKey);
|
|
} else {
|
|
data = GetRegValueString (key, Section);
|
|
if (!data) {
|
|
data = GetRegValueString (key, S_EMPTY);
|
|
}
|
|
}
|
|
|
|
if (data) {
|
|
//
|
|
// convert it to a reg key string
|
|
//
|
|
regPath = data;
|
|
|
|
//
|
|
// Skip past special chars
|
|
//
|
|
while (TRUE) {
|
|
ch = (CHARTYPE)_tcsnextc (regPath);
|
|
if (ch == TEXT('!') ||
|
|
ch == TEXT('#') ||
|
|
ch == TEXT('@')
|
|
) {
|
|
regPath = _tcsinc (regPath);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If SYS:, USR: or \Registry\Machine\ then replace appropriately
|
|
//
|
|
if (pDoesStrHavePrefix (®Path, TEXT("SYS:"))) {
|
|
p = TEXT("HKLM\\SOFTWARE");
|
|
} else if (pDoesStrHavePrefix (®Path, TEXT("USR:"))) {
|
|
p = TEXT("HKR");
|
|
} else if (pDoesStrHavePrefix (®Path, TEXT("\\Registry\\Machine\\"))) {
|
|
p = TEXT("HKLM");
|
|
}
|
|
|
|
_sntprintf (RegKey, MAX_REGISTRY_KEY, TEXT("%s\\%s"), p, regPath);
|
|
}
|
|
}
|
|
__finally {
|
|
if (key) {
|
|
CloseRegKey (key);
|
|
}
|
|
if (data) {
|
|
MemFree (g_hHeap, 0, data);
|
|
}
|
|
FreePathString (keyStr);
|
|
keyStr = NULL;
|
|
}
|
|
|
|
if (RegKey[0]) {
|
|
keyStr = DuplicateText (RegKey);
|
|
}
|
|
|
|
return keyStr;
|
|
}
|
|
|
|
BOOL
|
|
MergeIniFile (
|
|
IN PCTSTR FileNtLocation,
|
|
IN PCTSTR FileTempLocation,
|
|
IN BOOL TempHasPriority
|
|
)
|
|
{
|
|
TCHAR TempPath[MEMDB_MAX];
|
|
TCHAR srcValue[MEMDB_MAX];
|
|
TCHAR destValue[MEMDB_MAX];
|
|
DWORD Attribs = -1;
|
|
|
|
PTSTR Section, SectionBuf;
|
|
PTSTR Key, KeyBuf;
|
|
|
|
BOOL Result = TRUE;
|
|
BOOL IniFileChanged = FALSE;
|
|
PTSTR regKey;
|
|
PTSTR p;
|
|
PCTSTR fileName;
|
|
|
|
//
|
|
// sometimes, textmode setup doesn't move files from other drives to Windows drive,
|
|
// probably because textmode setup drive mapping doesn't match Win9x drive mappings.
|
|
// It's possible that the INI file hasn't actually been moved, so in this case there
|
|
// is nothing to do
|
|
// There is no data loss, since the file is actually not moved and it's converted
|
|
// in place in ConvertIniFiles
|
|
//
|
|
if (*g_WinDir != *FileNtLocation &&
|
|
!DoesFileExist (FileTempLocation) &&
|
|
DoesFileExist (FileNtLocation)
|
|
) {
|
|
//
|
|
// done, file is already in place
|
|
//
|
|
return TRUE;
|
|
}
|
|
//
|
|
// some desktop.ini are located in temp internet dirs that were removed
|
|
// when Win9x was shutting down; ignore these files
|
|
//
|
|
if (!DoesFileExist (FileTempLocation)) {
|
|
if (!StringIMatch (GetFileNameFromPath (FileNtLocation), TEXT("desktop.ini"))) {
|
|
DEBUGMSG ((DBG_ERROR, "MergeIniFile: File does not exist: %s (Nt=%s)", FileTempLocation, FileNtLocation));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
if (!DoesFileExist (FileNtLocation)) {
|
|
//
|
|
// just copy back to the original file
|
|
// if the file belongs to a directory that NT doesn't install,
|
|
// create it now
|
|
//
|
|
|
|
StackStringCopy (TempPath, FileNtLocation);
|
|
p = _tcsrchr (TempPath, TEXT('\\'));
|
|
if (p) {
|
|
*p = 0;
|
|
|
|
if (GetFileAttributes (TempPath) == (DWORD)-1) {
|
|
MakeSurePathExists (TempPath, TRUE);
|
|
}
|
|
}
|
|
|
|
if (!CopyFile (FileTempLocation, FileNtLocation, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"MergeIniFile: Cannot copy %s to %s", FileTempLocation, FileNtLocation));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, TempPath)) {
|
|
DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot create a temporary file"));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
|
|
//
|
|
// first of all we copy this INI file to be sure that GetPrivateProfileString function
|
|
// does not map our requests into registry
|
|
//
|
|
if (!CopyFile (FileTempLocation, TempPath, FALSE)) {
|
|
DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot copy %s to %s", FileTempLocation, TempPath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
Attribs = GetFileAttributes (FileNtLocation);
|
|
SetFileAttributes (FileNtLocation, FILE_ATTRIBUTE_NORMAL);
|
|
MYASSERT (Attribs != (DWORD)-1);
|
|
|
|
//
|
|
// now trying to get section buffer from the INI file
|
|
// We will try to get section buffer in a 1024 bytes buffer. If this is not enough then
|
|
// we will increase buffer size with 1024 and so on.
|
|
//
|
|
|
|
if (!pLoadIniFileBuffer (TempPath, NULL, NULL, &SectionBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot load section buffer for %s",TempPath));
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
fileName = GetFileNameFromPath (FileNtLocation);
|
|
if (!fileName) {
|
|
Result = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
__try {
|
|
|
|
//
|
|
// now we have all sections of the INI file and proceeding
|
|
//
|
|
|
|
Section = SectionBuf;
|
|
|
|
//
|
|
// there is a loop here for every section in the buffer
|
|
//
|
|
while (*Section) {
|
|
|
|
//
|
|
// now trying to get key buffer for this section
|
|
//
|
|
|
|
if (!pLoadIniFileBuffer (TempPath, Section, NULL, &KeyBuf)) {
|
|
|
|
DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot load key buffer for %s in %s", Section, TempPath));
|
|
Result = FALSE;
|
|
continue;
|
|
}
|
|
|
|
__try {
|
|
|
|
//
|
|
// now we have all keys from this section and proceeding
|
|
//
|
|
Key = KeyBuf;
|
|
|
|
//
|
|
// there is a loop here for every key in the section
|
|
//
|
|
while (*Key) {
|
|
BOOL unused;
|
|
|
|
//
|
|
// build the corresponding registry key
|
|
//
|
|
regKey = pMapIniSectionKeyToRegistryKey (fileName, Section, Key);
|
|
|
|
if (pShouldSaveKey (fileName, Section, Key, regKey, &unused, FALSE, TRUE)) {
|
|
|
|
GetPrivateProfileString(
|
|
Section,
|
|
Key,
|
|
TEXT(""),
|
|
srcValue,
|
|
MEMDB_MAX,
|
|
TempPath
|
|
);
|
|
|
|
GetPrivateProfileString(
|
|
Section,
|
|
Key,
|
|
TEXT(""),
|
|
destValue,
|
|
MEMDB_MAX,
|
|
FileNtLocation
|
|
);
|
|
|
|
if (*srcValue && !*destValue ||
|
|
TempHasPriority && !StringMatch (srcValue, destValue)) {
|
|
|
|
IniFileChanged = TRUE;
|
|
|
|
// writing the new value
|
|
if (!WritePrivateProfileString (
|
|
Section,
|
|
Key,
|
|
srcValue,
|
|
FileNtLocation
|
|
)) {
|
|
DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot write line %s=%s in %s in %s", Key, srcValue, Section, FileNtLocation));
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
ELSE_DEBUGMSG ((
|
|
DBG_VERBOSE,
|
|
"Merge Ini File : Suppressing key %s in section %s of %s",
|
|
Key,
|
|
Section,
|
|
FileNtLocation
|
|
));
|
|
|
|
FreeText (regKey);
|
|
|
|
Key = GetEndOfString (Key) + 1;
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
if (KeyBuf) {
|
|
MemFree (g_hHeap, 0, KeyBuf);
|
|
}
|
|
}
|
|
|
|
Section = GetEndOfString (Section) + 1;
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
if (SectionBuf) {
|
|
MemFree (g_hHeap, 0, SectionBuf);
|
|
}
|
|
}
|
|
|
|
//
|
|
// finally, if we made any changes then we will copy the INI file back
|
|
//
|
|
if (IniFileChanged) {
|
|
|
|
// flushing the INI file
|
|
WritePrivateProfileString (
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
FileNtLocation
|
|
);
|
|
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
if (Attribs != (DWORD)-1) {
|
|
SetFileAttributes (FileNtLocation, Attribs);
|
|
}
|
|
|
|
SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (TempPath);
|
|
}
|
|
|
|
return Result;
|
|
}
|