390 lines
9 KiB
C
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;
|
||
|
}
|
||
|
|
||
|
|