]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_cdsa_client/lib/dliterators.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_cdsa_client / lib / dliterators.h
diff --git a/Security/libsecurity_cdsa_client/lib/dliterators.h b/Security/libsecurity_cdsa_client/lib/dliterators.h
new file mode 100644 (file)
index 0000000..5512c3a
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
+ * 
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please obtain
+ * a copy of the License at http://www.apple.com/publicsource and read it before
+ * using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+ * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+ * specific language governing rights and limitations under the License.
+ */
+
+
+//
+// dliterators - DL/MDS table access as C++ iterators
+//
+// This is currently an almost read-only implementation.
+// (You can erase but you can't create or modify.)
+//
+#ifndef _H_CDSA_CLIENT_DLITERATORS
+#define _H_CDSA_CLIENT_DLITERATORS
+
+#include <security_utilities/threading.h>
+#include <security_utilities/globalizer.h>
+#include <security_utilities/refcount.h>
+#include <security_cdsa_utilities/cssmalloc.h>
+#include <security_cdsa_utilities/cssmpods.h>
+#include <security_cdsa_utilities/cssmerrors.h>
+#include <security_cdsa_utilities/cssmdb.h>
+#include <security_cdsa_client/dlquery.h>
+
+
+namespace Security {
+namespace CssmClient {
+
+
+//
+// An abstract interface to a (partial) DLDb-style object.
+// This is a particular (open) database that you can perform CSSM database
+// operations on.
+//
+class DLAccess {
+public:
+       virtual ~DLAccess();
+       
+       virtual CSSM_HANDLE dlGetFirst(const CSSM_QUERY &query,
+               CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
+               CSSM_DB_UNIQUE_RECORD *&id) = 0;
+       virtual bool dlGetNext(CSSM_HANDLE handle,
+               CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes, CSSM_DATA *data,
+               CSSM_DB_UNIQUE_RECORD *&id) = 0;
+       virtual void dlAbortQuery(CSSM_HANDLE handle) = 0;
+       virtual void dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id) = 0;
+       virtual void dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id) = 0;
+       virtual Allocator &allocator() = 0;
+};
+
+
+//
+// Abstract Database Records.
+// Each database record type has a subclass of this.
+// These are RefCounted; you can hang on to them as long as you like,
+// stick (RefPointers to) them into maps, and so on. Just go for it.
+//
+class Record : public RefCount, public CssmAutoData {
+public:
+       Record() : CssmAutoData(Allocator::standard(Allocator::sensitive)) { }
+       Record(const char * const * attributeNames);    // sets mAttributes
+       virtual ~Record();
+       static const CSSM_DB_RECORDTYPE recordType = CSSM_DL_DB_RECORD_ANY;
+
+       void addAttributes(const char * const * attributeNames); // add more
+
+       // raw attribute access
+       CssmDbRecordAttributeData &attributes() { return mAttributes; }
+       const CssmDbRecordAttributeData &attributes() const { return mAttributes; }
+       CSSM_DB_RECORDTYPE actualRecordType() const { return mAttributes.recordType(); }
+       
+       CssmAutoData &recordData() { return *this; }    // my data nature
+
+protected:
+       CssmAutoDbRecordAttributeData mAttributes;
+};
+
+
+//
+// TableBase is an implementation class for template Table below.
+// Do not use it directly (you'll be sorry).
+// Continue reading at template Table below.
+//
+class TableBase {
+public:
+       DLAccess &database;
+
+       CSSM_DB_RECORDTYPE recordType() const { return mRecordType; }
+       void recordType(CSSM_DB_RECORDTYPE t) { mRecordType = t; }      // override
+       
+       // erase all elements matching a query
+       uint32 erase(const CSSM_QUERY &query);
+       uint32 erase(const Query &query);
+
+protected:
+       TableBase(DLAccess &source, CSSM_DB_RECORDTYPE type, bool getData = true);
+       
+       class AccessRef : public RefCount {
+       protected:
+               AccessRef() : mAccess(NULL) { }
+               AccessRef(DLAccess *ac) : mAccess(ac) { }
+               DLAccess *mAccess;
+       };
+       
+       struct Handle : public AccessRef {
+               CSSM_HANDLE query;
+               Handle(DLAccess *ac, CSSM_HANDLE q) : AccessRef(ac), query(q) { }
+               ~Handle();
+       };
+       
+       struct Uid : public AccessRef {
+               CSSM_DB_UNIQUE_RECORD *uid;
+               Uid(DLAccess *ac, CSSM_DB_UNIQUE_RECORD *id) : AccessRef(ac), uid(id) { }
+               ~Uid();
+       };
+       
+       class Iterator {
+       public:
+               const CSSM_DB_UNIQUE_RECORD *recordHandle() const
+               { assert(mUid); return mUid->uid; }
+       
+       protected:
+               Iterator() { }
+               Iterator(DLAccess *ac, CSSM_HANDLE query, CSSM_DB_UNIQUE_RECORD *id,
+                       Record *record, bool getData);
+               void advance(Record *newRecord); // generic operator ++ helper
+       
+               DLAccess *mAccess;                              // data source
+               RefPointer<Handle> mQuery;              // DL/MDS query handle
+               RefPointer<Uid> mUid;                   // record unique identifier
+               RefPointer<Record> mRecord;             // current record value
+               bool mGetData;                                  // ask for data on iteration
+       };
+       
+protected:
+       CSSM_DB_RECORDTYPE mRecordType;         // CSSM/MDS record type
+       bool mGetData;                                          // ask for record data on primary iteration
+};
+
+
+//
+// A Table represents a single relation in a database (of some kind)
+//
+template <class RecordType>
+class Table : private TableBase {
+       typedef RefPointer<RecordType> RecPtr;
+public:
+       Table(DLAccess &source) : TableBase(source, RecordType::recordType) { }
+       Table(DLAccess &source, CSSM_DB_RECORDTYPE type) : TableBase(source, type) { }
+       Table(DLAccess &source, bool getData) : TableBase(source, RecordType::recordType, getData) { }
+       
+public:
+       class iterator : public Iterator,
+                       public std::iterator<forward_iterator_tag, RefPointer<RecordType> > {
+               friend class Table;
+       public:
+               iterator() { }
+
+               bool operator == (const iterator &other) const
+               { return mUid.get() == other.mUid.get(); }
+               bool operator != (const iterator &other) const
+               { return mUid.get() != other.mUid.get(); }
+
+               RecPtr operator * () const { return static_cast<RecordType *>(mRecord.get()); }
+               RecordType *operator -> () const { return static_cast<RecordType *>(mRecord.get()); }
+               iterator operator ++ () { advance(new RecordType); return *this; }
+               iterator operator ++ (int) { iterator old = *this; operator ++ (); return old; }
+               
+               void erase();
+               
+       private:
+               iterator(DLAccess *ac, CSSM_HANDLE query, CSSM_DB_UNIQUE_RECORD *id,
+                       RecordType *record, bool getData)
+                       : Iterator(ac, query, id, record, getData) { }
+       };
+       
+public:
+       iterator begin();
+       iterator find(const CSSM_QUERY &query);
+       iterator find(const Query &query);
+       iterator end()          { return iterator(); }
+       RecPtr fetch(const Query &query, CSSM_RETURN err = CSSM_OK) // one-stop shopping
+       { return fetchFirst(find(query), err); }
+       RecPtr fetch(CSSM_RETURN err = CSSM_OK) // fetch first of type
+       { return fetchFirst(begin(), err); }
+
+       // erase all records matching a query
+       void erase(const CSSM_QUERY &query);
+       void erase(const Query &query);
+       
+       void erase(iterator it) { it.erase(); }
+       
+private:
+       iterator startQuery(const CssmQuery &query, bool getData);
+       RecPtr fetchFirst(iterator it, CSSM_RETURN err);
+};
+
+
+//
+// Template out-of-line functions
+//
+template <class RecordType>
+typename Table<RecordType>::iterator Table<RecordType>::begin()
+{
+       return startQuery(CssmQuery(mRecordType), mGetData);
+}
+
+template <class RecordType>
+typename Table<RecordType>::iterator Table<RecordType>::find(const CSSM_QUERY &query)
+{
+       return startQuery(CssmQuery(CssmQuery::overlay(query), mRecordType), mGetData);
+}
+
+template <class RecordType>
+typename Table<RecordType>::iterator Table<RecordType>::find(const Query &query)
+{
+       return startQuery(CssmQuery(query.cssmQuery(), mRecordType), mGetData);
+}
+
+template <class RecordType>
+RefPointer<RecordType> Table<RecordType>::fetchFirst(iterator it, CSSM_RETURN err)
+{
+       if (it == end())
+               if (err)
+                       CssmError::throwMe(err);
+               else
+                       return NULL;
+       else
+               return *it;
+}
+
+
+template <class RecordType>
+typename Table<RecordType>::iterator Table<RecordType>::startQuery(const CssmQuery &query, bool getData)
+{
+       RefPointer<RecordType> record = new RecordType;
+       CSSM_DB_UNIQUE_RECORD *id;
+       CssmAutoData data(database.allocator());
+       CSSM_HANDLE queryHandle = database.dlGetFirst(query, record->attributes(),
+               getData ? &data.get() : NULL, id);
+       if (queryHandle == CSSM_INVALID_HANDLE)
+               return end();  // not found
+       if (getData)
+               record->recordData() = data;
+       return iterator(&database, queryHandle, id, record, getData);
+}
+
+
+template <class RecordType>
+void Table<RecordType>::iterator::erase()
+{
+       mAccess->dlDeleteRecord(mUid->uid);
+       mUid->uid = NULL;
+}
+
+
+} // end namespace CssmClient
+} // end namespace Security
+
+#endif // _H_CDSA_CLIENT_DLITERATORS