572 lines
14 KiB
C
572 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
commonnt.c
|
|
|
|
Abstract:
|
|
|
|
Common functionality between various parts of GUI mode-side processing.
|
|
The routines in this library are shared only by other LIBs in the
|
|
w95upgnt tree.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 18-Aug-1998
|
|
|
|
Revision History:
|
|
|
|
Name (alias) Date Description
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#define DBG_DATAFILTER "Data Filter"
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CommonNt_Entry (
|
|
IN HINSTANCE Instance,
|
|
IN DWORD Reason,
|
|
IN PVOID lpv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
CommonNt_Entry is a DllMain-like init funciton, called by w95upgnt\dll.
|
|
This function is called at process attach and detach.
|
|
|
|
Arguments:
|
|
|
|
Instance - (OS-supplied) instance handle for the DLL
|
|
Reason - (OS-supplied) indicates attach or detatch from process or
|
|
thread
|
|
lpv - unused
|
|
|
|
Return Value:
|
|
|
|
Return value is always TRUE (indicating successful init).
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Reason) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
// Nothing to do...
|
|
break;
|
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
// Nothing to do...
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
typedef enum {
|
|
STATE_NO_PATH,
|
|
STATE_PATH_FOUND,
|
|
STATE_IN_PATH,
|
|
STATE_PATH_CHANGED,
|
|
STATE_PATH_DELETED,
|
|
STATE_LONG_PATH_CHANGED,
|
|
STATE_SHORT_PATH_CHANGED,
|
|
STATE_RETURN_PATH
|
|
} SCANSTATE;
|
|
|
|
BOOL
|
|
pIsPathSeparator (
|
|
CHARTYPE ch
|
|
)
|
|
{
|
|
return ch == 0 ||
|
|
ch == TEXT(',') ||
|
|
ch == TEXT(';') ||
|
|
_istspace (ch) != 0;
|
|
}
|
|
|
|
BOOL
|
|
pIsValidPathCharacter (
|
|
CHARTYPE ch
|
|
)
|
|
{
|
|
if (_istalnum (ch)) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (ch == TEXT(',') ||
|
|
ch == TEXT(';') ||
|
|
ch == TEXT('\"') ||
|
|
ch == TEXT('<') ||
|
|
ch == TEXT('>') ||
|
|
ch == TEXT('|') ||
|
|
ch == TEXT('?') ||
|
|
ch == TEXT('*')
|
|
) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CONVERTPATH_RC
|
|
pGetReplacementPath (
|
|
IN PCTSTR DataStart,
|
|
IN PCTSTR Pos,
|
|
OUT PCTSTR *OldStart,
|
|
OUT PCTSTR *OldEnd,
|
|
OUT PTSTR ReplacementStr
|
|
)
|
|
{
|
|
CONVERTPATH_RC rc = CONVERTPATH_NOT_REMAPPED;
|
|
SCANSTATE State;
|
|
BOOL DontIncrement;
|
|
PCTSTR OrgStart = NULL;
|
|
TCHAR PathBuffer[MAX_TCHAR_PATH + 2];
|
|
TCHAR RenamedFile[MAX_TCHAR_PATH];
|
|
PTSTR PathBufferRoot = NULL;
|
|
PTSTR PathBufferPtr = NULL;
|
|
CONVERTPATH_RC ConvertCode = 0;
|
|
BOOL ShortPath = FALSE;
|
|
BOOL QuotesOn = FALSE;
|
|
BOOL Done = FALSE;
|
|
BOOL OrgPathHasSepChar = FALSE;
|
|
BOOL NeedQuotes = FALSE;
|
|
BOOL PathSepChar;
|
|
PCTSTR p;
|
|
BOOL QuotesOnColumn = FALSE;
|
|
PCTSTR LastPathPosition = NULL;
|
|
|
|
State = STATE_NO_PATH;
|
|
PathBuffer[0] = TEXT('\"');
|
|
|
|
//
|
|
// Scan string of Pos for command line
|
|
//
|
|
|
|
while (!Done) {
|
|
|
|
DontIncrement = FALSE;
|
|
|
|
switch (State) {
|
|
|
|
case STATE_NO_PATH:
|
|
if (Pos[0] == 0) {
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (Pos[1] == TEXT(':') && Pos[2] == TEXT('\\')) {
|
|
|
|
if (_istalpha (Pos[0])) {
|
|
QuotesOn = FALSE;
|
|
State = STATE_PATH_FOUND;
|
|
DontIncrement = TRUE;
|
|
}
|
|
} else if (Pos[0] == TEXT('\"')) {
|
|
if (_istalpha (Pos[1]) && Pos[2] == TEXT(':') && Pos[3] == TEXT('\\')) {
|
|
QuotesOn = TRUE;
|
|
State = STATE_PATH_FOUND;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case STATE_PATH_FOUND:
|
|
//
|
|
// Initialize path attributes
|
|
//
|
|
QuotesOnColumn = QuotesOn;
|
|
LastPathPosition = Pos;
|
|
|
|
OrgStart = Pos;
|
|
|
|
PathBufferRoot = &PathBuffer[1];
|
|
PathBufferRoot[0] = Pos[0];
|
|
PathBufferRoot[1] = Pos[1];
|
|
|
|
PathBufferPtr = &PathBufferRoot[2];
|
|
Pos = &Pos[2];
|
|
|
|
ShortPath = FALSE;
|
|
OrgPathHasSepChar = FALSE;
|
|
|
|
State = STATE_IN_PATH;
|
|
DontIncrement = TRUE;
|
|
break;
|
|
|
|
case STATE_IN_PATH:
|
|
//
|
|
// Is this a closing quote? If so, look for replacement path
|
|
// and fail entire string if it's not replaced.
|
|
//
|
|
|
|
if (Pos[0] == TEXT(':')) {
|
|
//
|
|
// bogus. This cannot be a path, it has two ':' characters
|
|
//
|
|
Pos = _tcsdec (LastPathPosition, Pos);
|
|
if (Pos) {
|
|
Pos = _tcsdec (LastPathPosition, Pos);
|
|
if (Pos) {
|
|
if (Pos[0] == TEXT('\"')) {
|
|
Pos = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (!Pos) {
|
|
Pos = LastPathPosition;
|
|
QuotesOn = QuotesOnColumn;
|
|
}
|
|
State = STATE_NO_PATH;
|
|
break;
|
|
}
|
|
|
|
if (QuotesOn && *Pos == TEXT('\"')) {
|
|
*PathBufferPtr = 0;
|
|
|
|
ConvertCode = ConvertWin9xPath (PathBufferRoot);
|
|
|
|
if (ConvertCode != CONVERTPATH_NOT_REMAPPED) {
|
|
|
|
State = STATE_PATH_CHANGED;
|
|
DontIncrement = TRUE;
|
|
break;
|
|
|
|
}
|
|
|
|
State = STATE_NO_PATH;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Is this a path separator? If so, look in memdb for replacement path.
|
|
//
|
|
|
|
if (Pos[0] == L'\\') {
|
|
PathSepChar = pIsPathSeparator ((CHARTYPE) _tcsnextc (Pos + 1));
|
|
} else {
|
|
PathSepChar = pIsPathSeparator ((CHARTYPE) _tcsnextc (Pos));
|
|
}
|
|
|
|
if (PathSepChar) {
|
|
|
|
*PathBufferPtr = 0;
|
|
|
|
ConvertCode = ConvertWin9xPath (PathBufferRoot);
|
|
|
|
if (ConvertCode != CONVERTPATH_NOT_REMAPPED) {
|
|
State = STATE_PATH_CHANGED;
|
|
DontIncrement = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for end of data
|
|
//
|
|
|
|
if (Pos[0] == 0) {
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy path character to buffer, break if we exceed max path length
|
|
//
|
|
|
|
*PathBufferPtr = *Pos;
|
|
PathBufferPtr = _tcsinc (PathBufferPtr);
|
|
|
|
if (PathBufferPtr == PathBufferRoot + MAX_TCHAR_PATH) {
|
|
Pos = OrgStart;
|
|
State = STATE_NO_PATH;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Test for short path
|
|
//
|
|
|
|
if (*Pos == TEXT('~')) {
|
|
ShortPath = TRUE;
|
|
}
|
|
|
|
OrgPathHasSepChar |= PathSepChar;
|
|
|
|
break;
|
|
|
|
case STATE_PATH_CHANGED:
|
|
if (ConvertCode == CONVERTPATH_DELETED) {
|
|
State = STATE_PATH_DELETED;
|
|
} else if (ShortPath) {
|
|
State = STATE_SHORT_PATH_CHANGED;
|
|
} else {
|
|
State = STATE_LONG_PATH_CHANGED;
|
|
}
|
|
|
|
//
|
|
// If replacement has introduced a path separator, set the
|
|
// NeedQuotes flag. Quotes will later be added if the path
|
|
// is only part of the complete string.
|
|
//
|
|
|
|
NeedQuotes = FALSE;
|
|
|
|
if (!OrgPathHasSepChar) {
|
|
|
|
for (p = PathBufferRoot ; *p ; p = _tcsinc (p)) {
|
|
if (pIsPathSeparator ((CHARTYPE) _tcsnextc (p))) {
|
|
NeedQuotes = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DontIncrement = TRUE;
|
|
break;
|
|
|
|
case STATE_PATH_DELETED:
|
|
State = STATE_RETURN_PATH;
|
|
DontIncrement = TRUE;
|
|
break;
|
|
|
|
case STATE_SHORT_PATH_CHANGED:
|
|
if (OurGetShortPathName (PathBufferRoot, RenamedFile, MAX_TCHAR_PATH)) {
|
|
PathBufferRoot = RenamedFile;
|
|
}
|
|
|
|
State = STATE_RETURN_PATH;
|
|
DontIncrement = TRUE;
|
|
break;
|
|
|
|
case STATE_LONG_PATH_CHANGED:
|
|
|
|
if (!QuotesOn && NeedQuotes) {
|
|
if (OrgStart != DataStart || Pos[0] != 0) {
|
|
|
|
PathBufferPtr = _tcschr (PathBufferRoot, 0);
|
|
PathBufferPtr[0] = TEXT('\"');
|
|
PathBufferPtr[1] = 0;
|
|
PathBufferRoot = PathBuffer;
|
|
}
|
|
}
|
|
|
|
State = STATE_RETURN_PATH;
|
|
DontIncrement = TRUE;
|
|
break;
|
|
|
|
case STATE_RETURN_PATH:
|
|
rc = ConvertCode;
|
|
StringCopy (ReplacementStr, PathBufferRoot);
|
|
*OldStart = OrgStart;
|
|
*OldEnd = Pos;
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!DontIncrement) {
|
|
Pos = _tcsinc (Pos);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
ConvertWin9xCmdLine (
|
|
IN OUT PTSTR CmdLine, // MAX_CMDLINE buffer
|
|
IN PCTSTR ObjectForDbgMsg, OPTIONAL
|
|
OUT PBOOL PointsToDeletedItem OPTIONAL
|
|
)
|
|
{
|
|
TCHAR NewCmdLine[MAX_CMDLINE];
|
|
TCHAR NewPathBuffer[MAX_TCHAR_PATH];
|
|
PCTSTR CmdLineStart;
|
|
PCTSTR ReplaceStart;
|
|
PCTSTR ExtraParamsStart;
|
|
CONVERTPATH_RC ConvertCode;
|
|
PTSTR EndOfNewCmdLine;
|
|
UINT End = 0;
|
|
BOOL NewCmdLineFlag = FALSE;
|
|
INT Bytes;
|
|
|
|
#ifdef DEBUG
|
|
TCHAR OriginalCmdLine[MAX_CMDLINE];
|
|
StringCopy (OriginalCmdLine, CmdLine);
|
|
#endif
|
|
|
|
if (PointsToDeletedItem) {
|
|
*PointsToDeletedItem = FALSE;
|
|
}
|
|
|
|
*NewCmdLine = 0;
|
|
ExtraParamsStart = CmdLine;
|
|
EndOfNewCmdLine = NewCmdLine;
|
|
|
|
for(;;) {
|
|
CmdLineStart = ExtraParamsStart;
|
|
|
|
//
|
|
// We must test for a command line argument that has quotes or
|
|
// doesn't need quotes, and then test for an argument that needs
|
|
// quotes but doesn't have them.
|
|
//
|
|
|
|
ConvertCode = pGetReplacementPath (
|
|
CmdLine,
|
|
CmdLineStart,
|
|
&ReplaceStart,
|
|
&ExtraParamsStart,
|
|
NewPathBuffer
|
|
);
|
|
|
|
if (ConvertCode == CONVERTPATH_NOT_REMAPPED) {
|
|
//
|
|
// Rest of command line does not have changed files
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If a command line was found, we must replace the text between
|
|
// ReplaceStart and ExtraParamsStart with NewPathBuffer. To do this,
|
|
// we copy the unchanged portion (from CmdLineStart to ReplaceStart)
|
|
// to the caller's buffer, and append the replacement text. The
|
|
// search continues, searching the rest of the command line specified
|
|
// by ExtraParamsStart.
|
|
//
|
|
|
|
if (ConvertCode == CONVERTPATH_DELETED && PointsToDeletedItem) {
|
|
*PointsToDeletedItem = TRUE;
|
|
}
|
|
|
|
if (ObjectForDbgMsg) {
|
|
|
|
DEBUGMSG_IF ((
|
|
ConvertCode == CONVERTPATH_DELETED,
|
|
DBG_WARNING,
|
|
"%s still points to the deleted Win9x file %s (command line: %s).",
|
|
ObjectForDbgMsg,
|
|
NewPathBuffer,
|
|
OriginalCmdLine
|
|
));
|
|
}
|
|
|
|
//
|
|
// Path has changed, so we replace the path in the command line.
|
|
//
|
|
|
|
End = ((PBYTE) EndOfNewCmdLine - (PBYTE) NewCmdLine) +
|
|
((PBYTE) ReplaceStart - (PBYTE) CmdLineStart) +
|
|
SizeOfString (NewPathBuffer);
|
|
|
|
if (End > sizeof (NewCmdLine)) {
|
|
LOG ((LOG_ERROR, "Converting CmdLine: Conversion caused buffer overrun - aborting"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (ReplaceStart > CmdLineStart) {
|
|
StringCopyAB (EndOfNewCmdLine, CmdLineStart, ReplaceStart);
|
|
}
|
|
|
|
EndOfNewCmdLine = _tcsappend (EndOfNewCmdLine, NewPathBuffer);
|
|
|
|
NewCmdLineFlag |= (ConvertCode == CONVERTPATH_REMAPPED);
|
|
}
|
|
|
|
if (NewCmdLineFlag) {
|
|
//
|
|
// We have changed the command line, so complete the processing.
|
|
//
|
|
|
|
if (ExtraParamsStart && *ExtraParamsStart) {
|
|
End = (PBYTE) EndOfNewCmdLine - (PBYTE) NewCmdLine + SizeOfString (ExtraParamsStart);
|
|
if (End > sizeof (NewCmdLine)) {
|
|
LOG ((LOG_ERROR, "Converting CmdLine: Conversion caused buffer overrun -- aborting (2)"));
|
|
return FALSE;
|
|
}
|
|
|
|
StringCopy (EndOfNewCmdLine, ExtraParamsStart);
|
|
}
|
|
|
|
//
|
|
// End is the number of bytes in NewCmdLine
|
|
//
|
|
|
|
Bytes = (INT) End - sizeof(TCHAR);
|
|
|
|
} else {
|
|
//
|
|
// No changes yet, initialize Bytes
|
|
//
|
|
|
|
Bytes = (INT) ByteCount (CmdLine);
|
|
|
|
}
|
|
|
|
//
|
|
// In-place string conversion, first look for a complete match, and when
|
|
// that fails, look for a partial match.
|
|
//
|
|
|
|
if (MappingSearchAndReplaceEx (
|
|
g_CompleteMatchMap,
|
|
NewCmdLineFlag ? NewCmdLine : CmdLine,
|
|
NewCmdLine,
|
|
Bytes,
|
|
NULL,
|
|
sizeof (NewCmdLine),
|
|
STRMAP_COMPLETE_MATCH_ONLY,
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
|
|
NewCmdLineFlag = TRUE;
|
|
|
|
} else {
|
|
|
|
NewCmdLineFlag |= MappingSearchAndReplaceEx (
|
|
g_SubStringMap,
|
|
NewCmdLineFlag ? NewCmdLine : CmdLine,
|
|
NewCmdLine,
|
|
Bytes,
|
|
NULL,
|
|
sizeof (NewCmdLine),
|
|
STRMAP_ANY_MATCH,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
if (NewCmdLineFlag) {
|
|
DEBUGMSG ((
|
|
DBG_DATAFILTER,
|
|
"Command line %s was modified to %s",
|
|
OriginalCmdLine,
|
|
NewCmdLine
|
|
));
|
|
|
|
StringCopy (CmdLine, NewCmdLine);
|
|
}
|
|
|
|
return NewCmdLineFlag;
|
|
}
|
|
|
|
|
|
|