Replace the custom rbtree by a std::map
authorJocelyn Turcotte <jturcotte@woboq.com>
Wed, 23 Aug 2017 17:16:12 +0000 (19:16 +0200)
committerRoeland Jago Douma <roeland@famdouma.nl>
Thu, 5 Oct 2017 20:01:33 +0000 (22:01 +0200)
18 files changed:
src/csync/csync.cpp
src/csync/csync_private.h
src/csync/csync_reconcile.cpp
src/csync/csync_rename.cpp
src/csync/csync_rename.h
src/csync/csync_statedb.cpp
src/csync/csync_update.cpp
src/csync/std/CMakeLists.txt
src/csync/std/c_lib.h
src/csync/std/c_rbtree.c [deleted file]
src/csync/std/c_rbtree.h [deleted file]
src/libsync/discoveryphase.cpp
src/libsync/discoveryphase.h
src/libsync/syncengine.cpp
test/csync/CMakeLists.txt
test/csync/csync_tests/check_csync_statedb_query.cpp
test/csync/csync_tests/check_csync_update.cpp
test/csync/std_tests/check_std_c_rbtree.c [deleted file]

index b37e2bdcd8ccea58ee26a8be25cc63119b6da8a5..ac096ae2b79e3b353b50493d22f4a44bdb3a01bf 100644 (file)
 #include "csync_rename.h"
 #include "c_jhash.h"
 
-static int _key_cmp(const void *key, const void *data) {
-  uint64_t a;
-  csync_file_stat_t *b;
-
-  a = *(uint64_t *) (key);
-  b = (csync_file_stat_t *) data;
-
-  if (a < b->phash) {
-    return -1;
-  } else if (a > b->phash) {
-    return 1;
-  }
-
-  return 0;
-}
-
-static int _data_cmp(const void *key, const void *data) {
-  csync_file_stat_t *a, *b;
-
-  a = (csync_file_stat_t *) key;
-  b = (csync_file_stat_t *) data;
-
-  if (a->phash < b->phash) {
-    return -1;
-  } else if (a->phash > b->phash) {
-    return 1;
-  }
-
-  return 0;
-}
 
 csync_s::csync_s(const char *localUri, const char *db_file) {
   size_t len = 0;
@@ -91,9 +61,6 @@ csync_s::csync_s(const char *localUri, const char *db_file) {
 
   local.uri = c_strndup(localUri, len);
 
-  c_rbtree_create(&local.tree, _key_cmp, _data_cmp);
-  c_rbtree_create(&remote.tree, _key_cmp, _data_cmp);
-
   statedb.file = c_strdup(db_file);
 }
 
@@ -137,7 +104,7 @@ int csync_update(CSYNC *ctx) {
 
   CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
             "Update detection for local replica took %.2f seconds walking %zu files.",
-            c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
+            c_secdiff(finish, start), ctx->local.files.size());
   csync_memstat_check();
 
   /* update detection for remote replica */
@@ -157,7 +124,7 @@ int csync_update(CSYNC *ctx) {
   CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
             "Update detection for remote replica took %.2f seconds "
             "walking %zu files.",
-            c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
+            c_secdiff(finish, start), ctx->remote.files.size());
   csync_memstat_check();
 
   ctx->status |= CSYNC_STATUS_UPDATE;
@@ -195,7 +162,7 @@ int csync_reconcile(CSYNC *ctx) {
 
   CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
       "Reconciliation for local replica took %.2f seconds visiting %zu files.",
-      c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
+      c_secdiff(finish, start), ctx->local.files.size());
 
   if (rc < 0) {
       if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
@@ -215,7 +182,7 @@ int csync_reconcile(CSYNC *ctx) {
 
   CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
       "Reconciliation for remote replica took %.2f seconds visiting %zu files.",
-      c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
+      c_secdiff(finish, start), ctx->remote.files.size());
 
   if (rc < 0) {
       if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
@@ -236,17 +203,11 @@ out:
 /*
  * local visitor which calls the user visitor with repacked stat info.
  */
-static int _csync_treewalk_visitor(void *obj, void *data) {
+static int _csync_treewalk_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
     int rc = 0;
-    csync_file_stat_t *cur         = NULL;
-    CSYNC *ctx                     = NULL;
     csync_treewalk_visit_func *visitor   = NULL;
     _csync_treewalk_context *twctx = NULL;
-    c_rbtree_t *other_tree = NULL;
-    c_rbnode_t *other_node = NULL;
-
-    cur = (csync_file_stat_t *) obj;
-    ctx = (CSYNC *) data;
+    csync_s::FileMap *other_tree = nullptr;
 
     if (ctx == NULL) {
       return -1;
@@ -255,51 +216,33 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
     /* we need the opposite tree! */
     switch (ctx->current) {
     case LOCAL_REPLICA:
-        other_tree = ctx->remote.tree;
+        other_tree = &ctx->remote.files;
         break;
     case REMOTE_REPLICA:
-        other_tree = ctx->local.tree;
+        other_tree = &ctx->local.files;
         break;
     default:
         break;
     }
 
-    other_node = c_rbtree_find(other_tree, &cur->phash);
+    csync_s::FileMap::const_iterator other_file_it = other_tree->find(cur->path);
 
-    if (!other_node) {
+    if (other_file_it == other_tree->cend()) {
         /* Check the renamed path as well. */
-        int len;
-        uint64_t h = 0;
-        char *renamed_path = csync_rename_adjust_path(ctx, cur->path);
-
-        if (!c_streq(renamed_path, cur->path)) {
-            len = strlen( renamed_path );
-            h = c_jhash64((uint8_t *) renamed_path, len, 0);
-            other_node = c_rbtree_find(other_tree, &h);
-        }
-        SAFE_FREE(renamed_path);
+        QByteArray renamed_path = csync_rename_adjust_path(ctx, cur->path);
+        if (renamed_path != cur->path)
+            other_file_it = other_tree->find(renamed_path);
     }
 
-    if (!other_node) {
+    if (other_file_it == other_tree->cend()) {
         /* Check the source path as well. */
-        int len;
-        uint64_t h = 0;
-        char *renamed_path = csync_rename_adjust_path_source(ctx, cur->path);
-
-        if (!c_streq(renamed_path, cur->path)) {
-            len = strlen( renamed_path );
-            h = c_jhash64((uint8_t *) renamed_path, len, 0);
-            other_node = c_rbtree_find(other_tree, &h);
-        }
-        SAFE_FREE(renamed_path);
+        QByteArray renamed_path = csync_rename_adjust_path_source(ctx, cur->path);
+        if (renamed_path != cur->path)
+            other_file_it = other_tree->find(renamed_path);
     }
 
-    csync_file_stat_t *other = other_node ? (csync_file_stat_t*)other_node->data : NULL;
+    csync_file_stat_t *other = (other_file_it != other_tree->cend()) ? other_file_it->second.get() : NULL;
 
-    if (obj == NULL || data == NULL) {
-      ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
-      return -1;
-    }
     ctx->status_code = CSYNC_STATUS_OK;
 
     twctx = (_csync_treewalk_context*) ctx->callbacks.userdata;
@@ -331,28 +274,24 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
  * which calls the local _csync_treewalk_visitor in this module.
  * The user visitor is called from there.
  */
-static int _csync_walk_tree(CSYNC *ctx, c_rbtree_t *tree, csync_treewalk_visit_func *visitor, int filter)
+static int _csync_walk_tree(CSYNC *ctx, csync_s::FileMap *tree, csync_treewalk_visit_func *visitor, int filter)
 {
     _csync_treewalk_context tw_ctx;
-    int rc = -1;
-
-    if (ctx == NULL) {
-        errno = EBADF;
-        return rc;
-    }
+    int rc = 0;
 
-    if (visitor == NULL || tree == NULL) {
-        ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
-        return rc;
-    }
-    
     tw_ctx.userdata = ctx->callbacks.userdata;
     tw_ctx.user_visitor = visitor;
     tw_ctx.instruction_filter = filter;
 
     ctx->callbacks.userdata = &tw_ctx;
 
-    rc = c_rbtree_walk(tree, (void*) ctx, _csync_treewalk_visitor);
+    for (auto &pair : *tree) {
+        if (_csync_treewalk_visitor(pair.second.get(), ctx) < 0) {
+          rc = -1;
+          break;
+        }
+    }
+
     if( rc < 0 ) {
       if( ctx->status_code == CSYNC_STATUS_OK )
           ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR);
@@ -367,18 +306,9 @@ static int _csync_walk_tree(CSYNC *ctx, c_rbtree_t *tree, csync_treewalk_visit_f
  */
 int csync_walk_remote_tree(CSYNC *ctx,  csync_treewalk_visit_func *visitor, int filter)
 {
-    c_rbtree_t *tree = NULL;
-    int rc = -1;
-
-    if(ctx != NULL) {
-        ctx->status_code = CSYNC_STATUS_OK;
-        ctx->current = REMOTE_REPLICA;
-        tree = ctx->remote.tree;
-    }
-
-    /* all error handling in the called function */
-    rc = _csync_walk_tree(ctx, tree, visitor, filter);
-    return rc;
+    ctx->status_code = CSYNC_STATUS_OK;
+    ctx->current = REMOTE_REPLICA;
+    return _csync_walk_tree(ctx, &ctx->remote.files, visitor, filter);
 }
 
 /*
@@ -386,25 +316,9 @@ int csync_walk_remote_tree(CSYNC *ctx,  csync_treewalk_visit_func *visitor, int
  */
 int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter)
 {
-    c_rbtree_t *tree = NULL;
-    int rc = -1;
-
-    if (ctx != NULL) {
-        ctx->status_code = CSYNC_STATUS_OK;
-        ctx->current = LOCAL_REPLICA;
-        tree = ctx->local.tree;
-    }
-
-    /* all error handling in the called function */
-    rc = _csync_walk_tree(ctx, tree, visitor, filter);
-    return rc;  
-}
-
-static void _tree_destructor(void *data) {
-  csync_file_stat_t *freedata = NULL;
-
-  freedata = (csync_file_stat_t *) data;
-  delete freedata;
+    ctx->status_code = CSYNC_STATUS_OK;
+    ctx->current = LOCAL_REPLICA;
+    return _csync_walk_tree(ctx, &ctx->local.files, visitor, filter);
 }
 
 int csync_s::reinitialize() {
@@ -419,26 +333,12 @@ int csync_s::reinitialize() {
   }
   statedb.db = NULL;
 
-  /* destroy the rbtrees */
-  if (c_rbtree_size(local.tree) > 0) {
-    c_rbtree_destroy(local.tree, _tree_destructor);
-  }
-
-  if (c_rbtree_size(remote.tree) > 0) {
-    c_rbtree_destroy(remote.tree, _tree_destructor);
-  }
-
-  /* free memory */
-  c_rbtree_free(local.tree);
-  c_rbtree_free(remote.tree);
-
   remote.read_from_db = 0;
   read_remote_from_db = true;
   db_is_empty = false;
 
-  /* Create new trees */
-  c_rbtree_create(&local.tree, _key_cmp, _data_cmp);
-  c_rbtree_create(&remote.tree, _key_cmp, _data_cmp);
+  local.files.clear();
+  remote.files.clear();
 
   status = CSYNC_STATUS_INIT;
   SAFE_FREE(error_string);
@@ -454,19 +354,6 @@ csync_s::~csync_s() {
   }
   statedb.db = NULL;
 
-  /* destroy the rbtrees */
-  if (c_rbtree_size(local.tree) > 0) {
-    c_rbtree_destroy(local.tree, _tree_destructor);
-  }
-
-  if (c_rbtree_size(remote.tree) > 0) {
-    c_rbtree_destroy(remote.tree, _tree_destructor);
-  }
-
-  /* free memory */
-  c_rbtree_free(local.tree);
-  c_rbtree_free(remote.tree);
-
   SAFE_FREE(statedb.file);
   SAFE_FREE(local.uri);
   SAFE_FREE(error_string);
index 605e1b2523c69c0481d1fbd68c7eddb279c5480f..53383db89c67c98d5c401daa42c45543aaf9182e 100644 (file)
@@ -36,6 +36,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <sqlite3.h>
+#include <map>
 
 #include "config_csync.h"
 #include "std/c_lib.h"
@@ -69,6 +70,14 @@ enum csync_replica_e {
  * @brief csync public structure
  */
 struct OCSYNC_EXPORT csync_s {
+  class FileMap : public std::map<QByteArray, std::unique_ptr<csync_file_stat_t>> {
+  public:
+      csync_file_stat_t *findFile(const QByteArray &key) const {
+          auto it = find(key);
+          return it != end() ? it->second.get() : nullptr;
+      }
+  };
+
   struct {
       csync_auth_callback auth_function = nullptr;
       void *userdata = nullptr;
@@ -76,8 +85,8 @@ struct OCSYNC_EXPORT csync_s {
       void *update_callback_userdata = nullptr;
 
       /* hooks for checking the white list (uses the update_callback_userdata) */
-      int (*checkSelectiveSyncBlackListHook)(void*, const char*) = nullptr;
-      int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */) = nullptr;
+      int (*checkSelectiveSyncBlackListHook)(void*, const QByteArray &) = nullptr;
+      int (*checkSelectiveSyncNewFolderHook)(void*, const QByteArray &/* path */, const QByteArray &/* remotePerm */) = nullptr;
 
 
       csync_vio_opendir_hook remote_opendir_hook = nullptr;
@@ -105,17 +114,17 @@ struct OCSYNC_EXPORT csync_s {
   } statedb;
 
   struct {
-    std::map<std::string, std::string> folder_renamed_to; // map from->to
-    std::map<std::string, std::string> folder_renamed_from; // map to->from
+    std::map<QByteArray, QByteArray> folder_renamed_to; // map from->to
+    std::map<QByteArray, QByteArray> folder_renamed_from; // map to->from
   } renames;
 
   struct {
     char *uri = nullptr;
-    c_rbtree_t *tree = nullptr;
+    FileMap files;
   } local;
 
   struct {
-    c_rbtree_t *tree = nullptr;
+    FileMap files;
     bool read_from_db = false;
     QByteArray root_perms; /* Permission of the root folder. (Since the root folder is not in the db tree, we need to keep a separate entry.) */
   } remote;
@@ -151,6 +160,13 @@ struct OCSYNC_EXPORT csync_s {
   csync_s(const char *localUri, const char *db_file);
   ~csync_s();
   int reinitialize();
+
+  // For some reason MSVC references the copy constructor and/or the assignment operator
+  // if a class is exported. This is a problem since unique_ptr isn't copyable.
+  // Explicitly disable them to fix the issue.
+  // https://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/e39ab33d-1aaf-4125-b6de-50410d9ced1d
+  csync_s(const csync_s &) = delete;
+  csync_s &operator=(const csync_s &) = delete;
 };
 
 /*
index 760c5ca463f234e20816c087238c5a91c1574d7a..ee7eee7a190aff9a4f946a515d6dbbe0907a5d46 100644 (file)
 
 /* Check if a file is ignored because one parent is ignored.
  * return the node of the ignored directoy if it's the case, or NULL if it is not ignored */
-static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int pathlen) {
-    uint64_t h = 0;
-    c_rbnode_t *node = NULL;
-
+static csync_file_stat_t *_csync_check_ignored(csync_s::FileMap *tree, const QByteArray &path) {
     /* compute the size of the parent directory */
-    int parentlen = pathlen - 1;
-    while (parentlen > 0 && path[parentlen] != '/') {
+    int parentlen = path.size() - 1;
+    while (parentlen > 0 && path.at(parentlen) != '/') {
         parentlen--;
     }
     if (parentlen <= 0) {
-        return NULL;
+        return nullptr;
     }
-
-    h = c_jhash64((uint8_t *) path, parentlen, 0);
-    node = c_rbtree_find(tree, &h);
-    if (node) {
-        csync_file_stat_t *n = (csync_file_stat_t*)node->data;
-        if (n->instruction == CSYNC_INSTRUCTION_IGNORE) {
+    QByteArray parentPath = path.left(parentlen);
+    csync_file_stat_t *fs = tree->findFile(parentPath);
+    if (fs) {
+        if (fs->instruction == CSYNC_INSTRUCTION_IGNORE) {
             /* Yes, we are ignored */
-            return node;
+            return fs;
         } else {
             /* Not ignored */
-            return NULL;
+            return nullptr;
         }
     } else {
         /* Try if the parent itself is ignored */
-        return _csync_check_ignored(tree, path, parentlen);
+        return _csync_check_ignored(tree, parentPath);
     }
 }
 
@@ -83,7 +78,7 @@ static bool _csync_is_collision_safe_hash(const char *checksum_header)
 /**
  * The main function in the reconcile pass.
  *
- * It's called for each entry in the local and remote rbtrees by
+ * It's called for each entry in the local and remote files by
  * csync_reconcile()
  *
  * Before the reconcile phase the trees already know about changes
@@ -107,52 +102,37 @@ static bool _csync_is_collision_safe_hash(const char *checksum_header)
  * (timestamp is newer), it is not overwritten. If both files, on the
  * source and the destination, have been changed, the newer file wins.
  */
-static int _csync_merge_algorithm_visitor(void *obj, void *data) {
-    csync_file_stat_t *cur = NULL;
-    csync_file_stat_t *other = NULL;
+static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) {
     std::unique_ptr<csync_file_stat_t> tmp;
-    uint64_t h = 0;
-    int len = 0;
-
-    CSYNC *ctx = NULL;
-    c_rbtree_t *tree = NULL;
-    c_rbnode_t *node = NULL;
 
-    cur = (csync_file_stat_t *) obj;
-    ctx = (CSYNC *) data;
+    csync_s::FileMap *other_tree = nullptr;
 
     /* we need the opposite tree! */
     switch (ctx->current) {
     case LOCAL_REPLICA:
-        tree = ctx->remote.tree;
+        other_tree = &ctx->remote.files;
         break;
     case REMOTE_REPLICA:
-        tree = ctx->local.tree;
+        other_tree = &ctx->local.files;
         break;
     default:
         break;
     }
 
-    node = c_rbtree_find(tree, &cur->phash);
+    csync_file_stat_t *other = other_tree->findFile(cur->path);;
 
-    if (!node) {
+    if (!other) {
         /* Check the renamed path as well. */
-        char *renamed_path = csync_rename_adjust_path(ctx, cur->path);
-        if (renamed_path != cur->path) {
-            len = strlen( renamed_path );
-            h = c_jhash64((uint8_t *) renamed_path, len, 0);
-            node = c_rbtree_find(tree, &h);
-        }
-        SAFE_FREE(renamed_path);
+        other = other_tree->findFile(csync_rename_adjust_path(ctx, cur->path));
     }
-    if (!node) {
+    if (!other) {
         /* Check if it is ignored */
-        node = _csync_check_ignored(tree, cur->path, cur->path.size());
+        other = _csync_check_ignored(other_tree, cur->path);
         /* If it is ignored, other->instruction will be  IGNORE so this one will also be ignored */
     }
 
     /* file only found on current replica */
-    if (node == NULL) {
+    if (!other) {
         switch(cur->instruction) {
         /* file has been modified */
         case CSYNC_INSTRUCTION_EVAL:
@@ -187,26 +167,20 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
             }
 
             if( tmp ) {
-                len = strlen( tmp->path );
-                if( len > 0 ) {
-                    h = c_jhash64((uint8_t *) tmp->path.constData(), len, 0);
+                if( !tmp->path.isEmpty() ) {
                     /* First, check that the file is NOT in our tree (another file with the same name was added) */
-                    node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h);
-                    if (node) {
+                    csync_s::FileMap *our_tree = ctx->current == REMOTE_REPLICA ? &ctx->remote.files : &ctx->local.files;
+                       if (our_tree->findFile(tmp->path)) {
                         CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path.constData());
                     } else {
-                        /* Find the temporar file in the other tree. */
-                        node = c_rbtree_find(tree, &h);
-                        CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "PHash of temporary opposite (%s): %" PRIu64 " %s",
-                                tmp->path.constData() , h, node ? "found": "not found" );
-                        if (node) {
-                            other = (csync_file_stat_t*)node->data;
-                        } else {
-                            /* the renamed file could not be found in the opposite tree. That is because it
-                            * is not longer existing there, maybe because it was renamed or deleted.
-                            * The journal is cleaned up later after propagation.
-                            */
-                        }
+                    /* Find the temporar file in the other tree.
+                    * If the renamed file could not be found in the opposite tree, that is because it
+                    * is not longer existing there, maybe because it was renamed or deleted.
+                    * The journal is cleaned up later after propagation.
+                    */
+                    other = other_tree->findFile(tmp->path);
+                    CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Temporary opposite (%s) %s",
+                            tmp->path.constData() , other ? "found": "not found" );
                     }
                 }
 
@@ -250,7 +224,6 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
         /*
      * file found on the other replica
      */
-        other = (csync_file_stat_t *) node->data;
 
         switch (cur->instruction) {
         case CSYNC_INSTRUCTION_UPDATE_METADATA:
@@ -395,25 +368,26 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
 }
 
 int csync_reconcile_updates(CSYNC *ctx) {
-  int rc;
-  c_rbtree_t *tree = NULL;
+  csync_s::FileMap *tree = nullptr;
 
   switch (ctx->current) {
     case LOCAL_REPLICA:
-      tree = ctx->local.tree;
+      tree = &ctx->local.files;
       break;
     case REMOTE_REPLICA:
-      tree = ctx->remote.tree;
+      tree = &ctx->remote.files;
       break;
     default:
       break;
   }
 
-  rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor);
-  if( rc < 0 ) {
-    ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR;
+  for (auto &pair : *tree) {
+    if (_csync_merge_algorithm_visitor(pair.second.get(), ctx) < 0) {
+      ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR;
+      return -1;
+    }
   }
-  return rc;
+  return 0;
 }
 
 /* vim: set ts=8 sw=2 et cindent: */
index 5196020eed0c38ab4772d26222883975ac86a168..ef825a606d8219e5d921e1892646118d9fea4d9e 100644 (file)
 #include "csync_private.h"
 #include "csync_rename.h"
 
-#include <string>
-#include <vector>
 #include <algorithm>
 
-static std::string _parentDir(const std::string &path) {
+static QByteArray _parentDir(const QByteArray &path) {
     int len = path.length();
-    while(len > 0 && path[len-1]!='/') len--;
-    while(len > 0 && path[len-1]=='/') len--;
-    return path.substr(0, len);
+    while(len > 0 && path.at(len-1)!='/') len--;
+    while(len > 0 && path.at(len-1)=='/') len--;
+    return path.left(len);
 }
 
-void csync_rename_record(CSYNC* ctx, const char* from, const char* to)
+void csync_rename_record(CSYNC* ctx, const QByteArray &from, const QByteArray &to)
 {
     ctx->renames.folder_renamed_to[from] = to;
     ctx->renames.folder_renamed_from[to] = from;
 }
 
-char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
+QByteArray csync_rename_adjust_path(CSYNC* ctx, const QByteArray &path)
 {
-    for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) {
-        std::map< std::string, std::string >::iterator it = ctx->renames.folder_renamed_to.find(p);
+    for (QByteArray p = _parentDir(path); !p.isEmpty(); p = _parentDir(p)) {
+        std::map< QByteArray, QByteArray >::iterator it = ctx->renames.folder_renamed_to.find(p);
         if (it != ctx->renames.folder_renamed_to.end()) {
-            std::string rep = it->second + (path + p.length());
-            return c_strdup(rep.c_str());
+            QByteArray rep = it->second + path.mid(p.length());
+            return rep;
         }
     }
-    return c_strdup(path);
+    return path;
 }
 
-char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path)
+QByteArray csync_rename_adjust_path_source(CSYNC* ctx, const QByteArray &path)
 {
-    for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) {
-        std::map< std::string, std::string >::iterator it = ctx->renames.folder_renamed_from.find(p);
+    for (QByteArray p = _parentDir(path); !p.isEmpty(); p = _parentDir(p)) {
+        std::map< QByteArray, QByteArray >::iterator it = ctx->renames.folder_renamed_from.find(p);
         if (it != ctx->renames.folder_renamed_from.end()) {
-            std::string rep = it->second + (path + p.length());
-            return c_strdup(rep.c_str());
+            QByteArray rep = it->second + path.mid(p.length());
+            return rep;
         }
     }
-    return c_strdup(path);
+    return path;
 }
 
 bool csync_rename_count(CSYNC *ctx) {
index 509b78afcc61f78929647d0b7c29fa5178531a9d..194f4256c8b5fa45df28c374bc1e342bc897dd9c 100644 (file)
@@ -23,9 +23,9 @@
 #include "csync.h"
 
 /* Return the final destination path of a given patch in case of renames */
-char OCSYNC_EXPORT *csync_rename_adjust_path(CSYNC *ctx, const char *path);
+QByteArray OCSYNC_EXPORT csync_rename_adjust_path(CSYNC *ctx, const QByteArray &path);
 /* Return the source of a given path in case of renames */
-char OCSYNC_EXPORT *csync_rename_adjust_path_source(CSYNC *ctx, const char *path);
-void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const char *from, const char *to);
+QByteArray OCSYNC_EXPORT csync_rename_adjust_path_source(CSYNC *ctx, const QByteArray &path);
+void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const QByteArray &from, const QByteArray &to);
 /*  Return the amount of renamed item recorded */
 bool OCSYNC_EXPORT csync_rename_count(CSYNC *ctx);
index 4d2598f79af350ef35dcbe3377191025a494acd9..ca5b615379b7bd36e9a7f1f1e2606f7e02bb1586 100644 (file)
@@ -486,18 +486,15 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
             }
 
             /* store into result list. */
-            if (c_rbtree_insert(ctx->remote.tree, (void *) st.release()) < 0) {
-                st.reset();
-                ctx->status_code = CSYNC_STATUS_TREE_ERROR;
-                break;
-            }
+            QByteArray path = st->path;
+            ctx->remote.files[path] = std::move(st);
             cnt++;
         }
     } while( rc == SQLITE_ROW );
 
     ctx->statedb.lastReturnValue = rc;
     if( rc != SQLITE_DONE ) {
-        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
+        ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
     } else {
         CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
     }
index 91afc8eb6437df535aa37ef4c3b1b04b7cd12b5e..f637572425a94acd71a9c43110e7b3cf957ab95b 100644 (file)
@@ -383,18 +383,13 @@ out:
   CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", fs->path.constData(),
       csync_instruction_str(fs->instruction));
 
+  QByteArray path = fs->path;
   switch (ctx->current) {
     case LOCAL_REPLICA:
-      if (c_rbtree_insert(ctx->local.tree, (void *) fs.release()) < 0) {
-        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
-        return -1;
-      }
+      ctx->local.files[path] = std::move(fs);
       break;
     case REMOTE_REPLICA:
-      if (c_rbtree_insert(ctx->remote.tree, (void *) fs.release()) < 0) {
-        ctx->status_code = CSYNC_STATUS_TREE_ERROR;
-        return -1;
-      }
+      ctx->remote.files[path] = std::move(fs);
       break;
     default:
       break;
index ef7a25bd3c0332a2095346961c0c6f6f214392ec..fddd02e996d462683b3e02c7bb1b3038212c1ff3 100644 (file)
@@ -17,7 +17,6 @@ set(CSTDLIB_LINK_LIBRARIES
 set(cstdlib_SRCS
   c_alloc.c
   c_path.c
-  c_rbtree.c
   c_string.c
   c_time.c
   c_utf8.cpp
index b9c1ea8d31c01122d3e4a58e64ba5a801b3f60aa..43f352ff420013730d67a63dfe15423ce0af3427 100644 (file)
@@ -24,7 +24,6 @@
 #include "c_macro.h"
 #include "c_alloc.h"
 #include "c_path.h"
-#include "c_rbtree.h"
 #include "c_string.h"
 #include "c_time.h"
 #include "c_private.h"
diff --git a/src/csync/std/c_rbtree.c b/src/csync/std/c_rbtree.c
deleted file mode 100644 (file)
index 9a38fd0..0000000
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * cynapses libc functions
- *
- * Copyright (c) 2003-2004 by Andrew Suffield <asuffield@debian.org>
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This code was originally released under GPL but Andrew Suffield agreed to
- * change it to LGPL.
- */
-
-/*
- * static function don't have NULL pointer checks, segfaults are intended.
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "c_alloc.h"
-#include "c_rbtree.h"
-
-#define NIL &_sentinel /* all leafs are sentinels */
-static c_rbnode_t _sentinel = {NULL, NIL, NIL, NULL, NULL, BLACK};
-
-void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare) {
-  assert(rbtree);
-  assert(key_compare);
-  assert(data_compare);
-
-  c_rbtree_t *tree = NULL;
-
-  tree = c_malloc(sizeof(*tree));
-  tree->root = NIL;
-  tree->key_compare = key_compare;
-  tree->data_compare = data_compare;
-  tree->size = 0;
-
-  *rbtree = tree;
-}
-
-static c_rbnode_t *_rbtree_subtree_dup(const c_rbnode_t *node, c_rbtree_t *new_tree, c_rbnode_t *new_parent) {
-  c_rbnode_t *new_node = NULL;
-
-  new_node = (c_rbnode_t*) c_malloc(sizeof(c_rbnode_t));
-
-  new_node->tree = new_tree;
-  new_node->data = node->data;
-  new_node->color = node->color;
-  new_node->parent = new_parent;
-
-  if (node->left == NIL) {
-    new_node->left = NIL;
-  } else {
-    new_node->left = _rbtree_subtree_dup(node->left, new_tree, new_node);
-  }
-
-  if (node->right == NIL) {
-    new_node->right = NIL;
-  } else {
-    new_node->right = _rbtree_subtree_dup(node->right, new_tree, new_node);
-  }
-
-  return new_node;
-}
-
-c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree) {
-  c_rbtree_t *new_tree = NULL;
-
-  new_tree = (c_rbtree_t*) c_malloc(sizeof(c_rbtree_t));
-
-  new_tree->key_compare = tree->key_compare;
-  new_tree->data_compare = tree->data_compare;
-  new_tree->size = tree->size;
-  new_tree->root = _rbtree_subtree_dup(tree->root, new_tree, NULL);
-
-  return new_tree;
-}
-
-static int _rbtree_subtree_free(c_rbnode_t *node) {
-  assert(node);
-
-  if (node->left != NIL) {
-    if (_rbtree_subtree_free(node->left) < 0) {
-      /* TODO: set errno? ECANCELED? */
-      return -1;
-    }
-  }
-
-  if (node->right != NIL) {
-    if (_rbtree_subtree_free(node->right) < 0) {
-      /* TODO: set errno? ECANCELED? */
-      return -1;
-    }
-  }
-
-  SAFE_FREE(node);
-
-  return 0;
-}
-
-int c_rbtree_free(c_rbtree_t *tree) {
-  if (tree == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  if (tree->root != NIL) {
-    _rbtree_subtree_free(tree->root);
-  }
-
-  SAFE_FREE(tree);
-
-  return 0;
-}
-
-static int _rbtree_subtree_walk(c_rbnode_t *node, void *data, c_rbtree_visit_func *visitor) {
-  assert(node);
-  assert(data);
-  assert(visitor);
-
-  if (node == NIL) {
-    return 0;
-  }
-
-  if (_rbtree_subtree_walk(node->left, data, visitor) < 0) {
-    return -1;
-  }
-
-  if ((*visitor)(node->data, data) < 0) {
-    return -1;
-  }
-
-  if (_rbtree_subtree_walk(node->right, data, visitor) < 0) {
-    return -1;
-  }
-
-  return 0;
-}
-
-int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor) {
-  if (tree == NULL || data == NULL || visitor == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  if (_rbtree_subtree_walk(tree->root, data, visitor) < 0) {
-    return -1;
-  }
-
-  return 0;
-}
-
-static c_rbnode_t *_rbtree_subtree_head(c_rbnode_t *node) {
-  assert(node);
-
-  if (node == NIL) {
-    return node;
-  }
-
-  while (node->left != NIL) {
-    node = node->left;
-  }
-
-  return node;
-}
-
-static c_rbnode_t *_rbtree_subtree_tail(c_rbnode_t *node) {
-  assert(node);
-
-  if (node == NIL) {
-    return node;
-  }
-
-  while (node->right != NIL) {
-    node = node->right;
-  }
-
-  return node;
-}
-
-c_rbnode_t *c_rbtree_head(c_rbtree_t *tree) {
-  c_rbnode_t *node = NULL;
-
-  if (tree == NULL) {
-    errno = EINVAL;
-    return NULL;
-  }
-
-  node = _rbtree_subtree_head(tree->root);
-
-  return node != NIL ? node : NULL;
-}
-
-c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree) {
-  c_rbnode_t *node = NULL;
-
-  if (tree == NULL) {
-    errno = EINVAL;
-    return NULL;
-  }
-
-  node = _rbtree_subtree_tail(tree->root);
-
-  return node != NIL ? node : NULL;
-}
-
-c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node) {
-  c_rbnode_t *parent = NULL;
-
-  if (node == NULL) {
-    errno = EINVAL;
-    return NULL;
-  }
-
-  if (node->right != NIL) {
-    c_rbnode_t *next = NULL;
-    next = _rbtree_subtree_head(node->right);
-
-    return next != NIL ? next : NULL;
-  }
-
-  parent = node->parent;
-  while (parent && node == parent->right) {
-    node = parent;
-    parent = node->parent;
-  }
-
-  return parent != NULL ? parent : NULL;
-}
-
-c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node) {
-  c_rbnode_t *parent = NULL;
-
-  if (node == NULL) {
-    return NULL;
-  }
-
-  if (node->left != NIL) {
-    c_rbnode_t *prev = NULL;
-    prev = _rbtree_subtree_tail(node->left);
-    return prev != NIL ? prev : NULL;
-  }
-
-  parent = node->parent;
-  while (parent && node == parent->left) {
-    node = parent;
-    parent = node->parent;
-  }
-
-  return parent != NULL ? parent : NULL;
-}
-
-c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key) {
-  int cmp = 0;
-  c_rbnode_t *node = NULL;
-
-  if (tree == NULL) {
-    errno = EINVAL;
-    return NULL;
-  }
-  node = tree->root;
-
-  while (node != NIL) {
-    cmp = tree->key_compare(key, node->data);
-    if (cmp == 0) {
-      return node;
-    }
-
-    if (cmp < 0) {
-      node = node->left;
-    } else {
-        node = node->right;
-    }
-  }
-
-  return NULL;
-}
-
-static void _rbtree_subtree_left_rotate(c_rbnode_t *x) {
-  c_rbnode_t *y = NULL;
-
-  assert(x);
-
-  y = x->right;
-
-  /* establish x-right link */
-  x->right = y->left;
-
-  if (y->left != NIL) {
-    y->left->parent = x;
-  }
-
-  /* establish y->parent link */
-  if (y != NIL) {
-    y->parent = x->parent;
-  }
-
-  if (x->parent) {
-    if (x == x->parent->left) {
-      x->parent->left = y;
-    } else {
-      x->parent->right = y;
-    }
-  } else {
-    x->tree->root = y;
-  }
-
-  /* link x and y */
-  y->left = x;
-  if (x != NIL) {
-    x->parent = y;
-  }
-}
-
-/* rotat node x to the right */
-static void _rbtree_subtree_right_rotate(c_rbnode_t *x) {
-  c_rbnode_t *y = NULL;
-
-  assert(x);
-
-  y = x->left;
-
-  /* establish x->left link */
-  x->left = y->right;
-
-  if (y->right != NIL) {
-    y->right->parent = x;
-  }
-
-  /* establish y->parent link */
-  if (y != NIL) {
-    y->parent = x->parent;
-  }
-
-  if (x->parent) {
-    if (x == x->parent->right) {
-        x->parent->right = y;
-    } else {
-      x->parent->left = y;
-    }
-  } else {
-    x->tree->root = y;
-  }
-
-  /* link x and y */
-  y->right = x;
-  if (x != NIL) {
-    x->parent = y;
-  }
-}
-
-int c_rbtree_insert(c_rbtree_t *tree, void *data) {
-  int cmp = 0;
-  c_rbnode_t *current = NULL;
-  c_rbnode_t *parent = NULL;
-  c_rbnode_t *x = NULL;
-
-  if (tree == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  /* First we do a classic binary tree insert */
-  current = tree->root;
-  parent = NULL;
-
-  while (current != NIL) {
-    cmp = tree->data_compare(data, current->data);
-    parent = current;
-    if (cmp == 0) {
-      return 1;
-    } else if (cmp < 0) {
-      current = current->left;
-    } else {
-      current = current->right;
-    }
-  }
-
-  x = (c_rbnode_t *) c_malloc(sizeof(c_rbnode_t));
-
-  x->tree = tree;
-  x->data = data;
-  x->parent = parent;
-  x->left = NIL;
-  x->right = NIL;
-  x->color = RED;
-
-  if (parent) {
-    /* Note that cmp still contains the comparison of data with
-     * parent->data, from the last pass through the loop above
-     */
-    if (cmp < 0) {
-        parent->left = x;
-    } else {
-        parent->right = x;
-    }
-  } else {
-    tree->root = x;
-  }
-
-  /* Insert fixup - check red-black properties */
-  while (x != tree->root && x->parent->color == RED) {
-    /* we have a violation */
-    if (x->parent == x->parent->parent->left) {
-      c_rbnode_t *y = NULL;
-
-      y = x->parent->parent->right;
-      if (y->color == RED) {
-        x->parent->color = BLACK;
-        y->color = BLACK;
-        x->parent->parent->color = RED;
-        x = x->parent->parent;
-      } else {
-        /* uncle is back */
-        if (x == x->parent->right) {
-          /* make x a left child */
-          x = x->parent;
-          _rbtree_subtree_left_rotate(x);
-        }
-        x->parent->color = BLACK;
-        x->parent->parent->color = RED;
-        _rbtree_subtree_right_rotate(x->parent->parent);
-      }
-    } else {
-      c_rbnode_t *y = NULL;
-
-      y = x->parent->parent->left;
-      if (y->color == RED) {
-        x->parent->color = BLACK;
-        y->color = BLACK;
-        x->parent->parent->color = RED;
-        x = x->parent->parent;
-      } else {
-        /* uncle is back */
-        if (x == x->parent->left) {
-          x = x->parent;
-          _rbtree_subtree_right_rotate(x);
-        }
-        x->parent->color = BLACK;
-        x->parent->parent->color = RED;
-        _rbtree_subtree_left_rotate(x->parent->parent);
-      }
-    }
-  } /* end while */
-  tree->root->color = BLACK;
-
-  tree->size++;
-
-  return 0;
-}
-
-int c_rbtree_node_delete(c_rbnode_t *node) {
-  c_rbtree_t *tree;
-  c_rbnode_t *y;
-  c_rbnode_t *x;
-
-  if (node == NULL || node == NIL) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  tree = node->tree;
-
-  if (node->left == NIL || node->right == NIL) {
-    /* y has a NIL node as a child */
-    y = node;
-  } else {
-    /* find tree successor with a NIL node as a child */
-    y = node;
-    while(y->left != NIL) {
-      y = y->left;
-    }
-  }
-
-  /* x is y's only child */
-  if (y->left != NIL) {
-    x = y->left;
-  } else {
-    x = y->right;
-  }
-
-  /* remove y from the parent chain */
-  x->parent = y->parent;
-
-  if (y->parent) {
-    if (y == y->parent->left) {
-        y->parent->left = x;
-    } else {
-      y->parent->right = x;
-    }
-  } else {
-    y->tree->root = x;
-  }
-
-  /* If y is not the node we're deleting, splice it in place of that
-   * node
-   *
-   * The traditional code would call for us to simply copy y->data, but
-   * that would invalidate the wrong pointer - there might be external
-   * references to this node, and we must preserve its address.
-   */
-  if (y != node) {
-    /* Update y */
-    y->parent = node->parent;
-    y->left = node->left;
-    y->right = node->right;
-
-    /* Update the children and the parent */
-    if (y->left != NIL) {
-        y->left->parent = y;
-    }
-    if (y->right != NIL) {
-      y->right->parent = y;
-    }
-    if (y->parent != NULL) {
-      if (node == y->parent->left) {
-        y->parent->left = y;
-      } else {
-        y->parent->right = y;
-      }
-    } else {
-      y->tree->root = y;
-    }
-  }
-
-  if (y->color == BLACK) {
-    while (x != y->tree->root && x->color == BLACK) {
-      if (x == x->parent->left) {
-        c_rbnode_t *w = NULL;
-
-        w = x->parent->right;
-
-        if (w->color == RED) {
-          w->color = BLACK;
-          x->parent->color = RED;
-          _rbtree_subtree_left_rotate(x->parent);
-          w = x->parent->right;
-        }
-
-        if (w->left->color == BLACK && w->right->color == BLACK) {
-          w->color = RED;
-          x = x->parent;
-        } else {
-          if (w->right->color == BLACK) {
-            w->left->color = BLACK;
-            w->color = RED;
-            _rbtree_subtree_right_rotate(w);
-            w = x->parent->right;
-          }
-          w->color = x->parent->color;
-          x->parent->color = BLACK;
-          w->right->color = BLACK;
-          _rbtree_subtree_left_rotate(x->parent);
-          x = y->tree->root;
-        }
-      } else {
-        c_rbnode_t *w = NULL;
-
-        w = x->parent->left;
-        if (w->color == RED) {
-          w->color = BLACK;
-          x->parent->color = RED;
-          _rbtree_subtree_right_rotate(x->parent);
-          w = x->parent->left;
-        }
-
-        if (w->right->color == BLACK && w->left->color == BLACK) {
-          w->color = RED;
-          x = x->parent;
-        } else {
-          if (w->left->color == BLACK) {
-            w->right->color = BLACK;
-            w->color = RED;
-            _rbtree_subtree_left_rotate(w);
-            w = x->parent->left;
-          }
-          w->color = x->parent->color;
-          x->parent->color = BLACK;
-          w->left->color = BLACK;
-          _rbtree_subtree_right_rotate(x->parent);
-          x = y->tree->root;
-        }
-      }
-    }
-    x->color = BLACK;
-  } /* end if: y->color == BLACK */
-
-  /* node has now been spliced out of the tree */
-  SAFE_FREE(y);
-  tree->size--;
-
-  return 0;
-}
-
-static int _rbtree_subtree_check_black_height(c_rbnode_t *node) {
-  int left = 0;
-  int right = 0;
-
-  assert(node);
-
-  if (node == NIL) {
-    return 0;
-  }
-
-  left = _rbtree_subtree_check_black_height(node->left);
-  right = _rbtree_subtree_check_black_height(node->right);
-  if (left != right) {
-    return -1;
-  }
-
-  return left + (node->color == BLACK);
-}
-
-int c_rbtree_check_sanity(c_rbtree_t *tree) {
-  c_rbnode_t *node = NULL;
-  c_rbnode_t *prev = NULL;
-  c_rbnode_t *next = NULL;
-  c_rbnode_t *tail = NULL;
-  size_t size = 0;
-
-  if (tree == NULL) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  if (! tree->key_compare || ! tree->data_compare) {
-    errno = EINVAL;
-    return -2;
-  }
-
-  /* Iterate the tree */
-  tail = c_rbtree_tail(tree);
-  for (node = c_rbtree_head(tree); node; node = next) {
-    if (node->tree != tree) {
-      return -4;
-    }
-
-    /* We should never see a nil while iterating */
-    if (node == NIL) {
-      return -5;
-    }
-
-    /* node == tree-root iff node->parent == NIL */
-    if (node == tree->root) {
-      if (node->parent != NULL) {
-        return -6;
-      }
-    } else {
-      if (node->parent == NULL) {
-        return -7;
-      }
-    }
-
-    /* Invertability of the iterate functions */
-    if (prev != c_rbtree_node_prev(node)) {
-      return -8;
-    }
-
-    /* Check the iteration sequence */
-    if (prev) {
-      if (tree->data_compare(prev->data, node->data) > 0) {
-        return -9;
-      }
-
-      /* And the other way around, to make sure data_compare is stable */
-      if (tree->data_compare(node->data, prev->data) < 0) {
-        return -10;
-      }
-    }
-
-    /* The binary tree property */
-    if (node->left != NIL) {
-      if (tree->data_compare(node->left->data, node->data) > 0) {
-        return -11;
-      }
-
-      if (tree->data_compare(node->data, node->left->data) < 0) {
-        return -11;
-      }
-    }
-
-    if (node->right != NIL) {
-      if (tree->data_compare(node->data, node->right->data) > 0) {
-        return -12;
-      }
-
-      if (tree->data_compare(node->right->data, node->data) < 0) {
-        return -13;
-      }
-    }
-
-    /* Red-black tree property 3: red nodes have black children */
-    if (node->color == RED) {
-      if (node->left->color == RED) {
-        return -14;
-      }
-      if (node->right->color == RED) {
-        return -15;
-      }
-    }
-
-    /* next == NULL if node == tail */
-    next = c_rbtree_node_next(node);
-    if (next) {
-      if (node == tail) {
-        return -16;
-      }
-    } else {
-      if (node != tail) {
-        return -17;
-      }
-    }
-
-    prev = node;
-    size++;
-  } /* end for loop */
-
-  if (size != tree->size) {
-    return -18;
-  }
-
-  if (_rbtree_subtree_check_black_height(tree->root) < 0) {
-    return -19;
-  }
-
-  return 0;
-}
diff --git a/src/csync/std/c_rbtree.h b/src/csync/std/c_rbtree.h
deleted file mode 100644 (file)
index 69b4c0d..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * cynapses libc functions
- *
- * Copyright (c) 2003-2004 by Andrew Suffield <asuffield@debian.org>
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file c_rbtree.h
- *
- * @brief Interface of the cynapses libc red-black tree implementation
- *
- * A red-black tree is a type of self-balancing binary search tree. It is
- * complex, but has good worst-case running time for its operations and is
- * efficient in practice: it can search, insert, and delete in O(log n)
- * time, where n is the number of elements in the tree.
- *
- * In red-black trees, the leaf nodes are not relevant and do not contain
- * data. Therefore we use a sentinal node to save memory. All references
- * from internal nodes to leaf nodes instead point to the sentinel node.
- *
- * In a red-black tree each node has a color attribute, the value of which
- * is either red or black. In addition to the ordinary requirements imposed
- * on binary search trees, the following additional requirements of any
- * valid red-black tree apply:
- *
- *    1. A node is either red or black.
- *    2. The root is black.
- *    3. All leaves are black, even when the parent is black
- *       (The leaves are the null children.)
- *    4. Both children of every red node are black.
- *    5. Every simple path from a node to a descendant leaf contains the same
- *       number of black nodes, either counting or not counting the null black
- *       nodes. (Counting or not counting the null black nodes does not affect
- *       the structure as long as the choice is used consistently.).
- *
- * These constraints enforce a critical property of red-black trees: that the
- * longest path from the root to a leaf is no more than twice as long as the
- * shortest path from the root to a leaf in that tree. The result is that the
- * tree is roughly balanced. Since operations such as inserting, deleting, and
- * finding values requires worst-case time proportional to the height of the
- * tree, this theoretical upper bound on the height allows red-black trees to
- * be efficient in the worst-case, unlike ordinary binary search trees.
- *
- * http://en.wikipedia.org/wiki/Red-black_tree
- *
- * @defgroup cynRBTreeInternals cynapses libc red-black tree functions
- * @ingroup cynLibraryAPI
- *
- * @{
- */
-#ifndef _C_RBTREE_H
-#define _C_RBTREE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Forward declarations */
-struct c_rbtree_s; typedef struct c_rbtree_s c_rbtree_t;
-struct c_rbnode_s; typedef struct c_rbnode_s c_rbnode_t;
-
-/**
- * Define the two colors for the red-black tree
- */
-enum xrbcolor_e { BLACK = 0, RED }; typedef enum xrbcolor_e xrbcolor_t;
-
-/**
- * @brief Callback function to compare a key with the data from a
- *        red-black tree node.
- *
- * @param key   key as a generic pointer
- * @param data  data as a generic pointer
- *
- * @return   It returns an integer less than, equal to, or greater than zero
- *           depending on the key or data you use. The function is similar
- *           to strcmp().
- */
-typedef int c_rbtree_compare_func(const void *key, const void *data);
-
-/**
- * @brief Visit function for the c_rbtree_walk() function.
- *
- * This function will be called by c_rbtree_walk() for every node. It is up to
- * the developer what the function does. The fist parameter is a node object
- * the second can be of any kind.
- *
- * @param obj    The node data that will be passed by c_rbtree_walk().
- * @param data   Generic data pointer.
- *
- * @return 0 on success, < 0 on error. You should set errno.
- *
- */
-typedef int c_rbtree_visit_func(void *, void *);
-
-/**
- * Structure that represents a red-black tree
- */
-struct c_rbtree_s {
-  c_rbnode_t *root;
-  c_rbtree_compare_func *key_compare;
-  c_rbtree_compare_func *data_compare;
-  size_t size;
-};
-
-/**
- * Structure that represents a node of a red-black tree
- */
-struct c_rbnode_s {
-  c_rbtree_t *tree;
-  c_rbnode_t *left;
-  c_rbnode_t *right;
-  c_rbnode_t *parent;
-  void *data;
-  xrbcolor_t color;
-};
-
-/**
- * @brief Create the red-black tree
- *
- * @param rbtree        The pointer to assign the allocated memory.
- *
- * @param key_compare   Callback function to compare a key with the data
- *                      inside a reb-black tree node.
- *
- * @param data_compare  Callback function to compare a key as data with thee
- *                      data inside a red-black tree node.
- */
-void c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare);
-
-/**
- * @brief Duplicate a red-black tree.
- *
- * @param tree Tree to duplicate.
- *
- * @return   Pointer to a new allocated duplicated rbtree. NULL if an error
- *           occurred.
- */
-c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree);
-
-/**
- * @brief Free the structure of a red-black tree.
- *
- * You should call c_rbtree_destroy() before you call this function.
- *
- * @param tree  The tree to free.
- *
- * @return   0 on success, less than 0 if an error occurred.
- */
-int c_rbtree_free(c_rbtree_t *tree);
-
-/**
- * @brief Destroy the content and the nodes of an red-black tree.
- *
- * This is far from the most efficient way to walk a tree, but it is
- * the *safest* way to destroy a tree - the destructor can do almost
- * anything (as long as it does not create an infinite loop) to the
- * tree structure without risk.
- *
- * If for some strange reason you need a faster destructor (think
- * twice - speed and memory deallocation don't mix well) then consider
- * stashing an llist of dataects and destroying that instead, and just
- * using c_rbtree_free() on your tree.
- *
- * @param T            The tree to destroy.
- * @param DESTRUCTOR   The destructor to call on a node to destroy.
- */
-#define c_rbtree_destroy(T, DESTRUCTOR)                 \
-  do {                                                  \
-    if (T) {                                            \
-      c_rbnode_t *_c_rbtree_temp;                       \
-      while ((_c_rbtree_temp = c_rbtree_head(T))) {     \
-        (DESTRUCTOR)(_c_rbtree_temp->data);             \
-        if (_c_rbtree_temp == c_rbtree_head(T)) {       \
-          c_rbtree_node_delete(_c_rbtree_temp);         \
-        }                                               \
-      }                                                 \
-    }                                                   \
-    SAFE_FREE(T);                                       \
-  } while (0);
-
-/**
- * @brief Inserts a node into a red black tree.
- *
- * @param tree  The red black tree to insert the node.
- * @param data  The data to insert into the tree.
- *
- * @return  0 on success, 1 if a duplicate has been found and < 0 if an error
- *          occurred with errno set.
- *          EINVAL if a null pointer has been passed as the tree.
- *          ENOMEM if there is no memory left.
- */
-int c_rbtree_insert(c_rbtree_t *tree, void *data);
-
-/**
- * @brief Find a node in a red-black tree.
- *
- * c_rbtree_find() is searching for the given  key  in a red-black tree and
- * returns the node if the key has been found.
- *
- * @param tree   The tree to search.
- * @param key    The key to search for.
- *
- * @return   If the key was found the node will be returned. On error NULL
- *           will be returned.
- */
-c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key);
-
-/**
- * @brief Get the head of the red-black tree.
- *
- * @param tree   The tree to get the head for.
- *
- * @return   The head node. NULL if an error occurred.
- */
-c_rbnode_t *c_rbtree_head(c_rbtree_t *tree);
-
-/**
- * @brief Get the tail of the red-black tree.
- *
- * @param tree   The tree to get the tail for.
- *
- * @return   The tail node. NULL if an error occurred.
- */
-c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree);
-
-/**
- * @brief Get the size of the red-black tree.
- *
- * @param T  The tree to get the size from.
- *
- * @return  The size of the red-black tree.
- */
-#define c_rbtree_size(T) (T) == NULL ? 0 : ((T)->size)
-
-/**
- * @brief Walk over a red-black tree.
- * 
- * Walk over a red-black tree calling a visitor function for each node found.
- *
- * @param tree     Tree to walk.
- * @param data     Data which should be passed to the visitor function.
- * @param visitor  Visitor function. This will be called for each node passed.
- *
- * @return   0 on sucess, less than 0 if an error occurred.
- */
-int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor);
-
-/**
- * @brief Delete a node in a red-black tree.
- *
- * @param node  Node which should be deleted.
- *
- * @return  0 on success, -1 if an error occurred.
- */
-int c_rbtree_node_delete(c_rbnode_t *node);
-
-/**
- * @brief Get the next node.
- *
- * @param node  The node of which you want the next node.
- *
- * @return  The next node, NULL if an error occurred.
- */
-c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node);
-
-/**
- * @brief Get the previous node.
- *
- * @param node  The node of which you want the previous node.
- *
- * @return  The previous node, NULL if an error occurred.
- */
-c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node);
-
-/**
- * @brief Get the data of a node.
- *
- * @param N  The node to get the data from.
- *
- * @return  The data, NULL if an error occurred.
- */
-#define c_rbtree_node_data(N) ((N) ? ((N)->data) : NULL)
-
-/**
- * @brief Perform a sanity check for a red-black tree.
- *
- * This is mostly for testing purposes.
- *
- * @param tree  The tree to check.
- *
- * @return 0 on success, less than 0 if an error occurred.
- */
-int c_rbtree_check_sanity(c_rbtree_t *tree);
-
-/**
- * }@
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _C_RBTREE_H */
index db846e69102ffe4904faca50c5ef1efbf623c4e1..9ebcd7fa84602e77e50531341d4710a1ba1c01aa 100644 (file)
@@ -59,7 +59,7 @@ static bool findPathInList(const QStringList &list, const QString &path)
     return pathSlash.startsWith(*it);
 }
 
-bool DiscoveryJob::isInSelectiveSyncBlackList(const char *path) const
+bool DiscoveryJob::isInSelectiveSyncBlackList(const QByteArray &path) const
 {
     if (_selectiveSyncBlackList.isEmpty()) {
         // If there is no black list, everything is allowed
@@ -73,24 +73,23 @@ bool DiscoveryJob::isInSelectiveSyncBlackList(const char *path) const
 
     // Also try to adjust the path if there was renames
     if (csync_rename_count(_csync_ctx)) {
-        QScopedPointer<char, QScopedPointerPodDeleter> adjusted(
-            csync_rename_adjust_path_source(_csync_ctx, path));
-        if (strcmp(adjusted.data(), path) != 0) {
-            return findPathInList(_selectiveSyncBlackList, QString::fromUtf8(adjusted.data()));
+        QByteArray adjusted = csync_rename_adjust_path_source(_csync_ctx, path);
+        if (adjusted != path) {
+            return findPathInList(_selectiveSyncBlackList, QString::fromUtf8(adjusted));
         }
     }
 
     return false;
 }
 
-int DiscoveryJob::isInSelectiveSyncBlackListCallback(void *data, const char *path)
+int DiscoveryJob::isInSelectiveSyncBlackListCallback(void *data, const QByteArray &path)
 {
     return static_cast<DiscoveryJob *>(data)->isInSelectiveSyncBlackList(path);
 }
 
-bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString &path, const char *remotePerm)
+bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString &path, const QByteArray &remotePerm)
 {
-    if (_syncOptions._confirmExternalStorage && std::strchr(remotePerm, 'M')) {
+    if (_syncOptions._confirmExternalStorage && remotePerm.contains('M')) {
         // 'M' in the permission means external storage.
 
         /* Note: DiscoverySingleDirectoryJob::directoryListingIteratedSlot make sure that only the
@@ -145,7 +144,7 @@ bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString &path, const char *
     }
 }
 
-int DiscoveryJob::checkSelectiveSyncNewFolderCallback(void *data, const char *path, const char *remotePerm)
+int DiscoveryJob::checkSelectiveSyncNewFolderCallback(void *data, const QByteArray &path, const QByteArray &remotePerm)
 {
     return static_cast<DiscoveryJob *>(data)->checkSelectiveSyncNewFolder(QString::fromUtf8(path), remotePerm);
 }
index 4a09c346279ff5291a188409ba5406c241088238..c3d44405b1ef7e38ae9e238658e656d99c2d9e5a 100644 (file)
@@ -210,10 +210,10 @@ class DiscoveryJob : public QObject
      * return true if the given path should be ignored,
      * false if the path should be synced
      */
-    bool isInSelectiveSyncBlackList(const char *path) const;
-    static int isInSelectiveSyncBlackListCallback(void *, const char *);
-    bool checkSelectiveSyncNewFolder(const QString &path, const char *remotePerm);
-    static int checkSelectiveSyncNewFolderCallback(void *data, const char *path, const char *remotePerm);
+    bool isInSelectiveSyncBlackList(const QByteArray &path) const;
+    static int isInSelectiveSyncBlackListCallback(void *, const QByteArray &);
+    bool checkSelectiveSyncNewFolder(const QString &path, const QByteArray &remotePerm);
+    static int checkSelectiveSyncNewFolderCallback(void *data, const QByteArray &path, const QByteArray &remotePerm);
 
     // Just for progress
     static void update_job_update_callback(bool local,
index a6599751e3f4b6228f05307a83dd15906e5641dc..ebb745f708e0f402369b6a3fa2eda9d6d91efabe 100644 (file)
@@ -128,9 +128,6 @@ QString SyncEngine::csyncErrorToString(CSYNC_STATUS err)
     case CSYNC_STATUS_NO_MODULE:
         errStr = tr("<p>The %1 plugin for csync could not be loaded.<br/>Please verify the installation!</p>").arg(qApp->applicationName());
         break;
-    case CSYNC_STATUS_TREE_ERROR:
-        errStr = tr("CSync got an error while processing internal trees.");
-        break;
     case CSYNC_STATUS_PARAM_ERROR:
         errStr = tr("CSync fatal parameter error.");
         break;
@@ -347,7 +344,7 @@ int SyncEngine::treewalkRemote(csync_file_stat_t *file, csync_file_stat_t *other
  * Called on each entry in the local and remote trees by
  * csync_walk_local_tree()/csync_walk_remote_tree().
  *
- * It merges the two csync rbtrees into a single map of SyncFileItems.
+ * It merges the two csync file trees into a single map of SyncFileItems.
  *
  * See doc/dev/sync-algorithm.md for an overview.
  */
@@ -359,7 +356,7 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
     QTextCodec::ConverterState utf8State;
     static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
     ASSERT(codec);
-    QString fileUtf8 = codec->toUnicode(file->path, qstrlen(file->path), &utf8State);
+    QString fileUtf8 = codec->toUnicode(file->path, file->path.size(), &utf8State);
     QString renameTarget;
     QString key = fileUtf8;
 
@@ -368,7 +365,7 @@ int SyncEngine::treewalkFile(csync_file_stat_t *file, csync_file_stat_t *other,
         qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence: " << file->path;
         instruction = CSYNC_INSTRUCTION_IGNORE;
     } else {
-        renameTarget = codec->toUnicode(file->rename_path, qstrlen(file->rename_path), &utf8State);
+        renameTarget = codec->toUnicode(file->rename_path, file->rename_path.size(), &utf8State);
         if (utf8State.invalidChars > 0 || utf8State.remainingChars > 0) {
             qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence in the rename_path: " << file->path << file->rename_path;
             instruction = CSYNC_INSTRUCTION_IGNORE;
@@ -937,7 +934,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
     _backInTimeFiles = 0;
     bool walkOk = true;
     _remotePerms.clear();
-    _remotePerms.reserve(c_rbtree_size(_csync_ctx->remote.tree));
+    _remotePerms.reserve(_csync_ctx->remote.files.size());
     _seenFiles.clear();
     _temporarilyUnavailablePaths.clear();
     _renamedFolders.clear();
index a735f8a0b9e01723e7863c51fb42e3da4cdb9be7..237c52e27224eca9100d2ef1886fa3490880d6f5 100644 (file)
@@ -23,7 +23,6 @@ set(TEST_TARGET_LIBRARIES ${TORTURE_LIBRARY})
 add_cmocka_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LIBRARIES})
 add_cmocka_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES})
 add_cmocka_test(check_std_c_path std_tests/check_std_c_path.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_std_c_rbtree std_tests/check_std_c_rbtree.c ${TEST_TARGET_LIBRARIES})
 add_cmocka_test(check_std_c_str std_tests/check_std_c_str.c ${TEST_TARGET_LIBRARIES})
 add_cmocka_test(check_std_c_time std_tests/check_std_c_time.c ${TEST_TARGET_LIBRARIES})
 
index d507c7108e09c19cbfcd6fb2803d5258b023de63..208e2c524706586deaf26dfa6c0ee6885eccebf5 100644 (file)
@@ -146,19 +146,18 @@ static void check_csync_statedb_drop_tables(void **state)
 static void check_csync_statedb_insert_metadata(void **state)
 {
     CSYNC *csync = (CSYNC*)*state;
-    csync_file_stat_t *st;
+    std::unique_ptr<csync_file_stat_t> st;
     int i, rc = 0;
 
     // rc = csync_statedb_create_tables(csync->statedb.db);
     assert_int_equal(rc, 0);
 
     for (i = 0; i < 100; i++) {
-        st = new csync_file_stat_t;
+        st.reset(new csync_file_stat_t);
         st->path = QString("file_%1").arg(i).toUtf8();
         st->phash = i;
 
-        rc = c_rbtree_insert(csync->local.tree, (void *) st);
-        assert_int_equal(rc, 0);
+        csync->local.files[st->path] = std::move(st);
     }
 
     // rc = csync_statedb_insert_metadata(csync, csync->statedb.db);
@@ -168,15 +167,15 @@ static void check_csync_statedb_insert_metadata(void **state)
 static void check_csync_statedb_write(void **state)
 {
     CSYNC *csync = (CSYNC*)*state;
-    csync_file_stat_t *st;
-    int i, rc;
+    std::unique_ptr<csync_file_stat_t> st;
+    int i, rc = 0;
 
     for (i = 0; i < 100; i++) {
-        st = new csync_file_stat_t;
+        st.reset(new csync_file_stat_t);
         st->path = QString("file_%1").arg(i).toUtf8();
         st->phash = i;
 
-        rc = c_rbtree_insert(csync->local.tree, (void *) st);
+        csync->local.files[st->path] = std::move(st);
         assert_int_equal(rc, 0);
     }
 
index f8329465fdbd9b677cc7216363d3f6feabe78137..4fae4e1a75ef0218a033d71076cea28a59eb1692 100644 (file)
@@ -227,7 +227,7 @@ static void check_csync_detect_update(void **state)
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
-    st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+    st = csync->local.files.begin()->second.get();
     assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
 
     /* create a statedb */
@@ -250,7 +250,7 @@ static void check_csync_detect_update_db_none(void **state)
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
-    st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+    st = csync->local.files.begin()->second.get();
     assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
 
 
@@ -271,7 +271,7 @@ static void check_csync_detect_update_db_eval(void **state)
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
-    st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+    st = csync->local.files.begin()->second.get();
     assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
 
     /* create a statedb */
@@ -296,7 +296,7 @@ static void check_csync_detect_update_db_rename(void **state)
     /* the instruction should be set to rename */
     /*
      * temporarily broken.
-    st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+    st = csync->local.files.begin()->second.get();
     assert_int_equal(st->instruction, CSYNC_INSTRUCTION_RENAME);
 
     st->instruction = CSYNC_INSTRUCTION_UPDATED;
@@ -318,7 +318,7 @@ static void check_csync_detect_update_db_new(void **state)
     assert_int_equal(rc, 0);
 
     /* the instruction should be set to new  */
-    st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+    st = csync->local.files.begin()->second.get();
     assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
 
 
diff --git a/test/csync/std_tests/check_std_c_rbtree.c b/test/csync/std_tests/check_std_c_rbtree.c
deleted file mode 100644 (file)
index a493ae3..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <errno.h>
-#include <time.h>
-
-#include "torture.h"
-
-#include "std/c_alloc.h"
-#include "std/c_rbtree.h"
-
-typedef struct test_s {
-    int key;
-    int number;
-} test_t;
-
-static int data_cmp(const void *key, const void *data) {
-    test_t *a, *b;
-
-    a = (test_t *) key;
-    b = (test_t *) data;
-
-    if (a->key < b->key) {
-        return -1;
-    } else if (a->key > b->key) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static int key_cmp(const void *key, const void *data) {
-    int a;
-    test_t *b;
-
-    a = POINTER_TO_INT(key);
-    b = (test_t *) data;
-
-    if (a < b->key) {
-        return -1;
-    } else if (a > b->key) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static int visitor(void *obj, void *data) {
-    test_t *a;
-    test_t *b;
-
-    a = (test_t *) obj;
-    b = (test_t *) data;
-
-    if (a->key == b->key) {
-        a->number = 42;
-    }
-
-    return 0;
-}
-
-static void destructor(void *data) {
-    test_t *freedata = NULL;
-
-    freedata = (test_t *) data;
-    SAFE_FREE(freedata);
-}
-
-static int setup(void **state) {
-    c_rbtree_t *tree = NULL;
-
-    c_rbtree_create(&tree, key_cmp, data_cmp);
-
-    *state = tree;
-    return 0;
-}
-
-static int setup_complete_tree(void **state) {
-    c_rbtree_t *tree = NULL;
-    int i = 0;
-    int rc;
-
-    c_rbtree_create(&tree, key_cmp, data_cmp);
-
-    for (i = 0; i < 100; i++) {
-        test_t *testdata = NULL;
-
-        testdata = c_malloc(sizeof(test_t));
-        assert_non_null(testdata);
-
-        testdata->key = i;
-
-        rc = c_rbtree_insert(tree, (void *) testdata);
-        assert_int_equal(rc, 0);
-    }
-
-    *state = tree;
-    return 0;
-}
-
-static int teardown(void **state) {
-    c_rbtree_t *tree = *state;
-
-    c_rbtree_destroy(tree, destructor);
-    c_rbtree_free(tree);
-
-    *state = NULL;
-    return 0;
-}
-
-static void check_c_rbtree_create_free(void **state)
-{
-    c_rbtree_t *tree = NULL;
-    int rc;
-
-    (void) state; /* unused */
-
-    c_rbtree_create(&tree, key_cmp, data_cmp);
-    assert_int_equal(tree->size, 0);
-
-    rc = c_rbtree_free(tree);
-    assert_int_equal(rc, 0);
-}
-
-static void check_c_rbtree_free_null(void **state)
-{
-    int rc;
-
-    (void) state; /* unused */
-
-    rc = c_rbtree_free(NULL);
-    assert_int_equal(rc, -1);
-}
-
-static void check_c_rbtree_insert_delete(void **state)
-{
-    c_rbtree_t *tree = NULL;
-    c_rbnode_t *node = NULL;
-    test_t *testdata = NULL;
-    int rc;
-
-    (void) state; /* unused */
-
-    c_rbtree_create(&tree, key_cmp, data_cmp);
-
-    testdata = malloc(sizeof(test_t));
-    testdata->key = 42;
-
-    rc = c_rbtree_insert(tree, (void *) testdata);
-    assert_int_equal(rc, 0);
-
-    node = c_rbtree_head(tree);
-    assert_non_null(node);
-
-    testdata = c_rbtree_node_data(node);
-    SAFE_FREE(testdata);
-    rc = c_rbtree_node_delete(node);
-    assert_int_equal(rc, 0);
-
-    c_rbtree_free(tree);
-}
-
-static void check_c_rbtree_insert_random(void **state)
-{
-    c_rbtree_t *tree = *state;
-    int i = 0, rc;
-
-    for (i = 0; i < 100; i++) {
-        test_t *testdata = NULL;
-
-        testdata = malloc(sizeof(test_t));
-        assert_non_null(testdata);
-
-        testdata->key = i;
-
-        rc = c_rbtree_insert(tree, testdata);
-        assert_int_equal(rc, 0);
-
-    }
-    rc = c_rbtree_check_sanity(tree);
-    assert_int_equal(rc, 0);
-}
-
-static void check_c_rbtree_insert_duplicate(void **state)
-{
-    c_rbtree_t *tree = *state;
-    test_t *testdata;
-    int rc;
-
-    testdata = malloc(sizeof(test_t));
-    assert_non_null(testdata);
-
-    testdata->key = 42;
-
-    rc = c_rbtree_insert(tree, (void *) testdata);
-    assert_int_equal(rc, 0);
-
-    /* add again */
-    testdata = malloc(sizeof(test_t));
-    assert_non_null(testdata);
-
-    testdata->key = 42;
-
-    /* check for duplicate */
-    rc = c_rbtree_insert(tree, (void *) testdata);
-    assert_int_equal(rc, 1);
-
-    free(testdata);
-}
-
-static void check_c_rbtree_find(void **state)
-{
-    c_rbtree_t *tree = *state;
-    int rc, i = 42;
-    c_rbnode_t *node;
-    test_t *testdata;
-
-    rc = c_rbtree_check_sanity(tree);
-    assert_int_equal(rc, 0);
-
-    /* find the node with the key 42 */
-    node = c_rbtree_find(tree, (void *) &i);
-    assert_non_null(node);
-
-    testdata = (test_t *) c_rbtree_node_data(node);
-    assert_int_equal(testdata->key, 42);
-}
-
-static void check_c_rbtree_delete(void **state)
-{
-    c_rbtree_t *tree = *state;
-    int rc, i = 42;
-    c_rbnode_t *node = NULL;
-    test_t *freedata = NULL;
-
-    rc = c_rbtree_check_sanity(tree);
-    assert_int_equal(rc, 0);
-
-    node = c_rbtree_find(tree, (void *) &i);
-    assert_non_null(node);
-
-    freedata = (test_t *) c_rbtree_node_data(node);
-    free(freedata);
-    rc = c_rbtree_node_delete(node);
-    assert_int_equal(rc, 0);
-
-    rc = c_rbtree_check_sanity(tree);
-    assert_int_equal(rc, 0);
-}
-
-static void check_c_rbtree_walk(void **state)
-{
-    c_rbtree_t *tree = *state;
-    int rc, i = 42;
-    test_t *testdata;
-    c_rbnode_t *node;
-
-    rc = c_rbtree_check_sanity(tree);
-    assert_int_equal(rc, 0);
-
-    testdata = (test_t *) c_malloc(sizeof(test_t));
-    testdata->key = 42;
-
-    rc = c_rbtree_walk(tree, testdata, visitor);
-    assert_int_equal(rc, 0);
-
-    /* find the node with the key 42 */
-    node = c_rbtree_find(tree, (void *) &i);
-    assert_non_null(node);
-    free(testdata);
-
-    testdata = (test_t *) c_rbtree_node_data(node);
-    assert_int_equal(testdata->number, 42);
-}
-
-static void check_c_rbtree_walk_null(void **state)
-{
-    c_rbtree_t *tree = *state;
-    int rc, i = 42;
-    test_t *testdata;
-    c_rbnode_t *node;
-
-    rc = c_rbtree_check_sanity(tree);
-    assert_int_equal(rc, 0);
-
-    testdata = (test_t *) malloc(sizeof(test_t));
-    testdata->key = 42;
-
-    rc = c_rbtree_walk(NULL, testdata, visitor);
-    assert_int_equal(rc, -1);
-    assert_int_equal(errno, EINVAL);
-
-    rc = c_rbtree_walk(tree, NULL, visitor);
-    assert_int_equal(rc, -1);
-    assert_int_equal(errno, EINVAL);
-
-    rc = c_rbtree_walk(tree, testdata, NULL);
-    assert_int_equal(rc, -1);
-    assert_int_equal(errno, EINVAL);
-
-    /* find the node with the key 42 */
-    node = c_rbtree_find(tree, (void *) &i);
-    assert_non_null(node);
-
-    free(testdata);
-}
-
-static void check_c_rbtree_dup(void **state)
-{
-    c_rbtree_t *tree = *state;
-    c_rbtree_t *duptree = NULL;
-    int rc = -1;
-
-    duptree = c_rbtree_dup(tree);
-    assert_non_null(duptree);
-
-    rc = c_rbtree_check_sanity(duptree);
-    assert_int_equal(rc, 0);
-
-    c_rbtree_free(duptree);
-}
-
-#if 0
-static void check_c_rbtree_x)
-{
-  int rc = -1;
-
-  rc = c_rbtree_check_sanity(tree);
-  fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
-}
-#endif
-
-int torture_run_tests(void)
-{
-  const struct CMUnitTest tests[] = {
-      cmocka_unit_test(check_c_rbtree_create_free),
-      cmocka_unit_test(check_c_rbtree_free_null),
-      cmocka_unit_test(check_c_rbtree_insert_delete),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_insert_random, setup, teardown),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_insert_duplicate, setup, teardown),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_find, setup_complete_tree, teardown),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_delete, setup_complete_tree, teardown),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_walk, setup_complete_tree, teardown),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_walk_null, setup_complete_tree, teardown),
-      cmocka_unit_test_setup_teardown(check_c_rbtree_dup, setup_complete_tree, teardown),
-  };
-
-  return cmocka_run_group_tests(tests, NULL, NULL);
-}
-