--- /dev/null
+/*
+ * Copyright (c) 2005-2006,2010 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The 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.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * 01DL_CreateReleation.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <Security/cssmapi.h>
+#include <Security/cssmapple.h>
+
+#include "testmore.h"
+#include "testenv.h"
+#include "testcssm.h"
+#include "testleaks.h"
+
+#define DBNAME "testdl"
+
+CSSM_APPLEDL_OPEN_PARAMETERS openParameters =
+{
+ sizeof(CSSM_APPLEDL_OPEN_PARAMETERS),
+ CSSM_APPLEDL_OPEN_PARAMETERS_VERSION,
+ CSSM_FALSE,
+ kCSSM_APPLEDL_MASK_MODE,
+ 0600
+};
+CSSM_DBINFO dbInfo =
+{
+ 0 /* NumberOfRecordTypes */,
+ NULL,
+ NULL,
+ NULL,
+ CSSM_TRUE /* IsLocal */,
+ NULL, /* AccessPath - URL, dir path, etc. */
+ NULL /* reserved */
+};
+CSSM_DB_SCHEMA_ATTRIBUTE_INFO attributeInfo[] =
+{
+ {
+ 1,
+ "string-1",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_STRING
+ },
+ {
+ 2,
+ "sint32-2",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_SINT32
+ },
+ {
+ 3,
+ "uint32-3",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_UINT32
+ },
+ {
+ 4,
+ "big_num-4",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
+ },
+ {
+ 5,
+ "real-5",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_REAL
+ },
+ {
+ 6,
+ "time-date-6",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
+ },
+ {
+ 7,
+ "blob-7",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_BLOB
+ },
+ {
+ 8,
+ "multi-uint32-8",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
+ },
+#if 0
+ /* @@@ DL bug if you create a relation with a
+ CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX type attribute it succeeds but
+ subsequent inserts in that table fail. */
+ {
+ 9,
+ "complex-9",
+ {},
+ CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX
+ }
+#endif
+};
+CSSM_DB_SCHEMA_INDEX_INFO indexInfo[] =
+{
+ {
+ 1,
+ 0,
+ CSSM_DB_INDEX_UNIQUE,
+ CSSM_DB_INDEX_ON_ATTRIBUTE
+ },
+ {
+ 1,
+ 1,
+ CSSM_DB_INDEX_NONUNIQUE,
+ CSSM_DB_INDEX_ON_ATTRIBUTE
+ },
+ {
+ 2,
+ 2,
+ CSSM_DB_INDEX_NONUNIQUE,
+ CSSM_DB_INDEX_ON_ATTRIBUTE
+ }
+};
+CSSM_DATA values_str_1[] =
+{
+ { 7, (uint8 *)"value-1" }
+};
+CSSM_DATA values_str_2[] =
+{
+ { 7, (uint8 *)"value-2" }
+};
+CSSM_DATA values_sint32_1[] =
+{
+ { sizeof(sint32), (uint8 *)"1111" }
+};
+CSSM_DATA values_sint32_2[] =
+{
+ { sizeof(sint32), (uint8 *)"2222" }
+};
+
+CSSM_DB_ATTRIBUTE_DATA attributeData[] =
+{
+ {
+ {
+ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
+ { (char *)((uint64_t)1<<32|1) },
+ CSSM_DB_ATTRIBUTE_FORMAT_STRING
+ },
+ sizeof(values_str_1) / sizeof(CSSM_DATA),
+ values_str_1
+ },
+ {
+ {
+ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
+ { (char *)((uint64_t)2<<32|2) },
+ CSSM_DB_ATTRIBUTE_FORMAT_SINT32
+ },
+ sizeof(values_sint32_1) / sizeof(CSSM_DATA),
+ values_sint32_1
+ }
+};
+CSSM_DB_RECORD_ATTRIBUTE_DATA attributes =
+{
+ 42,
+ 0x00008000,
+ sizeof(attributeData) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
+ attributeData
+};
+
+CSSM_DB_ATTRIBUTE_DATA newAttributeData[] =
+{
+ {
+ {
+ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
+ { (char *)((uint64_t)1<<32|1) },
+ CSSM_DB_ATTRIBUTE_FORMAT_STRING
+ },
+ sizeof(values_str_2) / sizeof(CSSM_DATA),
+ values_str_2
+ },
+ {
+ {
+ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER,
+ { (char *)((uint64_t)2<<32|2) },
+ CSSM_DB_ATTRIBUTE_FORMAT_SINT32
+ },
+ sizeof(values_sint32_2) / sizeof(CSSM_DATA),
+ values_sint32_2
+ }
+};
+CSSM_DB_RECORD_ATTRIBUTE_DATA newAttributes =
+{
+ 42,
+ 0x80000001, /* Semantic Information. */
+ sizeof(newAttributeData) / sizeof(CSSM_DB_ATTRIBUTE_DATA),
+ newAttributeData
+};
+
+static void free_attributes_data(const CSSM_API_MEMORY_FUNCS *memfuncs,
+ CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR attributes, CSSM_DATA_PTR data)
+{
+ if (data && data->Data)
+ {
+ memfuncs->free_func(data->Data, memfuncs->AllocRef);
+ data->Data = NULL;
+ }
+
+ if (attributes && attributes->AttributeData)
+ {
+ uint32 aix;
+ for (aix = 0; aix < attributes->NumberOfAttributes; ++aix)
+ {
+ if (attributes->AttributeData[aix].Value)
+ {
+ uint32 vix;
+ for (vix = 0;
+ vix < attributes->AttributeData[aix].NumberOfValues; ++vix)
+ {
+ if (attributes->AttributeData[aix].Value[vix].Data)
+ {
+ memfuncs->free_func(
+ attributes->AttributeData[aix].Value[vix].Data,
+ memfuncs->AllocRef);
+ }
+ }
+
+ memfuncs->free_func(attributes->AttributeData[aix].Value,
+ memfuncs->AllocRef);
+ attributes->AttributeData[aix].NumberOfValues = 0;
+ attributes->AttributeData[aix].Value = NULL;
+ }
+ }
+ }
+}
+
+static int test_is_attributes_data(
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes1, const CSSM_DATA *data1,
+ const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes2, const CSSM_DATA *data2,
+ const char *description, const char *directive,
+ const char *reason, const char *file, unsigned line)
+{
+ if (attributes1 || attributes2)
+ {
+ if (!attributes1 || !attributes2)
+ return test_ok(0, description, directive, reason, file, line,
+ "# got CSSM_DB_RECORD_ATTRIBUTE_DATA %p\n"
+ "# expected CSSM_DB_RECORD_ATTRIBUTE_DATA %p\n",
+ attributes1, attributes2);
+
+ if (attributes1->DataRecordType != attributes2->DataRecordType ||
+ attributes1->SemanticInformation !=
+ attributes2->SemanticInformation ||
+ attributes1->NumberOfAttributes != attributes2->NumberOfAttributes)
+ return test_ok(0, description, directive, reason, file, line,
+ "# got CSSM_DB_RECORD_ATTRIBUTE_DATA:\n"
+ "# DataRecordType: %08x\n"
+ "# SemanticInformation: %08x\n"
+ "# NumberOfAttributes: %lu\n"
+ "# expected CSSM_DB_RECORD_ATTRIBUTE_DATA:\n"
+ "# DataRecordType: %08x\n"
+ "# SemanticInformation: %08x\n"
+ "# NumberOfAttributes: %lu\n",
+ attributes1->DataRecordType,
+ attributes1->SemanticInformation,
+ attributes1->NumberOfAttributes,
+ attributes2->DataRecordType,
+ attributes2->SemanticInformation,
+ attributes2->NumberOfAttributes);
+ uint32 ai;
+ for (ai = 0; ai < attributes1->NumberOfAttributes; ++ai)
+ {
+ const CSSM_DB_ATTRIBUTE_DATA *a1 = &attributes1->AttributeData[ai];
+ const CSSM_DB_ATTRIBUTE_DATA *a2 = &attributes2->AttributeData[ai];
+ if (a1->Info.AttributeFormat != a2->Info.AttributeFormat ||
+ a1->NumberOfValues != a2->NumberOfValues)
+ return test_ok(0, description, directive, reason, file, line,
+ "# got AttributeData[%lu]:\n"
+ "# AttributeFormat: %08x\n"
+ "# NumberOfValues: %lu\n"
+ "# expected AttributeData[%lu]:\n"
+ "# AttributeFormat: %08x\n"
+ "# NumberOfValues: %lu\n",
+ ai, a1->Info.AttributeFormat, a1->NumberOfValues,
+ ai, a2->Info.AttributeFormat, a2->NumberOfValues);
+ uint32 vi;
+ for (vi = 0; vi < a1->NumberOfValues; ++vi)
+ {
+ const CSSM_DATA *d1 = &a1->Value[vi];
+ const CSSM_DATA *d2 = &a2->Value[vi];
+ if (d1->Length != d2->Length || !d1->Data || !d2->Data ||
+ memcmp(d1->Data, d2->Data, d1->Length))
+ return test_ok(d1->Data == d2->Data, description,
+ directive, reason, file, line,
+ "# got AttributeData[%lu].Value[%lu]:\n"
+ "# length: %lu\n"
+ "# data: '%.*s'\n"
+ "# expected AttributeData[%lu].Value[%lu]:\n"
+ "# length: %lu\n"
+ "# data: '%.*s'\n",
+ ai, vi, d1->Length, (int)d1->Length, d1->Data,
+ ai, vi, d2->Length, (int)d2->Length, d2->Data);
+ }
+ }
+ }
+ if (data1 || data2)
+ {
+ if (!data1 || !data2)
+ return test_ok(0, description, directive, reason, file, line,
+ "# got CSSM_DATA %p\n"
+ "# expected CSSM_DATA %p\n", data1, data2);
+ if (data1->Length != data2->Length || !data1->Data || !data2->Data ||
+ memcmp(data1->Data, data2->Data, data1->Length))
+ return test_ok(data1->Data == data2->Data, description, directive,
+ reason, file, line,
+ "# got CSSM_DATA:\n"
+ "# length: %lu\n"
+ "# data: '%.*s'\n"
+ "# expected CSSM_DATA:\n"
+ "# length: %lu\n"
+ "# data: '%.*s'\n",
+ data1->Length, (int)data1->Length, data1->Data,
+ data2->Length, (int)data2->Length, data2->Data);
+ }
+
+ return test_ok(1, description, directive, reason, file, line, NULL);
+}
+
+#define is_attributes_data(A1, D1, A2, D2, TESTNAME) \
+( \
+ test_is_attributes_data((A1), (D1), (A2), (D2), \
+ TESTNAME, test_directive, test_reason, __FILE__, __LINE__) \
+)
+
+static void test1(CSSM_DL_HANDLE dl)
+{
+ CSSM_DL_DB_HANDLE dldb = { dl };
+ CSSM_DB_UNIQUE_RECORD_PTR uniqueId;
+
+ CSSM_DATA data = { 4, (uint8 *)"test" };
+ ok_status(CSSM_DL_DbCreate(dl, DBNAME, NULL /* DbLocation */,
+ &dbInfo,
+ CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
+ NULL /* CredAndAclEntry */,
+ NULL /* &openParameters */,
+ &dldb.DBHandle),
+ "CSSM_DL_DbCreate");
+
+ is_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ &data,
+ &uniqueId),
+ CSSMERR_DL_INVALID_RECORDTYPE, "CSSM_DL_DataInsert no table");
+
+ ok_status(CSSM_DL_CreateRelation(dldb,
+ 42,
+ "Fourty Two",
+ sizeof(attributeInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO),
+ attributeInfo,
+ sizeof(indexInfo) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO),
+ indexInfo), "CSSM_DL_CreateRelation");
+
+ ok_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ &data,
+ &uniqueId), "CSSM_DL_DataInsert");
+
+ is_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ &data,
+ &uniqueId),
+ CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA, "CSSM_DL_DataInsert dupe");
+
+ ok_status(CSSM_DL_DataModify(dldb,
+ attributes.DataRecordType,
+ uniqueId,
+ &newAttributes,
+ &data,
+ CSSM_DB_MODIFY_ATTRIBUTE_REPLACE), "CSSM_DL_DataModify");
+
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+
+ ok_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ &data,
+ &uniqueId), "CSSM_DL_DataInsert old one again");
+
+ CSSM_API_MEMORY_FUNCS memfuncs = {};
+ ok_status(CSSM_GetAPIMemoryFunctions(dldb.DLHandle, &memfuncs),
+ "CSSM_GetAPIMemoryFunctions");
+
+ ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId, NULL, NULL),
+ "CSSM_DL_DataGetFromUniqueRecordId get nothing");
+
+ CSSM_DATA resultData = {};
+ ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
+ NULL, &resultData),
+ "CSSM_DL_DataGetFromUniqueRecordId get data");
+ is_attributes_data(NULL, &resultData, NULL, &data, "Does data match?");
+ free_attributes_data(&memfuncs, NULL, &resultData);
+
+ CSSM_DB_RECORD_ATTRIBUTE_DATA baseNoAttrs = attributes;
+ baseNoAttrs.NumberOfAttributes = 0;
+ baseNoAttrs.AttributeData = NULL;
+ CSSM_DB_RECORD_ATTRIBUTE_DATA resultNoAttrs = {};
+ ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
+ &resultNoAttrs, NULL),
+ "CSSM_DL_DataGetFromUniqueRecordId get 0 attributes");
+ is_attributes_data(&resultNoAttrs, NULL, &baseNoAttrs, NULL,
+ "Do attrs match?");
+ free_attributes_data(&memfuncs, &resultNoAttrs, NULL);
+
+ ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
+ &resultNoAttrs, &resultData),
+ "CSSM_DL_DataGetFromUniqueRecordId get data and 0 attributes");
+ is_attributes_data(&resultNoAttrs, &resultData, &baseNoAttrs, &data,
+ "Do attrs and data match?");
+ free_attributes_data(&memfuncs, &resultNoAttrs, &resultData);
+
+ CSSM_DB_ATTRIBUTE_DATA resultAttributeData[] =
+ {
+ {{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)1<<32|1) } }},
+ {{ CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)2<<32|2) } }}
+ };
+ CSSM_DB_RECORD_ATTRIBUTE_DATA resultAttrs =
+ {
+ 0, 0,
+ sizeof(resultAttributeData) / sizeof(*resultAttributeData),
+ resultAttributeData
+ };
+ ok_status(CSSM_DL_DataGetFromUniqueRecordId(dldb, uniqueId,
+ &resultAttrs, &resultData),
+ "CSSM_DL_DataGetFromUniqueRecordId get data and 2 attributes");
+ is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
+ "Do attrs and data match?");
+ free_attributes_data(&memfuncs, &resultAttrs, &resultData);
+
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+
+ CSSM_SELECTION_PREDICATE predicates[] =
+ {
+ {
+ CSSM_DB_EQUAL,
+ {
+ { CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER, { (char *)((uint64_t)1<<32|1) } },
+ 1, values_str_1
+ }
+ }
+ };
+ CSSM_QUERY query =
+ {
+ attributes.DataRecordType,
+ CSSM_DB_AND,
+ sizeof(predicates) / sizeof(*predicates),
+ predicates,
+ { CSSM_QUERY_TIMELIMIT_NONE, CSSM_QUERY_SIZELIMIT_NONE },
+ 0 /* CSSM_QUERY_RETURN_DATA -- for keys only to return raw key bits */
+ };
+ CSSM_HANDLE search = CSSM_INVALID_HANDLE;
+ is_status(CSSM_DL_DataGetFirst(dldb, &query, NULL,
+ NULL, NULL, NULL), CSSM_ERRCODE_INVALID_POINTER,
+ "CSSM_DL_DataGetFirst no search handle, no unique_record");
+ is_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ NULL, NULL, NULL), CSSM_ERRCODE_INVALID_POINTER,
+ "CSSM_DL_DataGetFirst no unique_record");
+ is_status(CSSM_DL_DataGetFirst(dldb, &query, NULL,
+ NULL, NULL, &uniqueId), CSSM_ERRCODE_INVALID_POINTER,
+ "CSSM_DL_DataGetFirst no search handle");
+
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ NULL, NULL, &uniqueId),
+ "CSSM_DL_DataGetFirst no data no attrs");
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataAbortQuery(dldb, search),
+ "CSSM_DL_DataAbortQuery");
+
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ &resultNoAttrs, NULL, &uniqueId),
+ "CSSM_DL_DataGetFirst 0 attrs");
+ is_attributes_data(&resultNoAttrs, NULL, &baseNoAttrs, NULL,
+ "Do attrs match?");
+ free_attributes_data(&memfuncs, &resultNoAttrs, NULL);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataAbortQuery(dldb, search),
+ "CSSM_DL_DataAbortQuery");
+
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ NULL, &resultData, &uniqueId),
+ "CSSM_DL_DataGetFirst data");
+ is_attributes_data(NULL, &resultData, NULL, &data, "Does data match?");
+ free_attributes_data(&memfuncs, NULL, &resultData);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataAbortQuery(dldb, search),
+ "CSSM_DL_DataAbortQuery");
+
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ &resultNoAttrs, &resultData, &uniqueId),
+ "CSSM_DL_DataGetFirst 0 attrs and data");
+ is_attributes_data(&resultNoAttrs, &resultData, &baseNoAttrs, &data,
+ "Do attrs and data match?");
+ free_attributes_data(&memfuncs, &resultNoAttrs, &resultData);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataAbortQuery(dldb, search),
+ "CSSM_DL_DataAbortQuery");
+
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ &resultAttrs, &resultData, &uniqueId),
+ "CSSM_DL_DataGetFirst 2 attrs and data");
+ is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
+ "Do attrs and data match?");
+ free_attributes_data(&memfuncs, &resultAttrs, &resultData);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataAbortQuery(dldb, search),
+ "CSSM_DL_DataAbortQuery");
+
+ SKIP: {
+ skip("nothing to free", 2,
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query, &search,
+ &resultAttrs, &resultData, &uniqueId),
+ "CSSM_DL_DataGetFirst 2 attrs and data"));
+ is_attributes_data(&resultAttrs, &resultData, &attributes, &data,
+ "Do attrs and data match?");
+ free_attributes_data(&memfuncs, &resultAttrs, &resultData);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ }
+
+ is_status(CSSM_DL_DataGetNext(dldb, search,
+ &resultAttrs, &resultData, &uniqueId),
+ CSSMERR_DL_ENDOFDATA, "CSSM_DL_DataGetNext returns eod");
+
+ CSSM_QUERY query2 =
+ {
+ attributes.DataRecordType,
+ CSSM_DB_NONE,
+ 0,
+ NULL,
+ { CSSM_QUERY_TIMELIMIT_NONE, CSSM_QUERY_SIZELIMIT_NONE },
+ 0 /* CSSM_QUERY_RETURN_DATA -- for keys only to return raw key bits */
+ };
+ ok_status(CSSM_DL_DataGetFirst(dldb, &query2, &search,
+ &resultAttrs, &resultData, &uniqueId),
+ "CSSM_DL_DataGetFirst 2 attrs and data");
+ free_attributes_data(&memfuncs, &resultAttrs, &resultData);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataGetNext(dldb, search,
+ &resultAttrs, &resultData, &uniqueId),
+ "CSSM_DL_DataGetNext 2 attrs and data");
+ free_attributes_data(&memfuncs, &resultAttrs, &resultData);
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+ ok_status(CSSM_DL_DataAbortQuery(dldb, search),
+ "CSSM_DL_DataAbortQuery");
+
+ ok_status(CSSM_DL_DbClose(dldb),
+ "CSSM_DL_DbClose");
+}
+
+static void test2(CSSM_DL_HANDLE dl)
+{
+ CSSM_DL_DB_HANDLE dldb = { dl };
+ CSSM_DB_UNIQUE_RECORD_PTR uniqueId;
+
+ ok_status(CSSM_DL_DbCreate(dl, DBNAME, NULL /* DbLocation */,
+ &dbInfo,
+ CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
+ NULL /* CredAndAclEntry */,
+ NULL,
+ &dldb.DBHandle),
+ "CSSM_DL_DbCreate");
+
+ ok_status(CSSM_DL_DbClose(dldb),
+ "CSSM_DL_DbClose");
+
+ ok_status(CSSM_DL_DbOpen(dl, DBNAME, NULL /* DbLocation */,
+ CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
+ NULL /* CredAndAclEntry */,
+ &openParameters,
+ &dldb.DBHandle),
+ "CSSM_DL_DbOpen");
+
+ is_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ NULL,
+ &uniqueId),
+ CSSMERR_DL_INVALID_RECORDTYPE, "CSSM_DL_DataInsert no table");
+
+ ok_status(CSSM_DL_CreateRelation(dldb,
+ 42,
+ "Fourty Two",
+ sizeof(attributeInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO),
+ attributeInfo,
+ sizeof(indexInfo) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO),
+ indexInfo), "CSSM_DL_CreateRelation");
+
+ ok_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ NULL,
+ &uniqueId), "CSSM_DL_DataInsert fails unless 4039735 is fixed");
+
+ is_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ NULL,
+ &uniqueId),
+ CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA,
+ "CSSM_DL_DataInsert dupe");
+
+ ok_status(CSSM_DL_DataDelete(dldb, uniqueId),
+ "CSSM_DL_Delete");
+
+ is_status(CSSM_DL_DataDelete(dldb, uniqueId),
+ CSSMERR_DL_RECORD_NOT_FOUND, "delete again should fail");
+
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+
+ ok_status(CSSM_DL_DataInsert(dldb,
+ attributes.DataRecordType,
+ &attributes,
+ NULL,
+ &uniqueId), "Insert again after delete");
+
+ ok_status(CSSM_DL_FreeUniqueRecord(dldb, uniqueId),
+ "CSSM_DL_FreeUniqueRecord");
+
+ ok_status(CSSM_DL_DbClose(dldb),
+ "CSSM_DL_DbDelete");
+}
+
+int
+main(int argc, char * const *argv)
+{
+ int guid_alt = argc > 1 && !strcmp(argv[1], "-g");
+ /* {2cb56191-ee6f-432d-a377-853d3c6b949e} */
+ CSSM_GUID s3dl_guid =
+ {
+ 0x2cb56191, 0xee6f, 0x432d,
+ { 0xa3, 0x77, 0x85, 0x3d, 0x3c, 0x6b, 0x94, 0x9e }
+ };
+ const CSSM_GUID *guid = guid_alt ? & s3dl_guid : &gGuidAppleFileDL;
+
+ plan_tests(70);
+
+ CSSM_DL_HANDLE dl;
+ ok(cssm_attach(guid, &dl), "cssm_attach");
+ ok(tests_begin(argc, argv), "tests_begin");
+
+ test1(dl);
+ ok_status(CSSM_DL_DbDelete(dl, DBNAME, NULL /* DbLocation */,
+ NULL /* AccessCred */), "CSSM_DL_DbDelete");
+ test2(dl);
+ ok_status(CSSM_DL_DbDelete(dl, DBNAME, NULL /* DbLocation */,
+ NULL /* AccessCred */), "CSSM_DL_DbDelete");
+ ok(cssm_detach(guid, dl), "cssm_detach");
+ ok_leaks("no leaks");
+
+ return !tests_end(1);
+}