1/*
2 * Copyright (c) 2000-2001,2003,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//  AppleDatabase.h - Description t.b.d.
21//
22#ifndef _H_APPLEDATABASE
23#define _H_APPLEDATABASE
24
25#include "MetaRecord.h"
26#include "SelectionPredicate.h"
27#include "DbIndex.h"
28
29#include <security_filedb/AtomicFile.h>
30#include <security_cdsa_plugin/Database.h>
31#include <security_cdsa_plugin/DbContext.h>
32#include <security_cdsa_utilities/handleobject.h>
33#include <security_utilities/refcount.h>
34#include <memory>
35#include <vector>
36#include <CoreFoundation/CFDate.h>
37
38namespace Security
39{
40
41// Abstract database Cursor class.
42class Cursor;
43class DbVersion;
44class CssmAutoQuery;
45
46struct AppleDatabaseTableName
47{
48	uint32 mTableId;
49	const char *mTableName;
50
51	// indices of meta-table entries in an array of table names
52
53	enum {
54		kSchemaInfo = 0,
55		kSchemaAttributes,
56		kSchemaIndexes,
57		kSchemaParsingModule,
58		kNumRequiredTableNames
59	};
60};
61
62//
63// This is what the CDSA standard refers to as a Relation.  We use
64// the more conventional term Table.
65//
66class Table
67{
68	NOCOPY(Table)
69public:
70	// Type used to refer to a table.
71	typedef CSSM_DB_RECORDTYPE Id;
72
73    Table(const ReadSection &inTableSection);
74	~Table();
75
76	// Return a newly created cursor satisfying inQuery on the receiving table
77	// The returned Cursor may or may not use indexes depending on their availability.
78	Cursor *createCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion) const;
79
80	const ReadSection getRecordSection(uint32 inRecordNumber) const;
81
82	const RecordId getRecord(const RecordId &inRecordId,
83							 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
84							 CssmData *inoutData,
85							 Allocator &inAllocator) const;
86
87	// Return the number of recordNumbers in use by this table including empty slots.
88    uint32 recordNumberCount() const { return mRecordNumbersCount; }
89    uint32 freeListHead() const { return mFreeListHead; }
90
91	// Return the record number corresponding to aFreeListHead and update
92	// aFreeListHead to point to the next availble recordNumber slot.
93	uint32 popFreeList(uint32 &aFreeListHead) const;
94
95	MetaRecord &getMetaRecord() { return mMetaRecord; }
96	const MetaRecord &getMetaRecord() const { return mMetaRecord; }
97
98	uint32 getRecordsCount() const { return mRecordsCount; }
99	const ReadSection getRecordsSection() const;
100
101	const ReadSection &getTableSection() const { return mTableSection; }
102
103	bool matchesTableId(Id inTableId) const;
104
105	void readIndexSection();
106
107	enum
108	{
109		OffsetSize					= AtomSize * 0,
110		OffsetId					= AtomSize * 1,
111		OffsetRecordsCount			= AtomSize * 2,
112		OffsetRecords				= AtomSize * 3,
113		OffsetIndexesOffset			= AtomSize * 4,
114		OffsetFreeListHead			= AtomSize * 5,
115		OffsetRecordNumbersCount	= AtomSize * 6,
116		OffsetRecordNumbers			= AtomSize * 7
117	};
118protected:
119	friend class ModifiedTable;
120
121	MetaRecord mMetaRecord;
122	const ReadSection mTableSection;
123
124	uint32 mRecordsCount;
125	uint32 mFreeListHead;
126	// Number of record numbers (including freelist slots) in this table.
127	uint32 mRecordNumbersCount;
128
129	// all the table's indexes, mapped by index id
130	typedef map<uint32, DbConstIndex *> ConstIndexMap;
131	ConstIndexMap mIndexMap;
132};
133
134class ModifiedTable
135{
136	NOCOPY(ModifiedTable)
137public:
138	ModifiedTable(const Table *inTable);
139	ModifiedTable(MetaRecord *inMetaRecord); // Take over ownership of inMetaRecord
140	~ModifiedTable();
141
142	// Mark the record with inRecordId as deleted.
143    void deleteRecord(const RecordId &inRecordId);
144    const RecordId insertRecord(uint32 inVersionId,
145								const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
146								const CssmData *inData);
147    const RecordId updateRecord(const RecordId &inRecordId,
148								const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
149								const CssmData *inData,
150								CSSM_DB_MODIFY_MODE inModifyMode);
151	const RecordId getRecord(const RecordId &inRecordId,
152							 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
153							 CssmData *inoutData,
154							 Allocator &inAllocator) const;
155
156	// Return the MetaRecord this table should use for writes.
157	const MetaRecord &getMetaRecord() const;
158
159	// find, and create if needed, an index with the given id
160	DbMutableIndex &findIndex(uint32 indexId, const MetaRecord &metaRecord, bool isUniqueIndex);
161
162	// Write this table to inOutputFile at inSectionOffset and return the new offset.
163    uint32 writeTable(AtomicTempFile &inAtomicTempFile, uint32 inSectionOffset);
164
165private:
166	// Return the next available record number for this table.
167    uint32 nextRecordNumber();
168
169	// Return the number of recordNumbers in use by this table including empty slots.
170    uint32 recordNumberCount() const;
171
172	void modifyTable();
173	void createMutableIndexes();
174	uint32 writeIndexSection(WriteSection &tableSection, uint32 offset);
175
176	// Optional, this is merly a reference, we do not own this object.
177	const Table *mTable;
178
179	// Optional, New MetaRecord.  This is only present if it is different from the
180	// MetaRecord of mTable or mTable is nil.
181	const MetaRecord *mNewMetaRecord;
182
183	// Set of Records that have been deleted or modified.
184    typedef set<uint32> DeletedSet;
185    DeletedSet mDeletedSet;
186
187	// Set of Records that have been inserted or modified.
188    typedef map<uint32, WriteSection *> InsertedMap;
189    InsertedMap mInsertedMap;
190
191	// Next lowest available RecordNumber
192    uint32 mRecordNumberCount;
193	// Head of the free list (if there is one) or 0 if either we have no
194	// mTable of the free list has been exhausted.
195    uint32 mFreeListHead;
196
197	// has this table actually been modified?
198	bool mIsModified;
199
200	typedef map<uint32, DbMutableIndex *> MutableIndexMap;
201	MutableIndexMap mIndexMap;
202};
203
204//
205// Read only snapshot of a database.
206//
207class Metadata
208{
209	NOCOPY(Metadata)
210protected:
211	Metadata() {}
212    enum
213    {
214		HeaderOffset		= 0,	// Absolute offset of header.
215		OffsetMagic			= AtomSize * 0,
216		OffsetVersion		= AtomSize * 1,
217		OffsetAuthOffset	= AtomSize * 2,
218		OffsetSchemaOffset	= AtomSize * 3,
219        HeaderSize			= AtomSize * 4,
220
221        HeaderMagic			= FOUR_CHAR_CODE('kych'),
222        HeaderVersion		= 0x00010000
223    };
224
225	enum
226	{
227		OffsetSchemaSize	= AtomSize * 0,
228		OffsetTablesCount	= AtomSize * 1,
229		OffsetTables		= AtomSize * 2
230	};
231};
232
233//
234// Read only representation of a database
235//
236class DbVersion : public Metadata, public RefCount
237{
238	NOCOPY(DbVersion)
239public:
240    DbVersion(const class AppleDatabase &db, const RefPointer <AtomicBufferedFile> &inAtomicBufferedFile);
241    ~DbVersion();
242
243	uint32 getVersionId() const { return mVersionId; }
244	const RecordId getRecord(Table::Id inTableId, const RecordId &inRecordId,
245							 CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
246							 CssmData *inoutData, Allocator &inAllocator) const;
247	Cursor *createCursor(const CSSM_QUERY *inQuery) const;
248protected:
249	const Table &findTable(Table::Id inTableId) const;
250	Table &findTable(Table::Id inTableId);
251
252private:
253    void open(); // Part of constructor contract.
254
255	ReadSection mDatabase;
256    uint32 mVersionId;
257
258	friend class DbModifier; // XXX Fixme
259    typedef map<Table::Id, Table *> TableMap;
260    TableMap mTableMap;
261	const class AppleDatabase &mDb;
262	RefPointer<AtomicBufferedFile> mBufferedFile;
263
264public:
265	typedef Table value_type;
266	typedef const Table &const_reference;
267	typedef const Table *const_pointer;
268
269	// A const forward iterator.
270	class const_iterator
271	{
272	public:
273		const_iterator(const TableMap::const_iterator &it) : mIterator(it) {}
274
275		// Use default copy consturctor and assignment operator.
276		//const_iterator(const const_iterator &it) : mIterator(it.mIterator) {}
277		//const_iterator &operator=(const const_iterator &it) { mIterator = it.mIterator; return *this; }
278		const_reference operator*() const { return *mIterator->second; }
279		const_iterator &operator++() { mIterator.operator++(); return *this; }
280		const_iterator operator++(int i) { return const_iterator(mIterator.operator++(i)); }
281		bool operator!=(const const_iterator &other) const { return mIterator != other.mIterator; }
282		bool operator==(const const_iterator &other) const { return mIterator == other.mIterator; }
283
284		const_pointer operator->() const { return mIterator->second; } // Not really needed.
285
286	private:
287		TableMap::const_iterator mIterator;
288	};
289
290	const_iterator begin() const { return const_iterator(mTableMap.begin()); }
291	const_iterator end() const { return const_iterator(mTableMap.end()); }
292
293	bool hasTable(Table::Id inTableId) const;
294};
295
296//
297// Cursor
298//
299class Cursor : public HandleObject
300{
301public:
302    Cursor();
303    Cursor(const DbVersion &inDbVersion);
304    virtual ~Cursor();
305    virtual bool next(Table::Id &outTableId,
306					CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
307					CssmData *outData,
308					Allocator &inAllocator,
309					RecordId &recordId);
310protected:
311	const RefPointer<const DbVersion> mDbVersion;
312};
313
314
315//
316// LinearCursor
317//
318class LinearCursor : public Cursor
319{
320    NOCOPY(LinearCursor)
321public:
322    LinearCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion,
323		   const Table &inTable);
324    virtual ~LinearCursor();
325    virtual bool next(Table::Id &outTableId,
326					CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
327					CssmData *outData,
328					Allocator &inAllocator,
329					RecordId &recordId);
330
331private:
332	uint32 mRecordsCount;
333    uint32 mRecord;
334	const ReadSection mRecordsSection;
335	uint32 mReadOffset;
336    const MetaRecord &mMetaRecord;
337
338    CSSM_DB_CONJUNCTIVE mConjunctive;
339    CSSM_QUERY_FLAGS mQueryFlags; // If CSSM_QUERY_RETURN_DATA is set return the raw key bits;
340    typedef vector<SelectionPredicate *> PredicateVector;
341
342    PredicateVector mPredicates;
343};
344
345//
346// A cursor that uses an index.
347//
348
349class IndexCursor : public Cursor
350{
351	NOCOPY(IndexCursor)
352public:
353	IndexCursor(DbQueryKey *queryKey, const DbVersion &inDbVersion,
354		const Table &table, const DbConstIndex *index);
355	virtual ~IndexCursor();
356
357    virtual bool next(Table::Id &outTableId,
358					CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
359					CssmData *outData,
360					Allocator &inAllocator,
361					RecordId &recordId);
362
363private:
364	auto_ptr<DbQueryKey> mQueryKey;
365	const Table &mTable;
366	const DbConstIndex *mIndex;
367
368	DbIndexIterator mBegin, mEnd;
369};
370
371//
372// MultiCursor
373//
374class MultiCursor : public Cursor
375{
376    NOCOPY(MultiCursor)
377public:
378    MultiCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion);
379    virtual ~MultiCursor();
380    virtual bool next(Table::Id &outTableId,
381					CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
382					CssmData *outData,
383					Allocator &inAllocator,
384					RecordId &recordId);
385private:
386	auto_ptr<CssmAutoQuery> mQuery;
387
388	DbVersion::const_iterator mTableIterator;
389	auto_ptr<Cursor> mCursor;
390};
391
392//
393// A DbModifier contains all pending changes to be made to a DB.
394// It also contains a DbVersion representing the state of the Database before any such changes
395// No read-style operations are supported by DbModifier.  If a DbModifier exists for a
396// particular Database and a client wishes to perform a query commit() must be called and
397// the client should perform the new query on the current database version after the commit.
398// Otherwise a client will not see changes made since the DbModifier was instanciated.
399//
400class DbModifier : public Metadata
401{
402	NOCOPY(DbModifier)
403public:
404    DbModifier(AtomicFile &inAtomicFile, const class AppleDatabase &db);
405    ~DbModifier();
406
407	// Whole database affecting members.
408    void createDatabase(const CSSM_DBINFO &inDbInfo,
409						const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry,
410						mode_t mode);
411	void openDatabase(); // This is optional right now.
412	void closeDatabase();
413	void deleteDatabase();
414
415    void commit();
416    void rollback() throw();
417
418	// Record changing members
419	void deleteRecord(Table::Id inTableId, const RecordId &inRecordId);
420	const RecordId insertRecord(Table::Id inTableId,
421								const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
422								const CssmData *inData);
423	const RecordId updateRecord(Table::Id inTableId, const RecordId &inRecordId,
424								const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
425								const CssmData *inData,
426								CSSM_DB_MODIFY_MODE inModifyMode);
427
428	// Schema changing members
429    void insertTable(Table::Id inTableId, const string &inTableName,
430					 uint32 inNumberOfAttributes,
431					 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
432					 uint32 inNumberOfIndexes,
433					 const CSSM_DB_SCHEMA_INDEX_INFO *inIndexInfo);
434	void deleteTable(Table::Id inTableId);
435
436	// Record reading members
437	const RecordId getRecord(Table::Id inTableId, const RecordId &inRecordId,
438							 CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
439							 CssmData *inoutData, Allocator &inAllocator);
440	Cursor *createCursor(const CSSM_QUERY *inQuery);
441
442	bool hasTable(Table::Id inTableid);
443
444protected:
445    void modifyDatabase();
446    const RefPointer<const DbVersion> getDbVersion(bool force);
447
448    ModifiedTable *createTable(MetaRecord *inMetaRecord); // Takes over ownership of inMetaRecord
449
450	void insertTableSchema(const CssmDbRecordAttributeInfo &inInfo,
451		const CSSM_DB_RECORD_INDEX_INFO *inIndexInfo = NULL);
452
453	void insertTable(const CssmDbRecordAttributeInfo &inInfo,
454		const CSSM_DB_RECORD_INDEX_INFO * inIndexInfo = NULL,
455		const CSSM_DB_PARSING_MODULE_INFO * inParsingModule = NULL);
456
457    ModifiedTable &findTable(Table::Id inTableId);
458
459    uint32 writeAuthSection(uint32 inSectionOffset);
460    uint32 writeSchemaSection(uint32 inSectionOffset);
461
462private:
463
464	/* mDbVersion is the current DbVersion of this database before any changes
465       we are going to make.  mNotifyCount holds the value of gNotifyCount at
466       the time mDbVersion was created.  mDbLastRead is the time at which we
467       last checked if the file from which mDbVersion was read has changed.
468       mDbVersionLock protects the other 3 fields.  */
469	RefPointer<const DbVersion> mDbVersion;
470    int32_t mNotifyCount;
471    CFAbsoluteTime mDbLastRead;
472	Mutex mDbVersionLock;
473
474    AtomicFile &mAtomicFile;
475    uint32 mVersionId;
476	RefPointer<AtomicTempFile> mAtomicTempFile;
477
478    typedef map<Table::Id, ModifiedTable *> ModifiedTableMap;
479    ModifiedTableMap mModifiedTableMap;
480
481	const class AppleDatabase &mDb;
482};
483
484//
485// AppleDatabaseManager
486//
487class AppleDatabaseManager : public DatabaseManager
488{
489public:
490	AppleDatabaseManager(const AppleDatabaseTableName *tableNames);
491    Database *make(const DbName &inDbName);
492
493protected:
494	const AppleDatabaseTableName *mTableNames;
495};
496
497//
498// AppleDbContext
499//
500class AppleDbContext : public DbContext
501{
502public:
503	AppleDbContext(Database &inDatabase,
504				   DatabaseSession &inDatabaseSession,
505				   CSSM_DB_ACCESS_TYPE inAccessRequest,
506				   const AccessCredentials *inAccessCred,
507				   const void *inOpenParameters);
508	virtual ~AppleDbContext();
509	bool autoCommit() const { return mAutoCommit; }
510	void autoCommit(bool on) { mAutoCommit = on; }
511	mode_t mode() const { return mMode; }
512
513private:
514	bool mAutoCommit;
515	mode_t mMode;
516};
517
518//
519// AppleDatabase
520//
521class AppleDatabase : public Database
522{
523public:
524    AppleDatabase(const DbName &inDbName, const AppleDatabaseTableName *tableNames);
525    virtual ~AppleDatabase();
526
527    virtual void
528        dbCreate(DbContext &inDbContext, const CSSM_DBINFO &inDBInfo,
529                 const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry);
530
531    virtual void
532        dbOpen(DbContext &inDbContext);
533
534    virtual void
535        dbClose();
536
537    virtual void
538        dbDelete(DatabaseSession &inDatabaseSession,
539                 const AccessCredentials *inAccessCred);
540
541    virtual void
542        createRelation(DbContext &inDbContext,
543                       CSSM_DB_RECORDTYPE inRelationID,
544                       const char *inRelationName,
545                       uint32 inNumberOfAttributes,
546                       const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
547                       uint32 inNumberOfIndexes,
548                       const CSSM_DB_SCHEMA_INDEX_INFO &inIndexInfo);
549
550    virtual void
551        destroyRelation(DbContext &inDbContext,
552                        CSSM_DB_RECORDTYPE inRelationID);
553
554    virtual void
555        authenticate(DbContext &inDbContext,
556                     CSSM_DB_ACCESS_TYPE inAccessRequest,
557                     const AccessCredentials &inAccessCred);
558
559    virtual void
560        getDbAcl(DbContext &inDbContext,
561                 const CSSM_STRING *inSelectionTag,
562                 uint32 &outNumberOfAclInfos,
563                 CSSM_ACL_ENTRY_INFO_PTR &outAclInfos);
564
565    virtual void
566        changeDbAcl(DbContext &inDbContext,
567                    const AccessCredentials &inAccessCred,
568                    const CSSM_ACL_EDIT &inAclEdit);
569
570    virtual void
571        getDbOwner(DbContext &inDbContext, CSSM_ACL_OWNER_PROTOTYPE &outOwner);
572
573    virtual void
574        changeDbOwner(DbContext &inDbContext,
575                      const AccessCredentials &inAccessCred,
576                      const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner);
577
578    virtual char *
579        getDbNameFromHandle(const DbContext &inDbContext) const;
580
581    virtual CSSM_DB_UNIQUE_RECORD_PTR
582        dataInsert(DbContext &inDbContext,
583                   CSSM_DB_RECORDTYPE RecordType,
584                   const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
585                   const CssmData *inData);
586
587    virtual void
588        dataDelete(DbContext &inDbContext,
589                   const CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier);
590
591    virtual void
592        dataModify(DbContext &inDbContext,
593                   CSSM_DB_RECORDTYPE inRecordType,
594                   CSSM_DB_UNIQUE_RECORD &inoutUniqueRecordIdentifier,
595                   const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributesToBeModified,
596                   const CssmData *inDataToBeModified,
597                   CSSM_DB_MODIFY_MODE inModifyMode);
598
599    virtual CSSM_HANDLE
600        dataGetFirst(DbContext &inDbContext,
601                     const CssmQuery *inQuery,
602                     CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
603                     CssmData *inoutData,
604                     CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord);
605
606    virtual bool
607        dataGetNext(DbContext &inDbContext,
608                    CSSM_HANDLE inResultsHandle,
609                    CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
610                    CssmData *inoutData,
611                    CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord);
612
613    virtual void
614        dataAbortQuery(DbContext &inDbContext,
615                       CSSM_HANDLE inResultsHandle);
616
617    virtual void
618        dataGetFromUniqueRecordId(DbContext &inDbContext,
619                                  const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
620                                  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
621                                  CssmData *inoutData);
622
623    virtual void
624        freeUniqueRecord(DbContext &inDbContext,
625                         CSSM_DB_UNIQUE_RECORD &inUniqueRecord);
626
627	virtual void passThrough(DbContext &dbContext,
628							 uint32 passThroughId,
629							 const void *inputParams,
630							 void **outputParams);
631
632    // Subclasses must implement this method.
633    virtual DbContext *makeDbContext(DatabaseSession &inDatabaseSession,
634                                     CSSM_DB_ACCESS_TYPE inAccessRequest,
635                                     const AccessCredentials *inAccessCred,
636                                     const void *inOpenParameters);
637
638	const CssmDbRecordAttributeInfo schemaRelations;
639	const CssmDbRecordAttributeInfo schemaAttributes;
640	const CssmDbRecordAttributeInfo schemaIndexes;
641	const CssmDbRecordAttributeInfo schemaParsingModule;
642
643	const char *recordName(CSSM_DB_RECORDTYPE inRecordType) const;
644
645private:
646	static void
647	updateUniqueRecord(DbContext &inDbContext,
648									CSSM_DB_RECORDTYPE inTableId,
649									const RecordId &inRecordId,
650									CSSM_DB_UNIQUE_RECORD &inoutUniqueRecord);
651
652	CSSM_DB_UNIQUE_RECORD_PTR
653	createUniqueRecord(DbContext &inDbContext, CSSM_DB_RECORDTYPE inTableId,
654					   const RecordId &inRecordId);
655	const RecordId parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
656									 CSSM_DB_RECORDTYPE &outTableId);
657
658    Mutex mWriteLock;
659    AtomicFile mAtomicFile;
660	DbModifier mDbModifier;
661	const AppleDatabaseTableName *mTableNames;
662};
663
664} // end namespace Security
665
666#endif //_H_APPLEDATABASE
667