]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_client/lib/dliterators.h
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_client / lib / dliterators.h
1 /*
2 * Copyright (c) 2000-2004,2011,2014 Apple 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 // dliterators - DL/MDS table access as C++ iterators
21 //
22 // This is currently an almost read-only implementation.
23 // (You can erase but you can't create or modify.)
24 //
25 #ifndef _H_CDSA_CLIENT_DLITERATORS
26 #define _H_CDSA_CLIENT_DLITERATORS
27
28 #include <security_utilities/threading.h>
29 #include <security_utilities/globalizer.h>
30 #include <security_utilities/refcount.h>
31 #include <security_cdsa_utilities/cssmalloc.h>
32 #include <security_cdsa_utilities/cssmpods.h>
33 #include <security_cdsa_utilities/cssmerrors.h>
34 #include <security_cdsa_utilities/cssmdb.h>
35 #include <security_cdsa_client/dlquery.h>
36
37
38 namespace Security {
39 namespace CssmClient {
40
41
42 //
43 // An abstract interface to a (partial) DLDb-style object.
44 // This is a particular (open) database that you can perform CSSM database
45 // operations on.
46 //
47 class DLAccess {
48 public:
49 virtual ~DLAccess();
50
51 virtual CSSM_HANDLE dlGetFirst(const CSSM_QUERY &query,
52 CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
53 CSSM_DB_UNIQUE_RECORD *&id) = 0;
54 virtual bool dlGetNext(CSSM_HANDLE handle,
55 CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
56 CSSM_DB_UNIQUE_RECORD *&id) = 0;
57 virtual void dlAbortQuery(CSSM_HANDLE handle) = 0;
58 virtual void dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id) = 0;
59 virtual void dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id) = 0;
60 virtual Allocator &allocator() = 0;
61 };
62
63
64 //
65 // Abstract Database Records.
66 // Each database record type has a subclass of this.
67 // These are RefCounted; you can hang on to them as long as you like,
68 // stick (RefPointers to) them into maps, and so on. Just go for it.
69 //
70 class Record : public RefCount, public CssmAutoData {
71 public:
72 Record() : CssmAutoData(Allocator::standard(Allocator::sensitive)) { }
73 Record(const char * const * attributeNames); // sets mAttributes
74 virtual ~Record();
75 static const CSSM_DB_RECORDTYPE recordType = CSSM_DL_DB_RECORD_ANY;
76
77 void addAttributes(const char * const * attributeNames); // add more
78
79 // raw attribute access
80 CssmDbRecordAttributeData &attributes() { return mAttributes; }
81 const CssmDbRecordAttributeData &attributes() const { return mAttributes; }
82 CSSM_DB_RECORDTYPE actualRecordType() const { return mAttributes.recordType(); }
83
84 CssmAutoData &recordData() { return *this; } // my data nature
85
86 protected:
87 CssmAutoDbRecordAttributeData mAttributes;
88 };
89
90
91 //
92 // TableBase is an implementation class for template Table below.
93 // Do not use it directly (you'll be sorry).
94 // Continue reading at template Table below.
95 //
96 class TableBase {
97 public:
98 DLAccess &database;
99
100 CSSM_DB_RECORDTYPE recordType() const { return mRecordType; }
101 void recordType(CSSM_DB_RECORDTYPE t) { mRecordType = t; } // override
102
103 // erase all elements matching a query
104 uint32 erase(const CSSM_QUERY &query);
105 uint32 erase(const Query &query);
106
107 protected:
108 TableBase(DLAccess &source, CSSM_DB_RECORDTYPE type, bool getData = true);
109
110 class AccessRef : public RefCount {
111 protected:
112 AccessRef() : mAccess(NULL) { }
113 AccessRef(DLAccess *ac) : mAccess(ac) { }
114 DLAccess *mAccess;
115 };
116
117 struct Handle : public AccessRef {
118 CSSM_HANDLE query;
119 Handle(DLAccess *ac, CSSM_HANDLE q) : AccessRef(ac), query(q) { }
120 ~Handle();
121 };
122
123 struct Uid : public AccessRef {
124 CSSM_DB_UNIQUE_RECORD *uid;
125 Uid(DLAccess *ac, CSSM_DB_UNIQUE_RECORD *id) : AccessRef(ac), uid(id) { }
126 ~Uid();
127 };
128
129 class Iterator {
130 public:
131 const CSSM_DB_UNIQUE_RECORD *recordHandle() const
132 { assert(mUid); return mUid->uid; }
133
134 protected:
135 Iterator() { }
136 Iterator(DLAccess *ac, CSSM_HANDLE query, CSSM_DB_UNIQUE_RECORD *id,
137 Record *record, bool getData);
138 void advance(Record *newRecord); // generic operator ++ helper
139
140 DLAccess *mAccess; // data source
141 RefPointer<Handle> mQuery; // DL/MDS query handle
142 RefPointer<Uid> mUid; // record unique identifier
143 RefPointer<Record> mRecord; // current record value
144 bool mGetData; // ask for data on iteration
145 };
146
147 protected:
148 CSSM_DB_RECORDTYPE mRecordType; // CSSM/MDS record type
149 bool mGetData; // ask for record data on primary iteration
150 };
151
152
153 //
154 // A Table represents a single relation in a database (of some kind)
155 //
156 template <class RecordType>
157 class Table : private TableBase {
158 typedef RefPointer<RecordType> RecPtr;
159 public:
160 Table(DLAccess &source) : TableBase(source, RecordType::recordType) { }
161 Table(DLAccess &source, CSSM_DB_RECORDTYPE type) : TableBase(source, type) { }
162 Table(DLAccess &source, bool getData) : TableBase(source, RecordType::recordType, getData) { }
163
164 public:
165 class iterator : public Iterator,
166 public std::iterator<forward_iterator_tag, RefPointer<RecordType> > {
167 friend class Table;
168 public:
169 iterator() { }
170
171 bool operator == (const iterator &other) const
172 { return mUid.get() == other.mUid.get(); }
173 bool operator != (const iterator &other) const
174 { return mUid.get() != other.mUid.get(); }
175
176 RecPtr operator * () const { return static_cast<RecordType *>(mRecord.get()); }
177 RecordType *operator -> () const { return static_cast<RecordType *>(mRecord.get()); }
178 iterator operator ++ () { advance(new RecordType); return *this; }
179 iterator operator ++ (int) { iterator old = *this; operator ++ (); return old; }
180
181 void erase();
182
183 private:
184 iterator(DLAccess *ac, CSSM_HANDLE query, CSSM_DB_UNIQUE_RECORD *id,
185 RecordType *record, bool getData)
186 : Iterator(ac, query, id, record, getData) { }
187 };
188
189 public:
190 iterator begin();
191 iterator find(const CSSM_QUERY &query);
192 iterator find(const Query &query);
193 iterator end() { return iterator(); }
194 RecPtr fetch(const Query &query, CSSM_RETURN err = CSSM_OK) // one-stop shopping
195 { return fetchFirst(find(query), err); }
196 RecPtr fetch(CSSM_RETURN err = CSSM_OK) // fetch first of type
197 { return fetchFirst(begin(), err); }
198
199 // erase all records matching a query
200 void erase(const CSSM_QUERY &query);
201 void erase(const Query &query);
202
203 void erase(iterator it) { it.erase(); }
204
205 private:
206 iterator startQuery(const CssmQuery &query, bool getData);
207 RecPtr fetchFirst(iterator it, CSSM_RETURN err);
208 };
209
210
211 //
212 // Template out-of-line functions
213 //
214 template <class RecordType>
215 typename Table<RecordType>::iterator Table<RecordType>::begin()
216 {
217 return startQuery(CssmQuery(mRecordType), mGetData);
218 }
219
220 template <class RecordType>
221 typename Table<RecordType>::iterator Table<RecordType>::find(const CSSM_QUERY &query)
222 {
223 return startQuery(CssmQuery(CssmQuery::overlay(query), mRecordType), mGetData);
224 }
225
226 template <class RecordType>
227 typename Table<RecordType>::iterator Table<RecordType>::find(const Query &query)
228 {
229 return startQuery(CssmQuery(query.cssmQuery(), mRecordType), mGetData);
230 }
231
232 template <class RecordType>
233 RefPointer<RecordType> Table<RecordType>::fetchFirst(iterator it, CSSM_RETURN err)
234 {
235 if (it == end())
236 if (err)
237 CssmError::throwMe(err);
238 else
239 return NULL;
240 else
241 return *it;
242 }
243
244
245 template <class RecordType>
246 typename Table<RecordType>::iterator Table<RecordType>::startQuery(const CssmQuery &query, bool getData)
247 {
248 RefPointer<RecordType> record = new RecordType;
249 CSSM_DB_UNIQUE_RECORD *id;
250 CssmAutoData data(database.allocator());
251 CSSM_HANDLE queryHandle = database.dlGetFirst(query, record->attributes(),
252 getData ? &data.get() : NULL, id);
253 if (queryHandle == CSSM_INVALID_HANDLE)
254 return end(); // not found
255 if (getData)
256 record->recordData() = data;
257 return iterator(&database, queryHandle, id, record, getData);
258 }
259
260
261 template <class RecordType>
262 void Table<RecordType>::iterator::erase()
263 {
264 mAccess->dlDeleteRecord(mUid->uid);
265 mUid->uid = NULL;
266 }
267
268
269 } // end namespace CssmClient
270 } // end namespace Security
271
272 #endif // _H_CDSA_CLIENT_DLITERATORS