#include "CDSRefTable.h"
#include <stdlib.h>
#include <string.h>
#include <syslog.h> // for syslog() to log calls
#include <libkern/OSAtomic.h>
CDSRefTable::CDSRefTable ( void ) : fTableMutex( "CDSRefTable::fTableMutex", false )
{
fTableCount = 0;
fRefCount = 0;
memset( fRefTables, 0, sizeof( fRefTables ) );
}
CDSRefTable::~CDSRefTable ( void )
{
ClearAllTables();
}
void CDSRefTable::ClearAllTables( void )
{
UInt32 i = 1;
UInt32 j = 1;
fTableMutex.WaitLock();
for ( i = 1; i <= kMaxFWTables; i++ ) {
if ( fRefTables[ i ] != nil )
{
for (j=0; j< kMaxFWTableItems; j++)
{
if (fRefTables[ i ]->fTableData[j] != nil)
{
free(fRefTables[ i ]->fTableData[j]);
fRefTables[ i ]->fTableData[j] = nil;
}
}
free( fRefTables[ i ] ); fRefTables[ i ] = nil;
fTableCount--;
}
}
fTableMutex.SignalLock();
}
tDirStatus CDSRefTable::VerifyReference ( tDirReference inDirRef,
UInt32 inType,
SInt32 inPID )
{
tDirStatus siResult = eDSNoErr;
sFWRefEntry *refData = nil;
sPIDFWInfo *pPIDInfo = nil;
siResult = GetReference( inDirRef, &refData );
if ( siResult == eDSNoErr )
{
if ( refData->fType != inType )
{
siResult = eDSInvalidRefType;
}
else
{
siResult = eDSInvalidRefType;
if (refData->fPID == inPID)
{
siResult = eDSNoErr;
}
else
{
pPIDInfo = refData->fChildPID;
while ( (pPIDInfo != nil) && (siResult != eDSNoErr) )
{
if (pPIDInfo->fPID == inPID)
{
siResult = eDSNoErr;
}
pPIDInfo = pPIDInfo->fNext;
}
}
}
}
return( siResult );
}
tDirStatus CDSRefTable::VerifyDirRef ( tDirReference inDirRef,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = VerifyReference( inDirRef, eDirectoryRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::VerifyNodeRef ( tDirNodeReference inDirNodeRef,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = VerifyReference( inDirNodeRef, eNodeRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::VerifyRecordRef ( tRecordReference inRecordRef,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = VerifyReference( inRecordRef, eRecordRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::VerifyAttrListRef ( tAttributeListRef inAttributeListRef,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = VerifyReference( inAttributeListRef, eAttrListRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::VerifyAttrValueRef ( tAttributeValueListRef inAttributeValueListRef,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = VerifyReference( inAttributeValueListRef, eAttrValueListRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::NewDirRef ( UInt32 *outNewRef, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = GetNewRef( outNewRef, 0, eDirectoryRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::NewNodeRef ( UInt32 *outNewRef,
UInt32 inParentID,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = GetNewRef( outNewRef, inParentID, eNodeRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::NewRecordRef ( UInt32 *outNewRef,
UInt32 inParentID,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = GetNewRef( outNewRef, inParentID, eRecordRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::NewAttrListRef ( UInt32 *outNewRef,
UInt32 inParentID,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = GetNewRef( outNewRef, inParentID, eAttrListRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::NewAttrValueRef ( UInt32 *outNewRef,
UInt32 inParentID,
SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = GetNewRef( outNewRef, inParentID, eAttrValueListRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::RemoveDirRef ( UInt32 inDirRef, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = RemoveRef( inDirRef, eDirectoryRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::RemoveNodeRef ( UInt32 inNodeRef, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = RemoveRef( inNodeRef, eNodeRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::RemoveRecordRef ( UInt32 inRecRef, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = RemoveRef( inRecRef, eRecordRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::RemoveAttrListRef ( UInt32 inAttrListRef, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = RemoveRef( inAttrListRef, eAttrListRefType, inPID );
return( siResult );
}
tDirStatus CDSRefTable::RemoveAttrValueRef ( UInt32 inAttrValueRef, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
siResult = RemoveRef( inAttrValueRef, eAttrValueListRefType, inPID );
return( siResult );
}
sFWRefEntry* CDSRefTable::GetTableRef ( UInt32 inRefNum )
{
UInt32 uiSlot = 0;
UInt32 uiRefNum = (inRefNum & 0x00FFFFFF);
UInt32 uiTableNum = (inRefNum & 0xFF000000) >> 24;
sRefFWTable *pTable = nil;
sFWRefEntry *pOutEntry = nil;
fTableMutex.WaitLock();
try
{
pTable = GetThisTable( uiTableNum );
if ( pTable == nil ) throw( (SInt32)eDSInvalidReference );
uiSlot = uiRefNum % kMaxFWTableItems;
if ( pTable->fTableData != nil)
{
if ( pTable->fTableData[ uiSlot ] != nil )
{
if ( uiRefNum == pTable->fTableData[ uiSlot ]->fRefNum )
{
pOutEntry = pTable->fTableData[ uiSlot ];
}
}
}
}
catch( SInt32 err )
{
}
fTableMutex.SignalLock();
return( pOutEntry );
}
sRefFWTable* CDSRefTable::GetNextTable ( sRefFWTable *inTable )
{
UInt32 uiTblNum = 0;
sRefFWTable *pOutTable = nil;
fTableMutex.WaitLock();
try
{
if ( inTable == nil )
{
if ( fRefTables[ 1 ] == nil )
{
fRefTables[ 1 ] = (sRefFWTable *)::calloc( sizeof( sRefFWTable ), sizeof( char ) );
if ( fRefTables[ 1 ] == nil ) throw((SInt32)eMemoryAllocError);
fRefTables[ 1 ]->fTableNum = 1;
fTableCount = 1;
}
pOutTable = fRefTables[ 1 ];
}
else
{
uiTblNum = inTable->fTableNum + 1;
if (uiTblNum > kMaxFWTables) throw( (SInt32)eDSInvalidReference );
if ( fRefTables[ uiTblNum ] == nil )
{
fTableCount = uiTblNum;
fRefTables[ uiTblNum ] = (sRefFWTable *)::calloc( sizeof( sRefFWTable ), sizeof( char ) );
if ( fRefTables[ uiTblNum ] == nil ) throw((SInt32)eMemoryAllocError);
if (uiTblNum == 0) throw( (SInt32)eDSInvalidReference );
fRefTables[ uiTblNum ]->fTableNum = uiTblNum;
}
pOutTable = fRefTables[ uiTblNum ];
}
}
catch( SInt32 err )
{
}
fTableMutex.SignalLock();
return( pOutTable );
}
sRefFWTable* CDSRefTable::GetThisTable ( UInt32 inTableNum )
{
sRefFWTable *pOutTable = nil;
fTableMutex.WaitLock();
pOutTable = fRefTables[ inTableNum ];
fTableMutex.SignalLock();
return( pOutTable );
}
tDirStatus CDSRefTable::GetNewRef ( UInt32 *outRef,
UInt32 inParentID,
eRefTypes inType,
SInt32 inPID )
{
bool done = false;
tDirStatus outResult = eDSNoErr;
sRefFWTable *pCurTable = nil;
UInt32 uiRefNum = 0;
UInt32 uiCntr = 0;
UInt32 uiSlot = 0;
UInt32 uiTableNum = 0;
fTableMutex.WaitLock();
try
{
*outRef = 0;
while ( !done )
{
pCurTable = GetNextTable( pCurTable );
if ( pCurTable == nil ) throw( (SInt32)eDSRefTableCSBPAllocError );
if ( pCurTable->fItemCnt < kMaxFWTableItems )
{
uiCntr = 0;
uiTableNum = pCurTable->fTableNum;
while ( (uiCntr < kMaxFWTableItems) && !done ) {
if ( (pCurTable->fCurRefNum == 0) ||
(pCurTable->fCurRefNum > 0x000FFFFF) )
{
pCurTable->fCurRefNum = 1;
}
uiRefNum = pCurTable->fCurRefNum++;
uiRefNum += 0x00300000;
uiSlot = uiRefNum % kMaxFWTableItems;
if ( pCurTable->fTableData[ uiSlot ] == nil )
{
pCurTable->fTableData[ uiSlot ] = (sFWRefEntry *)::calloc( sizeof( sFWRefEntry ), sizeof( char ) );
if ( pCurTable->fTableData[ uiSlot ] == nil ) throw( (SInt32)eDSRefTableCSBPAllocError );
pCurTable->fTableData[ uiSlot ]->fRefNum = uiRefNum;
pCurTable->fTableData[ uiSlot ]->fType = inType;
pCurTable->fTableData[ uiSlot ]->fParentID = inParentID;
pCurTable->fTableData[ uiSlot ]->fPID = inPID;
pCurTable->fTableData[ uiSlot ]->fOffset = 0;
pCurTable->fTableData[ uiSlot ]->fBufTag = 0;
pCurTable->fTableData[ uiSlot ]->fChildren = nil;
pCurTable->fTableData[ uiSlot ]->fChildPID = nil;
uiTableNum = (uiTableNum << 24);
uiRefNum = uiRefNum | uiTableNum;
*outRef = uiRefNum;
pCurTable->fItemCnt++;
fRefCount++;
outResult = eDSNoErr;
done = true;
}
uiCntr++; }
}
}
if ( inParentID != 0 )
{
outResult = LinkToParent( *outRef, inType, inParentID, inPID );
}
}
catch( SInt32 err )
{
outResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( outResult );
}
tDirStatus CDSRefTable::LinkToParent ( UInt32 inRefNum, UInt32 inType, UInt32 inParentID, SInt32 inPID )
{
tDirStatus dsResult = eDSNoErr;
sFWRefEntry *pCurrRef = nil;
sListFWInfo *pChildInfo = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inParentID );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
pChildInfo = (sListFWInfo *)::calloc( sizeof( sListFWInfo ), sizeof( char ) );
if ( pChildInfo == nil ) throw( (SInt32)eDSRefTableCSBPAllocError );
pChildInfo->fRefNum = inRefNum;
pChildInfo->fType = inType;
pChildInfo->fPID = inPID;
pChildInfo->fNext = pCurrRef->fChildren;
pCurrRef->fChildren = pChildInfo;
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CDSRefTable::UnlinkFromParent ( UInt32 inRefNum )
{
tDirStatus dsResult = eDSNoErr;
UInt32 i = 1;
UInt32 parentID = 0;
sFWRefEntry *pCurrRef = nil;
sFWRefEntry *pParentRef = nil;
sListFWInfo *pCurrChild = nil;
sListFWInfo *pPrevChild = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inRefNum );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
parentID = pCurrRef->fParentID;
if ( parentID != 0 )
{
pParentRef = GetTableRef( parentID );
if ( pParentRef == nil ) throw( (SInt32)eDSInvalidReference );
pCurrChild = pParentRef->fChildren;
pPrevChild = pParentRef->fChildren;
while ( pCurrChild != nil )
{
if ( pCurrChild->fRefNum == inRefNum )
{
if ( i == 1 )
{
pParentRef->fChildren = pCurrChild->fNext;
}
else
{
pPrevChild->fNext = pCurrChild->fNext;
}
free( pCurrChild );
pCurrChild = nil;
break;
}
pPrevChild = pCurrChild;
pCurrChild = pCurrChild->fNext;
i++;
}
}
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CDSRefTable::GetReference ( UInt32 inRefNum, sFWRefEntry **outRefData )
{
tDirStatus dsResult = eDSNoErr;
sFWRefEntry *pCurrRef = nil;
fTableMutex.WaitLock();
try
{
pCurrRef = GetTableRef( inRefNum );
if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
*outRefData = pCurrRef;
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
tDirStatus CDSRefTable::RemoveRef ( UInt32 inRefNum, UInt32 inType, SInt32 inPID )
{
tDirStatus dsResult = eDSNoErr;
sFWRefEntry *pCurrRef = nil;
sRefFWTable *pTable = nil;
UInt32 uiSlot = 0;
UInt32 uiTableNum = (inRefNum & 0xFF000000) >> 24;
UInt32 uiRefNum = (inRefNum & 0x00FFFFFF);
bool doFree = false;
sPIDFWInfo *pPIDInfo = nil;
sPIDFWInfo *pPrevPIDInfo = nil;
fTableMutex.WaitLock();
try
{
dsResult = VerifyReference( inRefNum, inType, inPID );
if ( dsResult == eDSNoErr )
{
pTable = GetThisTable( uiTableNum );
if ( pTable == nil ) throw( (SInt32)eDSInvalidReference );
uiSlot = uiRefNum % kMaxFWTableItems;
if ( inType != eDirectoryRefType ) {
dsResult = UnlinkFromParent( inRefNum );
if ( dsResult != eDSNoErr ) throw( (SInt32)dsResult );
}
pCurrRef = GetTableRef( inRefNum ); if ( pCurrRef == nil ) throw( (SInt32)eDSInvalidReference );
if (inType != pCurrRef->fType) throw( (SInt32)eDSInvalidReference );
if ( pCurrRef->fChildren != nil )
{
fTableMutex.SignalLock();
RemoveChildren( pCurrRef->fChildren, inPID );
fTableMutex.WaitLock();
}
if (pCurrRef->fPID == inPID)
{
pCurrRef->fPID = -1;
if (pCurrRef->fChildPID == nil)
{
doFree = true;
}
}
else
{
pPIDInfo = pCurrRef->fChildPID;
pPrevPIDInfo = pCurrRef->fChildPID;
while (pPIDInfo != nil)
{
if (pPIDInfo->fPID == inPID)
{
if (pPIDInfo == pCurrRef->fChildPID)
{
pCurrRef->fChildPID = pCurrRef->fChildPID->fNext;
free(pPIDInfo);
pPIDInfo = pCurrRef->fChildPID;
pPrevPIDInfo = pCurrRef->fChildPID;
}
else
{
pPrevPIDInfo->fNext = pPIDInfo->fNext;
free(pPIDInfo);
pPIDInfo = pPrevPIDInfo->fNext;
}
}
else
{
pPrevPIDInfo = pPIDInfo;
pPIDInfo = pPIDInfo->fNext;
}
}
if ( (pCurrRef->fPID == -1) && (pCurrRef->fChildPID == nil) )
{
doFree = true;
}
}
if (doFree)
{
if ( pTable->fTableData[ uiSlot ] != nil )
{
if ( uiRefNum == pTable->fTableData[ uiSlot ]->fRefNum )
{
pCurrRef = pTable->fTableData[ uiSlot ];
pTable->fTableData[ uiSlot ] = nil;
pTable->fItemCnt--;
fRefCount--;
if ( (pCurrRef->fBufTag == 'DbgA') || (pCurrRef->fBufTag == 'DbgB') )
{
if (inType == eAttrListRefType)
{
syslog(LOG_CRIT, "DS:dsCloseAttributeList:CDSRefTable::RemoveAttrListRef ref = %d", inRefNum);
}
else if (inType == eAttrValueListRefType)
{
syslog(LOG_CRIT, "DS:dsCloseAttributeValueList:CDSRefTable::RemoveAttrValueRef ref = %d", inRefNum);
}
}
free(pCurrRef);
pCurrRef = nil;
}
}
}
}
}
catch( SInt32 err )
{
dsResult = (tDirStatus)err;
}
fTableMutex.SignalLock();
return( dsResult );
}
void CDSRefTable::RemoveChildren ( sListFWInfo *inChildList, SInt32 inPID )
{
sListFWInfo *pCurrChild = nil;
sListFWInfo *pNextChild = nil;
fTableMutex.WaitLock();
try
{
pCurrChild = inChildList;
while ( pCurrChild != nil )
{
pNextChild = pCurrChild->fNext;
if ( pCurrChild->fPID == inPID )
{
fTableMutex.SignalLock();
RemoveRef( pCurrChild->fRefNum, pCurrChild->fType, inPID );
fTableMutex.WaitLock();
}
pCurrChild = pNextChild;
}
}
catch( SInt32 err )
{
}
fTableMutex.SignalLock();
}
tDirStatus CDSRefTable::GetOffset ( UInt32 inRefNum, UInt32 inType, UInt32* outOffset, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
sFWRefEntry *pCurrRef = nil;
siResult = VerifyReference( inRefNum, inType, inPID );
if (siResult == eDSNoErr)
{
pCurrRef = GetTableRef( inRefNum );
siResult = eDSInvalidReference;
if ( pCurrRef != nil )
{
*outOffset = pCurrRef->fOffset;
siResult = eDSNoErr;
}
}
return( siResult );
}
tDirStatus CDSRefTable::SetOffset ( UInt32 inRefNum, UInt32 inType, UInt32 inOffset, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
sFWRefEntry *pCurrRef = nil;
siResult = VerifyReference( inRefNum, inType, inPID );
if (siResult == eDSNoErr)
{
pCurrRef = GetTableRef( inRefNum );
siResult = eDSInvalidReference;
if ( pCurrRef != nil )
{
pCurrRef->fOffset = inOffset;
siResult = eDSNoErr;
}
}
return( siResult );
}
tDirStatus CDSRefTable::GetBufTag ( UInt32 inRefNum, UInt32 inType, UInt32* outBufTag, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
sFWRefEntry *pCurrRef = nil;
siResult = VerifyReference( inRefNum, inType, inPID );
if (siResult == eDSNoErr)
{
pCurrRef = GetTableRef( inRefNum );
siResult = eDSInvalidReference;
if ( pCurrRef != nil )
{
*outBufTag = pCurrRef->fBufTag;
siResult = eDSNoErr;
}
}
return( siResult );
}
tDirStatus CDSRefTable::SetBufTag ( UInt32 inRefNum, UInt32 inType, UInt32 inBufTag, SInt32 inPID )
{
tDirStatus siResult = eDSDirSrvcNotOpened;
sFWRefEntry *pCurrRef = nil;
siResult = VerifyReference( inRefNum, inType, inPID );
if (siResult == eDSNoErr)
{
pCurrRef = GetTableRef( inRefNum );
siResult = eDSInvalidReference;
if ( pCurrRef != nil )
{
pCurrRef->fBufTag = inBufTag;
if ( (inBufTag == 'DbgA') || (inBufTag == 'DbgB') )
{
if ( (inType == eAttrListRefType) || (inType == eAttrValueListRefType) )
{
UInt32 aRefCount = GetRefCount();
if ( ((aRefCount % 25) == 0) && (aRefCount > 100) )
{
syslog(LOG_CRIT, "DS:CDSRefTable::ClientSideRefCountExceedingReasonableValue Ref Count = %d", aRefCount);
}
}
}
siResult = eDSNoErr;
}
}
return( siResult );
}
UInt32 CDSRefTable::GetRefCount ( void )
{
return( fRefCount );
}