1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
/* gck-enumerator.c - the GObject PKCS#11 wrapper library
4
Copyright (C) 2010, Stefan Walter
6
The Gnome Keyring Library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public License as
8
published by the Free Software Foundation; either version 2 of the
9
License, or (at your option) any later version.
11
The Gnome Keyring Library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Library General Public
17
License along with the Gnome Library; see the file COPYING.LIB. If not,
18
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
Boston, MA 02111-1307, USA.
21
Author: Stef Walter <nielsen@memberwebs.com>
27
#define DEBUG_FLAG GCK_DEBUG_ENUMERATOR
28
#include "gck-debug.h"
29
#include "gck-private.h"
34
* SECTION:gck-enumerator
35
* @title: GckEnumerator
36
* @short_description: Enumerates through PKCS\#11 objects.
38
* A GckEnumerator can be used to enumerate through PKCS\#11 objects. It will
39
* automatically create sessions as necessary.
41
* Use gck_modules_enumerate_objects() or gck_modules_enumerate_uri() to create
42
* an enumerator. To get the objects use gck_enumerator_next() or
43
* gck_enumerator_next_async() functions.
56
* An object that allows enumerating of objects across modules, tokens.
59
typedef struct _GckEnumeratorResult {
63
} GckEnumeratorResult;
65
typedef struct _GckEnumeratorState GckEnumeratorState;
67
typedef gpointer (*GckEnumeratorFunc) (GckEnumeratorState *args,
70
struct _GckEnumeratorState {
72
GckEnumeratorState *chained;
74
/* For the current call */
77
/* The state we're currently in */
78
GckEnumeratorFunc handler;
80
/* Input to enumerator */
83
GckSessionOptions session_options;
84
GTlsInteraction *interaction;
86
/* The type of objects to create */
88
gpointer object_class;
89
GckObjectCacheIface *object_iface;
96
GckTokenInfo *token_info;
97
CK_FUNCTION_LIST_PTR funcs;
109
struct _GckEnumeratorPrivate {
111
GckEnumeratorState *the_state;
112
GTlsInteraction *interaction;
114
GckObjectClass *object_class;
115
GckEnumerator *chained;
118
G_DEFINE_TYPE (GckEnumerator, gck_enumerator, G_TYPE_OBJECT);
120
static gpointer state_modules (GckEnumeratorState *args,
123
static gpointer state_slots (GckEnumeratorState *args,
126
static gpointer state_slot (GckEnumeratorState *args,
129
static gpointer state_session (GckEnumeratorState *args,
132
static gpointer state_find (GckEnumeratorState *args,
135
static gpointer state_results (GckEnumeratorState *args,
140
_gck_enumerator_result_free (gpointer data)
142
GckEnumeratorResult *result = data;
143
g_object_unref (result->session);
145
gck_attributes_unref (result->attrs);
146
g_slice_free (GckEnumeratorResult, result);
150
rewind_state (GckEnumeratorState *args, GckEnumeratorFunc handler)
154
g_assert (args->handler);
156
while (handler != args->handler) {
157
args->handler = (args->handler) (args, FALSE);
158
g_assert (args->handler);
165
cleanup_state (GckEnumeratorState *args)
169
/* Have each state cleanup */
170
rewind_state (args, state_modules);
173
g_assert (!args->slots);
176
g_assert (!args->slot);
177
g_assert (!args->token_info);
178
g_assert (!args->funcs);
181
g_assert (!args->session);
185
g_queue_foreach (args->found, (GFunc) _gck_enumerator_result_free, NULL);
186
g_queue_free (args->found);
192
g_queue_foreach (args->results, (GFunc) _gck_enumerator_result_free, NULL);
193
g_queue_free (args->results);
194
args->results = NULL;
197
gck_list_unref_free (args->modules);
198
args->modules = NULL;
200
g_clear_object (&args->interaction);
202
if (args->object_class)
203
g_type_class_unref (args->object_class);
204
args->object_class = NULL;
205
args->object_type = 0;
208
gck_uri_data_free (args->match);
214
state_modules (GckEnumeratorState *args, gboolean forward)
218
g_assert (args->slots == NULL);
222
/* There are no more modules? */
223
if (!args->modules) {
224
_gck_debug ("no more modules, stopping enumerator");
228
/* Pop off the current module */
229
module = args->modules->data;
230
g_assert (GCK_IS_MODULE (module));
231
args->modules = g_list_delete_link (args->modules, args->modules);
233
args->slots = gck_module_get_slots (module, TRUE);
235
if (_gck_debugging) {
236
GckModuleInfo *info = gck_module_get_info (module);
237
_gck_debug ("enumerating into module: %s", info->library_description);
238
gck_module_info_free (info);
241
g_object_unref (module);
245
/* Should never be asked to go backward from start state */
246
g_assert_not_reached ();
250
state_slots (GckEnumeratorState *args, gboolean forward)
254
GckTokenInfo *token_info;
257
g_assert (args->slot == NULL);
259
/* slots to slot state */
262
/* If there are no more slots go back to start state */
264
_gck_debug ("no more slots, want next module");
265
return rewind_state (args, state_modules);
268
/* Pop the next slot off the stack */
269
slot = args->slots->data;
270
args->slots = g_list_delete_link (args->slots, args->slots);
272
token_info = gck_slot_get_token_info (slot);
274
g_message ("couldn't get token info while enumerating");
275
g_object_unref (slot);
276
return rewind_state (args, state_modules);
279
/* Do we have unrecognized matches? */
280
if (args->match->any_unrecognized) {
281
_gck_debug ("token uri had unrecognized, not matching any tokens");
284
/* Are we trying to match the slot? */
285
} else if (args->match->token_info) {
286
/* No match? Go to next slot */
287
matched = _gck_token_info_match (args->match->token_info, token_info);
289
_gck_debug ("%s token: %s", matched ? "matched" : "did not match",
293
_gck_debug ("matching all tokens: %s", token_info->label);
298
g_object_unref (slot);
299
gck_token_info_free (token_info);
303
module = gck_slot_get_module (slot);
304
args->funcs = gck_module_get_functions (module);
305
g_assert (args->funcs);
306
g_object_unref (module);
310
args->token_info = token_info;
313
/* slots state to modules state */
316
gck_list_unref_free (args->slots);
318
return state_modules;
323
state_slot (GckEnumeratorState *args, gboolean forward)
325
CK_SESSION_HANDLE session;
329
g_assert (args->slot);
330
g_assert (args->funcs);
331
g_assert (args->session == NULL);
333
/* slot to session state */
335
flags = CKF_SERIAL_SESSION;
336
if ((args->session_options & GCK_SESSION_READ_WRITE) == GCK_SESSION_READ_WRITE)
337
flags |= CKF_RW_SESSION;
339
rv = (args->funcs->C_OpenSession) (gck_slot_get_handle (args->slot),
340
flags, NULL, NULL, &session);
343
g_message ("couldn't open session on module while enumerating objects: %s",
344
gck_message_from_rv (rv));
345
return rewind_state (args, state_slots);
348
_gck_debug ("opened %s session", flags & CKF_RW_SESSION ? "read-write" : "read-only");
349
args->session = gck_session_from_handle (args->slot, session, args->session_options);
350
return state_session;
352
/* slot to slots state */
354
g_object_unref (args->slot);
358
gck_token_info_free (args->token_info);
359
args->token_info = NULL;
366
state_session (GckEnumeratorState *args, gboolean forward)
368
GTlsInteraction *interaction;
371
g_assert (args->funcs);
372
g_assert (args->session);
373
g_assert (args->token_info);
375
/* session to authenticated state */
378
/* Don't want to authenticate? */
379
if ((args->session_options & GCK_SESSION_LOGIN_USER) == 0) {
380
_gck_debug ("no authentication necessary, skipping");
384
/* Compatibility, hook into GckModule signals if no interaction set */
385
if (args->interaction)
386
interaction = g_object_ref (args->interaction);
388
interaction = _gck_interaction_new (args->slot);
390
rv = _gck_session_authenticate_token (args->funcs,
391
gck_session_get_handle (args->session),
392
args->slot, interaction, NULL);
394
g_object_unref (interaction);
397
g_message ("couldn't authenticate when enumerating: %s", gck_message_from_rv (rv));
399
/* We try to proceed anyway with the enumeration */
402
/* Session to slot state */
404
g_object_unref (args->session);
405
args->session = NULL;
411
state_find (GckEnumeratorState *args,
414
CK_OBJECT_HANDLE objects[128];
415
CK_SESSION_HANDLE session;
416
CK_ATTRIBUTE_PTR attrs;
417
CK_ULONG n_attrs, i,count;
418
GckEnumeratorResult *result;
421
/* Just go back, no logout */
423
return state_session;
425
/* This is where we do the actual searching */
427
g_assert (args->session != NULL);
428
g_assert (args->want_objects > 0);
429
g_assert (args->funcs != NULL);
432
args->found = g_queue_new ();
434
if (args->match->attributes) {
435
attrs = _gck_attributes_commit_out (args->match->attributes, &n_attrs);
436
if (_gck_debugging) {
437
gchar *string = gck_attributes_to_string (args->match->attributes);
438
_gck_debug ("finding objects matching: %s", string);
444
_gck_debug ("finding all objects");
447
session = gck_session_get_handle (args->session);
448
g_return_val_if_fail (session, NULL);
450
/* Get all the objects */
451
rv = (args->funcs->C_FindObjectsInit) (session, attrs, n_attrs);
455
rv = (args->funcs->C_FindObjects) (session, objects, G_N_ELEMENTS (objects), &count);
456
if (rv != CKR_OK || count == 0)
459
_gck_debug ("matched %lu objects", count);
461
for (i = 0; i < count; i++) {
462
result = g_slice_new0 (GckEnumeratorResult);
463
result->handle = objects[i];
464
result->session = g_object_ref (args->session);
465
g_queue_push_tail (args->found, result);
469
(args->funcs->C_FindObjectsFinal) (session);
472
_gck_debug ("finding objects completed with: %s", _gck_stringize_rv (rv));
473
return state_results;
477
state_results (GckEnumeratorState *args,
480
GckEnumeratorResult *result;
482
GckAttributes *attrs;
483
CK_ATTRIBUTE_PTR template;
485
CK_SESSION_HANDLE session;
490
g_assert (args->funcs != NULL);
491
g_assert (args->object_class != NULL);
492
g_assert (args->found != NULL);
494
/* No cleanup, just unwind */
499
args->results = g_queue_new ();
501
session = gck_session_get_handle (args->session);
502
g_return_val_if_fail (session, NULL);
504
/* Get the attributes for want_objects */
505
for (count = 0; count < args->want_objects; count++) {
506
result = g_queue_pop_head (args->found);
507
if (result == NULL) {
508
_gck_debug ("wanted %d objects, have %d, looking for more",
509
args->want_objects, g_queue_get_length (args->results));
510
return rewind_state (args, state_slots);
513
/* If no request for attributes, just go forward */
514
if (args->object_iface == NULL || args->object_iface->n_default_types == 0) {
515
g_queue_push_tail (args->results, result);
519
gck_builder_init (&builder);
521
for (i = 0; i < args->object_iface->n_default_types; ++i)
522
gck_builder_add_empty (&builder, args->object_iface->default_types[i]);
524
/* Ask for attribute sizes */
525
template = _gck_builder_prepare_in (&builder, &n_template);
527
rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
528
if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
530
/* Allocate memory for each value */
531
template = _gck_builder_commit_in (&builder, &n_template);
533
/* Now get the actual values */
534
rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
537
attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
539
if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
540
if (_gck_debugging) {
541
gchar *string = gck_attributes_to_string (attrs);
542
_gck_debug ("retrieved attributes for object %lu: %s",
543
result->handle, string);
546
result->attrs = attrs;
547
g_queue_push_tail (args->results, result);
550
g_message ("couldn't retrieve attributes when enumerating: %s",
551
gck_message_from_rv (rv));
552
gck_attributes_unref (attrs);
553
_gck_enumerator_result_free (result);
557
_gck_debug ("wanted %d objects, returned %d objects",
558
args->want_objects, g_queue_get_length (args->results));
560
/* We got all the results we wanted */
565
gck_enumerator_init (GckEnumerator *self)
567
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_ENUMERATOR, GckEnumeratorPrivate);
568
#if GLIB_CHECK_VERSION(2,31,2)
569
self->pv->mutex = g_new0 (GMutex, 1);
570
g_mutex_init (self->pv->mutex);
572
self->pv->mutex = g_mutex_new ();
574
self->pv->the_state = g_new0 (GckEnumeratorState, 1);
575
self->pv->object_type = GCK_TYPE_OBJECT;
576
self->pv->object_class = g_type_class_ref (self->pv->object_type);
577
g_assert (self->pv->object_class);
581
gck_enumerator_get_property (GObject *obj,
586
GckEnumerator *self = GCK_ENUMERATOR (obj);
589
case PROP_INTERACTION:
590
g_value_take_object (value, gck_enumerator_get_interaction (self));
592
case PROP_OBJECT_TYPE:
593
g_value_set_gtype (value, gck_enumerator_get_object_type (self));
596
g_value_set_object (value, gck_enumerator_get_chained (self));
599
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
605
gck_enumerator_set_property (GObject *obj,
610
GckEnumerator *self = GCK_ENUMERATOR (obj);
613
case PROP_INTERACTION:
614
gck_enumerator_set_interaction (self, g_value_get_object (value));
616
case PROP_OBJECT_TYPE:
617
gck_enumerator_set_object_type (self, g_value_get_gtype (value));
620
gck_enumerator_set_chained (self, g_value_get_object (value));
623
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
629
gck_enumerator_dispose (GObject *obj)
631
GckEnumerator *self = GCK_ENUMERATOR (obj);
633
gck_enumerator_set_interaction (self, NULL);
634
gck_enumerator_set_chained (self, NULL);
636
G_OBJECT_CLASS (gck_enumerator_parent_class)->dispose (obj);
640
gck_enumerator_finalize (GObject *obj)
642
GckEnumerator *self = GCK_ENUMERATOR (obj);
644
g_assert (self->pv->interaction == NULL);
646
g_assert (self->pv->the_state != NULL);
647
cleanup_state (self->pv->the_state);
648
g_free (self->pv->the_state);
650
#if GLIB_CHECK_VERSION(2,31,2)
651
g_mutex_clear (self->pv->mutex);
652
g_free (self->pv->mutex);
654
g_mutex_free (self->pv->mutex);
656
g_type_class_unref (self->pv->object_class);
658
G_OBJECT_CLASS (gck_enumerator_parent_class)->finalize (obj);
662
gck_enumerator_class_init (GckEnumeratorClass *klass)
664
GObjectClass *gobject_class = (GObjectClass*)klass;
666
gobject_class->get_property = gck_enumerator_get_property;
667
gobject_class->set_property = gck_enumerator_set_property;
668
gobject_class->dispose = gck_enumerator_dispose;
669
gobject_class->finalize = gck_enumerator_finalize;
671
g_type_class_add_private (klass, sizeof (GckEnumeratorPrivate));
674
* GckEnumerator:interaction:
676
* Interaction object used to ask the user for pins when opening
677
* sessions. Used if the session_options of the enumerator have
678
* %GCK_SESSION_LOGIN_USER
680
g_object_class_install_property (gobject_class, PROP_INTERACTION,
681
g_param_spec_object ("interaction", "Interaction", "Interaction asking for pins",
682
G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE));
685
* GckEnumerator:object-type:
687
* The type of objects that are created by the enumerator. Must be
688
* GckObject or derived from it.
690
g_object_class_install_property (gobject_class, PROP_OBJECT_TYPE,
691
g_param_spec_gtype ("object-type", "Object Type", "Type of objects created",
692
GCK_TYPE_OBJECT, G_PARAM_READWRITE));
695
* GckEnumerator:chained:
697
* Chained enumerator, which will be enumerated when this enumerator
698
* has enumerated all its objects.
700
g_object_class_install_property (gobject_class, PROP_CHAINED,
701
g_param_spec_object ("chained", "Chained", "Chained enumerator",
702
GCK_TYPE_ENUMERATOR, G_PARAM_READWRITE));
706
created_enumerator (GckUriData *uri_data,
709
if (_gck_debugging) {
711
attrs = uri_data->attributes ? gck_attributes_to_string (uri_data->attributes) : NULL;
712
uri = uri_data ? gck_uri_build (uri_data, GCK_URI_FOR_TOKEN | GCK_URI_FOR_MODULE) : NULL;
713
_gck_debug ("for = %s, tokens = %s, objects = %s", type, uri, attrs);
720
_gck_enumerator_new_for_modules (GList *modules,
721
GckSessionOptions session_options,
722
GckUriData *uri_data)
725
GckEnumeratorState *state;
727
self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
728
state = self->pv->the_state;
730
state->session_options = session_options;
732
state->modules = gck_list_ref_copy (modules);
734
state->handler = state_modules;
735
state->match = uri_data;
737
created_enumerator (uri_data, "modules");
742
_gck_enumerator_new_for_slots (GList *slots,
743
GckSessionOptions session_options,
744
GckUriData *uri_data)
747
GckEnumeratorState *state;
749
self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
750
state = self->pv->the_state;
752
state->session_options = session_options;
754
state->slots = gck_list_ref_copy (slots);
755
state->modules = NULL;
756
state->handler = state_slots;
757
state->match = uri_data;
759
created_enumerator (uri_data, "slots");
764
_gck_enumerator_new_for_session (GckSession *session,
765
GckUriData *uri_data)
768
GckEnumeratorState *state;
771
self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
772
state = self->pv->the_state;
774
state->session = g_object_ref (session);
775
state->modules = NULL;
777
state->handler = state_session;
778
state->match = uri_data;
780
state->slot = gck_session_get_slot (session);
781
state->token_info = gck_slot_get_token_info (state->slot);
783
module = gck_session_get_module (session);
784
state->funcs = gck_module_get_functions (module);
785
g_object_unref (module);
787
created_enumerator (uri_data, "session");
791
typedef struct _EnumerateNext {
793
GckEnumeratorState *state;
798
perform_enumerate_next (EnumerateNext *args)
800
GckEnumeratorFunc handler;
801
GckEnumeratorState *state;
804
g_assert (args->state);
806
for (state = args->state; state != NULL; state = state->chained) {
807
g_assert (state->handler);
808
state->want_objects = args->want_objects - count;
810
handler = (state->handler) (state, TRUE);
813
state->handler = handler;
816
count += state->results ? g_queue_get_length (state->results) : 0;
817
if (count >= args->want_objects)
821
/* TODO: In some modes, errors */
826
free_enumerate_next (EnumerateNext *args)
828
/* Should have been assigned back to enumerator */
829
g_assert (!args->state);
835
* gck_enumerator_get_object_type:
836
* @self: an enumerator
838
* Get the type of objects created by this enumerator. The type will always
839
* either be #GckObject or derived from it.
841
* Returns: (transfer none): the type of objects created
844
gck_enumerator_get_object_type (GckEnumerator *self)
848
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), 0);
850
g_mutex_lock (self->pv->mutex);
852
result = self->pv->object_type;
854
g_mutex_unlock (self->pv->mutex);
860
* gck_enumerator_set_object_type:
861
* @self: an enumerator
862
* @object_type: the type of objects to create
864
* Set the type of objects to be created by this enumerator. The type must
865
* always be either #GckObject or derived from it.
867
* If the #GckObjectCache interface is implemented on the derived class
868
* and the attribute_types field is set, then the enumerator will retrieve
869
* attributes for each object.
872
gck_enumerator_set_object_type (GckEnumerator *self,
877
g_return_if_fail (GCK_IS_ENUMERATOR (self));
879
if (!g_type_is_a (object_type, GCK_TYPE_OBJECT)) {
880
g_warning ("the object_type '%s' is not a derived type of GckObject",
881
g_type_name (object_type));
885
klass = g_type_class_ref (object_type);
887
g_mutex_lock (self->pv->mutex);
889
if (self->pv->object_type)
890
g_type_class_unref (self->pv->object_class);
891
self->pv->object_type = object_type;
892
self->pv->object_class = klass;
894
g_mutex_unlock (self->pv->mutex);
898
* gck_enumerator_get_chained:
899
* @self: the enumerator
901
* Get the enumerator that will be run after all objects from this one
904
* Returns: (transfer full) (allow-none): the chained enumerator or %NULL
907
gck_enumerator_get_chained (GckEnumerator *self)
909
GckEnumerator *chained = NULL;
911
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
913
g_mutex_lock (self->pv->mutex);
915
if (self->pv->chained)
916
chained = g_object_ref (self->pv->chained);
918
g_mutex_unlock (self->pv->mutex);
924
* gck_enumerator_set_interaction:
925
* @self: the enumerator
926
* @chained: (allow-none): the chained enumerator or %NULL
928
* Set a chained enumerator that will be run after all objects from this one
932
gck_enumerator_set_chained (GckEnumerator *self,
933
GckEnumerator *chained)
935
GckEnumerator *old_chained = NULL;
937
g_return_if_fail (GCK_IS_ENUMERATOR (self));
938
g_return_if_fail (chained == NULL || GCK_IS_ENUMERATOR (chained));
940
g_mutex_lock (self->pv->mutex);
942
old_chained = self->pv->chained;
944
g_object_ref (chained);
945
self->pv->chained = chained;
947
g_mutex_unlock (self->pv->mutex);
950
g_object_unref (old_chained);
952
g_object_notify (G_OBJECT (self), "chained");
956
* gck_enumerator_get_interaction:
957
* @self: the enumerator
959
* Get the interaction used when a pin is needed
961
* Returns: (transfer full) (allow-none): the interaction or %NULL
964
gck_enumerator_get_interaction (GckEnumerator *self)
966
GTlsInteraction *result = NULL;
968
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
970
g_mutex_lock (self->pv->mutex);
972
if (self->pv->interaction)
973
result = g_object_ref (self->pv->interaction);
975
g_mutex_unlock (self->pv->mutex);
981
* gck_enumerator_set_interaction:
982
* @self: the enumerator
983
* @interaction: (allow-none): the interaction or %NULL
985
* Set the interaction used when a pin is needed
988
gck_enumerator_set_interaction (GckEnumerator *self,
989
GTlsInteraction *interaction)
991
GTlsInteraction *previous = NULL;
993
g_return_if_fail (GCK_IS_ENUMERATOR (self));
994
g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
996
g_mutex_lock (self->pv->mutex);
998
if (interaction != self->pv->interaction) {
999
previous = self->pv->interaction;
1000
self->pv->interaction = interaction;
1002
g_object_ref (interaction);
1005
g_mutex_unlock (self->pv->mutex);
1007
g_clear_object (&previous);
1008
g_object_notify (G_OBJECT (self), "interaction");
1011
static GckEnumeratorState *
1012
check_out_enumerator_state (GckEnumerator *self)
1014
GckEnumeratorState *state = NULL;
1015
GTlsInteraction *old_interaction = NULL;
1016
gpointer old_object_class = NULL;
1017
GckEnumeratorState *chained_state = NULL;
1018
GckEnumerator *chained;
1020
chained = gck_enumerator_get_chained (self);
1022
chained_state = check_out_enumerator_state (chained);
1023
g_object_unref (chained);
1026
g_mutex_lock (self->pv->mutex);
1028
if (self->pv->the_state) {
1029
state = self->pv->the_state;
1030
self->pv->the_state = NULL;
1032
state->enumerator = g_object_ref (self);
1033
g_assert (state->chained == NULL);
1034
state->chained = chained_state;
1036
old_interaction = state->interaction;
1037
if (self->pv->interaction)
1038
state->interaction = g_object_ref (self->pv->interaction);
1040
state->interaction = NULL;
1042
old_object_class = state->object_class;
1044
/* Must already be holding a reference, state also holds a ref */
1045
state->object_type = self->pv->object_type;
1046
state->object_class = g_type_class_peek (state->object_type);
1047
g_assert (state->object_class == self->pv->object_class);
1048
state->object_iface = g_type_interface_peek (state->object_class,
1049
GCK_TYPE_OBJECT_CACHE);
1050
g_type_class_ref (state->object_type);
1053
g_mutex_unlock (self->pv->mutex);
1056
g_warning ("this enumerator is already running a next operation");
1058
/* Free these outside the lock */
1059
if (old_interaction)
1060
g_object_unref (old_interaction);
1061
if (old_object_class)
1062
g_type_class_unref (old_object_class);
1068
check_in_enumerator_state (GckEnumeratorState *state)
1070
GckEnumeratorState *chained = NULL;
1071
GckEnumerator *self;
1073
g_assert (GCK_IS_ENUMERATOR (state->enumerator));
1074
self = state->enumerator;
1076
g_mutex_lock (self->pv->mutex);
1078
state->enumerator = NULL;
1079
g_assert (self->pv->the_state == NULL);
1080
self->pv->the_state = state;
1081
chained = state->chained;
1082
state->chained = NULL;
1084
g_mutex_unlock (self->pv->mutex);
1086
/* matches ref in check_in */
1087
g_object_unref (self);
1090
check_in_enumerator_state (chained);
1094
extract_result (GckEnumeratorState *state)
1096
GckEnumeratorResult *result = NULL;
1100
g_assert (state != NULL);
1102
if (state->results != NULL)
1103
result = g_queue_pop_head (state->results);
1104
if (result == NULL) {
1106
return extract_result (state->chained);
1110
module = gck_session_get_module (result->session);
1111
object = g_object_new (state->object_type,
1113
"handle", result->handle,
1114
"session", result->session,
1115
result->attrs ? "attributes" : NULL, result->attrs,
1117
g_object_unref (module);
1119
_gck_enumerator_result_free (result);
1124
extract_results (GckEnumeratorState *state,
1127
GList *objects = NULL;
1131
g_assert (state != NULL);
1132
g_assert (want_objects != NULL);
1134
for (i = 0; i < *want_objects; i++) {
1135
object = extract_result (state);
1138
objects = g_list_prepend (objects, object);
1142
return g_list_reverse (objects);
1146
* gck_enumerator_next:
1147
* @self: The enumerator
1148
* @cancellable: A #GCancellable or %NULL
1149
* @error: A location to store an error on failure
1151
* Get the next object in the enumerator, or %NULL if there are no more objects.
1153
* %NULL is also returned if the function fails. Use the @error to determine
1154
* whether a failure occurred or not.
1156
* Returns: (transfer full) (allow-none): The next object, which must be released
1157
* using g_object_unref, or %NULL.
1160
gck_enumerator_next (GckEnumerator *self,
1161
GCancellable *cancellable,
1164
EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, };
1165
GckObject *result = NULL;
1167
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
1168
g_return_val_if_fail (!error || !*error, NULL);
1170
args.state = check_out_enumerator_state (self);
1171
g_return_val_if_fail (args.state != NULL, NULL);
1173
/* A result from a previous run? */
1174
result = extract_result (args.state);
1175
if (result == NULL) {
1176
args.want_objects = 1;
1178
/* Run the operation and steal away the results */
1179
if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
1180
result = extract_result (args.state);
1182
args.want_objects = 0;
1185
/* Put the state back */
1186
check_in_enumerator_state (args.state);
1192
* gck_enumerator_next_n:
1193
* @self: An enumerator
1194
* @max_objects: The maximum amount of objects to enumerate
1195
* @cancellable: A #GCancellable or %NULL
1196
* @error: A location to store an error on failure
1198
* Get the next set of objects from the enumerator. The maximum number of
1199
* objects can be specified with @max_objects. If -1 is specified, then all
1200
* the remaining objects will be returned.
1202
* %NULL is also returned if the function fails. Use the @error to determine
1203
* whether a failure occurred or not.
1205
* Returns: (transfer full) (element-type Gck.Object): A list of objects, which
1206
* should be freed using gck_list_unref_free().
1209
gck_enumerator_next_n (GckEnumerator *self,
1211
GCancellable *cancellable,
1214
EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, };
1215
GList *results = NULL;
1218
g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
1219
g_return_val_if_fail (max_objects == -1 || max_objects > 0, NULL);
1220
g_return_val_if_fail (!error || !*error, NULL);
1222
/* Remove the state and own it ourselves */
1223
args.state = check_out_enumerator_state (self);
1224
g_return_val_if_fail (args.state != NULL, NULL);
1226
want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
1228
/* A result from a previous run? */
1229
results = extract_results (args.state, &want_objects);
1230
if (want_objects > 0) {
1231
args.want_objects = want_objects;
1233
/* Run the operation and steal away the results */
1234
if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
1235
results = g_list_concat (results, extract_results (args.state, &want_objects));
1237
args.want_objects = 0;
1240
/* Put the state back */
1241
check_in_enumerator_state (args.state);
1244
g_clear_error (error);
1250
* gck_enumerator_next_async:
1251
* @self: An enumerator
1252
* @max_objects: The maximum number of objects to get
1253
* @cancellable: A #GCancellable or %NULL
1254
* @callback: Called when the result is ready
1255
* @user_data: Data to pass to the callback
1257
* Get the next set of objects from the enumerator. This operation completes
1258
* asynchronously.The maximum number of objects can be specified with
1259
* @max_objects. If -1 is specified, then all the remaining objects will be
1263
gck_enumerator_next_async (GckEnumerator *self, gint max_objects, GCancellable *cancellable,
1264
GAsyncReadyCallback callback, gpointer user_data)
1266
GckEnumeratorState *state;
1267
EnumerateNext *args;
1269
g_return_if_fail (GCK_IS_ENUMERATOR (self));
1270
g_return_if_fail (max_objects == -1 || max_objects > 0);
1272
g_object_ref (self);
1274
/* Remove the state and own it ourselves */
1275
state = check_out_enumerator_state (self);
1276
g_return_if_fail (state != NULL);
1278
args = _gck_call_async_prep (NULL, self, perform_enumerate_next, NULL,
1279
sizeof (*args), free_enumerate_next);
1280
args->want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
1282
args->state = state;
1283
_gck_call_async_ready_go (args, cancellable, callback, user_data);
1284
g_object_unref (self);
1288
* gck_enumerator_next_finish:
1289
* @self: An enumerator
1290
* @result: The result passed to the callback
1291
* @error: A location to raise an error on failure.
1293
* Complete an operation to enumerate next objects.
1295
* %NULL is also returned if the function fails. Use the @error to determine
1296
* whether a failure occurred or not.
1298
* Returns: (element-type Gck.Module) (transfer full): The list of objects, which
1299
* should be freed with gck_list_unref_free()
1302
gck_enumerator_next_finish (GckEnumerator *self, GAsyncResult *result, GError **error)
1304
EnumerateNext *args;
1305
GckEnumeratorState *state;
1306
GList *results = NULL;
1309
g_object_ref (self);
1311
args = _gck_call_arguments (result, EnumerateNext);
1312
state = args->state;
1314
want_objects = args->want_objects;
1315
args->want_objects = 0;
1317
if (_gck_call_basic_finish (result, error))
1318
results = extract_results (state, &want_objects);
1320
/* Put the state back */
1321
check_in_enumerator_state (state);
1323
g_object_unref (self);