gnome-keyring r1414 - in trunk: . gp11 gp11/tests tool



Author: nnielsen
Date: Tue Dec 30 02:18:02 2008
New Revision: 1414
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1414&view=rev

Log:
	* gp11/gp11.h:
	* gp11/gp11-attributes.c:
	* gp11/gp11-object.c:
	* gp11/gp11-private.h:
	* gp11/gp11-session.c:
	* gp11/tests/Makefile.am:
	* gp11/tests/unit-test-gp11-attributes.c:
	* gp11/tests/unit-test-gp11-crypto.c:
	* gp11/tests/unit-test-gp11-object.c:
	* tool/gkr-tool-import.c: Add support for specifying custom allocators
	on GP11Attributes, and fine tune how gp11_object_get_* work. Add 
	concept of locked attribute arrays with guarantees of application to 
	not modify while we're processing them. 


Modified:
   trunk/ChangeLog
   trunk/gp11/gp11-attributes.c
   trunk/gp11/gp11-object.c
   trunk/gp11/gp11-private.h
   trunk/gp11/gp11-session.c
   trunk/gp11/gp11.h
   trunk/gp11/tests/Makefile.am
   trunk/gp11/tests/unit-test-gp11-attributes.c
   trunk/gp11/tests/unit-test-gp11-crypto.c
   trunk/gp11/tests/unit-test-gp11-object.c
   trunk/tool/gkr-tool-import.c

Modified: trunk/gp11/gp11-attributes.c
==============================================================================
--- trunk/gp11/gp11-attributes.c	(original)
+++ trunk/gp11/gp11-attributes.c	Tue Dec 30 02:18:02 2008
@@ -29,6 +29,25 @@
 #include <stdlib.h>
 #include <string.h>
 
+
+static void
+attribute_init (GP11Attribute *attr, gulong attr_type, 
+                gconstpointer value, gsize length,
+                GP11Allocator allocator)
+{
+	g_assert (sizeof (GP11Attribute) == sizeof (CK_ATTRIBUTE));
+	g_assert (allocator);
+	
+	memset (attr, 0, sizeof (GP11Attribute));
+	attr->type = attr_type;
+	attr->length = length;
+	if (value && length) {
+		attr->value = (allocator) (NULL, length);
+		g_assert (attr->value);
+		memcpy (attr->value, value, length);
+	}
+}
+
 /**
  * gp11_attribute_init:
  * @attr: An uninitialized attribute.
@@ -46,11 +65,8 @@
 gp11_attribute_init (GP11Attribute *attr, gulong attr_type, 
                      gconstpointer value, gsize length)
 {
-	g_assert (sizeof (GP11Attribute) == sizeof (CK_ATTRIBUTE));
-	memset (attr, 0, sizeof (GP11Attribute));
-	attr->type = attr_type;
-	attr->length = length;
-	attr->value = value && length ? g_memdup (value, length) : NULL;
+	g_return_if_fail (attr);
+	attribute_init (attr, attr_type, value, length, g_realloc);
 }
 
 /**
@@ -68,21 +84,41 @@
 void
 gp11_attribute_init_invalid (GP11Attribute *attr, gulong attr_type)
 {
+	g_return_if_fail (attr);
 	g_assert (sizeof (GP11Attribute) == sizeof (CK_ATTRIBUTE));
 	memset (attr, 0, sizeof (GP11Attribute));
 	attr->type = attr_type;
 	attr->length = (gulong)-1;
 }
 
+/**
+ * gp11_attribute_init_empty:
+ * @attr: An uninitialized attribute.
+ * @attr_type: The PKCS#11 attribute type to set on the attribute.
+ * 
+ * Initialize a PKCS#11 attribute to an empty state. The attribute
+ * type will be set, but no data will be set.
+ * 
+ * When done with the attribute you should use gp11_attribute_clear()
+ * to free the internal memory. 
+ **/
 void
-_gp11_attribute_init_take (GP11Attribute *attr, gulong attr_type,
-                           gpointer value, gsize length)
+gp11_attribute_init_empty (GP11Attribute *attr, gulong attr_type)
 {
+	g_return_if_fail (attr);
 	g_assert (sizeof (GP11Attribute) == sizeof (CK_ATTRIBUTE));
 	memset (attr, 0, sizeof (GP11Attribute));
 	attr->type = attr_type;
-	attr->length = length;
-	attr->value = value && length ? value : NULL;	
+	attr->length = 0;
+	attr->value = 0;
+}
+
+static void 
+attribute_init_boolean (GP11Attribute *attr, gulong attr_type, 
+                        gboolean value, GP11Allocator allocator)
+{
+	CK_BBOOL bvalue = value ? CK_TRUE : CK_FALSE;
+	attribute_init (attr, attr_type, &bvalue, sizeof (bvalue), allocator);
 }
 
 /**
@@ -101,8 +137,25 @@
 gp11_attribute_init_boolean (GP11Attribute *attr, gulong attr_type, 
                              gboolean value)
 {
-	CK_BBOOL bvalue = value ? CK_TRUE : CK_FALSE;
-	gp11_attribute_init (attr, attr_type, &bvalue, sizeof (bvalue));
+	g_return_if_fail (attr);
+	attribute_init_boolean (attr, attr_type, value, g_realloc);
+}
+
+static void
+attribute_init_date (GP11Attribute *attr, gulong attr_type, 
+                     const GDate *value, GP11Allocator allocator)
+{
+	gchar buffer[9];
+	CK_DATE date;
+	g_assert (value);
+	g_snprintf (buffer, sizeof (buffer), "%04d%02d%02d",
+	            (int)g_date_get_year (value), 
+	            (int)g_date_get_month (value),
+	            (int)g_date_get_day (value));
+	memcpy (&date.year, buffer + 0, 4);
+	memcpy (&date.month, buffer + 4, 2);
+	memcpy (&date.day, buffer + 6, 2);
+	attribute_init (attr, attr_type, &date, sizeof (CK_DATE), allocator);
 }
 
 /**
@@ -121,17 +174,17 @@
 gp11_attribute_init_date (GP11Attribute *attr, gulong attr_type, 
                           const GDate *value)
 {
-	gchar buffer[9];
-	CK_DATE date;
+	g_return_if_fail (attr);
 	g_return_if_fail (value);
-	g_snprintf (buffer, sizeof (buffer), "%04d%02d%02d",
-	            (int)g_date_get_year (value), 
-	            (int)g_date_get_month (value),
-	            (int)g_date_get_day (value));
-	memcpy (&date.year, buffer + 0, 4);
-	memcpy (&date.month, buffer + 4, 2);
-	memcpy (&date.day, buffer + 6, 2);
-	gp11_attribute_init (attr, attr_type, &date, sizeof (CK_DATE));
+	attribute_init_date (attr, attr_type, value, g_realloc);
+}
+
+static void
+attribute_init_ulong (GP11Attribute *attr, gulong attr_type,
+                      gulong value, GP11Allocator allocator)
+{
+	CK_ULONG uvalue = value;
+	attribute_init (attr, attr_type, &uvalue, sizeof (uvalue), allocator);
 }
 
 /**
@@ -150,8 +203,16 @@
 gp11_attribute_init_ulong (GP11Attribute *attr, gulong attr_type,
                            gulong value)
 {
-	CK_ULONG uvalue = value;
-	gp11_attribute_init (attr, attr_type, &uvalue, sizeof (uvalue));
+	g_return_if_fail (attr);
+	attribute_init_ulong (attr, attr_type, value, g_realloc);
+}
+
+static void
+attribute_init_string (GP11Attribute *attr, gulong attr_type, 
+                       const gchar *value, GP11Allocator allocator)
+{
+	gsize len = value ? strlen (value) : 0;
+	attribute_init (attr, attr_type, (gpointer)value, len, allocator);
 }
 
 /**
@@ -172,8 +233,8 @@
 gp11_attribute_init_string (GP11Attribute *attr, gulong attr_type, 
                             const gchar *value)
 {
-	gsize len = value ? strlen (value) : 0;
-	gp11_attribute_init (attr, attr_type, (gpointer)value, len);
+	g_return_if_fail (attr);
+	attribute_init_string (attr, attr_type, value, g_realloc);
 }
 
 /**
@@ -192,7 +253,7 @@
 gp11_attribute_new (gulong attr_type, gpointer value, gsize length)
 {
 	GP11Attribute *attr = g_slice_new0 (GP11Attribute);
-	gp11_attribute_init (attr, attr_type, value, length);
+	attribute_init (attr, attr_type, value, length, g_realloc);
 	return attr;
 }
 
@@ -216,6 +277,23 @@
 }
 
 /**
+ * gp11_attribute_new_empty:
+ * @attr_type: The PKCS#11 attribute type to set on the attribute.
+ * 
+ * Create a new PKCS#11 attribute with empty data. 
+ * 
+ * Return value: The new attribute. When done with the attribute use 
+ * gp11_attribute_free() to free it.
+ */
+GP11Attribute*
+gp11_attribute_new_empty (gulong attr_type)
+{
+	GP11Attribute *attr = g_slice_new0 (GP11Attribute);
+	gp11_attribute_init_empty (attr, attr_type);
+	return attr;
+}
+
+/**
  * gp11_attribute_new_boolean:
  * @attr_type: The PKCS#11 attribute type to set on the attribute.
  * @value: The boolean value of the attribute.
@@ -230,7 +308,7 @@
 gp11_attribute_new_boolean (gulong attr_type, gboolean value)
 {
 	GP11Attribute *attr = g_slice_new0 (GP11Attribute);
-	gp11_attribute_init_boolean (attr, attr_type, value);
+	attribute_init_boolean (attr, attr_type, value, g_realloc);
 	return attr;	
 }
 
@@ -249,7 +327,7 @@
 gp11_attribute_new_date (gulong attr_type, const GDate *value)
 {
 	GP11Attribute *attr = g_slice_new0 (GP11Attribute);
-	gp11_attribute_init_date (attr, attr_type, value);
+	attribute_init_date (attr, attr_type, value, g_realloc);
 	return attr;		
 }
 
@@ -268,7 +346,7 @@
 gp11_attribute_new_ulong (gulong attr_type, gulong value)
 {
 	GP11Attribute *attr = g_slice_new0 (GP11Attribute);
-	gp11_attribute_init_ulong (attr, attr_type, value);
+	attribute_init_ulong (attr, attr_type, value, g_realloc);
 	return attr;			
 }
 
@@ -289,7 +367,7 @@
 gp11_attribute_new_string (gulong attr_type, const gchar *value)
 {
 	GP11Attribute *attr = g_slice_new0 (GP11Attribute);
-	gp11_attribute_init_string (attr, attr_type, value);
+	attribute_init_string (attr, attr_type, value, g_realloc);
 	return attr;		
 }
 
@@ -449,6 +527,26 @@
 	return copy;
 }
 
+static void
+attribute_init_copy (GP11Attribute *dest, const GP11Attribute *src, GP11Allocator allocator)
+{
+	g_assert (dest);
+	g_assert (src);
+	g_assert (allocator);
+
+	/* 
+	 * TODO: Handle stupid, dumb, broken, special cases like
+	 * CKA_WRAP_TEMPLATE and CKA_UNWRAP_TEMPLATE. 
+	 */
+
+	memcpy (dest, src, sizeof (GP11Attribute));
+	if (src->value && src->length) {
+		dest->value = (allocator) (NULL, src->length);
+		g_assert (dest->value);
+		memcpy (dest->value, src->value, src->length);
+	}
+}
+
 /**
  * gp11_attribute_init_copy:
  * @dest: An uninitialized attribute.
@@ -461,18 +559,22 @@
  * gp11_attribute_clear() to free the internal memory. 
  **/ 
 void
-gp11_attribute_init_copy (GP11Attribute *dest, GP11Attribute *src)
+gp11_attribute_init_copy (GP11Attribute *dest, const GP11Attribute *src)
 {
 	g_return_if_fail (dest);
 	g_return_if_fail (src);
+	attribute_init_copy (dest, src, g_realloc);
+}
 
-	/* 
-	 * TODO: Handle stupid, dumb, broken, special cases like
-	 * CKA_WRAP_TEMPLATE and CKA_UNWRAP_TEMPLATE. 
-	 */
-	
-	memcpy (dest, src, sizeof (GP11Attribute));
-	dest->value = src->value && src->length ? g_memdup (src->value, src->length) : NULL;
+static void
+attribute_clear (GP11Attribute *attr, GP11Allocator allocator)
+{
+	g_assert (attr);
+	g_assert (allocator);
+	if (attr->value)
+		(allocator) (attr->value, 0);
+	attr->value = NULL;
+	attr->length = 0;
 }
 
 /**
@@ -482,13 +584,14 @@
  * Clear allocated memory held by a statically allocated attribute.
  * These are usually initialized with gp11_attribute_init() or a 
  * similar function.
+ * 
+ * The type of the attribute will remain set.
  **/
 void
 gp11_attribute_clear (GP11Attribute *attr)
 {
 	g_return_if_fail (attr);
-	g_free (attr->value);
-	memset (attr, 0, sizeof (GP11Attribute));
+	attribute_clear (attr, g_realloc);
 }
 
 /**
@@ -503,14 +606,15 @@
 gp11_attribute_free (GP11Attribute *attr)
 {
 	if (attr) {
-		gp11_attribute_clear (attr);
+		attribute_clear (attr, g_realloc);
 		g_slice_free (GP11Attribute, attr);
 	}
 }
 
 struct _GP11Attributes {
 	GArray *array;
-	gint immutable;
+	GP11Allocator allocator;
+	gboolean locked;
 	gint refs;
 };
 
@@ -543,24 +647,73 @@
 GP11Attributes*
 gp11_attributes_new (void)
 {
+	return gp11_attributes_new_full (g_realloc);
+}
+
+/**
+ * gp11_attributes_new_full:
+ * @allocator: Memory allocator for attribute data, or NULL for default.
+ * 
+ * Create a new GP11Attributes array.
+ * 
+ * Return value: The new attributes array. When done with the array 
+ * release it with gp11_attributes_unref().
+ **/
+GP11Attributes*
+gp11_attributes_new_full (GP11Allocator allocator)
+{
 	GP11Attributes *attrs;
+
+	if (!allocator)
+		allocator = g_realloc;
 	
 	g_assert (sizeof (GP11Attribute) == sizeof (CK_ATTRIBUTE));
 	attrs = g_slice_new0 (GP11Attributes);
 	attrs->array = g_array_new (0, 1, sizeof (GP11Attribute));
+	attrs->allocator = allocator;
 	attrs->refs = 1;
-	attrs->immutable = 0;
+	attrs->locked = FALSE;
+	return attrs;
+}
+
+/**
+ * gp11_attributes_new_empty:
+ * @attr_type: The first attribute type to add as empty.
+ * 
+ * Creates an GP11Attributes array with empty attributes. The arguments 
+ * should be values of attribute types, terminated with -1.
+ * 
+ * Return value: The new attributes array. When done with the array 
+ * release it with gp11_attributes_unref().
+ **/
+GP11Attributes*
+gp11_attributes_new_empty (gulong attr_type, ...)
+{
+	GP11Attributes *attrs = gp11_attributes_new_full (g_realloc);
+	va_list va;
+
+	va_start (va, attr_type);
+	
+	while (attr_type != (gulong)-1) {
+		gp11_attributes_add_empty (attrs, attr_type);
+		attr_type = va_arg (va, gulong);
+	}
+
+	va_end (va);
+
 	return attrs;
 }
 
 static GP11Attributes*
-initialize_from_valist (gulong type, va_list va)
+initialize_from_valist (GP11Allocator allocator, gulong type, va_list va)
 {
 	GP11Attributes *attrs;
 	gssize length;
 	gpointer value;
 	
-	attrs = gp11_attributes_new ();
+	g_assert (allocator);
+	
+	attrs = gp11_attributes_new_full (allocator);
 	
 	/* No attributes */
 	if (type == (gulong)-1)
@@ -639,7 +792,7 @@
 	va_list va;
 	
 	va_start (va, first_type);
-	attrs = initialize_from_valist (first_type, va);
+	attrs = initialize_from_valist (g_realloc, first_type, va);
 	va_end (va);
 	
 	return attrs;
@@ -647,6 +800,7 @@
 
 /**
  * gp11_attributes_newv:
+ * @allocator: Memory allocator for attribute data, or NULL for default.
  * @va: Variable argument containing attributes to add. 
  * 
  * Create a new GP11Attributes array.
@@ -676,10 +830,14 @@
  * release it with gp11_attributes_unref().
  **/
 GP11Attributes*
-gp11_attributes_new_valist (va_list va)
+gp11_attributes_new_valist (GP11Allocator allocator, va_list va)
 {
 	gulong type = va_arg (va, gulong);
-	return initialize_from_valist (type, va);
+	
+	if (!allocator)
+		allocator = g_realloc;
+	
+	return initialize_from_valist (allocator, type, va);
 }
 
 /**
@@ -699,23 +857,15 @@
 {
 	g_return_val_if_fail (attrs && attrs->array, NULL);
 	g_return_val_if_fail (index < attrs->array->len, NULL);
-	g_return_val_if_fail (g_atomic_int_get (&attrs->immutable) == 0, NULL);
+	g_return_val_if_fail (!attrs->locked, NULL);
 	return &g_array_index (attrs->array, GP11Attribute, index);
 }
 
-CK_ATTRIBUTE_PTR
-_gp11_attributes_raw (GP11Attributes *attrs)
-{
-	g_return_val_if_fail (attrs && attrs->array, NULL);
-	return (CK_ATTRIBUTE_PTR)attrs->array->data;
-}
-
 static GP11Attribute*
 attributes_push (GP11Attributes *attrs)
 {
 	GP11Attribute attr;
-	g_assert (g_atomic_int_get (&attrs->immutable) == 0);
-	
+	g_assert (!attrs->locked);
 	memset (&attr, 0, sizeof (attr));
 	g_array_append_val (attrs->array, attr);
 	return &g_array_index (attrs->array, GP11Attribute, attrs->array->len - 1);
@@ -735,21 +885,10 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs && attrs->array);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	g_return_if_fail (attr);
 	added = attributes_push (attrs);
-	gp11_attribute_init_copy (added, attr);
-}
-
-void
-_gp11_attributes_add_take (GP11Attributes *attrs, gulong attr_type,
-                           gpointer value, gsize length)
-{
-	GP11Attribute *added;
-	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
-	added = attributes_push (attrs);
-	_gp11_attribute_init_take (added, attr_type, (gpointer)value, length);
+	attribute_init_copy (added, attr, attrs->allocator);
 }
 
 /**
@@ -769,9 +908,9 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	added = attributes_push (attrs);
-	gp11_attribute_init (added, attr_type, value, length);
+	attribute_init (added, attr_type, value, length, attrs->allocator);
 }
 
 /**
@@ -786,12 +925,29 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	added = attributes_push (attrs);
 	gp11_attribute_init_invalid (added, attr_type);	
 }
 
 /**
+ * gp11_attributes_add_empty:
+ * @attrs: The attributes array to add.
+ * @attr_type: The type of attribute to add.
+ * 
+ * Add an attribute with the specified type, with empty data.
+ **/
+void
+gp11_attributes_add_empty (GP11Attributes *attrs, gulong attr_type)
+{
+	GP11Attribute *added;
+	g_return_if_fail (attrs);
+	g_return_if_fail (!attrs->locked);
+	added = attributes_push (attrs);
+	gp11_attribute_init_empty (added, attr_type);		
+}
+
+/**
  * gp11_attributes_add_boolean:
  * @attrs: The attributes array to add to.
  * @attr_type: The type of attribute to add.
@@ -806,9 +962,9 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	added = attributes_push (attrs);
-	gp11_attribute_init_boolean (added, attr_type, value);
+	attribute_init_boolean (added, attr_type, value, attrs->allocator);
 }
 
 /**
@@ -826,9 +982,9 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	added = attributes_push (attrs);
-	gp11_attribute_init_string (added, attr_type, value);
+	attribute_init_string (added, attr_type, value, attrs->allocator);
 }
 
 /**
@@ -846,9 +1002,9 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	added = attributes_push (attrs);
-	gp11_attribute_init_date (added, attr_type, value);
+	attribute_init_date (added, attr_type, value, attrs->allocator);
 }
 
 /**
@@ -866,9 +1022,9 @@
 {
 	GP11Attribute *added;
 	g_return_if_fail (attrs);
-	g_return_if_fail (g_atomic_int_get (&attrs->immutable) == 0);
+	g_return_if_fail (!attrs->locked);
 	added = attributes_push (attrs);
-	gp11_attribute_init_ulong (added, attr_type, value);
+	attribute_init_ulong (added, attr_type, value, attrs->allocator);
 }
 
 /**
@@ -883,6 +1039,7 @@
 gp11_attributes_count (GP11Attributes *attrs)
 {
 	g_return_val_if_fail (attrs, 0);
+	g_return_val_if_fail (!attrs->locked, 0);
 	return attrs->array->len;
 }
 
@@ -902,7 +1059,8 @@
 	guint i;
 	
 	g_return_val_if_fail (attrs && attrs->array, NULL);
-	
+	g_return_val_if_fail (!attrs->locked, NULL);
+
 	for (i = 0; i < attrs->array->len; ++i) {
 		attr = gp11_attributes_at (attrs, i);
 		if (attr->type == attr_type)
@@ -930,7 +1088,9 @@
 gp11_attributes_find_boolean (GP11Attributes *attrs, gulong attr_type, gboolean *value)
 {
 	GP11Attribute *attr;
+
 	g_return_val_if_fail (value, FALSE);
+	g_return_val_if_fail (!attrs->locked, FALSE);
 
 	attr = gp11_attributes_find (attrs, attr_type);
 	if (!attr || gp11_attribute_is_invalid (attr))
@@ -957,7 +1117,9 @@
 gp11_attributes_find_ulong (GP11Attributes *attrs, gulong attr_type, gulong *value)
 {
 	GP11Attribute *attr;
+	
 	g_return_val_if_fail (value, FALSE);
+	g_return_val_if_fail (!attrs->locked, FALSE);
 
 	attr = gp11_attributes_find (attrs, attr_type);
 	if (!attr || gp11_attribute_is_invalid (attr))
@@ -984,7 +1146,9 @@
 gp11_attributes_find_string (GP11Attributes *attrs, gulong attr_type, gchar **value)
 {
 	GP11Attribute *attr;
+	
 	g_return_val_if_fail (value, FALSE);
+	g_return_val_if_fail (!attrs->locked, FALSE);
 
 	attr = gp11_attributes_find (attrs, attr_type);
 	if (!attr || gp11_attribute_is_invalid (attr))
@@ -1011,7 +1175,9 @@
 gp11_attributes_find_date (GP11Attributes *attrs, gulong attr_type, GDate *value)
 {
 	GP11Attribute *attr;
+	
 	g_return_val_if_fail (value, FALSE);
+	g_return_val_if_fail (!attrs->locked, FALSE);
 
 	attr = gp11_attributes_find (attrs, attr_type);
 	if (!attr || gp11_attribute_is_invalid (attr))
@@ -1052,10 +1218,101 @@
 	
 	if (g_atomic_int_dec_and_test (&attrs->refs)) {
 		g_return_if_fail (attrs->array);
+		g_return_if_fail (!attrs->locked);
 		for (i = 0; i < attrs->array->len; ++i)
-			gp11_attribute_clear (gp11_attributes_at (attrs, i));
+			attribute_clear (gp11_attributes_at (attrs, i), attrs->allocator);
 		g_array_free (attrs->array, TRUE);
 		attrs->array = NULL;
 		g_slice_free (GP11Attributes, attrs);
 	}
 }
+
+/* -------------------------------------------------------------------------------------------
+ * INTERNAL
+ * 
+ * The idea is that while we're processing a GP11Attributes array (via PKCS#11 
+ * C_GetAtributeValue for example) the calling application shouldn't access those
+ * attributes at all, except to ref or unref them.
+ * 
+ * We try to help debug this with our 'locked' states. The various processing 
+ * functions that accept GP11Attributes lock the attributes while handing 
+ * them off to be processed (perhaps in a different thread). We check this locked
+ * flag in all public functions accessing GP11Attributes.
+ * 
+ * The reason we don't use thread safe or atomic primitives here, is because:
+ *  a) The attributes are 'locked' by the same thread that prepares the call.
+ *  b) This is a debugging feature, and should not be relied on for correctness. 
+ */
+
+void
+_gp11_attributes_lock (GP11Attributes *attrs)
+{
+	g_assert (attrs);
+	g_assert (!attrs->locked);
+	attrs->locked = TRUE;
+}
+
+void
+_gp11_attributes_unlock (GP11Attributes *attrs)
+{
+	g_assert (attrs);
+	g_assert (attrs->locked);
+	attrs->locked = FALSE;
+}
+
+CK_ATTRIBUTE_PTR
+_gp11_attributes_prepare_in (GP11Attributes *attrs, CK_ULONG_PTR n_attrs)
+{
+	GP11Attribute *attr;
+	guint i;
+
+	g_assert (attrs);
+	g_assert (n_attrs);
+	g_assert (attrs->locked);
+	
+	/* Prepare the attributes to receive their length */
+	
+	for (i = 0; i < attrs->array->len; ++i) {
+		attr = &g_array_index (attrs->array, GP11Attribute, i);
+		attribute_clear (attr, attrs->allocator);
+	}
+	
+	*n_attrs = attrs->array->len;
+	return (CK_ATTRIBUTE_PTR)attrs->array->data;
+}
+
+CK_ATTRIBUTE_PTR
+_gp11_attributes_commit_in (GP11Attributes *attrs, CK_ULONG_PTR n_attrs)
+{
+	GP11Attribute *attr;
+	guint i;
+	
+	g_assert (attrs);
+	g_assert (n_attrs);
+	g_assert (attrs->locked);
+	
+	/* Allocate each attribute with the length that was set */
+	
+	for (i = 0; i < attrs->array->len; ++i) {
+		attr = &g_array_index (attrs->array, GP11Attribute, i);
+		g_assert (!attr->value);
+		if (attr->length != 0 && attr->length != (gulong)-1) {
+			attr->value = (attrs->allocator) (NULL, attr->length);
+			g_assert (attr->value);
+		}
+	}
+	
+	*n_attrs = attrs->array->len;
+	return (CK_ATTRIBUTE_PTR)attrs->array->data;	
+}
+
+CK_ATTRIBUTE_PTR
+_gp11_attributes_commit_out (GP11Attributes *attrs, CK_ULONG_PTR n_attrs)
+{
+	g_assert (attrs);
+	g_assert (n_attrs);
+	g_assert (attrs->locked);
+	
+	*n_attrs = attrs->array->len;
+	return (CK_ATTRIBUTE_PTR)attrs->array->data;
+}

Modified: trunk/gp11/gp11-object.c
==============================================================================
--- trunk/gp11/gp11-object.c	(original)
+++ trunk/gp11/gp11-object.c	Tue Dec 30 02:18:02 2008
@@ -286,28 +286,26 @@
 /**
  * gp11_objects_from_handle_array:
  * @slot: The slot on which these objects are present.
- * @attr: The raw object handles, contained in an attribute.
+ * @handles: The raw object handles.
+ * @n_handles: The number of raw object handles.
  * 
- * Initialize a list of GP11Object from raw PKCS#11 handles contained inside 
- * of an attribute. The attribute must contain contiguous CK_OBJECT_HANDLE
- * handles in an array.
+ * Initialize a list of GP11Object from raw PKCS#11 handles. The handles argument must contain 
+ * contiguous CK_OBJECT_HANDLE handles in an array.
  * 
  * Return value: The list of GP11Object. You should use gp11_list_unref_free() when done with 
  * this list. 
  **/
 GList*
-gp11_objects_from_handle_array (GP11Slot *slot, const GP11Attribute *attr)
+gp11_objects_from_handle_array (GP11Slot *slot, CK_OBJECT_HANDLE_PTR handles, CK_ULONG n_handles)
 {
 	GList *results = NULL;
-	CK_OBJECT_HANDLE *array;
-	guint i, n_array;
+	CK_ULONG i;
 	
 	g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
+	g_return_val_if_fail (handles || !n_handles, NULL);
 	
-	array = (CK_OBJECT_HANDLE*)attr->value;
-	n_array = attr->length / sizeof (CK_OBJECT_HANDLE);
-	for (i = 0; i < n_array; ++i)
-		results = g_list_prepend (results, gp11_object_from_handle (slot, array[i]));
+	for (i = 0; i < n_handles; ++i)
+		results = g_list_prepend (results, gp11_object_from_handle (slot, handles[i]));
 	return g_list_reverse (results);
 }
 
@@ -428,7 +426,9 @@
 	g_static_mutex_unlock (&pv->mutex);
 }
 
-/* DESTROY */
+/* --------------------------------------------------------------------------------------
+ * DESTROY
+ */
 
 typedef struct _Destroy {
 	GP11Arguments base;
@@ -438,6 +438,7 @@
 static CK_RV
 perform_destroy (Destroy *args)
 {
+	g_assert (args);
 	return (args->base.pkcs11->C_DestroyObject) (args->base.handle, args->object);
 }
 
@@ -454,6 +455,8 @@
 gboolean
 gp11_object_destroy (GP11Object *self, GError **err)
 {
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
 	return gp11_object_destroy_full (self, NULL, err);
 }
 
@@ -478,6 +481,7 @@
 	
 	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
 	g_return_val_if_fail (GP11_IS_SLOT (data->slot), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
 	
 	args.object = data->handle;
 
@@ -530,9 +534,15 @@
 gboolean
 gp11_object_destroy_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (GP11_IS_CALL (result), FALSE);
 	return _gp11_call_basic_finish (result, err);
 }
 
+/* --------------------------------------------------------------------------------------
+ * SET ATTRIBUTES
+ */
+
 typedef struct _SetAttributes {
 	GP11Arguments base;
 	GP11Attributes *attrs;
@@ -542,14 +552,20 @@
 static CK_RV
 perform_set_attributes (SetAttributes *args)
 {
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs;
+	
+	g_assert (args);
+	attrs = _gp11_attributes_commit_out (args->attrs, &n_attrs);
+	
 	return (args->base.pkcs11->C_SetAttributeValue) (args->base.handle, args->object, 
-	                                                 _gp11_attributes_raw (args->attrs),
-	                                                 gp11_attributes_count (args->attrs));
+	                                                 attrs, n_attrs);
 }
 
 static void
 free_set_attributes (SetAttributes *args)
 {
+	g_assert (args);
 	gp11_attributes_unref (args->attrs);
 	g_free (args);
 }
@@ -593,8 +609,11 @@
 	va_list va;
 	CK_RV rv;
 	
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
 	va_start (va, err);
-	attrs = gp11_attributes_new_valist (va);
+	attrs = gp11_attributes_new_valist (g_realloc, va);
 	va_end (va);
 	
 	rv = gp11_object_set_full (self, attrs, NULL, err);
@@ -624,6 +643,10 @@
 	gboolean ret = FALSE;
 	
 	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (attrs, FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
+	_gp11_attributes_lock (attrs);
 	
 	memset (&args, 0, sizeof (args));
 	args.attrs = attrs;
@@ -632,6 +655,8 @@
 	session = require_session_sync (self, CKF_RW_SESSION, err);
 	if (session)
 		ret = _gp11_call_sync (session, perform_set_attributes, NULL, &args, cancellable, err);
+	
+	_gp11_attributes_unlock (attrs);
 	g_object_unref (session);
 	return ret;
 }
@@ -656,9 +681,12 @@
 	GP11Call *call;
 	
 	g_return_if_fail (GP11_IS_OBJECT (self));
+	g_return_if_fail (attrs);
 
 	args = _gp11_call_async_prep (data->slot, self, perform_set_attributes, 
 	                              NULL, sizeof (*args), free_set_attributes);
+	
+	_gp11_attributes_lock (attrs);
 	args->attrs = gp11_attributes_ref (attrs);
 	args->object = data->handle;
 	
@@ -680,15 +708,28 @@
 gboolean
 gp11_object_set_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
+	SetAttributes *args;
+	
+	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (GP11_IS_CALL (result), FALSE);
+	g_return_val_if_fail (!err || !*err, FALSE);
+	
+	/* Unlock the attributes we were using */
+	args = _gp11_call_arguments (result, SetAttributes);
+	g_assert (args->attrs);
+	_gp11_attributes_unlock (args->attrs);
+
 	return _gp11_call_basic_finish (result, err);
 }
 
+/* ------------------------------------------------------------------------------------
+ * GET ATTRIBUTES
+ */
+
 typedef struct _GetAttributes {
 	GP11Arguments base;
-	gulong *attr_types;
-	gsize n_attr_types;
 	CK_OBJECT_HANDLE object;
-	GP11Attributes *results;
+	GP11Attributes *attrs;
 } GetAttributes;
 
 /* 
@@ -713,18 +754,14 @@
 perform_get_attributes (GetAttributes *args)
 {
 	CK_ATTRIBUTE_PTR attrs;
-	CK_ULONG i, n_attrs;
+	CK_ULONG n_attrs;
 	CK_RV rv;
 	
-	/* Allocate the CK_ATTRIBUTE's */
-	n_attrs = args->n_attr_types;
-	if (n_attrs) {
-		attrs = g_new0 (CK_ATTRIBUTE, n_attrs);
-		for (i = 0; i < n_attrs; ++i)
-			attrs[i].type = args->attr_types[i];
-	} else {
-		attrs = NULL;
-	}
+	g_assert (args);
+	g_assert (args->attrs);
+	
+	/* Prepare all the attributes */
+	attrs = _gp11_attributes_prepare_in (args->attrs, &n_attrs);
 
 	/* Get the size of each value */
 	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
@@ -735,31 +772,12 @@
 	}
 	
 	/* Allocate memory for each value */
-	for (i = 0; i < n_attrs; ++i) {
-		if (attrs[i].ulValueLen > 0 && attrs[i].ulValueLen != (CK_ULONG)-1)
-			attrs[i].pValue = g_malloc0 (attrs[i].ulValueLen);
-	}
+	attrs = _gp11_attributes_commit_in (args->attrs, &n_attrs);
 	
 	/* Now get the actual values */
 	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
 	                                               attrs, n_attrs);
 	
-	/* Transfer over the memory to the results */
-	if (is_ok_get_attributes_rv (rv)) {
-		g_assert (!args->results);
-		args->results = gp11_attributes_new ();
-		for (i = 0; i < n_attrs; ++i) {
-			_gp11_attributes_add_take (args->results, attrs[i].type,
-			                           attrs[i].pValue, attrs[i].ulValueLen);
-			memset (&attrs[i], 0, sizeof (attrs[0]));
-		}
-	}
-
-	/* Free any memory we didn't use */
-	for (i = 0; i < n_attrs; ++i)
-		g_free (attrs[i].pValue);
-	g_free (attrs);
-	
 	if (is_ok_get_attributes_rv (rv))
 		rv = CKR_OK;
 	
@@ -769,9 +787,10 @@
 static void
 free_get_attributes (GetAttributes *args)
 {
-	g_free (args->attr_types);
-	if (args->results)
-		gp11_attributes_unref (args->results);
+	g_assert (args);
+	g_assert (args->attrs);
+	gp11_attributes_unref (args->attrs);
+	g_free (args);
 }
 
 
@@ -784,107 +803,114 @@
  * Get the specified attributes from the object. This call may
  * block for an indefinite period.
  * 
- * Note that the returned attributes are not required to be 
- * in the order they were requested.
- * 
  * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
+ * The result must be unreffed when you're finished with it.
  **/
 GP11Attributes*
 gp11_object_get (GP11Object *self, GError **err, ...)
 {
-	GP11Attributes *result;
-	GArray *array;
+	GP11Attributes *attrs;
 	va_list va;
 	gulong type;
 	
-	array = g_array_new (0, 1, sizeof (gulong));
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (!err || !*err, NULL);
+
+	attrs = gp11_attributes_new ();
 	va_start (va, err);
 	for (;;) {
 		type = va_arg (va, gulong);
 		if (type == (gulong)-1)
 			break;
-		g_array_append_val (array, type);
+		gp11_attributes_add_invalid (attrs, type);
 	}
 	va_end (va);
 	
-	result = gp11_object_get_full (self, (gulong*)array->data, array->len, NULL, err);
-	g_array_free (array, TRUE);
-	return result;
+	if (!gp11_object_get_full (self, attrs, NULL, err)) {
+		gp11_attributes_unref (attrs);
+		return NULL;
+	}
+
+	return attrs;
 }
 
 /**
  * gp11_object_get:
  * @self: The object to get attributes from.
- * @attr_types: The attributes to get.
- * @n_attr_types: The number of attributes to get.
+ * @attrs: The attributes to get, with the types filled in.
  * @cancellable: Optional cancellation object, or NULL.
  * @err: A location to store an error.
  * 
  * Get the specified attributes from the object. This call may
  * block for an indefinite period.
  * 
- * Note that the returned attributes are not required to be 
- * in the order they were requested.
+ * No extra references are added to the returned attributes pointer. 
+ * During this call you may not access the attributes in any way. 
  * 
- * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
+ * Return value: A pointer to the filled in attributes if successful, 
+ * or NULL if not. 
  **/
 GP11Attributes*
-gp11_object_get_full (GP11Object *self, const gulong *attr_types, gsize n_attr_types,
+gp11_object_get_full (GP11Object *self, GP11Attributes *attrs,
                       GCancellable *cancellable, GError **err)
 {
 	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	GetAttributes args;
 	GP11Session *session;
+	gboolean ret;
 	
-	g_return_val_if_fail (GP11_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (attrs, NULL);
+	g_return_val_if_fail (!err || !*err, NULL);
 	
 	session = require_session_sync (self, 0, err);
 	if (!session)
 		return NULL;
 	
+	_gp11_attributes_lock (attrs);
+	
 	memset (&args, 0, sizeof (args));
-	args.attr_types = (gulong*)attr_types;
-	args.n_attr_types = n_attr_types;
+	args.attrs = attrs;
 	args.object = data->handle;
 
-	if (!_gp11_call_sync (session, perform_get_attributes, NULL, &args, cancellable, err)) {
-		gp11_attributes_unref (args.results);
-		g_object_unref (session);
-		return NULL;
-	}
-	
+	ret = _gp11_call_sync (session, perform_get_attributes, NULL, &args, cancellable, err);
+	_gp11_attributes_unlock (attrs);
 	g_object_unref (session);
-	return args.results;
+	
+	return ret ? attrs : NULL;
 }
 
 /**
  * gp11_object_get_async:
  * @self: The object to get attributes from.
- * @attr_types: The attributes to get.
- * @n_attr_types: The number of attributes to get.
+ * @attrs: The attributes to get, initialized with their types.
  * @cancellable: Optional cancellation object, or NULL.
  * @callback: A callback which is called when the operation completes.
  * @user_data: Data to be passed to the callback.
  * 
- * Get the specified attributes from the object. This call returns
- * immediately and completes asynchronously.
+ * Get the specified attributes from the object. The attributes will be cleared
+ * of their current values, and new attributes will be stored. The attributes
+ * should not be accessed in any way except for referencing and unreferencing 
+ * them until gp11_object_get_finish() is called.
+ * 
+ * This call returns immediately and completes asynchronously.
  **/
 void
-gp11_object_get_async (GP11Object *self, const gulong *attr_types, gsize n_attr_types,
-                       GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+gp11_object_get_async (GP11Object *self, GP11Attributes *attrs, GCancellable *cancellable, 
+                       GAsyncReadyCallback callback, gpointer user_data)
 {
 	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
 	GetAttributes *args;
 	GP11Call *call;
 	
 	g_return_if_fail (GP11_IS_OBJECT (self));
+	g_return_if_fail (attrs);
 
 	args = _gp11_call_async_prep (data->slot, self, perform_get_attributes, 
 	                              NULL, sizeof (*args), free_get_attributes);
 	
-	args->n_attr_types = n_attr_types;
-	if (n_attr_types)
-		args->attr_types = g_memdup (attr_types, sizeof (gulong) * n_attr_types);
+	_gp11_attributes_lock (attrs);
+	args->attrs = gp11_attributes_ref (attrs);
 	args->object = data->handle;
 	
 	call = _gp11_call_async_ready (args, cancellable, callback, user_data);
@@ -900,119 +926,228 @@
  * Get the result of a get operation and return specified attributes from 
  * the object. 
  * 
- * Note that the returned attributes are not required to be 
- * in the order they were requested.
+ * No extra references are added to the returned attributes pointer. 
  * 
- * Return value: The resulting PKCS#11 attributes, or NULL if an error occurred. 
+ * Return value: The filled in attributes structure if successful or 
+ * NULL if not successful.
  **/
 GP11Attributes*
 gp11_object_get_finish (GP11Object *self, GAsyncResult *result, GError **err)
 {
-	GP11Attributes *results;
 	GetAttributes *args;
 	
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (GP11_IS_CALL (result), NULL);
+	g_return_val_if_fail (!err || !*err, NULL);
+
+	args = _gp11_call_arguments (result, GetAttributes);
+	_gp11_attributes_unlock (args->attrs);
+
 	if (!_gp11_call_basic_finish (result, err))
 		return NULL;
 	
-	args = _gp11_call_arguments (result, GetAttributes);
+	return args->attrs;
+}
+
+/* ---------------------------------------------------------------------------------
+ * GET ATTRIBUTE DATA
+ */
+
+typedef struct _GetAttributeData {
+	GP11Arguments base;
+	CK_OBJECT_HANDLE object;
+	CK_ATTRIBUTE_TYPE type;
+	GP11Allocator allocator;
+	guchar *result;
+	gsize n_result;
+} GetAttributeData;
+
+static CK_RV
+perform_get_attribute_data (GetAttributeData *args)
+{
+	CK_ATTRIBUTE attr;
+	CK_RV rv;
+	
+	g_assert (args);
+	g_assert (args->allocator);
+	
+	attr.type = args->type;
+	attr.ulValueLen = 0;
+	attr.pValue = 0;
+	
+	/* Get the size of the value */
+	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
+	                                               &attr, 1);
+	if (rv != CKR_OK) 
+		return rv;
 	
-	results = args->results;
-	args->results = NULL;
+	/* Allocate memory for the value */
+	args->result = (args->allocator) (NULL, attr.ulValueLen);
+	g_assert (args->result);
+	attr.pValue = args->result;
 	
-	return results;
+	/* Now get the actual value */
+	rv = (args->base.pkcs11->C_GetAttributeValue) (args->base.handle, args->object,
+	                                               &attr, 1);
+
+	if (rv == CKR_OK)
+		args->n_result = attr.ulValueLen;
+	
+	return rv;
+}
+
+static void
+free_get_attribute_data (GetAttributeData *args)
+{
+	g_assert (args);
+	g_free (args->result);
+	g_free (args);
 }
 
 /**
- * gp11_object_get_one:
- * @self: The object to get an attribute from.
- * @attr_type: The attribute to get.
+ * gp11_object_get_data:
+ * @self: The object to get attribute data from.
+ * @attr_type: The attribute to get data for.
+ * @n_data: The length of the resulting data.
  * @err: A location to store an error.
  * 
- * Get the specified attribute from the object. This call may
- * block for an indefinite period.
+ * Get the data for the specified attribute from the object. This call 
+ * may block for an indefinite period.
  * 
- * Return value: The resulting PKCS#11 attribute, or NULL if an error occurred. 
+ * Return value: The resulting PKCS#11 attribute data, or NULL if an error occurred. 
  **/
-GP11Attribute*
-gp11_object_get_one (GP11Object *self, gulong attr_type, GError **err)
+gpointer
+gp11_object_get_data (GP11Object *self, gulong attr_type, gsize *n_data, GError **err)
 {
-	return gp11_object_get_one_full (self, attr_type, NULL, err);
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (n_data, NULL);
+	g_return_val_if_fail (!err || !*err, NULL);
+	
+	return gp11_object_get_data_full (self, attr_type, g_realloc, NULL, n_data, err);
 }
 
 /**
- * gp11_object_get_one_full:
- * @self: The object to get an attribute from.
- * @attr_type: The attribute to get.
+ * gp11_object_get_data_full:
+ * @self: The object to get attribute data from.
+ * @attr_type: The attribute to get data for.
+ * @allocator: An allocator with which to allocate memory for the data, or NULL for default.
  * @cancellable: Optional cancellation object, or NULL.
+ * @n_data: The length of the resulting data.
  * @err: A location to store an error.
  * 
- * Get the specified attribute from the object. This call may
- * block for an indefinite period.
+ * Get the data for the specified attribute from the object. This call 
+ * may block for an indefinite period.
  * 
- * Return value: The resulting PKCS#11 attribute, or NULL if an error occurred. 
+ * Return value: The resulting PKCS#11 attribute data, or NULL if an error occurred. 
  **/
-GP11Attribute*
-gp11_object_get_one_full (GP11Object *self, gulong attr_type, 
-                          GCancellable *cancellable, GError **err)
+gpointer
+gp11_object_get_data_full (GP11Object *self, gulong attr_type, GP11Allocator allocator,
+                           GCancellable *cancellable, gsize *n_data, GError **err)
 {
-	GP11Attributes *attrs;
-	GP11Attribute *attr;
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	GetAttributeData args;
+	GP11Session *session;
+	gboolean ret;
+	
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (n_data, NULL);
+	g_return_val_if_fail (!err || !*err, NULL);
+	
+	if (!allocator)
+		allocator = g_realloc;
+	
+	session = require_session_sync (self, 0, err);
+	if (!session)
+		return NULL;
+	
+	memset (&args, 0, sizeof (args));
+	args.allocator = allocator;
+	args.object = data->handle;
+	args.type = attr_type;
+
+	ret = _gp11_call_sync (session, perform_get_attribute_data, NULL, &args, cancellable, err);
+	g_object_unref (session);
 	
-	attrs = gp11_object_get_full (self, &attr_type, 1, cancellable, err);
-	if (!attrs || !gp11_attributes_count (attrs))
+	/* Free any value if failed */
+	if (!ret) {
+		if (args.result)
+			(allocator) (args.result, 0);
 		return NULL;
+	}
 	
-	attr = gp11_attributes_at (attrs, 0);
-	g_return_val_if_fail (attr, NULL);
-	attr = gp11_attribute_dup (attr);
-	gp11_attributes_unref (attrs);
-	return attr;
+	*n_data = args.n_result;
+	return args.result;
 }
 
 /**
- * gp11_object_get_one_async:
- * @self: The object to get an attribute from.
- * @attr_type: The attribute to get.
+ * gp11_object_get_data_async:
+ * @self: The object to get attribute data from.
+ * @attr_type: The attribute to get data for.
+ * @allocator: An allocator with which to allocate memory for the data, or NULL for default.
  * @cancellable: Optional cancellation object, or NULL.
  * @callback: Called when the operation completes.
  * @user_data: Data to be passed to the callback.
  * 
- * Get the specified attribute from the object. This call will
+ * Get the data for the specified attribute from the object. This call will
  * return immediately and complete asynchronously.
  **/
 void
-gp11_object_get_one_async (GP11Object *self, gulong attr_type, GCancellable *cancellable,
-                           GAsyncReadyCallback callback, gpointer user_data)
+gp11_object_get_data_async (GP11Object *self, gulong attr_type, GP11Allocator allocator, 
+                            GCancellable *cancellable, GAsyncReadyCallback callback, 
+                            gpointer user_data)
 {
-	gp11_object_get_async (self, &attr_type, 1, cancellable, callback, user_data);
+	GP11ObjectData *data = GP11_OBJECT_GET_DATA (self);
+	GetAttributeData *args;
+	GP11Call *call;
+	
+	g_return_if_fail (GP11_IS_OBJECT (self));
+	
+	if (!allocator)
+		allocator = g_realloc;
+
+	args = _gp11_call_async_prep (data->slot, self, perform_get_attribute_data, 
+	                              NULL, sizeof (*args), free_get_attribute_data);
+
+	args->allocator = allocator;
+	args->object = data->handle;
+	args->type = attr_type;
+	
+	call = _gp11_call_async_ready (args, cancellable, callback, user_data);
+	require_session_async (self, call, 0, cancellable);
 }
 
 /**
- * gp11_object_get_one_finish:
+ * gp11_object_get_data_finish:
  * @self: The object to get an attribute from.
  * @result: The result passed to the callback.
+ * @n_data: The length of the resulting data.
  * @err: A location to store an error.
  *
- * Get the result of an operation to get an attribute from 
+ * Get the result of an operation to get attribute data from 
  * an object. 
  * 
- * Return value: The PKCS#11 attribute or NULL if an error occurred.
+ * Return value: The PKCS#11 attribute data or NULL if an error occurred.
  **/
-
-GP11Attribute*
-gp11_object_get_one_finish (GP11Object *self, GAsyncResult *result, GError **err)
+gpointer
+gp11_object_get_data_finish (GP11Object *self, GAsyncResult *result, 
+                             gsize *n_data, GError **err)
 {
-	GP11Attributes *attrs;
-	GP11Attribute *attr;
+	GetAttributeData *args;
+	guchar *data;
 	
-	attrs = gp11_object_get_finish (self, result, err);
-	if (!attrs)
+	g_return_val_if_fail (GP11_IS_OBJECT (self), NULL);
+	g_return_val_if_fail (GP11_IS_CALL (result), NULL);
+	g_return_val_if_fail (n_data, NULL);
+	g_return_val_if_fail (!err || !*err, NULL);
+	
+	if (!_gp11_call_basic_finish (result, err))
 		return NULL;
+
+	args = _gp11_call_arguments (result, GetAttributeData);
+
+	*n_data = args->n_result;
+	data = args->result;
+	args->result = NULL;
 	
-	attr = gp11_attributes_at (attrs, 0);
-	g_return_val_if_fail (attr, NULL);
-	attr = gp11_attribute_dup (attr);
-	gp11_attributes_unref (attrs);
-	return attr;
+	return data;
 }
-

Modified: trunk/gp11/gp11-private.h
==============================================================================
--- trunk/gp11/gp11-private.h	(original)
+++ trunk/gp11/gp11-private.h	Tue Dec 30 02:18:02 2008
@@ -36,17 +36,18 @@
  * ATTRIBUTE INTERNALS
  */
 
-void                _gp11_attribute_init_take               (GP11Attribute *attr, 
-                                                             gulong attr_type,
-                                                             gpointer value,
-                                                             gsize length);
-
-void                _gp11_attributes_add_take               (GP11Attributes *attr, 
-                                                             gulong attr_type,
-                                                             gpointer value,
-                                                             gsize length);
+void                _gp11_attributes_lock                   (GP11Attributes *attrs);
 
-CK_ATTRIBUTE_PTR    _gp11_attributes_raw                    (GP11Attributes *attrs);
+void                _gp11_attributes_unlock                 (GP11Attributes *attrs);
+
+CK_ATTRIBUTE_PTR    _gp11_attributes_prepare_in             (GP11Attributes *attrs, 
+                                                             CK_ULONG_PTR n_attrs);
+
+CK_ATTRIBUTE_PTR    _gp11_attributes_commit_in              (GP11Attributes *attrs, 
+                                                             CK_ULONG_PTR n_attrs);
+
+CK_ATTRIBUTE_PTR    _gp11_attributes_commit_out             (GP11Attributes *attrs, 
+                                                             CK_ULONG_PTR n_attrs);
 
 /* ----------------------------------------------------------------------------
  * SLOT

Modified: trunk/gp11/gp11-session.c
==============================================================================
--- trunk/gp11/gp11-session.c	(original)
+++ trunk/gp11/gp11-session.c	Tue Dec 30 02:18:02 2008
@@ -618,9 +618,13 @@
 static CK_RV
 perform_create_object (CreateObject *args)
 {
-	return (args->base.pkcs11->C_CreateObject) (args->base.handle, 
-	                                            _gp11_attributes_raw (args->attrs),
-	                                            gp11_attributes_count (args->attrs),
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs;
+	
+	attrs = _gp11_attributes_commit_out (args->attrs, &n_attrs);
+	
+	return (args->base.pkcs11->C_CreateObject) (args->base.handle,
+	                                            attrs, n_attrs, 
 	                                            &args->object);
 }
 
@@ -665,7 +669,7 @@
 	va_list va;
 	
 	va_start (va, err);
-	attrs = gp11_attributes_new_valist (va);
+	attrs = gp11_attributes_new_valist (g_realloc, va);
 	va_end (va);
 	
 	object = gp11_session_create_object_full (self, attrs, NULL, err);
@@ -691,8 +695,18 @@
 {
 	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
 	CreateObject args = { GP11_ARGUMENTS_INIT, attrs, 0 };
-	if (!_gp11_call_sync (self, perform_create_object, NULL, &args, cancellable, err))
+	gboolean ret;
+	
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+	g_return_val_if_fail (attrs, NULL);
+	
+	_gp11_attributes_lock (attrs);
+	ret = _gp11_call_sync (self, perform_create_object, NULL, &args, cancellable, err);
+	_gp11_attributes_unlock (attrs);
+	
+	if (!ret)
 		return NULL;
+	
 	return gp11_object_from_handle (data->slot, args.object);
 }
 
@@ -714,8 +728,12 @@
 {
 	CreateObject *args = _gp11_call_async_prep (self, self, perform_create_object, 
 	                                            NULL, sizeof (*args), free_create_object);
-	args->attrs = attrs;
-	gp11_attributes_ref (attrs);
+	
+	g_return_if_fail (attrs);
+	
+	args->attrs = gp11_attributes_ref (attrs);
+	_gp11_attributes_lock (attrs);
+
 	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
 }
 
@@ -734,10 +752,12 @@
 {
 	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
 	CreateObject *args;
-	
+
+	args = _gp11_call_arguments (result, CreateObject);
+	_gp11_attributes_unlock (args->attrs); 
+
 	if (!_gp11_call_basic_finish (result, err))
 		return NULL;
-	args = _gp11_call_arguments (result, CreateObject);
 	return gp11_object_from_handle (data->slot, args->object);
 }
 
@@ -764,12 +784,15 @@
 {
 	CK_OBJECT_HANDLE_PTR batch;
 	CK_ULONG n_batch, n_found;
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs;
 	GArray *array;
 	CK_RV rv;
 	
+	attrs = _gp11_attributes_commit_out (args->attrs, &n_attrs);
+	
 	rv = (args->base.pkcs11->C_FindObjectsInit) (args->base.handle, 
-	                                             _gp11_attributes_raw (args->attrs),
-	                                             gp11_attributes_count (args->attrs));
+	                                             attrs, n_attrs);
 	if (rv != CKR_OK)
 		return rv;
 	
@@ -868,7 +891,7 @@
 	va_list va;
 	
 	va_start (va, err);
-	attrs = gp11_attributes_new_valist (va);
+	attrs = gp11_attributes_new_valist (g_realloc, va);
 	va_end (va);
 
 	results = gp11_session_find_objects_full (self, attrs, NULL, err);
@@ -895,9 +918,14 @@
 	FindObjects args = { GP11_ARGUMENTS_INIT, attrs, NULL, 0 };
 	GList *results = NULL;
 	
+	g_return_val_if_fail (attrs, NULL);
+	_gp11_attributes_lock (attrs);
+	
 	if (_gp11_call_sync (self, perform_find_objects, NULL, &args, cancellable, err)) 
 		results = objlist_from_handles (self, args.objects, args.n_objects);
+	
 	g_free (args.objects);
+	_gp11_attributes_unlock (attrs);
 	return results;
 }
 
@@ -919,8 +947,8 @@
 {
 	FindObjects *args = _gp11_call_async_prep (self, self, perform_find_objects, 
 	                                           NULL, sizeof (*args), free_find_objects);
-	args->attrs = attrs;
-	gp11_attributes_ref (attrs);
+	args->attrs = gp11_attributes_ref (attrs);
+	_gp11_attributes_lock (attrs);
 	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
 }
 
@@ -938,10 +966,12 @@
 gp11_session_find_objects_finish (GP11Session *self, GAsyncResult *result, GError **err)
 {
 	FindObjects *args;
-	
+
+	args = _gp11_call_arguments (result, FindObjects);
+	_gp11_attributes_unlock (args->attrs);
+
 	if (!_gp11_call_basic_finish (result, err))
 		return NULL;
-	args = _gp11_call_arguments (result, FindObjects);
 	return objlist_from_handles (self, args->objects, args->n_objects);
 }
 

Modified: trunk/gp11/gp11.h
==============================================================================
--- trunk/gp11/gp11.h	(original)
+++ trunk/gp11/gp11.h	Tue Dec 30 02:18:02 2008
@@ -47,6 +47,8 @@
 
 gchar*              gp11_string_from_chars                  (const guchar *data, gsize max);
 
+typedef gpointer    (*GP11Allocator)                        (gpointer data, gsize length);
+
 typedef struct GP11Mechanism {
 	gulong type;
 	gpointer parameter;
@@ -80,6 +82,9 @@
 void                gp11_attribute_init_invalid             (GP11Attribute *attr,
                                                              gulong attr_type);
 
+void                gp11_attribute_init_empty               (GP11Attribute *attr,
+                                                             gulong attr_type);
+
 void                gp11_attribute_init_boolean             (GP11Attribute *attr,
                                                              gulong attr_type,
                                                              gboolean value);
@@ -97,7 +102,7 @@
                                                              const gchar *value);
 
 void                gp11_attribute_init_copy                (GP11Attribute *dest, 
-                                                             GP11Attribute *src);
+                                                             const GP11Attribute *src);
 
 GP11Attribute*      gp11_attribute_new                      (gulong attr_type,
                                                              gpointer value,
@@ -105,6 +110,8 @@
 
 GP11Attribute*      gp11_attribute_new_invalid              (gulong attr_type);
 
+GP11Attribute*      gp11_attribute_new_empty                (gulong attr_type);
+
 GP11Attribute*      gp11_attribute_new_boolean              (gulong attr_type,
                                                              gboolean value);
 
@@ -143,13 +150,13 @@
  
 GP11Attributes*     gp11_attributes_new                     (void);
 
-GP11Attributes*     gp11_attributes_newv                    (gulong attr_type, ...);
+GP11Attributes*     gp11_attributes_new_empty               (gulong attr_type, ...);
 
-GP11Attributes*     gp11_attributes_new_valist              (va_list va);
+GP11Attributes*     gp11_attributes_new_full                (GP11Allocator allocator);
 
-void                gp11_attributes_set_immutable           (GP11Attributes *attrs);
+GP11Attributes*     gp11_attributes_newv                    (gulong attr_type, ...);
 
-gboolean            gp11_attributes_is_immutable            (GP11Attributes *attrs);
+GP11Attributes*     gp11_attributes_new_valist              (GP11Allocator allocator, va_list va);
 
 GP11Attribute*      gp11_attributes_at                      (GP11Attributes *attrs,
                                                              guint index);
@@ -165,6 +172,9 @@
 void                gp11_attributes_add_invalid             (GP11Attributes *attrs,
                                                              gulong attr_type);
 
+void                gp11_attributes_add_empty               (GP11Attributes *attrs,
+                                                             gulong attr_type);
+
 void                gp11_attributes_add_boolean             (GP11Attributes *attrs,
                                                              gulong attr_type,
                                                              gboolean value);
@@ -1201,7 +1211,8 @@
                                                              CK_OBJECT_HANDLE handle);
 
 GList*              gp11_objects_from_handle_array          (GP11Slot *slot,
-                                                             const GP11Attribute *attr);
+                                                             CK_OBJECT_HANDLE_PTR handles,
+                                                             CK_ULONG n_handles);
 
 GP11Module*         gp11_object_get_module                  (GP11Object *self);
 
@@ -1295,14 +1306,12 @@
                                                              ...);
 
 GP11Attributes*     gp11_object_get_full                    (GP11Object *self,
-                                                             const gulong *attr_types,
-                                                             gsize n_attr_types,
+                                                             GP11Attributes *attrs,
                                                              GCancellable *cancellable,
                                                              GError **err);
 
 void                gp11_object_get_async                   (GP11Object *self,
-                                                             const gulong *attr_types,
-                                                             gsize n_attr_types,
+                                                             GP11Attributes *attrs,
                                                              GCancellable *cancellable,
                                                              GAsyncReadyCallback callback,
                                                              gpointer user_data);
@@ -1311,23 +1320,28 @@
                                                              GAsyncResult *result,
                                                              GError **err);
 
-GP11Attribute*      gp11_object_get_one                     (GP11Object *self,
+gpointer            gp11_object_get_data                    (GP11Object *self,
                                                              gulong attr_type,
+                                                             gsize *n_data,
                                                              GError **err);
 
-GP11Attribute*      gp11_object_get_one_full                (GP11Object *self,
+gpointer            gp11_object_get_data_full               (GP11Object *self,
                                                              gulong attr_type,
+                                                             GP11Allocator allocator,
                                                              GCancellable *cancellable,
+                                                             gsize *n_data,
                                                              GError **err);
 
-void                gp11_object_get_one_async               (GP11Object *self,
+void                gp11_object_get_data_async              (GP11Object *self,
                                                              gulong attr_type,
+                                                             GP11Allocator allocator,
                                                              GCancellable *cancellable,
                                                              GAsyncReadyCallback callback,
                                                              gpointer user_data);
 
-GP11Attribute*      gp11_object_get_one_finish              (GP11Object *self,
+gpointer            gp11_object_get_data_finish             (GP11Object *self,
                                                              GAsyncResult *result,
+                                                             gsize *n_data,
                                                              GError **err);
 
 

Modified: trunk/gp11/tests/Makefile.am
==============================================================================
--- trunk/gp11/tests/Makefile.am	(original)
+++ trunk/gp11/tests/Makefile.am	Tue Dec 30 02:18:02 2008
@@ -1,10 +1,12 @@
+
+# Keep these in the order they should be tested
 UNIT_AUTO = \
 	unit-test-gp11-attributes.c \
-	unit-test-gp11-crypto.c \
 	unit-test-gp11-module.c \
-	unit-test-gp11-object.c \
+	unit-test-gp11-slot.c \
 	unit-test-gp11-session.c \
-	unit-test-gp11-slot.c 
+	unit-test-gp11-object.c \
+	unit-test-gp11-crypto.c
 
 UNIT_FLAGS = \
 	-I$(top_srcdir)/gp11/ \

Modified: trunk/gp11/tests/unit-test-gp11-attributes.c
==============================================================================
--- trunk/gp11/tests/unit-test-gp11-attributes.c	(original)
+++ trunk/gp11/tests/unit-test-gp11-attributes.c	Tue Dec 30 02:18:02 2008
@@ -77,6 +77,31 @@
 
 	gp11_attribute_clear (&attr);
 }
+
+DEFINE_TEST(init_invalid)
+{
+	GP11Attribute attr;
+	
+	gp11_attribute_init_invalid (&attr, ATTR_TYPE);
+	g_assert (attr.type == ATTR_TYPE);
+	g_assert (attr.length == (gulong)-1);
+	g_assert (attr.value == NULL);
+
+	g_assert (gp11_attribute_is_invalid (&attr));
+	gp11_attribute_clear (&attr);
+}
+
+DEFINE_TEST(init_empty)
+{
+	GP11Attribute attr;
+	
+	gp11_attribute_init_empty (&attr, ATTR_TYPE);
+	g_assert (attr.type == ATTR_TYPE);
+	g_assert (attr.length == 0);
+	g_assert (attr.value == NULL);
+
+	gp11_attribute_clear (&attr);
+}
 	
 DEFINE_TEST(new_memory)
 {
@@ -145,6 +170,32 @@
 	gp11_attribute_free (attr);
 }
 
+DEFINE_TEST(new_invalid)
+{
+	GP11Attribute *attr;
+	
+	attr = gp11_attribute_new_invalid (ATTR_TYPE);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == (gulong)-1);
+	g_assert (attr->value == NULL);
+
+	g_assert (gp11_attribute_is_invalid (attr));
+	
+	gp11_attribute_free (attr);
+}
+
+DEFINE_TEST(new_empty)
+{
+	GP11Attribute *attr;
+	
+	attr = gp11_attribute_new_empty (ATTR_TYPE);
+	g_assert (attr->type == ATTR_TYPE);
+	g_assert (attr->length == 0);
+	g_assert (attr->value == NULL);
+
+	gp11_attribute_free (attr);
+}
+
 DEFINE_TEST(get_boolean)
 {
 	GP11Attribute *attr;
@@ -243,14 +294,16 @@
 }
 
 static void
-test_attributes_contents (GP11Attributes *attrs)
+test_attributes_contents (GP11Attributes *attrs, gboolean extras)
 {
 	GP11Attribute *attr;
 	gchar *value;
 	GDate date, *check;
+	guint count;
 	
 	g_assert (attrs != NULL);
-	g_assert (gp11_attributes_count (attrs) == 5);
+	count = extras ? 7 : 5;
+	g_assert_cmpuint (gp11_attributes_count (attrs), ==, count);
 	
 	attr = gp11_attributes_at (attrs, 0);
 	g_assert (attr->type == 0);
@@ -277,6 +330,20 @@
 	g_assert (attr->type == 404);
 	g_assert (attr->length == N_ATTR_DATA);
 	g_assert (memcmp (attr->value, ATTR_DATA, N_ATTR_DATA) == 0);
+	
+	if (!extras)
+		return;
+	
+	attr = gp11_attributes_at (attrs, 5);
+	g_assert (attr->type == 505);
+	g_assert (attr->length == (gulong)-1);
+	g_assert (attr->value == NULL);
+	g_assert (gp11_attribute_is_invalid (attr));
+
+	attr = gp11_attributes_at (attrs, 6);
+	g_assert (attr->type == 606);
+	g_assert (attr->length == 0);
+	g_assert (attr->value == NULL);
 }
 
 DEFINE_TEST(newv_attributes)
@@ -291,7 +358,7 @@
 	                              -1);
 	g_date_free (date);
 
-	test_attributes_contents (attrs);
+	test_attributes_contents (attrs, FALSE);
 	gp11_attributes_unref (attrs);
 	
 	/* An empty one */
@@ -299,6 +366,21 @@
 	gp11_attributes_unref (attrs);
 }
 
+DEFINE_TEST(new_empty_attributes)
+{
+	GP11Attributes *attrs = gp11_attributes_new_empty (101, 202, 303, 404, -1);
+	GP11Attribute *attr;
+	guint i;
+	
+	g_assert_cmpuint (gp11_attributes_count (attrs), ==, 4);
+	for (i = 0; i < gp11_attributes_count (attrs); ++i) {
+		attr = gp11_attributes_at (attrs, i);
+		g_assert (attr->type == ((i + 1) * 100) + i + 1);
+		g_assert (attr->value == NULL);
+		g_assert (attr->length == 0);
+	}
+}
+
 static GP11Attributes*
 help_attributes_valist (int dummy, ...)
 {
@@ -306,7 +388,7 @@
 	va_list va;
 	
 	va_start (va, dummy);
-	attrs = gp11_attributes_new_valist (va);
+	attrs = gp11_attributes_new_valist (NULL, va);
 	va_end (va);
 	
 	return attrs;
@@ -326,7 +408,7 @@
 	                                -1);
 	
 	g_date_free (date);
-	test_attributes_contents (attrs);
+	test_attributes_contents (attrs, FALSE);
 	gp11_attributes_unref (attrs);	
 }
 
@@ -354,7 +436,9 @@
 	gp11_attributes_add_date (attrs, 303, date);
 	g_date_free (date);
 	gp11_attributes_add_data (attrs, 404, ATTR_DATA, N_ATTR_DATA);
-	test_attributes_contents (attrs);
+	gp11_attributes_add_invalid (attrs, 505);
+	gp11_attributes_add_empty (attrs, 606);
+	test_attributes_contents (attrs, TRUE);
 	gp11_attributes_unref (attrs);
 }
 
@@ -387,7 +471,15 @@
 	gp11_attributes_add (attrs, &attr);
 	gp11_attribute_clear (&attr);
 	
-	test_attributes_contents (attrs);
+	gp11_attribute_init_invalid (&attr, 505);
+	gp11_attributes_add (attrs, &attr);
+	gp11_attribute_clear (&attr);
+
+	gp11_attribute_init_empty (&attr, 606);
+	gp11_attributes_add (attrs, &attr);
+	gp11_attribute_clear (&attr);
+
+	test_attributes_contents (attrs, TRUE);
 	gp11_attributes_unref (attrs);
 }
 

Modified: trunk/gp11/tests/unit-test-gp11-crypto.c
==============================================================================
--- trunk/gp11/tests/unit-test-gp11-crypto.c	(original)
+++ trunk/gp11/tests/unit-test-gp11-crypto.c	Tue Dec 30 02:18:02 2008
@@ -51,18 +51,20 @@
 {
 	GList *objects, *l;
 	GP11Object *object = NULL;
-	GP11Attribute *attr;
+	CK_MECHANISM_TYPE_PTR mechs;
+	gsize n_mechs;
 	
 	objects = gp11_session_find_objects (session, NULL, method, GP11_BOOLEAN, TRUE, GP11_INVALID);
 	g_assert (objects);
 	
 	for (l = objects; l; l = g_list_next (l)) {
 		gp11_object_set_session (l->data, session);
-		attr = gp11_object_get_one (l->data, CKA_ALLOWED_MECHANISMS, NULL);
-		g_assert (attr);
+		mechs = gp11_object_get_data (l->data, CKA_ALLOWED_MECHANISMS, &n_mechs, NULL);
+		g_assert (mechs);
+		g_assert (n_mechs == sizeof (CK_MECHANISM_TYPE));
 		
 		/* We know all of them only have one allowed mech */
-		if (gp11_attribute_get_ulong (attr) == mech) {
+		if (*mechs == mech) {
 			object = l->data;
 			g_object_ref (object);
 			break;

Modified: trunk/gp11/tests/unit-test-gp11-object.c
==============================================================================
--- trunk/gp11/tests/unit-test-gp11-object.c	(original)
+++ trunk/gp11/tests/unit-test-gp11-object.c	Tue Dec 30 02:18:02 2008
@@ -185,11 +185,10 @@
 DEFINE_TEST(get_attributes)
 {
 	GAsyncResult *result = NULL;
-	GP11Attributes *attrs;
+	GP11Attributes *attrs, *attrs_ret;
 	GError *err = NULL;
 	gulong klass;
 	gchar *value = NULL;
-	gulong types[2] = { CKA_CLASS, CKA_LABEL };
 	
 	/* Simple */
 	attrs = gp11_object_get (object, &err, CKA_CLASS, CKA_LABEL, -1);
@@ -198,69 +197,78 @@
 		g_assert (gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass) && klass == CKO_DATA);
 		g_assert (gp11_attributes_find_string (attrs, CKA_LABEL, &value) && strcmp (value, "TEST LABEL") == 0);
 		g_free (value); value = NULL;
-		gp11_attributes_unref (attrs);
 	}
+	gp11_attributes_unref (attrs);
 
 	/* Full */
-	attrs = gp11_object_get_full (object, types, 2, NULL, &err);
-	SUCCESS_RES (attrs, err);
-	if (attrs != NULL) {
+	attrs = gp11_attributes_new_empty (CKA_CLASS, CKA_LABEL, -1);
+	attrs_ret = gp11_object_get_full (object, attrs, NULL, &err);
+	SUCCESS_RES (attrs_ret, err);
+	if (attrs_ret != NULL) {
+		g_assert (attrs_ret == attrs);
 		g_assert (gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass) && klass == CKO_DATA);
 		g_assert (gp11_attributes_find_string (attrs, CKA_LABEL, &value) && strcmp (value, "TEST LABEL") == 0);
 		g_free (value); value = NULL;
-		gp11_attributes_unref (attrs);
 	}
+	gp11_attributes_unref (attrs);
 
 	/* Async */
-	gp11_object_get_async (object, types, 2, NULL, fetch_async_result, &result);
+	attrs = gp11_attributes_new_empty (CKA_CLASS, CKA_LABEL, -1);
+	gp11_object_get_async (object, attrs, NULL, fetch_async_result, &result);
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
 
-	attrs = gp11_object_get_finish (object, result, &err);
+	attrs_ret = gp11_object_get_finish (object, result, &err);
 	g_object_unref (result);
 	SUCCESS_RES (attrs, err);
 	if (attrs != NULL) {
+		g_assert (attrs_ret == attrs);
 		g_assert (gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass) && klass == CKO_DATA);
 		g_assert (gp11_attributes_find_string (attrs, CKA_LABEL, &value) && strcmp (value, "TEST LABEL") == 0);
 		g_free (value); value = NULL;
-		gp11_attributes_unref (attrs);
 	}
+	gp11_attributes_unref (attrs);
 }
 
-DEFINE_TEST(get_one_attribute)
+DEFINE_TEST(get_data_attribute)
 {
 	GAsyncResult *result = NULL;
-	GP11Attribute *attr;
+	CK_OBJECT_CLASS_PTR klass;
+	gsize n_data;
 	GError *err = NULL;
 	
 	/* Simple */
-	attr = gp11_object_get_one (object, CKA_CLASS, &err);
-	SUCCESS_RES (attr, err);
-	if (attr != NULL) {
-		g_assert (attr->type == CKA_CLASS && gp11_attribute_get_ulong (attr) == CKO_DATA);
-		gp11_attribute_free (attr);
+	klass = gp11_object_get_data (object, CKA_CLASS, &n_data, &err);
+	SUCCESS_RES (klass, err);
+	if (klass != NULL) {
+		g_assert (n_data == sizeof (CK_OBJECT_CLASS));
+		g_assert (*klass == CKO_DATA);
+		g_free (klass);
 	}
 
 	/* Full */
-	attr = gp11_object_get_one_full (object, CKA_CLASS, NULL, &err);
-	SUCCESS_RES (attr, err);
-	if (attr != NULL) {
-		g_assert (attr->type == CKA_CLASS && gp11_attribute_get_ulong (attr) == CKO_DATA);
-		gp11_attribute_free (attr);
+	klass = gp11_object_get_data_full (object, CKA_CLASS, NULL, NULL, &n_data, &err);
+	SUCCESS_RES (klass, err);
+	if (klass != NULL) {
+		g_assert (n_data == sizeof (CK_OBJECT_CLASS));
+		g_assert (*klass == CKO_DATA);
+		g_free (klass);
 	}
 
 	/* Async */
-	gp11_object_get_one_async (object, CKA_CLASS, NULL, fetch_async_result, &result);
+	gp11_object_get_data_async (object, CKA_CLASS, NULL, NULL, fetch_async_result, &result);
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
 
-	attr = gp11_object_get_one_finish (object, result, &err);
+	klass = gp11_object_get_data_finish (object, result, &n_data, &err);
 	g_object_unref (result);
-	SUCCESS_RES (attr, err);
-	if (attr != NULL) {
-		g_assert (attr->type == CKA_CLASS && gp11_attribute_get_ulong (attr) == CKO_DATA);
-		gp11_attribute_free (attr);
+	SUCCESS_RES (klass, err);
+	if (klass != NULL) {
+		g_assert (n_data == sizeof (CK_OBJECT_CLASS));
+		g_assert (*klass == CKO_DATA);
+		g_free (klass);
 	}
+
 }
 
 DEFINE_TEST(set_attributes)
@@ -372,11 +380,9 @@
 {
 	GP11Session *sess;
 	GAsyncResult *result = NULL;
-	GP11Attributes *attrs;
+	CK_OBJECT_CLASS_PTR klass;
 	GError *err = NULL;
-	gulong klass;
-	gchar *value = NULL;
-	gulong types[2] = { CKA_CLASS, CKA_LABEL };
+	gsize n_data;
 
 	/* Set an explicit session */
 	gp11_object_set_session (object, session);
@@ -388,28 +394,26 @@
 	g_object_unref (sess);
 	
 	/* Simple */
-	attrs = gp11_object_get (object, &err, CKA_CLASS, CKA_LABEL, -1);
-	SUCCESS_RES (attrs, err);
-	if (attrs != NULL) {
-		g_assert (gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass) && klass == CKO_DATA);
-		g_assert (gp11_attributes_find_string (attrs, CKA_LABEL, &value) && strcmp (value, "TEST LABEL") == 0);
-		g_free (value); value = NULL;
-		gp11_attributes_unref (attrs);
+	klass = gp11_object_get_data (object, CKA_CLASS, &n_data, &err);
+	SUCCESS_RES (klass, err);
+	if (klass != NULL) {
+		g_assert (n_data == sizeof (CK_OBJECT_CLASS));
+		g_assert (*klass == CKO_DATA);
+		g_free (klass);
 	}
 
 	/* Async */
-	gp11_object_get_async (object, types, 2, NULL, fetch_async_result, &result);
+	gp11_object_get_data_async (object, CKA_CLASS, NULL, NULL, fetch_async_result, &result);
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
 
-	attrs = gp11_object_get_finish (object, result, &err);
+	klass = gp11_object_get_data_finish (object, result, &n_data, &err);
 	g_object_unref (result);
-	SUCCESS_RES (attrs, err);
-	if (attrs != NULL) {
-		g_assert (gp11_attributes_find_ulong (attrs, CKA_CLASS, &klass) && klass == CKO_DATA);
-		g_assert (gp11_attributes_find_string (attrs, CKA_LABEL, &value) && strcmp (value, "TEST LABEL") == 0);
-		g_free (value); value = NULL;
-		gp11_attributes_unref (attrs);
+	SUCCESS_RES (klass, err);
+	if (klass != NULL) {
+		g_assert (n_data == sizeof (CK_OBJECT_CLASS));
+		g_assert (*klass == CKO_DATA);
+		g_free (klass);
 	}
 
 	/* Set it to null and make sure taht works */

Modified: trunk/tool/gkr-tool-import.c
==============================================================================
--- trunk/tool/gkr-tool-import.c	(original)
+++ trunk/tool/gkr-tool-import.c	Tue Dec 30 02:18:02 2008
@@ -55,8 +55,8 @@
 	GError *err = NULL;
 	gchar *label;
 	
-	attrs = gp11_object_get_full (object, ATTR_TYPES, G_N_ELEMENTS(ATTR_TYPES), NULL, &err);
-	if(!attrs) {
+	attrs = gp11_attributes_new_empty (CKA_LABEL, CKA_CLASS, CKA_ID, -1);
+	if (!gp11_object_get_full (object, attrs, NULL, &err)) {
 		gkr_tool_handle_error (&err, "couldn't get imported object info");
 		return;
 	}
@@ -115,18 +115,27 @@
 static void
 print_import_information (GP11Session *session, GP11Object *import)
 {
-	GP11Attribute *attr;
+	CK_OBJECT_HANDLE_PTR handles;
+	CK_ULONG n_handles;
+	gsize length;
 	GList *objects, *l;
+	GP11Slot *slot;
 	GError *err;
 	
-	attr = gp11_object_get_one (import, CKA_GNOME_IMPORT_OBJECTS, &err);
-	if (!attr) {
+	handles = gp11_object_get_data (import, CKA_GNOME_IMPORT_OBJECTS, &length, &err);
+	if (!handles) {
 		gkr_tool_handle_error (&err, "couldn't find imported objects");
 		return;
 	}
+	
+	n_handles = length / sizeof (CK_OBJECT_HANDLE);
+	
+	slot = gp11_session_get_slot (session);
+	g_return_if_fail (slot);
 
-	objects = gp11_objects_from_handle_array (session, attr);
-	gp11_attribute_free (attr);
+	objects = gp11_objects_from_handle_array (slot, handles, n_handles);
+	g_free (handles);
+	g_object_unref (slot);
 
 	for (l = objects; l; l = g_list_next (l))
 		print_object_information (GP11_OBJECT (l->data));



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]