D-Bus  1.8.20
dbus-object-tree.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-object-tree.c  DBusObjectTree (internals of DBusConnection)
00003  *
00004  * Copyright (C) 2003, 2005  Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-object-tree.h"
00026 #include "dbus-connection-internal.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-hash.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-string.h"
00031 #include <string.h>
00032 #include <stdlib.h>
00033 
00046 typedef struct DBusObjectSubtree DBusObjectSubtree;
00047 
00048 static DBusObjectSubtree* _dbus_object_subtree_new   (const char                  *name,
00049                                                       const DBusObjectPathVTable  *vtable,
00050                                                       void                        *user_data);
00051 static DBusObjectSubtree* _dbus_object_subtree_ref   (DBusObjectSubtree           *subtree);
00052 static void               _dbus_object_subtree_unref (DBusObjectSubtree           *subtree);
00053 
00057 struct DBusObjectTree
00058 {
00059   int                 refcount;   
00060   DBusConnection     *connection; 
00062   DBusObjectSubtree  *root;       
00063 };
00064 
00070 struct DBusObjectSubtree
00071 {
00072   DBusAtomic                         refcount;            
00073   DBusObjectSubtree                 *parent;              
00074   DBusObjectPathUnregisterFunction   unregister_function; 
00075   DBusObjectPathMessageFunction      message_function;    
00076   void                              *user_data;           
00077   DBusObjectSubtree                **subtrees;            
00078   int                                n_subtrees;          
00079   int                                max_subtrees;        
00080   unsigned int                       invoke_as_fallback : 1; 
00081   char                               name[1]; 
00082 };
00083 
00091 DBusObjectTree*
00092 _dbus_object_tree_new (DBusConnection *connection)
00093 {
00094   DBusObjectTree *tree;
00095 
00096   /* the connection passed in here isn't fully constructed,
00097    * so don't do anything more than store a pointer to
00098    * it
00099    */
00100 
00101   tree = dbus_new0 (DBusObjectTree, 1);
00102   if (tree == NULL)
00103     goto oom;
00104 
00105   tree->refcount = 1;
00106   tree->connection = connection;
00107   tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
00108   if (tree->root == NULL)
00109     goto oom;
00110   tree->root->invoke_as_fallback = TRUE;
00111   
00112   return tree;
00113 
00114  oom:
00115   if (tree)
00116     {
00117       dbus_free (tree);
00118     }
00119 
00120   return NULL;
00121 }
00122 
00128 DBusObjectTree *
00129 _dbus_object_tree_ref (DBusObjectTree *tree)
00130 {
00131   _dbus_assert (tree->refcount > 0);
00132 
00133   tree->refcount += 1;
00134 
00135   return tree;
00136 }
00137 
00142 void
00143 _dbus_object_tree_unref (DBusObjectTree *tree)
00144 {
00145   _dbus_assert (tree->refcount > 0);
00146 
00147   tree->refcount -= 1;
00148 
00149   if (tree->refcount == 0)
00150     {
00151       _dbus_object_tree_free_all_unlocked (tree);
00152 
00153       dbus_free (tree);
00154     }
00155 }
00156 
00160 #define VERBOSE_FIND 0
00161 
00162 static DBusObjectSubtree*
00163 find_subtree_recurse (DBusObjectSubtree  *subtree,
00164                       const char        **path,
00165                       dbus_bool_t         create_if_not_found,
00166                       int                *index_in_parent,
00167                       dbus_bool_t        *exact_match)
00168 {
00169   int i, j;
00170   dbus_bool_t return_deepest_match;
00171 
00172   return_deepest_match = exact_match != NULL;
00173 
00174   _dbus_assert (!(return_deepest_match && create_if_not_found));
00175 
00176   if (path[0] == NULL)
00177     {
00178 #if VERBOSE_FIND
00179       _dbus_verbose ("  path exhausted, returning %s\n",
00180                      subtree->name);
00181 #endif
00182       if (exact_match != NULL)
00183         *exact_match = TRUE;
00184       return subtree;
00185     }
00186 
00187 #if VERBOSE_FIND
00188   _dbus_verbose ("  searching children of %s for %s\n",
00189                  subtree->name, path[0]);
00190 #endif
00191   
00192   i = 0;
00193   j = subtree->n_subtrees;
00194   while (i < j)
00195     {
00196       int k, v;
00197 
00198       k = (i + j) / 2;
00199       v = strcmp (path[0], subtree->subtrees[k]->name);
00200 
00201 #if VERBOSE_FIND
00202       _dbus_verbose ("  %s cmp %s = %d\n",
00203                      path[0], subtree->subtrees[k]->name,
00204                      v);
00205 #endif
00206       
00207       if (v == 0)
00208         {
00209           if (index_in_parent)
00210             {
00211 #if VERBOSE_FIND
00212               _dbus_verbose ("  storing parent index %d\n", k);
00213 #endif
00214               *index_in_parent = k;
00215             }
00216 
00217           if (return_deepest_match)
00218             {
00219               DBusObjectSubtree *next;
00220 
00221               next = find_subtree_recurse (subtree->subtrees[k],
00222                                            &path[1], create_if_not_found, 
00223                                            index_in_parent, exact_match);
00224               if (next == NULL &&
00225                   subtree->invoke_as_fallback)
00226                 {
00227 #if VERBOSE_FIND
00228                   _dbus_verbose ("  no deeper match found, returning %s\n",
00229                                  subtree->name);
00230 #endif
00231                   if (exact_match != NULL)
00232                     *exact_match = FALSE;
00233                   return subtree;
00234                 }
00235               else
00236                 return next;
00237             }
00238           else
00239             return find_subtree_recurse (subtree->subtrees[k],
00240                                          &path[1], create_if_not_found, 
00241                                          index_in_parent, exact_match);
00242         }
00243       else if (v < 0)
00244         {
00245           j = k;
00246         }
00247       else
00248         {
00249           i = k + 1;
00250         }
00251     }
00252 
00253 #if VERBOSE_FIND
00254   _dbus_verbose ("  no match found, current tree %s, create_if_not_found = %d\n",
00255                  subtree->name, create_if_not_found);
00256 #endif
00257   
00258   if (create_if_not_found)
00259     {
00260       DBusObjectSubtree* child;
00261       int child_pos, new_n_subtrees;
00262 
00263 #if VERBOSE_FIND
00264       _dbus_verbose ("  creating subtree %s\n",
00265                      path[0]);
00266 #endif
00267       
00268       child = _dbus_object_subtree_new (path[0],
00269                                         NULL, NULL);
00270       if (child == NULL)
00271         return NULL;
00272 
00273       new_n_subtrees = subtree->n_subtrees + 1;
00274       if (new_n_subtrees > subtree->max_subtrees)
00275         {
00276           int new_max_subtrees;
00277           DBusObjectSubtree **new_subtrees;
00278 
00279           new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees;
00280           new_subtrees = dbus_realloc (subtree->subtrees,
00281                                        new_max_subtrees * sizeof (DBusObjectSubtree*));
00282           if (new_subtrees == NULL)
00283             {
00284               _dbus_object_subtree_unref (child);
00285               return NULL;
00286             }
00287           subtree->subtrees = new_subtrees;
00288           subtree->max_subtrees = new_max_subtrees;
00289         }
00290 
00291       /* The binary search failed, so i == j points to the 
00292          place the child should be inserted. */
00293       child_pos = i;
00294       _dbus_assert (child_pos < new_n_subtrees &&
00295                     new_n_subtrees <= subtree->max_subtrees);
00296       if (child_pos + 1 < new_n_subtrees)
00297         {
00298           memmove (&subtree->subtrees[child_pos+1], 
00299                    &subtree->subtrees[child_pos], 
00300                    (new_n_subtrees - child_pos - 1) * 
00301                    sizeof subtree->subtrees[0]);
00302         }
00303       subtree->subtrees[child_pos] = child;
00304 
00305       if (index_in_parent)
00306         *index_in_parent = child_pos;
00307       subtree->n_subtrees = new_n_subtrees;
00308       child->parent = subtree;
00309 
00310       return find_subtree_recurse (child,
00311                                    &path[1], create_if_not_found, 
00312                                    index_in_parent, exact_match);
00313     }
00314   else
00315     {
00316       if (exact_match != NULL)
00317         *exact_match = FALSE;
00318       return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
00319     }
00320 }
00321 
00322 static DBusObjectSubtree*
00323 find_subtree (DBusObjectTree *tree,
00324               const char    **path,
00325               int            *index_in_parent)
00326 {
00327   DBusObjectSubtree *subtree;
00328 
00329 #if VERBOSE_FIND
00330   _dbus_verbose ("Looking for exact registered subtree\n");
00331 #endif
00332   
00333   subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL);
00334 
00335   if (subtree && subtree->message_function == NULL)
00336     return NULL;
00337   else
00338     return subtree;
00339 }
00340 
00341 static DBusObjectSubtree*
00342 lookup_subtree (DBusObjectTree *tree,
00343                 const char    **path)
00344 {
00345 #if VERBOSE_FIND
00346   _dbus_verbose ("Looking for subtree\n");
00347 #endif
00348   return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
00349 }
00350 
00351 static DBusObjectSubtree*
00352 find_handler (DBusObjectTree *tree,
00353               const char    **path,
00354               dbus_bool_t    *exact_match)
00355 {
00356 #if VERBOSE_FIND
00357   _dbus_verbose ("Looking for deepest handler\n");
00358 #endif
00359   _dbus_assert (exact_match != NULL);
00360 
00361   *exact_match = FALSE; /* ensure always initialized */
00362   
00363   return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match);
00364 }
00365 
00366 static DBusObjectSubtree*
00367 ensure_subtree (DBusObjectTree *tree,
00368                 const char    **path)
00369 {
00370 #if VERBOSE_FIND
00371   _dbus_verbose ("Ensuring subtree\n");
00372 #endif
00373   return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL);
00374 }
00375 
00376 static char *flatten_path (const char **path);
00377 
00390 dbus_bool_t
00391 _dbus_object_tree_register (DBusObjectTree              *tree,
00392                             dbus_bool_t                  fallback,
00393                             const char                 **path,
00394                             const DBusObjectPathVTable  *vtable,
00395                             void                        *user_data,
00396                             DBusError                   *error)
00397 {
00398   DBusObjectSubtree  *subtree;
00399 
00400   _dbus_assert (tree != NULL);
00401   _dbus_assert (vtable->message_function != NULL);
00402   _dbus_assert (path != NULL);
00403 
00404   subtree = ensure_subtree (tree, path);
00405   if (subtree == NULL)
00406     {
00407       _DBUS_SET_OOM (error);
00408       return FALSE;
00409     }
00410 
00411   if (subtree->message_function != NULL)
00412     {
00413       if (error != NULL)
00414         {
00415           char *complete_path = flatten_path (path);
00416 
00417           dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE,
00418                           "A handler is already registered for %s",
00419                           complete_path ? complete_path
00420                                         : "(cannot represent path: out of memory!)");
00421 
00422           dbus_free (complete_path);
00423         }
00424 
00425       return FALSE;
00426     }
00427 
00428   subtree->message_function = vtable->message_function;
00429   subtree->unregister_function = vtable->unregister_function;
00430   subtree->user_data = user_data;
00431   subtree->invoke_as_fallback = fallback != FALSE;
00432 
00433   return TRUE;
00434 }
00435 
00447 static dbus_bool_t
00448 unregister_subtree (DBusObjectSubtree                 *subtree,
00449                     DBusObjectPathUnregisterFunction  *unregister_function_out,
00450                     void                             **user_data_out)
00451 {
00452   _dbus_assert (subtree != NULL);
00453   _dbus_assert (unregister_function_out != NULL);
00454   _dbus_assert (user_data_out != NULL);
00455 
00456   /* Confirm subtree is registered */
00457   if (subtree->message_function != NULL)
00458     {
00459       subtree->message_function = NULL;
00460 
00461       *unregister_function_out = subtree->unregister_function;
00462       *user_data_out = subtree->user_data;
00463 
00464       subtree->unregister_function = NULL;
00465       subtree->user_data = NULL;
00466 
00467       return TRUE;
00468     }
00469   else
00470     {
00471       /* Assert that this unregistered subtree is either the root node or has
00472          children, otherwise we have a dangling path which should never
00473          happen */
00474       _dbus_assert (subtree->parent == NULL || subtree->n_subtrees > 0);
00475 
00476       /* The subtree is not registered */
00477       return FALSE;
00478     }
00479 }
00480 
00492 static dbus_bool_t
00493 attempt_child_removal (DBusObjectSubtree  *parent,
00494                        int child_index)
00495 {
00496   /* Candidate for removal */
00497   DBusObjectSubtree* candidate;
00498 
00499   _dbus_assert (parent != NULL);
00500   _dbus_assert (child_index >= 0 && child_index < parent->n_subtrees);
00501 
00502   candidate = parent->subtrees[child_index];
00503   _dbus_assert (candidate != NULL);
00504 
00505   if (candidate->n_subtrees == 0 && candidate->message_function == NULL)
00506     {
00507       /* The candidate node is childless and is not a registered
00508          path, so... */
00509 
00510       /* ... remove it from its parent... */
00511       /* Assumes a 0-byte memmove is OK */
00512       memmove (&parent->subtrees[child_index],
00513                &parent->subtrees[child_index + 1],
00514                (parent->n_subtrees - child_index - 1)
00515                * sizeof (parent->subtrees[0]));
00516       parent->n_subtrees -= 1;
00517 
00518       /* ... and free it */
00519       candidate->parent = NULL;
00520       _dbus_object_subtree_unref (candidate);
00521 
00522       return TRUE;
00523     }
00524   return FALSE;
00525 }
00526 
00564 static dbus_bool_t
00565 unregister_and_free_path_recurse
00566 (DBusObjectSubtree                 *subtree,
00567  const char                       **path,
00568  dbus_bool_t                       *continue_removal_attempts,
00569  DBusObjectPathUnregisterFunction  *unregister_function_out,
00570  void                             **user_data_out)
00571 {
00572   int i, j;
00573 
00574   _dbus_assert (continue_removal_attempts != NULL);
00575   _dbus_assert (*continue_removal_attempts);
00576   _dbus_assert (unregister_function_out != NULL);
00577   _dbus_assert (user_data_out != NULL);
00578 
00579   if (path[0] == NULL)
00580     return unregister_subtree (subtree, unregister_function_out, user_data_out);
00581 
00582   i = 0;
00583   j = subtree->n_subtrees;
00584   while (i < j)
00585     {
00586       int k, v;
00587 
00588       k = (i + j) / 2;
00589       v = strcmp (path[0], subtree->subtrees[k]->name);
00590 
00591       if (v == 0)
00592         {
00593           dbus_bool_t freed;
00594           freed = unregister_and_free_path_recurse (subtree->subtrees[k],
00595                                                     &path[1],
00596                                                     continue_removal_attempts,
00597                                                     unregister_function_out,
00598                                                     user_data_out);
00599           if (freed && *continue_removal_attempts)
00600             *continue_removal_attempts = attempt_child_removal (subtree, k);
00601           return freed;
00602         }
00603       else if (v < 0)
00604         {
00605           j = k;
00606         }
00607       else
00608         {
00609           i = k + 1;
00610         }
00611     }
00612   return FALSE;
00613 }
00614 
00622 void
00623 _dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,
00624                                          const char             **path)
00625 {
00626   dbus_bool_t found_subtree;
00627   dbus_bool_t continue_removal_attempts;
00628   DBusObjectPathUnregisterFunction unregister_function;
00629   void *user_data;
00630   DBusConnection *connection;
00631 
00632   _dbus_assert (tree != NULL);
00633   _dbus_assert (path != NULL);
00634 
00635   continue_removal_attempts = TRUE;
00636   unregister_function = NULL;
00637   user_data = NULL;
00638 
00639   found_subtree = unregister_and_free_path_recurse (tree->root,
00640                                                     path,
00641                                                     &continue_removal_attempts,
00642                                                     &unregister_function,
00643                                                     &user_data);
00644 
00645 #ifndef DBUS_DISABLE_CHECKS
00646   if (found_subtree == FALSE)
00647     {
00648       _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
00649                   path[0] ? path[0] : "null",
00650                   (path[0] && path[1]) ? path[1] : "null");
00651       goto unlock;    
00652     }
00653 #else
00654   _dbus_assert (found_subtree == TRUE);
00655 #endif
00656 
00657 unlock:
00658   connection = tree->connection;
00659 
00660   /* Unlock and call application code */
00661 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00662   if (connection)
00663 #endif
00664     {
00665       _dbus_connection_ref_unlocked (connection);
00666       _dbus_verbose ("unlock\n");
00667       _dbus_connection_unlock (connection);
00668     }
00669 
00670   if (unregister_function)
00671     (* unregister_function) (connection, user_data);
00672 
00673 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00674   if (connection)
00675 #endif
00676     dbus_connection_unref (connection);
00677 }
00678 
00679 static void
00680 free_subtree_recurse (DBusConnection    *connection,
00681                       DBusObjectSubtree *subtree)
00682 {
00683   /* Delete them from the end, for slightly
00684    * more robustness against odd reentrancy.
00685    */
00686   while (subtree->n_subtrees > 0)
00687     {
00688       DBusObjectSubtree *child;
00689 
00690       child = subtree->subtrees[subtree->n_subtrees - 1];
00691       subtree->subtrees[subtree->n_subtrees - 1] = NULL;
00692       subtree->n_subtrees -= 1;
00693       child->parent = NULL;
00694 
00695       free_subtree_recurse (connection, child);
00696     }
00697 
00698   /* Call application code */
00699   if (subtree->unregister_function)
00700     (* subtree->unregister_function) (connection,
00701                                       subtree->user_data);
00702 
00703   subtree->message_function = NULL;
00704   subtree->unregister_function = NULL;
00705   subtree->user_data = NULL;
00706 
00707   /* Now free ourselves */
00708   _dbus_object_subtree_unref (subtree);
00709 }
00710 
00717 void
00718 _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
00719 {
00720   if (tree->root)
00721     free_subtree_recurse (tree->connection,
00722                           tree->root);
00723   tree->root = NULL;
00724 }
00725 
00726 static dbus_bool_t
00727 _dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
00728                                             const char    **parent_path,
00729                                             char         ***child_entries)
00730 {
00731   DBusObjectSubtree *subtree;
00732   char **retval;
00733   
00734   _dbus_assert (parent_path != NULL);
00735   _dbus_assert (child_entries != NULL);
00736 
00737   *child_entries = NULL;
00738   
00739   subtree = lookup_subtree (tree, parent_path);
00740   if (subtree == NULL)
00741     {
00742       retval = dbus_new0 (char *, 1);
00743     }
00744   else
00745     {
00746       int i;
00747       retval = dbus_new0 (char*, subtree->n_subtrees + 1);
00748       if (retval == NULL)
00749         goto out;
00750       i = 0;
00751       while (i < subtree->n_subtrees)
00752         {
00753           retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
00754           if (retval[i] == NULL)
00755             {
00756               dbus_free_string_array (retval);
00757               retval = NULL;
00758               goto out;
00759             }
00760           ++i;
00761         }
00762     }
00763 
00764  out:
00765     
00766   *child_entries = retval;
00767   return retval != NULL;
00768 }
00769 
00770 static DBusHandlerResult
00771 handle_default_introspect_and_unlock (DBusObjectTree          *tree,
00772                                       DBusMessage             *message,
00773                                       const char             **path)
00774 {
00775   DBusString xml;
00776   DBusHandlerResult result;
00777   char **children;
00778   int i;
00779   DBusMessage *reply;
00780   DBusMessageIter iter;
00781   const char *v_STRING;
00782   dbus_bool_t already_unlocked;
00783 
00784   /* We have the connection lock here */
00785 
00786   already_unlocked = FALSE;
00787   
00788   _dbus_verbose (" considering default Introspect() handler...\n");
00789 
00790   reply = NULL;
00791   
00792   if (!dbus_message_is_method_call (message,
00793                                     DBUS_INTERFACE_INTROSPECTABLE,
00794                                     "Introspect"))
00795     {
00796 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00797       if (tree->connection)
00798 #endif
00799         {
00800           _dbus_verbose ("unlock\n");
00801           _dbus_connection_unlock (tree->connection);
00802         }
00803       
00804       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00805     }
00806 
00807   _dbus_verbose (" using default Introspect() handler!\n");
00808   
00809   if (!_dbus_string_init (&xml))
00810     {
00811 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00812       if (tree->connection)
00813 #endif
00814         {
00815           _dbus_verbose ("unlock\n");
00816           _dbus_connection_unlock (tree->connection);
00817         }
00818 
00819       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00820     }
00821 
00822   result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00823 
00824   children = NULL;
00825   if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
00826     goto out;
00827 
00828   if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
00829     goto out;
00830   
00831   if (!_dbus_string_append (&xml, "<node>\n"))
00832     goto out;
00833 
00834   i = 0;
00835   while (children[i] != NULL)
00836     {
00837       if (!_dbus_string_append_printf (&xml, "  <node name=\"%s\"/>\n",
00838                                        children[i]))
00839         goto out;
00840 
00841       ++i;
00842     }
00843 
00844   if (!_dbus_string_append (&xml, "</node>\n"))
00845     goto out;
00846 
00847   reply = dbus_message_new_method_return (message);
00848   if (reply == NULL)
00849     goto out;
00850 
00851   dbus_message_iter_init_append (reply, &iter);
00852   v_STRING = _dbus_string_get_const_data (&xml);
00853   if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING))
00854     goto out;
00855   
00856 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00857   if (tree->connection)
00858 #endif
00859     {
00860       already_unlocked = TRUE;
00861       
00862       if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL))
00863         goto out;
00864     }
00865   
00866   result = DBUS_HANDLER_RESULT_HANDLED;
00867   
00868  out:
00869 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00870   if (tree->connection)
00871 #endif
00872     {
00873       if (!already_unlocked)
00874         {
00875           _dbus_verbose ("unlock\n");
00876           _dbus_connection_unlock (tree->connection);
00877         }
00878     }
00879   
00880   _dbus_string_free (&xml);
00881   dbus_free_string_array (children);
00882   if (reply)
00883     dbus_message_unref (reply);
00884   
00885   return result;
00886 }
00887 
00902 DBusHandlerResult
00903 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,
00904                                        DBusMessage             *message,
00905                                        dbus_bool_t             *found_object)
00906 {
00907   char **path;
00908   dbus_bool_t exact_match;
00909   DBusList *list;
00910   DBusList *link;
00911   DBusHandlerResult result;
00912   DBusObjectSubtree *subtree;
00913   
00914 #if 0
00915   _dbus_verbose ("Dispatch of message by object path\n");
00916 #endif
00917   
00918   path = NULL;
00919   if (!dbus_message_get_path_decomposed (message, &path))
00920     {
00921 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00922       if (tree->connection)
00923 #endif
00924         {
00925           _dbus_verbose ("unlock\n");
00926           _dbus_connection_unlock (tree->connection);
00927         }
00928       
00929       _dbus_verbose ("No memory to get decomposed path\n");
00930 
00931       return DBUS_HANDLER_RESULT_NEED_MEMORY;
00932     }
00933 
00934   if (path == NULL)
00935     {
00936 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00937       if (tree->connection)
00938 #endif
00939         {
00940           _dbus_verbose ("unlock\n");
00941           _dbus_connection_unlock (tree->connection);
00942         }
00943       
00944       _dbus_verbose ("No path field in message\n");
00945       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00946     }
00947   
00948   /* Find the deepest path that covers the path in the message */
00949   subtree = find_handler (tree, (const char**) path, &exact_match);
00950   
00951   if (found_object)
00952     *found_object = !!subtree;
00953 
00954   /* Build a list of all paths that cover the path in the message */
00955 
00956   list = NULL;
00957 
00958   while (subtree != NULL)
00959     {
00960       if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback))
00961         {
00962           _dbus_object_subtree_ref (subtree);
00963 
00964           /* run deepest paths first */
00965           if (!_dbus_list_append (&list, subtree))
00966             {
00967               result = DBUS_HANDLER_RESULT_NEED_MEMORY;
00968               _dbus_object_subtree_unref (subtree);
00969               goto free_and_return;
00970             }
00971         }
00972 
00973       exact_match = FALSE;
00974       subtree = subtree->parent;
00975     }
00976 
00977   _dbus_verbose ("%d handlers in the path tree for this message\n",
00978                  _dbus_list_get_length (&list));
00979 
00980   /* Invoke each handler in the list */
00981 
00982   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00983 
00984   link = _dbus_list_get_first_link (&list);
00985   while (link != NULL)
00986     {
00987       DBusList *next = _dbus_list_get_next_link (&list, link);
00988       subtree = link->data;
00989 
00990       /* message_function is NULL if we're unregistered
00991        * due to reentrancy
00992        */
00993       if (subtree->message_function)
00994         {
00995           DBusObjectPathMessageFunction message_function;
00996           void *user_data;
00997 
00998           message_function = subtree->message_function;
00999           user_data = subtree->user_data;
01000 
01001 #if 0
01002           _dbus_verbose ("  (invoking a handler)\n");
01003 #endif
01004           
01005 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
01006           if (tree->connection)
01007 #endif
01008             {
01009               _dbus_verbose ("unlock\n");
01010               _dbus_connection_unlock (tree->connection);
01011             }
01012 
01013           /* FIXME you could unregister the subtree in another thread
01014            * before we invoke the callback, and I can't figure out a
01015            * good way to solve this.
01016            */
01017 
01018           result = (* message_function) (tree->connection,
01019                                          message,
01020                                          user_data);
01021 
01022 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
01023           if (tree->connection)
01024 #endif
01025             _dbus_connection_lock (tree->connection);
01026 
01027           if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
01028             goto free_and_return;
01029         }
01030 
01031       link = next;
01032     }
01033 
01034  free_and_return:
01035 
01036   if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
01037     {
01038       /* This hardcoded default handler does a minimal Introspect()
01039        */
01040       result = handle_default_introspect_and_unlock (tree, message,
01041                                                      (const char**) path);
01042     }
01043   else
01044     {
01045 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
01046       if (tree->connection)
01047 #endif
01048         {
01049           _dbus_verbose ("unlock\n");
01050           _dbus_connection_unlock (tree->connection);
01051         }
01052     }
01053   
01054   while (list != NULL)
01055     {
01056       link = _dbus_list_get_first_link (&list);
01057       _dbus_object_subtree_unref (link->data);
01058       _dbus_list_remove_link (&list, link);
01059     }
01060   
01061   dbus_free_string_array (path);
01062 
01063   return result;
01064 }
01065 
01074 void*
01075 _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree,
01076                                           const char    **path)
01077 {
01078   dbus_bool_t exact_match;
01079   DBusObjectSubtree *subtree;
01080 
01081   _dbus_assert (tree != NULL);
01082   _dbus_assert (path != NULL);
01083   
01084   /* Find the deepest path that covers the path in the message */
01085   subtree = find_handler (tree, (const char**) path, &exact_match);
01086 
01087   if ((subtree == NULL) || !exact_match)
01088     {
01089       _dbus_verbose ("No object at specified path found\n");
01090       return NULL;
01091     }
01092 
01093   return subtree->user_data;
01094 }
01095 
01102 static DBusObjectSubtree*
01103 allocate_subtree_object (const char *name)
01104 {
01105   int len;
01106   DBusObjectSubtree *subtree;
01107   const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
01108 
01109   _dbus_assert (name != NULL);
01110 
01111   len = strlen (name);
01112 
01113   subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
01114 
01115   if (subtree == NULL)
01116     return NULL;
01117 
01118   memcpy (subtree->name, name, len + 1);
01119 
01120   return subtree;
01121 }
01122 
01123 static DBusObjectSubtree*
01124 _dbus_object_subtree_new (const char                  *name,
01125                           const DBusObjectPathVTable  *vtable,
01126                           void                        *user_data)
01127 {
01128   DBusObjectSubtree *subtree;
01129 
01130   subtree = allocate_subtree_object (name);
01131   if (subtree == NULL)
01132     goto oom;
01133 
01134   _dbus_assert (name != NULL);
01135 
01136   subtree->parent = NULL;
01137 
01138   if (vtable)
01139     {
01140       subtree->message_function = vtable->message_function;
01141       subtree->unregister_function = vtable->unregister_function;
01142     }
01143   else
01144     {
01145       subtree->message_function = NULL;
01146       subtree->unregister_function = NULL;
01147     }
01148 
01149   subtree->user_data = user_data;
01150   _dbus_atomic_inc (&subtree->refcount);
01151   subtree->subtrees = NULL;
01152   subtree->n_subtrees = 0;
01153   subtree->max_subtrees = 0;
01154   subtree->invoke_as_fallback = FALSE;
01155 
01156   return subtree;
01157 
01158  oom:
01159   return NULL;
01160 }
01161 
01162 static DBusObjectSubtree *
01163 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
01164 {
01165 #ifdef DBUS_DISABLE_ASSERT
01166   _dbus_atomic_inc (&subtree->refcount);
01167 #else
01168   dbus_int32_t old_value;
01169 
01170   old_value = _dbus_atomic_inc (&subtree->refcount);
01171   _dbus_assert (old_value > 0);
01172 #endif
01173 
01174   return subtree;
01175 }
01176 
01177 static void
01178 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
01179 {
01180   dbus_int32_t old_value;
01181 
01182   old_value = _dbus_atomic_dec (&subtree->refcount);
01183   _dbus_assert (old_value > 0);
01184 
01185   if (old_value == 1)
01186     {
01187       _dbus_assert (subtree->unregister_function == NULL);
01188       _dbus_assert (subtree->message_function == NULL);
01189 
01190       dbus_free (subtree->subtrees);
01191       dbus_free (subtree);
01192     }
01193 }
01194 
01205 dbus_bool_t
01206 _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
01207                                               const char    **parent_path,
01208                                               char         ***child_entries)
01209 {
01210   dbus_bool_t result;
01211 
01212   result = _dbus_object_tree_list_registered_unlocked (tree,
01213                                                        parent_path,
01214                                                        child_entries);
01215   
01216 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
01217   if (tree->connection)
01218 #endif
01219     {
01220       _dbus_verbose ("unlock\n");
01221       _dbus_connection_unlock (tree->connection);
01222     }
01223 
01224   return result;
01225 }
01226 
01227 
01229 #define VERBOSE_DECOMPOSE 0
01230 
01241 dbus_bool_t
01242 _dbus_decompose_path (const char*     data,
01243                       int             len,
01244                       char         ***path,
01245                       int            *path_len)
01246 {
01247   char **retval;
01248   int n_components;
01249   int i, j, comp;
01250 
01251   _dbus_assert (data != NULL);
01252   _dbus_assert (path != NULL);
01253   
01254 #if VERBOSE_DECOMPOSE
01255   _dbus_verbose ("Decomposing path \"%s\"\n",
01256                  data);
01257 #endif
01258   
01259   n_components = 0;
01260   if (len > 1) /* if path is not just "/" */
01261     {
01262       i = 0;
01263       while (i < len)
01264         {
01265           _dbus_assert (data[i] != '\0');
01266           if (data[i] == '/')
01267             n_components += 1;
01268           ++i;
01269         }
01270     }
01271   
01272   retval = dbus_new0 (char*, n_components + 1);
01273 
01274   if (retval == NULL)
01275     return FALSE;
01276 
01277   comp = 0;
01278   if (n_components == 0)
01279     i = 1;
01280   else
01281     i = 0;
01282   while (comp < n_components)
01283     {
01284       _dbus_assert (i < len);
01285       
01286       if (data[i] == '/')
01287         ++i;
01288       j = i;
01289 
01290       while (j < len && data[j] != '/')
01291         ++j;
01292 
01293       /* Now [i, j) is the path component */
01294       _dbus_assert (i < j);
01295       _dbus_assert (data[i] != '/');
01296       _dbus_assert (j == len || data[j] == '/');
01297 
01298 #if VERBOSE_DECOMPOSE
01299       _dbus_verbose ("  (component in [%d,%d))\n",
01300                      i, j);
01301 #endif
01302       
01303       retval[comp] = _dbus_memdup (&data[i], j - i + 1);
01304       if (retval[comp] == NULL)
01305         {
01306           dbus_free_string_array (retval);
01307           return FALSE;
01308         }
01309       retval[comp][j-i] = '\0';
01310 #if VERBOSE_DECOMPOSE
01311       _dbus_verbose ("  (component %d = \"%s\")\n",
01312                      comp, retval[comp]);
01313 #endif
01314 
01315       ++comp;
01316       i = j;
01317     }
01318   _dbus_assert (i == len);
01319   
01320   *path = retval;
01321   if (path_len)
01322     *path_len = n_components;
01323   
01324   return TRUE;
01325 }
01326 
01329 static char*
01330 flatten_path (const char **path)
01331 {
01332   DBusString str;
01333   char *s;
01334 
01335   if (!_dbus_string_init (&str))
01336     return NULL;
01337 
01338   if (path[0] == NULL)
01339     {
01340       if (!_dbus_string_append_byte (&str, '/'))
01341         goto nomem;
01342     }
01343   else
01344     {
01345       int i;
01346       
01347       i = 0;
01348       while (path[i])
01349         {
01350           if (!_dbus_string_append_byte (&str, '/'))
01351             goto nomem;
01352           
01353           if (!_dbus_string_append (&str, path[i]))
01354             goto nomem;
01355           
01356           ++i;
01357         }
01358     }
01359 
01360   if (!_dbus_string_steal_data (&str, &s))
01361     goto nomem;
01362 
01363   _dbus_string_free (&str);
01364 
01365   return s;
01366 
01367  nomem:
01368   _dbus_string_free (&str);
01369   return NULL;
01370 }
01371 
01372 
01373 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
01374 
01375 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01376 
01377 #include "dbus-test.h"
01378 #include <stdio.h>
01379 
01380 typedef enum 
01381 {
01382   STR_EQUAL,
01383   STR_PREFIX,
01384   STR_DIFFERENT
01385 } StrComparison;
01386 
01387 /* Returns TRUE if container is a parent of child
01388  */
01389 static StrComparison
01390 path_contains (const char **container,
01391                const char **child)
01392 {
01393   int i;
01394 
01395   i = 0;
01396   while (child[i] != NULL)
01397     {
01398       int v;
01399 
01400       if (container[i] == NULL)
01401         return STR_PREFIX; /* container ran out, child continues;
01402                             * thus the container is a parent of the
01403                             * child.
01404                             */
01405 
01406       _dbus_assert (container[i] != NULL);
01407       _dbus_assert (child[i] != NULL);
01408 
01409       v = strcmp (container[i], child[i]);
01410 
01411       if (v != 0)
01412         return STR_DIFFERENT; /* they overlap until here and then are different,
01413                                * not overlapping
01414                                */
01415 
01416       ++i;
01417     }
01418 
01419   /* Child ran out; if container also did, they are equal;
01420    * otherwise, the child is a parent of the container.
01421    */
01422   if (container[i] == NULL)
01423     return STR_EQUAL;
01424   else
01425     return STR_DIFFERENT;
01426 }
01427 
01428 #if 0
01429 static void
01430 spew_subtree_recurse (DBusObjectSubtree *subtree,
01431                       int                indent)
01432 {
01433   int i;
01434 
01435   i = 0;
01436   while (i < indent)
01437     {
01438       _dbus_verbose (" ");
01439       ++i;
01440     }
01441 
01442   _dbus_verbose ("%s (%d children)\n",
01443                  subtree->name, subtree->n_subtrees);
01444 
01445   i = 0;
01446   while (i < subtree->n_subtrees)
01447     {
01448       spew_subtree_recurse (subtree->subtrees[i], indent + 2);
01449 
01450       ++i;
01451     }
01452 }
01453 
01454 static void
01455 spew_tree (DBusObjectTree *tree)
01456 {
01457   spew_subtree_recurse (tree->root, 0);
01458 }
01459 #endif
01460 
01464 typedef struct
01465 {
01466   const char **path; 
01467   dbus_bool_t handler_fallback; 
01468   dbus_bool_t message_handled; 
01469   dbus_bool_t handler_unregistered; 
01470 } TreeTestData;
01471 
01472 
01473 static void
01474 test_unregister_function (DBusConnection  *connection,
01475                           void            *user_data)
01476 {
01477   TreeTestData *ttd = user_data;
01478 
01479   ttd->handler_unregistered = TRUE;
01480 }
01481 
01482 static DBusHandlerResult
01483 test_message_function (DBusConnection  *connection,
01484                        DBusMessage     *message,
01485                        void            *user_data)
01486 {
01487   TreeTestData *ttd = user_data;
01488 
01489   ttd->message_handled = TRUE;
01490 
01491   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01492 }
01493 
01494 static dbus_bool_t
01495 do_register (DBusObjectTree *tree,
01496              const char    **path,
01497              dbus_bool_t     fallback,
01498              int             i,
01499              TreeTestData   *tree_test_data)
01500 {
01501   DBusObjectPathVTable vtable = { test_unregister_function,
01502                                   test_message_function, NULL };
01503 
01504   tree_test_data[i].message_handled = FALSE;
01505   tree_test_data[i].handler_unregistered = FALSE;
01506   tree_test_data[i].handler_fallback = fallback;
01507   tree_test_data[i].path = path;
01508 
01509   if (!_dbus_object_tree_register (tree, fallback, path,
01510                                    &vtable,
01511                                    &tree_test_data[i],
01512                                    NULL))
01513     return FALSE;
01514 
01515   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) ==
01516                 &tree_test_data[i]);
01517   
01518   return TRUE;
01519 }
01520 
01521 static dbus_bool_t
01522 do_test_dispatch (DBusObjectTree *tree,
01523                   const char    **path,
01524                   int             i,
01525                   TreeTestData   *tree_test_data,
01526                   int             n_test_data)
01527 {
01528   DBusMessage *message;
01529   int j;
01530   DBusHandlerResult result;
01531   char *flat;
01532 
01533   message = NULL;
01534   
01535   flat = flatten_path (path);
01536   if (flat == NULL)
01537     goto oom;
01538 
01539   message = dbus_message_new_method_call (NULL,
01540                                           flat,
01541                                           "org.freedesktop.TestInterface",
01542                                           "Foo");
01543   dbus_free (flat);
01544   if (message == NULL)
01545     goto oom;
01546 
01547   j = 0;
01548   while (j < n_test_data)
01549     {
01550       tree_test_data[j].message_handled = FALSE;
01551       ++j;
01552     }
01553 
01554   result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
01555   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
01556     goto oom;
01557 
01558   _dbus_assert (tree_test_data[i].message_handled);
01559 
01560   j = 0;
01561   while (j < n_test_data)
01562     {
01563       if (tree_test_data[j].message_handled)
01564         {
01565           if (tree_test_data[j].handler_fallback)
01566             _dbus_assert (path_contains (tree_test_data[j].path,
01567                                          path) != STR_DIFFERENT);
01568           else
01569             _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL);
01570         }
01571       else
01572         {
01573           if (tree_test_data[j].handler_fallback)
01574             _dbus_assert (path_contains (tree_test_data[j].path,
01575                                          path) == STR_DIFFERENT);
01576           else
01577             _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL);
01578         }
01579 
01580       ++j;
01581     }
01582 
01583   dbus_message_unref (message);
01584 
01585   return TRUE;
01586 
01587  oom:
01588   if (message)
01589     dbus_message_unref (message);
01590   return FALSE;
01591 }
01592 
01593 static size_t
01594 string_array_length (const char **array)
01595 {
01596   size_t i;
01597   for (i = 0; array[i]; i++) ;
01598   return i;
01599 }
01600 
01601 typedef struct
01602 {
01603   const char *path;
01604   const char *result[20];
01605 } DecomposePathTest;
01606 
01607 static DecomposePathTest decompose_tests[] = {
01608   { "/foo", { "foo", NULL } },
01609   { "/foo/bar", { "foo", "bar", NULL } },
01610   { "/", { NULL } },
01611   { "/a/b", { "a", "b", NULL } },
01612   { "/a/b/c", { "a", "b", "c", NULL } },
01613   { "/a/b/c/d", { "a", "b", "c", "d", NULL } },
01614   { "/foo/bar/q", { "foo", "bar", "q", NULL } },
01615   { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } }
01616 };
01617 
01618 static dbus_bool_t
01619 run_decompose_tests (void)
01620 {
01621   int i;
01622 
01623   i = 0;
01624   while (i < _DBUS_N_ELEMENTS (decompose_tests))
01625     {
01626       char **result;
01627       int    result_len;
01628       int    expected_len;
01629 
01630       if (!_dbus_decompose_path (decompose_tests[i].path,
01631                                  strlen (decompose_tests[i].path),
01632                                  &result, &result_len))
01633         return FALSE;
01634 
01635       expected_len = string_array_length (decompose_tests[i].result);
01636       
01637       if (result_len != (int) string_array_length ((const char**)result) ||
01638           expected_len != result_len ||
01639           path_contains (decompose_tests[i].result,
01640                          (const char**) result) != STR_EQUAL)
01641         {
01642           int real_len = string_array_length ((const char**)result);
01643           _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n",
01644                       decompose_tests[i].path, expected_len, result_len,
01645                       real_len);
01646           _dbus_warn ("Decompose resulted in elements: { ");
01647           i = 0;
01648           while (i < real_len)
01649             {
01650               _dbus_warn ("\"%s\"%s", result[i],
01651                           (i + 1) == real_len ? "" : ", ");
01652               ++i;
01653             }
01654           _dbus_warn ("}\n");
01655           _dbus_assert_not_reached ("path decompose failed\n");
01656         }
01657 
01658       dbus_free_string_array (result);
01659 
01660       ++i;
01661     }
01662   
01663   return TRUE;
01664 }
01665 
01666 static DBusObjectSubtree*
01667 find_subtree_registered_or_unregistered (DBusObjectTree *tree,
01668                                          const char    **path)
01669 {
01670 #if VERBOSE_FIND
01671   _dbus_verbose ("Looking for exact subtree, registered or unregistered\n");
01672 #endif
01673 
01674   return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL);
01675 }
01676 
01677 static dbus_bool_t
01678 object_tree_test_iteration (void *data)
01679 {
01680   const char *path0[] = { NULL };
01681   const char *path1[] = { "foo", NULL };
01682   const char *path2[] = { "foo", "bar", NULL };
01683   const char *path3[] = { "foo", "bar", "baz", NULL };
01684   const char *path4[] = { "foo", "bar", "boo", NULL };
01685   const char *path5[] = { "blah", NULL };
01686   const char *path6[] = { "blah", "boof", NULL };
01687   const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
01688   const char *path8[] = { "childless", NULL };
01689   const char *path9[] = { "blah", "a", NULL };
01690   const char *path10[] = { "blah", "b", NULL };
01691   const char *path11[] = { "blah", "c", NULL };
01692   const char *path12[] = { "blah", "a", "d", NULL };
01693   const char *path13[] = { "blah", "b", "d", NULL };
01694   const char *path14[] = { "blah", "c", "d", NULL };
01695   DBusObjectPathVTable test_vtable = { NULL, test_message_function, NULL };
01696   DBusObjectTree *tree;
01697   TreeTestData tree_test_data[9];
01698   int i;
01699   dbus_bool_t exact_match;
01700 
01701   if (!run_decompose_tests ())
01702     return FALSE;
01703   
01704   tree = NULL;
01705 
01706   tree = _dbus_object_tree_new (NULL);
01707   if (tree == NULL)
01708     goto out;
01709 
01710   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01711     goto out;
01712 
01713   _dbus_assert (find_subtree (tree, path0, NULL));
01714   _dbus_assert (!find_subtree (tree, path1, NULL));
01715   _dbus_assert (!find_subtree (tree, path2, NULL));
01716   _dbus_assert (!find_subtree (tree, path3, NULL));
01717   _dbus_assert (!find_subtree (tree, path4, NULL));
01718   _dbus_assert (!find_subtree (tree, path5, NULL));
01719   _dbus_assert (!find_subtree (tree, path6, NULL));
01720   _dbus_assert (!find_subtree (tree, path7, NULL));
01721   _dbus_assert (!find_subtree (tree, path8, NULL));
01722 
01723   _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match);
01724   _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match);
01725   _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match);
01726   _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match);
01727   _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match);
01728   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01729   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01730   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01731   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01732   
01733   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01734     goto out;
01735 
01736   _dbus_assert (find_subtree (tree, path0, NULL));
01737   _dbus_assert (find_subtree (tree, path1, NULL));
01738   _dbus_assert (!find_subtree (tree, path2, NULL));
01739   _dbus_assert (!find_subtree (tree, path3, NULL));
01740   _dbus_assert (!find_subtree (tree, path4, NULL));
01741   _dbus_assert (!find_subtree (tree, path5, NULL));
01742   _dbus_assert (!find_subtree (tree, path6, NULL));
01743   _dbus_assert (!find_subtree (tree, path7, NULL));
01744   _dbus_assert (!find_subtree (tree, path8, NULL));
01745 
01746   _dbus_assert (find_handler (tree, path0, &exact_match) &&  exact_match);
01747   _dbus_assert (find_handler (tree, path1, &exact_match) &&  exact_match);
01748   _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match);
01749   _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match);
01750   _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match);
01751   _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match);
01752   _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match);
01753   _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match);
01754   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01755 
01756   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01757     goto out;
01758 
01759   _dbus_assert (find_subtree (tree, path1, NULL));
01760   _dbus_assert (find_subtree (tree, path2, NULL));
01761   _dbus_assert (!find_subtree (tree, path3, NULL));
01762   _dbus_assert (!find_subtree (tree, path4, NULL));
01763   _dbus_assert (!find_subtree (tree, path5, NULL));
01764   _dbus_assert (!find_subtree (tree, path6, NULL));
01765   _dbus_assert (!find_subtree (tree, path7, NULL));
01766   _dbus_assert (!find_subtree (tree, path8, NULL));
01767 
01768   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01769     goto out;
01770 
01771   _dbus_assert (find_subtree (tree, path0, NULL));
01772   _dbus_assert (find_subtree (tree, path1, NULL));
01773   _dbus_assert (find_subtree (tree, path2, NULL));
01774   _dbus_assert (find_subtree (tree, path3, NULL));
01775   _dbus_assert (!find_subtree (tree, path4, NULL));
01776   _dbus_assert (!find_subtree (tree, path5, NULL));
01777   _dbus_assert (!find_subtree (tree, path6, NULL));
01778   _dbus_assert (!find_subtree (tree, path7, NULL));
01779   _dbus_assert (!find_subtree (tree, path8, NULL));
01780   
01781   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01782     goto out;
01783 
01784   _dbus_assert (find_subtree (tree, path0, NULL));
01785   _dbus_assert (find_subtree (tree, path1, NULL));
01786   _dbus_assert (find_subtree (tree, path2, NULL));
01787   _dbus_assert (find_subtree (tree, path3, NULL));  
01788   _dbus_assert (find_subtree (tree, path4, NULL));
01789   _dbus_assert (!find_subtree (tree, path5, NULL));
01790   _dbus_assert (!find_subtree (tree, path6, NULL));
01791   _dbus_assert (!find_subtree (tree, path7, NULL));
01792   _dbus_assert (!find_subtree (tree, path8, NULL));
01793   
01794   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01795     goto out;
01796 
01797   _dbus_assert (find_subtree (tree, path0, NULL));
01798   _dbus_assert (find_subtree (tree, path1, NULL));
01799   _dbus_assert (find_subtree (tree, path2, NULL));
01800   _dbus_assert (find_subtree (tree, path3, NULL));
01801   _dbus_assert (find_subtree (tree, path4, NULL));
01802   _dbus_assert (find_subtree (tree, path5, NULL));
01803   _dbus_assert (!find_subtree (tree, path6, NULL));
01804   _dbus_assert (!find_subtree (tree, path7, NULL));
01805   _dbus_assert (!find_subtree (tree, path8, NULL));
01806 
01807   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01808   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root &&  exact_match);
01809   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root &&  exact_match);
01810   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root &&  exact_match);
01811   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root &&  exact_match);
01812   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root &&  exact_match);
01813   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match);
01814   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match);
01815   _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match);
01816 
01817   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01818     goto out;
01819 
01820   _dbus_assert (find_subtree (tree, path0, NULL));
01821   _dbus_assert (find_subtree (tree, path1, NULL));
01822   _dbus_assert (find_subtree (tree, path2, NULL));
01823   _dbus_assert (find_subtree (tree, path3, NULL));
01824   _dbus_assert (find_subtree (tree, path4, NULL));
01825   _dbus_assert (find_subtree (tree, path5, NULL));
01826   _dbus_assert (find_subtree (tree, path6, NULL));
01827   _dbus_assert (!find_subtree (tree, path7, NULL));
01828   _dbus_assert (!find_subtree (tree, path8, NULL));
01829 
01830   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01831     goto out;
01832 
01833   _dbus_assert (find_subtree (tree, path0, NULL));
01834   _dbus_assert (find_subtree (tree, path1, NULL));
01835   _dbus_assert (find_subtree (tree, path2, NULL));
01836   _dbus_assert (find_subtree (tree, path3, NULL));
01837   _dbus_assert (find_subtree (tree, path4, NULL));
01838   _dbus_assert (find_subtree (tree, path5, NULL));
01839   _dbus_assert (find_subtree (tree, path6, NULL));
01840   _dbus_assert (find_subtree (tree, path7, NULL));
01841   _dbus_assert (!find_subtree (tree, path8, NULL));
01842 
01843   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01844     goto out;
01845 
01846   _dbus_assert (find_subtree (tree, path0, NULL));
01847   _dbus_assert (find_subtree (tree, path1, NULL));
01848   _dbus_assert (find_subtree (tree, path2, NULL));
01849   _dbus_assert (find_subtree (tree, path3, NULL));
01850   _dbus_assert (find_subtree (tree, path4, NULL));
01851   _dbus_assert (find_subtree (tree, path5, NULL));
01852   _dbus_assert (find_subtree (tree, path6, NULL));
01853   _dbus_assert (find_subtree (tree, path7, NULL));
01854   _dbus_assert (find_subtree (tree, path8, NULL));
01855 
01856   _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root &&  exact_match);
01857   _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match);
01858   _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match);
01859   _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match);
01860   _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match);
01861   _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match);
01862   _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match);
01863   _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match);
01864   _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match);
01865   
01866   /* test the list_registered function */
01867 
01868   {
01869     const char *root[] = { NULL };
01870     char **child_entries;
01871     int nb;
01872 
01873     _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries);
01874     if (child_entries != NULL)
01875       {
01876         nb = string_array_length ((const char**)child_entries);
01877         _dbus_assert (nb == 1);
01878         dbus_free_string_array (child_entries);
01879       }
01880 
01881     _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries);
01882     if (child_entries != NULL)
01883       {
01884         nb = string_array_length ((const char**)child_entries);
01885         _dbus_assert (nb == 2);
01886         dbus_free_string_array (child_entries);
01887       }
01888 
01889     _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries);
01890     if (child_entries != NULL)
01891       {
01892         nb = string_array_length ((const char**)child_entries);
01893         _dbus_assert (nb == 0);
01894         dbus_free_string_array (child_entries);
01895       }
01896 
01897     _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries);
01898     if (child_entries != NULL)
01899       {
01900         nb = string_array_length ((const char**)child_entries);
01901         _dbus_assert (nb == 3);
01902         dbus_free_string_array (child_entries);
01903       }
01904   }
01905 
01906   /* Check that destroying tree calls unregister funcs */
01907   _dbus_object_tree_unref (tree);
01908 
01909   i = 0;
01910   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
01911     {
01912       _dbus_assert (tree_test_data[i].handler_unregistered);
01913       _dbus_assert (!tree_test_data[i].message_handled);
01914       ++i;
01915     }
01916 
01917   /* Now start again and try the individual unregister function */
01918   tree = _dbus_object_tree_new (NULL);
01919   if (tree == NULL)
01920     goto out;
01921 
01922   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
01923     goto out;
01924   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
01925     goto out;
01926   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
01927     goto out;
01928   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
01929     goto out;
01930   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
01931     goto out;
01932   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
01933     goto out;
01934   if (!do_register (tree, path6, TRUE, 6, tree_test_data))
01935     goto out;
01936   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
01937     goto out;
01938   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
01939     goto out;
01940 
01941   _dbus_object_tree_unregister_and_unlock (tree, path0);
01942   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL);
01943 
01944   _dbus_assert (!find_subtree (tree, path0, NULL));
01945   _dbus_assert (find_subtree (tree, path1, NULL));
01946   _dbus_assert (find_subtree (tree, path2, NULL));
01947   _dbus_assert (find_subtree (tree, path3, NULL));
01948   _dbus_assert (find_subtree (tree, path4, NULL));
01949   _dbus_assert (find_subtree (tree, path5, NULL));
01950   _dbus_assert (find_subtree (tree, path6, NULL));
01951   _dbus_assert (find_subtree (tree, path7, NULL));
01952   _dbus_assert (find_subtree (tree, path8, NULL));
01953   
01954   _dbus_object_tree_unregister_and_unlock (tree, path1);
01955   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL);
01956 
01957   _dbus_assert (!find_subtree (tree, path0, NULL));
01958   _dbus_assert (!find_subtree (tree, path1, NULL));
01959   _dbus_assert (find_subtree (tree, path2, NULL));
01960   _dbus_assert (find_subtree (tree, path3, NULL));
01961   _dbus_assert (find_subtree (tree, path4, NULL));
01962   _dbus_assert (find_subtree (tree, path5, NULL));
01963   _dbus_assert (find_subtree (tree, path6, NULL));
01964   _dbus_assert (find_subtree (tree, path7, NULL));
01965   _dbus_assert (find_subtree (tree, path8, NULL));
01966 
01967   _dbus_object_tree_unregister_and_unlock (tree, path2);
01968   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
01969 
01970   _dbus_assert (!find_subtree (tree, path0, NULL));
01971   _dbus_assert (!find_subtree (tree, path1, NULL));
01972   _dbus_assert (!find_subtree (tree, path2, NULL));
01973   _dbus_assert (find_subtree (tree, path3, NULL));
01974   _dbus_assert (find_subtree (tree, path4, NULL));
01975   _dbus_assert (find_subtree (tree, path5, NULL));
01976   _dbus_assert (find_subtree (tree, path6, NULL));
01977   _dbus_assert (find_subtree (tree, path7, NULL));
01978   _dbus_assert (find_subtree (tree, path8, NULL));
01979   
01980   _dbus_object_tree_unregister_and_unlock (tree, path3);
01981   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL);
01982 
01983   _dbus_assert (!find_subtree (tree, path0, NULL));
01984   _dbus_assert (!find_subtree (tree, path1, NULL));
01985   _dbus_assert (!find_subtree (tree, path2, NULL));
01986   _dbus_assert (!find_subtree (tree, path3, NULL));
01987   _dbus_assert (find_subtree (tree, path4, NULL));
01988   _dbus_assert (find_subtree (tree, path5, NULL));
01989   _dbus_assert (find_subtree (tree, path6, NULL));
01990   _dbus_assert (find_subtree (tree, path7, NULL));
01991   _dbus_assert (find_subtree (tree, path8, NULL));
01992   
01993   _dbus_object_tree_unregister_and_unlock (tree, path4);
01994   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL);
01995 
01996   _dbus_assert (!find_subtree (tree, path0, NULL));
01997   _dbus_assert (!find_subtree (tree, path1, NULL));
01998   _dbus_assert (!find_subtree (tree, path2, NULL));
01999   _dbus_assert (!find_subtree (tree, path3, NULL));
02000   _dbus_assert (!find_subtree (tree, path4, NULL));
02001   _dbus_assert (find_subtree (tree, path5, NULL));
02002   _dbus_assert (find_subtree (tree, path6, NULL));
02003   _dbus_assert (find_subtree (tree, path7, NULL));
02004   _dbus_assert (find_subtree (tree, path8, NULL));
02005   
02006   _dbus_object_tree_unregister_and_unlock (tree, path5);
02007   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL);
02008 
02009   _dbus_assert (!find_subtree (tree, path0, NULL));
02010   _dbus_assert (!find_subtree (tree, path1, NULL));
02011   _dbus_assert (!find_subtree (tree, path2, NULL));
02012   _dbus_assert (!find_subtree (tree, path3, NULL));
02013   _dbus_assert (!find_subtree (tree, path4, NULL));
02014   _dbus_assert (!find_subtree (tree, path5, NULL));
02015   _dbus_assert (find_subtree (tree, path6, NULL));
02016   _dbus_assert (find_subtree (tree, path7, NULL));
02017   _dbus_assert (find_subtree (tree, path8, NULL));
02018   
02019   _dbus_object_tree_unregister_and_unlock (tree, path6);
02020   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL);
02021 
02022   _dbus_assert (!find_subtree (tree, path0, NULL));
02023   _dbus_assert (!find_subtree (tree, path1, NULL));
02024   _dbus_assert (!find_subtree (tree, path2, NULL));
02025   _dbus_assert (!find_subtree (tree, path3, NULL));
02026   _dbus_assert (!find_subtree (tree, path4, NULL));
02027   _dbus_assert (!find_subtree (tree, path5, NULL));
02028   _dbus_assert (!find_subtree (tree, path6, NULL));
02029   _dbus_assert (find_subtree (tree, path7, NULL));
02030   _dbus_assert (find_subtree (tree, path8, NULL));
02031 
02032   _dbus_object_tree_unregister_and_unlock (tree, path7);
02033   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL);
02034 
02035   _dbus_assert (!find_subtree (tree, path0, NULL));
02036   _dbus_assert (!find_subtree (tree, path1, NULL));
02037   _dbus_assert (!find_subtree (tree, path2, NULL));
02038   _dbus_assert (!find_subtree (tree, path3, NULL));
02039   _dbus_assert (!find_subtree (tree, path4, NULL));
02040   _dbus_assert (!find_subtree (tree, path5, NULL));
02041   _dbus_assert (!find_subtree (tree, path6, NULL));
02042   _dbus_assert (!find_subtree (tree, path7, NULL));
02043   _dbus_assert (find_subtree (tree, path8, NULL));
02044 
02045   _dbus_object_tree_unregister_and_unlock (tree, path8);
02046   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL);
02047 
02048   _dbus_assert (!find_subtree (tree, path0, NULL));
02049   _dbus_assert (!find_subtree (tree, path1, NULL));
02050   _dbus_assert (!find_subtree (tree, path2, NULL));
02051   _dbus_assert (!find_subtree (tree, path3, NULL));
02052   _dbus_assert (!find_subtree (tree, path4, NULL));
02053   _dbus_assert (!find_subtree (tree, path5, NULL));
02054   _dbus_assert (!find_subtree (tree, path6, NULL));
02055   _dbus_assert (!find_subtree (tree, path7, NULL));
02056   _dbus_assert (!find_subtree (tree, path8, NULL));
02057   
02058   i = 0;
02059   while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
02060     {
02061       _dbus_assert (tree_test_data[i].handler_unregistered);
02062       _dbus_assert (!tree_test_data[i].message_handled);
02063       ++i;
02064     }
02065 
02066   /* Test removal of newly-childless unregistered nodes */
02067   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
02068     goto out;
02069 
02070   _dbus_object_tree_unregister_and_unlock (tree, path2);
02071   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
02072   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
02073   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02074 
02075   /* Test that unregistered parents cannot be freed out from under their
02076      children */
02077   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
02078     goto out;
02079 
02080   _dbus_assert (!find_subtree (tree, path1, NULL));
02081   _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
02082   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02083 
02084 #if 0
02085   /* This triggers the "Attempted to unregister path ..." warning message */
02086   _dbus_object_tree_unregister_and_unlock (tree, path1);
02087 #endif
02088   _dbus_assert (find_subtree (tree, path2, NULL));
02089   _dbus_assert (!find_subtree (tree, path1, NULL));
02090   _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
02091   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02092 
02093   _dbus_object_tree_unregister_and_unlock (tree, path2);
02094   _dbus_assert (!find_subtree (tree, path2, NULL));
02095   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
02096   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
02097   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02098 
02099   /* Test that registered parents cannot be freed out from under their
02100      children, and that if they are unregistered before their children, they
02101      are still freed when their children are unregistered */
02102   if (!do_register (tree, path1, TRUE, 1, tree_test_data))
02103     goto out;
02104   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
02105     goto out;
02106 
02107   _dbus_assert (find_subtree (tree, path1, NULL));
02108   _dbus_assert (find_subtree (tree, path2, NULL));
02109 
02110   _dbus_object_tree_unregister_and_unlock (tree, path1);
02111   _dbus_assert (!find_subtree (tree, path1, NULL));
02112   _dbus_assert (find_subtree (tree, path2, NULL));
02113   _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
02114   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02115 
02116   _dbus_object_tree_unregister_and_unlock (tree, path2);
02117   _dbus_assert (!find_subtree (tree, path1, NULL));
02118   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
02119   _dbus_assert (!find_subtree (tree, path2, NULL));
02120   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
02121   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02122 
02123   /* Test with NULL unregister_function and user_data */
02124   if (!_dbus_object_tree_register (tree, TRUE, path2,
02125                                    &test_vtable,
02126                                    NULL,
02127                                    NULL))
02128     goto out;
02129 
02130   _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL);
02131   _dbus_object_tree_unregister_and_unlock (tree, path2);
02132   _dbus_assert (!find_subtree (tree, path2, NULL));
02133   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
02134   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
02135   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02136 
02137   /* Test freeing a long path */
02138   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
02139     goto out;
02140 
02141   _dbus_object_tree_unregister_and_unlock (tree, path3);
02142   _dbus_assert (!find_subtree (tree, path3, NULL));
02143   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
02144   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
02145   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
02146   _dbus_assert (find_subtree_registered_or_unregistered (tree, path0));
02147 
02148   /* Test freeing multiple children from the same path */
02149   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
02150     goto out;
02151   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
02152     goto out;
02153 
02154   _dbus_assert (find_subtree (tree, path3, NULL));
02155   _dbus_assert (find_subtree (tree, path4, NULL));
02156 
02157   _dbus_object_tree_unregister_and_unlock (tree, path3);
02158   _dbus_assert (!find_subtree (tree, path3, NULL));
02159   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
02160   _dbus_assert (find_subtree (tree, path4, NULL));
02161   _dbus_assert (find_subtree_registered_or_unregistered (tree, path4));
02162   _dbus_assert (find_subtree_registered_or_unregistered (tree, path2));
02163   _dbus_assert (find_subtree_registered_or_unregistered (tree, path1));
02164 
02165   _dbus_object_tree_unregister_and_unlock (tree, path4);
02166   _dbus_assert (!find_subtree (tree, path4, NULL));
02167   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path4));
02168   _dbus_assert (!find_subtree (tree, path3, NULL));
02169   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path3));
02170   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path2));
02171   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path1));
02172 
02173   /* Test subtree removal */
02174   if (!_dbus_object_tree_register (tree, TRUE, path12,
02175                                    &test_vtable,
02176                                    NULL,
02177                                    NULL))
02178     goto out;
02179 
02180   _dbus_assert (find_subtree (tree, path12, NULL));
02181 
02182   if (!_dbus_object_tree_register (tree, TRUE, path13,
02183                                    &test_vtable,
02184                                    NULL,
02185                                    NULL))
02186     goto out;
02187 
02188   _dbus_assert (find_subtree (tree, path13, NULL));
02189 
02190   if (!_dbus_object_tree_register (tree, TRUE, path14,
02191                                    &test_vtable,
02192                                    NULL,
02193                                    NULL))
02194     goto out;
02195 
02196   _dbus_assert (find_subtree (tree, path14, NULL));
02197 
02198   _dbus_object_tree_unregister_and_unlock (tree, path12);
02199 
02200   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12));
02201   _dbus_assert (find_subtree (tree, path13, NULL));
02202   _dbus_assert (find_subtree (tree, path14, NULL));
02203   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9));
02204   _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
02205 
02206   if (!_dbus_object_tree_register (tree, TRUE, path12,
02207                                    &test_vtable,
02208                                    NULL,
02209                                    NULL))
02210     goto out;
02211 
02212   _dbus_assert (find_subtree (tree, path12, NULL));
02213 
02214   _dbus_object_tree_unregister_and_unlock (tree, path13);
02215 
02216   _dbus_assert (find_subtree (tree, path12, NULL));
02217   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13));
02218   _dbus_assert (find_subtree (tree, path14, NULL));
02219   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10));
02220   _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
02221 
02222   if (!_dbus_object_tree_register (tree, TRUE, path13,
02223                                    &test_vtable,
02224                                    NULL,
02225                                    NULL))
02226     goto out;
02227 
02228   _dbus_assert (find_subtree (tree, path13, NULL));
02229 
02230   _dbus_object_tree_unregister_and_unlock (tree, path14);
02231 
02232   _dbus_assert (find_subtree (tree, path12, NULL));
02233   _dbus_assert (find_subtree (tree, path13, NULL));
02234   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path14));
02235   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path11));
02236   _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
02237 
02238   _dbus_object_tree_unregister_and_unlock (tree, path12);
02239 
02240   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path12));
02241   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path9));
02242   _dbus_assert (find_subtree_registered_or_unregistered (tree, path5));
02243 
02244   _dbus_object_tree_unregister_and_unlock (tree, path13);
02245 
02246   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path13));
02247   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path10));
02248   _dbus_assert (!find_subtree_registered_or_unregistered (tree, path5));
02249 
02250 #if 0
02251   /* Test attempting to unregister non-existent paths.  These trigger
02252      "Attempted to unregister path ..." warning messages */
02253   _dbus_object_tree_unregister_and_unlock (tree, path0);
02254   _dbus_object_tree_unregister_and_unlock (tree, path1);
02255   _dbus_object_tree_unregister_and_unlock (tree, path2);
02256   _dbus_object_tree_unregister_and_unlock (tree, path3);
02257   _dbus_object_tree_unregister_and_unlock (tree, path4);
02258 #endif
02259 
02260   /* Register it all again, and test dispatch */
02261   
02262   if (!do_register (tree, path0, TRUE, 0, tree_test_data))
02263     goto out;
02264   if (!do_register (tree, path1, FALSE, 1, tree_test_data))
02265     goto out;
02266   if (!do_register (tree, path2, TRUE, 2, tree_test_data))
02267     goto out;
02268   if (!do_register (tree, path3, TRUE, 3, tree_test_data))
02269     goto out;
02270   if (!do_register (tree, path4, TRUE, 4, tree_test_data))
02271     goto out;
02272   if (!do_register (tree, path5, TRUE, 5, tree_test_data))
02273     goto out;
02274   if (!do_register (tree, path6, FALSE, 6, tree_test_data))
02275     goto out;
02276   if (!do_register (tree, path7, TRUE, 7, tree_test_data))
02277     goto out;
02278   if (!do_register (tree, path8, TRUE, 8, tree_test_data))
02279     goto out;
02280 
02281 #if 0
02282   spew_tree (tree);
02283 #endif
02284 
02285   if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02286     goto out;
02287   if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02288     goto out;
02289   if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02290     goto out;
02291   if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02292     goto out;
02293   if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02294     goto out;
02295   if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02296     goto out;
02297   if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02298     goto out;
02299   if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02300     goto out;
02301   if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
02302     goto out;
02303   
02304  out:
02305   if (tree)
02306     {
02307       /* test ref */
02308       _dbus_object_tree_ref (tree);
02309       _dbus_object_tree_unref (tree);
02310       _dbus_object_tree_unref (tree);
02311     }
02312 
02313   return TRUE;
02314 }
02315 
02321 dbus_bool_t
02322 _dbus_object_tree_test (void)
02323 {
02324   _dbus_test_oom_handling ("object tree",
02325                            object_tree_test_iteration,
02326                            NULL);
02327 
02328   return TRUE;
02329 }
02330 
02331 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
02332 
02333 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */