]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_filedb/lib/AppleDatabase.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / libsecurity_filedb / lib / AppleDatabase.cpp
diff --git a/libsecurity_filedb/lib/AppleDatabase.cpp b/libsecurity_filedb/lib/AppleDatabase.cpp
deleted file mode 100644 (file)
index 4d640eb..0000000
+++ /dev/null
@@ -1,2561 +0,0 @@
-/*
- * Copyright (c) 2000-2001, 2003 Apple Computer, 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.
- */
-
-
-//
-//  AppleDatabase.cpp - Description t.b.d.
-//
-#include "AppleDatabase.h"
-#include <security_cdsa_plugin/DatabaseSession.h>
-#include <security_cdsa_plugin/DbContext.h>
-#include <security_cdsa_utilities/cssmdb.h>
-#include <Security/cssmapple.h>
-#include <security_utilities/trackingallocator.h>
-#include <security_utilities/logging.h>
-#include <fcntl.h>
-#include <memory>
-#include <libkern/OSAtomic.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <Security/cssmapplePriv.h>
-#include <syslog.h>
-
-static const char *kAppleDatabaseChanged = "com.apple.AppleDatabaseChanged";
-
-/* Number of seconds after which we open/pread/close a db to check it's
-   version number even if we didn't get any notifications.  Note that we always
-   check just after we take a write lock and whenever we get a notification
-   that any db on the system has changed. */
-static const CFTimeInterval kForceReReadTime = 15.0;
-
-/* Token on which we receive notifications and the pthread_once_t protecting
-   it's initialization. */
-pthread_once_t gCommonInitMutex = PTHREAD_ONCE_INIT;
-
-/* Global counter of how many notifications we have received and a lock to
-   protect the counter. */
-static int kSegmentSize = 4;
-int32_t* gSegment = NULL;
-
-/* Registration routine for notifcations. Called inside a pthread_once(). */
-static void initCommon(void)
-{
-       // open the file
-       int segmentDescriptor = shm_open (kAppleDatabaseChanged, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
-       if (segmentDescriptor < 0)
-       {
-               return;
-       }
-       
-       // set the segment size
-       ftruncate (segmentDescriptor, kSegmentSize);
-       
-       // map it into memory
-       int32_t* tmp = (int32_t*) mmap (NULL, kSegmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, segmentDescriptor, 0);
-       close (segmentDescriptor);
-
-       if (tmp == (int32_t*) -1) // can't map the memory?
-       {
-               gSegment = NULL;
-       }
-       else
-       {
-               gSegment = tmp;
-       }
-}
-
-//
-// Table
-//
-Table::Table(const ReadSection &inTableSection) :
-       mMetaRecord(inTableSection[OffsetId]),
-       mTableSection(inTableSection),
-       mRecordsCount(inTableSection[OffsetRecordsCount]),
-       mFreeListHead(inTableSection[OffsetFreeListHead]),
-       mRecordNumbersCount(inTableSection[OffsetRecordNumbersCount])
-{
-       // can't easily initialize indexes here, since meta record is incomplete
-       // until much later... see DbVersion::open()
-}
-
-Table::~Table() 
-{
-       for_each_map_delete(mIndexMap.begin(), mIndexMap.end());
-}
-
-void
-Table::readIndexSection()
-{
-       uint32 indexSectionOffset = mTableSection.at(OffsetIndexesOffset);
-
-       uint32 numIndexes = mTableSection.at(indexSectionOffset + AtomSize);
-
-       for (uint32 i = 0; i < numIndexes; i++) {
-               uint32 indexOffset = mTableSection.at(indexSectionOffset + (i + 2) * AtomSize);
-               ReadSection indexSection(mTableSection.subsection(indexOffset));
-       
-               auto_ptr<DbConstIndex> index(new DbConstIndex(*this, indexSection));
-               mIndexMap.insert(ConstIndexMap::value_type(index->indexId(), index.get()));
-               index.release();
-       }
-}
-
-Cursor *
-Table::createCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion) const
-{
-       // if an index matches the query, return a cursor which uses the index
-
-       ConstIndexMap::const_iterator it;
-       DbQueryKey *queryKey;
-       
-       for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-               if (it->second->matchesQuery(*inQuery, queryKey)) {
-                       IndexCursor *cursor = new IndexCursor(queryKey, inDbVersion, *this, it->second);
-                       return cursor;
-               }
-
-       // otherwise, return a cursor that iterates over all table records
-
-       return new LinearCursor(inQuery, inDbVersion, *this);
-}
-
-const ReadSection
-Table::getRecordSection(uint32 inRecordNumber) const
-{
-       if (inRecordNumber >= mRecordNumbersCount)
-               CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
-
-       uint32 aRecordOffset = mTableSection[OffsetRecordNumbers + AtomSize
-                                                                                * inRecordNumber];
-
-       // Check if this RecordNumber has been deleted.
-       if (aRecordOffset & 1 || aRecordOffset == 0)
-               CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-
-       return MetaRecord::readSection(mTableSection, aRecordOffset);
-}
-
-const RecordId
-Table::getRecord(const RecordId &inRecordId,
-                                CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                                CssmData *inoutData,
-                                Allocator &inAllocator) const
-{
-       const ReadSection aRecordSection = getRecordSection(inRecordId.mRecordNumber);
-       const RecordId aRecordId = MetaRecord::unpackRecordId(aRecordSection);
-
-       // Make sure the RecordNumber matches that in the RecordId we just retrived.
-       if (aRecordId.mRecordNumber != inRecordId.mRecordNumber)
-               CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-
-       if (aRecordId.mCreateVersion != inRecordId.mCreateVersion)
-               CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
-
-       // XXX Figure out which value to pass for inQueryFlags (5th) argument
-       mMetaRecord.unpackRecord(aRecordSection, inAllocator, inoutAttributes,
-                                                        inoutData, 0);
-       return aRecordId;
-}
-
-uint32
-Table::popFreeList(uint32 &aFreeListHead) const
-{
-       assert(aFreeListHead | 1);
-       uint32 anOffset = aFreeListHead ^ 1;
-       uint32 aRecordNumber = (anOffset - OffsetRecordNumbers) / AtomSize;
-       aFreeListHead = mTableSection[anOffset];
-       return aRecordNumber;
-}
-
-const ReadSection
-Table::getRecordsSection() const
-{
-       return mTableSection.subsection(mTableSection[OffsetRecords]);
-}
-
-bool
-Table::matchesTableId(Id inTableId) const
-{
-       Id anId = mMetaRecord.dataRecordType();
-       if (inTableId == CSSM_DL_DB_RECORD_ANY) // All non schema tables.
-               return !(CSSM_DB_RECORDTYPE_SCHEMA_START <= anId
-                                && anId < CSSM_DB_RECORDTYPE_SCHEMA_END);
-
-       if (inTableId == CSSM_DL_DB_RECORD_ALL_KEYS) // All key tables.
-               return (anId == CSSM_DL_DB_RECORD_PUBLIC_KEY
-                               || anId == CSSM_DL_DB_RECORD_PRIVATE_KEY
-                               || anId == CSSM_DL_DB_RECORD_SYMMETRIC_KEY);
-
-       return inTableId == anId; // Only if exact match.
-}
-
-
-//
-// ModifiedTable
-//
-ModifiedTable::ModifiedTable(const Table *inTable) :
-       mTable(inTable),
-       mNewMetaRecord(nil),
-       mRecordNumberCount(inTable->recordNumberCount()),
-       mFreeListHead(inTable->freeListHead()),
-       mIsModified(false)
-{
-}
-
-ModifiedTable::ModifiedTable(MetaRecord *inMetaRecord) :
-       mTable(nil),
-       mNewMetaRecord(inMetaRecord),
-       mRecordNumberCount(0),
-       mFreeListHead(0),
-       mIsModified(true)
-{
-}
-
-ModifiedTable::~ModifiedTable()
-{
-       for_each_map_delete(mIndexMap.begin(), mIndexMap.end());
-       for_each_map_delete(mInsertedMap.begin(), mInsertedMap.end());
-
-       delete mNewMetaRecord;
-}
-
-void
-ModifiedTable::deleteRecord(const RecordId &inRecordId)
-{
-       modifyTable();
-
-    uint32 aRecordNumber = inRecordId.mRecordNumber;
-       
-       // remove the record from all the indexes
-       MutableIndexMap::iterator it;
-       for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-               it->second->removeRecord(aRecordNumber);
-
-       InsertedMap::iterator anIt = mInsertedMap.find(aRecordNumber);
-       if (anIt == mInsertedMap.end())
-       {
-               // If we have no old table than this record can not exist yet.
-               if (!mTable)
-                       CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-
-#if RECORDVERSIONCHECK
-               const RecordId aRecordId = MetaRecord::unpackRecordId(mTable->getRecordSection(aRecordNumber));
-               if (aRecordId.mRecordVersion != inRecordId.mRecordVersion)
-                       CssmError::throwMe(CSSMERR_DL_RECORD_MODIFIED);
-#endif
-
-               // Schedule the record for deletion
-               if (!mDeletedSet.insert(aRecordNumber).second)
-                       CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND); // It was already deleted
-       }
-       else
-       {
-               const RecordId aRecordId = MetaRecord::unpackRecordId(*anIt->second);
-               if (aRecordId.mCreateVersion != inRecordId.mCreateVersion)
-                       CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-
-#if RECORDVERSIONCHECK
-               if (aRecordId.mRecordVersion != inRecordId.mRecordVersion)
-                       CssmError::throwMe(CSSMERR_DL_RECORD_MODIFIED);
-#endif
-
-               // Remove the inserted (but uncommited) record.  It should already be in mDeletedSet
-               // if it existed previously in mTable.
-        delete anIt->second;           
-               mInsertedMap.erase(anIt);
-       }
-}
-
-const RecordId
-ModifiedTable::insertRecord(uint32 inVersionId,
-                                                       const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
-                                                       const CssmData *inData)
-{
-       modifyTable();
-       
-       auto_ptr<WriteSection> aWriteSection(new WriteSection());
-       getMetaRecord().packRecord(*aWriteSection, inAttributes, inData);
-    uint32 aRecordNumber = nextRecordNumber();
-       
-       // add the record to all the indexes; this will throw if the new record
-       // violates a unique index
-       MutableIndexMap::iterator it;
-       for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-               it->second->insertRecord(aRecordNumber, *(aWriteSection.get()));
-
-       // schedule the record for insertion
-       RecordId aRecordId(aRecordNumber, inVersionId);
-       MetaRecord::packRecordId(aRecordId, *aWriteSection);
-    mInsertedMap.insert(InsertedMap::value_type(aRecordNumber, aWriteSection.get()));
-
-    aWriteSection.release();
-       
-    return aRecordId;
-}
-
-const RecordId
-ModifiedTable::updateRecord(const RecordId &inRecordId,
-                                                       const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
-                                                       const CssmData *inData,
-                                                       CSSM_DB_MODIFY_MODE inModifyMode)
-{
-       modifyTable();
-
-    uint32 aRecordNumber = inRecordId.mRecordNumber;
-       InsertedMap::iterator anIt = mInsertedMap.find(aRecordNumber);
-
-       // aReUpdate is true iff we are updating an already updated record.
-       bool aReUpdate = anIt != mInsertedMap.end();
-
-       // If we are not re-updating and there is no old table than this record does not exist yet.
-       if (!aReUpdate && !mTable)
-               CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-
-       const ReadSection &anOldDbRecord = aReUpdate ? *anIt->second : mTable->getRecordSection(aRecordNumber);
-       const RecordId aRecordId = MetaRecord::unpackRecordId(anOldDbRecord);
-
-       // Did someone else delete the record we are trying to update.
-       if (aRecordId.mCreateVersion != inRecordId.mCreateVersion)
-               CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-
-#if RECORDVERSIONCHECK
-       // Is the record we that our update is based on current?
-       if (aRecordId.mRecordVersion != inRecordId.mRecordVersion)
-               CssmError::throwMe(CSSMERR_DL_STALE_UNIQUE_RECORD);
-#endif
-
-       // Update the actual packed record.
-    auto_ptr<WriteSection> aDbRecord(new WriteSection());
-       getMetaRecord().updateRecord(anOldDbRecord, *aDbRecord,
-               CssmDbRecordAttributeData::overlay(inAttributes), inData, inModifyMode);
-
-
-       // Bump the RecordVersion of this record.
-       RecordId aNewRecordId(aRecordNumber, inRecordId.mCreateVersion, inRecordId.mRecordVersion + 1);
-       // Store the RecordVersion in the packed aDbRecord.
-       MetaRecord::packRecordId(aNewRecordId, *aDbRecord);
-
-       if (!aReUpdate && !mDeletedSet.insert(aRecordNumber).second)
-               CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND); // Record was already in mDeletedSet
-
-       // remove the original record from all the indexes
-       MutableIndexMap::iterator it;
-       for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-               it->second->removeRecord(aRecordNumber);
-
-       try
-       {
-               // Add the updated record to all the indexes; this will throw if the new record
-               // violates a unique index
-               for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-                       it->second->insertRecord(aRecordNumber, *(aDbRecord.get()));
-
-               if (aReUpdate)
-               {
-                       // Get rid of anOldDbRecord from the inserted map and replace it
-                       // with aDbRecord.
-                       delete anIt->second;
-                       anIt->second = aDbRecord.get();
-               }
-               else
-               {
-                       // First time though so let's just put the new value in the map.
-                       mInsertedMap.insert(InsertedMap::value_type(aRecordNumber, aDbRecord.get()));
-               }
-               aDbRecord.release();
-       }
-       catch(...)
-       {
-               // We only remove aRecordNumber from mDeletedSet if we added it above.
-               if (!aReUpdate)
-                       mDeletedSet.erase(aRecordNumber);
-
-               // The 2 operations below are an attempt to preserve the indices when
-               // an insert fails.
-
-               // Remove the updated record from all the indexes
-               MutableIndexMap::iterator it;
-               for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-                       it->second->removeRecord(aRecordNumber);
-
-               // Add the original record back to all the indexes
-               for (it = mIndexMap.begin(); it != mIndexMap.end(); it++)
-                       it->second->insertRecord(aRecordNumber, anOldDbRecord);
-
-               throw;
-       }
-
-       return aNewRecordId;
-}
-
-const RecordId
-ModifiedTable::getRecord(const RecordId &inRecordId,
-                                                CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                                                CssmData *inoutData,
-                                                Allocator &inAllocator) const
-{
-       if (mIsModified)
-       {
-               uint32 aRecordNumber = inRecordId.mRecordNumber;
-               InsertedMap::const_iterator anIt = mInsertedMap.find(aRecordNumber);
-               if (anIt != mInsertedMap.end())
-               {
-                       // We found the record in mInsertedMap so we use the inserted
-                       // record.
-                       const ReadSection &aRecordSection = *(anIt->second);
-                       const RecordId aRecordId = MetaRecord::unpackRecordId(aRecordSection);
-
-                       // Make sure the RecordNumber matches that in the RecordId we just retrived.
-                       if (aRecordId.mRecordNumber != aRecordNumber)
-                               CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-
-                       if (aRecordId.mCreateVersion != inRecordId.mCreateVersion)
-                               CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
-
-                       // XXX Figure out which value to pass for inQueryFlags (5th) argument
-                       getMetaRecord().unpackRecord(aRecordSection, inAllocator,
-                               inoutAttributes, inoutData, 0);
-
-                       return aRecordId;
-               }
-               else if (mDeletedSet.find(aRecordNumber) != mDeletedSet.end())
-               {
-                        // If aRecordNumber was not in mInsertedMap but it was in
-                        // mDeletedSet then it was deleted but not yet commited.
-                       CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-               }
-       }
-
-       if (!mTable)
-               CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND);
-
-       // Either this table wasn't modified yet or we didn't find aRecordNumber in
-       // mInsertedMap nor mDeletedSet so just ask mTable for it.
-       return mTable->getRecord(inRecordId, inoutAttributes, inoutData,
-               inAllocator);
-}
-
-uint32
-ModifiedTable::nextRecordNumber()
-{
-       // If we still have unused free records in mTable get the next one.
-       if (mFreeListHead)
-               return mTable->popFreeList(mFreeListHead);
-
-       // Bump up the mRecordNumberCount so we don't reuse the same one.
-       return mRecordNumberCount++;
-}
-
-uint32
-ModifiedTable::recordNumberCount() const
-{
-       uint32 anOldMax = !mTable ? 0 : mTable->recordNumberCount() - 1;
-       uint32 anInsertedMax = mInsertedMap.empty() ? 0 : mInsertedMap.rbegin()->first;
-
-       DeletedSet::reverse_iterator anIt = mDeletedSet.rbegin();
-       DeletedSet::reverse_iterator anEnd = mDeletedSet.rend();
-       for (; anIt != anEnd; anIt++)
-       {
-               if (*anIt != anOldMax || anOldMax <= anInsertedMax)
-                       break;
-               anOldMax--;
-       }
-
-       return max(anOldMax,anInsertedMax) + 1;
-}
-
-const MetaRecord &
-ModifiedTable::getMetaRecord() const
-{
-       return mNewMetaRecord ? *mNewMetaRecord : mTable->getMetaRecord();
-}
-
-// prepare to modify the table
-
-void
-ModifiedTable::modifyTable()
-{
-       if (!mIsModified) {
-               createMutableIndexes();
-               mIsModified = true;
-       }
-}
-
-// create mutable indexes from the read-only indexes in the underlying table
-
-void
-ModifiedTable::createMutableIndexes()
-{
-       if (mTable == NULL)
-               return;
-       
-       Table::ConstIndexMap::const_iterator it;
-       for (it = mTable->mIndexMap.begin(); it != mTable->mIndexMap.end(); it++) {
-               auto_ptr<DbMutableIndex> mutableIndex(new DbMutableIndex(*it->second));
-               mIndexMap.insert(MutableIndexMap::value_type(it->first, mutableIndex.get()));
-               mutableIndex.release();
-       }
-}
-
-// find, and create if needed, an index with the given id
-
-DbMutableIndex &
-ModifiedTable::findIndex(uint32 indexId, const MetaRecord &metaRecord, bool isUniqueIndex)
-{
-       MutableIndexMap::iterator it = mIndexMap.find(indexId);
-
-       if (it == mIndexMap.end()) {
-               // create the new index
-               auto_ptr<DbMutableIndex> index(new DbMutableIndex(metaRecord, indexId, isUniqueIndex));
-               it = mIndexMap.insert(MutableIndexMap::value_type(indexId, index.get())).first;
-               index.release();
-       }
-
-       return *it->second;
-}
-
-uint32
-ModifiedTable::writeIndexSection(WriteSection &tableSection, uint32 offset)
-{
-       MutableIndexMap::iterator it;
-       
-       tableSection.put(Table::OffsetIndexesOffset, offset);
-       
-       // leave room for the size, to be written later
-       uint32 indexSectionOffset = offset;
-       offset += AtomSize;
-       
-       offset = tableSection.put(offset, (uint32)mIndexMap.size());
-       
-       // leave room for the array of offsets to the indexes
-       uint32 indexOffsetOffset = offset;
-       offset += mIndexMap.size() * AtomSize;
-       
-       // write the indexes
-       for (it = mIndexMap.begin(); it != mIndexMap.end(); it++) {
-               indexOffsetOffset = tableSection.put(indexOffsetOffset, offset);
-               offset = it->second->writeIndex(tableSection, offset);
-       }
-       
-       // write the total index section size
-       tableSection.put(indexSectionOffset, offset - indexSectionOffset);
-
-       return offset;
-}
-
-uint32
-ModifiedTable::writeTable(AtomicTempFile &inAtomicTempFile, uint32 inSectionOffset)
-{
-       if (mTable && !mIsModified) {
-               // the table has not been modified, so we can just dump the old table
-               // section into the new database
-
-               const ReadSection &tableSection = mTable->getTableSection();
-               uint32 tableSize = tableSection.at(Table::OffsetSize);
-               
-               inAtomicTempFile.write(AtomicFile::FromStart, inSectionOffset,
-                       tableSection.range(Range(0, tableSize)), tableSize);
-
-               return inSectionOffset + tableSize;
-       }
-
-       // We should have an old mTable or a mNewMetaRecord but not both.
-       assert(mTable != nil ^ mNewMetaRecord != nil);
-       const MetaRecord &aNewMetaRecord = getMetaRecord();
-       
-       uint32 aRecordsCount = 0;
-       uint32 aRecordNumbersCount = recordNumberCount();
-       uint32 aRecordsOffset = Table::OffsetRecordNumbers + AtomSize * aRecordNumbersCount;
-       WriteSection aTableSection(Allocator::standard(), aRecordsOffset);
-       aTableSection.size(aRecordsOffset);
-       aTableSection.put(Table::OffsetId, aNewMetaRecord.dataRecordType());
-       aTableSection.put(Table::OffsetRecords, aRecordsOffset);
-       aTableSection.put(Table::OffsetRecordNumbersCount, aRecordNumbersCount);
-       
-       uint32 anOffset = inSectionOffset + aRecordsOffset;
-
-       if (mTable)
-       {
-               // XXX Handle schema changes in the future.
-               assert(mNewMetaRecord == nil);
-               
-               // We have a modified old table so copy all non deleted records
-               // The code below is rather elaborate, but this is because it attempts
-               // to copy large ranges of non deleted records with single calls
-               // to AtomicFile::write()
-               uint32 anOldRecordsCount = mTable->getRecordsCount();
-               ReadSection aRecordsSection = mTable->getRecordsSection();
-               uint32 aReadOffset = 0;                                 // Offset of current record
-               uint32 aWriteOffset = aRecordsOffset;   // Offset for current write record
-               uint32 aBlockStart = aReadOffset;               // Starting point for read 
-               uint32 aBlockSize = 0;                                  // Size of block to read
-               for (uint32 aRecord = 0; aRecord < anOldRecordsCount; aRecord++)
-               {
-                       ReadSection aRecordSection = MetaRecord::readSection(aRecordsSection, aReadOffset);
-                       uint32 aRecordNumber = MetaRecord::unpackRecordNumber(aRecordSection);
-                       uint32 aRecordSize = aRecordSection.size();
-                       aReadOffset += aRecordSize;
-                       if (mDeletedSet.find(aRecordNumber) == mDeletedSet.end())
-                       {
-                               // This record has not been deleted.  Register the offset
-                               // at which it will be in the new file in aTableSection.
-                               aTableSection.put(Table::OffsetRecordNumbers
-                                                                 + AtomSize * aRecordNumber,
-                                                                 aWriteOffset);
-                               aWriteOffset += aRecordSize;
-                               aBlockSize += aRecordSize;
-                               aRecordsCount++;
-                               // XXX update all indexes being created.
-                       }
-                       else
-                       {
-                               // The current record has been deleted.  Copy all records up
-                               // to but not including the current one to the new file.
-                               if (aBlockSize > 0)
-                               {
-                                       inAtomicTempFile.write(AtomicFile::FromStart, anOffset,
-                                                                          aRecordsSection.range(Range(aBlockStart,
-                                                                                                                                  aBlockSize)),
-                                                                          aBlockSize);
-                                       anOffset += aBlockSize;
-                               }
-
-                               // Set the start of the next block to the start of the next
-                               // record, and the size of the block to 0.
-                               aBlockStart = aReadOffset;
-                               aBlockSize = 0;
-                       } // if (mDeletedSet..)
-               } // for (aRecord...)
-
-               // Copy all records that have not yet been copied to the new file.
-               if (aBlockSize > 0)
-               {
-                       inAtomicTempFile.write(AtomicFile::FromStart, anOffset,
-                                                          aRecordsSection.range(Range(aBlockStart,
-                                                                                                                  aBlockSize)),
-                                                          aBlockSize);
-                       anOffset += aBlockSize;
-               }
-       } // if (mTable)
-
-       // Now add all inserted records to the table.
-       InsertedMap::const_iterator anIt = mInsertedMap.begin();
-       InsertedMap::const_iterator anEnd = mInsertedMap.end();
-       // Iterate over all inserted objects.
-       for (; anIt != anEnd; anIt++)
-       {
-               // Write out each inserted/modified record
-               const WriteSection &aRecord = *anIt->second;
-               uint32 aRecordNumber = anIt->first;
-               // Put offset relative to start of this table in recordNumber array.
-               aTableSection.put(Table::OffsetRecordNumbers + AtomSize * aRecordNumber,
-                                                 anOffset - inSectionOffset);
-               inAtomicTempFile.write(AtomicFile::FromStart, anOffset,
-                                                  aRecord.address(), aRecord.size());
-               anOffset += aRecord.size();
-               aRecordsCount++;
-               // XXX update all indexes being created.
-       }
-
-       // Reconstruct the freelist (this is O(N) where N is the number of recordNumbers)
-       // We could implement it faster by using the old freelist and skipping the records
-       // that have been inserted.  However building the freelist for the newly used
-       // recordNumbers (not in mTable) would look like the code below anyway (starting
-       // from mTable->recordNumberCount()).
-       // The first part of this would be O(M Log(N))  (where M is the old number of
-       // free records, and N is the number of newly inserted records)
-       // The second part would be O(N) where N is the currently max RecordNumber
-       // in use - the old max RecordNumber in use.
-       uint32 aFreeListHead = 0;       // Link to previous free record
-       for (uint32 aRecordNumber = 0; aRecordNumber < aRecordNumbersCount; aRecordNumber++)
-       {
-               // Make the freelist a list of all records with 0 offset (non existing).
-               if (!aTableSection.at(Table::OffsetRecordNumbers + AtomSize * aRecordNumber))
-               {
-                       aTableSection.put(Table::OffsetRecordNumbers
-                                                               + AtomSize * aRecordNumber,
-                                                               aFreeListHead);
-                       // Make aFreeListHead point to the previous free recordNumber slot in the table.
-                       aFreeListHead = (Table::OffsetRecordNumbers + AtomSize * aRecordNumber) | 1;
-               }
-       }
-       aTableSection.put(Table::OffsetFreeListHead, aFreeListHead);
-
-       anOffset -= inSectionOffset;
-       
-       // Write out indexes, which are part of the table section
-
-       {       
-               uint32 indexOffset = anOffset;
-               anOffset = writeIndexSection(aTableSection, anOffset);
-               inAtomicTempFile.write(AtomicFile::FromStart, inSectionOffset + indexOffset,
-                       aTableSection.address() + indexOffset, anOffset - indexOffset);
-       }
-
-       // Set the section size and recordCount.
-       aTableSection.put(Table::OffsetSize, anOffset);
-       aTableSection.put(Table::OffsetRecordsCount, aRecordsCount);
-
-       // Write out aTableSection header.
-       inAtomicTempFile.write(AtomicFile::FromStart, inSectionOffset,
-                                          aTableSection.address(), aTableSection.size());
-
-    return anOffset + inSectionOffset;
-}
-
-
-
-//
-// Metadata
-//
-
-// Attribute definitions
-
-static const CSSM_DB_ATTRIBUTE_INFO RelationID =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "RelationID"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO RelationName =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "RelationName"},
-    CSSM_DB_ATTRIBUTE_FORMAT_STRING
-};
-static const CSSM_DB_ATTRIBUTE_INFO AttributeID =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "AttributeID"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO AttributeNameFormat =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "AttributeNameFormat"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO AttributeName =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "AttributeName"},
-    CSSM_DB_ATTRIBUTE_FORMAT_STRING
-};
-static const CSSM_DB_ATTRIBUTE_INFO AttributeNameID =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "AttributeNameID"},
-    CSSM_DB_ATTRIBUTE_FORMAT_BLOB
-};
-static const CSSM_DB_ATTRIBUTE_INFO AttributeFormat =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "AttributeFormat"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO IndexID =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "IndexID"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO IndexType =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "IndexType"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO IndexedDataLocation =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "IndexedDataLocation"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO ModuleID =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "ModuleID"},
-    CSSM_DB_ATTRIBUTE_FORMAT_BLOB
-};
-static const CSSM_DB_ATTRIBUTE_INFO AddinVersion =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "AddinVersion"},
-    CSSM_DB_ATTRIBUTE_FORMAT_STRING
-};
-static const CSSM_DB_ATTRIBUTE_INFO SSID =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "SSID"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-static const CSSM_DB_ATTRIBUTE_INFO SubserviceType =
-{
-    CSSM_DB_ATTRIBUTE_NAME_AS_STRING,
-    {(char*) "SubserviceType"},
-    CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-};
-
-#define ATTRIBUTE(type, name) \
-       { CSSM_DB_ATTRIBUTE_NAME_AS_STRING, { (char*) #name }, CSSM_DB_ATTRIBUTE_FORMAT_ ## type }
-       
-static const CSSM_DB_ATTRIBUTE_INFO AttrSchemaRelations[] =
-{
-       //RelationID, RelationName
-       ATTRIBUTE(UINT32, RelationID),
-       ATTRIBUTE(STRING, RelationName)
-};
-
-static const CSSM_DB_ATTRIBUTE_INFO AttrSchemaAttributes[] =
-{
-       //RelationID, AttributeID,
-    //AttributeNameFormat, AttributeName, AttributeNameID,
-    //AttributeFormat
-       ATTRIBUTE(UINT32, RelationID),
-       ATTRIBUTE(UINT32, AttributeID),
-       ATTRIBUTE(UINT32, AttributeNameFormat),
-       ATTRIBUTE(STRING, AttributeName),
-       ATTRIBUTE(BLOB, AttributeNameID),
-       ATTRIBUTE(UINT32, AttributeFormat)
-};
-
-static const CSSM_DB_ATTRIBUTE_INFO AttrSchemaIndexes[] =
-{
-       ATTRIBUTE(UINT32, RelationID),
-       ATTRIBUTE(UINT32, IndexID),
-       ATTRIBUTE(UINT32, AttributeID),
-       ATTRIBUTE(UINT32, IndexType),
-       ATTRIBUTE(UINT32, IndexedDataLocation)
-    //RelationID, IndexID, AttributeID,
-    //IndexType, IndexedDataLocation
-};
-
-static const CSSM_DB_ATTRIBUTE_INFO AttrSchemaParsingModule[] =
-{
-       ATTRIBUTE(UINT32, RelationID),
-       ATTRIBUTE(UINT32, AttributeID),
-       ATTRIBUTE(BLOB, ModuleID),
-       ATTRIBUTE(STRING, AddinVersion),
-       ATTRIBUTE(UINT32, SSID),
-       ATTRIBUTE(UINT32, SubserviceType)
-    //RelationID, AttributeID,
-    //ModuleID, AddinVersion, SSID, SubserviceType
-};
-
-#undef ATTRIBUTE
-
-//
-// DbVersion
-//
-DbVersion::DbVersion(const AppleDatabase &db, const RefPointer <AtomicBufferedFile> &inAtomicBufferedFile) :
-       mDatabase(reinterpret_cast<const uint8 *>(NULL), 0),
-       mDb(db),
-       mBufferedFile(inAtomicBufferedFile)
-{
-       off_t aLength = mBufferedFile->length();
-       off_t bytesRead = 0;
-       const uint8 *ptr = mBufferedFile->read(0, aLength, bytesRead);
-       mBufferedFile->close();
-       mDatabase = ReadSection(ptr, (size_t)bytesRead);
-       open();
-}
-
-DbVersion::~DbVersion()
-{
-       try
-       {
-               for_each_map_delete(mTableMap.begin(), mTableMap.end());
-       }
-       catch(...) {}
-}
-
-void
-DbVersion::open()
-{
-       try
-       {
-               // This is the oposite of DbModifier::commit()
-               mVersionId = mDatabase[mDatabase.size() - AtomSize];
-
-               const ReadSection aHeaderSection = mDatabase.subsection(HeaderOffset,
-                                                                                                                               HeaderSize);
-               if (aHeaderSection.at(OffsetMagic) != HeaderMagic)
-                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-       
-               // We currently only support one version.  If we support additional
-               // file format versions in the future fix this.
-               uint32 aVersion = aHeaderSection.at(OffsetVersion);
-               if (aVersion != HeaderVersion)
-                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-       
-               //const ReadSection anAuthSection =
-               //      mDatabase.subsection(HeaderOffset + aHeaderSection.at(OffsetAuthOffset));
-               // XXX Do something with anAuthSection.
-       
-               uint32 aSchemaOffset = aHeaderSection.at(OffsetSchemaOffset);
-               const ReadSection aSchemaSection =
-                       mDatabase.subsection(HeaderOffset + aSchemaOffset);
-       
-               uint32 aSchemaSize = aSchemaSection[OffsetSchemaSize];
-               // Make sure that the given range exists.
-               aSchemaSection.subsection(0, aSchemaSize);
-               uint32 aTableCount = aSchemaSection[OffsetTablesCount];
-       
-               // Assert that the size of this section is big enough.
-               if (aSchemaSize < OffsetTables + AtomSize * aTableCount)
-                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-       
-               for (uint32 aTableNumber = 0; aTableNumber < aTableCount;
-                        aTableNumber++)
-               {
-                       uint32 aTableOffset = aSchemaSection.at(OffsetTables + AtomSize
-                                                                                                       * aTableNumber);
-                       // XXX Set the size boundary on aTableSection.
-                       const ReadSection aTableSection =
-                               aSchemaSection.subsection(aTableOffset);
-                       auto_ptr<Table> aTable(new Table(aTableSection));
-                       Table::Id aTableId = aTable->getMetaRecord().dataRecordType();
-                       mTableMap.insert(TableMap::value_type(aTableId, aTable.get()));
-                       aTable.release();
-               }
-
-               // Fill in the schema for the meta tables.
-               
-               findTable(mDb.schemaRelations.DataRecordType).getMetaRecord().
-                       setRecordAttributeInfo(mDb.schemaRelations);
-               findTable(mDb.schemaIndexes.DataRecordType).getMetaRecord().
-                       setRecordAttributeInfo(mDb.schemaIndexes);
-               findTable(mDb.schemaParsingModule.DataRecordType).getMetaRecord().
-                       setRecordAttributeInfo(mDb.schemaParsingModule);
-
-               // OK, we have created all the tables in the tableMap.  Now
-               // lets read the schema and proccess it accordingly.
-               // Iterate over all schema records.
-               Table &aTable = findTable(mDb.schemaAttributes.DataRecordType);
-               aTable.getMetaRecord().setRecordAttributeInfo(mDb.schemaAttributes);
-               uint32 aRecordsCount = aTable.getRecordsCount();
-               ReadSection aRecordsSection = aTable.getRecordsSection();
-               uint32 aReadOffset = 0;
-               const MetaRecord &aMetaRecord = aTable.getMetaRecord();
-
-               CSSM_DB_ATTRIBUTE_DATA aRelationIDData =
-               {
-                       RelationID,
-                       0,
-                       NULL
-               };
-               CSSM_DB_ATTRIBUTE_DATA aAttributeIDData =
-               {
-                       AttributeID,
-                       0,
-                       NULL
-               };
-               CSSM_DB_ATTRIBUTE_DATA aAttributeNameFormatData =
-               {
-                       AttributeNameFormat,
-                       0,
-                       NULL
-               };
-               CSSM_DB_ATTRIBUTE_DATA aAttributeNameData =
-               {
-                       AttributeName,
-                       0,
-                       NULL
-               };
-               CSSM_DB_ATTRIBUTE_DATA aAttributeNameIDData =
-               {
-                       AttributeNameID,
-                       0,
-                       NULL
-               };
-               CSSM_DB_ATTRIBUTE_DATA aAttributeFormatData =
-               {
-                       AttributeFormat,
-                       0,
-                       NULL
-               };
-               CSSM_DB_ATTRIBUTE_DATA aRecordAttributes[] =
-               {
-                       aRelationIDData,
-                       aAttributeIDData,
-                       aAttributeNameFormatData,
-                       aAttributeNameData,
-                       aAttributeNameIDData,
-                       aAttributeFormatData
-               };
-               CSSM_DB_RECORD_ATTRIBUTE_DATA aRecordAttributeData =
-               {
-                       aMetaRecord.dataRecordType(),
-                       0,
-                       sizeof(aRecordAttributes) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
-                       aRecordAttributes
-               };
-               CssmDbRecordAttributeData &aRecordData = CssmDbRecordAttributeData::overlay(aRecordAttributeData);
-
-               TrackingAllocator recordAllocator(Allocator::standard());
-               for (uint32 aRecord = 0; aRecord != aRecordsCount; aRecord++)
-               {
-                       ReadSection aRecordSection = MetaRecord::readSection(aRecordsSection, aReadOffset);
-                       uint32 aRecordSize = aRecordSection.size();
-                       aReadOffset += aRecordSize;
-                       aMetaRecord.unpackRecord(aRecordSection, recordAllocator,
-                                                                               &aRecordAttributeData, NULL, 0);
-                       // Create the attribute coresponding to this entry
-                       if (aRecordData[0].size() != 1 || aRecordData[0].format() != CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
-                               CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-                       uint32 aRelationId = aRecordData[0];
-
-                       // Skip the schema relations for the meta tables themselves.
-                       // FIXME: this hard-wires the meta-table relation IDs to be
-                       // within {CSSM_DB_RECORDTYPE_SCHEMA_START...
-                       // CSSM_DB_RECORDTYPE_SCHEMA_END} (which is {0..4}). 
-                       // Bogus - the MDS schema relation IDs start at 
-                       // CSSM_DB_RELATIONID_MDS_START which is 0x40000000.
-                       // Ref. Radar 2817921.
-                       if (CSSM_DB_RECORDTYPE_SCHEMA_START <= aRelationId && aRelationId < CSSM_DB_RECORDTYPE_SCHEMA_END)
-                               continue;
-
-                       // Get the MetaRecord corresponding to the specified RelationId
-                       MetaRecord &aMetaRecord = findTable(aRelationId).getMetaRecord();
-
-                       if (aRecordData[1].size() != 1
-                               || aRecordData[1].format() != CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-                               || aRecordData[2].size() != 1
-                               || aRecordData[2].format() != CSSM_DB_ATTRIBUTE_FORMAT_UINT32
-                               || aRecordData[5].size() != 1
-                               || aRecordData[5].format() != CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
-                               CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-
-                       uint32 anAttributeId = aRecordData[1];
-                       uint32 anAttributeNameFormat = aRecordData[2];
-                       uint32 anAttributeFormat = aRecordData[5];
-                       auto_ptr<string> aName;
-                       const CssmData *aNameID = NULL;
-
-                       if (aRecordData[3].size() == 1)
-                       {
-                               if (aRecordData[3].format() != CSSM_DB_ATTRIBUTE_FORMAT_STRING)
-                                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-
-                               auto_ptr<string> aName2(new string(static_cast<string>(aRecordData[3])));
-                               aName = aName2;
-                       }
-
-                       if (aRecordData[4].size() == 1)
-                       {
-                               if (aRecordData[4].format() != CSSM_DB_ATTRIBUTE_FORMAT_BLOB)
-                                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-
-                                                                       // @@@ Invoking conversion operator to CssmData & on aRecordData[4]
-                                                                       // And taking address of result.
-                               aNameID = &static_cast<const CssmData &>(aRecordData[4]);
-                       }
-
-                       // Make sure that the attribute specified by anAttributeNameFormat is present. 
-                       switch (anAttributeNameFormat)
-                       {
-                       case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
-                               if (aRecordData[3].size() != 1)
-                                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-                               break;
-                       case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
-                               if (aRecordData[4].size() != 1)
-                                       CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-                               break;
-                       case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
-                               break;
-                       default:
-                               CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-                       }
-
-                       // Create the attribute
-                       aMetaRecord.createAttribute(aName.get(), aNameID, anAttributeId, anAttributeFormat);
-        }
-               
-               // initialize the indexes associated with each table
-               {
-                       TableMap::iterator it;
-                       for (it = mTableMap.begin(); it != mTableMap.end(); it++)
-                               it->second->readIndexSection();
-               }
-       }
-       catch(...)
-       {
-               for_each_map_delete(mTableMap.begin(), mTableMap.end());
-               mTableMap.clear();
-               throw;
-       }
-}
-
-const RecordId
-DbVersion::getRecord(Table::Id inTableId, const RecordId &inRecordId,
-                                                       CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
-                                                       CssmData *inoutData,
-                                                       Allocator &inAllocator) const
-{
-       return findTable(inTableId).getRecord(inRecordId, inoutAttributes,
-                                                                                 inoutData, inAllocator);
-}
-
-Cursor *
-DbVersion::createCursor(const CSSM_QUERY *inQuery) const
-{
-       // XXX We should add support for these special query types
-       // By Creating a Cursor that iterates over multiple tables
-       if (!inQuery || inQuery->RecordType == CSSM_DL_DB_RECORD_ANY
-               || inQuery->RecordType == CSSM_DL_DB_RECORD_ALL_KEYS)
-       {
-               return new MultiCursor(inQuery, *this);
-       }
-
-       return findTable(inQuery->RecordType).createCursor(inQuery, *this);
-}
-
-bool DbVersion::hasTable(Table::Id inTableId) const
-{
-    TableMap::const_iterator it = mTableMap.find(inTableId);
-       return it != mTableMap.end();
-}
-
-const Table &
-DbVersion::findTable(Table::Id inTableId) const
-{
-    TableMap::const_iterator it = mTableMap.find(inTableId);
-    if (it == mTableMap.end())
-               CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-       return *it->second;
-}
-
-Table &
-DbVersion::findTable(Table::Id inTableId)
-{
-    TableMap::iterator it = mTableMap.find(inTableId);
-    if (it == mTableMap.end())
-               CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-       return *it->second;
-}
-
-//
-// Cursor implemetation
-//
-Cursor::Cursor()
-{
-}
-
-Cursor::Cursor(const DbVersion &inDbVersion) : mDbVersion(&inDbVersion)
-{
-}
-
-Cursor::~Cursor()
-{
-}
-
-bool
-Cursor::next(Table::Id &outTableId,
-                        CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
-                        CssmData *outData,
-                        Allocator &inAllocator,
-                        RecordId &recordId)
-{
-       return false;
-}
-
-//
-// LinearCursor implemetation
-//
-LinearCursor::LinearCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion,
-                                                  const Table &inTable) :
-    Cursor(inDbVersion),
-    mRecordsCount(inTable.getRecordsCount()),
-    mRecord(0),
-    mRecordsSection(inTable.getRecordsSection()),
-    mReadOffset(0),
-    mMetaRecord(inTable.getMetaRecord())
-{
-       if (inQuery)
-       {
-           mConjunctive = inQuery->Conjunctive;
-           mQueryFlags = inQuery->QueryFlags;
-           // XXX Do something with inQuery->QueryLimits?
-           uint32 aPredicatesCount = inQuery->NumSelectionPredicates;
-           mPredicates.resize(aPredicatesCount);
-               try
-               {
-                       for (uint32 anIndex = 0; anIndex < aPredicatesCount; anIndex++)
-                       {
-                               CSSM_SELECTION_PREDICATE &aPredicate = inQuery->SelectionPredicate[anIndex];
-                               mPredicates[anIndex] = new SelectionPredicate(mMetaRecord, aPredicate);
-                       }
-               }
-               catch(...)
-               {
-                       for_each_delete(mPredicates.begin(), mPredicates.end());
-                       throw;
-               }
-       }
-}
-
-LinearCursor::~LinearCursor()
-{
-       for_each_delete(mPredicates.begin(), mPredicates.end());
-}
-
-bool
-LinearCursor::next(Table::Id &outTableId,
-                                  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                                  CssmData *inoutData, Allocator &inAllocator, RecordId &recordId)
-{
-       while (mRecord++ < mRecordsCount)
-       {
-               ReadSection aRecordSection = MetaRecord::readSection(mRecordsSection, mReadOffset);
-               uint32 aRecordSize = aRecordSection.size();
-               mReadOffset += aRecordSize;
-
-        PredicateVector::const_iterator anIt = mPredicates.begin();
-        PredicateVector::const_iterator anEnd = mPredicates.end();
-               bool aMatch;
-               if (anIt == anEnd)
-               {
-                       // If there are no predicates we have a match.
-                       aMatch = true;
-               }
-               else if (mConjunctive == CSSM_DB_OR)
-               {
-                       // If mConjunctive is OR, the first predicate that returns
-                       // true indicates a match. Dropthough means no match
-                       aMatch = false;
-                       for (; anIt != anEnd; anIt++)
-                       {
-                               if ((*anIt)->evaluate(aRecordSection))
-                               {
-                                       aMatch = true;
-                    break;
-                               }
-                       }
-               }
-               else if (mConjunctive == CSSM_DB_AND || mConjunctive == CSSM_DB_NONE)
-               {
-                       // If mConjunctive is AND (or NONE), the first predicate that returns
-                       // false indicates a mismatch. Dropthough means a match
-                       aMatch = true;
-                       for (; anIt != anEnd; anIt++)
-                       {
-                               if (!(*anIt)->evaluate(aRecordSection))
-                               {
-                                       aMatch = false;
-                    break;
-                               }
-                       }
-               }
-               else
-               {
-                       // XXX Should be CSSMERR_DL_INVALID_QUERY (or CSSMERR_DL_INVALID_CONJUNTIVE).
-                       CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_QUERY);
-               }
-
-        if (aMatch)
-        {
-            // Get the actual record.
-            mMetaRecord.unpackRecord(aRecordSection, inAllocator,
-                                                                        inoutAttributes, inoutData,
-                                                                        mQueryFlags);
-                       outTableId = mMetaRecord.dataRecordType();
-                       recordId = MetaRecord::unpackRecordId(aRecordSection);
-                       return true;
-        }
-    }
-
-       return false;
-}
-
-//
-// IndexCursor
-// 
-
-IndexCursor::IndexCursor(DbQueryKey *queryKey, const DbVersion &inDbVersion,
-       const Table &table, const DbConstIndex *index) :
-       Cursor(inDbVersion), mQueryKey(queryKey), mTable(table), mIndex(index)
-{
-       index->performQuery(*queryKey, mBegin, mEnd);
-}
-
-IndexCursor::~IndexCursor()
-{
-       // the query key will be deleted automatically, since it's an auto_ptr
-}
-
-bool
-IndexCursor::next(Table::Id &outTableId,
-       CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
-       CssmData *outData,
-       Allocator &inAllocator, RecordId &recordId)
-{
-       if (mBegin == mEnd)
-               return false;
-               
-       ReadSection rs = mIndex->getRecordSection(mBegin++);
-       const MetaRecord &metaRecord = mTable.getMetaRecord();
-
-       outTableId = metaRecord.dataRecordType();
-       metaRecord.unpackRecord(rs, inAllocator, outAttributes, outData, 0);
-       
-       recordId = MetaRecord::unpackRecordId(rs);
-       return true;
-}
-
-//
-// MultiCursor
-//
-MultiCursor::MultiCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion) :
-    Cursor(inDbVersion), mTableIterator(inDbVersion.begin())
-{
-       if (inQuery)
-               mQuery.reset(new CssmAutoQuery(*inQuery));
-       else
-       {
-               mQuery.reset(new CssmAutoQuery());
-               mQuery->recordType(CSSM_DL_DB_RECORD_ANY);
-       }
-}
-
-MultiCursor::~MultiCursor()
-{
-}
-
-bool
-MultiCursor::next(Table::Id &outTableId,
-                                 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                                 CssmData *inoutData, Allocator &inAllocator, RecordId &recordId)
-{
-       for (;;)
-       {
-               if (!mCursor.get())
-               {
-                       if (mTableIterator == mDbVersion->end())
-                               return false;
-
-                       const Table &aTable = *mTableIterator++;
-                       if (!aTable.matchesTableId(mQuery->recordType()))
-                               continue;
-
-                       mCursor.reset(aTable.createCursor(mQuery.get(), *mDbVersion));
-               }
-
-               if (mCursor->next(outTableId, inoutAttributes, inoutData, inAllocator, recordId))
-                       return true;
-                       
-               mCursor.reset(NULL);
-       }
-}
-
-
-//
-// DbModifier
-//
-DbModifier::DbModifier(AtomicFile &inAtomicFile, const AppleDatabase &db) :
-       Metadata(),
-       mDbVersion(),
-    mAtomicFile(inAtomicFile),
-       mDb(db)
-{
-}
-
-DbModifier::~DbModifier()
-{
-    try
-    {
-               for_each_map_delete(mModifiedTableMap.begin(), mModifiedTableMap.end());
-               // mAtomicTempFile will do automatic rollback on destruction.
-    }
-    catch(...) {}
-}
-
-const RefPointer<const DbVersion>
-DbModifier::getDbVersion(bool force)
-{
-    StLock<Mutex> _(mDbVersionLock);
-
-    /* Initialize the shared memory file change mechanism */
-    pthread_once(&gCommonInitMutex, initCommon);
-
-    /* If we don't have a mDbVersion yet, or we are force to re-read the file
-       before a write transaction, or we have received any notifications after
-       the last time we read the file, or more than kForceReReadTime seconds
-       have passed since the last time we read the file, we open the file and
-       check if it has changed. */
-    if (!mDbVersion ||
-        force ||
-               gSegment == NULL ||
-        mNotifyCount != *gSegment ||
-        CFAbsoluteTimeGetCurrent() > mDbLastRead + kForceReReadTime)
-    {
-        RefPointer <AtomicBufferedFile> atomicBufferedFile(mAtomicFile.read());
-        off_t length = atomicBufferedFile->open();
-        /* Record the number of notifications we've seen and when we last
-           opened the file.  */
-               if (gSegment != NULL)
-               {
-                       mNotifyCount = *gSegment;
-               }
-               
-        mDbLastRead = CFAbsoluteTimeGetCurrent();
-
-        /* If we already have a mDbVersion, let's check if we can reuse it. */
-        if (mDbVersion)
-        {
-            if (length < AtomSize)
-                CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
-
-            off_t bytesRead = 0;
-            const uint8 *ptr = atomicBufferedFile->read(length - AtomSize,
-                AtomSize, bytesRead);
-            ReadSection aVersionSection(ptr, (size_t)bytesRead);
-            uint32 aVersionId = aVersionSection[0];
-
-            /* If the version stamp hasn't changed the old mDbVersion is still
-               current. */
-            if (aVersionId == mDbVersion->getVersionId())
-                return mDbVersion;
-        }
-
-       mDbVersion = new DbVersion(mDb, atomicBufferedFile);
-    }
-
-    return mDbVersion;
-}
-
-void
-DbModifier::createDatabase(const CSSM_DBINFO &inDbInfo,
-                                                  const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry,
-                                                  mode_t mode)
-{
-       // XXX This needs better locking.  There is a possible race condition between
-       // two concurrent creators.  Or a writer/creator or a close/create etc.
-       if (mAtomicTempFile || !mModifiedTableMap.empty())
-               CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
-
-    mAtomicTempFile = mAtomicFile.create(mode);
-       // Set mVersionId to one since this is the first version of the database.
-       mVersionId = 1;
-
-       // we need to create the meta tables first, because inserting tables
-       // (including the meta tables themselves) relies on them being there
-    createTable(new MetaRecord(mDb.schemaRelations));
-    createTable(new MetaRecord(mDb.schemaAttributes));
-    createTable(new MetaRecord(mDb.schemaIndexes));
-    createTable(new MetaRecord(mDb.schemaParsingModule));
-       
-       // now add the meta-tables' schema to the meta tables themselves
-       insertTableSchema(mDb.schemaRelations);
-       insertTableSchema(mDb.schemaAttributes);
-       insertTableSchema(mDb.schemaIndexes);
-       insertTableSchema(mDb.schemaParsingModule);
-
-    if (inInitialAclEntry != NULL)
-    {
-        //createACL(*inInitialAclEntry);
-    }
-
-    if (inDbInfo.NumberOfRecordTypes == 0)
-        return;
-    if (inDbInfo.RecordAttributeNames == NULL)
-        CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-    if (inDbInfo.RecordIndexes == NULL)
-        CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_INDEX);
-    if (inDbInfo.DefaultParsingModules == NULL)
-        CssmError::throwMe(CSSMERR_DL_INVALID_PARSING_MODULE);
-
-    for (uint32 anIndex = 0; anIndex < inDbInfo.NumberOfRecordTypes; anIndex++)
-    {
-        insertTable(CssmDbRecordAttributeInfo::overlay(inDbInfo.RecordAttributeNames[anIndex]),
-                                       &inDbInfo.RecordIndexes[anIndex],
-                                       &inDbInfo.DefaultParsingModules[anIndex]);
-    }
-}
-
-void DbModifier::openDatabase()
-{
-       // No need to do anything on open if we are already writing the database.
-       if (!mAtomicTempFile)
-               getDbVersion(false);
-}
-
-void DbModifier::closeDatabase()
-{
-       commit(); // XXX Requires write lock.
-       StLock<Mutex> _(mDbVersionLock);
-       mDbVersion = NULL;
-}
-
-void DbModifier::deleteDatabase()
-{
-       bool isDirty = mAtomicTempFile;
-       rollback(); // XXX Requires write lock.
-       StLock<Mutex> _(mDbVersionLock);
-
-       // Clean up mModifiedTableMap in case this object gets reused again for
-       // a new create.
-       for_each_map_delete(mModifiedTableMap.begin(), mModifiedTableMap.end());
-       mModifiedTableMap.clear();
-
-       // If the database was dirty and we had no mDbVersion yet then rollback()
-       // would have deleted the db.
-       if (!isDirty || mDbVersion)
-       {
-               mDbVersion = NULL;
-               mAtomicFile.performDelete();
-       }
-}
-
-void
-DbModifier::modifyDatabase()
-{
-       if (mAtomicTempFile)
-               return;
-
-       try
-       {
-               mAtomicTempFile = mAtomicFile.write();
-               // Now we are holding the write lock make sure we get the latest greatest version of the db.
-               // Also set mVersionId to one more that that of the old database.
-               mVersionId = getDbVersion(true)->getVersionId() + 1;
-
-               // Never make a database with mVersionId 0 since it makes bad things happen to Jaguar and older systems
-               if (mVersionId == 0)
-                       mVersionId = 1;
-
-               // Remove all old modified tables
-               for_each_map_delete(mModifiedTableMap.begin(), mModifiedTableMap.end());
-               mModifiedTableMap.clear();
-
-               // Setup the new tables
-               DbVersion::TableMap::const_iterator anIt =
-                       mDbVersion->mTableMap.begin();
-               DbVersion::TableMap::const_iterator anEnd =
-                       mDbVersion->mTableMap.end();
-               for (; anIt != anEnd; ++anIt)
-               {
-                       auto_ptr<ModifiedTable> aTable(new ModifiedTable(anIt->second));
-                       mModifiedTableMap.insert(ModifiedTableMap::value_type(anIt->first,
-                                                                                                                                 aTable.get()));
-                       aTable.release();
-               }
-       }
-       catch(...)
-       {
-               for_each_map_delete(mModifiedTableMap.begin(), mModifiedTableMap.end());
-               mModifiedTableMap.clear();
-               rollback();
-               throw;
-       }
-}
-
-void
-DbModifier::deleteRecord(Table::Id inTableId, const RecordId &inRecordId)
-{
-       modifyDatabase();
-       findTable(inTableId).deleteRecord(inRecordId);
-}
-
-const RecordId
-DbModifier::insertRecord(Table::Id inTableId,
-                                                const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
-                                                const CssmData *inData)
-{
-       modifyDatabase();
-       return findTable(inTableId).insertRecord(mVersionId, inAttributes, inData);
-}
-
-const RecordId
-DbModifier::updateRecord(Table::Id inTableId, const RecordId &inRecordId,
-                                                const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
-                                                const CssmData *inData,
-                                                CSSM_DB_MODIFY_MODE inModifyMode)
-{
-       modifyDatabase();
-       return findTable(inTableId).updateRecord(inRecordId, inAttributes, inData, inModifyMode);
-}
-
-// Create a table associated with a given metarecord, and add the table
-// to the database.
-
-ModifiedTable *
-DbModifier::createTable(MetaRecord *inMetaRecord)
-{
-       auto_ptr<MetaRecord> aMetaRecord(inMetaRecord);
-       auto_ptr<ModifiedTable> aModifiedTable(new ModifiedTable(inMetaRecord));
-       // Now that aModifiedTable is fully constructed it owns inMetaRecord
-       aMetaRecord.release();
-
-       if (!mModifiedTableMap.insert
-               (ModifiedTableMap::value_type(inMetaRecord->dataRecordType(),
-                                                                         aModifiedTable.get())).second)
-       {
-               // XXX Should be CSSMERR_DL_DUPLICATE_RECORDTYPE.  Since that
-               // doesn't exist we report that the metatable's unique index would
-               // no longer be valid
-        CssmError::throwMe(CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA);
-       }
-
-       return aModifiedTable.release();
-}
-
-void
-DbModifier::deleteTable(Table::Id inTableId)
-{
-       modifyDatabase();
-    // Can't delete schema tables.
-    if (CSSM_DB_RECORDTYPE_SCHEMA_START <= inTableId
-               && inTableId < CSSM_DB_RECORDTYPE_SCHEMA_END)
-        CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-
-       // Find the ModifiedTable and delete it
-    ModifiedTableMap::iterator it = mModifiedTableMap.find(inTableId);
-    if (it == mModifiedTableMap.end())
-        CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-
-    delete it->second;
-    mModifiedTableMap.erase(it);
-}
-
-uint32
-DbModifier::writeAuthSection(uint32 inSectionOffset)
-{
-       WriteSection anAuthSection;
-
-    // XXX Put real data into the authsection.
-       uint32 anOffset = anAuthSection.put(0, 0);
-       anAuthSection.size(anOffset);
-
-       mAtomicTempFile->write(AtomicFile::FromStart, inSectionOffset,
-                                       anAuthSection.address(), anAuthSection.size());
-    return inSectionOffset + anOffset;
-}
-
-uint32
-DbModifier::writeSchemaSection(uint32 inSectionOffset)
-{
-       uint32 aTableCount = (uint32) mModifiedTableMap.size();
-       WriteSection aTableSection(Allocator::standard(),
-                                                          OffsetTables + AtomSize * aTableCount);
-       // Set aTableSection to the correct size.
-       aTableSection.size(OffsetTables + AtomSize * aTableCount);
-       aTableSection.put(OffsetTablesCount, aTableCount);
-
-       uint32 anOffset = inSectionOffset + OffsetTables + AtomSize * aTableCount;
-       ModifiedTableMap::const_iterator anIt = mModifiedTableMap.begin();
-       ModifiedTableMap::const_iterator anEnd = mModifiedTableMap.end();
-       for (uint32 aTableNumber = 0; anIt != anEnd; anIt++, aTableNumber++)
-       {
-               // Put the offset to the current table relative to the start of
-               // this section into the tables array
-               aTableSection.put(OffsetTables + AtomSize * aTableNumber,
-                                                 anOffset - inSectionOffset);
-               anOffset = anIt->second->writeTable(*mAtomicTempFile, anOffset);
-       }
-
-       aTableSection.put(OffsetSchemaSize, anOffset - inSectionOffset);
-       mAtomicTempFile->write(AtomicFile::FromStart, inSectionOffset,
-                                       aTableSection.address(), aTableSection.size());
-
-       return anOffset;
-}
-
-void
-DbModifier::commit()
-{
-    if (!mAtomicTempFile)
-        return;
-    try
-    {
-               WriteSection aHeaderSection(Allocator::standard(), size_t(HeaderSize));
-               // Set aHeaderSection to the correct size.
-               aHeaderSection.size(HeaderSize);
-
-        // Start writing sections after the header
-        uint32 anOffset = HeaderOffset + HeaderSize;
-
-        // Write auth section
-               aHeaderSection.put(OffsetAuthOffset, anOffset);
-        anOffset = writeAuthSection(anOffset);
-        // Write schema section
-               aHeaderSection.put(OffsetSchemaOffset, anOffset);
-        anOffset = writeSchemaSection(anOffset);
-
-               // Write out the file header.
-               aHeaderSection.put(OffsetMagic, HeaderMagic);
-               aHeaderSection.put(OffsetVersion, HeaderVersion);
-        mAtomicTempFile->write(AtomicFile::FromStart, HeaderOffset,
-                                                          aHeaderSection.address(), aHeaderSection.size());
-
-               // Write out the versionId.
-               WriteSection aVersionSection(Allocator::standard(), size_t(AtomSize));
-               anOffset = aVersionSection.put(0, mVersionId);
-               aVersionSection.size(anOffset);
-
-        mAtomicTempFile->write(AtomicFile::FromEnd, 0,
-                                                          aVersionSection.address(), aVersionSection.size());
-
-               mAtomicTempFile->commit();
-               mAtomicTempFile = NULL;
-          /* Initialize the shared memory file change mechanism */
-          pthread_once(&gCommonInitMutex, initCommon);
-       
-          if (gSegment != NULL)
-               {
-                       /*
-                               PLEASE NOTE:
-                               
-                               The following operation is endian safe because we are not looking 
-                               for monotonic increase. I have tested every possible value of 
-                               *gSegment, and there is no value for which alternating
-                               big and little endian increments will produce the original value.
-                       */
-       
-                       OSAtomicIncrement32Barrier (gSegment);
-               }
-    }
-    catch(...)
-    {
-               rollback();
-               throw;
-    }
-}
-
-void
-DbModifier::rollback() throw()
-{
-       // This will destroy the AtomicTempFile if we have one causing it to rollback.
-       mAtomicTempFile = NULL;
-}
-
-const RecordId
-DbModifier::getRecord(Table::Id inTableId, const RecordId &inRecordId,
-                                         CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
-                                         CssmData *inoutData, Allocator &inAllocator)
-{
-    if (mAtomicTempFile)
-       {
-               // We are in the midst of changing the database.
-               return findTable(inTableId).getRecord(inRecordId, inoutAttributes,
-                       inoutData, inAllocator);
-       }
-       else
-       {
-               return getDbVersion(false)->getRecord(inTableId, inRecordId,
-                       inoutAttributes, inoutData, inAllocator);
-       }
-}
-
-Cursor *
-DbModifier::createCursor(const CSSM_QUERY *inQuery)
-{
-       if (mAtomicTempFile)
-       {
-               // We are modifying this database.
-               
-               // If we have a mDbVersion already then it's a snapshot of the database
-               // right before the modifications started.  So return a cursor using
-               // that.
-               if (mDbVersion)
-                       return mDbVersion->createCursor(inQuery);
-
-               // This is a newly created but never commited database.  Return a
-               // Cursor that will not return any matches.
-               return new Cursor();
-       }
-
-       // Get the latest and greatest version of the db and create the cursor
-       // on that.
-       return getDbVersion(false)->createCursor(inQuery);
-}
-
-// Insert schema records for a new table into the metatables of the database. This gets
-// called while a database is being created.
-
-void
-DbModifier::insertTableSchema(const CssmDbRecordAttributeInfo &inInfo,
-       const CSSM_DB_RECORD_INDEX_INFO *inIndexInfo /* = NULL */)
-{
-       ModifiedTable &aTable = findTable(inInfo.DataRecordType);
-       const MetaRecord &aMetaRecord = aTable.getMetaRecord();
-
-       CssmAutoDbRecordAttributeData aRecordBuilder(5); // Set capacity to 5 so we don't need to grow
-
-       // Create the entry for the SchemaRelations table.
-       aRecordBuilder.add(RelationID, inInfo.recordType());
-       aRecordBuilder.add(RelationName, mDb.recordName(inInfo.recordType()));
-
-       // Insert the record into the SchemaRelations ModifiedTable
-    findTable(mDb.schemaRelations.DataRecordType).insertRecord(mVersionId,
-               &aRecordBuilder, NULL);
-       
-       ModifiedTable &anAttributeTable = findTable(mDb.schemaAttributes.DataRecordType);
-    for (uint32 anIndex = 0; anIndex < inInfo.size(); anIndex++)
-    {
-               // Create an entry for the SchemaAttributes table.
-               aRecordBuilder.clear();
-               aRecordBuilder.add(RelationID, inInfo.recordType());
-               aRecordBuilder.add(AttributeNameFormat, inInfo.at(anIndex).nameFormat());
-
-               uint32 attributeId = aMetaRecord.metaAttribute(inInfo.at(anIndex)).attributeId();
-               
-        switch (inInfo.at(anIndex).nameFormat())
-        {
-            case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
-                               aRecordBuilder.add(AttributeName, inInfo.at(anIndex).Label.AttributeName);
-                               break;
-            case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
-                               aRecordBuilder.add(AttributeNameID, inInfo.at(anIndex).Label.AttributeOID);
-                               break;
-            case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
-                break;
-            default:
-                CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
-               }
-
-               aRecordBuilder.add(AttributeID, attributeId);
-               aRecordBuilder.add(AttributeFormat, inInfo.at(anIndex).format());
-
-               // Insert the record into the SchemaAttributes ModifiedTable
-               anAttributeTable.insertRecord(mVersionId, &aRecordBuilder, NULL);
-    }
-
-       if (inIndexInfo != NULL) {
-       
-               if (inIndexInfo->DataRecordType != inInfo.DataRecordType &&
-                       inIndexInfo->NumberOfIndexes > 0)
-                       CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-       
-               ModifiedTable &indexMetaTable = findTable(mDb.schemaIndexes.DataRecordType);
-               uint32 aNumberOfIndexes = inIndexInfo->NumberOfIndexes;
-               
-               for (uint32 anIndex = 0; anIndex < aNumberOfIndexes; anIndex++)
-               {
-                       const CssmDbIndexInfo &thisIndex = CssmDbIndexInfo::overlay(inIndexInfo->IndexInfo[anIndex]);
-                       
-                       // make sure the index is supported
-                       if (thisIndex.dataLocation() != CSSM_DB_INDEX_ON_ATTRIBUTE)
-                               CssmError::throwMe(CSSMERR_DL_INVALID_INDEX_INFO);
-                       
-                       // assign an index ID: the unique index is ID 0, all others are ID > 0
-                       uint32 indexId;
-                       if (thisIndex.IndexType == CSSM_DB_INDEX_UNIQUE)
-                               indexId = 0;
-                       else
-                               indexId = anIndex + 1;
-                               
-                       // figure out the attribute ID
-                       uint32 attributeId =
-                               aMetaRecord.metaAttribute(thisIndex.Info).attributeId();
-                       
-                       // Create an entry for the SchemaIndexes table.
-                       aRecordBuilder.clear();
-                       aRecordBuilder.add(RelationID, inInfo.DataRecordType);
-                       aRecordBuilder.add(IndexID, indexId);
-                       aRecordBuilder.add(AttributeID, attributeId);
-                       aRecordBuilder.add(IndexType, thisIndex.IndexType);
-                       aRecordBuilder.add(IndexedDataLocation, thisIndex.IndexedDataLocation);
-
-                       // Insert the record into the SchemaIndexes ModifiedTable
-                       indexMetaTable.insertRecord(mVersionId, &aRecordBuilder, NULL);
-                       
-                       // update the table's index objects
-                       DbMutableIndex &index = aTable.findIndex(indexId, aMetaRecord, indexId == 0);
-                       index.appendAttribute(attributeId);
-               }
-       }
-}
-
-// Insert a new table. The attribute info is required; the index and parsing module
-// descriptions are optional. This version gets called during the creation of a
-// database.
-
-void
-DbModifier::insertTable(const CssmDbRecordAttributeInfo &inInfo,
-                                               const CSSM_DB_RECORD_INDEX_INFO *inIndexInfo /* = NULL */,
-                                               const CSSM_DB_PARSING_MODULE_INFO *inParsingModule /* = NULL */)
-{
-       modifyDatabase();
-       createTable(new MetaRecord(inInfo));
-       insertTableSchema(inInfo, inIndexInfo);
-}
-
-// Insert a new table. This is the version that gets called when a table is added
-// after a database has been created.
-
-void
-DbModifier::insertTable(Table::Id inTableId, const string &inTableName,
-                                               uint32 inNumberOfAttributes,
-                                               const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
-                                               uint32 inNumberOfIndexes,
-                                               const CSSM_DB_SCHEMA_INDEX_INFO *inIndexInfo)
-{
-       modifyDatabase();
-       ModifiedTable *aTable = createTable(new MetaRecord(inTableId, inNumberOfAttributes, inAttributeInfo));
-
-       CssmAutoDbRecordAttributeData aRecordBuilder(6); // Set capacity to 6 so we don't need to grow
-
-       // Create the entry for the SchemaRelations table.
-       aRecordBuilder.add(RelationID, inTableId);
-       aRecordBuilder.add(RelationName, inTableName);
-
-       // Insert the record into the SchemaRelations ModifiedTable
-    findTable(mDb.schemaRelations.DataRecordType).insertRecord(mVersionId,
-               &aRecordBuilder, NULL);
-
-       ModifiedTable &anAttributeTable = findTable(mDb.schemaAttributes.DataRecordType);
-    for (uint32 anIndex = 0; anIndex < inNumberOfAttributes; anIndex++)
-    {
-               // Create an entry for the SchemaAttributes table.
-               aRecordBuilder.clear();
-               aRecordBuilder.add(RelationID, inTableId);
-               // XXX What should this be?  We set it to CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER for now
-               // since the AttributeID is always valid.
-               aRecordBuilder.add(AttributeNameFormat, uint32(CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER));
-               aRecordBuilder.add(AttributeID, inAttributeInfo[anIndex].AttributeId);
-               if (inAttributeInfo[anIndex].AttributeName)
-                       aRecordBuilder.add(AttributeName, inAttributeInfo[anIndex].AttributeName);
-               if (inAttributeInfo[anIndex].AttributeNameID.Length > 0)
-                       aRecordBuilder.add(AttributeNameID, inAttributeInfo[anIndex].AttributeNameID);
-               aRecordBuilder.add(AttributeFormat, inAttributeInfo[anIndex].DataType);
-
-               // Insert the record into the SchemaAttributes ModifiedTable
-               anAttributeTable.insertRecord(mVersionId, &aRecordBuilder, NULL);
-    }
-
-       ModifiedTable &anIndexTable = findTable(mDb.schemaIndexes.DataRecordType);
-    for (uint32 anIndex = 0; anIndex < inNumberOfIndexes; anIndex++)
-    {
-               // Create an entry for the SchemaIndexes table.
-               aRecordBuilder.clear();
-               aRecordBuilder.add(RelationID, inTableId);
-               aRecordBuilder.add(IndexID, inIndexInfo[anIndex].IndexId);
-               aRecordBuilder.add(AttributeID, inIndexInfo[anIndex].AttributeId);
-               aRecordBuilder.add(IndexType, inIndexInfo[anIndex].IndexType);
-               aRecordBuilder.add(IndexedDataLocation, inIndexInfo[anIndex].IndexedDataLocation);
-
-               // Insert the record into the SchemaIndexes ModifiedTable
-               anIndexTable.insertRecord(mVersionId, &aRecordBuilder, NULL);
-               
-               // update the table's index objects
-               DbMutableIndex &index = aTable->findIndex(inIndexInfo[anIndex].IndexId,
-                       aTable->getMetaRecord(), inIndexInfo[anIndex].IndexType == CSSM_DB_INDEX_UNIQUE);
-               index.appendAttribute(inIndexInfo[anIndex].AttributeId);
-    }
-}
-
-
-
-bool DbModifier::hasTable(Table::Id inTableId)
-{
-       return getDbVersion(false)->hasTable(inTableId);
-}
-
-
-
-ModifiedTable &
-DbModifier::findTable(Table::Id inTableId)
-{
-    ModifiedTableMap::iterator it = mModifiedTableMap.find(inTableId);
-    if (it == mModifiedTableMap.end())
-               CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-       return *it->second;
-}
-
-
-//
-// AppleDatabaseManager implementation
-//
-
-AppleDatabaseManager::AppleDatabaseManager(const AppleDatabaseTableName *tableNames)
-       :       DatabaseManager(),
-               mTableNames(tableNames)
-{
-       // make sure that a proper set of table ids and names has been provided
-       
-       if (!mTableNames)
-               CssmError::throwMe(CSSMERR_DL_INTERNAL_ERROR);
-       else {
-               uint32 i;
-               for (i = 0; mTableNames[i].mTableName; i++) {}
-               if (i < AppleDatabaseTableName::kNumRequiredTableNames)
-                       CssmError::throwMe(CSSMERR_DL_INTERNAL_ERROR);
-       }
-}
-
-Database *
-AppleDatabaseManager::make(const DbName &inDbName)
-{
-    return new AppleDatabase(inDbName, mTableNames);
-}
-
-
-//
-// AppleDbContext implementation
-//
-
-/* This is the version 0 CSSM_APPLEDL_OPEN_PARAMETERS struct used up to 10.2.x. */
-extern "C" {
-
-typedef struct cssm_appledl_open_parameters_v0
-{
-               uint32 length;  /* Should be sizeof(CSSM_APPLEDL_OPEN_PARAMETERS_V0). */
-               uint32 version; /* Should be 0. */
-               CSSM_BOOL autoCommit;
-} CSSM_APPLEDL_OPEN_PARAMETERS_V0;
-
-};
-
-AppleDbContext::AppleDbContext(Database &inDatabase,
-                                                          DatabaseSession &inDatabaseSession,
-                                                          CSSM_DB_ACCESS_TYPE inAccessRequest,
-                                                          const AccessCredentials *inAccessCred,
-                                                          const void *inOpenParameters) :
-       DbContext(inDatabase, inDatabaseSession, inAccessRequest, inAccessCred),
-       mAutoCommit(true),
-       mMode(0666)
-{
-       const CSSM_APPLEDL_OPEN_PARAMETERS *anOpenParameters =
-               reinterpret_cast<const CSSM_APPLEDL_OPEN_PARAMETERS *>(inOpenParameters);
-
-       if (anOpenParameters)
-       {
-               switch (anOpenParameters->version)
-               {
-               case 1:
-                       if (anOpenParameters->length < sizeof(CSSM_APPLEDL_OPEN_PARAMETERS))
-                               CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
-
-                       if (anOpenParameters->mask & kCSSM_APPLEDL_MASK_MODE)
-                               mMode = anOpenParameters->mode;
-                       /*DROPTHROUGH*/
-               case 0:
-                       if (anOpenParameters->length < sizeof(CSSM_APPLEDL_OPEN_PARAMETERS_V0))
-                               CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
-
-                       mAutoCommit = anOpenParameters->autoCommit == CSSM_FALSE ? false : true;
-                       break;
-
-               default:
-                       CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
-               }
-       }
-}
-
-AppleDbContext::~AppleDbContext()
-{
-}
-
-//
-// AppleDatabase implementation
-//
-AppleDatabase::AppleDatabase(const DbName &inDbName, const AppleDatabaseTableName *tableNames) :
-    Database(inDbName),
-       schemaRelations(tableNames[AppleDatabaseTableName::kSchemaInfo].mTableId,
-               sizeof(AttrSchemaRelations) / sizeof(CSSM_DB_ATTRIBUTE_INFO),
-               const_cast<CSSM_DB_ATTRIBUTE_INFO_PTR>(AttrSchemaRelations)),
-       schemaAttributes(tableNames[AppleDatabaseTableName::kSchemaAttributes].mTableId,
-               sizeof(AttrSchemaAttributes) / sizeof(CSSM_DB_ATTRIBUTE_INFO),
-               const_cast<CSSM_DB_ATTRIBUTE_INFO_PTR>(AttrSchemaAttributes)),
-       schemaIndexes(tableNames[AppleDatabaseTableName::kSchemaIndexes].mTableId,
-               sizeof(AttrSchemaIndexes) / sizeof(CSSM_DB_ATTRIBUTE_INFO),
-               const_cast<CSSM_DB_ATTRIBUTE_INFO_PTR>(AttrSchemaIndexes)),
-       schemaParsingModule(tableNames[AppleDatabaseTableName::kSchemaParsingModule].mTableId,
-               sizeof(AttrSchemaParsingModule) / sizeof(CSSM_DB_ATTRIBUTE_INFO),
-               const_cast<CSSM_DB_ATTRIBUTE_INFO_PTR>(AttrSchemaParsingModule)),
-    mAtomicFile(mDbName.dbName()),
-       mDbModifier(mAtomicFile, *this),
-       mTableNames(tableNames)
-{
-       /* temp check for X509Anchors access - this should removed before Leopard GM */
-       if(!strcmp(inDbName.dbName(), "/System/Library/Keychains/X509Anchors")) {
-               Syslog::alert("Warning: accessing obsolete X509Anchors.");
-       }
-}
-
-AppleDatabase::~AppleDatabase()
-{
-}
-
-// Return the name of a record type. This uses a table that maps record types
-// to record names. The table is provided when the database is created.
-
-const char *AppleDatabase::recordName(CSSM_DB_RECORDTYPE inRecordType) const
-{
-       if (inRecordType == CSSM_DL_DB_RECORD_ANY || inRecordType == CSSM_DL_DB_RECORD_ALL_KEYS)
-               CssmError::throwMe(CSSMERR_DL_INVALID_RECORDTYPE);
-               
-       for (uint32 i = 0; mTableNames[i].mTableName; i++)
-               if (mTableNames[i].mTableId == inRecordType)
-                       return mTableNames[i].mTableName;
-                       
-       return "";
-}
-
-DbContext *
-AppleDatabase::makeDbContext(DatabaseSession &inDatabaseSession,
-                             CSSM_DB_ACCESS_TYPE inAccessRequest,
-                             const AccessCredentials *inAccessCred,
-                             const void *inOpenParameters)
-{
-    return new AppleDbContext(*this, inDatabaseSession, inAccessRequest,
-                                                         inAccessCred, inOpenParameters);
-}
-
-void
-AppleDatabase::dbCreate(DbContext &inDbContext, const CSSM_DBINFO &inDBInfo,
-                        const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry)
-{
-       AppleDbContext &context = safer_cast<AppleDbContext &>(inDbContext);
-    try
-    {
-               StLock<Mutex> _(mWriteLock);
-        mDbModifier.createDatabase(inDBInfo, inInitialAclEntry, context.mode());
-    }
-    catch(...)
-    {
-        mDbModifier.rollback();
-        throw;
-    }
-       if (context.autoCommit())
-               mDbModifier.commit();
-}
-
-void
-AppleDatabase::dbOpen(DbContext &inDbContext)
-{
-       mDbModifier.openDatabase();
-}
-
-void
-AppleDatabase::dbClose()
-{
-       StLock<Mutex> _(mWriteLock);
-       mDbModifier.closeDatabase();
-}
-
-void
-AppleDatabase::dbDelete(DatabaseSession &inDatabaseSession,
-                        const AccessCredentials *inAccessCred)
-{
-       StLock<Mutex> _(mWriteLock);
-    // XXX Check callers credentials.
-       mDbModifier.deleteDatabase();
-}
-
-void
-AppleDatabase::createRelation(DbContext &inDbContext,
-                              CSSM_DB_RECORDTYPE inRelationID,
-                              const char *inRelationName,
-                              uint32 inNumberOfAttributes,
-                              const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
-                              uint32 inNumberOfIndexes,
-                              const CSSM_DB_SCHEMA_INDEX_INFO &inIndexInfo)
-{
-       try
-       {
-               StLock<Mutex> _(mWriteLock);
-               // XXX Fix the refs here.
-               mDbModifier.insertTable(inRelationID, inRelationName,
-                                                               inNumberOfAttributes, inAttributeInfo,
-                                                               inNumberOfIndexes, &inIndexInfo);
-       }
-       catch(...)
-       {
-               if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-                       mDbModifier.rollback();
-               throw;
-       }
-       if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-               mDbModifier.commit();
-}
-
-void
-AppleDatabase::destroyRelation(DbContext &inDbContext,
-                               CSSM_DB_RECORDTYPE inRelationID)
-{
-       try
-       {
-               StLock<Mutex> _(mWriteLock);
-               mDbModifier.deleteTable(inRelationID);
-       }
-       catch(...)
-       {
-               if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-                       mDbModifier.rollback();
-               throw;
-       }
-       if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-               mDbModifier.commit();
-}
-
-void
-AppleDatabase::authenticate(DbContext &inDbContext,
-                            CSSM_DB_ACCESS_TYPE inAccessRequest,
-                            const AccessCredentials &inAccessCred)
-{
-    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-}
-
-void
-AppleDatabase::getDbAcl(DbContext &inDbContext,
-                        const CSSM_STRING *inSelectionTag,
-                        uint32 &outNumberOfAclInfos,
-                        CSSM_ACL_ENTRY_INFO_PTR &outAclInfos)
-{
-    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-}
-
-void
-AppleDatabase::changeDbAcl(DbContext &inDbContext,
-                           const AccessCredentials &inAccessCred,
-                           const CSSM_ACL_EDIT &inAclEdit)
-{
-    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-}
-
-void
-AppleDatabase::getDbOwner(DbContext &inDbContext,
-                                                 CSSM_ACL_OWNER_PROTOTYPE &outOwner)
-{
-    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-}
-
-void
-AppleDatabase::changeDbOwner(DbContext &inDbContext,
-                             const AccessCredentials &inAccessCred,
-                             const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner)
-{
-    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-}
-
-char *
-AppleDatabase::getDbNameFromHandle(const DbContext &inDbContext) const
-{
-    CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-}
-
-CSSM_DB_UNIQUE_RECORD_PTR
-AppleDatabase::dataInsert(DbContext &inDbContext,
-                          CSSM_DB_RECORDTYPE inRecordType,
-                          const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
-                          const CssmData *inData)
-{
-       CSSM_DB_UNIQUE_RECORD_PTR anUniqueRecordPtr = NULL;
-       try
-       {
-               StLock<Mutex> _(mWriteLock);
-               const RecordId aRecordId =
-                       mDbModifier.insertRecord(inRecordType, inAttributes, inData);
-
-               anUniqueRecordPtr = createUniqueRecord(inDbContext, inRecordType,
-                                                                                          aRecordId);
-               if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-                       mDbModifier.commit();
-       }
-       catch(...)
-       {
-               if (anUniqueRecordPtr != NULL)
-                       freeUniqueRecord(inDbContext, *anUniqueRecordPtr);
-
-               if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-                       mDbModifier.rollback();
-               throw;
-       }
-
-       return anUniqueRecordPtr;
-}
-
-void
-AppleDatabase::dataDelete(DbContext &inDbContext,
-                          const CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
-{
-    try
-    {
-               // syslog if it's the .Mac password
-               CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
-               // we have to do this in two phases -- the first to get the record type, and the second to actually read the attributes.  Otherwise, we might get
-               // an exception.
-               memset(&attrData, 0, sizeof(attrData));
-               dataGetFromUniqueRecordId(inDbContext, inUniqueRecord, &attrData, NULL);
-               
-               if (attrData.DataRecordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD)
-               {
-                       CSSM_DB_ATTRIBUTE_DATA attributes;
-                       
-                       // setup some attributes and see if we are indeed the .Mac password
-                       attributes.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
-                       attributes.Info.Label.AttributeID = 'svce';
-                       attributes.Info.AttributeFormat = 0;
-                       attributes.NumberOfValues = 1;
-                       attributes.Value = NULL;
-
-                       attrData.NumberOfAttributes = 1;
-                       attrData.AttributeData = &attributes;           
-                       
-                       dataGetFromUniqueRecordId(inDbContext, inUniqueRecord, &attrData, NULL);
-                       
-                       // now check the results
-                       std::string dataString((const char*) attrData.AttributeData[0].Value[0].Data, attrData.AttributeData[0].Value[0].Length);
-                       if (dataString == "iTools")
-                       {
-                               syslog(LOG_WARNING, "Warning: Removed .Me password");
-                       }
-                       
-                       free(attrData.AttributeData[0].Value[0].Data);
-                       free(attrData.AttributeData[0].Value);
-               }
-               
-               StLock<Mutex> _(mWriteLock);
-               Table::Id aTableId;
-               const RecordId aRecordId(parseUniqueRecord(inUniqueRecord, aTableId));
-               mDbModifier.deleteRecord(aTableId, aRecordId);
-       }
-    catch(...)
-    {
-               if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-                       mDbModifier.rollback();
-        throw;
-    }
-
-       if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-               mDbModifier.commit();
-}
-
-void
-AppleDatabase::dataModify(DbContext &inDbContext,
-                          CSSM_DB_RECORDTYPE inRecordType,
-                          CSSM_DB_UNIQUE_RECORD &inoutUniqueRecord,
-                          const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributesToBeModified,
-                          const CssmData *inDataToBeModified,
-                          CSSM_DB_MODIFY_MODE inModifyMode)
-{
-    try
-    {
-               StLock<Mutex> _(mWriteLock);
-               Table::Id aTableId;
-               const RecordId oldRecordId = parseUniqueRecord(inoutUniqueRecord,
-                       aTableId);
-#if 1
-               if (inRecordType != aTableId)
-#else
-               if (inRecordType != aTableId &&
-                       inRecordType != CSSM_DL_DB_RECORD_ANY &&
-                       !(inRecordType == CSSM_DL_DB_RECORD_ALL_KEYS &&
-                         (aTableId == CSSM_DL_DB_RECORD_PUBLIC_KEY ||
-                          aTableId == CSSM_DL_DB_RECORD_PRIVATE_KEY ||
-                          aTableId == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)))
-#endif
-               {
-                       CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
-               }
-
-               const RecordId newRecordId =
-                       mDbModifier.updateRecord(aTableId,
-                                                                        oldRecordId,
-                                                                        inAttributesToBeModified,
-                                                                        inDataToBeModified,
-                                                                        inModifyMode);
-               updateUniqueRecord(inDbContext, aTableId, newRecordId,
-                       inoutUniqueRecord);
-       }
-    catch(...)
-    {
-               if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-                       mDbModifier.rollback();
-        throw;
-    }
-
-       if (safer_cast<AppleDbContext &>(inDbContext).autoCommit())
-               mDbModifier.commit();
-}
-
-CSSM_HANDLE
-AppleDatabase::dataGetFirst(DbContext &inDbContext,
-                            const CssmQuery *inQuery,
-                            CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                            CssmData *inoutData,
-                            CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
-{
-       // XXX: register Cursor with DbContext and have DbContext call
-       // dataAbortQuery for all outstanding Query objects on close.
-       auto_ptr<Cursor> aCursor(mDbModifier.createCursor(inQuery));
-       Table::Id aTableId;
-       RecordId aRecordId;
-       
-       if (!aCursor->next(aTableId, inoutAttributes, inoutData,
-                                          inDbContext.mDatabaseSession, aRecordId))
-               // return a NULL handle, and implicitly delete the cursor
-               return CSSM_INVALID_HANDLE;
-
-       outUniqueRecord = createUniqueRecord(inDbContext, aTableId, aRecordId);
-       return aCursor.release()->handle(); // We didn't throw so keep the Cursor around.
-}
-
-bool
-AppleDatabase::dataGetNext(DbContext &inDbContext,
-                           CSSM_HANDLE inResultsHandle,
-                           CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                           CssmData *inoutData,
-                           CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
-{
-       auto_ptr<Cursor> aCursor(&HandleObject::find<Cursor>(inResultsHandle, CSSMERR_DL_INVALID_RESULTS_HANDLE));
-       Table::Id aTableId;
-       RecordId aRecordId;
-       
-       if (!aCursor->next(aTableId, inoutAttributes, inoutData, inDbContext.mDatabaseSession, aRecordId))
-               return false;
-
-       outUniqueRecord = createUniqueRecord(inDbContext, aTableId, aRecordId);
-
-       aCursor.release();
-       return true;
-}
-
-void
-AppleDatabase::dataAbortQuery(DbContext &inDbContext,
-                              CSSM_HANDLE inResultsHandle)
-{
-       delete &HandleObject::find<Cursor>(inResultsHandle, CSSMERR_DL_INVALID_RESULTS_HANDLE);
-}
-
-void
-AppleDatabase::dataGetFromUniqueRecordId(DbContext &inDbContext,
-                                         const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
-                                         CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
-                                         CssmData *inoutData)
-{
-       Table::Id aTableId;
-       const RecordId aRecordId(parseUniqueRecord(inUniqueRecord, aTableId));
-       // XXX Change CDSA spec to use new RecordId returned by this function
-       mDbModifier.getRecord(aTableId, aRecordId, inoutAttributes, inoutData,
-                                                 inDbContext.mDatabaseSession);
-}
-
-void
-AppleDatabase::freeUniqueRecord(DbContext &inDbContext,
-                                CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
-{
-       if (inUniqueRecord.RecordIdentifier.Length != 0
-               && inUniqueRecord.RecordIdentifier.Data != NULL)
-       {
-               inUniqueRecord.RecordIdentifier.Length = 0;
-               inDbContext.mDatabaseSession.free(inUniqueRecord.RecordIdentifier.Data);
-       }
-       inDbContext.mDatabaseSession.free(&inUniqueRecord);
-}
-
-void
-AppleDatabase::updateUniqueRecord(DbContext &inDbContext,
-                                                                 CSSM_DB_RECORDTYPE inTableId,
-                                                                 const RecordId &inRecordId,
-                                                                 CSSM_DB_UNIQUE_RECORD &inoutUniqueRecord)
-{
-       uint32 *aBuffer = reinterpret_cast<uint32 *>(inoutUniqueRecord.RecordIdentifier.Data);
-       aBuffer[0] = inTableId;
-       aBuffer[1] = inRecordId.mRecordNumber;
-       aBuffer[2] = inRecordId.mCreateVersion;
-       aBuffer[3] = inRecordId.mRecordVersion;
-}
-
-CSSM_DB_UNIQUE_RECORD_PTR
-AppleDatabase::createUniqueRecord(DbContext &inDbContext,
-                                                                 CSSM_DB_RECORDTYPE inTableId,
-                                                                 const RecordId &inRecordId)
-{
-       CSSM_DB_UNIQUE_RECORD_PTR aUniqueRecord =
-               inDbContext.mDatabaseSession.alloc<CSSM_DB_UNIQUE_RECORD>();
-       memset(aUniqueRecord, 0, sizeof(*aUniqueRecord));
-       aUniqueRecord->RecordIdentifier.Length = sizeof(uint32) * 4;
-       try
-       {
-               aUniqueRecord->RecordIdentifier.Data =
-                       inDbContext.mDatabaseSession.alloc<uint8>(sizeof(uint32) * 4);
-               updateUniqueRecord(inDbContext, inTableId, inRecordId, *aUniqueRecord);
-       }
-       catch(...)
-       {
-               inDbContext.mDatabaseSession.free(aUniqueRecord);
-               throw;
-       }
-
-       return aUniqueRecord;
-}
-
-const RecordId
-AppleDatabase::parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
-                                                                CSSM_DB_RECORDTYPE &outTableId)
-{
-       if (inUniqueRecord.RecordIdentifier.Length != sizeof(uint32) * 4)
-               CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
-
-       uint32 *aBuffer = reinterpret_cast<uint32 *>(inUniqueRecord.RecordIdentifier.Data);
-       outTableId = aBuffer[0];
-       return RecordId(aBuffer[1], aBuffer[2], aBuffer[3]);
-}
-
-void
-AppleDatabase::passThrough(DbContext &dbContext,
-                                                  uint32 passThroughId,
-                                                  const void *inputParams,
-                                                  void **outputParams)
-{
-       switch (passThroughId)
-       {
-       case CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT:
-               {
-                       AppleDbContext &dbc = safer_cast<AppleDbContext &>(dbContext);
-                       // Return the old state of the autoCommit flag if requested
-                       if (outputParams)
-                               *reinterpret_cast<CSSM_BOOL *>(outputParams) = dbc.autoCommit();
-                       dbc.autoCommit(inputParams ? CSSM_TRUE : CSSM_FALSE);
-               }
-               break;
-               
-       case CSSM_APPLEFILEDL_COMMIT:
-               mDbModifier.commit();
-               break;
-               
-       case CSSM_APPLEFILEDL_ROLLBACK:
-               mDbModifier.rollback();
-               break;
-
-       case CSSM_APPLECSPDL_DB_RELATION_EXISTS:
-       {
-               CSSM_BOOL returnValue;
-               
-               CSSM_DB_RECORDTYPE recordType = *(CSSM_DB_RECORDTYPE*) inputParams;
-               if (recordType == CSSM_DL_DB_RECORD_ANY || recordType == CSSM_DL_DB_RECORD_ALL_KEYS)
-               {
-                       returnValue = CSSM_TRUE;
-               }
-               else
-               {
-                       returnValue = mDbModifier.hasTable(recordType);
-               }
-               
-               *(CSSM_BOOL*) outputParams = returnValue;
-               break;
-       }
-
-       default:
-               CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
-               break;
-       }
-}