Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2167 lines
58 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
baseobj.cxx
Abstract:
Basic Object Class for IIS MetaBase.
Author:
Michael W. Thomas 20-May-96
Revision History:
--*/
#include "precomp.hxx"
CMDBaseObject::CMDBaseObject(
LPSTR strName,
LPSTR
)
/*++
Routine Description:
Constructor for an object.
Arguments:
Name - The name of the object.
Tag - Optional tag for the object. Intended to store a physical path.
Return Value:
--*/
:
m_strMDName(strName),
m_bufKey(),
m_pboParent(NULL),
m_pbocChildHead (NULL),
m_cbo(0),
m_phtChildren(NULL),
m_dwReadCounter (0),
m_dwReadPathCounter (0),
m_dwWriteCounter (0),
m_dwWritePathCounter (0),
m_dwNumNonInheritableData (0)
{
BOOL fRet;
DWORD i;
m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
if (m_dwDataSetNumber==0 || m_dwDataSetNumber==0xFFFFFFFF) // check for possible zero
{
m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
}
fRet = GenerateKey();
MD_ASSERT(fRet);
for (i = 0; i < INVALID_END_METADATA; i++) {
m_pdcarrayDataHead[i] = NULL;
}
SetLastChangeTime();
};
CMDBaseObject::CMDBaseObject(
LPWSTR strName,
LPWSTR
)
/*++
Routine Description:
Constructor for an object.
Arguments:
Name - The name of the object.
Tag - Optional tag for the object. Intended to store a physical path.
Return Value:
--*/
:
m_strMDName(strName),
m_bufKey(),
m_pboParent(NULL),
m_pbocChildHead (NULL),
m_cbo(0),
m_phtChildren(NULL),
m_dwReadCounter (0),
m_dwReadPathCounter (0),
m_dwWriteCounter (0),
m_dwWritePathCounter (0),
m_dwNumNonInheritableData (0)
{
BOOL fRet;
DWORD i;
m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
if (m_dwDataSetNumber==0 || m_dwDataSetNumber==0xFFFFFFFF) // check for possible zero
{
m_dwDataSetNumber = InterlockedExchangeAdd ((LONG *)&g_dwCMDBaseObjectNextUniqueDataSetNumber,2);
}
fRet = GenerateKey();
MD_ASSERT(fRet);
for (i = 0; i < INVALID_END_METADATA; i++) {
m_pdcarrayDataHead[i] = NULL;
}
SetLastChangeTime();
};
CMDBaseObject::~CMDBaseObject()
/*++
Routine Description:
Destructor for an object. Deletes all data and recursively deletes
all child objects.
Arguments:
Return Value:
--*/
{
PDATA_CONTAINER pdcIndex, pdcSave;
PBASEOBJECT_CONTAINER pbocIndex, pbocSave;
int i;
for (i = 1; i < INVALID_END_METADATA; i++) {
for (pdcIndex=m_pdcarrayDataHead[i];pdcIndex!=NULL;pdcIndex=pdcSave) {
pdcSave=pdcIndex->NextPtr;
DeleteDataObject(pdcIndex->pbdDataObject);
delete(pdcIndex);
}
}
if (m_phtChildren)
delete(m_phtChildren);
for (pbocIndex=m_pbocChildHead;pbocIndex!=NULL;pbocIndex=pbocSave) {
pbocSave=pbocIndex->NextPtr;
delete(pbocIndex->pboMetaObject);
delete(pbocIndex);
}
}
BOOL
CMDBaseObject::SetName(
LPSTR strName,
BOOL bUnicode
)
/*++
Routine Description:
Sets the name of an object.
Arguments:
Name - The name of the object.
Return Value:
BOOL - TRUE is succeeded.
--*/
{
BOOL fRet;
if (bUnicode)
fRet = m_strMDName.SafeCopy((LPWSTR)strName);
else
fRet = m_strMDName.SafeCopy((LPSTR)strName);
if (fRet)
return GenerateKey();
/* else */
return FALSE;
};
BOOL
CMDBaseObject::SetName(
LPWSTR strName
)
/*++
Routine Description:
Sets the name of an object.
Arguments:
Name - The name of the object.
Return Value:
BOOL - TRUE is succeeded.
--*/
{
BOOL fRet;
fRet = m_strMDName.SafeCopy(strName);
if (fRet)
return GenerateKey();
/* else */
return FALSE;
};
HRESULT
CMDBaseObject::InsertChildObject(
IN CMDBaseObject *pboChild
)
/*++
Routine Description:
Inserts a child object into the list of child objects.
Arguments:
Child - the object to insert.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_NOT_ENOUGH_MEMORY
ERROR_DUP_NAME
--*/
{
MD_ASSERT(pboChild != NULL);
MD_ASSERT(pboChild->m_bufKey.QuerySize() > 0);
HRESULT hresReturn = ERROR_SUCCESS;
PBASEOBJECT_CONTAINER pbocNew = new BASEOBJECT_CONTAINER;
// Bail if not enough memory.
if (pbocNew == NULL)
return RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
pbocNew->pboMetaObject = pboChild;
pbocNew->NextPtr = NULL;
pboChild->SetParent(this);
hresReturn = AddChildObjectToHash(pboChild,
pbocNew);
// Attach to the chain at the end (to keep enumeration ordering)
if (SUCCEEDED(hresReturn))
{
if (m_pbocChildHead == NULL)
m_pbocChildHead = pbocNew;
else
m_pbocChildTail->NextPtr = pbocNew;
m_pbocChildTail = pbocNew;
m_cbo++;
SetLastChangeTime();
}
else
delete pbocNew;
return(hresReturn);
}
CMDBaseObject *
CMDBaseObject::GetChildObject(
IN OUT LPSTR &strName,
OUT HRESULT *phresReturn,
IN BOOL bUnicode
)
/*++
Routine Description:
Gets a child object by name. Updates strName to point past the end of the Name if found.
Arguments:
Name - name of the object. End delimeter can be '\0', '\\', or '/'.
Return Value:
CBaseObject * - The child object or NULL if the child is not found.
Notes:
--*/
{
CMDBaseObject *pboReturn = NULL;
LPSTR pchDelimiter = strName;
// Find the delimiter. Change to terminate character.
if (bUnicode)
{
LPWSTR pchDelimiterW = (LPWSTR) pchDelimiter;
WCHAR chW;
while ((chW = *pchDelimiterW) != MD_ALT_PATH_DELIMETERW &&
chW != MD_PATH_DELIMETERW &&
chW != (WCHAR)L'\0')
{
pchDelimiterW++;
}
pchDelimiter = (LPSTR) pchDelimiterW;
}
else
{
CHAR chA;
while ((chA = *(LPSTR) pchDelimiter) != MD_ALT_PATH_DELIMETERA &&
chA != MD_PATH_DELIMETERA &&
chA != (CHAR) '\0')
{
(LPSTR) pchDelimiter = CharNextExA(CP_ACP,
(LPSTR) pchDelimiter,
0);
}
}
// Find the child.
pboReturn = FindChild(strName, (int)DIFF(pchDelimiter-strName), bUnicode, phresReturn);
// If we found the name, move up the pointer to the delimiter
if (pboReturn != NULL)
{
MD_ASSERT(*phresReturn == ERROR_SUCCESS);
strName = pchDelimiter;
}
#if 0 // SAB
// If we didn't find the name, return the "not found" error.
else if (*phresReturn == ERROR_SUCCESS)
{
*phresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
}
#endif
return(pboReturn);
}
CMDBaseObject *
CMDBaseObject::EnumChildObject(
IN DWORD dwEnumObjectIndex
)
/*++
Routine Description:
Gets a child object by index.
Arguments:
EnumObjectIndex - The 0 based index of the object to get.
Return Value:
CMDBaseObject * - The child object or NULL if the child is not found.
Notes:
--*/
{
PBASEOBJECT_CONTAINER pbocCurrent;
CMDBaseObject *pboReturn;
DWORD i;
for (pbocCurrent = m_pbocChildHead, i=0;
(pbocCurrent!=NULL) && (i < dwEnumObjectIndex);
pbocCurrent=pbocCurrent->NextPtr, i++) {
}
if (pbocCurrent != NULL) {
pboReturn = pbocCurrent->pboMetaObject;
}
else {
pboReturn = NULL;
}
return (pboReturn);
}
PBASEOBJECT_CONTAINER
CMDBaseObject::NextChildObject(
IN PBASEOBJECT_CONTAINER pbocCurrent
)
/*++
Routine Description:
Given a BASEOBJECT_CONTAINER returns the next BASEOBJECT_CONTAINER in the linked list.
Much more efficient than EnumchildObject, if the whole list is being traversed.
Arguments:
pbocCurrent - Current container object.
Return Value:
PBASEOBJECT_CONTAINER - The child object container or NULL if the container is not found.
Notes:
--*/
{
if (pbocCurrent == NULL)
{
return m_pbocChildHead;
}
return pbocCurrent->NextPtr;
}
HRESULT
CMDBaseObject::RemoveChildObject(
IN LPTSTR strName,
IN BOOL bUnicode
)
/*++
Routine Description:
Removes a child object from the list of child objects and deletes it.
Arguments:
Name - The name of the object to remove.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_PATH_NOT_FOUND
--*/
{
MD_ASSERT (strName != NULL);
CMDBaseObject* pboCurrent;
BASEOBJECT_CONTAINER* pbocPrev;
HRESULT hresReturn;
// Find the object, including the previous container.
pboCurrent = FindChild(strName,
/* Length */ -1,
bUnicode,
&hresReturn,
/* fUseHash */ FALSE,
&pbocPrev);
if (hresReturn == ERROR_SUCCESS)
{ // Either we found it, or it's not there. But no errors occurred.
if (pboCurrent != NULL)
{ // We found it.
BASEOBJECT_CONTAINER* pbocCurrent;
RemoveChildObjectFromHash(pboCurrent);
// Remove from the container chain, keeping a pointer to the container to delete.
if (pbocPrev == NULL)
{
pbocCurrent = m_pbocChildHead;
MD_ASSERT(pbocCurrent != NULL);
m_pbocChildHead = pbocCurrent->NextPtr;
// If tail pointed to pbocCurrent, then head will become NULL,
// in which case tail will be ignored.
}
else
{
pbocCurrent = pbocPrev->NextPtr;
MD_ASSERT(pbocCurrent != NULL);
pbocPrev->NextPtr = pbocCurrent->NextPtr;
if (m_pbocChildTail == pbocCurrent)
{
MD_ASSERT(pbocPrev->NextPtr == NULL);
m_pbocChildTail = pbocPrev;
}
}
// Delete the container. The base object itself is deleted as part of
// CMDHandle::RemoveNotifications.
delete pbocCurrent;
MD_ASSERT(m_cbo != 0);
m_cbo--;
SetLastChangeTime();
}
// If FindChild() succeeded but didn't find anything, return the error.
else
{
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
}
}
return hresReturn;
}
HRESULT
CMDBaseObject::AddChildObjectToHash(
IN CMDBaseObject *pboChild,
IN BASEOBJECT_CONTAINER* pbocChild
)
/*++
Routine Description:
Add child object from the hash table.
Arguments:
Child - The object to remove.
pbocChild - The container for the child object. If NULL,
the child must already be on the child list.
This routine will find the child container, and will
not check the child list for ERROR_DUP_NAME.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_NOT_ENOUGH_MEMORY
ERROR_DUP_NAME
--*/
{
HRESULT hresReturn = NO_ERROR;
BOOL bCheckForDups = (pbocChild == NULL) ? FALSE : TRUE;
// Should we create the hash table now?
if (m_phtChildren == NULL && m_cbo >= cboCreateHashThreashold)
{ // Time to create hash table
// Just skip if we can't create table for some reason.
m_phtChildren = new CChildNodeHashTable;
if (m_phtChildren != NULL)
{ // Create successful. Let's fill the sucker.
BASEOBJECT_CONTAINER* pboc = m_pbocChildHead;
while (pboc != NULL)
{
LK_RETCODE ret;
MD_ASSERT(pboc->pboMetaObject != NULL);
MD_ASSERT(pboc->pboMetaObject->m_bufKey.QuerySize() > 0);
ret = m_phtChildren->InsertRecord(pboc,
/* fOverwrite */ FALSE);
MD_ASSERT(ret == LK_SUCCESS);
if (ret != LK_SUCCESS)
{
delete m_phtChildren;
m_phtChildren = NULL;
break;
}
pboc = pboc->NextPtr;
}
}
}
// Use hash table if it exists.
if (m_phtChildren != NULL)
{
LK_RETCODE ret;
if (pbocChild == NULL) {
//
// Need container for insert function.
// If it came in as NULL, then the node is not
// really new (ie. rename) and should already be
// on the list, so find it.
//
BASEOBJECT_CONTAINER* pbocIndex = m_pbocChildHead;
while ((pbocIndex != NULL) && (pbocIndex->pboMetaObject != pboChild)) {
pbocIndex = pbocIndex->NextPtr;
}
DBG_ASSERT((pbocIndex != NULL) && (pbocIndex->pboMetaObject == pboChild));
pbocChild = pbocIndex;
}
// Put in hash table. This looks for dups.
ret = m_phtChildren->InsertRecord(pbocChild,
/* fOverwrite */ FALSE);
DBG_ASSERT( ret != LK_KEY_EXISTS);
if (ret == LK_KEY_EXISTS)
{
return RETURNCODETOHRESULT(ERROR_DUP_NAME);
}
if (ret != LK_SUCCESS)
{
MD_ASSERT(ret == LK_SUCCESS); // Put up debug assert now.
delete m_phtChildren;
m_phtChildren = NULL;
goto NoHashTable;
}
}
// If hash table doesn't exist, check for duplicate by searching chain.
else
{
NoHashTable:
if (m_pbocChildHead != NULL && bCheckForDups)
{
LPSTR strChildName;
// Check for duplicates
strChildName = pboChild->GetName(/* bUnicode */ TRUE);
if (strChildName == NULL)
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
else if (FindChild(strChildName,
/* Length */ -1,
/* bUnicode */ TRUE,
&hresReturn,
/* fUseHash */ FALSE,
NULL) != NULL)
{
hresReturn = RETURNCODETOHRESULT(ERROR_DUP_NAME);
}
}
}
return hresReturn;
}
VOID
CMDBaseObject::RemoveChildObjectFromHash(
IN CMDBaseObject *pboChild
)
/*++
Routine Description:
Removes a child object from the hash table.
Arguments:
Child - The object to remove.
Return Value:
none
--*/
{
// Delete from the hash table.
if (m_phtChildren != NULL)
{
m_phtChildren->DeleteKey(&pboChild->m_bufKey);
// Delete the hash table if we've gone below the threashold.
if (m_cbo <= cboDeleteHashThreashold)
{
delete m_phtChildren;
m_phtChildren = NULL;
}
}
}
HRESULT
CMDBaseObject::RemoveChildObject(
IN CMDBaseObject *pboChild
)
/*++
Routine Description:
Removes a child object from the list of child objects and deletes it.
Arguments:
Name - The name of the object to remove.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_PATH_NOT_FOUND
--*/
{
MD_ASSERT (pboChild != NULL);
BASEOBJECT_CONTAINER* pbocCurrent;
BASEOBJECT_CONTAINER* pbocPrev;
HRESULT hresReturn;
// Find the object in the container chain.
pbocPrev = NULL;
pbocCurrent = m_pbocChildHead;
while (pbocCurrent != NULL && pbocCurrent->pboMetaObject != pboChild)
{
pbocPrev = pbocCurrent;
pbocCurrent = pbocCurrent->NextPtr;
}
if (pbocCurrent != NULL)
{ // Found it
MD_ASSERT (pbocCurrent->pboMetaObject == pboChild);
RemoveChildObjectFromHash(pboChild);
// Remove from the container chain.
if (pbocPrev == NULL)
{
m_pbocChildHead = pbocCurrent->NextPtr;
// If tail pointed to pbocCurrent, then head will become NULL,
// in which case tail will be ignored.
}
else
{
pbocPrev->NextPtr = pbocCurrent->NextPtr;
if (m_pbocChildTail == pbocCurrent)
{
MD_ASSERT(pbocPrev->NextPtr == NULL);
m_pbocChildTail = pbocPrev;
}
}
// Delete it. Actual base object is deleted as part of
// CMDHandle::RemoveNotifications.
delete pbocCurrent;
hresReturn = ERROR_SUCCESS;
MD_ASSERT(m_cbo != 0);
m_cbo--;
SetLastChangeTime();
}
else {
hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
}
return hresReturn;
}
HRESULT
CMDBaseObject::InsertDataObject(
IN CMDBaseData *pbdInsert
)
/*++
Routine Description:
Inserts a data object into the list of data objects of that type.
Arguments:
Data - The data object to insert.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_INTERNAL_ERROR
Notes:
Does not check for duplicates. This should be checked by the calling routine.
--*/
{
HRESULT hresReturn = ERROR_SUCCESS;
MD_ASSERT (pbdInsert != NULL);
PDATA_CONTAINER *pdcHead;
PDATA_CONTAINER pdcNew;
pdcNew = new (DATA_CONTAINER);
if (pdcNew == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
pdcHead = &(m_pdcarrayDataHead[pbdInsert->GetDataType()]);
pdcNew->NextPtr = NULL;
pdcNew->pbdDataObject = pbdInsert;
if (*pdcHead == NULL) {
*pdcHead = pdcNew;
}
else {
//
// It seems likely that the first paths read in will be the most common
// paths, so insert at end of list
//
PDATA_CONTAINER pdcIndex;
for (pdcIndex = *pdcHead;
pdcIndex->NextPtr != NULL;
pdcIndex = pdcIndex->NextPtr) {
}
MD_ASSERT(pdcIndex!=NULL);
MD_ASSERT(pdcIndex->NextPtr==NULL);
pdcIndex->NextPtr = pdcNew;
if ((pbdInsert->GetAttributes() & METADATA_INHERIT) == 0) {
m_dwNumNonInheritableData++;
}
}
}
if (SUCCEEDED(hresReturn)) {
SetLastChangeTime();
}
return(hresReturn);
}
HRESULT
CMDBaseObject::SetDataObject(
IN CMDBaseData *pbdNew
)
/*++
Routine Description:
Sets a data object.
If data of that name does not already exist,
it creates and inserts a data object into the list of data objects
of that type.
If data of that name aready exists, it sets the new data values.
Arguments:
Data - The data to insert.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_NOT_ENOUGH_MEMORY
ERROR_INTERNAL_ERROR
Notes:
Checks for duplicates.
--*/
{
HRESULT hresReturn;
MD_ASSERT (pbdNew != NULL);
CMDBaseData *pbdOld = GetDataObject(pbdNew->GetIdentifier(), METADATA_NO_ATTRIBUTES, ALL_METADATA); //Check for all types
if (pbdOld == pbdNew) {
//
// It's already there, leave it alone.
//
hresReturn = ERROR_SUCCESS;
}
else {
//
// Insert the new first so if there's a problem leave the old.
//
hresReturn = InsertDataObject(pbdNew);
if (SUCCEEDED(hresReturn)) {
pbdNew->IncrementReferenceCount();
if (pbdOld != NULL) {
hresReturn = RemoveDataObject(pbdOld, TRUE);
MD_ASSERT(SUCCEEDED(hresReturn));
}
}
}
return(hresReturn);
}
HRESULT
CMDBaseObject::SetDataObject(
IN PMETADATA_RECORD pmdrMDData,
IN BOOL bUnicode)
/*++
Routine Description:
Sets a data object.
If data of that name does not already exist,
it creates and inserts a data object into the list of data objects
of that type.
If data of that name aready exists, it sets the new data values.
Arguments:
Data - The data to set.
Identifier - The identifier of the data.
Attributes - The flags for the data.
METADATA_INHERIT
UserType - The User Type for the data. User Defined.
DataType - The Type of the data.
DWORD_METADATA
STRING_METADATA
BINARY_METADATA
DataLen - The length of the data. Only used if DataType == BINARY_METADATA.
Data - Pointer to the data.
Return Value:
DWORD - ERROR_SUCCESS
ERROR_NOT_ENOUGH_MEMORY
ERROR_INTERNAL_ERROR
MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE
Notes:
Checks for duplicates.
--*/
{
HRESULT hresReturn;
CMDBaseData *pbdNew;
CMDBaseData *pbdOld = GetDataObject(pmdrMDData->dwMDIdentifier, METADATA_NO_ATTRIBUTES, ALL_METADATA); //Check for all types
if ((pbdOld != NULL) &&
((pbdOld->GetAttributes() & METADATA_SECURE) != 0) &&
((pmdrMDData->dwMDAttributes & METADATA_SECURE) == 0)) {
hresReturn = MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE;
}
else {
pbdNew = MakeDataObject(pmdrMDData, bUnicode);
if (pbdNew == NULL) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
else {
if (pbdOld == pbdNew) {
//
// It's already there, just correct the ref count,
// which MakeDataObject incremented.
//
DeleteDataObject(pbdNew);
hresReturn = ERROR_SUCCESS;
}
else {
hresReturn = InsertDataObject(pbdNew);
if (FAILED(hresReturn)) {
DeleteDataObject(pbdNew);
pbdNew = NULL;
}
else {
if (pbdOld!=NULL) {
//
// Data exists with same name.
// Need to delete old data.
//
hresReturn = RemoveDataObject(pbdOld, TRUE);
MD_ASSERT(SUCCEEDED(hresReturn));
}
}
}
}
}
return(hresReturn);
}
HRESULT
CMDBaseObject::RemoveDataObject(
IN CMDBaseData *pbdRemove,
IN BOOL bDelete
)
/*++
Routine Description:
Removes and optionally deletes a data object.
Arguments:
Remove - The data object to remove.
Delete - If true, the object is deleted.
Return Value:
BOOL - TRUE if the data was successfully removed.
FALSE if the data object is not associated with this metaobject.
--*/
{
HRESULT hresReturn;
MD_ASSERT (pbdRemove != NULL);
PDATA_CONTAINER *ppdcHead;
PDATA_CONTAINER pdcSave;
ppdcHead = &(m_pdcarrayDataHead[pbdRemove->GetDataType()]);
if (*ppdcHead == NULL) {
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
else {
if ((*ppdcHead)->pbdDataObject == pbdRemove) {
pdcSave = *ppdcHead;
*ppdcHead = (*ppdcHead)->NextPtr;
delete pdcSave;
hresReturn = ERROR_SUCCESS;
}
else {
PDATA_CONTAINER ppdcIndex;
for (ppdcIndex = *ppdcHead;
(ppdcIndex->NextPtr!=NULL) && (ppdcIndex->NextPtr->pbdDataObject!=pbdRemove);
ppdcIndex=ppdcIndex->NextPtr) {
}
if (ppdcIndex->NextPtr==NULL) {
hresReturn = MD_ERROR_DATA_NOT_FOUND;
}
else {
MD_ASSERT(ppdcIndex->NextPtr->pbdDataObject == pbdRemove);
pdcSave = ppdcIndex->NextPtr;
ppdcIndex->NextPtr = pdcSave->NextPtr;
delete (pdcSave);
hresReturn = ERROR_SUCCESS;
}
}
}
if (SUCCEEDED(hresReturn)) {
if ((pbdRemove->GetAttributes() & METADATA_INHERIT) == 0) {
m_dwNumNonInheritableData--;
}
if (bDelete) {
DeleteDataObject(pbdRemove);
}
SetLastChangeTime();
}
return (hresReturn);
}
CMDBaseData *
CMDBaseObject::RemoveDataObject(
IN DWORD dwIdentifier,
IN DWORD dwDataType,
IN BOOL bDelete
)
/*++
Routine Description:
Removes and optionally deletes a data object.
Arguments:
Name - The name of the data to remove.
DataType - Optional type of the data to remove. If specified, only data of that
type will be removed.
bDelete - If true, the object is deleted.
Return Value:
CMDBaseData * - Pointer to the data object removed. If bDelete == TRUE, the pointer will still be
returned, but will not be valid.
NULL if the data was not found.
--*/
{
CMDBaseData *pbdRemove;
pbdRemove=GetDataObject(dwIdentifier, METADATA_NO_ATTRIBUTES, dwDataType);
if (pbdRemove != NULL) {
MD_REQUIRE(RemoveDataObject(pbdRemove, bDelete) == ERROR_SUCCESS);
}
return(pbdRemove);
}
bool
CMDBaseObject::GenerateKey()
{
LPSTR pstr = (LPSTR) m_strMDName.QueryStrW();
if (pstr == NULL)
return FALSE;
return GenerateBufFromStr(pstr,
/* cch */ -1,
/* fUnicode */ TRUE,
&m_bufKey);
}
bool
CMDBaseObject::GenerateBufFromStr(
IN const char* pstr,
IN int cch,
IN BOOL fUnicode,
OUT CMDKeyBuffer* pbuf)
/*++
Routine Description:
Fills the given buffer with the object key based on the given string.
Arguments:
str - The string to convert into the key.
fUnicode - TRUE if the string is unicode, FALSE if ansi.
pbuf - Pointer to the buffer that will contain the new key.
Return Value:
BOOL - FALSE if out-of-memory allocating the buffer.
--*/
{
BUFFER bufUnicode; // Use this to hold unicode string if needed.
int cchRet; // Length of actual converted string.
MD_ASSERT(cch != 0); // Must either be -1 or a non-null string length.
// If not unicode, convert to unicode now.
if (!fUnicode)
{
// If we know the size, guess at the unicode size.
if (cch > 0)
if (!bufUnicode.Resize(cch*2+50))
return FALSE;
// Loop until we have big enough buffer to hold unicode string
for ( ; ; )
{
// Buffer length can't be zero, or MultiByteToWideChar() will
// interpret this by returning "required buffer length" and do
// no conversion.
MD_ASSERT(bufUnicode.QuerySize() > 1);
cchRet = MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
pstr,
cch,
(LPWSTR) bufUnicode.QueryPtr(),
bufUnicode.QuerySize()/2);
// Handle error during conversion.
if (cchRet == 0)
{
// If error wasn't lack of buffer, fail.
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return FALSE;
// Otherwise, make the buffer larger and try again.
/* else */
if (!bufUnicode.Resize(bufUnicode.QuerySize()+50))
return FALSE;
}
// Succeed, continue.
else
break;
}
// Point to the buffer now.
pstr = (char *) bufUnicode.QueryPtr();
cch = cchRet * 2;
}
// If we know the length, guess at the destination length.
if (cch > 0)
{
if (!pbuf->Resize(cch))
return FALSE;
}
// Otherwise, reset the length to whatever is allocated.
else
pbuf->SyncSize();
// Loop until we have a buffer large enough.
for ( ; ; )
{
// Buffer size can't be 0, because LCMapString will interpret
// this by returning "required buffer length" and not actually
// converting the string.
MD_ASSERT(pbuf->QuerySize() > 0);
cchRet = LCMapStringW(LOCALE_SYSTEM_DEFAULT,
LCMAP_UPPERCASE,
(LPWSTR) pstr,
(cch < 0) ? cch : cch/2,
(LPWSTR) pbuf->QueryPtr(),
pbuf->QuerySize()/2);
// Handle errors
if (cchRet == 0)
{
// If error wasn't lack of buffer, fail.
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return FALSE;
// Otherwise, make the buffer larger and try again.
/* else */
if (!pbuf->Resize(pbuf->QuerySize() + 50))
return FALSE;
}
else
break;
}
// If last character is a null-terminator, remove it in the key.
if (*((LPWSTR) pbuf->QueryPtr() + cchRet - 1) == (WCHAR) '\0')
cchRet--;
// Resize the buffer to the final length. Length includes null-terminator.
if (!pbuf->Resize(cchRet*2))
{
return FALSE;
}
return TRUE;
}
CMDBaseData *
CMDBaseObject::GetDataObjectByType(
IN DWORD dwIdentifier,
IN DWORD dwDataType
)
/*++
Routine Description:
Gets a data object from the list passed in.
Arguments:
Identifier - The identifier of the data to get.
ListHead - The head of the list to search.
Return Value:
CMDBaseData * - Pointer to the data object found.
NULL if the data was not found.
--*/
{
PDATA_CONTAINER pdcIndex;
CMDBaseData *pbdReturn = NULL;
MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
for (pdcIndex=m_pdcarrayDataHead[dwDataType];pdcIndex!=NULL;pdcIndex=pdcIndex->NextPtr) {
if (dwIdentifier == pdcIndex->pbdDataObject->GetIdentifier()) {
break;
}
}
if (pdcIndex != NULL) {
pbdReturn = pdcIndex->pbdDataObject;
}
return (pbdReturn);
}
CMDBaseData *
CMDBaseObject::GetDataObject(
IN DWORD dwIdentifier,
IN DWORD dwAttributes,
IN DWORD dwDataType,
CMDBaseObject **ppboAssociated
)
/*++
Routine Description:
Gets a data object.
Arguments:
Identifier - The identifier of the data to get.
DataType - Optional type of the data to get.
Return Value:
CMDBaseData * - Pointer to the data object found.
NULL if the data was not found.
--*/
{
CMDBaseData *pbdReturn = NULL;
DWORD i;
if (dwDataType == ALL_METADATA) {
for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
pbdReturn = GetDataObjectByType(dwIdentifier, i);
}
}
else {
pbdReturn = GetDataObjectByType(dwIdentifier, dwDataType);
}
if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
//
// Found data in this object
//
*ppboAssociated = this;
}
if ((pbdReturn == NULL) &&
(dwAttributes & METADATA_INHERIT) &&
(GetParent()!=NULL)) {
pbdReturn = GetParent()->GetInheritableDataObject(dwIdentifier,
dwDataType,
ppboAssociated);
}
return (pbdReturn);
}
CMDBaseData *
CMDBaseObject::GetInheritableDataObject(
IN DWORD dwIdentifier,
IN DWORD dwDataType,
CMDBaseObject **ppboAssociated
)
/*++
Routine Description:
Gets a data object.
Arguments:
Identifier - The identifier of the data to get.
DataType - Optional type of the data to get.
Return Value:
CMDBaseData * - Pointer to the data object found.
NULL if the data was not found.
--*/
{
CMDBaseData *pbdReturn = NULL;
DWORD i;
if (dwDataType == ALL_METADATA) {
for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
pbdReturn = GetDataObjectByType(dwIdentifier, i);
}
}
else {
pbdReturn = GetDataObjectByType(dwIdentifier, dwDataType);
}
if ((pbdReturn != NULL) &&
((pbdReturn->GetAttributes() & METADATA_INHERIT) == 0)) {
pbdReturn = NULL;
}
if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
//
// Found data in this object
//
*ppboAssociated = this;
}
if ((pbdReturn == NULL) && (GetParent() != NULL)) {
pbdReturn = GetParent()->GetInheritableDataObject(dwIdentifier,
dwDataType,
ppboAssociated);
}
return (pbdReturn);
}
CMDBaseData *
CMDBaseObject::EnumDataObjectByType(
IN DWORD &dwEnumDataIndex,
IN DWORD dwUserType,
IN DWORD dwDataType
)
/*++
Routine Description:
Gets a data object from the list passed in.
Arguments:
EnumDataIndex - The 0 based index of the data to get.
Updated by the number of matching entries found,
not including the entry returned, if any.
UserType - Optional UserType of the data to get.
ListHead - The head of the list to search.
Return Value:
CMDBaseData * - Pointer to the data object found.
NULL if the data was not found.
--*/
{
PDATA_CONTAINER pdcIndex;
CMDBaseData *dataReturn = NULL;
MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
if (dwUserType == ALL_METADATA) {
for (pdcIndex = m_pdcarrayDataHead[dwDataType];
(pdcIndex!=NULL) && dwEnumDataIndex != 0;
pdcIndex=pdcIndex->NextPtr, dwEnumDataIndex--) {
}
}
else {
for (pdcIndex=m_pdcarrayDataHead[dwDataType];
(pdcIndex!=NULL);
pdcIndex=pdcIndex->NextPtr) {
if (dwUserType == pdcIndex->pbdDataObject->GetUserType()) {
if (dwEnumDataIndex == 0) {
break;
}
dwEnumDataIndex--;
}
}
}
if (pdcIndex != NULL) {
dataReturn = pdcIndex->pbdDataObject;
}
return (dataReturn);
}
CMDBaseData *
CMDBaseObject::EnumDataObject(
IN DWORD dwEnumDataIndex,
IN DWORD dwAttributes,
IN DWORD dwUserType,
IN DWORD dwDataType,
CMDBaseObject **ppboAssociated
)
/*++
Routine Description:
Enumerates a data object.
Arguments:
EnumDataIndex - The 0 based index of the data to get.
Attributes - Specifies the Attributes of the get operation.
UserType - Optional UserType of the data to get.
DataType - Optional type of the data to get.
Return Value:
CMDBaseData * - Pointer to the data object found.
NULL if the data was not found.
--*/
{
CMDBaseData *pbdReturn = NULL;
PVOID *ppvMainDataBuf;
DWORD dwNumBufferEntries;
DWORD i;
if (dwDataType == ALL_METADATA) {
for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
pbdReturn = EnumDataObjectByType(dwEnumDataIndex, dwUserType, i);
}
}
else {
pbdReturn = EnumDataObjectByType(dwEnumDataIndex, dwUserType, dwDataType);
}
if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
//
// Found data in this object
//
*ppboAssociated = this;
}
if ((pbdReturn == NULL) && (dwAttributes & METADATA_INHERIT) && (GetParent() != NULL)) {
//
// Not in current object and inherited data is specified.
// Build list of data objects in current meta object,
// and call parent for inherited data.
//
ppvMainDataBuf = GetMainDataBuffer();
MD_ASSERT (ppvMainDataBuf != NULL);
dwNumBufferEntries = 0;
CopyDataObjectsToBuffer(dwUserType, dwDataType, ppvMainDataBuf, dwNumBufferEntries, FALSE, FALSE);
pbdReturn = GetParent()->EnumInheritableDataObject(dwEnumDataIndex,
dwUserType,
dwDataType,
ppvMainDataBuf,
dwNumBufferEntries,
ppboAssociated);
FreeMainDataBuffer(ppvMainDataBuf);
}
return (pbdReturn);
}
CMDBaseData *
CMDBaseObject::EnumInheritableDataObjectByType(
IN DWORD &dwEnumDataIndex,
IN DWORD dwUserType,
IN DWORD dwDataType,
IN OUT PVOID *ppvMainDataBuf,
IN OUT DWORD &dwNumBufferEntries)
/*++
Routine Description:
Gets a data object from the list passed in.
Arguments:
EnumDataIndex - The 0 based index of the data to get.
Updated by the number of matching entries found,
not including the entry returned, if any.
UserType - Optional UserType of the data to get.
ListHead - The head of the list to search.
MainDataBuf - The buffer filled with previously enumerated values.
NumBufferEntries - The number of entries in MainDataBuf.
Return Value:
CMDBaseData * - Pointer to the data object found.
NULL if the data was not found.
--*/
{
PDATA_CONTAINER pdcIndex;
CMDBaseData *pbdReturn = NULL;
BOOL bRet;
MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
if (dwUserType == ALL_METADATA) {
for (pdcIndex = m_pdcarrayDataHead[dwDataType];
(pdcIndex!=NULL);
pdcIndex=pdcIndex->NextPtr) {
if (((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
!IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf)) {
if (dwEnumDataIndex == 0) {
break;
}
else {
bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
MD_ASSERT(bRet);
if (!bRet) {
pdcIndex = NULL;
break;
}
}
dwEnumDataIndex--;
}
}
}
else {
for (pdcIndex = m_pdcarrayDataHead[dwDataType];
(pdcIndex!=NULL);
pdcIndex=pdcIndex->NextPtr) {
if (dwUserType == pdcIndex->pbdDataObject->GetUserType() &&
((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
!IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf)) {
if (dwEnumDataIndex == 0) {
break;
}
else {
bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
MD_ASSERT(bRet);
if (!bRet) {
pdcIndex = NULL;
break;
}
}
dwEnumDataIndex--;
}
}
}
if (pdcIndex != NULL) {
pbdReturn = pdcIndex->pbdDataObject;
}
return (pbdReturn);
}
CMDBaseData *
CMDBaseObject::EnumInheritableDataObject(
DWORD &dwEnumDataIndex,
DWORD dwUserType,
DWORD dwDataType,
CMDBaseObject **ppboAssociated)
{
PVOID *ppvMainDataBuf = GetMainDataBuffer();
DWORD dwNumBufferEntries = 0;
CMDBaseData *pbdReturn;
MD_ASSERT(ppvMainDataBuf != NULL);
pbdReturn = EnumInheritableDataObject(dwEnumDataIndex,
dwUserType,
dwDataType,
ppvMainDataBuf,
dwNumBufferEntries,
ppboAssociated);
FreeMainDataBuffer(ppvMainDataBuf);
return(pbdReturn);
}
CMDBaseData *
CMDBaseObject::EnumInheritableDataObject(
IN OUT DWORD &dwEnumDataIndex,
IN DWORD dwUserType,
IN DWORD dwDataType,
IN OUT PVOID *ppvMainDataBuf,
IN OUT DWORD &dwNumBufferEntries,
CMDBaseObject **ppboAssociated)
{
CMDBaseData *pbdReturn = NULL;
DWORD i;
if (dwDataType == ALL_METADATA) {
for (i = 1; (pbdReturn == NULL) && (i < INVALID_END_METADATA); i++) {
pbdReturn = EnumInheritableDataObjectByType(dwEnumDataIndex,
dwUserType,
i,
ppvMainDataBuf,
dwNumBufferEntries);
}
}
else {
pbdReturn = EnumInheritableDataObjectByType(dwEnumDataIndex,
dwUserType,
dwDataType,
ppvMainDataBuf,
dwNumBufferEntries);
}
if ((ppboAssociated != NULL) && (pbdReturn != NULL)) {
//
// Found data in this object
//
*ppboAssociated = this;
}
if ((pbdReturn == NULL) && (GetParent() != NULL)) {
//
// Not in current object.
// Call parent for inherited data.
//
pbdReturn = GetParent()->EnumInheritableDataObject(dwEnumDataIndex,
dwUserType,
dwDataType,
ppvMainDataBuf,
dwNumBufferEntries,
ppboAssociated);
}
return (pbdReturn);
}
VOID
CMDBaseObject::CopyDataObjectsToBufferByType(
IN DWORD dwUserType,
IN DWORD dwDataType,
OUT PVOID *ppvMainDataBuf,
IN OUT DWORD &dwNumBufferEntries,
IN BOOL bInheritableOnly,
IN BOOL bNonSecureOnly)
/*++
Routine Description:
Copies all data objects which match the criteria specified
by the parameters to MainDataBuf.
Arguments:
UserType - Optional UserType of the data to copy.
ListHead - The list of data objects.
MainDataBuf - The buffer to copy the data objects to.
NumBufferEntries - The Number of data objects in MainDataBuf.
bInheritableOnly - If TRUE, only copies data objects that are
inheritable and not already in the buffer.
bNonSecureOnly - If TRUE, then only retrieve non-secure properties
Return Value:
--*/
{
PDATA_CONTAINER pdcIndex;
BOOL bRet;
MD_ASSERT((dwDataType > ALL_METADATA) && (dwDataType < INVALID_END_METADATA));
if (dwUserType == ALL_METADATA) {
for (pdcIndex = m_pdcarrayDataHead[dwDataType];
(pdcIndex!=NULL);
pdcIndex=pdcIndex->NextPtr) {
if ((!bInheritableOnly) ||
(((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
!IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf))){
if (bNonSecureOnly && pdcIndex->pbdDataObject->GetAttributes() & METADATA_SECURE) {
continue;
}
bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
MD_ASSERT(bRet);
if (!bRet) {
break;
}
}
}
}
else {
for (pdcIndex = m_pdcarrayDataHead[dwDataType];
(pdcIndex!=NULL);
pdcIndex=pdcIndex->NextPtr) {
if (dwUserType == pdcIndex->pbdDataObject->GetUserType()) {
if ((!bInheritableOnly) ||
(((pdcIndex->pbdDataObject->GetAttributes() & METADATA_INHERIT) != 0) &&
!IsDataInBuffer(pdcIndex->pbdDataObject->GetIdentifier(), ppvMainDataBuf))){
if (bNonSecureOnly && pdcIndex->pbdDataObject->GetAttributes() & METADATA_SECURE) {
continue;
}
bRet = InsertItemIntoDataBuffer((PVOID)pdcIndex->pbdDataObject, ppvMainDataBuf, dwNumBufferEntries);
MD_ASSERT(bRet);
if (!bRet) {
break;
}
}
}
}
}
}
VOID
CMDBaseObject::CopyDataObjectsToBuffer(
IN DWORD dwUserType,
IN DWORD dwDataType,
OUT PVOID *ppvMainDataBuf,
IN OUT DWORD &dwNumBufferEntries,
IN BOOL bInheritableOnly,
IN BOOL bNonSecureOnly)
/*++
Routine Description:
Copies all data objects which match the criteria specified
by the parameters to MainDataBuf.
Arguments:
UserType - Optional UserType of the data to copy.
DataType - Optional UserType of the data to copy.
MainDataBuf - The buffer to copy the data objects to.
NumBufferEntries - The Number of data objects in MainDataBuf.
bInheritableOnly - If TRUE, only copies data objects that are
inheritable and not already in the buffer.
bNonSecureOnly - If TRUE, then copy only non-secure properties
Return Value:
--*/
{
DWORD i;
if (dwDataType == ALL_METADATA) {
for (i = 1; i < INVALID_END_METADATA; i++) {
CopyDataObjectsToBufferByType(dwUserType, i, ppvMainDataBuf, dwNumBufferEntries, bInheritableOnly, bNonSecureOnly);
}
}
else {
CopyDataObjectsToBufferByType(dwUserType, dwDataType, ppvMainDataBuf, dwNumBufferEntries, bInheritableOnly, bNonSecureOnly);
}
}
DWORD
CMDBaseObject::GetAllDataObjects(
OUT PVOID *ppvMainDataBuf,
IN DWORD dwAttributes,
IN DWORD dwUserType,
IN DWORD dwDataType,
IN BOOL bInheritableOnly,
IN BOOL bNonSecureOnly
)
/*++
Routine Description:
Gets all data objects which match the criteria specified by the parameters.
Arguments:
MainDataBuf - The buffer to store the data objects in.
Attributes - Specifies the Attributes of the get operation.
UserType - Optional UserType of the data to get.
DataType - Optional type of the data to get.
bInheritableOnly - If TRUE, only gets data objects that are
inheritable and not already in the buffer.
bNonSecureOnly - If TRUE, only copy non-secure properties
Return Value:
DWORD - Number of Data Objects in Buffer.
--*/
{
DWORD dwNumBufferEntries;
CMDBaseObject *objIndex;
//
// Not in current object and inherited data is specified.
// Build list of data objects in current meta object,
// and call parent for inherited data.
//
MD_ASSERT (ppvMainDataBuf != NULL);
dwNumBufferEntries = 0;
CopyDataObjectsToBuffer(dwUserType,
dwDataType,
ppvMainDataBuf,
dwNumBufferEntries,
bInheritableOnly,
bNonSecureOnly);
if (dwAttributes & METADATA_INHERIT) {
for (objIndex = GetParent(); objIndex != NULL; objIndex = objIndex->GetParent()) {
objIndex->CopyDataObjectsToBuffer(dwUserType,
dwDataType,
ppvMainDataBuf,
dwNumBufferEntries,
TRUE,
bNonSecureOnly);
}
}
return (dwNumBufferEntries);
}
HRESULT
CMDBaseObject::GetDataRecursive(
IN OUT BUFFER *pbufMainDataBuf,
IN DWORD dwMDIdentifier,
IN DWORD dwMDDataType,
IN OUT DWORD &rdwNumMetaObjects)
{
CMDBaseObject *pboChild;
DWORD i;
MD_ASSERT (pbufMainDataBuf != NULL);
HRESULT hresReturn = ERROR_SUCCESS;
if (GetDataObject(dwMDIdentifier,
METADATA_NO_ATTRIBUTES,
dwMDDataType,
NULL) != NULL) {
DWORD dwSize = sizeof(CMDBaseObject *) * (rdwNumMetaObjects + 1);
if (pbufMainDataBuf->QuerySize() < dwSize) {
if (!pbufMainDataBuf->Resize(dwSize + (sizeof(CMDBaseObject *) * 1000))) {
hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
}
}
if (SUCCEEDED(hresReturn)) {
((CMDBaseObject **)(pbufMainDataBuf->QueryPtr()))[rdwNumMetaObjects++] = (CMDBaseObject *)this;
}
}
for (i = 0;
SUCCEEDED(hresReturn) &&
(pboChild = EnumChildObject(i)) != NULL;
i++) {
hresReturn = pboChild->GetDataRecursive(pbufMainDataBuf,
dwMDIdentifier,
dwMDDataType,
rdwNumMetaObjects);
}
return hresReturn;
}
VOID
CMDBaseObject::SetLastChangeTime(PFILETIME pftLastChangeTime)
{
if (pftLastChangeTime != NULL) {
m_ftLastChangeTime = *pftLastChangeTime;
}
else {
GetSystemTimeAsFileTime(&m_ftLastChangeTime);
}
}
PFILETIME
CMDBaseObject::GetLastChangeTime()
{
return &m_ftLastChangeTime;
}
DWORD
CMDBaseObject::GetObjectLevel()
{
DWORD dwLevel = 0;
if (m_pboParent != NULL) {
dwLevel = m_pboParent->GetObjectLevel() + 1;
}
return dwLevel;
}
BOOL
CMDBaseObject::IsDataInBuffer(
IN DWORD dwIdentifier,
IN PVOID *ppvMainDataBuf)
/*++
Routine Description:
Checks if the buffer contains an object with the specified id.
Arguments:
Identifier - The id to check for.
MainDataBuf - The buffer to search.
Return Value:
BOOL - TRUE if the buffer contains data with the specified id.
--*/
{
BOOL bReturn = FALSE;
DWORD i;
CMDBaseData *pbdDataObject;
for (i = 0;
(pbdDataObject = (CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i)) != NULL;
i++) {
if (pbdDataObject->GetIdentifier() == dwIdentifier) {
bReturn = TRUE;
break;
}
}
return (bReturn);
}
#if 0 // No longer used. /SAB
BOOL
CMDBaseObject::CompareDelimitedString(
IN LPTSTR strNonDelimitedString,
IN OUT LPTSTR &strDelimitedString,
IN BOOL bUnicode)
/*++
Routine Description:
Compared a nondelimeted string to a delimeted string.
Updates Delimited String on success to point past the string.
Arguments:
NonDelimiterString - The nondelimited string.
DelimiterString - The delimited string.
Return Value:
BOOL - TRUE if strings are the same.
--*/
{
LPTSTR i,j;
BOOL RetCode = FALSE;
j = strDelimitedString;
DWORD dwStringLen;
/*
//
// Change in semantics. To differentiate between "/" and "//",
// the leading delimeter is skipped before we get here.
//
// Skip leading delimeter, if any
//
if ((*j == MD_PATH_DELIMETER) || (*j == MD_ALT_PATH_DELIMETER)) {
j++;
}
*/
if (bUnicode) {
dwStringLen = wcslen((LPWSTR)strNonDelimitedString);
//
// Compare up to delimiter
// Actually we don't need to check for the delimiter here
// because NonDelimitedString cannot contain delimiter, so
// *j==*i will fail on delimiter. Also do not need to check if *i
// == \0 because *j==*i would fail if *j were not also equal to \0
// for (i=strNonDelimitedString;((*j == *i) && (*j!=(TCHAR)'\0'));i++,j++) {
// }
if (_wcsnicmp((LPWSTR)strDelimitedString, (LPWSTR)strNonDelimitedString, dwStringLen) == 0) {
if (((*((LPWSTR)strDelimitedString + dwStringLen)==MD_ALT_PATH_DELIMETERW) ||
(*((LPWSTR)strDelimitedString + dwStringLen)==MD_PATH_DELIMETERW) ||
(*((LPWSTR)strDelimitedString + dwStringLen)== (WCHAR)'\0'))) { //We have a match
RetCode = TRUE;
strDelimitedString += dwStringLen * sizeof(WCHAR); //Point to next section or \0
}
}
}
else {
dwStringLen = MD_STRLEN(strNonDelimitedString);
//
// Compare up to delimiter
// Actually we don't need to check for the delimiter here
// because NonDelimitedString cannot contain delimiter, so
// *j==*i will fail on delimiter. Also do not need to check if *i
// == \0 because *j==*i would fail if *j were not also equal to \0
// for (i=strNonDelimitedString;((*j == *i) && (*j!=(TCHAR)'\0'));i++,j++) {
// }
if (MD_STRNICMP(strDelimitedString, strNonDelimitedString, dwStringLen) == 0) {
DWORD dwStrBytes = MD_STRBYTES(strNonDelimitedString);
if (((*(strDelimitedString + dwStrBytes)==MD_ALT_PATH_DELIMETERA) ||
(*(strDelimitedString + dwStrBytes)==MD_PATH_DELIMETERA) ||
(*(strDelimitedString + dwStrBytes)== (CHAR)'\0'))) { //We have a match
RetCode = TRUE;
strDelimitedString += dwStrBytes; //Point to next section or \0
}
}
}
return (RetCode);
}
#endif
CMDBaseObject*
CMDBaseObject::FindChild(
LPSTR szName, // Name of child to find.
int cchName, // Length of the name.
BOOL fUnicode, // TRUE if unicode name.
HRESULT* phresult, // Result code.
BOOL fUseHash, // Allow use of hash table
BASEOBJECT_CONTAINER** ppbocPrev) // If non-NULL & !fUseHash, prev. object container in list.
{
UCHAR localBufferForBufKey[SIZE_FOR_ON_STACK_BUFFER];
CMDKeyBuffer bufKey (localBufferForBufKey,SIZE_FOR_ON_STACK_BUFFER);
BASEOBJECT_CONTAINER* pbocCurrent = NULL;
MD_ASSERT(phresult != NULL);
//
// Trap case of being called with an empty path segment.
// GenerateBufFromStr should not be called with cch == 0
//
if( cchName == 0 )
{
*phresult = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
return NULL;
}
// Convert the given string to a key.
if (!GenerateBufFromStr(szName, cchName, fUnicode, &bufKey))
{
*phresult = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
// Use hash table if it exists and we are allowed to.
if (fUseHash && m_phtChildren != NULL)
{
m_phtChildren->FindKey(&bufKey, &pbocCurrent);
}
// Otherwise use brute force linear search.
else
{
BASEOBJECT_CONTAINER* pbocPrev = NULL;
pbocCurrent = m_pbocChildHead;
while (pbocCurrent != NULL &&
!FCompareKeys(&bufKey, &pbocCurrent->pboMetaObject->m_bufKey))
{
pbocPrev = pbocCurrent;
pbocCurrent = pbocCurrent->NextPtr;
}
if (ppbocPrev != NULL)
*ppbocPrev = pbocPrev;
}
*phresult = ERROR_SUCCESS;
if (pbocCurrent != NULL)
return pbocCurrent->pboMetaObject;
/* else */
return NULL;
}
void CMDBaseObject::CascadingDataCleanup()
/*++
Routine Description:
Deletes all data and recursively deletes all data of child objects.
Arguments:
Return Value:
--*/
{
PDATA_CONTAINER pdcIndex, pdcSave;
PBASEOBJECT_CONTAINER pbocIndex, pbocSave;
int i;
for (i = 1; i < INVALID_END_METADATA; i++) {
for (pdcIndex=m_pdcarrayDataHead[i];pdcIndex!=NULL;pdcIndex=pdcSave) {
pdcSave=pdcIndex->NextPtr;
delete(pdcIndex);
}
m_pdcarrayDataHead[i] = NULL;
}
for (pbocIndex=m_pbocChildHead;pbocIndex!=NULL;pbocIndex=pbocSave) {
pbocSave=pbocIndex->NextPtr;
pbocIndex->pboMetaObject->CascadingDataCleanup();
}
return;
}