#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;
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);
}
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 */
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;
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)) {
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)) {
/*
* 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;
/* 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;
* 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);
*/
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);
}
/*
*/
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() {
}
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);
}
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);
#include <stdint.h>
#include <stdbool.h>
#include <sqlite3.h>
+#include <map>
#include "config_csync.h"
#include "std/c_lib.h"
* @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;
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;
} 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;
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;
};
/*
/* 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);
}
}
/**
* 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
* (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:
}
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" );
}
}
/*
* file found on the other replica
*/
- other = (csync_file_stat_t *) node->data;
switch (cur->instruction) {
case CSYNC_INSTRUCTION_UPDATE_METADATA:
}
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: */
#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) {
#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);
}
/* 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);
}
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;
set(cstdlib_SRCS
c_alloc.c
c_path.c
- c_rbtree.c
c_string.c
c_time.c
c_utf8.cpp
#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"
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 */
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
// 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
}
}
-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);
}
* 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,
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;
* 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.
*/
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;
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;
_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();
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})
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);
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);
}
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 */
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);
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 */
/* 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;
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);
+++ /dev/null
-/*
- * 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);
-}
-