windows-nt/Source/XPSP1/NT/admin/pchealth/sr/kernel/ptree.c
2020-09-26 16:20:57 +08:00

390 lines
9 KiB
C

/******************************************************************************
*
* Copyright (c) 1999 Microsoft Corporation
*
* Module Name:
* pathtree.c
*
* Abstract:
* This file contains the implementation for pathtree.
*
* Revision History:
* Kanwaljit S Marok ( kmarok ) 05/17/99
* created
*
*****************************************************************************/
#include "precomp.h"
#include "pathtree.h"
#include "hashlist.h"
#ifndef RING3
//
// linker commands
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, ConvertToParsedPath )
#pragma alloc_text( PAGE, MatchPrefix )
#endif // ALLOC_PRAGMA
#endif
static WCHAR g_bWildCardNode[2] = { 4, L'*' };
//
// Converts a Wide Char String to Parsed Path
//
// This routine expects the path to be in the format:
// \[full path]
// Note: There should be no trailing '\' on directory names.
//
BOOL
ConvertToParsedPath(
LPWSTR lpszPath,
WORD nPathLen,
PBYTE pPathBuf,
WORD nBufSize
)
{
BOOL fRet = FALSE;
WORD nLen = 0;
WORD nChars = 0;
WORD nPrefix = 0;
WCHAR *pWStr = NULL;
WCHAR *pWBuf = NULL;
WCHAR *peLength = NULL;
BYTE *pElem = NULL;
if(NULL == lpszPath)
{
#ifndef RING3
SrTrace( LOOKUP, ("lpszPath is null\n")) ;
#endif
goto done;
}
if(NULL == pPathBuf)
{
#ifndef RING3
SrTrace( LOOKUP, ("pPathBuf is null\n")) ;
#endif
goto done;
}
nLen = nPathLen;
pWStr = lpszPath;
if( nLen && nBufSize < CALC_PPATH_SIZE(nLen) )
{
#ifndef RING3
SrTrace( LOOKUP, ("Passed in buffer is too small\n")) ;
#endif
goto done;
}
memset( pPathBuf, 0, nBufSize );
pWStr = lpszPath;
//
// Skip the leading '\'
//
while( *pWStr == L'\\' )
{
pWStr++;
nLen--;
}
//
// Parse and convert to PPATH
//
pWBuf = (PWCHAR)(pPathBuf + 2*sizeof(WCHAR));
nChars = 0;
nPrefix = 2 * sizeof(WCHAR);
peLength = pWBuf;
*peLength = 0;
pWBuf++;
while( nLen )
{
if ( *pWStr == L'\\' )
{
//
// Set pe_length
//
*peLength = (nChars+1)*sizeof(WCHAR);
//
// update PrefixLength
//
nPrefix += (*peLength);
peLength = pWBuf;
nChars = 0;
if (nPrefix >= nBufSize)
{
#ifndef RING3
SrTrace( LOOKUP, ("Passed in buffer is too small - 2\n")) ;
#endif
fRet = FALSE;
goto done;
}
}
else
{
nChars++;
#ifdef RING3
*pWBuf = (WCHAR)CharUpperW((PWCHAR)(*pWStr));
#else
*pWBuf = RtlUpcaseUnicodeChar(*pWStr);
#endif
}
pWStr++;
pWBuf++;
nLen--;
}
//
// When we terminate the above loop, the peLength for the final portion of
// the name will not have been set, but peLength will be pointing to the
// correct location for this sections length. Go ahead and set it now.
//
*peLength = (nChars+1)*sizeof(WCHAR);
//
// Set PrefixLength
//
( (ParsedPath *)pPathBuf )->pp_prefixLength = nPrefix;
//
// Set TotalLength
//
( (ParsedPath *)pPathBuf )->pp_totalLength = nPrefix + (*peLength);
//
// Set the last WORD to 0x00
//
*( (PWCHAR)((PBYTE)pPathBuf + nPrefix + (*peLength)) ) = 0;
fRet = TRUE;
done:
return fRet;
}
//
// MatchPrefix : Matches Parsed Path Elements with the given tree.
//
BOOL
MatchPrefix(
BYTE * pTree, // Pointer to the tree blob
INT iFather, // Parent/Starting Node
struct PathElement * ppElem , // PathElement to match
INT * pNode, // Matched node return
INT * pLevel, // Level of matching
INT * pType, // Node type : Incl/Excl/Sfp
BOOL * pfProtected, // Protection flag
BOOL * pfExactMatch // TRUE : if the path matched exactly
)
{
TreeNode * node;
BOOL fRet = FALSE;
if( pLevel )
(*pLevel)++;
if( ppElem->pe_length )
{
INT iNode = 0;
INT iWildCardNode = 0;
iNode = TREE_NODEPTR(pTree, iFather)->m_iSon;
//
// Start by looking at the children of the passed in father
//
while( iNode )
{
node = TREE_NODEPTR(pTree,iNode);
//
// if we encounter a wildcar node, make a note of it
//
if (RtlCompareMemory(g_bWildCardNode,
pTree + node->m_dwData,
((PathElement *)g_bWildCardNode)->pe_length) ==
((PathElement *)g_bWildCardNode)->pe_length)
{
iWildCardNode = iNode;
}
//
// compare the node contents
//
if (RtlCompareMemory(ppElem,
pTree + node->m_dwData,
ppElem->pe_length) ==
ppElem->pe_length )
{
break;
}
iNode = node->m_iSibling;
}
//
// Note: Wildcard processing
// incase we don't have a complete node match, use the
// wildcard node if one was found above unless we are at
// last element in the path, in which case we need to
// lookup hashlist first before doing the wildcard match
//
if ( iNode == 0 &&
iWildCardNode != 0 &&
IFSNextElement(ppElem)->pe_length != 0 )
{
iNode = iWildCardNode;
}
//
// Check for lower levels or file children
//
if( iNode != 0 )
{
//
// Since we have found a matching node with non default type
// we need to set the pType to this node type. This is required
// to enforce the parent's type on the children nodes, except
// in the case of SFP type. SFP type is marked on a directory
// to specify there are SFP files in that directory
//
if ( ( NODE_TYPE_UNKNOWN != node->m_dwType ) )
{
*pType = node->m_dwType;
}
//
// if the node is disabled then abort any furthur seach and
// return NODE_TYPE_EXCLUDE from here
//
if ( node->m_dwFlags & TREEFLAGS_DISABLE_SUBTREE )
{
*pType = NODE_TYPE_EXCLUDE;
*pNode = iNode;
fRet = TRUE;
goto Exit;
}
//
// Return from here to preserve the level
//
fRet = MatchPrefix(
pTree,
iNode,
IFSNextElement(ppElem),
pNode,
pLevel,
pType,
pfProtected,
pfExactMatch);
if (fRet)
{
goto Exit;
}
}
else
{
TreeNode * pFatherNode;
//
// if this the last node check in the Hashlist of parent
//
if ( IFSNextElement(ppElem)->pe_length == 0 )
{
pFatherNode = TREE_NODEPTR(pTree,iFather);
if ( pFatherNode->m_dwFileList &&
MatchEntry(
pTree + pFatherNode->m_dwFileList,
(LPWSTR)(ppElem->pe_unichars),
(INT)(ppElem->pe_length - sizeof(USHORT)),
pType)
)
{
//
// Current Father node needs to be returned
//
*pfExactMatch = TRUE;
*pNode = iFather;
fRet = TRUE;
}
else
{
//
// So we have failed to match the hashlist, but
// we have encountered a wildcard node then we
// need to return that node's type as it will
// be the match in this case
//
if ( iWildCardNode != 0 )
{
node = TREE_NODEPTR(pTree,iWildCardNode);
*pNode = iWildCardNode;
*pType = node->m_dwType;
fRet = TRUE;
}
else
{
fRet = FALSE;
}
}
}
}
}
else
{
*pfExactMatch = TRUE;
*pNode = iFather;
fRet = TRUE;
}
(*pLevel)--;
Exit:
return fRet;
}