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