464 lines
14 KiB
C++
464 lines
14 KiB
C++
//
|
|
// The developer of the original code and/or files is Tripwire, Inc.
|
|
// Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire,
|
|
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
|
|
// reserved.
|
|
//
|
|
// This program is free software. The contents of this file are subject
|
|
// to the terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 2 of the License, or (at your
|
|
// option) any later version. You may redistribute it and/or modify it
|
|
// only in compliance with the GNU General Public License.
|
|
//
|
|
// This program is distributed in the hope that it will be useful.
|
|
// However, this program is distributed AS-IS WITHOUT ANY
|
|
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
|
|
// for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// Nothing in the GNU General Public License or any other license to use
|
|
// the code or files shall permit you to use Tripwire's trademarks,
|
|
// service marks, or other intellectual property without Tripwire's
|
|
// prior written consent.
|
|
//
|
|
// If you have any questions, please contact Tripwire, Inc. at either
|
|
// info@tripwire.org or www.tripwire.org.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// fcodatasourceiterimpl.cpp
|
|
//
|
|
|
|
//=========================================================================
|
|
// DEFINES AND MACROS
|
|
//=========================================================================
|
|
|
|
//=========================================================================
|
|
// INCLUDES
|
|
//=========================================================================
|
|
|
|
#include "stdfco.h"
|
|
#include "fcodatasourceiterimpl.h"
|
|
#include "fco.h"
|
|
#include "core/upperbound.h"
|
|
#include "core/errorbucket.h"
|
|
|
|
//=========================================================================
|
|
// METHOD CODE
|
|
//=========================================================================
|
|
|
|
cFCODataSourceIterImpl::cFCODataSourceIterImpl()
|
|
: mFlags(0)
|
|
{
|
|
}
|
|
|
|
|
|
cFCODataSourceIterImpl::~cFCODataSourceIterImpl()
|
|
{
|
|
ClearList();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// operator =
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cFCODataSourceIterImpl& cFCODataSourceIterImpl::operator=( const cFCODataSourceIterImpl& rhs )
|
|
{
|
|
ClearList();
|
|
mPeers = rhs.mPeers;
|
|
mParentName = rhs.mParentName;
|
|
mpErrorBucket = rhs.mpErrorBucket;
|
|
mFlags = rhs.mFlags;
|
|
//
|
|
// we need to addref all of the fcos we just got...
|
|
//
|
|
for( FCOList::const_iterator i = mPeers.begin(); i != mPeers.end(); i++ )
|
|
{
|
|
(*i)->AddRef();
|
|
}
|
|
//
|
|
// figuring out where to put the iterator is a little trickier...
|
|
// TODO -- if we ever change the mPeers data structure from a vector, this will
|
|
// have to change (luckily, the compiler should catch this!)
|
|
//
|
|
if( rhs.Done() )
|
|
{
|
|
mCurPos = mPeers.end();
|
|
}
|
|
else
|
|
{
|
|
int offset = rhs.mCurPos - rhs.mPeers.begin();
|
|
mCurPos = mPeers.begin() + offset;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetShortName
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
const TCHAR* cFCODataSourceIterImpl::GetShortName() const
|
|
{
|
|
ASSERT( ! Done() );
|
|
|
|
return ( (*mCurPos)->GetName().GetShortName() );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetName
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cFCOName cFCODataSourceIterImpl::GetName() const
|
|
{
|
|
ASSERT( ! Done() );
|
|
|
|
return ( (*mCurPos)->GetName() );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetParentName
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cFCOName cFCODataSourceIterImpl::GetParentName() const
|
|
{
|
|
return mParentName;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetParentName
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cFCODataSourceIterImpl::AtRoot() const //throw (eError)
|
|
{
|
|
return ( mParentName.GetSize() == 0 );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CanDescend
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cFCODataSourceIterImpl::CanDescend() const //throw (eError)
|
|
{
|
|
ASSERT( ! Done() );
|
|
if( Done() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ( (*mCurPos)->GetCaps() & iFCO::CAP_CAN_HAVE_CHILDREN );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Descend
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::Descend() //throw (eError)
|
|
{
|
|
ASSERT( CanDescend() );
|
|
|
|
mParentName = GetName();
|
|
GeneratePeers( );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Ascend
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::Ascend() //throw (eError)
|
|
{
|
|
ASSERT( ! AtRoot() );
|
|
|
|
cFCOName name = mParentName;
|
|
SeekToFCO( name ); // I do this because SeekToFCO modifies mCwd and takes a reference parameter.
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SeekBegin
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::SeekBegin()
|
|
{
|
|
mCurPos = mPeers.begin();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Done
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cFCODataSourceIterImpl::Done() const
|
|
{
|
|
return ( mCurPos == mPeers.end() );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Next
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::Next()
|
|
{
|
|
mCurPos++;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CreateFCO
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
iFCO* cFCODataSourceIterImpl::CreateFCO() //throw (eError)
|
|
{
|
|
ASSERT( ! Done() );
|
|
InitializeTypeInfo( *mCurPos );
|
|
(*mCurPos)->AddRef();
|
|
return *mCurPos;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SeekToFCO
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::SeekToFCO(const cFCOName& name, bool bCreatePeers) // throw (eFCODataSourceIter)
|
|
{
|
|
ASSERT( name.GetSize() > 0 );
|
|
ASSERT( name.IsCaseSensitive() == IsCaseSensitive() );
|
|
|
|
//
|
|
// get the parent name and pop the short child name
|
|
//
|
|
cFCOName parentName = name;
|
|
|
|
parentName.Pop(); // RAD:05/10/1999 -- Used to assign result to "shortname"
|
|
|
|
if( parentName.GetSize() == 0 )
|
|
{
|
|
// we are going to the root directory...
|
|
// note that we are not responsible for iterating over the root nodes (for example,
|
|
// all of the drive letters in NT or all the hive names in the registry)
|
|
//
|
|
mParentName.Clear();
|
|
ClearList();
|
|
iFCO* pObj = CreateObject( name, bCreatePeers );
|
|
if( ! pObj )
|
|
{
|
|
// error creating object; just return.
|
|
return;
|
|
}
|
|
|
|
InsertIntoPeers( pObj );
|
|
mCurPos = mPeers.begin();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// if we are not creating our peers, simply create the single object and return...
|
|
//
|
|
if( ! bCreatePeers )
|
|
{
|
|
ClearList();
|
|
mParentName = parentName;
|
|
iFCO* pNewObj = CreateObject( name, false );
|
|
if( pNewObj )
|
|
{
|
|
InsertIntoPeers( pNewObj );
|
|
mCurPos = mPeers.begin();
|
|
}
|
|
return;
|
|
}
|
|
//
|
|
// otherwise, load up everything. Note that we can't do the if(parentName == mParentName) optimization
|
|
// because if you do a SeekToFCO( c:/foo, false) and then a SeekToFCO( c:/bar, true), it won't work
|
|
// correctly -- 27 Jan 99 mdb
|
|
//
|
|
mParentName = parentName;
|
|
ClearList();
|
|
GeneratePeers();
|
|
}
|
|
|
|
SeekToPeerByName( (*mCurPos)->GetName().GetShortName() );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// IsCaseSensitive
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cFCODataSourceIterImpl::IsCaseSensitive() const
|
|
{
|
|
return mParentName.IsCaseSensitive();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ClearList
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::ClearList()
|
|
{
|
|
for( mCurPos = mPeers.begin(); mCurPos != mPeers.end(); mCurPos++ )
|
|
{
|
|
(*mCurPos)->Release();
|
|
}
|
|
|
|
mPeers.clear();
|
|
mCurPos = mPeers.end();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GeneratePeers
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::GeneratePeers()
|
|
{
|
|
///TODO -- BIG BIG TODO -- I need to implement some lazy evaluation for these
|
|
// fcos so that when I seek to a start point, I don't stat everything in the
|
|
// same directory as myself.
|
|
// NOTE: This might be alleviated by differentiating between seeks that need
|
|
// peers and ones that do not (or maybe lazy evaluation of the peers)
|
|
|
|
ClearList();
|
|
|
|
//
|
|
// read all of the children of the parent...
|
|
//
|
|
std::vector<TSTRING> vChildrenNames;
|
|
GetChildrenNames( mParentName.AsString(), vChildrenNames );
|
|
|
|
//
|
|
// insert the children into the set...
|
|
//
|
|
std::vector<TSTRING>::iterator i;
|
|
cFCOName curName = mParentName;
|
|
for( i = vChildrenNames.begin(); i != vChildrenNames.end(); i++)
|
|
{
|
|
curName.Push( *i );
|
|
|
|
iFCO* pNewObj = CreateObject( curName, true );
|
|
if( pNewObj )
|
|
{
|
|
if( ! InsertIntoPeers( pNewObj ) )
|
|
{
|
|
// no need for an error msg; that is handled by InsertIntoPeers;
|
|
// just release the object.
|
|
//
|
|
pNewObj->Release();
|
|
}
|
|
}
|
|
curName.Pop();
|
|
}
|
|
|
|
mCurPos = mPeers.begin();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// TraceContents
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cFCODataSourceIterImpl::SeekTo( const TCHAR* shortName )
|
|
{
|
|
FCOList::iterator i = UpperBound( shortName );
|
|
if( i != mPeers.end() )
|
|
{
|
|
if( REL_EQ == Compare( shortName, (*i)->GetName().GetShortName() ) )
|
|
{
|
|
mCurPos = i;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
mCurPos = mPeers.end();
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// TraceContents
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::TraceContents(int dl) const
|
|
{
|
|
if( dl == -1 )
|
|
dl = cDebug::D_DEBUG;
|
|
|
|
cDebug d("cFCODataSourceIterImpl::TraceContents");
|
|
|
|
d.Trace( dl, "FCO Iterator; parent = %s\n", mParentName.AsString().c_str() );
|
|
d.Trace( dl, "---- Peers ---- (current has a * by it)\n" );
|
|
int cnt = 0;
|
|
for( FCOList::const_iterator iter = mPeers.begin(); iter != mPeers.end(); iter++, cnt++ )
|
|
{
|
|
d.Trace( dl, "[%d]%c\t:%s\n", cnt, iter == mCurPos ? _T('*') : _T(' '), (*iter)->GetName().AsString().c_str() );
|
|
}
|
|
d.Trace( dl, "--------------- \n" );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InsertIntoPeers
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// inserts the fco into peers.
|
|
// Sorted in increasing order by short name of the FCO.
|
|
bool cFCODataSourceIterImpl::InsertIntoPeers( iFCO* pFCO )
|
|
{
|
|
FCOList::iterator i = UpperBound( pFCO->GetName().GetShortName() );
|
|
|
|
if( i != mPeers.end() )
|
|
{
|
|
// never insert two objects that have the same name...
|
|
//
|
|
if( REL_EQ == Compare( pFCO->GetName().GetShortName(), (*i)->GetName().GetShortName() ) )
|
|
{
|
|
mpErrorBucket->AddError( eFCODataSourceIterDupeFCO( pFCO->GetName().AsString(), eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
else
|
|
mPeers.insert( i, pFCO );
|
|
}
|
|
else
|
|
mPeers.push_back( pFCO );
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SeekToPeerByName
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFCODataSourceIterImpl::SeekToPeerByName( const TCHAR* pchName )
|
|
{
|
|
FCOList::iterator i = UpperBound( pchName );
|
|
if( i != mPeers.end() )
|
|
{
|
|
if( REL_EQ == Compare( pchName, (*i)->GetName().GetShortName() ) )
|
|
{
|
|
mCurPos = i;
|
|
return;
|
|
}
|
|
}
|
|
|
|
mCurPos = mPeers.end();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CompareShortName
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool cFCODataSourceIterImpl::CompareForUpperBound( const iFCO* pFCO, const TCHAR* pchName ) const
|
|
{
|
|
return( Compare( pFCO->GetName().GetShortName(), pchName ) == REL_LT );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// cFCODataSourceIterImplCallCompare
|
|
// -- used to sneak a pointer-to-member-function where a
|
|
// pointer-to-non-member-function is expected
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class cFCODataSourceIterImplCallCompare
|
|
{
|
|
public:
|
|
cFCODataSourceIterImplCallCompare( const cFCODataSourceIterImpl* pcls )
|
|
: pc( pcls ) {};
|
|
|
|
bool operator()( const iFCO* a1, const TCHAR* a2 )
|
|
{
|
|
return pc->CompareForUpperBound( a1, a2 );
|
|
}
|
|
|
|
private:
|
|
const cFCODataSourceIterImpl* pc;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// UpperBound
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
cFCODataSourceIterImpl::FCOList::iterator cFCODataSourceIterImpl::UpperBound( const TCHAR* pchShortName )
|
|
{
|
|
cFCODataSourceIterImplCallCompare comp( this );
|
|
return ::UpperBound( mPeers.begin(), mPeers.end(), pchShortName, comp );
|
|
}
|
|
|