mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1185 lines
28 KiB
1185 lines
28 KiB
/*++
|
|
|
|
© 1998 Seagate Software, Inc. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
hsmrule.cpp
|
|
|
|
Abstract:
|
|
|
|
This component represents a rule for a job's policy.
|
|
|
|
Author:
|
|
|
|
Chuck Bardeen [cbardeen] 29-Oct-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "wsb.h"
|
|
#include "job.h"
|
|
#include "hsmrule.h"
|
|
|
|
#define WSB_TRACE_IS WSB_TRACE_BIT_JOB
|
|
|
|
// These are defined in nt.h, but it takes all sorts of grief to try to include them. Since
|
|
// they are just used internally, it isn't even inportant that we have the same definitions.
|
|
#if !defined(DOS_STAR)
|
|
#define DOS_STAR (L'<')
|
|
#endif
|
|
|
|
#if !defined(DOS_QM)
|
|
#define DOS_QM (L'>')
|
|
#endif
|
|
|
|
#if !defined(DOS_DOT)
|
|
#define DOS_DOT (L'"')
|
|
#endif
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::CompareTo(
|
|
IN IUnknown* pUnknown,
|
|
OUT SHORT* pResult
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IWsbCollectable::CompareTo().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IHsmRule> pRule;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::CompareTo"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
// Did they give us a valid item to compare to?
|
|
WsbAssert(0 != pUnknown, E_POINTER);
|
|
|
|
// We need the IWsbBool interface to get the value of the object.
|
|
WsbAffirmHr(pUnknown->QueryInterface(IID_IHsmRule, (void**) &pRule));
|
|
|
|
// Compare the rules.
|
|
hr = CompareToIRule(pRule, pResult);
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::CompareTo"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::CompareToIRule(
|
|
IN IHsmRule* pRule,
|
|
OUT SHORT* pResult
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::CompareToIRule().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
OLECHAR* path = 0;
|
|
OLECHAR* name = 0;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::CompareToIRule"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
// Did they give us a valid item to compare to?
|
|
WsbAssert(0 != pRule, E_POINTER);
|
|
|
|
// Get the path and name.
|
|
WsbAffirmHr(pRule->GetPath(&path, 0));
|
|
WsbAffirmHr(pRule->GetName(&name, 0));
|
|
|
|
// Compare to the path and name.
|
|
hr = CompareToPathAndName(path, name, pResult);
|
|
|
|
} WsbCatch(hr);
|
|
|
|
if (0 != path) {
|
|
WsbFree(path);
|
|
}
|
|
|
|
if (0 != name) {
|
|
WsbFree(name);
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::CompareToIRule"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::CompareToPathAndName(
|
|
IN OLECHAR* path,
|
|
IN OLECHAR* name,
|
|
OUT SHORT* pResult
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::CompareToPathAndName().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SHORT aResult = 0;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::CompareToPathAndName"), OLESTR("path = <%ls>, name = <%ls>"), path, name);
|
|
|
|
try {
|
|
|
|
// Compare the path.
|
|
aResult = (SHORT)_wcsicmp(m_path, path);
|
|
|
|
// Compare the name.
|
|
if (0 == aResult) {
|
|
aResult = (SHORT)_wcsicmp(m_name, name);
|
|
}
|
|
|
|
if (0 != aResult) {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if (0 != pResult) {
|
|
*pResult = aResult;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::CompareToIRule"), OLESTR("hr = <%ls>, result = <%u>"), WsbHrAsString(hr), aResult);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::Criteria(
|
|
OUT IWsbCollection** ppCriteria
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::Criteria().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
WsbAssert(0 != ppCriteria, E_POINTER);
|
|
*ppCriteria = m_pCriteria;
|
|
m_pCriteria->AddRef();
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::DoesNameContainWildcards(
|
|
OLECHAR* name
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::DoesNameContainWildcards().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
try {
|
|
WsbAssert(0 != name, E_POINTER);
|
|
|
|
if (wcscspn(name, OLESTR("*?<>\"")) < wcslen(name)) {
|
|
hr = S_OK;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::EnumCriteria(
|
|
OUT IWsbEnum** ppEnum
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::EnumCriteria().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
WsbAssert(0 != ppEnum, E_POINTER);
|
|
WsbAffirmHr(m_pCriteria->Enum(ppEnum));
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::FinalConstruct(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CComObjectRoot::FinalConstruct().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
WsbAffirmHr(CWsbObject::FinalConstruct());
|
|
|
|
m_isInclude = TRUE;
|
|
m_isUserDefined = TRUE;
|
|
m_isUsedInSubDirs = TRUE;
|
|
|
|
//Create the criteria collection.
|
|
WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_ALL, IID_IWsbCollection, (void**) &m_pCriteria));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::GetClassID(
|
|
OUT CLSID* pClsid
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersist::GetClassID().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::GetClassID"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
WsbAssert(0 != pClsid, E_POINTER);
|
|
*pClsid = CLSID_CHsmRule;
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::GetName(
|
|
OUT OLECHAR** pName,
|
|
IN ULONG bufferSize
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::GetName().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
WsbAssert(0 != pName, E_POINTER);
|
|
WsbAffirmHr(m_name.CopyTo(pName, bufferSize));
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::GetPath(
|
|
OUT OLECHAR** pPath,
|
|
IN ULONG bufferSize
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::GetPath().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
WsbAssert(0 != pPath, E_POINTER);
|
|
WsbAffirmHr(m_path.CopyTo(pPath, bufferSize));
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::GetSearchName(
|
|
OUT OLECHAR** pName,
|
|
IN ULONG bufferSize
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::GetSearchName().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
WsbAssert(0 != pName, E_POINTER);
|
|
WsbAffirmHr(m_searchName.CopyTo(pName, bufferSize));
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::GetSizeMax(
|
|
OUT ULARGE_INTEGER* pSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersistStream::GetSizeMax().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IPersistStream> pPersistStream;
|
|
ULARGE_INTEGER entrySize;
|
|
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::GetSizeMax"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
WsbAssert(0 != pSize, E_POINTER);
|
|
|
|
// Determine the size for a rule with no criteria.
|
|
pSize->QuadPart = WsbPersistSize((wcslen(m_path) + 1) * sizeof(OLECHAR)) + WsbPersistSize((wcslen(m_name) + 1) * sizeof(OLECHAR)) + WsbPersistSize((wcslen(m_searchName) + 1) * sizeof(OLECHAR)) + 3 * WsbPersistSizeOf(BOOL) + WsbPersistSizeOf(ULONG);
|
|
|
|
// Now allocate space for the criteria (assume they are all the
|
|
// same size).
|
|
WsbAffirmHr(m_pCriteria->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
|
|
WsbAffirmHr(pPersistStream->GetSizeMax(&entrySize));
|
|
pSize->QuadPart += entrySize.QuadPart;
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::IsUserDefined(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::IsUserDefined().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_isUserDefined) {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::IsInclude(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::IsInclude().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_isInclude) {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::IsNameInExpression(
|
|
IN OLECHAR* expression,
|
|
IN OLECHAR* name,
|
|
IN BOOL ignoreCase
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmRule::IsNameInExpression().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
USHORT nameLength;
|
|
USHORT expressionLength;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::IsNameInExpression"), OLESTR("expression = %ls, name = %ls, ignoreCase = %ls"), expression, name, WsbBoolAsString(ignoreCase));
|
|
|
|
try {
|
|
|
|
// This is algorithm is from FsRtlIsNameInExpressionPrivate(), but has been rewritten to fit
|
|
// our coding standards, data structures, and to remove other dependencies on Rtl...() code.
|
|
|
|
// The idea behind the algorithm is pretty simple. We keep track of
|
|
// all possible locations in the regular expression that are matching
|
|
// the name. If when the name has been exhausted one of the locations
|
|
// in the expression is also just exhausted, the name is in the language
|
|
// defined by the regular expression.
|
|
WsbAssert(name != 0, E_POINTER);
|
|
WsbAssert(expression != 0, E_POINTER);
|
|
|
|
nameLength = (SHORT)wcslen(name);
|
|
expressionLength = (SHORT)wcslen(expression);
|
|
|
|
// If one string is empty return FALSE. If both are empty return TRUE.
|
|
if ((nameLength == 0) && (expressionLength == 0)) {
|
|
hr = S_OK;
|
|
} else if ((nameLength != 0) && (expressionLength != 0)) {
|
|
|
|
// Special case by far the most common wild card search of *
|
|
if ((expressionLength == 1) && (expression[0] == L'*')) {
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Also special case expressions of the form *X. With this and the prior
|
|
// case we have covered virtually all normal queries.
|
|
else if (expression[0] == L'*') {
|
|
|
|
// Only special case an expression with a single *
|
|
if (DoesNameContainWildcards(&expression[1]) == S_FALSE) {
|
|
|
|
// If the name is smaller than the expression, than it isn't a match. Otherwise,
|
|
// we need to check.
|
|
if (nameLength >= (expressionLength - 1)) {
|
|
|
|
// Do a simple memory compare if case sensitive, otherwise
|
|
// we have got to check this one character at a time.
|
|
if (ignoreCase) {
|
|
if (_wcsicmp(&expression[1], &name[nameLength - (expressionLength - 1)]) == 0) {
|
|
hr = S_OK;
|
|
}
|
|
} else {
|
|
if (wcscmp(&expression[1], &name[nameLength - (expressionLength - 1)]) == 0) {
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
|
|
// This is the general matching code. Since it is messy, it is put in its
|
|
// own method.
|
|
hr = IsNameInExpressionGuts(expression, expressionLength, name, nameLength, ignoreCase);
|
|
}
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::IsNameInExpression"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::IsNameInExpressionGuts(
|
|
IN OLECHAR* expression,
|
|
IN USHORT expressionLength,
|
|
IN OLECHAR* name,
|
|
IN USHORT nameLength,
|
|
IN BOOL ignoreCase
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmRule::IsNameInExpressionGuts().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
USHORT nameOffset = 0;
|
|
OLECHAR nameChar = '0';
|
|
USHORT exprOffset = 0;
|
|
OLECHAR exprChar;
|
|
BOOL nameFinished = FALSE;
|
|
ULONG srcCount;
|
|
ULONG destCount;
|
|
ULONG previousDestCount;
|
|
ULONG matchesCount;
|
|
USHORT* previousMatches = 0;
|
|
USHORT* currentMatches = 0;
|
|
USHORT maxState;
|
|
USHORT currentState;
|
|
|
|
// Walk through the name string, picking off characters. We go one
|
|
// character beyond the end because some wild cards are able to match
|
|
// zero characters beyond the end of the string.
|
|
//
|
|
// With each new name character we determine a new set of states that
|
|
// match the name so far. We use two arrays that we swap back and forth
|
|
// for this purpose. One array lists the possible expression states for
|
|
// all name characters up to but not including the current one, and other
|
|
// array is used to build up the list of states considering the current
|
|
// name character as well. The arrays are then switched and the process
|
|
// repeated.
|
|
//
|
|
// There is not a one-to-one correspondence between state number and
|
|
// offset into the expression. This is evident from the NFAs in the
|
|
// initial comment to this function. State numbering is not continuous.
|
|
// This allows a simple conversion between state number and expression
|
|
// offset. Each character in the expression can represent one or two
|
|
// states. * and DOS_STAR generate two states: ExprOffset*2 and
|
|
// ExprOffset*2 + 1. All other expreesion characters can produce only
|
|
// a single state. Thus ExprOffset = State/2.
|
|
//
|
|
//
|
|
// Here is a short description of the variables involved:
|
|
//
|
|
// nameOffset - The offset of the current name char being processed.
|
|
// exprOffset - The offset of the current expression char being processed.
|
|
//
|
|
// srcCount - Prior match being investigated with current name char
|
|
// previousDestCount - This is used to prevent entry duplication, see comment
|
|
// previousMatches - Holds the previous set of matches (the Src array)
|
|
//
|
|
// destCount - Next location to put a match assuming current name char
|
|
// currentMatches - Holds the current set of matches (the Dest array)
|
|
//
|
|
// nameFinished - Allows one more itteration through the Matches array
|
|
// after the name is exhusted (to come *s for example)
|
|
|
|
try {
|
|
|
|
// Since you can get at most two matches per character in the expression, the
|
|
// biggest arrays you will need is twice the expression length.
|
|
currentMatches = (USHORT*)WsbAlloc(nameLength * 2 * expressionLength * sizeof(USHORT));
|
|
WsbAffirm(0 != currentMatches, E_OUTOFMEMORY);
|
|
previousMatches = (USHORT*)WsbAlloc(nameLength * 2 * expressionLength * sizeof(USHORT));
|
|
WsbAffirm(0 != previousMatches, E_OUTOFMEMORY);
|
|
|
|
previousMatches[0] = 0;
|
|
matchesCount = 1;
|
|
maxState = (USHORT)( expressionLength * 2 );
|
|
|
|
while (!nameFinished) {
|
|
|
|
if (nameOffset < nameLength) {
|
|
nameChar = name[nameOffset];
|
|
nameOffset++;
|
|
} else {
|
|
nameFinished = TRUE;
|
|
|
|
// If we have already exhasted the expression, cool. Don't
|
|
// continue.
|
|
if (previousMatches[matchesCount - 1] == maxState) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now, for each of the previous stored expression matches, see what
|
|
// we can do with this name character.
|
|
srcCount = 0;
|
|
destCount = 0;
|
|
previousDestCount = 0;
|
|
|
|
while (srcCount < matchesCount) {
|
|
USHORT length;
|
|
|
|
// We have to carry on our expression analysis as far as possible
|
|
// for each character of name, so we loop here until the
|
|
// expression stops matching. A clue here is that expression
|
|
// cases that can match zero or more characters end with a
|
|
// continue, while those that can accept only a single character
|
|
// end with a break.
|
|
exprOffset = (USHORT)( ( ( previousMatches[srcCount++] + 1 ) / 2 ) );
|
|
length = 0;
|
|
|
|
while (TRUE) {
|
|
|
|
if (exprOffset == expressionLength) {
|
|
break;
|
|
}
|
|
|
|
// The first time through the loop we don't want
|
|
// to increment ExprOffset.
|
|
exprOffset = (USHORT)( exprOffset + length );
|
|
length = 1;
|
|
|
|
currentState = (USHORT)( exprOffset * 2 );
|
|
|
|
if (exprOffset == expressionLength) {
|
|
currentMatches[destCount++] = maxState;
|
|
break;
|
|
}
|
|
|
|
exprChar = expression[exprOffset];
|
|
|
|
// * matches any character zero or more times.
|
|
if (exprChar == L'*') {
|
|
currentMatches[destCount++] = currentState;
|
|
currentMatches[destCount++] = (USHORT)( currentState + 1 );
|
|
continue;
|
|
}
|
|
|
|
// DOS_STAR matches any character except . zero or more times.
|
|
if (exprChar == DOS_STAR) {
|
|
BOOLEAN iCanEatADot = FALSE;
|
|
|
|
// If we are at a period, determine if we are allowed to
|
|
// consume it, ie. make sure it is not the last one.
|
|
if (!nameFinished && (nameChar == '.')) {
|
|
USHORT offset;
|
|
|
|
for (offset = nameOffset; offset < nameLength; offset++) {
|
|
if (name[offset] == L'.') {
|
|
iCanEatADot = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nameFinished || (nameChar != L'.') || iCanEatADot) {
|
|
currentMatches[destCount++] = currentState;
|
|
currentMatches[destCount++] = (USHORT)( currentState + 1 );
|
|
continue;
|
|
} else {
|
|
|
|
// We are at a period. We can only match zero
|
|
// characters (ie. the epsilon transition).
|
|
currentMatches[destCount++] = (USHORT)( currentState + 1 );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// The following expreesion characters all match by consuming
|
|
// a character, thus force the expression, and thus state
|
|
// forward.
|
|
currentState += 2;
|
|
|
|
// DOS_QM is the most complicated. If the name is finished,
|
|
// we can match zero characters. If this name is a '.', we
|
|
// don't match, but look at the next expression. Otherwise
|
|
// we match a single character.
|
|
if (exprChar == DOS_QM) {
|
|
|
|
if (nameFinished || (nameChar == L'.')) {
|
|
continue;
|
|
}
|
|
|
|
currentMatches[destCount++] = currentState;
|
|
break;
|
|
}
|
|
|
|
// A DOS_DOT can match either a period, or zero characters
|
|
// beyond the end of name.
|
|
if (exprChar == DOS_DOT) {
|
|
|
|
if (nameFinished) {
|
|
continue;
|
|
}
|
|
|
|
if (nameChar == L'.') {
|
|
currentMatches[destCount++] = currentState;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// From this point on a name character is required to even
|
|
// continue, let alone make a match.
|
|
if (nameFinished) {
|
|
break;
|
|
}
|
|
|
|
// If this expression was a '?' we can match it once.
|
|
if (exprChar == L'?') {
|
|
currentMatches[destCount++] = currentState;
|
|
break;
|
|
}
|
|
|
|
// Finally, check if the expression char matches the name char
|
|
if (ignoreCase) {
|
|
if (towlower(exprChar) == towlower(nameChar)) {
|
|
currentMatches[destCount++] = currentState;
|
|
break;
|
|
}
|
|
} else if (exprChar == nameChar) {
|
|
currentMatches[destCount++] = currentState;
|
|
break;
|
|
}
|
|
|
|
// The expression didn't match so go look at the next
|
|
// previous match.
|
|
break;
|
|
}
|
|
|
|
|
|
// Prevent duplication in the destination array.
|
|
//
|
|
// Each of the arrays is montonically increasing and non-
|
|
// duplicating, thus we skip over any source element in the src
|
|
// array if we just added the same element to the destination
|
|
// array. This guarentees non-duplication in the dest. array.
|
|
if ((srcCount < matchesCount) && (previousDestCount < destCount) ) {
|
|
while (previousDestCount < destCount) {
|
|
while (previousMatches[srcCount] < currentMatches[previousDestCount]) {
|
|
srcCount += 1;
|
|
}
|
|
|
|
previousDestCount += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we found no matches in the just finished itteration, it's time
|
|
// to bail.
|
|
|
|
if (destCount == 0) {
|
|
WsbThrow(S_FALSE);
|
|
}
|
|
|
|
// Swap the meaning the two arrays
|
|
{
|
|
USHORT* tmp;
|
|
|
|
tmp = previousMatches;
|
|
previousMatches = currentMatches;
|
|
currentMatches = tmp;
|
|
}
|
|
|
|
matchesCount = destCount;
|
|
}
|
|
|
|
currentState = previousMatches[matchesCount - 1];
|
|
|
|
if (currentState == maxState) {
|
|
hr = S_OK;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
// Free the matches buffers that we allocated previously.
|
|
if (0 != currentMatches) {
|
|
WsbFree(currentMatches);
|
|
}
|
|
|
|
if (0 != previousMatches) {
|
|
WsbFree(previousMatches);
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::IsUsedInSubDirs(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::IsUsedInSubDirs().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_isUsedInSubDirs) {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::Load(
|
|
IN IStream* pStream
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersistStream::Load().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IPersistStream> pPersistStream;
|
|
CComPtr<IWsbCollectable> pCollectable;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::Load"), OLESTR(""));
|
|
|
|
try {
|
|
WsbAssert(0 != pStream, E_POINTER);
|
|
|
|
// Do the easy stuff, but make sure that this order matches the order
|
|
// in the save method.
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_path, 0));
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_name, 0));
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_searchName, 0));
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_isUserDefined));
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_isInclude));
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_isUsedInSubDirs));
|
|
|
|
// Load all the criteria.
|
|
WsbAffirmHr(m_pCriteria->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
|
|
WsbAffirmHr(pPersistStream->Load(pStream));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::MatchesName(
|
|
IN OLECHAR* name
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::MatchesName().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::MatchesName"), OLESTR("name = <%ls>"), (OLECHAR *)name);
|
|
|
|
try {
|
|
|
|
WsbAssert(0 != name, E_POINTER);
|
|
|
|
// It is assumed that these names have been converted from they way they
|
|
// might have been input into proper names for IsNameInExpression()
|
|
// function. See NameToSearchName().
|
|
hr = IsNameInExpression(m_searchName, name, TRUE);
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::MatchesName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::NameToSearchName(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmRule::NameToSearchName().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int length;
|
|
int i;
|
|
|
|
try {
|
|
|
|
WsbAssert(m_name != 0, E_POINTER);
|
|
|
|
// These name alterations are copied from the NT FindFirstFileExW() code;
|
|
// although the code had to be changed to work with the data structures that
|
|
// are available.
|
|
//
|
|
// *.* -> *
|
|
// ? -> DOS_QM
|
|
// . followed by ? or * -> DOS_DOT
|
|
// * followed by a . -> DOS_STAR
|
|
|
|
if (_wcsicmp(m_name, OLESTR("*.*")) == 0) {
|
|
m_searchName = OLESTR("*");
|
|
} else {
|
|
m_searchName = m_name;
|
|
length = wcslen(m_searchName);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
if ((i != 0) && (m_searchName[i] == L'.') && (m_searchName[i-1] == L'*')) {
|
|
m_searchName[i-1] = DOS_STAR;
|
|
}
|
|
|
|
if ((m_searchName[i] == L'?') || (m_searchName[i] == L'*')) {
|
|
if (m_searchName[i] == L'?') {
|
|
m_searchName[i] = DOS_QM;
|
|
}
|
|
|
|
if ((i != 0) && (m_searchName[i-1] == L'.')) {
|
|
m_searchName[i-1] = DOS_DOT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::Save(
|
|
IN IStream* pStream,
|
|
IN BOOL clearDirty
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersistStream::Save().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IPersistStream> pPersistStream;
|
|
|
|
WsbTraceIn(OLESTR("CHsmRule::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
|
|
|
|
try {
|
|
WsbAssert(0 != pStream, E_POINTER);
|
|
|
|
// Do the easy stuff, but make sure that this order matches the order
|
|
// in the save method.
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_path));
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_name));
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_searchName));
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_isUserDefined));
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_isInclude));
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_isUsedInSubDirs));
|
|
|
|
// Save off all the criteria.
|
|
WsbAffirmHr(m_pCriteria->QueryInterface(IID_IPersistStream, (void**) &pPersistStream));
|
|
WsbAffirmHr(pPersistStream->Save(pStream, clearDirty));
|
|
|
|
// If we got it saved and we were asked to clear the dirty bit, then
|
|
// do so now.
|
|
if (clearDirty) {
|
|
m_isDirty = FALSE;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmRule::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::SetIsInclude(
|
|
IN BOOL isInclude
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::SetIsInclude().
|
|
|
|
--*/
|
|
{
|
|
m_isInclude = isInclude;
|
|
m_isDirty = TRUE;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::SetIsUserDefined(
|
|
IN BOOL isUserDefined
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::SetIsUserDefined().
|
|
|
|
--*/
|
|
{
|
|
m_isUserDefined = isUserDefined;
|
|
m_isDirty = TRUE;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::SetIsUsedInSubDirs(
|
|
IN BOOL isUsed
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::SetIsUsedInSubDirs().
|
|
|
|
--*/
|
|
{
|
|
m_isUsedInSubDirs = isUsed;
|
|
m_isDirty = TRUE;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::SetName(
|
|
IN OLECHAR* name
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::SetName().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
m_name = name;
|
|
WsbAffirmHr(NameToSearchName());
|
|
m_isDirty = TRUE;
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::SetPath(
|
|
IN OLECHAR* path
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmRule::SetPath().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
m_path = path;
|
|
m_isDirty = TRUE;
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmRule::Test(
|
|
USHORT* passed,
|
|
USHORT* failed
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IWsbTestable::Test().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
try {
|
|
|
|
WsbAssert(0 != passed, E_POINTER);
|
|
WsbAssert(0 != failed, E_POINTER);
|
|
|
|
*passed = 0;
|
|
*failed = 0;
|
|
|
|
} WsbCatch(hr);
|
|
|
|
return(hr);
|
|
}
|