#include <Security/multidldb.h>
#include <Security/securestorage.h>
#include <Security/cssmerrno.h>
namespace Security
{
using namespace CssmClient;
namespace CssmClient
{
class MultiDLDbDbCursorImpl : public DbCursorImpl
{
public:
MultiDLDbDbCursorImpl(const MultiDLDb &parent, const CSSM_QUERY &query, CssmAllocator &allocator);
MultiDLDbDbCursorImpl(const MultiDLDb &parent, uint32 capacity, CssmAllocator &allocator);
virtual ~MultiDLDbDbCursorImpl();
bool next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId);
private:
MultiDLDb multiDLDb() { return parent<MultiDLDb>(); }
void activate();
void deactivate();
MultiDLDbImpl::ListRef mListRef;
MultiDLDbImpl::List::const_iterator mNext;
MultiDLDbImpl::List::const_iterator mEnd;
DbCursor mCursor;
};
}
}
MultiDLDbImpl::MultiDLDbImpl(const vector<DLDbIdentifier> &list, bool useSecureStorage, const Cssm &cssm)
: ObjectImpl(cssm), mListRef(list), mUseSecureStorage(useSecureStorage)
{
}
MultiDLDbImpl::MultiDLDbImpl(const vector<DLDbIdentifier> &list, bool useSecureStorage)
: ObjectImpl(Cssm::standard()), mListRef(list), mUseSecureStorage(useSecureStorage)
{
}
MultiDLDbImpl::~MultiDLDbImpl()
{
deactivate();
}
Db
MultiDLDbImpl::database(const DLDbIdentifier &dlDbIdentifier)
{
StLock<Mutex> _(mLock);
DbMap::const_iterator it = mDbMap.find(dlDbIdentifier);
if (it != mDbMap.end())
return it->second;
Module module(dlDbIdentifier.ssuid().guid(), cssm());
DL dl;
if (dlDbIdentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP)
{
if (mUseSecureStorage)
dl = SSCSPDL(module);
else
dl = CSPDL(module);
}
else
dl = DL(module);
dl->subserviceId(dlDbIdentifier.ssuid().subserviceId());
dl->version(dlDbIdentifier.ssuid().version());
Db db(dl, dlDbIdentifier.dbName());
if (find(mListRef->begin(), mListRef->end(), dlDbIdentifier) != mListRef->end())
mDbMap.insert(DbMap::value_type(dlDbIdentifier, db));
return db;
}
void
MultiDLDbImpl::list(const vector<DLDbIdentifier> &list)
{
StLock<Mutex> _(mLock);
set<DLDbIdentifier> oldList(mListRef->begin(), mListRef->end());
mListRef = ListRef(list);
set<DLDbIdentifier> newList(mListRef->begin(), mListRef->end());
vector<DLDbIdentifier> obsolete;
back_insert_iterator<vector<DLDbIdentifier> > ii(obsolete);
set_difference(oldList.begin(), oldList.end(), newList.begin(), newList.end(), ii);
for (vector<DLDbIdentifier>::const_iterator it = obsolete.begin(); it != obsolete.end(); ++it)
mDbMap.erase(*it);
}
DbCursorImpl *
MultiDLDbImpl::newDbCursor(const CSSM_QUERY &query, CssmAllocator &allocator)
{
return new MultiDLDbDbCursorImpl(MultiDLDb(this), query, allocator);
}
DbCursorImpl *
MultiDLDbImpl::newDbCursor(uint32 capacity, CssmAllocator &allocator)
{
return new MultiDLDbDbCursorImpl(MultiDLDb(this), capacity, allocator);
}
void
MultiDLDbImpl::activate()
{
}
void
MultiDLDbImpl::deactivate()
{
StLock<Mutex> _(mLock);
mDbMap.erase(mDbMap.begin(), mDbMap.end());
}
MultiDLDbDbCursorImpl::MultiDLDbDbCursorImpl(const MultiDLDb &parent,
const CSSM_QUERY &query, CssmAllocator &allocator)
: DbCursorImpl(parent, query, allocator)
{
}
MultiDLDbDbCursorImpl::MultiDLDbDbCursorImpl(const MultiDLDb &parent,
uint32 capacity, CssmAllocator &allocator)
: DbCursorImpl(parent, capacity, allocator)
{
}
MultiDLDbDbCursorImpl::~MultiDLDbDbCursorImpl()
{
try
{
deactivate();
}
catch(...) {}
}
bool
MultiDLDbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
{
activate();
for (;;)
{
if (!mCursor)
{
if (mNext == mEnd)
{
deactivate();
return false;
}
mCursor = DbCursor(multiDLDb()->database(*mNext++), *this);
}
try
{
if (mCursor->next(attributes, data, uniqueId))
return true;
}
catch(const CssmCommonError &err)
{
OSStatus status = err.osStatus();
if(status != CSSMERR_DL_DATASTORE_DOESNOT_EXIST)
throw;
}
mCursor = DbCursor();
}
}
void
MultiDLDbDbCursorImpl::activate()
{
if (!mActive)
{
mListRef = multiDLDb()->listRef();
mNext = mListRef->begin();
mEnd = mListRef->end();
mActive = true;
}
}
void
MultiDLDbDbCursorImpl::deactivate()
{
if (mActive)
{
mActive = false;
mListRef = MultiDLDbImpl::ListRef();
mNext = mEnd;
mCursor = DbCursor();
}
}