D-Bus  1.4.10
dbus-object-tree.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-object-tree.c DBusObjectTree (internals of DBusConnection)
3  *
4  * Copyright (C) 2003, 2005 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 
24 #include <config.h>
25 #include "dbus-object-tree.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-internals.h"
28 #include "dbus-hash.h"
29 #include "dbus-protocol.h"
30 #include "dbus-string.h"
31 #include <string.h>
32 #include <stdlib.h>
33 
47 
48 static DBusObjectSubtree* _dbus_object_subtree_new (const char *name,
49  const DBusObjectPathVTable *vtable,
50  void *user_data);
51 static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree);
52 static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree);
53 
58 {
59  int refcount;
63 };
64 
71 {
76  void *user_data;
78  int n_subtrees;
80  unsigned int invoke_as_fallback : 1;
81  char name[1];
82 };
83 
93 {
94  DBusObjectTree *tree;
95 
96  /* the connection passed in here isn't fully constructed,
97  * so don't do anything more than store a pointer to
98  * it
99  */
100 
101  tree = dbus_new0 (DBusObjectTree, 1);
102  if (tree == NULL)
103  goto oom;
104 
105  tree->refcount = 1;
106  tree->connection = connection;
107  tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
108  if (tree->root == NULL)
109  goto oom;
110  tree->root->invoke_as_fallback = TRUE;
111 
112  return tree;
113 
114  oom:
115  if (tree)
116  {
117  dbus_free (tree);
118  }
119 
120  return NULL;
121 }
122 
130 {
131  _dbus_assert (tree->refcount > 0);
132 
133  tree->refcount += 1;
134 
135  return tree;
136 }
137 
142 void
144 {
145  _dbus_assert (tree->refcount > 0);
146 
147  tree->refcount -= 1;
148 
149  if (tree->refcount == 0)
150  {
152 
153  dbus_free (tree);
154  }
155 }
156 
160 #define VERBOSE_FIND 0
161 
162 static DBusObjectSubtree*
163 find_subtree_recurse (DBusObjectSubtree *subtree,
164  const char **path,
165  dbus_bool_t create_if_not_found,
166  int *index_in_parent,
167  dbus_bool_t *exact_match)
168 {
169  int i, j;
170  dbus_bool_t return_deepest_match;
171 
172  return_deepest_match = exact_match != NULL;
173 
174  _dbus_assert (!(return_deepest_match && create_if_not_found));
175 
176  if (path[0] == NULL)
177  {
178 #if VERBOSE_FIND
179  _dbus_verbose (" path exhausted, returning %s\n",
180  subtree->name);
181 #endif
182  if (exact_match != NULL)
183  *exact_match = TRUE;
184  return subtree;
185  }
186 
187 #if VERBOSE_FIND
188  _dbus_verbose (" searching children of %s for %s\n",
189  subtree->name, path[0]);
190 #endif
191 
192  i = 0;
193  j = subtree->n_subtrees;
194  while (i < j)
195  {
196  int k, v;
197 
198  k = (i + j) / 2;
199  v = strcmp (path[0], subtree->subtrees[k]->name);
200 
201 #if VERBOSE_FIND
202  _dbus_verbose (" %s cmp %s = %d\n",
203  path[0], subtree->subtrees[k]->name,
204  v);
205 #endif
206 
207  if (v == 0)
208  {
209  if (index_in_parent)
210  {
211 #if VERBOSE_FIND
212  _dbus_verbose (" storing parent index %d\n", k);
213 #endif
214  *index_in_parent = k;
215  }
216 
217  if (return_deepest_match)
218  {
219  DBusObjectSubtree *next;
220 
221  next = find_subtree_recurse (subtree->subtrees[k],
222  &path[1], create_if_not_found,
223  index_in_parent, exact_match);
224  if (next == NULL &&
225  subtree->invoke_as_fallback)
226  {
227 #if VERBOSE_FIND
228  _dbus_verbose (" no deeper match found, returning %s\n",
229  subtree->name);
230 #endif
231  if (exact_match != NULL)
232  *exact_match = FALSE;
233  return subtree;
234  }
235  else
236  return next;
237  }
238  else
239  return find_subtree_recurse (subtree->subtrees[k],
240  &path[1], create_if_not_found,
241  index_in_parent, exact_match);
242  }
243  else if (v < 0)
244  {
245  j = k;
246  }
247  else
248  {
249  i = k + 1;
250  }
251  }
252 
253 #if VERBOSE_FIND
254  _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
255  subtree->name, create_if_not_found);
256 #endif
257 
258  if (create_if_not_found)
259  {
260  DBusObjectSubtree* child;
261  int child_pos, new_n_subtrees;
262 
263 #if VERBOSE_FIND
264  _dbus_verbose (" creating subtree %s\n",
265  path[0]);
266 #endif
267 
268  child = _dbus_object_subtree_new (path[0],
269  NULL, NULL);
270  if (child == NULL)
271  return NULL;
272 
273  new_n_subtrees = subtree->n_subtrees + 1;
274  if (new_n_subtrees > subtree->max_subtrees)
275  {
276  int new_max_subtrees;
277  DBusObjectSubtree **new_subtrees;
278 
279  new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees;
280  new_subtrees = dbus_realloc (subtree->subtrees,
281  new_max_subtrees * sizeof (DBusObjectSubtree*));
282  if (new_subtrees == NULL)
283  {
284  _dbus_object_subtree_unref (child);
285  return NULL;
286  }
287  subtree->subtrees = new_subtrees;
288  subtree->max_subtrees = new_max_subtrees;
289  }
290 
291  /* The binary search failed, so i == j points to the
292  place the child should be inserted. */
293  child_pos = i;
294  _dbus_assert (child_pos < new_n_subtrees &&
295  new_n_subtrees <= subtree->max_subtrees);
296  if (child_pos + 1 < new_n_subtrees)
297  {
298  memmove (&subtree->subtrees[child_pos+1],
299  &subtree->subtrees[child_pos],
300  (new_n_subtrees - child_pos - 1) *
301  sizeof subtree->subtrees[0]);
302  }
303  subtree->subtrees[child_pos] = child;
304 
305  if (index_in_parent)
306  *index_in_parent = child_pos;
307  subtree->n_subtrees = new_n_subtrees;
308  child->parent = subtree;
309 
310  return find_subtree_recurse (child,
311  &path[1], create_if_not_found,
312  index_in_parent, exact_match);
313  }
314  else
315  {
316  if (exact_match != NULL)
317  *exact_match = FALSE;
318  return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
319  }
320 }
321 
322 static DBusObjectSubtree*
323 find_subtree (DBusObjectTree *tree,
324  const char **path,
325  int *index_in_parent)
326 {
327  DBusObjectSubtree *subtree;
328 
329 #if VERBOSE_FIND
330  _dbus_verbose ("Looking for exact registered subtree\n");
331 #endif
332 
333  subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
334 
335  if (subtree && subtree->message_function == NULL)
336  return NULL;
337  else
338  return subtree;
339 }
340 
341 static DBusObjectSubtree*
342 lookup_subtree (DBusObjectTree *tree,
343  const char **path)
344 {
345 #if VERBOSE_FIND
346  _dbus_verbose ("Looking for subtree\n");
347 #endif
348  return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
349 }
350 
351 static DBusObjectSubtree*
352 find_handler (DBusObjectTree *tree,
353  const char **path,
354  dbus_bool_t *exact_match)
355 {
356 #if VERBOSE_FIND
357  _dbus_verbose ("Looking for deepest handler\n");
358 #endif
359  _dbus_assert (exact_match != NULL);
360 
361  *exact_match = FALSE; /* ensure always initialized */
362 
363  return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
364 }
365 
366 static DBusObjectSubtree*
367 ensure_subtree (DBusObjectTree *tree,
368  const char **path)
369 {
370 #if VERBOSE_FIND
371  _dbus_verbose ("Ensuring subtree\n");
372 #endif
373  return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
374 }
375 
376 static char *flatten_path (const char **path);
377 
392  dbus_bool_t fallback,
393  const char **path,
394  const DBusObjectPathVTable *vtable,
395  void *user_data,
396  DBusError *error)
397 {
398  DBusObjectSubtree *subtree;
399 
400  _dbus_assert (tree != NULL);
401  _dbus_assert (vtable->message_function != NULL);
402  _dbus_assert (path != NULL);
403 
404  subtree = ensure_subtree (tree, path);
405  if (subtree == NULL)
406  {
407  _DBUS_SET_OOM (error);
408  return FALSE;
409  }
410 
411  if (subtree->message_function != NULL)
412  {
413  if (error != NULL)
414  {
415  char *complete_path = flatten_path (path);
416 
418  "A handler is already registered for %s",
419  complete_path ? complete_path
420  : "(cannot represent path: out of memory!)");
421 
422  dbus_free (complete_path);
423  }
424 
425  return FALSE;
426  }
427 
428  subtree->message_function = vtable->message_function;
429  subtree->unregister_function = vtable->unregister_function;
430  subtree->user_data = user_data;
431  subtree->invoke_as_fallback = fallback != FALSE;
432 
433  return TRUE;
434 }
435 
443 void
445  const char **path)
446 {
447  int i;
448  DBusObjectSubtree *subtree;
449  DBusObjectPathUnregisterFunction unregister_function;
450  void *user_data;
451  DBusConnection *connection;
452 
453  _dbus_assert (path != NULL);
454 
455  unregister_function = NULL;
456  user_data = NULL;
457 
458  subtree = find_subtree (tree, path, &i);
459 
460 #ifndef DBUS_DISABLE_CHECKS
461  if (subtree == NULL)
462  {
463  _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
464  path[0] ? path[0] : "null",
465  path[1] ? path[1] : "null");
466  goto unlock;
467  }
468 #else
469  _dbus_assert (subtree != NULL);
470 #endif
471 
472  _dbus_assert (subtree->parent == NULL ||
473  (i >= 0 && subtree->parent->subtrees[i] == subtree));
474 
475  subtree->message_function = NULL;
476 
477  unregister_function = subtree->unregister_function;
478  user_data = subtree->user_data;
479 
480  subtree->unregister_function = NULL;
481  subtree->user_data = NULL;
482 
483  /* If we have no subtrees of our own, remove from
484  * our parent (FIXME could also be more aggressive
485  * and remove our parent if it becomes empty)
486  */
487  if (subtree->parent && subtree->n_subtrees == 0)
488  {
489  /* assumes a 0-byte memmove is OK */
490  memmove (&subtree->parent->subtrees[i],
491  &subtree->parent->subtrees[i+1],
492  (subtree->parent->n_subtrees - i - 1) *
493  sizeof (subtree->parent->subtrees[0]));
494  subtree->parent->n_subtrees -= 1;
495 
496  subtree->parent = NULL;
497 
498  _dbus_object_subtree_unref (subtree);
499  }
500  subtree = NULL;
501 
502 unlock:
503  connection = tree->connection;
504 
505  /* Unlock and call application code */
506 #ifdef DBUS_BUILD_TESTS
507  if (connection)
508 #endif
509  {
510  _dbus_connection_ref_unlocked (connection);
511  _dbus_verbose ("unlock\n");
512  _dbus_connection_unlock (connection);
513  }
514 
515  if (unregister_function)
516  (* unregister_function) (connection, user_data);
517 
518 #ifdef DBUS_BUILD_TESTS
519  if (connection)
520 #endif
521  dbus_connection_unref (connection);
522 }
523 
524 static void
525 free_subtree_recurse (DBusConnection *connection,
526  DBusObjectSubtree *subtree)
527 {
528  /* Delete them from the end, for slightly
529  * more robustness against odd reentrancy.
530  */
531  while (subtree->n_subtrees > 0)
532  {
533  DBusObjectSubtree *child;
534 
535  child = subtree->subtrees[subtree->n_subtrees - 1];
536  subtree->subtrees[subtree->n_subtrees - 1] = NULL;
537  subtree->n_subtrees -= 1;
538  child->parent = NULL;
539 
540  free_subtree_recurse (connection, child);
541  }
542 
543  /* Call application code */
544  if (subtree->unregister_function)
545  (* subtree->unregister_function) (connection,
546  subtree->user_data);
547 
548  subtree->message_function = NULL;
549  subtree->unregister_function = NULL;
550  subtree->user_data = NULL;
551 
552  /* Now free ourselves */
553  _dbus_object_subtree_unref (subtree);
554 }
555 
562 void
564 {
565  if (tree->root)
566  free_subtree_recurse (tree->connection,
567  tree->root);
568  tree->root = NULL;
569 }
570 
571 static dbus_bool_t
572 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
573  const char **parent_path,
574  char ***child_entries)
575 {
576  DBusObjectSubtree *subtree;
577  char **retval;
578 
579  _dbus_assert (parent_path != NULL);
580  _dbus_assert (child_entries != NULL);
581 
582  *child_entries = NULL;
583 
584  subtree = lookup_subtree (tree, parent_path);
585  if (subtree == NULL)
586  {
587  retval = dbus_new0 (char *, 1);
588  }
589  else
590  {
591  int i;
592  retval = dbus_new0 (char*, subtree->n_subtrees + 1);
593  if (retval == NULL)
594  goto out;
595  i = 0;
596  while (i < subtree->n_subtrees)
597  {
598  retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
599  if (retval[i] == NULL)
600  {
601  dbus_free_string_array (retval);
602  retval = NULL;
603  goto out;
604  }
605  ++i;
606  }
607  }
608 
609  out:
610 
611  *child_entries = retval;
612  return retval != NULL;
613 }
614 
615 static DBusHandlerResult
616 handle_default_introspect_and_unlock (DBusObjectTree *tree,
617  DBusMessage *message,
618  const char **path)
619 {
620  DBusString xml;
621  DBusHandlerResult result;
622  char **children;
623  int i;
624  DBusMessage *reply;
625  DBusMessageIter iter;
626  const char *v_STRING;
627  dbus_bool_t already_unlocked;
628 
629  /* We have the connection lock here */
630 
631  already_unlocked = FALSE;
632 
633  _dbus_verbose (" considering default Introspect() handler...\n");
634 
635  reply = NULL;
636 
637  if (!dbus_message_is_method_call (message,
639  "Introspect"))
640  {
641 #ifdef DBUS_BUILD_TESTS
642  if (tree->connection)
643 #endif
644  {
645  _dbus_verbose ("unlock\n");
647  }
648 
650  }
651 
652  _dbus_verbose (" using default Introspect() handler!\n");
653 
654  if (!_dbus_string_init (&xml))
655  {
656 #ifdef DBUS_BUILD_TESTS
657  if (tree->connection)
658 #endif
659  {
660  _dbus_verbose ("unlock\n");
662  }
663 
665  }
666 
668 
669  children = NULL;
670  if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
671  goto out;
672 
674  goto out;
675 
676  if (!_dbus_string_append (&xml, "<node>\n"))
677  goto out;
678 
679  i = 0;
680  while (children[i] != NULL)
681  {
682  if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
683  children[i]))
684  goto out;
685 
686  ++i;
687  }
688 
689  if (!_dbus_string_append (&xml, "</node>\n"))
690  goto out;
691 
692  reply = dbus_message_new_method_return (message);
693  if (reply == NULL)
694  goto out;
695 
696  dbus_message_iter_init_append (reply, &iter);
697  v_STRING = _dbus_string_get_const_data (&xml);
698  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
699  goto out;
700 
701 #ifdef DBUS_BUILD_TESTS
702  if (tree->connection)
703 #endif
704  {
705  already_unlocked = TRUE;
706 
707  if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
708  goto out;
709  }
710 
712 
713  out:
714 #ifdef DBUS_BUILD_TESTS
715  if (tree->connection)
716 #endif
717  {
718  if (!already_unlocked)
719  {
720  _dbus_verbose ("unlock\n");
722  }
723  }
724 
725  _dbus_string_free (&xml);
726  dbus_free_string_array (children);
727  if (reply)
728  dbus_message_unref (reply);
729 
730  return result;
731 }
732 
748  DBusMessage *message)
749 {
750  char **path;
751  dbus_bool_t exact_match;
752  DBusList *list;
753  DBusList *link;
754  DBusHandlerResult result;
755  DBusObjectSubtree *subtree;
756 
757 #if 0
758  _dbus_verbose ("Dispatch of message by object path\n");
759 #endif
760 
761  path = NULL;
762  if (!dbus_message_get_path_decomposed (message, &path))
763  {
764 #ifdef DBUS_BUILD_TESTS
765  if (tree->connection)
766 #endif
767  {
768  _dbus_verbose ("unlock\n");
770  }
771 
772  _dbus_verbose ("No memory to get decomposed path\n");
773 
775  }
776 
777  if (path == NULL)
778  {
779 #ifdef DBUS_BUILD_TESTS
780  if (tree->connection)
781 #endif
782  {
783  _dbus_verbose ("unlock\n");
785  }
786 
787  _dbus_verbose ("No path field in message\n");
789  }
790 
791  /* Find the deepest path that covers the path in the message */
792  subtree = find_handler (tree, (const char**) path, &exact_match);
793 
794  /* Build a list of all paths that cover the path in the message */
795 
796  list = NULL;
797 
798  while (subtree != NULL)
799  {
800  if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
801  {
802  _dbus_object_subtree_ref (subtree);
803 
804  /* run deepest paths first */
805  if (!_dbus_list_append (&list, subtree))
806  {
808  _dbus_object_subtree_unref (subtree);
809  goto free_and_return;
810  }
811  }
812 
813  exact_match = FALSE;
814  subtree = subtree->parent;
815  }
816 
817  _dbus_verbose ("%d handlers in the path tree for this message\n",
818  _dbus_list_get_length (&list));
819 
820  /* Invoke each handler in the list */
821 
823 
824  link = _dbus_list_get_first_link (&list);
825  while (link != NULL)
826  {
827  DBusList *next = _dbus_list_get_next_link (&list, link);
828  subtree = link->data;
829 
830  /* message_function is NULL if we're unregistered
831  * due to reentrancy
832  */
833  if (subtree->message_function)
834  {
835  DBusObjectPathMessageFunction message_function;
836  void *user_data;
837 
838  message_function = subtree->message_function;
839  user_data = subtree->user_data;
840 
841 #if 0
842  _dbus_verbose (" (invoking a handler)\n");
843 #endif
844 
845 #ifdef DBUS_BUILD_TESTS
846  if (tree->connection)
847 #endif
848  {
849  _dbus_verbose ("unlock\n");
851  }
852 
853  /* FIXME you could unregister the subtree in another thread
854  * before we invoke the callback, and I can't figure out a
855  * good way to solve this.
856  */
857 
858  result = (* message_function) (tree->connection,
859  message,
860  user_data);
861 
862 #ifdef DBUS_BUILD_TESTS
863  if (tree->connection)
864 #endif
866 
868  goto free_and_return;
869  }
870 
871  link = next;
872  }
873 
874  free_and_return:
875 
877  {
878  /* This hardcoded default handler does a minimal Introspect()
879  */
880  result = handle_default_introspect_and_unlock (tree, message,
881  (const char**) path);
882  }
883  else
884  {
885 #ifdef DBUS_BUILD_TESTS
886  if (tree->connection)
887 #endif
888  {
889  _dbus_verbose ("unlock\n");
891  }
892  }
893 
894  while (list != NULL)
895  {
896  link = _dbus_list_get_first_link (&list);
897  _dbus_object_subtree_unref (link->data);
898  _dbus_list_remove_link (&list, link);
899  }
900 
901  dbus_free_string_array (path);
902 
903  return result;
904 }
905 
914 void*
916  const char **path)
917 {
918  dbus_bool_t exact_match;
919  DBusObjectSubtree *subtree;
920 
921  _dbus_assert (tree != NULL);
922  _dbus_assert (path != NULL);
923 
924  /* Find the deepest path that covers the path in the message */
925  subtree = find_handler (tree, (const char**) path, &exact_match);
926 
927  if ((subtree == NULL) || !exact_match)
928  {
929  _dbus_verbose ("No object at specified path found\n");
930  return NULL;
931  }
932 
933  return subtree->user_data;
934 }
935 
942 static DBusObjectSubtree*
943 allocate_subtree_object (const char *name)
944 {
945  int len;
946  DBusObjectSubtree *subtree;
947  const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
948 
949  _dbus_assert (name != NULL);
950 
951  len = strlen (name);
952 
953  subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
954 
955  if (subtree == NULL)
956  return NULL;
957 
958  memcpy (subtree->name, name, len + 1);
959 
960  return subtree;
961 }
962 
963 static DBusObjectSubtree*
964 _dbus_object_subtree_new (const char *name,
965  const DBusObjectPathVTable *vtable,
966  void *user_data)
967 {
968  DBusObjectSubtree *subtree;
969 
970  subtree = allocate_subtree_object (name);
971  if (subtree == NULL)
972  goto oom;
973 
974  _dbus_assert (name != NULL);
975 
976  subtree->parent = NULL;
977 
978  if (vtable)
979  {
980  subtree->message_function = vtable->message_function;
981  subtree->unregister_function = vtable->unregister_function;
982  }
983  else
984  {
985  subtree->message_function = NULL;
986  subtree->unregister_function = NULL;
987  }
988 
989  subtree->user_data = user_data;
990  subtree->refcount.value = 1;
991  subtree->subtrees = NULL;
992  subtree->n_subtrees = 0;
993  subtree->max_subtrees = 0;
994  subtree->invoke_as_fallback = FALSE;
995 
996  return subtree;
997 
998  oom:
999  return NULL;
1000 }
1001 
1002 static DBusObjectSubtree *
1003 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
1004 {
1005  _dbus_assert (subtree->refcount.value > 0);
1006  _dbus_atomic_inc (&subtree->refcount);
1007 
1008  return subtree;
1009 }
1010 
1011 static void
1012 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
1013 {
1014  _dbus_assert (subtree->refcount.value > 0);
1015 
1016  if (_dbus_atomic_dec (&subtree->refcount) == 1)
1017  {
1018  _dbus_assert (subtree->unregister_function == NULL);
1019  _dbus_assert (subtree->message_function == NULL);
1020 
1021  dbus_free (subtree->subtrees);
1022  dbus_free (subtree);
1023  }
1024 }
1025 
1038  const char **parent_path,
1039  char ***child_entries)
1040 {
1041  dbus_bool_t result;
1042 
1043  result = _dbus_object_tree_list_registered_unlocked (tree,
1044  parent_path,
1045  child_entries);
1046 
1047 #ifdef DBUS_BUILD_TESTS
1048  if (tree->connection)
1049 #endif
1050  {
1051  _dbus_verbose ("unlock\n");
1053  }
1054 
1055  return result;
1056 }
1057 
1058 
1060 #define VERBOSE_DECOMPOSE 0
1061 
1073 _dbus_decompose_path (const char* data,
1074  int len,
1075  char ***path,
1076  int *path_len)
1077 {
1078  char **retval;
1079  int n_components;
1080  int i, j, comp;
1081 
1082  _dbus_assert (data != NULL);
1083  _dbus_assert (path != NULL);
1084 
1085 #if VERBOSE_DECOMPOSE
1086  _dbus_verbose ("Decomposing path \"%s\"\n",
1087  data);
1088 #endif
1089 
1090  n_components = 0;
1091  if (len > 1) /* if path is not just "/" */
1092  {
1093  i = 0;
1094  while (i < len)
1095  {
1096  _dbus_assert (data[i] != '\0');
1097  if (data[i] == '/')
1098  n_components += 1;
1099  ++i;
1100  }
1101  }
1102 
1103  retval = dbus_new0 (char*, n_components + 1);
1104 
1105  if (retval == NULL)
1106  return FALSE;
1107 
1108  comp = 0;
1109  if (n_components == 0)
1110  i = 1;
1111  else
1112  i = 0;
1113  while (comp < n_components)
1114  {
1115  _dbus_assert (i < len);
1116 
1117  if (data[i] == '/')
1118  ++i;
1119  j = i;
1120 
1121  while (j < len && data[j] != '/')
1122  ++j;
1123 
1124  /* Now [i, j) is the path component */
1125  _dbus_assert (i < j);
1126  _dbus_assert (data[i] != '/');
1127  _dbus_assert (j == len || data[j] == '/');
1128 
1129 #if VERBOSE_DECOMPOSE
1130  _dbus_verbose (" (component in [%d,%d))\n",
1131  i, j);
1132 #endif
1133 
1134  retval[comp] = _dbus_memdup (&data[i], j - i + 1);
1135  if (retval[comp] == NULL)
1136  {
1137  dbus_free_string_array (retval);
1138  return FALSE;
1139  }
1140  retval[comp][j-i] = '\0';
1141 #if VERBOSE_DECOMPOSE
1142  _dbus_verbose (" (component %d = \"%s\")\n",
1143  comp, retval[comp]);
1144 #endif
1145 
1146  ++comp;
1147  i = j;
1148  }
1149  _dbus_assert (i == len);
1150 
1151  *path = retval;
1152  if (path_len)
1153  *path_len = n_components;
1154 
1155  return TRUE;
1156 }
1157 
1160 static char*
1161 flatten_path (const char **path)
1162 {
1163  DBusString str;
1164  char *s;
1165 
1166  if (!_dbus_string_init (&str))
1167  return NULL;
1168 
1169  if (path[0] == NULL)
1170  {
1171  if (!_dbus_string_append_byte (&str, '/'))
1172  goto nomem;
1173  }
1174  else
1175  {
1176  int i;
1177 
1178  i = 0;
1179  while (path[i])
1180  {
1181  if (!_dbus_string_append_byte (&str, '/'))
1182  goto nomem;
1183 
1184  if (!_dbus_string_append (&str, path[i]))
1185  goto nomem;
1186 
1187  ++i;
1188  }
1189  }
1190 
1191  if (!_dbus_string_steal_data (&str, &s))
1192  goto nomem;
1193 
1194  _dbus_string_free (&str);
1195 
1196  return s;
1197 
1198  nomem:
1199  _dbus_string_free (&str);
1200  return NULL;
1201 }
1202 
1203 
1204 #ifdef DBUS_BUILD_TESTS
1205 
1206 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1207 
1208 #include "dbus-test.h"
1209 #include <stdio.h>
1210 
1211 typedef enum
1212 {
1213  STR_EQUAL,
1214  STR_PREFIX,
1215  STR_DIFFERENT
1216 } StrComparison;
1217 
1218 /* Returns TRUE if container is a parent of child
1219  */
1220 static StrComparison
1221 path_contains (const char **container,
1222  const char **child)
1223 {
1224  int i;
1225 
1226  i = 0;
1227  while (child[i] != NULL)
1228  {
1229  int v;
1230 
1231  if (container[i] == NULL)
1232  return STR_PREFIX; /* container ran out, child continues;
1233  * thus the container is a parent of the
1234  * child.
1235  */
1236 
1237  _dbus_assert (container[i] != NULL);
1238  _dbus_assert (child[i] != NULL);
1239 
1240  v = strcmp (container[i], child[i]);
1241 
1242  if (v != 0)
1243  return STR_DIFFERENT; /* they overlap until here and then are different,
1244  * not overlapping
1245  */
1246 
1247  ++i;
1248  }
1249 
1250  /* Child ran out; if container also did, they are equal;
1251  * otherwise, the child is a parent of the container.
1252  */
1253  if (container[i] == NULL)
1254  return STR_EQUAL;
1255  else
1256  return STR_DIFFERENT;
1257 }
1258 
1259 #if 0
1260 static void
1261 spew_subtree_recurse (DBusObjectSubtree *subtree,
1262  int indent)
1263 {
1264  int i;
1265 
1266  i = 0;
1267  while (i < indent)
1268  {
1269  _dbus_verbose (" ");
1270  ++i;
1271  }
1272 
1273  _dbus_verbose ("%s (%d children)\n",
1274  subtree->name, subtree->n_subtrees);
1275 
1276  i = 0;
1277  while (i < subtree->n_subtrees)
1278  {
1279  spew_subtree_recurse (subtree->subtrees[i], indent + 2);
1280 
1281  ++i;
1282  }
1283 }
1284 
1285 static void
1286 spew_tree (DBusObjectTree *tree)
1287 {
1288  spew_subtree_recurse (tree->root, 0);
1289 }
1290 #endif
1291 
1295 typedef struct
1296 {
1297  const char **path;
1298  dbus_bool_t handler_fallback;
1299  dbus_bool_t message_handled;
1300  dbus_bool_t handler_unregistered;
1301 } TreeTestData;
1302 
1303 
1304 static void
1305 test_unregister_function (DBusConnection *connection,
1306  void *user_data)
1307 {
1308  TreeTestData *ttd = user_data;
1309 
1310  ttd->handler_unregistered = TRUE;
1311 }
1312 
1313 static DBusHandlerResult
1314 test_message_function (DBusConnection *connection,
1315  DBusMessage *message,
1316  void *user_data)
1317 {
1318  TreeTestData *ttd = user_data;
1319 
1320  ttd->message_handled = TRUE;
1321 
1323 }
1324 
1325 static dbus_bool_t
1326 do_register (DBusObjectTree *tree,
1327  const char **path,
1328  dbus_bool_t fallback,
1329  int i,
1330  TreeTestData *tree_test_data)
1331 {
1332  DBusObjectPathVTable vtable = { test_unregister_function,
1333  test_message_function, NULL };
1334 
1335  tree_test_data[i].message_handled = FALSE;
1336  tree_test_data[i].handler_unregistered = FALSE;
1337  tree_test_data[i].handler_fallback = fallback;
1338  tree_test_data[i].path = path;
1339 
1340  if (!_dbus_object_tree_register (tree, fallback, path,
1341  &vtable,
1342  &tree_test_data[i],
1343  NULL))
1344  return FALSE;
1345 
1347  &tree_test_data[i]);
1348 
1349  return TRUE;
1350 }
1351 
1352 static dbus_bool_t
1353 do_test_dispatch (DBusObjectTree *tree,
1354  const char **path,
1355  int i,
1356  TreeTestData *tree_test_data,
1357  int n_test_data)
1358 {
1359  DBusMessage *message;
1360  int j;
1361  DBusHandlerResult result;
1362  char *flat;
1363 
1364  message = NULL;
1365 
1366  flat = flatten_path (path);
1367  if (flat == NULL)
1368  goto oom;
1369 
1371  flat,
1372  "org.freedesktop.TestInterface",
1373  "Foo");
1374  dbus_free (flat);
1375  if (message == NULL)
1376  goto oom;
1377 
1378  j = 0;
1379  while (j < n_test_data)
1380  {
1381  tree_test_data[j].message_handled = FALSE;
1382  ++j;
1383  }
1384 
1385  result = _dbus_object_tree_dispatch_and_unlock (tree, message);
1386  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
1387  goto oom;
1388 
1389  _dbus_assert (tree_test_data[i].message_handled);
1390 
1391  j = 0;
1392  while (j < n_test_data)
1393  {
1394  if (tree_test_data[j].message_handled)
1395  {
1396  if (tree_test_data[j].handler_fallback)
1397  _dbus_assert (path_contains (tree_test_data[j].path,
1398  path) != STR_DIFFERENT);
1399  else
1400  _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
1401  }
1402  else
1403  {
1404  if (tree_test_data[j].handler_fallback)
1405  _dbus_assert (path_contains (tree_test_data[j].path,
1406  path) == STR_DIFFERENT);
1407  else
1408  _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
1409  }
1410 
1411  ++j;
1412  }
1413 
1414  dbus_message_unref (message);
1415 
1416  return TRUE;
1417 
1418  oom:
1419  if (message)
1420  dbus_message_unref (message);
1421  return FALSE;
1422 }
1423 
1424 static size_t
1425 string_array_length (const char **array)
1426 {
1427  size_t i;
1428  for (i = 0; array[i]; i++) ;
1429  return i;
1430 }
1431 
1432 typedef struct
1433 {
1434  const char *path;
1435  const char *result[20];
1436 } DecomposePathTest;
1437 
1438 static DecomposePathTest decompose_tests[] = {
1439  { "/foo", { "foo", NULL } },
1440  { "/foo/bar", { "foo", "bar", NULL } },
1441  { "/", { NULL } },
1442  { "/a/b", { "a", "b", NULL } },
1443  { "/a/b/c", { "a", "b", "c", NULL } },
1444  { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
1445  { "/foo/bar/q", { "foo", "bar", "q", NULL } },
1446  { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
1447 };
1448 
1449 static dbus_bool_t
1450 run_decompose_tests (void)
1451 {
1452  int i;
1453 
1454  i = 0;
1455  while (i < _DBUS_N_ELEMENTS (decompose_tests))
1456  {
1457  char **result;
1458  int result_len;
1459  int expected_len;
1460 
1461  if (!_dbus_decompose_path (decompose_tests[i].path,
1462  strlen (decompose_tests[i].path),
1463  &result, &result_len))
1464  return FALSE;
1465 
1466  expected_len = string_array_length (decompose_tests[i].result);
1467 
1468  if (result_len != (int) string_array_length ((const char**)result) ||
1469  expected_len != result_len ||
1470  path_contains (decompose_tests[i].result,
1471  (const char**) result) != STR_EQUAL)
1472  {
1473  int real_len = string_array_length ((const char**)result);
1474  _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
1475  decompose_tests[i].path, expected_len, result_len,
1476  real_len);
1477  _dbus_warn ("Decompose resulted in elements: { ");
1478  i = 0;
1479  while (i < real_len)
1480  {
1481  _dbus_warn ("\"%s\"%s", result[i],
1482  (i + 1) == real_len ? "" : ", ");
1483  ++i;
1484  }
1485  _dbus_warn ("}\n");
1486  _dbus_assert_not_reached ("path decompose failed\n");
1487  }
1488 
1489  dbus_free_string_array (result);
1490 
1491  ++i;
1492  }
1493 
1494  return TRUE;
1495 }
1496 
1497 static dbus_bool_t
1498 object_tree_test_iteration (void *data)
1499 {
1500  const char *path0[] = { NULL };
1501  const char *path1[] = { "foo", NULL };
1502  const char *path2[] = { "foo", "bar", NULL };
1503  const char *path3[] = { "foo", "bar", "baz", NULL };
1504  const char *path4[] = { "foo", "bar", "boo", NULL };
1505  const char *path5[] = { "blah", NULL };
1506  const char *path6[] = { "blah", "boof", NULL };
1507  const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
1508  const char *path8[] = { "childless", NULL };
1509  DBusObjectTree *tree;
1510  TreeTestData tree_test_data[9];
1511  int i;
1512  dbus_bool_t exact_match;
1513 
1514  if (!run_decompose_tests ())
1515  return FALSE;
1516 
1517  tree = NULL;
1518 
1519  tree = _dbus_object_tree_new (NULL);
1520  if (tree == NULL)
1521  goto out;
1522 
1523  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1524  goto out;
1525 
1526  _dbus_assert (find_subtree (tree, path0, NULL));
1527  _dbus_assert (!find_subtree (tree, path1, NULL));
1528  _dbus_assert (!find_subtree (tree, path2, NULL));
1529  _dbus_assert (!find_subtree (tree, path3, NULL));
1530  _dbus_assert (!find_subtree (tree, path4, NULL));
1531  _dbus_assert (!find_subtree (tree, path5, NULL));
1532  _dbus_assert (!find_subtree (tree, path6, NULL));
1533  _dbus_assert (!find_subtree (tree, path7, NULL));
1534  _dbus_assert (!find_subtree (tree, path8, NULL));
1535 
1536  _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1537  _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
1538  _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
1539  _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
1540  _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
1541  _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1542  _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1543  _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1544  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1545 
1546  if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1547  goto out;
1548 
1549  _dbus_assert (find_subtree (tree, path0, NULL));
1550  _dbus_assert (find_subtree (tree, path1, NULL));
1551  _dbus_assert (!find_subtree (tree, path2, NULL));
1552  _dbus_assert (!find_subtree (tree, path3, NULL));
1553  _dbus_assert (!find_subtree (tree, path4, NULL));
1554  _dbus_assert (!find_subtree (tree, path5, NULL));
1555  _dbus_assert (!find_subtree (tree, path6, NULL));
1556  _dbus_assert (!find_subtree (tree, path7, NULL));
1557  _dbus_assert (!find_subtree (tree, path8, NULL));
1558 
1559  _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
1560  _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match);
1561  _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
1562  _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
1563  _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
1564  _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
1565  _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
1566  _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
1567  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1568 
1569  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1570  goto out;
1571 
1572  _dbus_assert (find_subtree (tree, path1, NULL));
1573  _dbus_assert (find_subtree (tree, path2, NULL));
1574  _dbus_assert (!find_subtree (tree, path3, NULL));
1575  _dbus_assert (!find_subtree (tree, path4, NULL));
1576  _dbus_assert (!find_subtree (tree, path5, NULL));
1577  _dbus_assert (!find_subtree (tree, path6, NULL));
1578  _dbus_assert (!find_subtree (tree, path7, NULL));
1579  _dbus_assert (!find_subtree (tree, path8, NULL));
1580 
1581  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1582  goto out;
1583 
1584  _dbus_assert (find_subtree (tree, path0, NULL));
1585  _dbus_assert (find_subtree (tree, path1, NULL));
1586  _dbus_assert (find_subtree (tree, path2, NULL));
1587  _dbus_assert (find_subtree (tree, path3, NULL));
1588  _dbus_assert (!find_subtree (tree, path4, NULL));
1589  _dbus_assert (!find_subtree (tree, path5, NULL));
1590  _dbus_assert (!find_subtree (tree, path6, NULL));
1591  _dbus_assert (!find_subtree (tree, path7, NULL));
1592  _dbus_assert (!find_subtree (tree, path8, NULL));
1593 
1594  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1595  goto out;
1596 
1597  _dbus_assert (find_subtree (tree, path0, NULL));
1598  _dbus_assert (find_subtree (tree, path1, NULL));
1599  _dbus_assert (find_subtree (tree, path2, NULL));
1600  _dbus_assert (find_subtree (tree, path3, NULL));
1601  _dbus_assert (find_subtree (tree, path4, NULL));
1602  _dbus_assert (!find_subtree (tree, path5, NULL));
1603  _dbus_assert (!find_subtree (tree, path6, NULL));
1604  _dbus_assert (!find_subtree (tree, path7, NULL));
1605  _dbus_assert (!find_subtree (tree, path8, NULL));
1606 
1607  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1608  goto out;
1609 
1610  _dbus_assert (find_subtree (tree, path0, NULL));
1611  _dbus_assert (find_subtree (tree, path1, NULL));
1612  _dbus_assert (find_subtree (tree, path2, NULL));
1613  _dbus_assert (find_subtree (tree, path3, NULL));
1614  _dbus_assert (find_subtree (tree, path4, NULL));
1615  _dbus_assert (find_subtree (tree, path5, NULL));
1616  _dbus_assert (!find_subtree (tree, path6, NULL));
1617  _dbus_assert (!find_subtree (tree, path7, NULL));
1618  _dbus_assert (!find_subtree (tree, path8, NULL));
1619 
1620  _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1621  _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1622  _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1623  _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1624  _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1625  _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1626  _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
1627  _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
1628  _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
1629 
1630  if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1631  goto out;
1632 
1633  _dbus_assert (find_subtree (tree, path0, NULL));
1634  _dbus_assert (find_subtree (tree, path1, NULL));
1635  _dbus_assert (find_subtree (tree, path2, NULL));
1636  _dbus_assert (find_subtree (tree, path3, NULL));
1637  _dbus_assert (find_subtree (tree, path4, NULL));
1638  _dbus_assert (find_subtree (tree, path5, NULL));
1639  _dbus_assert (find_subtree (tree, path6, NULL));
1640  _dbus_assert (!find_subtree (tree, path7, NULL));
1641  _dbus_assert (!find_subtree (tree, path8, NULL));
1642 
1643  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1644  goto out;
1645 
1646  _dbus_assert (find_subtree (tree, path0, NULL));
1647  _dbus_assert (find_subtree (tree, path1, NULL));
1648  _dbus_assert (find_subtree (tree, path2, NULL));
1649  _dbus_assert (find_subtree (tree, path3, NULL));
1650  _dbus_assert (find_subtree (tree, path4, NULL));
1651  _dbus_assert (find_subtree (tree, path5, NULL));
1652  _dbus_assert (find_subtree (tree, path6, NULL));
1653  _dbus_assert (find_subtree (tree, path7, NULL));
1654  _dbus_assert (!find_subtree (tree, path8, NULL));
1655 
1656  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1657  goto out;
1658 
1659  _dbus_assert (find_subtree (tree, path0, NULL));
1660  _dbus_assert (find_subtree (tree, path1, NULL));
1661  _dbus_assert (find_subtree (tree, path2, NULL));
1662  _dbus_assert (find_subtree (tree, path3, NULL));
1663  _dbus_assert (find_subtree (tree, path4, NULL));
1664  _dbus_assert (find_subtree (tree, path5, NULL));
1665  _dbus_assert (find_subtree (tree, path6, NULL));
1666  _dbus_assert (find_subtree (tree, path7, NULL));
1667  _dbus_assert (find_subtree (tree, path8, NULL));
1668 
1669  _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match);
1670  _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
1671  _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
1672  _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
1673  _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
1674  _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
1675  _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
1676  _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
1677  _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
1678 
1679  /* test the list_registered function */
1680 
1681  {
1682  const char *root[] = { NULL };
1683  char **child_entries;
1684  int nb;
1685 
1686  _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
1687  if (child_entries != NULL)
1688  {
1689  nb = string_array_length ((const char**)child_entries);
1690  _dbus_assert (nb == 1);
1691  dbus_free_string_array (child_entries);
1692  }
1693 
1694  _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
1695  if (child_entries != NULL)
1696  {
1697  nb = string_array_length ((const char**)child_entries);
1698  _dbus_assert (nb == 2);
1699  dbus_free_string_array (child_entries);
1700  }
1701 
1702  _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
1703  if (child_entries != NULL)
1704  {
1705  nb = string_array_length ((const char**)child_entries);
1706  _dbus_assert (nb == 0);
1707  dbus_free_string_array (child_entries);
1708  }
1709 
1710  _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
1711  if (child_entries != NULL)
1712  {
1713  nb = string_array_length ((const char**)child_entries);
1714  _dbus_assert (nb == 3);
1715  dbus_free_string_array (child_entries);
1716  }
1717  }
1718 
1719  /* Check that destroying tree calls unregister funcs */
1720  _dbus_object_tree_unref (tree);
1721 
1722  i = 0;
1723  while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1724  {
1725  _dbus_assert (tree_test_data[i].handler_unregistered);
1726  _dbus_assert (!tree_test_data[i].message_handled);
1727  ++i;
1728  }
1729 
1730  /* Now start again and try the individual unregister function */
1731  tree = _dbus_object_tree_new (NULL);
1732  if (tree == NULL)
1733  goto out;
1734 
1735  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1736  goto out;
1737  if (!do_register (tree, path1, TRUE, 1, tree_test_data))
1738  goto out;
1739  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1740  goto out;
1741  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1742  goto out;
1743  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1744  goto out;
1745  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1746  goto out;
1747  if (!do_register (tree, path6, TRUE, 6, tree_test_data))
1748  goto out;
1749  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1750  goto out;
1751  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1752  goto out;
1753 
1756 
1757  _dbus_assert (!find_subtree (tree, path0, NULL));
1758  _dbus_assert (find_subtree (tree, path1, NULL));
1759  _dbus_assert (find_subtree (tree, path2, NULL));
1760  _dbus_assert (find_subtree (tree, path3, NULL));
1761  _dbus_assert (find_subtree (tree, path4, NULL));
1762  _dbus_assert (find_subtree (tree, path5, NULL));
1763  _dbus_assert (find_subtree (tree, path6, NULL));
1764  _dbus_assert (find_subtree (tree, path7, NULL));
1765  _dbus_assert (find_subtree (tree, path8, NULL));
1766 
1769 
1770  _dbus_assert (!find_subtree (tree, path0, NULL));
1771  _dbus_assert (!find_subtree (tree, path1, NULL));
1772  _dbus_assert (find_subtree (tree, path2, NULL));
1773  _dbus_assert (find_subtree (tree, path3, NULL));
1774  _dbus_assert (find_subtree (tree, path4, NULL));
1775  _dbus_assert (find_subtree (tree, path5, NULL));
1776  _dbus_assert (find_subtree (tree, path6, NULL));
1777  _dbus_assert (find_subtree (tree, path7, NULL));
1778  _dbus_assert (find_subtree (tree, path8, NULL));
1779 
1782 
1783  _dbus_assert (!find_subtree (tree, path0, NULL));
1784  _dbus_assert (!find_subtree (tree, path1, NULL));
1785  _dbus_assert (!find_subtree (tree, path2, NULL));
1786  _dbus_assert (find_subtree (tree, path3, NULL));
1787  _dbus_assert (find_subtree (tree, path4, NULL));
1788  _dbus_assert (find_subtree (tree, path5, NULL));
1789  _dbus_assert (find_subtree (tree, path6, NULL));
1790  _dbus_assert (find_subtree (tree, path7, NULL));
1791  _dbus_assert (find_subtree (tree, path8, NULL));
1792 
1795 
1796  _dbus_assert (!find_subtree (tree, path0, NULL));
1797  _dbus_assert (!find_subtree (tree, path1, NULL));
1798  _dbus_assert (!find_subtree (tree, path2, NULL));
1799  _dbus_assert (!find_subtree (tree, path3, NULL));
1800  _dbus_assert (find_subtree (tree, path4, NULL));
1801  _dbus_assert (find_subtree (tree, path5, NULL));
1802  _dbus_assert (find_subtree (tree, path6, NULL));
1803  _dbus_assert (find_subtree (tree, path7, NULL));
1804  _dbus_assert (find_subtree (tree, path8, NULL));
1805 
1808 
1809  _dbus_assert (!find_subtree (tree, path0, NULL));
1810  _dbus_assert (!find_subtree (tree, path1, NULL));
1811  _dbus_assert (!find_subtree (tree, path2, NULL));
1812  _dbus_assert (!find_subtree (tree, path3, NULL));
1813  _dbus_assert (!find_subtree (tree, path4, NULL));
1814  _dbus_assert (find_subtree (tree, path5, NULL));
1815  _dbus_assert (find_subtree (tree, path6, NULL));
1816  _dbus_assert (find_subtree (tree, path7, NULL));
1817  _dbus_assert (find_subtree (tree, path8, NULL));
1818 
1821 
1822  _dbus_assert (!find_subtree (tree, path0, NULL));
1823  _dbus_assert (!find_subtree (tree, path1, NULL));
1824  _dbus_assert (!find_subtree (tree, path2, NULL));
1825  _dbus_assert (!find_subtree (tree, path3, NULL));
1826  _dbus_assert (!find_subtree (tree, path4, NULL));
1827  _dbus_assert (!find_subtree (tree, path5, NULL));
1828  _dbus_assert (find_subtree (tree, path6, NULL));
1829  _dbus_assert (find_subtree (tree, path7, NULL));
1830  _dbus_assert (find_subtree (tree, path8, NULL));
1831 
1834 
1835  _dbus_assert (!find_subtree (tree, path0, NULL));
1836  _dbus_assert (!find_subtree (tree, path1, NULL));
1837  _dbus_assert (!find_subtree (tree, path2, NULL));
1838  _dbus_assert (!find_subtree (tree, path3, NULL));
1839  _dbus_assert (!find_subtree (tree, path4, NULL));
1840  _dbus_assert (!find_subtree (tree, path5, NULL));
1841  _dbus_assert (!find_subtree (tree, path6, NULL));
1842  _dbus_assert (find_subtree (tree, path7, NULL));
1843  _dbus_assert (find_subtree (tree, path8, NULL));
1844 
1847 
1848  _dbus_assert (!find_subtree (tree, path0, NULL));
1849  _dbus_assert (!find_subtree (tree, path1, NULL));
1850  _dbus_assert (!find_subtree (tree, path2, NULL));
1851  _dbus_assert (!find_subtree (tree, path3, NULL));
1852  _dbus_assert (!find_subtree (tree, path4, NULL));
1853  _dbus_assert (!find_subtree (tree, path5, NULL));
1854  _dbus_assert (!find_subtree (tree, path6, NULL));
1855  _dbus_assert (!find_subtree (tree, path7, NULL));
1856  _dbus_assert (find_subtree (tree, path8, NULL));
1857 
1860 
1861  _dbus_assert (!find_subtree (tree, path0, NULL));
1862  _dbus_assert (!find_subtree (tree, path1, NULL));
1863  _dbus_assert (!find_subtree (tree, path2, NULL));
1864  _dbus_assert (!find_subtree (tree, path3, NULL));
1865  _dbus_assert (!find_subtree (tree, path4, NULL));
1866  _dbus_assert (!find_subtree (tree, path5, NULL));
1867  _dbus_assert (!find_subtree (tree, path6, NULL));
1868  _dbus_assert (!find_subtree (tree, path7, NULL));
1869  _dbus_assert (!find_subtree (tree, path8, NULL));
1870 
1871  i = 0;
1872  while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
1873  {
1874  _dbus_assert (tree_test_data[i].handler_unregistered);
1875  _dbus_assert (!tree_test_data[i].message_handled);
1876  ++i;
1877  }
1878 
1879  /* Register it all again, and test dispatch */
1880 
1881  if (!do_register (tree, path0, TRUE, 0, tree_test_data))
1882  goto out;
1883  if (!do_register (tree, path1, FALSE, 1, tree_test_data))
1884  goto out;
1885  if (!do_register (tree, path2, TRUE, 2, tree_test_data))
1886  goto out;
1887  if (!do_register (tree, path3, TRUE, 3, tree_test_data))
1888  goto out;
1889  if (!do_register (tree, path4, TRUE, 4, tree_test_data))
1890  goto out;
1891  if (!do_register (tree, path5, TRUE, 5, tree_test_data))
1892  goto out;
1893  if (!do_register (tree, path6, FALSE, 6, tree_test_data))
1894  goto out;
1895  if (!do_register (tree, path7, TRUE, 7, tree_test_data))
1896  goto out;
1897  if (!do_register (tree, path8, TRUE, 8, tree_test_data))
1898  goto out;
1899 
1900 #if 0
1901  spew_tree (tree);
1902 #endif
1903 
1904  if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1905  goto out;
1906  if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1907  goto out;
1908  if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1909  goto out;
1910  if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1911  goto out;
1912  if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1913  goto out;
1914  if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1915  goto out;
1916  if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1917  goto out;
1918  if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1919  goto out;
1920  if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
1921  goto out;
1922 
1923  out:
1924  if (tree)
1925  {
1926  /* test ref */
1927  _dbus_object_tree_ref (tree);
1928  _dbus_object_tree_unref (tree);
1929  _dbus_object_tree_unref (tree);
1930  }
1931 
1932  return TRUE;
1933 }
1934 
1941 _dbus_object_tree_test (void)
1942 {
1943  _dbus_test_oom_handling ("object tree",
1944  object_tree_test_iteration,
1945  NULL);
1946 
1947  return TRUE;
1948 }
1949 
1950 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
1951 
1952 #endif /* DBUS_BUILD_TESTS */