2 * Copyright (c) 2000-2001,2003,2011,2014 Apple Inc. All Rights Reserved.
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
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.
20 // AppleDatabase.h - Description t.b.d.
22 #ifndef _H_APPLEDATABASE
23 #define _H_APPLEDATABASE
25 #include "MetaRecord.h"
26 #include "SelectionPredicate.h"
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>
36 #include <CoreFoundation/CFDate.h>
41 // Abstract database Cursor class.
46 struct AppleDatabaseTableName
49 const char *mTableName
;
51 // indices of meta-table entries in an array of table names
58 kNumRequiredTableNames
63 // This is what the CDSA standard refers to as a Relation. We use
64 // the more conventional term Table.
70 // Type used to refer to a table.
71 typedef CSSM_DB_RECORDTYPE Id
;
73 Table(const ReadSection
&inTableSection
);
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;
80 const ReadSection
getRecordSection(uint32 inRecordNumber
) const;
82 const RecordId
getRecord(const RecordId
&inRecordId
,
83 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
85 Allocator
&inAllocator
) const;
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
; }
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;
95 MetaRecord
&getMetaRecord() { return mMetaRecord
; }
96 const MetaRecord
&getMetaRecord() const { return mMetaRecord
; }
98 uint32
getRecordsCount() const { return mRecordsCount
; }
99 const ReadSection
getRecordsSection() const;
101 const ReadSection
&getTableSection() const { return mTableSection
; }
103 bool matchesTableId(Id inTableId
) const;
105 void readIndexSection();
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
119 friend class ModifiedTable
;
121 MetaRecord mMetaRecord
;
122 const ReadSection mTableSection
;
124 uint32 mRecordsCount
;
125 uint32 mFreeListHead
;
126 // Number of record numbers (including freelist slots) in this table.
127 uint32 mRecordNumbersCount
;
129 // all the table's indexes, mapped by index id
130 typedef map
<uint32
, DbConstIndex
*> ConstIndexMap
;
131 ConstIndexMap mIndexMap
;
136 NOCOPY(ModifiedTable
)
138 ModifiedTable(const Table
*inTable
);
139 ModifiedTable(MetaRecord
*inMetaRecord
); // Take over ownership of inMetaRecord
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
,
154 Allocator
&inAllocator
) const;
156 // Return the MetaRecord this table should use for writes.
157 const MetaRecord
&getMetaRecord() const;
159 // find, and create if needed, an index with the given id
160 DbMutableIndex
&findIndex(uint32 indexId
, const MetaRecord
&metaRecord
, bool isUniqueIndex
);
162 // Write this table to inOutputFile at inSectionOffset and return the new offset.
163 uint32
writeTable(AtomicTempFile
&inAtomicTempFile
, uint32 inSectionOffset
);
166 // Return the next available record number for this table.
167 uint32
nextRecordNumber();
169 // Return the number of recordNumbers in use by this table including empty slots.
170 uint32
recordNumberCount() const;
173 void createMutableIndexes();
174 uint32
writeIndexSection(WriteSection
&tableSection
, uint32 offset
);
176 // Optional, this is merly a reference, we do not own this object.
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
;
183 // Set of Records that have been deleted or modified.
184 typedef set
<uint32
> DeletedSet
;
185 DeletedSet mDeletedSet
;
187 // Set of Records that have been inserted or modified.
188 typedef map
<uint32
, WriteSection
*> InsertedMap
;
189 InsertedMap mInsertedMap
;
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
;
197 // has this table actually been modified?
200 typedef map
<uint32
, DbMutableIndex
*> MutableIndexMap
;
201 MutableIndexMap mIndexMap
;
205 // Read only snapshot of a database.
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,
221 HeaderMagic
= FOUR_CHAR_CODE('kych'),
222 HeaderVersion
= 0x00010000
227 OffsetSchemaSize
= AtomSize
* 0,
228 OffsetTablesCount
= AtomSize
* 1,
229 OffsetTables
= AtomSize
* 2
234 // Read only representation of a database
236 class DbVersion
: public Metadata
, public RefCount
240 DbVersion(const class AppleDatabase
&db
, const RefPointer
<AtomicBufferedFile
> &inAtomicBufferedFile
);
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;
249 const Table
&findTable(Table::Id inTableId
) const;
250 Table
&findTable(Table::Id inTableId
);
253 void open(); // Part of constructor contract.
255 ReadSection mDatabase
;
258 friend class DbModifier
; // XXX Fixme
259 typedef map
<Table::Id
, Table
*> TableMap
;
261 const class AppleDatabase
&mDb
;
262 RefPointer
<AtomicBufferedFile
> mBufferedFile
;
265 typedef Table value_type
;
266 typedef const Table
&const_reference
;
267 typedef const Table
*const_pointer
;
269 // A const forward iterator.
273 const_iterator(const TableMap::const_iterator
&it
) : mIterator(it
) {}
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
; }
284 const_pointer
operator->() const { return mIterator
->second
; } // Not really needed.
287 TableMap::const_iterator mIterator
;
290 const_iterator
begin() const { return const_iterator(mTableMap
.begin()); }
291 const_iterator
end() const { return const_iterator(mTableMap
.end()); }
293 bool hasTable(Table::Id inTableId
) const;
299 class Cursor
: public HandleObject
303 Cursor(const DbVersion
&inDbVersion
);
305 virtual bool next(Table::Id
&outTableId
,
306 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
308 Allocator
&inAllocator
,
311 const RefPointer
<const DbVersion
> mDbVersion
;
318 class LinearCursor
: public Cursor
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
,
328 Allocator
&inAllocator
,
332 uint32 mRecordsCount
;
334 const ReadSection mRecordsSection
;
336 const MetaRecord
&mMetaRecord
;
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
;
342 PredicateVector mPredicates
;
346 // A cursor that uses an index.
349 class IndexCursor
: public Cursor
353 IndexCursor(DbQueryKey
*queryKey
, const DbVersion
&inDbVersion
,
354 const Table
&table
, const DbConstIndex
*index
);
355 virtual ~IndexCursor();
357 virtual bool next(Table::Id
&outTableId
,
358 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes
,
360 Allocator
&inAllocator
,
364 auto_ptr
<DbQueryKey
> mQueryKey
;
366 const DbConstIndex
*mIndex
;
368 DbIndexIterator mBegin
, mEnd
;
374 class MultiCursor
: public Cursor
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
,
383 Allocator
&inAllocator
,
386 auto_ptr
<CssmAutoQuery
> mQuery
;
388 DbVersion::const_iterator mTableIterator
;
389 auto_ptr
<Cursor
> mCursor
;
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.
400 class DbModifier
: public Metadata
404 DbModifier(AtomicFile
&inAtomicFile
, const class AppleDatabase
&db
);
407 // Whole database affecting members.
408 void createDatabase(const CSSM_DBINFO
&inDbInfo
,
409 const CSSM_ACL_ENTRY_INPUT
*inInitialAclEntry
,
411 void openDatabase(); // This is optional right now.
412 void closeDatabase();
413 void deleteDatabase();
416 void rollback() throw();
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
);
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
);
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
);
442 bool hasTable(Table::Id inTableid
);
444 void modifyDatabase();
446 const RefPointer
<const DbVersion
> getDbVersion(bool force
);
448 ModifiedTable
*createTable(MetaRecord
*inMetaRecord
); // Takes over ownership of inMetaRecord
450 void insertTableSchema(const CssmDbRecordAttributeInfo
&inInfo
,
451 const CSSM_DB_RECORD_INDEX_INFO
*inIndexInfo
= NULL
);
453 void insertTable(const CssmDbRecordAttributeInfo
&inInfo
,
454 const CSSM_DB_RECORD_INDEX_INFO
* inIndexInfo
= NULL
,
455 const CSSM_DB_PARSING_MODULE_INFO
* inParsingModule
= NULL
);
457 ModifiedTable
&findTable(Table::Id inTableId
);
459 uint32
writeAuthSection(uint32 inSectionOffset
);
460 uint32
writeSchemaSection(uint32 inSectionOffset
);
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
;
474 AtomicFile
&mAtomicFile
;
476 RefPointer
<AtomicTempFile
> mAtomicTempFile
;
478 typedef map
<Table::Id
, ModifiedTable
*> ModifiedTableMap
;
479 ModifiedTableMap mModifiedTableMap
;
481 const class AppleDatabase
&mDb
;
485 // AppleDatabaseManager
487 class AppleDatabaseManager
: public DatabaseManager
490 AppleDatabaseManager(const AppleDatabaseTableName
*tableNames
);
491 Database
*make(const DbName
&inDbName
);
494 const AppleDatabaseTableName
*mTableNames
;
500 class AppleDbContext
: public DbContext
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
; }
521 class AppleDatabase
: public Database
524 AppleDatabase(const DbName
&inDbName
, const AppleDatabaseTableName
*tableNames
);
525 virtual ~AppleDatabase();
528 dbCreate(DbContext
&inDbContext
, const CSSM_DBINFO
&inDBInfo
,
529 const CSSM_ACL_ENTRY_INPUT
*inInitialAclEntry
);
532 dbOpen(DbContext
&inDbContext
);
538 dbDelete(DatabaseSession
&inDatabaseSession
,
539 const AccessCredentials
*inAccessCred
);
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
);
551 destroyRelation(DbContext
&inDbContext
,
552 CSSM_DB_RECORDTYPE inRelationID
);
555 authenticate(DbContext
&inDbContext
,
556 CSSM_DB_ACCESS_TYPE inAccessRequest
,
557 const AccessCredentials
&inAccessCred
);
560 getDbAcl(DbContext
&inDbContext
,
561 const CSSM_STRING
*inSelectionTag
,
562 uint32
&outNumberOfAclInfos
,
563 CSSM_ACL_ENTRY_INFO_PTR
&outAclInfos
);
566 changeDbAcl(DbContext
&inDbContext
,
567 const AccessCredentials
&inAccessCred
,
568 const CSSM_ACL_EDIT
&inAclEdit
);
571 getDbOwner(DbContext
&inDbContext
, CSSM_ACL_OWNER_PROTOTYPE
&outOwner
);
574 changeDbOwner(DbContext
&inDbContext
,
575 const AccessCredentials
&inAccessCred
,
576 const CSSM_ACL_OWNER_PROTOTYPE
&inNewOwner
);
579 getDbNameFromHandle(const DbContext
&inDbContext
) const;
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
);
588 dataDelete(DbContext
&inDbContext
,
589 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
);
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
);
600 dataGetFirst(DbContext
&inDbContext
,
601 const CssmQuery
*inQuery
,
602 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
604 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
);
607 dataGetNext(DbContext
&inDbContext
,
608 CSSM_HANDLE inResultsHandle
,
609 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
611 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
);
614 dataAbortQuery(DbContext
&inDbContext
,
615 CSSM_HANDLE inResultsHandle
);
618 dataGetFromUniqueRecordId(DbContext
&inDbContext
,
619 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
620 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
621 CssmData
*inoutData
);
624 freeUniqueRecord(DbContext
&inDbContext
,
625 CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
);
627 virtual void passThrough(DbContext
&dbContext
,
628 uint32 passThroughId
,
629 const void *inputParams
,
630 void **outputParams
);
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
);
638 // These two methods will throw an exception on error
639 virtual void dbMakeBackup();
640 virtual void dbMakeCopy(const char * path
);
642 // Delete the file under this database
643 virtual void dbDeleteFile();
645 const CssmDbRecordAttributeInfo schemaRelations
;
646 const CssmDbRecordAttributeInfo schemaAttributes
;
647 const CssmDbRecordAttributeInfo schemaIndexes
;
648 const CssmDbRecordAttributeInfo schemaParsingModule
;
650 const char *recordName(CSSM_DB_RECORDTYPE inRecordType
) const;
654 updateUniqueRecord(DbContext
&inDbContext
,
655 CSSM_DB_RECORDTYPE inTableId
,
656 const RecordId
&inRecordId
,
657 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecord
);
659 CSSM_DB_UNIQUE_RECORD_PTR
660 createUniqueRecord(DbContext
&inDbContext
, CSSM_DB_RECORDTYPE inTableId
,
661 const RecordId
&inRecordId
);
662 const RecordId
parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
663 CSSM_DB_RECORDTYPE
&outTableId
);
666 AtomicFile mAtomicFile
;
667 DbModifier mDbModifier
;
668 const AppleDatabaseTableName
*mTableNames
;
671 } // end namespace Security
673 #endif //_H_APPLEDATABASE