1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// MultiDLDb implementation.
21//
22
23#include <security_cdsa_client/multidldb.h>
24#include <security_cdsa_client/securestorage.h>
25
26
27
28namespace Security
29{
30
31using namespace CssmClient;
32
33namespace CssmClient
34{
35
36//
37// MultiDLDbDbCursorImpl declaration
38//
39class MultiDLDbDbCursorImpl : public DbCursorImpl
40{
41public:
42	MultiDLDbDbCursorImpl(const MultiDLDb &parent, const CSSM_QUERY &query, Allocator &allocator);
43	MultiDLDbDbCursorImpl(const MultiDLDb &parent, uint32 capacity, Allocator &allocator);
44	virtual ~MultiDLDbDbCursorImpl();
45
46	bool next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId);
47private:
48	MultiDLDb multiDLDb() { return parent<MultiDLDb>(); }
49	void activate();
50	void deactivate();
51
52	MultiDLDbImpl::ListRef mListRef;
53	MultiDLDbImpl::List::const_iterator mNext;
54	MultiDLDbImpl::List::const_iterator mEnd;
55	DbCursor mCursor;
56};
57
58} // end namespace CssmClient
59
60} // end namespace Security
61
62//
63// MultiDLDbImpl
64//
65MultiDLDbImpl::MultiDLDbImpl(const vector<DLDbIdentifier> &list, bool useSecureStorage, const Cssm &cssm)
66: ObjectImpl(cssm), mListRef(list), mUseSecureStorage(useSecureStorage)
67{
68}
69
70MultiDLDbImpl::MultiDLDbImpl(const vector<DLDbIdentifier> &list, bool useSecureStorage)
71: ObjectImpl(Cssm::standard()), mListRef(list), mUseSecureStorage(useSecureStorage)
72{
73}
74
75MultiDLDbImpl::~MultiDLDbImpl()
76{
77	deactivate();
78}
79
80Db
81MultiDLDbImpl::database(const DLDbIdentifier &dlDbIdentifier)
82{
83	StLock<Mutex> _(mLock);
84	DbMap::const_iterator it = mDbMap.find(dlDbIdentifier);
85	if (it != mDbMap.end())
86		return it->second;
87
88	Module module(dlDbIdentifier.ssuid().guid(), cssm());
89	DL dl;
90	if (dlDbIdentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP)
91	{
92		if (mUseSecureStorage)
93			dl = SSCSPDL(module);
94		else
95			dl = CSPDL(module);
96	}
97	else
98		dl = DL(module);
99
100	dl->subserviceId(dlDbIdentifier.ssuid().subserviceId());
101	dl->version(dlDbIdentifier.ssuid().version());
102	Db db(dl, dlDbIdentifier.dbName());
103	if (find(mListRef->begin(), mListRef->end(), dlDbIdentifier) != mListRef->end())
104		mDbMap.insert(DbMap::value_type(dlDbIdentifier, db));
105
106	return db;
107}
108
109void
110MultiDLDbImpl::list(const vector<DLDbIdentifier> &list)
111{
112	StLock<Mutex> _(mLock);
113	set<DLDbIdentifier> oldList(mListRef->begin(), mListRef->end());
114	mListRef = ListRef(list);
115	set<DLDbIdentifier> newList(mListRef->begin(), mListRef->end());
116	vector<DLDbIdentifier> obsolete;
117	back_insert_iterator<vector<DLDbIdentifier> > ii(obsolete);
118	// Remove all db's from the map that were in oldList but are not in mListRef.
119	set_difference(oldList.begin(), oldList.end(), newList.begin(), newList.end(), ii);
120	for (vector<DLDbIdentifier>::const_iterator it = obsolete.begin(); it != obsolete.end(); ++it)
121		mDbMap.erase(*it);
122}
123
124DbCursorImpl *
125MultiDLDbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
126{
127	return new MultiDLDbDbCursorImpl(MultiDLDb(this), query, allocator);
128}
129
130DbCursorImpl *
131MultiDLDbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
132{
133	return new MultiDLDbDbCursorImpl(MultiDLDb(this), capacity, allocator);
134}
135
136void
137MultiDLDbImpl::activate()
138{
139}
140
141void
142MultiDLDbImpl::deactivate()
143{
144	StLock<Mutex> _(mLock);
145	mDbMap.erase(mDbMap.begin(), mDbMap.end());
146}
147
148
149//
150// MultiDLDbDbCursorImpl
151//
152MultiDLDbDbCursorImpl::MultiDLDbDbCursorImpl(const MultiDLDb &parent,
153											 const CSSM_QUERY &query, Allocator &allocator)
154: DbCursorImpl(parent, query, allocator)
155{
156}
157
158MultiDLDbDbCursorImpl::MultiDLDbDbCursorImpl(const MultiDLDb &parent,
159											 uint32 capacity, Allocator &allocator)
160: DbCursorImpl(parent, capacity, allocator)
161{
162}
163
164MultiDLDbDbCursorImpl::~MultiDLDbDbCursorImpl()
165{
166	try
167	{
168		deactivate();
169	}
170	catch(...) {}
171}
172
173bool
174MultiDLDbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
175{
176	activate();
177	for (;;)
178	{
179		if (!mCursor)
180		{
181			if (mNext == mEnd)
182			{
183				// This is how it ends.
184				deactivate();
185				return false;
186			}
187
188			mCursor = DbCursor(multiDLDb()->database(*mNext++), *this);
189		}
190
191		try
192		{
193			if (mCursor->next(attributes, data, uniqueId))
194				return true;
195		}
196
197		catch(const CommonError &err)
198		{
199			OSStatus status = err.osStatus();
200			if(status != CSSMERR_DL_DATASTORE_DOESNOT_EXIST)
201				throw;
202		}
203
204
205
206		mCursor = DbCursor();
207	}
208}
209
210void
211MultiDLDbDbCursorImpl::activate()
212{
213    StLock<Mutex> _(mActivateMutex);
214	if (!mActive)
215	{
216		mListRef = multiDLDb()->listRef();
217		mNext = mListRef->begin();
218		mEnd = mListRef->end();
219		mActive = true;
220	}
221}
222
223void
224MultiDLDbDbCursorImpl::deactivate()
225{
226    StLock<Mutex> _(mActivateMutex);
227	if (mActive)
228	{
229		mActive = false;
230		mListRef = MultiDLDbImpl::ListRef();
231		mNext = mEnd;
232		mCursor = DbCursor();
233	}
234}
235
236