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