This will allow us to unify data structures between csync and libsync.
Utility functions like csync_time and c_std are still compiled as C
since we won't need to be coupled with Qt in the short term.
--- /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 "csync_update.cpp"
+
+extern "C" {
+
+#include "torture.h"
+
+#define TESTDB "/tmp/check_csync/journal.db"
+
+static int firstrun = 1;
+
+static void statedb_create_metadata_table(sqlite3 *db)
+{
+ int rc = 0;
+
+ if( db ) {
+ const char *sql = "CREATE TABLE IF NOT EXISTS metadata("
+ "phash INTEGER(8),"
+ "pathlen INTEGER,"
+ "path VARCHAR(4096),"
+ "inode INTEGER,"
+ "uid INTEGER,"
+ "gid INTEGER,"
+ "mode INTEGER,"
+ "modtime INTEGER(8),"
+ "type INTEGER,"
+ "md5 VARCHAR(32),"
+ "fileid VARCHAR(128),"
+ "remotePerm VARCHAR(128),"
+ "filesize BIGINT,"
+ "ignoredChildrenRemote INT,"
+ "contentChecksum TEXT,"
+ "contentChecksumTypeId INTEGER,"
+ "PRIMARY KEY(phash));";
+
+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+ //const char *msg = sqlite3_errmsg(db);
+ assert_int_equal( rc, SQLITE_OK );
+
+ sql = "CREATE TABLE IF NOT EXISTS checksumtype("
+ "id INTEGER PRIMARY KEY,"
+ "name TEXT UNIQUE"
+ ");";
+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+ assert_int_equal( rc, SQLITE_OK );
+ }
+}
+
+static void statedb_insert_metadata(sqlite3 *db)
+{
+ int rc = 0;
+
+ if( db ) {
+ char *stmt = sqlite3_mprintf("INSERT INTO metadata"
+ "(phash, pathlen, path, inode, uid, gid, mode, modtime,type,md5) VALUES"
+ "(%lld, %d, '%q', %d, %d, %d, %d, %lld, %d, '%q');",
+ (long long signed int)42,
+ 42,
+ "I_was_wurst_before_I_became_wurstsalat",
+ 619070,
+ 42,
+ 42,
+ 42,
+ (long long signed int)42,
+ 0,
+ "4711");
+
+ char *errmsg;
+ rc = sqlite3_exec(db, stmt, NULL, NULL, &errmsg);
+ sqlite3_free(stmt);
+ assert_int_equal( rc, SQLITE_OK );
+ }
+}
+
+static int setup(void **state)
+{
+ CSYNC *csync;
+ int rc;
+
+ unlink(TESTDB);
+ rc = system("mkdir -p /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ csync_create(&csync, "/tmp/check_csync1");
+ csync_init(csync, TESTDB);
+
+ /* Create a new db with metadata */
+ sqlite3 *db;
+ csync->statedb.file = c_strdup(TESTDB);
+ rc = sqlite3_open(csync->statedb.file, &db);
+ statedb_create_metadata_table(db);
+ if( firstrun ) {
+ statedb_insert_metadata(db);
+ firstrun = 0;
+ }
+ sqlite3_close(db);
+
+ rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+ assert_int_equal(rc, 0);
+
+ *state = csync;
+
+ return 0;
+}
+
+static int setup_ftw(void **state)
+{
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ csync_create(&csync, "/tmp");
+ csync_init(csync, TESTDB);
+
+ sqlite3 *db = NULL;
+ rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
+ assert_int_equal(rc, SQLITE_OK);
+ statedb_create_metadata_table(db);
+ rc = sqlite3_close(db);
+ assert_int_equal(rc, SQLITE_OK);
+
+ rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+ assert_int_equal(rc, 0);
+
+ csync->statedb.file = c_strdup( TESTDB );
+ *state = csync;
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ unlink( csync->statedb.file);
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static int teardown_rm(void **state) {
+ int rc;
+
+ teardown(state);
+
+ rc = system("rm -rf /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ return 0;
+}
+
+/* create a file stat, caller must free memory */
+static csync_vio_file_stat_t* create_fstat(const char *name,
+ ino_t inode,
+ time_t mtime)
+{
+ csync_vio_file_stat_t *fs = NULL;
+ time_t t;
+
+ fs = csync_vio_file_stat_new();
+ if (fs == NULL) {
+ return NULL;
+ }
+
+ if (name && *name) {
+ fs->name = c_strdup(name);
+ } else {
+ fs->name = c_strdup("file.txt");
+ }
+
+ if (fs->name == NULL) {
+ csync_vio_file_stat_destroy(fs);
+ return NULL;
+ }
+
+ fs->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
+
+ fs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+
+
+ if (inode == 0) {
+ fs->inode = 619070;
+ } else {
+ fs->inode = inode;
+ }
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
+
+
+ fs->size = 157459;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
+
+
+
+ if (mtime == 0) {
+ fs->atime = fs->ctime = fs->mtime = time(&t);
+ } else {
+ fs->atime = fs->ctime = fs->mtime = mtime;
+ }
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
+
+ return fs;
+}
+
+static int failing_fn(CSYNC *ctx,
+ const char *file,
+ const csync_vio_file_stat_t *fs,
+ int flag)
+{
+ (void) ctx;
+ (void) file;
+ (void) fs;
+ (void) flag;
+
+ return -1;
+}
+
+/* detect a new file */
+static void check_csync_detect_update(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 1217597845);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+/* Test behaviour in case no db is there. For that its important that the
+ * test before this one uses teardown_rm.
+ */
+static void check_csync_detect_update_db_none(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 1217597845);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_detect_update_db_eval(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 42);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+
+static void check_csync_detect_update_db_rename(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ // csync_file_stat_t *st;
+
+ csync_vio_file_stat_t *fs;
+ int rc = 0;
+
+ fs = create_fstat("wurst.txt", 0, 42);
+ assert_non_null(fs);
+ csync_set_statedb_exists(csync, 1);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/wurst.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, 0);
+
+ /* the instruction should be set to rename */
+ /*
+ * temporarily broken.
+ st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_RENAME);
+
+ st->instruction = CSYNC_INSTRUCTION_UPDATED;
+ */
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_detect_update_db_new(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 42000, 0);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_detect_update_null(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 0);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ NULL,
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, -1);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ NULL,
+ CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, -1);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_ftw(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_ftw(csync, "/tmp", csync_walker, MAX_DEPTH);
+ assert_int_equal(rc, 0);
+}
+
+static void check_csync_ftw_empty_uri(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_ftw(csync, "", csync_walker, MAX_DEPTH);
+ assert_int_equal(rc, -1);
+}
+
+static void check_csync_ftw_failing_fn(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_ftw(csync, "/tmp", failing_fn, MAX_DEPTH);
+ assert_int_equal(rc, -1);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
+
+ cmocka_unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+}
endif()
set(csync_SRCS
- csync.c
- csync_exclude.c
- csync_log.c
- csync_statedb.c
+ csync.cpp
+ csync_exclude.cpp
+ csync_log.cpp
+ csync_statedb.cpp
csync_time.c
- csync_util.c
- csync_misc.c
+ csync_util.cpp
+ csync_misc.cpp
- csync_update.c
- csync_reconcile.c
+ csync_update.cpp
+ csync_reconcile.cpp
csync_rename.cpp
- vio/csync_vio.c
- vio/csync_vio_file_stat.c
+ vio/csync_vio.cpp
+ vio/csync_vio_file_stat.cpp
)
if (WIN32)
list(APPEND csync_SRCS
- vio/csync_vio_local_win.c
+ vio/csync_vio_local_win.cpp
)
else()
list(APPEND csync_SRCS
- vio/csync_vio_local_unix.c
+ vio/csync_vio_local_unix.cpp
)
endif()
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 "config_csync.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <stdbool.h>
-
-#include "c_lib.h"
-#include "csync_private.h"
-#include "csync_exclude.h"
-#include "csync_statedb.h"
-#include "csync_time.h"
-#include "csync_util.h"
-#include "csync_misc.h"
-#include "std/c_private.h"
-
-#include "csync_update.h"
-#include "csync_reconcile.h"
-
-#include "vio/csync_vio.h"
-
-#include "csync_log.h"
-#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;
-}
-
-void csync_create(CSYNC **csync, const char *local) {
- CSYNC *ctx;
- size_t len = 0;
-
- ctx = c_malloc(sizeof(CSYNC));
-
- ctx->status_code = CSYNC_STATUS_OK;
-
- /* remove trailing slashes */
- len = strlen(local);
- while(len > 0 && local[len - 1] == '/') --len;
-
- ctx->local.uri = c_strndup(local, len);
-
- ctx->status_code = CSYNC_STATUS_OK;
-
- ctx->current_fs = NULL;
-
- ctx->abort = false;
-
- ctx->ignore_hidden_files = true;
-
- *csync = ctx;
-}
-
-void csync_init(CSYNC *ctx, const char *db_file) {
- assert(ctx);
- /* Do not initialize twice */
-
- assert(!(ctx->status & CSYNC_STATUS_INIT));
- ctx->status_code = CSYNC_STATUS_OK;
-
- ctx->local.type = LOCAL_REPLICA;
-
- ctx->remote.type = REMOTE_REPLICA;
-
- SAFE_FREE(ctx->statedb.file);
- ctx->statedb.file = c_strdup(db_file);
-
- c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
- c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
-
- ctx->remote.root_perms = 0;
-
- ctx->status = CSYNC_STATUS_INIT;
-
- /* initialize random generator */
- srand(time(NULL));
-}
-
-int csync_update(CSYNC *ctx) {
- int rc = -1;
- struct timespec start, finish;
-
- if (ctx == NULL) {
- errno = EBADF;
- return -1;
- }
- ctx->status_code = CSYNC_STATUS_OK;
-
- /* Path of database file is set in csync_init */
- if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
- rc = -1;
- return rc;
- }
-
- ctx->status_code = CSYNC_STATUS_OK;
-
- csync_memstat_check();
-
- if (!ctx->excludes) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "No exclude file loaded or defined!");
- }
-
- /* update detection for local replica */
- csync_gettime(&start);
- ctx->current = LOCAL_REPLICA;
- ctx->replica = ctx->local.type;
-
- rc = csync_ftw(ctx, ctx->local.uri, csync_walker, MAX_DEPTH);
- if (rc < 0) {
- if(ctx->status_code == CSYNC_STATUS_OK) {
- ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
- }
- goto out;
- }
-
- csync_gettime(&finish);
-
- 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));
- csync_memstat_check();
-
- /* update detection for remote replica */
- csync_gettime(&start);
- ctx->current = REMOTE_REPLICA;
- ctx->replica = ctx->remote.type;
-
- rc = csync_ftw(ctx, "", csync_walker, MAX_DEPTH);
- if (rc < 0) {
- if(ctx->status_code == CSYNC_STATUS_OK) {
- ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
- }
- goto out;
- }
-
- csync_gettime(&finish);
-
- 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));
- csync_memstat_check();
-
- ctx->status |= CSYNC_STATUS_UPDATE;
-
- rc = 0;
-
-out:
- csync_statedb_close(ctx);
- return rc;
-}
-
-int csync_reconcile(CSYNC *ctx) {
- int rc = -1;
- struct timespec start, finish;
-
- if (ctx == NULL) {
- errno = EBADF;
- return -1;
- }
- ctx->status_code = CSYNC_STATUS_OK;
-
- /* Reconciliation for local replica */
- csync_gettime(&start);
-
- if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
- rc = -1;
- return rc;
- }
-
- ctx->current = LOCAL_REPLICA;
- ctx->replica = ctx->local.type;
-
- rc = csync_reconcile_updates(ctx);
-
- csync_gettime(&finish);
-
- 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));
-
- if (rc < 0) {
- if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
- ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR );
- }
- goto out;
- }
-
- /* Reconciliation for remote replica */
- csync_gettime(&start);
-
- ctx->current = REMOTE_REPLICA;
- ctx->replica = ctx->remote.type;
-
- rc = csync_reconcile_updates(ctx);
-
- csync_gettime(&finish);
-
- 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));
-
- if (rc < 0) {
- if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
- ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_RECONCILE_ERROR );
- }
- goto out;
- }
-
- ctx->status |= CSYNC_STATUS_RECONCILE;
-
- rc = 0;
-
-out:
- csync_statedb_close(ctx);
- return 0;
-}
-
-/*
- * local visitor which calls the user visitor with repacked stat info.
- */
-static int _csync_treewalk_visitor(void *obj, void *data) {
- int rc = 0;
- csync_file_stat_t *cur = NULL;
- CSYNC *ctx = NULL;
- c_rbtree_visit_func *visitor = NULL;
- _csync_treewalk_context *twctx = NULL;
- TREE_WALK_FILE trav;
- c_rbtree_t *other_tree = NULL;
- c_rbnode_t *other_node = NULL;
-
- cur = (csync_file_stat_t *) obj;
- ctx = (CSYNC *) data;
-
- if (ctx == NULL) {
- return -1;
- }
-
- /* we need the opposite tree! */
- switch (ctx->current) {
- case LOCAL_REPLICA:
- other_tree = ctx->remote.tree;
- break;
- case REMOTE_REPLICA:
- other_tree = ctx->local.tree;
- break;
- default:
- break;
- }
-
- other_node = c_rbtree_find(other_tree, &cur->phash);
-
- if (!other_node) {
- /* 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);
- }
-
- if (!other_node) {
- /* 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);
- }
-
- 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;
- if (twctx == NULL) {
- ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
- return -1;
- }
-
- if (twctx->instruction_filter > 0 &&
- !(twctx->instruction_filter & cur->instruction) ) {
- return 0;
- }
-
- visitor = (c_rbtree_visit_func*)(twctx->user_visitor);
- if (visitor != NULL) {
- trav.path = cur->path;
- trav.size = cur->size;
- trav.modtime = cur->modtime;
- trav.mode = cur->mode;
- trav.type = cur->type;
- trav.instruction = cur->instruction;
- trav.rename_path = cur->destpath;
- trav.etag = cur->etag;
- trav.file_id = cur->file_id;
- trav.remotePerm = cur->remotePerm;
- trav.directDownloadUrl = cur->directDownloadUrl;
- trav.directDownloadCookies = cur->directDownloadCookies;
- trav.inode = cur->inode;
-
- trav.error_status = cur->error_status;
- trav.has_ignored_files = cur->has_ignored_files;
- trav.checksumHeader = cur->checksumHeader;
-
- if( other_node ) {
- csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
- trav.other.etag = other_stat->etag;
- trav.other.file_id = other_stat->file_id;
- trav.other.instruction = other_stat->instruction;
- trav.other.modtime = other_stat->modtime;
- trav.other.size = other_stat->size;
- } else {
- trav.other.etag = 0;
- trav.other.file_id = 0;
- trav.other.instruction = CSYNC_INSTRUCTION_NONE;
- trav.other.modtime = 0;
- trav.other.size = 0;
- }
-
- rc = (*visitor)(&trav, twctx->userdata);
- cur->instruction = trav.instruction;
- if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
- SAFE_FREE(cur->etag);
- cur->etag = c_strdup(trav.etag);
- }
-
- return rc;
- }
- ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
- return -1;
-}
-
-/*
- * treewalk function, called from its wrappers below.
- *
- * it encapsulates the user visitor function, the filter and the userdata
- * into a treewalk_context structure and calls the rb treewalk function,
- * 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)
-{
- _csync_treewalk_context tw_ctx;
- int rc = -1;
-
- if (ctx == NULL) {
- errno = EBADF;
- return rc;
- }
-
- 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);
- if( rc < 0 ) {
- if( ctx->status_code == CSYNC_STATUS_OK )
- ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR);
- }
- ctx->callbacks.userdata = tw_ctx.userdata;
-
- return rc;
-}
-
-/*
- * wrapper function for treewalk on the remote tree
- */
-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;
-}
-
-/*
- * wrapper function for treewalk on the local tree
- */
-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;
- csync_file_stat_free(freedata);
-}
-
-/* reset all the list to empty.
- * used by csync_commit and csync_destroy */
-static void _csync_clean_ctx(CSYNC *ctx)
-{
- /* destroy the rbtrees */
- if (c_rbtree_size(ctx->local.tree) > 0) {
- c_rbtree_destroy(ctx->local.tree, _tree_destructor);
- }
-
- if (c_rbtree_size(ctx->remote.tree) > 0) {
- c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
- }
-
- csync_rename_destroy(ctx);
-
- /* free memory */
- c_rbtree_free(ctx->local.tree);
- c_rbtree_free(ctx->remote.tree);
-
- SAFE_FREE(ctx->remote.root_perms);
-}
-
-int csync_commit(CSYNC *ctx) {
- int rc = 0;
-
- if (ctx == NULL) {
- return -1;
- }
-
- ctx->status_code = CSYNC_STATUS_OK;
-
- if (ctx->statedb.db != NULL
- && csync_statedb_close(ctx) < 0) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed.");
- rc = -1;
- }
- ctx->statedb.db = NULL;
-
- _csync_clean_ctx(ctx);
-
- ctx->remote.read_from_db = 0;
- ctx->read_remote_from_db = true;
- ctx->db_is_empty = false;
-
-
- /* Create new trees */
- c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
- c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
-
-
- ctx->status = CSYNC_STATUS_INIT;
- SAFE_FREE(ctx->error_string);
-
- rc = 0;
- return rc;
-}
-
-int csync_destroy(CSYNC *ctx) {
- int rc = 0;
-
- if (ctx == NULL) {
- errno = EBADF;
- return -1;
- }
- ctx->status_code = CSYNC_STATUS_OK;
-
- if (ctx->statedb.db != NULL
- && csync_statedb_close(ctx) < 0) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed.");
- rc = -1;
- }
- ctx->statedb.db = NULL;
-
- _csync_clean_ctx(ctx);
-
- SAFE_FREE(ctx->statedb.file);
- SAFE_FREE(ctx->local.uri);
- SAFE_FREE(ctx->error_string);
-
- SAFE_FREE(ctx);
-
- return rc;
-}
-
-void *csync_get_userdata(CSYNC *ctx) {
- if (ctx == NULL) {
- return NULL;
- }
- return ctx->callbacks.userdata;
-}
-
-int csync_set_userdata(CSYNC *ctx, void *userdata) {
- if (ctx == NULL) {
- return -1;
- }
-
- ctx->callbacks.userdata = userdata;
-
- return 0;
-}
-
-csync_auth_callback csync_get_auth_callback(CSYNC *ctx) {
- if (ctx == NULL) {
- return NULL;
- }
-
- return ctx->callbacks.auth_function;
-}
-
-int csync_set_status(CSYNC *ctx, int status) {
- if (ctx == NULL || status < 0) {
- return -1;
- }
-
- ctx->status = status;
-
- return 0;
-}
-
-CSYNC_STATUS csync_get_status(CSYNC *ctx) {
- if (ctx == NULL) {
- return -1;
- }
-
- return ctx->status_code;
-}
-
-const char *csync_get_status_string(CSYNC *ctx)
-{
- return csync_vio_get_status_string(ctx);
-}
-
-void csync_request_abort(CSYNC *ctx)
-{
- if (ctx != NULL) {
- ctx->abort = true;
- }
-}
-
-void csync_resume(CSYNC *ctx)
-{
- if (ctx != NULL) {
- ctx->abort = false;
- }
-}
-
-int csync_abort_requested(CSYNC *ctx)
-{
- if (ctx != NULL) {
- return ctx->abort;
- } else {
- return (1 == 0);
- }
-}
-
-void csync_file_stat_free(csync_file_stat_t *st)
-{
- if (st) {
- SAFE_FREE(st->directDownloadUrl);
- SAFE_FREE(st->directDownloadCookies);
- SAFE_FREE(st->etag);
- SAFE_FREE(st->destpath);
- SAFE_FREE(st->checksumHeader);
- SAFE_FREE(st);
- }
-}
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 "config_csync.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include "c_lib.h"
+#include "csync_private.h"
+#include "csync_exclude.h"
+#include "csync_statedb.h"
+#include "csync_time.h"
+#include "csync_util.h"
+#include "csync_misc.h"
+#include "std/c_private.h"
+
+#include "csync_update.h"
+#include "csync_reconcile.h"
+
+#include "vio/csync_vio.h"
+
+#include "csync_log.h"
+#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;
+}
+
+void csync_create(CSYNC **csync, const char *local) {
+ CSYNC *ctx;
+ size_t len = 0;
+
+ ctx = (CSYNC*)c_malloc(sizeof(CSYNC));
+
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ /* remove trailing slashes */
+ len = strlen(local);
+ while(len > 0 && local[len - 1] == '/') --len;
+
+ ctx->local.uri = c_strndup(local, len);
+
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ ctx->current_fs = NULL;
+
+ ctx->abort = false;
+
+ ctx->ignore_hidden_files = true;
+
+ *csync = ctx;
+}
+
+void csync_init(CSYNC *ctx, const char *db_file) {
+ assert(ctx);
+ /* Do not initialize twice */
+
+ assert(!(ctx->status & CSYNC_STATUS_INIT));
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ ctx->local.type = LOCAL_REPLICA;
+
+ ctx->remote.type = REMOTE_REPLICA;
+
+ SAFE_FREE(ctx->statedb.file);
+ ctx->statedb.file = c_strdup(db_file);
+
+ c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
+ c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
+
+ ctx->remote.root_perms = 0;
+
+ ctx->status = CSYNC_STATUS_INIT;
+
+ /* initialize random generator */
+ srand(time(NULL));
+}
+
+int csync_update(CSYNC *ctx) {
+ int rc = -1;
+ struct timespec start, finish;
+
+ if (ctx == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ /* Path of database file is set in csync_init */
+ if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
+ rc = -1;
+ return rc;
+ }
+
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ csync_memstat_check();
+
+ if (!ctx->excludes) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "No exclude file loaded or defined!");
+ }
+
+ /* update detection for local replica */
+ csync_gettime(&start);
+ ctx->current = LOCAL_REPLICA;
+ ctx->replica = ctx->local.type;
+
+ rc = csync_ftw(ctx, ctx->local.uri, csync_walker, MAX_DEPTH);
+ if (rc < 0) {
+ if(ctx->status_code == CSYNC_STATUS_OK) {
+ ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
+ }
+ goto out;
+ }
+
+ csync_gettime(&finish);
+
+ 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));
+ csync_memstat_check();
+
+ /* update detection for remote replica */
+ csync_gettime(&start);
+ ctx->current = REMOTE_REPLICA;
+ ctx->replica = ctx->remote.type;
+
+ rc = csync_ftw(ctx, "", csync_walker, MAX_DEPTH);
+ if (rc < 0) {
+ if(ctx->status_code == CSYNC_STATUS_OK) {
+ ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
+ }
+ goto out;
+ }
+
+ csync_gettime(&finish);
+
+ 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));
+ csync_memstat_check();
+
+ ctx->status |= CSYNC_STATUS_UPDATE;
+
+ rc = 0;
+
+out:
+ csync_statedb_close(ctx);
+ return rc;
+}
+
+int csync_reconcile(CSYNC *ctx) {
+ int rc = -1;
+ struct timespec start, finish;
+
+ if (ctx == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ /* Reconciliation for local replica */
+ csync_gettime(&start);
+
+ if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
+ rc = -1;
+ return rc;
+ }
+
+ ctx->current = LOCAL_REPLICA;
+ ctx->replica = ctx->local.type;
+
+ rc = csync_reconcile_updates(ctx);
+
+ csync_gettime(&finish);
+
+ 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));
+
+ if (rc < 0) {
+ if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
+ ctx->status_code = csync_errno_to_status( errno, CSYNC_STATUS_RECONCILE_ERROR );
+ }
+ goto out;
+ }
+
+ /* Reconciliation for remote replica */
+ csync_gettime(&start);
+
+ ctx->current = REMOTE_REPLICA;
+ ctx->replica = ctx->remote.type;
+
+ rc = csync_reconcile_updates(ctx);
+
+ csync_gettime(&finish);
+
+ 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));
+
+ if (rc < 0) {
+ if (!CSYNC_STATUS_IS_OK(ctx->status_code)) {
+ ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_RECONCILE_ERROR );
+ }
+ goto out;
+ }
+
+ ctx->status |= CSYNC_STATUS_RECONCILE;
+
+ rc = 0;
+
+out:
+ csync_statedb_close(ctx);
+ return 0;
+}
+
+/*
+ * local visitor which calls the user visitor with repacked stat info.
+ */
+static int _csync_treewalk_visitor(void *obj, void *data) {
+ int rc = 0;
+ csync_file_stat_t *cur = NULL;
+ CSYNC *ctx = NULL;
+ c_rbtree_visit_func *visitor = NULL;
+ _csync_treewalk_context *twctx = NULL;
+ TREE_WALK_FILE trav;
+ c_rbtree_t *other_tree = NULL;
+ c_rbnode_t *other_node = NULL;
+
+ cur = (csync_file_stat_t *) obj;
+ ctx = (CSYNC *) data;
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ /* we need the opposite tree! */
+ switch (ctx->current) {
+ case LOCAL_REPLICA:
+ other_tree = ctx->remote.tree;
+ break;
+ case REMOTE_REPLICA:
+ other_tree = ctx->local.tree;
+ break;
+ default:
+ break;
+ }
+
+ other_node = c_rbtree_find(other_tree, &cur->phash);
+
+ if (!other_node) {
+ /* 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);
+ }
+
+ if (!other_node) {
+ /* 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);
+ }
+
+ 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;
+ if (twctx == NULL) {
+ ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
+ return -1;
+ }
+
+ if (twctx->instruction_filter > 0 &&
+ !(twctx->instruction_filter & cur->instruction) ) {
+ return 0;
+ }
+
+ visitor = (c_rbtree_visit_func*)(twctx->user_visitor);
+ if (visitor != NULL) {
+ trav.path = cur->path;
+ trav.size = cur->size;
+ trav.modtime = cur->modtime;
+ trav.mode = cur->mode;
+ trav.type = cur->type;
+ trav.instruction = cur->instruction;
+ trav.rename_path = cur->destpath;
+ trav.etag = cur->etag;
+ trav.file_id = cur->file_id;
+ trav.remotePerm = cur->remotePerm;
+ trav.directDownloadUrl = cur->directDownloadUrl;
+ trav.directDownloadCookies = cur->directDownloadCookies;
+ trav.inode = cur->inode;
+
+ trav.error_status = cur->error_status;
+ trav.has_ignored_files = cur->has_ignored_files;
+ trav.checksumHeader = cur->checksumHeader;
+
+ if( other_node ) {
+ csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
+ trav.other.etag = other_stat->etag;
+ trav.other.file_id = other_stat->file_id;
+ trav.other.instruction = other_stat->instruction;
+ trav.other.modtime = other_stat->modtime;
+ trav.other.size = other_stat->size;
+ } else {
+ trav.other.etag = 0;
+ trav.other.file_id = 0;
+ trav.other.instruction = CSYNC_INSTRUCTION_NONE;
+ trav.other.modtime = 0;
+ trav.other.size = 0;
+ }
+
+ rc = (*visitor)(&trav, twctx->userdata);
+ cur->instruction = trav.instruction;
+ if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
+ SAFE_FREE(cur->etag);
+ cur->etag = c_strdup(trav.etag);
+ }
+
+ return rc;
+ }
+ ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
+ return -1;
+}
+
+/*
+ * treewalk function, called from its wrappers below.
+ *
+ * it encapsulates the user visitor function, the filter and the userdata
+ * into a treewalk_context structure and calls the rb treewalk function,
+ * 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)
+{
+ _csync_treewalk_context tw_ctx;
+ int rc = -1;
+
+ if (ctx == NULL) {
+ errno = EBADF;
+ return rc;
+ }
+
+ 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);
+ if( rc < 0 ) {
+ if( ctx->status_code == CSYNC_STATUS_OK )
+ ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_TREE_ERROR);
+ }
+ ctx->callbacks.userdata = tw_ctx.userdata;
+
+ return rc;
+}
+
+/*
+ * wrapper function for treewalk on the remote tree
+ */
+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;
+}
+
+/*
+ * wrapper function for treewalk on the local tree
+ */
+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;
+ csync_file_stat_free(freedata);
+}
+
+/* reset all the list to empty.
+ * used by csync_commit and csync_destroy */
+static void _csync_clean_ctx(CSYNC *ctx)
+{
+ /* destroy the rbtrees */
+ if (c_rbtree_size(ctx->local.tree) > 0) {
+ c_rbtree_destroy(ctx->local.tree, _tree_destructor);
+ }
+
+ if (c_rbtree_size(ctx->remote.tree) > 0) {
+ c_rbtree_destroy(ctx->remote.tree, _tree_destructor);
+ }
+
+ csync_rename_destroy(ctx);
+
+ /* free memory */
+ c_rbtree_free(ctx->local.tree);
+ c_rbtree_free(ctx->remote.tree);
+
+ SAFE_FREE(ctx->remote.root_perms);
+}
+
+int csync_commit(CSYNC *ctx) {
+ int rc = 0;
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ if (ctx->statedb.db != NULL
+ && csync_statedb_close(ctx) < 0) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed.");
+ rc = -1;
+ }
+ ctx->statedb.db = NULL;
+
+ _csync_clean_ctx(ctx);
+
+ ctx->remote.read_from_db = 0;
+ ctx->read_remote_from_db = true;
+ ctx->db_is_empty = false;
+
+
+ /* Create new trees */
+ c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
+ c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
+
+
+ ctx->status = CSYNC_STATUS_INIT;
+ SAFE_FREE(ctx->error_string);
+
+ rc = 0;
+ return rc;
+}
+
+int csync_destroy(CSYNC *ctx) {
+ int rc = 0;
+
+ if (ctx == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+ ctx->status_code = CSYNC_STATUS_OK;
+
+ if (ctx->statedb.db != NULL
+ && csync_statedb_close(ctx) < 0) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "ERR: closing of statedb failed.");
+ rc = -1;
+ }
+ ctx->statedb.db = NULL;
+
+ _csync_clean_ctx(ctx);
+
+ SAFE_FREE(ctx->statedb.file);
+ SAFE_FREE(ctx->local.uri);
+ SAFE_FREE(ctx->error_string);
+
+ SAFE_FREE(ctx);
+
+ return rc;
+}
+
+void *csync_get_userdata(CSYNC *ctx) {
+ if (ctx == NULL) {
+ return NULL;
+ }
+ return ctx->callbacks.userdata;
+}
+
+int csync_set_userdata(CSYNC *ctx, void *userdata) {
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ ctx->callbacks.userdata = userdata;
+
+ return 0;
+}
+
+csync_auth_callback csync_get_auth_callback(CSYNC *ctx) {
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ return ctx->callbacks.auth_function;
+}
+
+int csync_set_status(CSYNC *ctx, int status) {
+ if (ctx == NULL || status < 0) {
+ return -1;
+ }
+
+ ctx->status = status;
+
+ return 0;
+}
+
+CSYNC_STATUS csync_get_status(CSYNC *ctx) {
+ if (ctx == NULL) {
+ return CSYNC_STATUS_ERROR;
+ }
+
+ return ctx->status_code;
+}
+
+const char *csync_get_status_string(CSYNC *ctx)
+{
+ return csync_vio_get_status_string(ctx);
+}
+
+void csync_request_abort(CSYNC *ctx)
+{
+ if (ctx != NULL) {
+ ctx->abort = true;
+ }
+}
+
+void csync_resume(CSYNC *ctx)
+{
+ if (ctx != NULL) {
+ ctx->abort = false;
+ }
+}
+
+int csync_abort_requested(CSYNC *ctx)
+{
+ if (ctx != NULL) {
+ return ctx->abort;
+ } else {
+ return (1 == 0);
+ }
+}
+
+void csync_file_stat_free(csync_file_stat_t *st)
+{
+ if (st) {
+ SAFE_FREE(st->directDownloadUrl);
+ SAFE_FREE(st->directDownloadCookies);
+ SAFE_FREE(st->etag);
+ SAFE_FREE(st->destpath);
+ SAFE_FREE(st->checksumHeader);
+ SAFE_FREE(st);
+ }
+}
#include <sys/types.h>
#include <config_csync.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
enum csync_status_codes_e {
CSYNC_STATUS_OK = 0,
int fields; // actually enum csync_vio_file_stat_fields_e fields;
enum csync_vio_file_type_e type;
- enum csync_vio_file_flags_e flags;
+ int flags;
char *original_name; // only set if locale conversion fails
char OCSYNC_EXPORT *csync_normalize_etag(const char *);
time_t OCSYNC_EXPORT oc_httpdate_parse( const char *date );
-#ifdef __cplusplus
-}
-#endif
-
/**
* }@
*/
+++ /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 "config_csync.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <stdio.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "c_lib.h"
-#include "c_private.h"
-
-#include "csync_private.h"
-#include "csync_exclude.h"
-#include "csync_misc.h"
-
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
-#include "csync_log.h"
-
-#ifndef WITH_TESTING
-static
-#endif
-int _csync_exclude_add(c_strlist_t **inList, const char *string) {
- size_t i = 0;
-
- // We never want duplicates, so check whether the string is already
- // in the list first.
- if (*inList) {
- for (i = 0; i < (*inList)->count; ++i) {
- char *pattern = (*inList)->vector[i];
- if (c_streq(pattern, string)) {
- return 1;
- }
- }
- }
- return c_strlist_add_grow(inList, string);
-}
-
-/** Expands C-like escape sequences.
- *
- * The returned string is heap-allocated and owned by the caller.
- */
-static const char *csync_exclude_expand_escapes(const char * input)
-{
- size_t i_len = strlen(input) + 1;
- char *out = c_malloc(i_len); // out can only be shorter
-
- size_t i = 0;
- size_t o = 0;
- for (; i < i_len; ++i) {
- if (input[i] == '\\') {
- // at worst input[i+1] is \0
- switch (input[i+1]) {
- case '\'': out[o++] = '\''; break;
- case '"': out[o++] = '"'; break;
- case '?': out[o++] = '?'; break;
- case '\\': out[o++] = '\\'; break;
- case 'a': out[o++] = '\a'; break;
- case 'b': out[o++] = '\b'; break;
- case 'f': out[o++] = '\f'; break;
- case 'n': out[o++] = '\n'; break;
- case 'r': out[o++] = '\r'; break;
- case 't': out[o++] = '\t'; break;
- case 'v': out[o++] = '\v'; break;
- default:
- out[o++] = input[i];
- out[o++] = input[i+1];
- break;
- }
- ++i;
- } else {
- out[o++] = input[i];
- }
- }
- return out;
-}
-
-int csync_exclude_load(const char *fname, c_strlist_t **list) {
- int fd = -1;
- int i = 0;
- int rc = -1;
- int64_t size;
- char *buf = NULL;
- char *entry = NULL;
- mbchar_t *w_fname;
-
- if (fname == NULL) {
- return -1;
- }
-
-#ifdef _WIN32
- _fmode = _O_BINARY;
-#endif
-
- w_fname = c_utf8_path_to_locale(fname);
- if (w_fname == NULL) {
- return -1;
- }
-
- fd = _topen(w_fname, O_RDONLY);
- c_free_locale_string(w_fname);
- if (fd < 0) {
- return -1;
- }
-
- size = lseek(fd, 0, SEEK_END);
- if (size < 0) {
- rc = -1;
- goto out;
- }
- lseek(fd, 0, SEEK_SET);
- if (size == 0) {
- rc = 0;
- goto out;
- }
- buf = c_malloc(size + 1);
- if (read(fd, buf, size) != size) {
- rc = -1;
- goto out;
- }
- buf[size] = '\0';
-
- /* FIXME: Use fgets and don't add duplicates */
- entry = buf;
- for (i = 0; i < size; i++) {
- if (buf[i] == '\n' || buf[i] == '\r') {
- if (entry != buf + i) {
- buf[i] = '\0';
- if (*entry != '#') {
- const char *unescaped = csync_exclude_expand_escapes(entry);
- rc = _csync_exclude_add(list, unescaped);
- if( rc == 0 ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped);
- }
- SAFE_FREE(unescaped);
- if (rc < 0) {
- goto out;
- }
- }
- }
- entry = buf + i + 1;
- }
- }
-
- rc = 0;
-out:
- SAFE_FREE(buf);
- close(fd);
- return rc;
-}
-
-// See http://support.microsoft.com/kb/74496 and
-// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
-// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955
-static const char* win_reserved_words[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
- "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4",
- "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "CLOCK$", "$Recycle.Bin" };
-
-bool csync_is_windows_reserved_word(const char* filename) {
-
- size_t win_reserve_words_len = sizeof(win_reserved_words) / sizeof(char*);
- size_t j;
-
- for (j = 0; j < win_reserve_words_len; j++) {
- int len_reserved_word = strlen(win_reserved_words[j]);
- int len_filename = strlen(filename);
- if (len_filename == 2 && filename[1] == ':') {
- if (filename[0] >= 'a' && filename[0] <= 'z') {
- return true;
- }
- if (filename[0] >= 'A' && filename[0] <= 'Z') {
- return true;
- }
- }
- if (c_strncasecmp(filename, win_reserved_words[j], len_reserved_word) == 0) {
- if (len_filename == len_reserved_word) {
- return true;
- }
- if ((len_filename > len_reserved_word) && (filename[len_reserved_word] == '.')) {
- return true;
- }
- }
- }
- return false;
-}
-
-static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
- size_t i = 0;
- const char *bname = NULL;
- size_t blen = 0;
- char *conflict = NULL;
- int rc = -1;
- CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
- CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
-
- /* split up the path */
- bname = strrchr(path, '/');
- if (bname) {
- bname += 1; // don't include the /
- } else {
- bname = path;
- }
- blen = strlen(bname);
-
- rc = csync_fnmatch("._sync_*.db*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
- rc = csync_fnmatch(".sync_*.db*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
- rc = csync_fnmatch(".csync_journal.db*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
-
- // check the strlen and ignore the file if its name is longer than 254 chars.
- // whenever changing this also check createDownloadTmpFileName
- if (blen > 254) {
- match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
- goto out;
- }
-
-#ifdef _WIN32
- // Windows cannot sync files ending in spaces (#2176). It also cannot
- // distinguish files ending in '.' from files without an ending,
- // as '.' is a separator that is not stored internally, so let's
- // not allow to sync those to avoid file loss/ambiguities (#416)
- if (blen > 1) {
- if (bname[blen-1]== ' ') {
- match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
- goto out;
- } else if (bname[blen-1]== '.' ) {
- match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
- goto out;
- }
- }
-
- if (csync_is_windows_reserved_word(bname)) {
- match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
- goto out;
- }
-
- // Filter out characters not allowed in a filename on windows
- const char *p = NULL;
- for (p = path; *p; p++) {
- switch (*p) {
- case '\\':
- case ':':
- case '?':
- case '*':
- case '"':
- case '>':
- case '<':
- case '|':
- match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
- goto out;
- default:
- break;
- }
- }
-#endif
-
- /* We create a desktop.ini on Windows for the sidebar icon, make sure we don't sync them. */
- rc = csync_fnmatch("Desktop.ini", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
-
- rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_SILENTLY_EXCLUDED;
- goto out;
- }
-
- /* Always ignore conflict files, not only via the exclude list */
- rc = csync_fnmatch("*_conflict-*", bname, 0);
- if (rc == 0) {
- match = CSYNC_FILE_EXCLUDE_CONFLICT;
- goto out;
- }
-
- if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
- rc = asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
- if (rc < 0) {
- goto out;
- }
- rc = csync_fnmatch(conflict, path, 0);
- if (rc == 0) {
- match = CSYNC_FILE_EXCLUDE_CONFLICT;
- SAFE_FREE(conflict);
- goto out;
- }
- SAFE_FREE(conflict);
- }
-
- if( ! excludes ) {
- goto out;
- }
-
- c_strlist_t *path_components = NULL;
- if (check_leading_dirs) {
- /* Build a list of path components to check. */
- path_components = c_strlist_new(32);
- char *path_split = strdup(path);
- size_t len = strlen(path_split);
- for (i = len; ; --i) {
- // read backwards until a path separator is found
- if (i != 0 && path_split[i-1] != '/') {
- continue;
- }
-
- // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
- if (path_split[i] != 0) {
- c_strlist_add_grow(&path_components, path_split + i);
- }
-
- if (i == 0) {
- break;
- }
-
- // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
- path_split[i-1] = '\0';
- c_strlist_add_grow(&path_components, path_split);
- }
- SAFE_FREE(path_split);
- }
-
- /* Loop over all exclude patterns and evaluate the given path */
- for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
- bool match_dirs_only = false;
- char *pattern = excludes->vector[i];
-
- type = CSYNC_FILE_EXCLUDE_LIST;
- if (!pattern[0]) { /* empty pattern */
- continue;
- }
- /* Excludes starting with ']' means it can be cleanup */
- if (pattern[0] == ']') {
- ++pattern;
- if (filetype == CSYNC_FTW_TYPE_FILE) {
- type = CSYNC_FILE_EXCLUDE_AND_REMOVE;
- }
- }
- /* Check if the pattern applies to pathes only. */
- if (pattern[strlen(pattern)-1] == '/') {
- if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) {
- continue;
- }
- match_dirs_only = true;
- pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
- }
-
- /* check if the pattern contains a / and if, compare to the whole path */
- if (strchr(pattern, '/')) {
- rc = csync_fnmatch(pattern, path, FNM_PATHNAME);
- if( rc == 0 ) {
- match = type;
- }
- /* if the pattern requires a dir, but path is not, its still not excluded. */
- if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) {
- match = CSYNC_NOT_EXCLUDED;
- }
- }
-
- /* if still not excluded, check each component and leading directory of the path */
- if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) {
- size_t j = 0;
- if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
- j = 1; // skip the first entry, which is bname
- }
- for (; j < path_components->count; ++j) {
- rc = csync_fnmatch(pattern, path_components->vector[j], 0);
- if (rc == 0) {
- match = type;
- break;
- }
- }
- } else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) {
- rc = csync_fnmatch(pattern, bname, 0);
- if (rc == 0) {
- match = type;
- }
- }
- if (match_dirs_only) {
- /* restore the '/' */
- pattern[strlen(pattern)] = '/';
- }
- }
- c_strlist_destroy(path_components);
-
- out:
-
- return match;
-}
-
-CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype) {
- return _csync_excluded_common(excludes, path, filetype, false);
-}
-
-CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype) {
- return _csync_excluded_common(excludes, path, filetype, true);
-}
-
--- /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 "config_csync.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "c_lib.h"
+#include "c_private.h"
+
+#include "csync_private.h"
+#include "csync_exclude.h"
+#include "csync_misc.h"
+
+#ifdef _WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
+#include "csync_log.h"
+
+#ifndef WITH_TESTING
+static
+#endif
+int _csync_exclude_add(c_strlist_t **inList, const char *string) {
+ size_t i = 0;
+
+ // We never want duplicates, so check whether the string is already
+ // in the list first.
+ if (*inList) {
+ for (i = 0; i < (*inList)->count; ++i) {
+ char *pattern = (*inList)->vector[i];
+ if (c_streq(pattern, string)) {
+ return 1;
+ }
+ }
+ }
+ return c_strlist_add_grow(inList, string);
+}
+
+/** Expands C-like escape sequences.
+ *
+ * The returned string is heap-allocated and owned by the caller.
+ */
+static const char *csync_exclude_expand_escapes(const char * input)
+{
+ size_t i_len = strlen(input) + 1;
+ char *out = (char*)c_malloc(i_len); // out can only be shorter
+
+ size_t i = 0;
+ size_t o = 0;
+ for (; i < i_len; ++i) {
+ if (input[i] == '\\') {
+ // at worst input[i+1] is \0
+ switch (input[i+1]) {
+ case '\'': out[o++] = '\''; break;
+ case '"': out[o++] = '"'; break;
+ case '?': out[o++] = '?'; break;
+ case '\\': out[o++] = '\\'; break;
+ case 'a': out[o++] = '\a'; break;
+ case 'b': out[o++] = '\b'; break;
+ case 'f': out[o++] = '\f'; break;
+ case 'n': out[o++] = '\n'; break;
+ case 'r': out[o++] = '\r'; break;
+ case 't': out[o++] = '\t'; break;
+ case 'v': out[o++] = '\v'; break;
+ default:
+ out[o++] = input[i];
+ out[o++] = input[i+1];
+ break;
+ }
+ ++i;
+ } else {
+ out[o++] = input[i];
+ }
+ }
+ return out;
+}
+
+int csync_exclude_load(const char *fname, c_strlist_t **list) {
+ int fd = -1;
+ int i = 0;
+ int rc = -1;
+ int64_t size;
+ char *buf = NULL;
+ char *entry = NULL;
+ mbchar_t *w_fname;
+
+ if (fname == NULL) {
+ return -1;
+ }
+
+#ifdef _WIN32
+ _fmode = _O_BINARY;
+#endif
+
+ w_fname = c_utf8_path_to_locale(fname);
+ if (w_fname == NULL) {
+ return -1;
+ }
+
+ fd = _topen(w_fname, O_RDONLY);
+ c_free_locale_string(w_fname);
+ if (fd < 0) {
+ return -1;
+ }
+
+ size = lseek(fd, 0, SEEK_END);
+ if (size < 0) {
+ rc = -1;
+ goto out;
+ }
+ lseek(fd, 0, SEEK_SET);
+ if (size == 0) {
+ rc = 0;
+ goto out;
+ }
+ buf = (char*)c_malloc(size + 1);
+ if (read(fd, buf, size) != size) {
+ rc = -1;
+ goto out;
+ }
+ buf[size] = '\0';
+
+ /* FIXME: Use fgets and don't add duplicates */
+ entry = buf;
+ for (i = 0; i < size; i++) {
+ if (buf[i] == '\n' || buf[i] == '\r') {
+ if (entry != buf + i) {
+ buf[i] = '\0';
+ if (*entry != '#') {
+ const char *unescaped = csync_exclude_expand_escapes(entry);
+ rc = _csync_exclude_add(list, unescaped);
+ if( rc == 0 ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped);
+ }
+ SAFE_FREE(unescaped);
+ if (rc < 0) {
+ goto out;
+ }
+ }
+ }
+ entry = buf + i + 1;
+ }
+ }
+
+ rc = 0;
+out:
+ SAFE_FREE(buf);
+ close(fd);
+ return rc;
+}
+
+// See http://support.microsoft.com/kb/74496 and
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955
+static const char* win_reserved_words[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
+ "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4",
+ "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "CLOCK$", "$Recycle.Bin" };
+
+bool csync_is_windows_reserved_word(const char* filename) {
+
+ size_t win_reserve_words_len = sizeof(win_reserved_words) / sizeof(char*);
+ size_t j;
+
+ for (j = 0; j < win_reserve_words_len; j++) {
+ int len_reserved_word = strlen(win_reserved_words[j]);
+ int len_filename = strlen(filename);
+ if (len_filename == 2 && filename[1] == ':') {
+ if (filename[0] >= 'a' && filename[0] <= 'z') {
+ return true;
+ }
+ if (filename[0] >= 'A' && filename[0] <= 'Z') {
+ return true;
+ }
+ }
+ if (c_strncasecmp(filename, win_reserved_words[j], len_reserved_word) == 0) {
+ if (len_filename == len_reserved_word) {
+ return true;
+ }
+ if ((len_filename > len_reserved_word) && (filename[len_reserved_word] == '.')) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
+ size_t i = 0;
+ const char *bname = NULL;
+ size_t blen = 0;
+ char *conflict = NULL;
+ int rc = -1;
+ CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
+ CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
+ c_strlist_t *path_components = NULL;
+
+ /* split up the path */
+ bname = strrchr(path, '/');
+ if (bname) {
+ bname += 1; // don't include the /
+ } else {
+ bname = path;
+ }
+ blen = strlen(bname);
+
+ rc = csync_fnmatch("._sync_*.db*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+ rc = csync_fnmatch(".sync_*.db*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+ rc = csync_fnmatch(".csync_journal.db*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+
+ // check the strlen and ignore the file if its name is longer than 254 chars.
+ // whenever changing this also check createDownloadTmpFileName
+ if (blen > 254) {
+ match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
+ goto out;
+ }
+
+#ifdef _WIN32
+ // Windows cannot sync files ending in spaces (#2176). It also cannot
+ // distinguish files ending in '.' from files without an ending,
+ // as '.' is a separator that is not stored internally, so let's
+ // not allow to sync those to avoid file loss/ambiguities (#416)
+ if (blen > 1) {
+ if (bname[blen-1]== ' ') {
+ match = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
+ goto out;
+ } else if (bname[blen-1]== '.' ) {
+ match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
+ goto out;
+ }
+ }
+
+ if (csync_is_windows_reserved_word(bname)) {
+ match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
+ goto out;
+ }
+
+ // Filter out characters not allowed in a filename on windows
+ for (const char *p = path; *p; p++) {
+ switch (*p) {
+ case '\\':
+ case ':':
+ case '?':
+ case '*':
+ case '"':
+ case '>':
+ case '<':
+ case '|':
+ match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
+ goto out;
+ default:
+ break;
+ }
+ }
+#endif
+
+ /* We create a desktop.ini on Windows for the sidebar icon, make sure we don't sync them. */
+ rc = csync_fnmatch("Desktop.ini", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+
+ rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_SILENTLY_EXCLUDED;
+ goto out;
+ }
+
+ /* Always ignore conflict files, not only via the exclude list */
+ rc = csync_fnmatch("*_conflict-*", bname, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_EXCLUDE_CONFLICT;
+ goto out;
+ }
+
+ if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
+ rc = asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
+ if (rc < 0) {
+ goto out;
+ }
+ rc = csync_fnmatch(conflict, path, 0);
+ if (rc == 0) {
+ match = CSYNC_FILE_EXCLUDE_CONFLICT;
+ SAFE_FREE(conflict);
+ goto out;
+ }
+ SAFE_FREE(conflict);
+ }
+
+ if( ! excludes ) {
+ goto out;
+ }
+
+ if (check_leading_dirs) {
+ /* Build a list of path components to check. */
+ path_components = c_strlist_new(32);
+ char *path_split = strdup(path);
+ size_t len = strlen(path_split);
+ for (i = len; ; --i) {
+ // read backwards until a path separator is found
+ if (i != 0 && path_split[i-1] != '/') {
+ continue;
+ }
+
+ // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
+ if (path_split[i] != 0) {
+ c_strlist_add_grow(&path_components, path_split + i);
+ }
+
+ if (i == 0) {
+ break;
+ }
+
+ // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
+ path_split[i-1] = '\0';
+ c_strlist_add_grow(&path_components, path_split);
+ }
+ SAFE_FREE(path_split);
+ }
+
+ /* Loop over all exclude patterns and evaluate the given path */
+ for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
+ bool match_dirs_only = false;
+ char *pattern = excludes->vector[i];
+
+ type = CSYNC_FILE_EXCLUDE_LIST;
+ if (!pattern[0]) { /* empty pattern */
+ continue;
+ }
+ /* Excludes starting with ']' means it can be cleanup */
+ if (pattern[0] == ']') {
+ ++pattern;
+ if (filetype == CSYNC_FTW_TYPE_FILE) {
+ type = CSYNC_FILE_EXCLUDE_AND_REMOVE;
+ }
+ }
+ /* Check if the pattern applies to pathes only. */
+ if (pattern[strlen(pattern)-1] == '/') {
+ if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) {
+ continue;
+ }
+ match_dirs_only = true;
+ pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
+ }
+
+ /* check if the pattern contains a / and if, compare to the whole path */
+ if (strchr(pattern, '/')) {
+ rc = csync_fnmatch(pattern, path, FNM_PATHNAME);
+ if( rc == 0 ) {
+ match = type;
+ }
+ /* if the pattern requires a dir, but path is not, its still not excluded. */
+ if (match_dirs_only && filetype != CSYNC_FTW_TYPE_DIR) {
+ match = CSYNC_NOT_EXCLUDED;
+ }
+ }
+
+ /* if still not excluded, check each component and leading directory of the path */
+ if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) {
+ size_t j = 0;
+ if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
+ j = 1; // skip the first entry, which is bname
+ }
+ for (; j < path_components->count; ++j) {
+ rc = csync_fnmatch(pattern, path_components->vector[j], 0);
+ if (rc == 0) {
+ match = type;
+ break;
+ }
+ }
+ } else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) {
+ rc = csync_fnmatch(pattern, bname, 0);
+ if (rc == 0) {
+ match = type;
+ }
+ }
+ if (match_dirs_only) {
+ /* restore the '/' */
+ pattern[strlen(pattern)] = '/';
+ }
+ }
+ c_strlist_destroy(path_components);
+
+ out:
+
+ return match;
+}
+
+CSYNC_EXCLUDE_TYPE csync_excluded_traversal(c_strlist_t *excludes, const char *path, int filetype) {
+ return _csync_excluded_common(excludes, path, filetype, false);
+}
+
+CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path, int filetype) {
+ return _csync_excluded_common(excludes, path, filetype, true);
+}
+
+++ /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 "config_csync.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "csync_private.h"
-#include "csync_log.h"
-
-CSYNC_THREAD int csync_log_level;
-CSYNC_THREAD csync_log_callback csync_log_cb;
-
-void csync_log(int verbosity,
- const char *function,
- const char *format, ...)
-{
- csync_log_callback log_fn = csync_get_log_callback();
- if (log_fn && verbosity <= csync_get_log_level()) {
- char buffer[1024];
- va_list va;
-
- va_start(va, format);
- vsnprintf(buffer, sizeof(buffer), format, va);
- va_end(va);
-
- log_fn(verbosity, function, buffer);
- return;
- }
-}
-
-int csync_set_log_level(int level) {
- if (level < 0) {
- return -1;
- }
-
- csync_log_level = level;
-
- return 0;
-}
-
-int csync_get_log_level(void) {
- return csync_log_level;
-}
-
-int csync_set_log_callback(csync_log_callback cb) {
- if (cb == NULL) {
- return -1;
- }
-
- csync_log_cb = cb;
-
- return 0;
-}
-
-csync_log_callback csync_get_log_callback(void) {
- return csync_log_cb;
-}
--- /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 "config_csync.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "csync_private.h"
+#include "csync_log.h"
+
+CSYNC_THREAD int csync_log_level;
+CSYNC_THREAD csync_log_callback csync_log_cb;
+
+void csync_log(int verbosity,
+ const char *function,
+ const char *format, ...)
+{
+ csync_log_callback log_fn = csync_get_log_callback();
+ if (log_fn && verbosity <= csync_get_log_level()) {
+ char buffer[1024];
+ va_list va;
+
+ va_start(va, format);
+ vsnprintf(buffer, sizeof(buffer), format, va);
+ va_end(va);
+
+ log_fn(verbosity, function, buffer);
+ return;
+ }
+}
+
+int csync_set_log_level(int level) {
+ if (level < 0) {
+ return -1;
+ }
+
+ csync_log_level = level;
+
+ return 0;
+}
+
+int csync_get_log_level(void) {
+ return csync_log_level;
+}
+
+int csync_set_log_callback(csync_log_callback cb) {
+ if (cb == NULL) {
+ return -1;
+ }
+
+ csync_log_cb = cb;
+
+ return 0;
+}
+
+csync_log_callback csync_get_log_callback(void) {
+ return csync_log_cb;
+}
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 "config_csync.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#if _WIN32
-# ifndef _WIN32_IE
-# define _WIN32_IE 0x0501 // SHGetSpecialFolderPath
-# endif
-# include <shlobj.h>
-#else /* _WIN32 */
-# include <pwd.h>
-#endif /* _WIN32 */
-
-#include "c_lib.h"
-#include "csync_misc.h"
-#include "csync_macros.h"
-#include "csync_log.h"
-
-#ifdef HAVE_FNMATCH
-#include <fnmatch.h>
-
-int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) {
- return fnmatch(__pattern, __name, __flags);
-}
-
-#else /* HAVE_FNMATCH */
-
-#include <shlwapi.h>
-int csync_fnmatch(const char *pattern, const char *name, int flags) {
- BOOL match;
-
- (void) flags;
-
- match = PathMatchSpecA(name, pattern);
-
- if(match)
- return 0;
- else
- return 1;
-}
-#endif /* HAVE_FNMATCH */
-
-CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status)
-{
- CSYNC_STATUS status = CSYNC_STATUS_OK;
-
- switch (error) {
- case 0:
- status = CSYNC_STATUS_OK;
- break;
- /* The custom errnos first. */
- case ERRNO_GENERAL_ERROR:
- status = CSYNC_STATUS_UNSUCCESSFUL;
- break;
- case ERRNO_LOOKUP_ERROR: /* In Neon: Server or proxy hostname lookup failed */
- status = CSYNC_STATUS_LOOKUP_ERROR;
- break;
- case ERRNO_USER_UNKNOWN_ON_SERVER: /* Neon: User authentication on server failed. */
- status = CSYNC_STATUS_SERVER_AUTH_ERROR;
- break;
- case ERRNO_PROXY_AUTH:
- status = CSYNC_STATUS_PROXY_AUTH_ERROR; /* Neon: User authentication on proxy failed */
- break;
- case ERRNO_CONNECT:
- status = CSYNC_STATUS_CONNECT_ERROR; /* Network: Connection error */
- break;
- case ERRNO_TIMEOUT:
- status = CSYNC_STATUS_TIMEOUT; /* Network: Timeout error */
- break;
- case ERRNO_SERVICE_UNAVAILABLE:
- status = CSYNC_STATUS_SERVICE_UNAVAILABLE; /* Service temporarily down */
- break;
- case ERRNO_STORAGE_UNAVAILABLE:
- status = CSYNC_STATUS_STORAGE_UNAVAILABLE; /* Storage temporarily unavailable */
- break;
- case EFBIG:
- status = CSYNC_STATUS_FILE_SIZE_ERROR; /* File larger than 2MB */
- break;
- case ERRNO_PRECONDITION:
- case ERRNO_RETRY:
- case ERRNO_REDIRECT:
- case ERRNO_WRONG_CONTENT:
- status = CSYNC_STATUS_HTTP_ERROR;
- break;
-
- case EPERM: /* Operation not permitted */
- case EACCES: /* Permission denied */
- status = CSYNC_STATUS_PERMISSION_DENIED;
- break;
- case ENOENT: /* No such file or directory */
- status = CSYNC_STATUS_NOT_FOUND;
- break;
- case EAGAIN: /* Try again */
- status = CSYNC_STATUS_TIMEOUT;
- break;
- case EEXIST: /* File exists */
- status = CSYNC_STATUS_FILE_EXISTS;
- break;
- case EINVAL:
- status = CSYNC_STATUS_PARAM_ERROR;
- break;
- case ENOSPC:
- status = CSYNC_STATUS_OUT_OF_SPACE;
- break;
-
- /* All the remaining basic errnos: */
- case EIO: /* I/O error */
- case ESRCH: /* No such process */
- case EINTR: /* Interrupted system call */
- case ENXIO: /* No such device or address */
- case E2BIG: /* Argument list too long */
- case ENOEXEC: /* Exec format error */
- case EBADF: /* Bad file number */
- case ECHILD: /* No child processes */
- case ENOMEM: /* Out of memory */
- case EFAULT: /* Bad address */
-#ifndef _WIN32
- case ENOTBLK: /* Block device required */
-#endif
- case EBUSY: /* Device or resource busy */
- case EXDEV: /* Cross-device link */
- case ENODEV: /* No such device */
- case ENOTDIR: /* Not a directory */
- case EISDIR: /* Is a directory */
- case ENFILE: /* File table overflow */
- case EMFILE: /* Too many open files */
- case ENOTTY: /* Not a typewriter */
-#ifndef _WIN32
- case ETXTBSY: /* Text file busy */
-#endif
- case ESPIPE: /* Illegal seek */
- case EROFS: /* Read-only file system */
- case EMLINK: /* Too many links */
- case EPIPE: /* Broken pipe */
-
- case ERRNO_ERROR_STRING:
- default:
- status = default_status;
- }
-
- return status;
-}
-
-/* Remove possible quotes, and also the -gzip at the end
- * Remove "-gzip" at the end (cf. https://github.comowncloud/client/issues/1195)
- * The caller must take ownership of the resulting string.
- */
-char *csync_normalize_etag(const char *etag)
-{
- int len = 0;
- char *buf = NULL;
- if (!etag)
- return NULL;
-
- len = strlen(etag);
- /* strip "XXXX-gzip" */
- if(len >= 7 && etag[0] == '"' && c_streq(etag + len - 6, "-gzip\"")) {
- etag++;
- len -= 7;
- }
- /* strip leading -gzip */
- if(len >= 5 && c_streq(etag + len - 5, "-gzip")) {
- len -= 5;
- }
- /* strip normal quotes */
- if (etag[0] == '"' && etag[len-1] == '"') {
- etag++;
- len -= 2;
- }
-
- buf = c_malloc( len+1 );
- strncpy( buf, etag, len );
- buf[len] = '\0';
- return buf;
-}
-
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 "config_csync.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if _WIN32
+# ifndef _WIN32_IE
+# define _WIN32_IE 0x0501 // SHGetSpecialFolderPath
+# endif
+# include <shlobj.h>
+#else /* _WIN32 */
+# include <pwd.h>
+#endif /* _WIN32 */
+
+#include "c_lib.h"
+#include "csync_misc.h"
+#include "csync_macros.h"
+#include "csync_log.h"
+
+#ifdef HAVE_FNMATCH
+#include <fnmatch.h>
+
+int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) {
+ return fnmatch(__pattern, __name, __flags);
+}
+
+#else /* HAVE_FNMATCH */
+
+#include <shlwapi.h>
+int csync_fnmatch(const char *pattern, const char *name, int flags) {
+ BOOL match;
+
+ (void) flags;
+
+ match = PathMatchSpecA(name, pattern);
+
+ if(match)
+ return 0;
+ else
+ return 1;
+}
+#endif /* HAVE_FNMATCH */
+
+CSYNC_STATUS csync_errno_to_status(int error, CSYNC_STATUS default_status)
+{
+ CSYNC_STATUS status = CSYNC_STATUS_OK;
+
+ switch (error) {
+ case 0:
+ status = CSYNC_STATUS_OK;
+ break;
+ /* The custom errnos first. */
+ case ERRNO_GENERAL_ERROR:
+ status = CSYNC_STATUS_UNSUCCESSFUL;
+ break;
+ case ERRNO_LOOKUP_ERROR: /* In Neon: Server or proxy hostname lookup failed */
+ status = CSYNC_STATUS_LOOKUP_ERROR;
+ break;
+ case ERRNO_USER_UNKNOWN_ON_SERVER: /* Neon: User authentication on server failed. */
+ status = CSYNC_STATUS_SERVER_AUTH_ERROR;
+ break;
+ case ERRNO_PROXY_AUTH:
+ status = CSYNC_STATUS_PROXY_AUTH_ERROR; /* Neon: User authentication on proxy failed */
+ break;
+ case ERRNO_CONNECT:
+ status = CSYNC_STATUS_CONNECT_ERROR; /* Network: Connection error */
+ break;
+ case ERRNO_TIMEOUT:
+ status = CSYNC_STATUS_TIMEOUT; /* Network: Timeout error */
+ break;
+ case ERRNO_SERVICE_UNAVAILABLE:
+ status = CSYNC_STATUS_SERVICE_UNAVAILABLE; /* Service temporarily down */
+ break;
+ case ERRNO_STORAGE_UNAVAILABLE:
+ status = CSYNC_STATUS_STORAGE_UNAVAILABLE; /* Storage temporarily unavailable */
+ break;
+ case EFBIG:
+ status = CSYNC_STATUS_FILE_SIZE_ERROR; /* File larger than 2MB */
+ break;
+ case ERRNO_PRECONDITION:
+ case ERRNO_RETRY:
+ case ERRNO_REDIRECT:
+ case ERRNO_WRONG_CONTENT:
+ status = CSYNC_STATUS_HTTP_ERROR;
+ break;
+
+ case EPERM: /* Operation not permitted */
+ case EACCES: /* Permission denied */
+ status = CSYNC_STATUS_PERMISSION_DENIED;
+ break;
+ case ENOENT: /* No such file or directory */
+ status = CSYNC_STATUS_NOT_FOUND;
+ break;
+ case EAGAIN: /* Try again */
+ status = CSYNC_STATUS_TIMEOUT;
+ break;
+ case EEXIST: /* File exists */
+ status = CSYNC_STATUS_FILE_EXISTS;
+ break;
+ case EINVAL:
+ status = CSYNC_STATUS_PARAM_ERROR;
+ break;
+ case ENOSPC:
+ status = CSYNC_STATUS_OUT_OF_SPACE;
+ break;
+
+ /* All the remaining basic errnos: */
+ case EIO: /* I/O error */
+ case ESRCH: /* No such process */
+ case EINTR: /* Interrupted system call */
+ case ENXIO: /* No such device or address */
+ case E2BIG: /* Argument list too long */
+ case ENOEXEC: /* Exec format error */
+ case EBADF: /* Bad file number */
+ case ECHILD: /* No child processes */
+ case ENOMEM: /* Out of memory */
+ case EFAULT: /* Bad address */
+#ifndef _WIN32
+ case ENOTBLK: /* Block device required */
+#endif
+ case EBUSY: /* Device or resource busy */
+ case EXDEV: /* Cross-device link */
+ case ENODEV: /* No such device */
+ case ENOTDIR: /* Not a directory */
+ case EISDIR: /* Is a directory */
+ case ENFILE: /* File table overflow */
+ case EMFILE: /* Too many open files */
+ case ENOTTY: /* Not a typewriter */
+#ifndef _WIN32
+ case ETXTBSY: /* Text file busy */
+#endif
+ case ESPIPE: /* Illegal seek */
+ case EROFS: /* Read-only file system */
+ case EMLINK: /* Too many links */
+ case EPIPE: /* Broken pipe */
+
+ case ERRNO_ERROR_STRING:
+ default:
+ status = default_status;
+ }
+
+ return status;
+}
+
+/* Remove possible quotes, and also the -gzip at the end
+ * Remove "-gzip" at the end (cf. https://github.comowncloud/client/issues/1195)
+ * The caller must take ownership of the resulting string.
+ */
+char *csync_normalize_etag(const char *etag)
+{
+ int len = 0;
+ char *buf = NULL;
+ if (!etag)
+ return NULL;
+
+ len = strlen(etag);
+ /* strip "XXXX-gzip" */
+ if(len >= 7 && etag[0] == '"' && c_streq(etag + len - 6, "-gzip\"")) {
+ etag++;
+ len -= 7;
+ }
+ /* strip leading -gzip */
+ if(len >= 5 && c_streq(etag + len - 5, "-gzip")) {
+ len -= 5;
+ }
+ /* strip normal quotes */
+ if (etag[0] == '"' && etag[len-1] == '"') {
+ etag++;
+ len -= 2;
+ }
+
+ buf = (char*)c_malloc( len+1 );
+ strncpy( buf, etag, len );
+ buf[len] = '\0';
+ return buf;
+}
+
size_t pathlen; /* u64 */
uint64_t inode; /* u64 */
mode_t mode; /* u32 */
- unsigned int type : 4;
+ enum csync_ftw_type_e type : 4;
unsigned int child_modified : 1;
unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */
+++ /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 "config_csync.h"
-
-#include <assert.h>
-#include "csync_private.h"
-#include "csync_reconcile.h"
-#include "csync_util.h"
-#include "csync_statedb.h"
-#include "csync_rename.h"
-#include "c_jhash.h"
-
-#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler"
-#include "csync_log.h"
-
-#include "inttypes.h"
-
-/* 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;
-
- /* compute the size of the parent directory */
- int parentlen = pathlen - 1;
- while (parentlen > 0 && path[parentlen] != '/') {
- parentlen--;
- }
- if (parentlen <= 0) {
- return NULL;
- }
-
- 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) {
- /* Yes, we are ignored */
- return node;
- } else {
- /* Not ignored */
- return NULL;
- }
- } else {
- /* Try if the parent itself is ignored */
- return _csync_check_ignored(tree, path, parentlen);
- }
-}
-
-/* Returns true if we're reasonably certain that hash equality
- * for the header means content equality.
- *
- * Cryptographic safety is not required - this is mainly
- * intended to rule out checksums like Adler32 that are not intended for
- * hashing and have high likelihood of collision with particular inputs.
- */
-static bool _csync_is_collision_safe_hash(const char *checksum_header)
-{
- return strncmp(checksum_header, "SHA1:", 5) == 0
- || strncmp(checksum_header, "MD5:", 4) == 0;
-}
-
-/**
- * The main function in the reconcile pass.
- *
- * It's called for each entry in the local and remote rbtrees by
- * csync_reconcile()
- *
- * Before the reconcile phase the trees already know about changes
- * relative to the sync journal. This function's job is to spot conflicts
- * between local and remote changes and adjust the nodes accordingly.
- *
- * See doc/dev/sync-algorithm.md for an overview.
- *
- *
- * Older detail comment:
- *
- * We merge replicas at the file level. The merged replica contains the
- * superset of files that are on the local machine and server copies of
- * the replica. In the case where the same file is in both the local
- * and server copy, the file that was modified most recently is used.
- * This means that new files are not deleted, and updated versions of
- * existing files are not overwritten.
- *
- * When a file is updated, the merge algorithm compares the destination
- * file with the the source file. If the destination file is newer
- * (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;
- csync_file_stat_t *tmp = NULL;
- 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;
-
- /* we need the opposite tree! */
- switch (ctx->current) {
- case LOCAL_REPLICA:
- tree = ctx->remote.tree;
- break;
- case REMOTE_REPLICA:
- tree = ctx->local.tree;
- break;
- default:
- break;
- }
-
- node = c_rbtree_find(tree, &cur->phash);
-
- if (!node) {
- /* Check the renamed path as well. */
- 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);
- node = c_rbtree_find(tree, &h);
- }
- SAFE_FREE(renamed_path);
- }
- if (!node) {
- /* Check if it is ignored */
- node = _csync_check_ignored(tree, cur->path, cur->pathlen);
- /* 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) {
- switch(cur->instruction) {
- /* file has been modified */
- case CSYNC_INSTRUCTION_EVAL:
- cur->instruction = CSYNC_INSTRUCTION_NEW;
- break;
- /* file has been removed on the opposite replica */
- case CSYNC_INSTRUCTION_NONE:
- case CSYNC_INSTRUCTION_UPDATE_METADATA:
- if (cur->has_ignored_files) {
- /* Do not remove a directory that has ignored files */
- break;
- }
- if (cur->child_modified) {
- /* re-create directory that has modified contents */
- cur->instruction = CSYNC_INSTRUCTION_NEW;
- break;
- }
- cur->instruction = CSYNC_INSTRUCTION_REMOVE;
- break;
- case CSYNC_INSTRUCTION_EVAL_RENAME:
- if(ctx->current == LOCAL_REPLICA ) {
- /* use the old name to find the "other" node */
- tmp = csync_statedb_get_stat_by_inode(ctx, cur->inode);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through inode %" PRIu64 ": %s",
- cur->inode, tmp ? "true":"false");
- } else if( ctx->current == REMOTE_REPLICA ) {
- tmp = csync_statedb_get_stat_by_file_id(ctx, cur->file_id);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through file ID %s: %s",
- cur->file_id, tmp ? "true":"false");
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unknown replica...");
- }
-
- if( tmp ) {
- len = strlen( tmp->path );
- if( len > 0 ) {
- h = c_jhash64((uint8_t *) tmp->path, len, 0);
- /* 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_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path);
- } 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 , 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.
- */
- }
- }
- }
-
- if(!other) {
- cur->instruction = CSYNC_INSTRUCTION_NEW;
- } else if (other->instruction == CSYNC_INSTRUCTION_NONE
- || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA
- || cur->type == CSYNC_FTW_TYPE_DIR) {
- other->instruction = CSYNC_INSTRUCTION_RENAME;
- other->destpath = c_strdup( cur->path );
- if( !c_streq(cur->file_id, "") ) {
- csync_vio_set_file_id( other->file_id, cur->file_id );
- }
- other->inode = cur->inode;
- cur->instruction = CSYNC_INSTRUCTION_NONE;
- } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
- other->instruction = CSYNC_INSTRUCTION_RENAME;
- other->destpath = c_strdup( cur->path );
-
- if( !c_streq(cur->file_id, "") ) {
- csync_vio_set_file_id( other->file_id, cur->file_id );
- }
- other->inode = cur->inode;
- cur->instruction = CSYNC_INSTRUCTION_NONE;
- } else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
- cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
- } else {
- assert(other->type != CSYNC_FTW_TYPE_DIR);
- cur->instruction = CSYNC_INSTRUCTION_NONE;
- other->instruction = CSYNC_INSTRUCTION_SYNC;
- }
- csync_file_stat_free(tmp);
- }
-
- break;
- default:
- break;
- }
- } else {
- bool is_conflict = true;
- /*
- * file found on the other replica
- */
- other = (csync_file_stat_t *) node->data;
-
- switch (cur->instruction) {
- case CSYNC_INSTRUCTION_UPDATE_METADATA:
- if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) {
- // Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last.
- cur->instruction = CSYNC_INSTRUCTION_NONE;
- }
- break;
- case CSYNC_INSTRUCTION_EVAL_RENAME:
- /* If the file already exist on the other side, we have a conflict.
- Abort the rename and consider it is a new file. */
- cur->instruction = CSYNC_INSTRUCTION_NEW;
- /* fall trough */
- /* file on current replica is changed or new */
- case CSYNC_INSTRUCTION_EVAL:
- case CSYNC_INSTRUCTION_NEW:
- // This operation is usually a no-op and will by default return false
- if (csync_file_locked_or_open(ctx->local.uri, cur->path)) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path);
- cur->instruction = CSYNC_INSTRUCTION_ERROR;
- if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error
- cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN;
- break;
- } else {
- //CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path);
- }
- switch (other->instruction) {
- /* file on other replica is changed or new */
- case CSYNC_INSTRUCTION_NEW:
- case CSYNC_INSTRUCTION_EVAL:
- if (other->type == CSYNC_FTW_TYPE_DIR &&
- cur->type == CSYNC_FTW_TYPE_DIR) {
- // Folders of the same path are always considered equals
- is_conflict = false;
- } else {
- // If the size or mtime is different, it's definitely a conflict.
- is_conflict = ((other->size != cur->size) || (other->modtime != cur->modtime));
-
- // It could be a conflict even if size and mtime match!
- //
- // In older client versions we always treated these cases as a
- // non-conflict. This behavior is preserved in case the server
- // doesn't provide a suitable content hash.
- //
- // When it does have one, however, we do create a job, but the job
- // will compare hashes and avoid the download if they are equal.
- const char *remoteChecksumHeader =
- (ctx->current == REMOTE_REPLICA ? cur->checksumHeader : other->checksumHeader);
- if (remoteChecksumHeader) {
- is_conflict |= _csync_is_collision_safe_hash(remoteChecksumHeader);
- }
-
- // SO: If there is no checksum, we can have !is_conflict here
- // even though the files have different content! This is an
- // intentional tradeoff. Downloading and comparing files would
- // be technically correct in this situation but leads to too
- // much waste.
- // In particular this kind of NEW/NEW situation with identical
- // sizes and mtimes pops up when the local database is lost for
- // whatever reason.
- }
- if (ctx->current == REMOTE_REPLICA) {
- // If the files are considered equal, only update the DB with the etag from remote
- cur->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
- other->instruction = CSYNC_INSTRUCTION_NONE;
- } else {
- cur->instruction = CSYNC_INSTRUCTION_NONE;
- other->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
- }
-
- break;
- /* file on the other replica has not been modified */
- case CSYNC_INSTRUCTION_NONE:
- case CSYNC_INSTRUCTION_UPDATE_METADATA:
- if (cur->type != other->type) {
- // If the type of the entity changed, it's like NEW, but
- // needs to delete the other entity first.
- cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE;
- other->instruction = CSYNC_INSTRUCTION_NONE;
- } else if (cur->type == CSYNC_FTW_TYPE_DIR) {
- cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
- other->instruction = CSYNC_INSTRUCTION_NONE;
- } else {
- cur->instruction = CSYNC_INSTRUCTION_SYNC;
- other->instruction = CSYNC_INSTRUCTION_NONE;
- }
- break;
- case CSYNC_INSTRUCTION_IGNORE:
- cur->instruction = CSYNC_INSTRUCTION_IGNORE;
- break;
- default:
- break;
- }
- default:
- break;
- }
- }
-
- //hide instruction NONE messages when log level is set to debug,
- //only show these messages on log level trace
- const char *repo = ctx->current == REMOTE_REPLICA ? "server" : "client";
- if(cur->instruction ==CSYNC_INSTRUCTION_NONE)
- {
- if(cur->type == CSYNC_FTW_TYPE_DIR)
- {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
- "%-30s %s dir: %s",
- csync_instruction_str(cur->instruction),
- repo,
- cur->path);
- }
- else
- {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
- "%-30s %s file: %s",
- csync_instruction_str(cur->instruction),
- repo,
- cur->path);
- }
- }
- else
- {
- if(cur->type == CSYNC_FTW_TYPE_DIR)
- {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO,
- "%-30s %s dir: %s",
- csync_instruction_str(cur->instruction),
- repo,
- cur->path);
- }
- else
- {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO,
- "%-30s %s file: %s",
- csync_instruction_str(cur->instruction),
- repo,
- cur->path);
- }
- }
-
- return 0;
-}
-
-int csync_reconcile_updates(CSYNC *ctx) {
- int rc;
- c_rbtree_t *tree = NULL;
-
- switch (ctx->current) {
- case LOCAL_REPLICA:
- tree = ctx->local.tree;
- break;
- case REMOTE_REPLICA:
- tree = ctx->remote.tree;
- break;
- default:
- break;
- }
-
- rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor);
- if( rc < 0 ) {
- ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR;
- }
- return rc;
-}
-
-/* vim: set ts=8 sw=2 et cindent: */
--- /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 "config_csync.h"
+
+#include <assert.h>
+#include "csync_private.h"
+#include "csync_reconcile.h"
+#include "csync_util.h"
+#include "csync_statedb.h"
+#include "csync_rename.h"
+#include "c_jhash.h"
+
+#define CSYNC_LOG_CATEGORY_NAME "csync.reconciler"
+#include "csync_log.h"
+
+// Needed for PRIu64 on MinGW in C++ mode.
+#define __STDC_FORMAT_MACROS
+#include "inttypes.h"
+
+/* 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;
+
+ /* compute the size of the parent directory */
+ int parentlen = pathlen - 1;
+ while (parentlen > 0 && path[parentlen] != '/') {
+ parentlen--;
+ }
+ if (parentlen <= 0) {
+ return NULL;
+ }
+
+ 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) {
+ /* Yes, we are ignored */
+ return node;
+ } else {
+ /* Not ignored */
+ return NULL;
+ }
+ } else {
+ /* Try if the parent itself is ignored */
+ return _csync_check_ignored(tree, path, parentlen);
+ }
+}
+
+/* Returns true if we're reasonably certain that hash equality
+ * for the header means content equality.
+ *
+ * Cryptographic safety is not required - this is mainly
+ * intended to rule out checksums like Adler32 that are not intended for
+ * hashing and have high likelihood of collision with particular inputs.
+ */
+static bool _csync_is_collision_safe_hash(const char *checksum_header)
+{
+ return strncmp(checksum_header, "SHA1:", 5) == 0
+ || strncmp(checksum_header, "MD5:", 4) == 0;
+}
+
+/**
+ * The main function in the reconcile pass.
+ *
+ * It's called for each entry in the local and remote rbtrees by
+ * csync_reconcile()
+ *
+ * Before the reconcile phase the trees already know about changes
+ * relative to the sync journal. This function's job is to spot conflicts
+ * between local and remote changes and adjust the nodes accordingly.
+ *
+ * See doc/dev/sync-algorithm.md for an overview.
+ *
+ *
+ * Older detail comment:
+ *
+ * We merge replicas at the file level. The merged replica contains the
+ * superset of files that are on the local machine and server copies of
+ * the replica. In the case where the same file is in both the local
+ * and server copy, the file that was modified most recently is used.
+ * This means that new files are not deleted, and updated versions of
+ * existing files are not overwritten.
+ *
+ * When a file is updated, the merge algorithm compares the destination
+ * file with the the source file. If the destination file is newer
+ * (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;
+ csync_file_stat_t *tmp = NULL;
+ 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;
+
+ /* we need the opposite tree! */
+ switch (ctx->current) {
+ case LOCAL_REPLICA:
+ tree = ctx->remote.tree;
+ break;
+ case REMOTE_REPLICA:
+ tree = ctx->local.tree;
+ break;
+ default:
+ break;
+ }
+
+ node = c_rbtree_find(tree, &cur->phash);
+
+ if (!node) {
+ /* Check the renamed path as well. */
+ 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);
+ node = c_rbtree_find(tree, &h);
+ }
+ SAFE_FREE(renamed_path);
+ }
+ if (!node) {
+ /* Check if it is ignored */
+ node = _csync_check_ignored(tree, cur->path, cur->pathlen);
+ /* 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) {
+ switch(cur->instruction) {
+ /* file has been modified */
+ case CSYNC_INSTRUCTION_EVAL:
+ cur->instruction = CSYNC_INSTRUCTION_NEW;
+ break;
+ /* file has been removed on the opposite replica */
+ case CSYNC_INSTRUCTION_NONE:
+ case CSYNC_INSTRUCTION_UPDATE_METADATA:
+ if (cur->has_ignored_files) {
+ /* Do not remove a directory that has ignored files */
+ break;
+ }
+ if (cur->child_modified) {
+ /* re-create directory that has modified contents */
+ cur->instruction = CSYNC_INSTRUCTION_NEW;
+ break;
+ }
+ cur->instruction = CSYNC_INSTRUCTION_REMOVE;
+ break;
+ case CSYNC_INSTRUCTION_EVAL_RENAME:
+ if(ctx->current == LOCAL_REPLICA ) {
+ /* use the old name to find the "other" node */
+ tmp = csync_statedb_get_stat_by_inode(ctx, cur->inode);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through inode %" PRIu64 ": %s",
+ cur->inode, tmp ? "true":"false");
+ } else if( ctx->current == REMOTE_REPLICA ) {
+ tmp = csync_statedb_get_stat_by_file_id(ctx, cur->file_id);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Finding opposite temp through file ID %s: %s",
+ cur->file_id, tmp ? "true":"false");
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unknown replica...");
+ }
+
+ if( tmp ) {
+ len = strlen( tmp->path );
+ if( len > 0 ) {
+ h = c_jhash64((uint8_t *) tmp->path, len, 0);
+ /* 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_LOG(CSYNC_LOG_PRIORITY_TRACE, "Origin found in our tree : %s", tmp->path);
+ } 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 , 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.
+ */
+ }
+ }
+ }
+
+ if(!other) {
+ cur->instruction = CSYNC_INSTRUCTION_NEW;
+ } else if (other->instruction == CSYNC_INSTRUCTION_NONE
+ || other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA
+ || cur->type == CSYNC_FTW_TYPE_DIR) {
+ other->instruction = CSYNC_INSTRUCTION_RENAME;
+ other->destpath = c_strdup( cur->path );
+ if( !c_streq(cur->file_id, "") ) {
+ csync_vio_set_file_id( other->file_id, cur->file_id );
+ }
+ other->inode = cur->inode;
+ cur->instruction = CSYNC_INSTRUCTION_NONE;
+ } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
+ other->instruction = CSYNC_INSTRUCTION_RENAME;
+ other->destpath = c_strdup( cur->path );
+
+ if( !c_streq(cur->file_id, "") ) {
+ csync_vio_set_file_id( other->file_id, cur->file_id );
+ }
+ other->inode = cur->inode;
+ cur->instruction = CSYNC_INSTRUCTION_NONE;
+ } else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
+ cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
+ } else {
+ assert(other->type != CSYNC_FTW_TYPE_DIR);
+ cur->instruction = CSYNC_INSTRUCTION_NONE;
+ other->instruction = CSYNC_INSTRUCTION_SYNC;
+ }
+ csync_file_stat_free(tmp);
+ }
+
+ break;
+ default:
+ break;
+ }
+ } else {
+ bool is_conflict = true;
+ /*
+ * file found on the other replica
+ */
+ other = (csync_file_stat_t *) node->data;
+
+ switch (cur->instruction) {
+ case CSYNC_INSTRUCTION_UPDATE_METADATA:
+ if (other->instruction == CSYNC_INSTRUCTION_UPDATE_METADATA && ctx->current == LOCAL_REPLICA) {
+ // Remote wins, the SyncEngine will pick relevant local metadata since the remote tree is walked last.
+ cur->instruction = CSYNC_INSTRUCTION_NONE;
+ }
+ break;
+ case CSYNC_INSTRUCTION_EVAL_RENAME:
+ /* If the file already exist on the other side, we have a conflict.
+ Abort the rename and consider it is a new file. */
+ cur->instruction = CSYNC_INSTRUCTION_NEW;
+ /* fall trough */
+ /* file on current replica is changed or new */
+ case CSYNC_INSTRUCTION_EVAL:
+ case CSYNC_INSTRUCTION_NEW:
+ // This operation is usually a no-op and will by default return false
+ if (csync_file_locked_or_open(ctx->local.uri, cur->path)) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path);
+ cur->instruction = CSYNC_INSTRUCTION_ERROR;
+ if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error
+ cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN;
+ break;
+ } else {
+ //CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path);
+ }
+ switch (other->instruction) {
+ /* file on other replica is changed or new */
+ case CSYNC_INSTRUCTION_NEW:
+ case CSYNC_INSTRUCTION_EVAL:
+ if (other->type == CSYNC_FTW_TYPE_DIR &&
+ cur->type == CSYNC_FTW_TYPE_DIR) {
+ // Folders of the same path are always considered equals
+ is_conflict = false;
+ } else {
+ // If the size or mtime is different, it's definitely a conflict.
+ is_conflict = ((other->size != cur->size) || (other->modtime != cur->modtime));
+
+ // It could be a conflict even if size and mtime match!
+ //
+ // In older client versions we always treated these cases as a
+ // non-conflict. This behavior is preserved in case the server
+ // doesn't provide a suitable content hash.
+ //
+ // When it does have one, however, we do create a job, but the job
+ // will compare hashes and avoid the download if they are equal.
+ const char *remoteChecksumHeader =
+ (ctx->current == REMOTE_REPLICA ? cur->checksumHeader : other->checksumHeader);
+ if (remoteChecksumHeader) {
+ is_conflict |= _csync_is_collision_safe_hash(remoteChecksumHeader);
+ }
+
+ // SO: If there is no checksum, we can have !is_conflict here
+ // even though the files have different content! This is an
+ // intentional tradeoff. Downloading and comparing files would
+ // be technically correct in this situation but leads to too
+ // much waste.
+ // In particular this kind of NEW/NEW situation with identical
+ // sizes and mtimes pops up when the local database is lost for
+ // whatever reason.
+ }
+ if (ctx->current == REMOTE_REPLICA) {
+ // If the files are considered equal, only update the DB with the etag from remote
+ cur->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
+ other->instruction = CSYNC_INSTRUCTION_NONE;
+ } else {
+ cur->instruction = CSYNC_INSTRUCTION_NONE;
+ other->instruction = is_conflict ? CSYNC_INSTRUCTION_CONFLICT : CSYNC_INSTRUCTION_UPDATE_METADATA;
+ }
+
+ break;
+ /* file on the other replica has not been modified */
+ case CSYNC_INSTRUCTION_NONE:
+ case CSYNC_INSTRUCTION_UPDATE_METADATA:
+ if (cur->type != other->type) {
+ // If the type of the entity changed, it's like NEW, but
+ // needs to delete the other entity first.
+ cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE;
+ other->instruction = CSYNC_INSTRUCTION_NONE;
+ } else if (cur->type == CSYNC_FTW_TYPE_DIR) {
+ cur->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+ other->instruction = CSYNC_INSTRUCTION_NONE;
+ } else {
+ cur->instruction = CSYNC_INSTRUCTION_SYNC;
+ other->instruction = CSYNC_INSTRUCTION_NONE;
+ }
+ break;
+ case CSYNC_INSTRUCTION_IGNORE:
+ cur->instruction = CSYNC_INSTRUCTION_IGNORE;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ //hide instruction NONE messages when log level is set to debug,
+ //only show these messages on log level trace
+ const char *repo = ctx->current == REMOTE_REPLICA ? "server" : "client";
+ if(cur->instruction ==CSYNC_INSTRUCTION_NONE)
+ {
+ if(cur->type == CSYNC_FTW_TYPE_DIR)
+ {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
+ "%-30s %s dir: %s",
+ csync_instruction_str(cur->instruction),
+ repo,
+ cur->path);
+ }
+ else
+ {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE,
+ "%-30s %s file: %s",
+ csync_instruction_str(cur->instruction),
+ repo,
+ cur->path);
+ }
+ }
+ else
+ {
+ if(cur->type == CSYNC_FTW_TYPE_DIR)
+ {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO,
+ "%-30s %s dir: %s",
+ csync_instruction_str(cur->instruction),
+ repo,
+ cur->path);
+ }
+ else
+ {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO,
+ "%-30s %s file: %s",
+ csync_instruction_str(cur->instruction),
+ repo,
+ cur->path);
+ }
+ }
+
+ return 0;
+}
+
+int csync_reconcile_updates(CSYNC *ctx) {
+ int rc;
+ c_rbtree_t *tree = NULL;
+
+ switch (ctx->current) {
+ case LOCAL_REPLICA:
+ tree = ctx->local.tree;
+ break;
+ case REMOTE_REPLICA:
+ tree = ctx->remote.tree;
+ break;
+ default:
+ break;
+ }
+
+ rc = c_rbtree_walk(tree, (void *) ctx, _csync_merge_algorithm_visitor);
+ if( rc < 0 ) {
+ ctx->status_code = CSYNC_STATUS_RECONCILE_ERROR;
+ }
+ return rc;
+}
+
+/* vim: set ts=8 sw=2 et cindent: */
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-extern "C" {
#include "csync_private.h"
#include "csync_rename.h"
-}
#include <map>
#include <string>
std::vector<renameop> todo;
};
-extern "C" {
void csync_rename_destroy(CSYNC* ctx)
{
delete reinterpret_cast<csync_rename_s *>(ctx->rename_info);
csync_rename_s* d = csync_rename_s::get(ctx);
return d->folder_renamed_from.size();
}
-
-}
#include "csync.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* 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);
/* Return the source of a given path in case of renames */
void OCSYNC_EXPORT csync_rename_record(CSYNC *ctx, const char *from, const char *to);
/* Return the amount of renamed item recorded */
bool OCSYNC_EXPORT csync_rename_count(CSYNC *ctx);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 "config_csync.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <sqlite3.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <inttypes.h>
-
-#include "c_lib.h"
-#include "csync_private.h"
-#include "csync_statedb.h"
-#include "csync_util.h"
-#include "csync_misc.h"
-#include "csync_exclude.h"
-
-#include "c_string.h"
-#include "c_jhash.h"
-#include "csync_time.h"
-
-#define CSYNC_LOG_CATEGORY_NAME "csync.statedb"
-#include "csync_log.h"
-#include "csync_rename.h"
-
-#define BUF_SIZE 16
-
-#define sqlite_open(A, B) sqlite3_open_v2(A,B, SQLITE_OPEN_READONLY+SQLITE_OPEN_NOMUTEX, NULL)
-
-#define SQLTM_TIME 150
-#define SQLTM_COUNT 10
-
-#define SQLITE_BUSY_HANDLED(F) if(1) { \
- int n = 0; \
- do { rc = F ; \
- if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) { \
- n++; \
- csync_sleep(SQLTM_TIME); \
- } \
- }while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))); \
- }
-
-
-void csync_set_statedb_exists(CSYNC *ctx, int val) {
- ctx->statedb.exists = val;
-}
-
-int csync_get_statedb_exists(CSYNC *ctx) {
- return ctx->statedb.exists;
-}
-
-static int _csync_check_db_integrity(sqlite3 *db) {
- c_strlist_t *result = NULL;
- int rc = -1;
-
- result = csync_statedb_query(db, "PRAGMA quick_check;");
- if (result != NULL) {
- /* There is a result */
- if (result->count > 0) {
- if (c_streq(result->vector[0], "ok")) {
- rc = 0;
- }
- }
- c_strlist_destroy(result);
- }
-
- if( sqlite3_threadsafe() == 0 ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "* WARNING: SQLite module is not threadsafe!");
- rc = -1;
- }
-
- return rc;
-}
-
-static int _csync_statedb_is_empty(sqlite3 *db) {
- c_strlist_t *result = NULL;
- int rc = 0;
-
- result = csync_statedb_query(db, "SELECT COUNT(phash) FROM metadata LIMIT 1 OFFSET 0;");
- if (result == NULL) {
- rc = 1;
- }
- c_strlist_destroy(result);
-
- return rc;
-}
-
-#ifndef NDEBUG
-static void sqlite_profile( void *x, const char* sql, sqlite3_uint64 time)
-{
- (void)x;
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
- "_SQL_ %s: %llu", sql, time);
-
-}
-#endif
-
-int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb) {
- int rc = -1;
- c_strlist_t *result = NULL;
- sqlite3 *db = NULL;
-
- if( !ctx ) {
- return -1;
- }
-
- if (ctx->statedb.db) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: DB already open");
- ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
- return -1;
- }
-
- ctx->statedb.lastReturnValue = SQLITE_OK;
-
- /* Openthe database */
- if (sqlite_open(statedb, &db) != SQLITE_OK) {
- const char *errmsg= sqlite3_errmsg(ctx->statedb.db);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: Failed to sqlite3 open statedb - bail out: %s.",
- errmsg ? errmsg : "<no sqlite3 errormsg>");
-
- rc = -1;
- ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
- goto out;
- }
-
- if (_csync_check_db_integrity(db) != 0) {
- const char *errmsg= sqlite3_errmsg(db);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: sqlite3 integrity check failed - bail out: %s.",
- errmsg ? errmsg : "<no sqlite3 errormsg>");
- rc = -1;
- ctx->status_code = CSYNC_STATUS_STATEDB_CORRUPTED;
- goto out;
- }
-
- if (_csync_statedb_is_empty(db)) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "statedb contents doesn't exist");
- csync_set_statedb_exists(ctx, 0);
- } else {
- csync_set_statedb_exists(ctx, 1);
- }
-
- /* Print out the version */
- //
- result = csync_statedb_query(db, "SELECT sqlite_version();");
- if (result && result->count >= 1) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3 version \"%s\"", *result->vector);
- }
- c_strlist_destroy(result);
-
- /* optimization for speeding up SQLite */
- result = csync_statedb_query(db, "PRAGMA synchronous = NORMAL;");
- c_strlist_destroy(result);
- result = csync_statedb_query(db, "PRAGMA case_sensitive_like = ON;");
- c_strlist_destroy(result);
-
- /* set a busy handler with 5 seconds timeout */
- sqlite3_busy_timeout(db, 5000);
-
-#ifndef NDEBUG
- sqlite3_profile(db, sqlite_profile, 0 );
-#endif
- *pdb = db;
-
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Success");
-
- return 0;
-out:
- sqlite3_close(db);
- return rc;
-}
-
-int csync_statedb_close(CSYNC *ctx) {
- int rc = 0;
-
- if (!ctx) {
- return -1;
- }
-
- /* deallocate query resources */
- if( ctx->statedb.by_fileid_stmt ) {
- sqlite3_finalize(ctx->statedb.by_fileid_stmt);
- ctx->statedb.by_fileid_stmt = NULL;
- }
- if( ctx->statedb.by_hash_stmt ) {
- sqlite3_finalize(ctx->statedb.by_hash_stmt);
- ctx->statedb.by_hash_stmt = NULL;
- }
- if( ctx->statedb.by_inode_stmt) {
- sqlite3_finalize(ctx->statedb.by_inode_stmt);
- ctx->statedb.by_inode_stmt = NULL;
- }
-
- ctx->statedb.lastReturnValue = SQLITE_OK;
-
- int sr = sqlite3_close(ctx->statedb.db);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_close=%d", sr);
-
- ctx->statedb.db = 0;
-
- return rc;
-}
-
-#define METADATA_QUERY \
- "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, " \
- "filesize, ignoredChildrenRemote, " \
- "contentchecksumtype.name || ':' || contentChecksum " \
- "FROM metadata " \
- "LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id"
-
-// This funciton parses a line from the metadata table into the given csync_file_stat
-// structure which it is also allocating.
-// Note that this function calls laso sqlite3_step to actually get the info from db and
-// returns the sqlite return type.
-static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3_stmt *stmt )
-{
- int rc = SQLITE_ERROR;
- int column_count;
- int len;
-
- if( ! stmt ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Fatal: Statement is NULL.");
- return SQLITE_ERROR;
- }
-
- column_count = sqlite3_column_count(stmt);
-
- SQLITE_BUSY_HANDLED( sqlite3_step(stmt) );
-
- if( rc == SQLITE_ROW ) {
- if(column_count > 7) {
- const char *name;
-
- /* phash, pathlen, path, inode, uid, gid, mode, modtime */
- len = sqlite3_column_int(stmt, 1);
- *st = c_malloc(sizeof(csync_file_stat_t) + len + 1);
- /* clear the whole structure */
- ZERO_STRUCTP(*st);
-
- /* The query suceeded so use the phash we pass to the function. */
- (*st)->phash = sqlite3_column_int64(stmt, 0);
-
- (*st)->pathlen = sqlite3_column_int(stmt, 1);
- name = (const char*) sqlite3_column_text(stmt, 2);
- memcpy((*st)->path, (len ? name : ""), len + 1);
- (*st)->inode = sqlite3_column_int64(stmt,3);
- (*st)->mode = sqlite3_column_int(stmt, 6);
- (*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
-
- if(*st && column_count > 8 ) {
- (*st)->type = sqlite3_column_int(stmt, 8);
- }
-
- if(column_count > 9 && sqlite3_column_text(stmt, 9)) {
- (*st)->etag = c_strdup( (char*) sqlite3_column_text(stmt, 9) );
- }
- if(column_count > 10 && sqlite3_column_text(stmt,10)) {
- csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
- }
- if(column_count > 11 && sqlite3_column_text(stmt,11)) {
- strncpy((*st)->remotePerm,
- (char*) sqlite3_column_text(stmt, 11),
- REMOTE_PERM_BUF_SIZE);
- }
- if(column_count > 12 && sqlite3_column_int64(stmt,12)) {
- (*st)->size = sqlite3_column_int64(stmt, 12);
- }
- if(column_count > 13) {
- (*st)->has_ignored_files = sqlite3_column_int(stmt, 13);
- }
- if (column_count > 14 && sqlite3_column_text(stmt, 14)) {
- (*st)->checksumHeader = c_strdup((char *)sqlite3_column_text(stmt, 14));
- }
-
- }
- } else {
- if( rc != SQLITE_DONE ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Query results in %d", rc);
- }
- }
- return rc;
-}
-
-/* caller must free the memory */
-csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
- uint64_t phash)
-{
- csync_file_stat_t *st = NULL;
- int rc;
-
- if( !ctx || ctx->db_is_empty ) {
- return NULL;
- }
-
- if( ctx->statedb.by_hash_stmt == NULL ) {
- const char *hash_query = "SELECT " METADATA_QUERY " WHERE phash=?1";
-
- SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL));
- ctx->statedb.lastReturnValue = rc;
- if( rc != SQLITE_OK ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query.");
- return NULL;
- }
- }
-
- if( ctx->statedb.by_hash_stmt == NULL ) {
- return NULL;
- }
-
- sqlite3_bind_int64(ctx->statedb.by_hash_stmt, 1, (long long signed int)phash);
-
- rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_hash_stmt);
- ctx->statedb.lastReturnValue = rc;
- if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
- }
- sqlite3_reset(ctx->statedb.by_hash_stmt);
-
- return st;
-}
-
-csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
- const char *file_id ) {
- csync_file_stat_t *st = NULL;
- int rc = 0;
-
- if (!file_id) {
- return 0;
- }
- if (c_streq(file_id, "")) {
- return 0;
- }
-
- if( !ctx || ctx->db_is_empty ) {
- return NULL;
- }
-
- if( ctx->statedb.by_fileid_stmt == NULL ) {
- const char *query = "SELECT " METADATA_QUERY " WHERE fileid=?1";
-
- SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL));
- ctx->statedb.lastReturnValue = rc;
- if( rc != SQLITE_OK ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query.");
- return NULL;
- }
- }
-
- /* bind the query value */
- sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC);
-
- rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt);
- ctx->statedb.lastReturnValue = rc;
- if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
- }
- // clear the resources used by the statement.
- sqlite3_reset(ctx->statedb.by_fileid_stmt);
-
- return st;
-}
-
-/* caller must free the memory */
-csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
- uint64_t inode)
-{
- csync_file_stat_t *st = NULL;
- int rc;
-
- if (!inode) {
- return NULL;
- }
-
- if( !ctx || ctx->db_is_empty ) {
- return NULL;
- }
-
- if( ctx->statedb.by_inode_stmt == NULL ) {
- const char *inode_query = "SELECT " METADATA_QUERY " WHERE inode=?1";
-
- SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL));
- ctx->statedb.lastReturnValue = rc;
- if( rc != SQLITE_OK ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for inode query.");
- return NULL;
- }
- }
-
- if( ctx->statedb.by_inode_stmt == NULL ) {
- return NULL;
- }
-
- sqlite3_bind_int64(ctx->statedb.by_inode_stmt, 1, (long long signed int)inode);
-
- rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_inode_stmt);
- ctx->statedb.lastReturnValue = rc;
- if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata by inode: %d!", rc);
- }
- sqlite3_reset(ctx->statedb.by_inode_stmt);
-
- return st;
-}
-
-int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
- int rc;
- sqlite3_stmt *stmt = NULL;
- int64_t cnt = 0;
-
- if( !path ) {
- return -1;
- }
-
- if( !ctx || ctx->db_is_empty ) {
- return -1;
- }
-
- /* Select the entries for anything that starts with (path+'/')
- * In other words, anything that is between path+'/' and path+'0',
- * (because '0' follows '/' in ascii)
- */
- const char *below_path_query = "SELECT " METADATA_QUERY " WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC";
- SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL));
- ctx->statedb.lastReturnValue = rc;
- if( rc != SQLITE_OK ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query.");
- return -1;
- }
-
- if (stmt == NULL) {
- return -1;
- }
-
- sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC);
- sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC);
-
- cnt = 0;
-
- ctx->statedb.lastReturnValue = rc;
- do {
- csync_file_stat_t *st = NULL;
-
- rc = _csync_file_stat_from_metadata_table( &st, stmt);
- if( st ) {
- /* When selective sync is used, the database may have subtrees with a parent
- * whose etag (md5) is _invalid_. These are ignored and shall not appear in the
- * remote tree.
- * Sometimes folders that are not ignored by selective sync get marked as
- * _invalid_, but that is not a problem as the next discovery will retrieve
- * their correct etags again and we don't run into this case.
- */
- if( c_streq(st->etag, "_invalid_") ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded", st->path);
- char *skipbase = c_strdup(st->path);
- skipbase[st->pathlen] = '/';
- int skiplen = st->pathlen + 1;
-
- /* Skip over all entries with the same base path. Note that this depends
- * strongly on the ordering of the retrieved items. */
- do {
- csync_file_stat_free(st);
- rc = _csync_file_stat_from_metadata_table( &st, stmt);
- if( st && strncmp(st->path, skipbase, skiplen) != 0 ) {
- break;
- }
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded because the parent is", st->path);
- } while( rc == SQLITE_ROW );
-
- /* End of data? */
- if( rc != SQLITE_ROW || !st ) {
- continue;
- }
- }
-
- /* Check for exclusion from the tree.
- * Note that this is only a safety net in case the ignore list changes
- * without a full remote discovery being triggered. */
- CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx->excludes, st->path, st->type);
- if (excluded != CSYNC_NOT_EXCLUDED) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", st->path, excluded);
-
- if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
- || excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
- csync_file_stat_free(st);
- continue;
- }
-
- st->instruction = CSYNC_INSTRUCTION_IGNORE;
- }
-
- /* store into result list. */
- if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
- csync_file_stat_free(st);
- ctx->status_code = CSYNC_STATUS_TREE_ERROR;
- break;
- }
- cnt++;
- }
- } while( rc == SQLITE_ROW );
-
- ctx->statedb.lastReturnValue = rc;
- if( rc != SQLITE_DONE ) {
- ctx->status_code = CSYNC_STATUS_TREE_ERROR;
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
- }
- sqlite3_finalize(stmt);
-
- return 0;
-}
-
-/* query the statedb, caller must free the memory */
-c_strlist_t *csync_statedb_query(sqlite3 *db,
- const char *statement) {
- int err = SQLITE_OK;
- int rc = SQLITE_OK;
- size_t i = 0;
- size_t busy_count = 0;
- size_t retry_count = 0;
- size_t column_count = 0;
- sqlite3_stmt *stmt;
- const char *tail = NULL;
- const char *field = NULL;
- c_strlist_t *result = NULL;
- int row = 0;
-
- do {
- /* compile SQL program into a virtual machine, reattempteing if busy */
- do {
- if (busy_count) {
- csync_sleep(100);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count);
- }
- err = sqlite3_prepare(db, statement, -1, &stmt, &tail);
- } while (err == SQLITE_BUSY && busy_count ++ < 120);
-
- if (err != SQLITE_OK) {
- if (err == SQLITE_BUSY) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear");
- }
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
- "sqlite3_compile error: %s - on query %s",
- sqlite3_errmsg(db), statement);
- break;
- } else {
- busy_count = 0;
- column_count = sqlite3_column_count(stmt);
-
- /* execute virtual machine by iterating over rows */
- for(;;) {
- err = sqlite3_step(stmt);
-
- if (err == SQLITE_BUSY) {
- if (busy_count++ > 120) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
- break;
- }
- csync_sleep(100);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count);
- continue;
- }
-
- if (err == SQLITE_MISUSE) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!");
- }
-
- if (err == SQLITE_DONE) {
- if (result == NULL) {
- result = c_strlist_new(1);
- }
- break;
- }
-
- if (err == SQLITE_ERROR) {
- break;
- }
-
- row++;
- if( result ) {
- result = c_strlist_expand(result, row*column_count);
- } else {
- result = c_strlist_new(column_count);
- }
-
- if (result == NULL) {
- return NULL;
- }
-
- /* iterate over columns */
- for (i = 0; i < column_count; i++) {
- field = (const char *) sqlite3_column_text(stmt, i);
- if (!field)
- field = "";
- // CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", field);
- if (c_strlist_add(result, field) < 0) {
- c_strlist_destroy(result);
- return NULL;
- }
- }
- } /* end infinite for loop */
-
- /* deallocate vm resources */
- rc = sqlite3_finalize(stmt);
-
- if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(db), statement);
- if (result != NULL) {
- c_strlist_destroy(result);
- }
- return NULL;
- }
-
- if (rc == SQLITE_SCHEMA) {
- retry_count ++;
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement);
- if (retry_count < 10) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now.");
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement);
- if (result != NULL) {
- c_strlist_destroy(result);
- }
- result = c_strlist_new(1);
- }
- }
- }
- } while (rc == SQLITE_SCHEMA && retry_count < 10);
-
- return result;
-}
-
-/* vim: set ts=8 sw=2 et cindent: */
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 "config_csync.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sqlite3.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "c_lib.h"
+#include "csync_private.h"
+#include "csync_statedb.h"
+#include "csync_util.h"
+#include "csync_misc.h"
+#include "csync_exclude.h"
+
+#include "c_string.h"
+#include "c_jhash.h"
+#include "csync_time.h"
+
+#define CSYNC_LOG_CATEGORY_NAME "csync.statedb"
+#include "csync_log.h"
+#include "csync_rename.h"
+
+// Needed for PRIu64 on MinGW in C++ mode.
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#define BUF_SIZE 16
+
+#define sqlite_open(A, B) sqlite3_open_v2(A,B, SQLITE_OPEN_READONLY+SQLITE_OPEN_NOMUTEX, NULL)
+
+#define SQLTM_TIME 150
+#define SQLTM_COUNT 10
+
+#define SQLITE_BUSY_HANDLED(F) if(1) { \
+ int n = 0; \
+ do { rc = F ; \
+ if( (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED) ) { \
+ n++; \
+ csync_sleep(SQLTM_TIME); \
+ } \
+ }while( (n < SQLTM_COUNT) && ((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))); \
+ }
+
+
+void csync_set_statedb_exists(CSYNC *ctx, int val) {
+ ctx->statedb.exists = val;
+}
+
+int csync_get_statedb_exists(CSYNC *ctx) {
+ return ctx->statedb.exists;
+}
+
+static int _csync_check_db_integrity(sqlite3 *db) {
+ c_strlist_t *result = NULL;
+ int rc = -1;
+
+ result = csync_statedb_query(db, "PRAGMA quick_check;");
+ if (result != NULL) {
+ /* There is a result */
+ if (result->count > 0) {
+ if (c_streq(result->vector[0], "ok")) {
+ rc = 0;
+ }
+ }
+ c_strlist_destroy(result);
+ }
+
+ if( sqlite3_threadsafe() == 0 ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "* WARNING: SQLite module is not threadsafe!");
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static int _csync_statedb_is_empty(sqlite3 *db) {
+ c_strlist_t *result = NULL;
+ int rc = 0;
+
+ result = csync_statedb_query(db, "SELECT COUNT(phash) FROM metadata LIMIT 1 OFFSET 0;");
+ if (result == NULL) {
+ rc = 1;
+ }
+ c_strlist_destroy(result);
+
+ return rc;
+}
+
+#ifndef NDEBUG
+static void sqlite_profile( void *x, const char* sql, sqlite3_uint64 time)
+{
+ (void)x;
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
+ "_SQL_ %s: %llu", sql, time);
+
+}
+#endif
+
+int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb) {
+ int rc = -1;
+ c_strlist_t *result = NULL;
+ sqlite3 *db = NULL;
+
+ if( !ctx ) {
+ return -1;
+ }
+
+ if (ctx->statedb.db) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: DB already open");
+ ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
+ return -1;
+ }
+
+ ctx->statedb.lastReturnValue = SQLITE_OK;
+
+ /* Openthe database */
+ if (sqlite_open(statedb, &db) != SQLITE_OK) {
+ const char *errmsg= sqlite3_errmsg(ctx->statedb.db);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: Failed to sqlite3 open statedb - bail out: %s.",
+ errmsg ? errmsg : "<no sqlite3 errormsg>");
+
+ rc = -1;
+ ctx->status_code = CSYNC_STATUS_STATEDB_LOAD_ERROR;
+ goto out;
+ }
+
+ if (_csync_check_db_integrity(db) != 0) {
+ const char *errmsg= sqlite3_errmsg(db);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: sqlite3 integrity check failed - bail out: %s.",
+ errmsg ? errmsg : "<no sqlite3 errormsg>");
+ rc = -1;
+ ctx->status_code = CSYNC_STATUS_STATEDB_CORRUPTED;
+ goto out;
+ }
+
+ if (_csync_statedb_is_empty(db)) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "statedb contents doesn't exist");
+ csync_set_statedb_exists(ctx, 0);
+ } else {
+ csync_set_statedb_exists(ctx, 1);
+ }
+
+ /* Print out the version */
+ //
+ result = csync_statedb_query(db, "SELECT sqlite_version();");
+ if (result && result->count >= 1) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3 version \"%s\"", *result->vector);
+ }
+ c_strlist_destroy(result);
+
+ /* optimization for speeding up SQLite */
+ result = csync_statedb_query(db, "PRAGMA synchronous = NORMAL;");
+ c_strlist_destroy(result);
+ result = csync_statedb_query(db, "PRAGMA case_sensitive_like = ON;");
+ c_strlist_destroy(result);
+
+ /* set a busy handler with 5 seconds timeout */
+ sqlite3_busy_timeout(db, 5000);
+
+#ifndef NDEBUG
+ sqlite3_profile(db, sqlite_profile, 0 );
+#endif
+ *pdb = db;
+
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Success");
+
+ return 0;
+out:
+ sqlite3_close(db);
+ return rc;
+}
+
+int csync_statedb_close(CSYNC *ctx) {
+ int rc = 0;
+
+ if (!ctx) {
+ return -1;
+ }
+
+ /* deallocate query resources */
+ if( ctx->statedb.by_fileid_stmt ) {
+ sqlite3_finalize(ctx->statedb.by_fileid_stmt);
+ ctx->statedb.by_fileid_stmt = NULL;
+ }
+ if( ctx->statedb.by_hash_stmt ) {
+ sqlite3_finalize(ctx->statedb.by_hash_stmt);
+ ctx->statedb.by_hash_stmt = NULL;
+ }
+ if( ctx->statedb.by_inode_stmt) {
+ sqlite3_finalize(ctx->statedb.by_inode_stmt);
+ ctx->statedb.by_inode_stmt = NULL;
+ }
+
+ ctx->statedb.lastReturnValue = SQLITE_OK;
+
+ int sr = sqlite3_close(ctx->statedb.db);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_close=%d", sr);
+
+ ctx->statedb.db = 0;
+
+ return rc;
+}
+
+#define METADATA_QUERY \
+ "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, " \
+ "filesize, ignoredChildrenRemote, " \
+ "contentchecksumtype.name || ':' || contentChecksum " \
+ "FROM metadata " \
+ "LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id"
+
+// This funciton parses a line from the metadata table into the given csync_file_stat
+// structure which it is also allocating.
+// Note that this function calls laso sqlite3_step to actually get the info from db and
+// returns the sqlite return type.
+static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3_stmt *stmt )
+{
+ int rc = SQLITE_ERROR;
+ int column_count;
+ int len;
+
+ if( ! stmt ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Fatal: Statement is NULL.");
+ return SQLITE_ERROR;
+ }
+
+ column_count = sqlite3_column_count(stmt);
+
+ SQLITE_BUSY_HANDLED( sqlite3_step(stmt) );
+
+ if( rc == SQLITE_ROW ) {
+ if(column_count > 7) {
+ const char *name;
+
+ /* phash, pathlen, path, inode, uid, gid, mode, modtime */
+ len = sqlite3_column_int(stmt, 1);
+ *st = (csync_file_stat_t*)c_malloc(sizeof(csync_file_stat_t) + len + 1);
+ /* clear the whole structure */
+ ZERO_STRUCTP(*st);
+
+ /* The query suceeded so use the phash we pass to the function. */
+ (*st)->phash = sqlite3_column_int64(stmt, 0);
+
+ (*st)->pathlen = sqlite3_column_int(stmt, 1);
+ name = (const char*) sqlite3_column_text(stmt, 2);
+ memcpy((*st)->path, (len ? name : ""), len + 1);
+ (*st)->inode = sqlite3_column_int64(stmt,3);
+ (*st)->mode = sqlite3_column_int(stmt, 6);
+ (*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
+
+ if(*st && column_count > 8 ) {
+ (*st)->type = static_cast<enum csync_ftw_type_e>(sqlite3_column_int(stmt, 8));
+ }
+
+ if(column_count > 9 && sqlite3_column_text(stmt, 9)) {
+ (*st)->etag = c_strdup( (char*) sqlite3_column_text(stmt, 9) );
+ }
+ if(column_count > 10 && sqlite3_column_text(stmt,10)) {
+ csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
+ }
+ if(column_count > 11 && sqlite3_column_text(stmt,11)) {
+ strncpy((*st)->remotePerm,
+ (char*) sqlite3_column_text(stmt, 11),
+ REMOTE_PERM_BUF_SIZE);
+ }
+ if(column_count > 12 && sqlite3_column_int64(stmt,12)) {
+ (*st)->size = sqlite3_column_int64(stmt, 12);
+ }
+ if(column_count > 13) {
+ (*st)->has_ignored_files = sqlite3_column_int(stmt, 13);
+ }
+ if (column_count > 14 && sqlite3_column_text(stmt, 14)) {
+ (*st)->checksumHeader = c_strdup((char *)sqlite3_column_text(stmt, 14));
+ }
+
+ }
+ } else {
+ if( rc != SQLITE_DONE ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Query results in %d", rc);
+ }
+ }
+ return rc;
+}
+
+/* caller must free the memory */
+csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
+ uint64_t phash)
+{
+ csync_file_stat_t *st = NULL;
+ int rc;
+
+ if( !ctx || ctx->db_is_empty ) {
+ return NULL;
+ }
+
+ if( ctx->statedb.by_hash_stmt == NULL ) {
+ const char *hash_query = "SELECT " METADATA_QUERY " WHERE phash=?1";
+
+ SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL));
+ ctx->statedb.lastReturnValue = rc;
+ if( rc != SQLITE_OK ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query.");
+ return NULL;
+ }
+ }
+
+ if( ctx->statedb.by_hash_stmt == NULL ) {
+ return NULL;
+ }
+
+ sqlite3_bind_int64(ctx->statedb.by_hash_stmt, 1, (long long signed int)phash);
+
+ rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_hash_stmt);
+ ctx->statedb.lastReturnValue = rc;
+ if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
+ }
+ sqlite3_reset(ctx->statedb.by_hash_stmt);
+
+ return st;
+}
+
+csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
+ const char *file_id ) {
+ csync_file_stat_t *st = NULL;
+ int rc = 0;
+
+ if (!file_id) {
+ return 0;
+ }
+ if (c_streq(file_id, "")) {
+ return 0;
+ }
+
+ if( !ctx || ctx->db_is_empty ) {
+ return NULL;
+ }
+
+ if( ctx->statedb.by_fileid_stmt == NULL ) {
+ const char *query = "SELECT " METADATA_QUERY " WHERE fileid=?1";
+
+ SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL));
+ ctx->statedb.lastReturnValue = rc;
+ if( rc != SQLITE_OK ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query.");
+ return NULL;
+ }
+ }
+
+ /* bind the query value */
+ sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC);
+
+ rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt);
+ ctx->statedb.lastReturnValue = rc;
+ if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata: %d!", rc);
+ }
+ // clear the resources used by the statement.
+ sqlite3_reset(ctx->statedb.by_fileid_stmt);
+
+ return st;
+}
+
+/* caller must free the memory */
+csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
+ uint64_t inode)
+{
+ csync_file_stat_t *st = NULL;
+ int rc;
+
+ if (!inode) {
+ return NULL;
+ }
+
+ if( !ctx || ctx->db_is_empty ) {
+ return NULL;
+ }
+
+ if( ctx->statedb.by_inode_stmt == NULL ) {
+ const char *inode_query = "SELECT " METADATA_QUERY " WHERE inode=?1";
+
+ SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL));
+ ctx->statedb.lastReturnValue = rc;
+ if( rc != SQLITE_OK ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for inode query.");
+ return NULL;
+ }
+ }
+
+ if( ctx->statedb.by_inode_stmt == NULL ) {
+ return NULL;
+ }
+
+ sqlite3_bind_int64(ctx->statedb.by_inode_stmt, 1, (long long signed int)inode);
+
+ rc = _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_inode_stmt);
+ ctx->statedb.lastReturnValue = rc;
+ if( !(rc == SQLITE_ROW || rc == SQLITE_DONE) ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata by inode: %d!", rc);
+ }
+ sqlite3_reset(ctx->statedb.by_inode_stmt);
+
+ return st;
+}
+
+int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
+ int rc;
+ sqlite3_stmt *stmt = NULL;
+ int64_t cnt = 0;
+
+ if( !path ) {
+ return -1;
+ }
+
+ if( !ctx || ctx->db_is_empty ) {
+ return -1;
+ }
+
+ /* Select the entries for anything that starts with (path+'/')
+ * In other words, anything that is between path+'/' and path+'0',
+ * (because '0' follows '/' in ascii)
+ */
+ const char *below_path_query = "SELECT " METADATA_QUERY " WHERE path > (?||'/') AND path < (?||'0') ORDER BY path||'/' ASC";
+ SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL));
+ ctx->statedb.lastReturnValue = rc;
+ if( rc != SQLITE_OK ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query.");
+ return -1;
+ }
+
+ if (stmt == NULL) {
+ return -1;
+ }
+
+ sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC);
+ sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC);
+
+ cnt = 0;
+
+ ctx->statedb.lastReturnValue = rc;
+ do {
+ csync_file_stat_t *st = NULL;
+
+ rc = _csync_file_stat_from_metadata_table( &st, stmt);
+ if( st ) {
+ /* When selective sync is used, the database may have subtrees with a parent
+ * whose etag (md5) is _invalid_. These are ignored and shall not appear in the
+ * remote tree.
+ * Sometimes folders that are not ignored by selective sync get marked as
+ * _invalid_, but that is not a problem as the next discovery will retrieve
+ * their correct etags again and we don't run into this case.
+ */
+ if( c_streq(st->etag, "_invalid_") ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded", st->path);
+ char *skipbase = c_strdup(st->path);
+ skipbase[st->pathlen] = '/';
+ int skiplen = st->pathlen + 1;
+
+ /* Skip over all entries with the same base path. Note that this depends
+ * strongly on the ordering of the retrieved items. */
+ do {
+ csync_file_stat_free(st);
+ rc = _csync_file_stat_from_metadata_table( &st, stmt);
+ if( st && strncmp(st->path, skipbase, skiplen) != 0 ) {
+ break;
+ }
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s selective sync excluded because the parent is", st->path);
+ } while( rc == SQLITE_ROW );
+
+ /* End of data? */
+ if( rc != SQLITE_ROW || !st ) {
+ continue;
+ }
+ }
+
+ /* Check for exclusion from the tree.
+ * Note that this is only a safety net in case the ignore list changes
+ * without a full remote discovery being triggered. */
+ CSYNC_EXCLUDE_TYPE excluded = csync_excluded_traversal(ctx->excludes, st->path, st->type);
+ if (excluded != CSYNC_NOT_EXCLUDED) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", st->path, excluded);
+
+ if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
+ || excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
+ csync_file_stat_free(st);
+ continue;
+ }
+
+ st->instruction = CSYNC_INSTRUCTION_IGNORE;
+ }
+
+ /* store into result list. */
+ if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
+ csync_file_stat_free(st);
+ ctx->status_code = CSYNC_STATUS_TREE_ERROR;
+ break;
+ }
+ cnt++;
+ }
+ } while( rc == SQLITE_ROW );
+
+ ctx->statedb.lastReturnValue = rc;
+ if( rc != SQLITE_DONE ) {
+ ctx->status_code = CSYNC_STATUS_TREE_ERROR;
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
+ }
+ sqlite3_finalize(stmt);
+
+ return 0;
+}
+
+/* query the statedb, caller must free the memory */
+c_strlist_t *csync_statedb_query(sqlite3 *db,
+ const char *statement) {
+ int err = SQLITE_OK;
+ int rc = SQLITE_OK;
+ size_t i = 0;
+ size_t busy_count = 0;
+ size_t retry_count = 0;
+ size_t column_count = 0;
+ sqlite3_stmt *stmt;
+ const char *tail = NULL;
+ const char *field = NULL;
+ c_strlist_t *result = NULL;
+ int row = 0;
+
+ do {
+ /* compile SQL program into a virtual machine, reattempteing if busy */
+ do {
+ if (busy_count) {
+ csync_sleep(100);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count);
+ }
+ err = sqlite3_prepare(db, statement, -1, &stmt, &tail);
+ } while (err == SQLITE_BUSY && busy_count ++ < 120);
+
+ if (err != SQLITE_OK) {
+ if (err == SQLITE_BUSY) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear");
+ }
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
+ "sqlite3_compile error: %s - on query %s",
+ sqlite3_errmsg(db), statement);
+ break;
+ } else {
+ busy_count = 0;
+ column_count = sqlite3_column_count(stmt);
+
+ /* execute virtual machine by iterating over rows */
+ for(;;) {
+ err = sqlite3_step(stmt);
+
+ if (err == SQLITE_BUSY) {
+ if (busy_count++ > 120) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
+ break;
+ }
+ csync_sleep(100);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count);
+ continue;
+ }
+
+ if (err == SQLITE_MISUSE) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!");
+ }
+
+ if (err == SQLITE_DONE) {
+ if (result == NULL) {
+ result = c_strlist_new(1);
+ }
+ break;
+ }
+
+ if (err == SQLITE_ERROR) {
+ break;
+ }
+
+ row++;
+ if( result ) {
+ result = c_strlist_expand(result, row*column_count);
+ } else {
+ result = c_strlist_new(column_count);
+ }
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ /* iterate over columns */
+ for (i = 0; i < column_count; i++) {
+ field = (const char *) sqlite3_column_text(stmt, i);
+ if (!field)
+ field = "";
+ // CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", field);
+ if (c_strlist_add(result, field) < 0) {
+ c_strlist_destroy(result);
+ return NULL;
+ }
+ }
+ } /* end infinite for loop */
+
+ /* deallocate vm resources */
+ rc = sqlite3_finalize(stmt);
+
+ if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(db), statement);
+ if (result != NULL) {
+ c_strlist_destroy(result);
+ }
+ return NULL;
+ }
+
+ if (rc == SQLITE_SCHEMA) {
+ retry_count ++;
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement);
+ if (retry_count < 10) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now.");
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement);
+ if (result != NULL) {
+ c_strlist_destroy(result);
+ }
+ result = c_strlist_new(1);
+ }
+ }
+ }
+ } while (rc == SQLITE_SCHEMA && retry_count < 10);
+
+ return result;
+}
+
+/* vim: set ts=8 sw=2 et cindent: */
#ifndef _CSYNC_STATEDB_H
#define _CSYNC_STATEDB_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "c_lib.h"
#include "csync_private.h"
*/
c_strlist_t *csync_statedb_query(sqlite3 *db, const char *statement);
-#ifdef __cplusplus
-}
-#endif
-
/**
* }@
*/
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
+#else
+#include <windows.h>
#endif
#define CSYNC_LOG_CATEGORY_NAME "csync.time"
#ifndef _CSYNC_TIME_H
#define _CSYNC_TIME_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <time.h>
#include "csync_private.h"
int csync_gettime(struct timespec *tp);
void csync_sleep(unsigned int msecs);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _CSYNC_TIME_H */
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 "config_csync.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <time.h>
-#include <math.h>
-
-#include "c_lib.h"
-#include "c_jhash.h"
-
-#include "csync_private.h"
-#include "csync_exclude.h"
-#include "csync_statedb.h"
-#include "csync_update.h"
-#include "csync_util.h"
-#include "csync_misc.h"
-
-#include "vio/csync_vio.h"
-
-#define CSYNC_LOG_CATEGORY_NAME "csync.updater"
-#include "csync_log.h"
-#include "csync_rename.h"
-
-/* calculate the hash of a given uri */
-static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
- const char *path;
- int len;
- uint64_t h = 0;
-
- if( ctx && file ) {
- path = file;
- if (ctx->current == LOCAL_REPLICA) {
- if (strlen(path) <= strlen(ctx->local.uri)) {
- return 0;
- }
- path += strlen(ctx->local.uri) + 1;
- }
- len = strlen(path);
- h = c_jhash64((uint8_t *) path, len, 0);
- }
- return h;
-}
-
-#ifdef NO_RENAME_EXTENSION
-/* Return true if the two path have the same extension. false otherwise. */
-static bool _csync_sameextension(const char *p1, const char *p2) {
- /* Find pointer to the extensions */
- const char *e1 = strrchr(p1, '.');
- const char *e2 = strrchr(p2, '.');
-
- /* If the found extension contains a '/', it is because the . was in the folder name
- * => no extensions */
- if (e1 && strchr(e1, '/')) e1 = NULL;
- if (e2 && strchr(e2, '/')) e2 = NULL;
-
- /* If none have extension, it is the same extension */
- if (!e1 && !e2)
- return true;
-
- /* c_streq takes care of the rest */
- return c_streq(e1, e2);
-}
-#endif
-
-static bool _last_db_return_error(CSYNC* ctx) {
- return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW;
-}
-
-/*
- * This static method is needed because the type members of the two structs use
- * different enum values. A direct comparion is not neccessarily correct.
- *
- * tmp is csync_file_stat_t
- * fs is csync_vio_file_stat_t with this vio type:
- * enum csync_vio_file_type_e {
- * CSYNC_VIO_FILE_TYPE_UNKNOWN,
- * CSYNC_VIO_FILE_TYPE_REGULAR,
- * CSYNC_VIO_FILE_TYPE_DIRECTORY,
- * CSYNC_VIO_FILE_TYPE_FIFO,
- * CSYNC_VIO_FILE_TYPE_SOCKET,
- * CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE,
- * CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE,
- * CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK
- * };
- *
- * csync_file_stat_t can be:
- * CSYNC_FTW_TYPE_SKIP, CSYNC_FTW_TYPE_FILE
- * CSYNC_FTW_TYPE_DIR, CSYNC_FTW_TYPE_SLINK
- */
-static bool _csync_filetype_different( const csync_file_stat_t *tmp, const csync_vio_file_stat_t *fs)
-{
- if( !(tmp && fs)) return false;
-
- if( tmp->type == CSYNC_FTW_TYPE_SKIP ) return true;
-
- if( tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY )
- return true;
- if( tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR )
- return true;
- if( tmp->type == CSYNC_FTW_TYPE_SLINK && fs->type != CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK )
- return true;
-
- return false; // both are NOT different.
-}
-
-/* Return true if two mtime are considered equal
- * We consider mtime that are one hour difference to be equal if they are one hour appart
- * because on some system (FAT) the date is changing when the daylight saving is changing */
-static bool _csync_mtime_equal(time_t a, time_t b)
-{
- if (a == b)
- return true;
-
- /* 1h of difference +- 1 second because the accuracy of FAT is 2 seconds (#2438) */
- if (fabs(3600 - fabs(difftime(a, b))) < 2)
- return true;
-
- return false;
-}
-
-/**
- * The main function of the discovery/update pass.
- *
- * It's called (indirectly) by csync_update(), once for each entity in the
- * local filesystem and once for each entity in the server data.
- *
- * It has two main jobs:
- * - figure out whether anything happened compared to the sync journal
- * and set (primarily) the instruction flag accordingly
- * - build the ctx->local.tree / ctx->remote.tree
- *
- * See doc/dev/sync-algorithm.md for an overview.
- */
-static int _csync_detect_update(CSYNC *ctx, const char *file,
- const csync_vio_file_stat_t *fs, const int type) {
- uint64_t h = 0;
- size_t len = 0;
- size_t size = 0;
- const char *path = NULL;
- csync_file_stat_t *st = NULL;
- csync_file_stat_t *tmp = NULL;
- CSYNC_EXCLUDE_TYPE excluded;
-
- if ((file == NULL) || (fs == NULL)) {
- errno = EINVAL;
- ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
- return -1;
- }
-
- path = file;
- if (ctx->current == LOCAL_REPLICA) {
- if (strlen(path) <= strlen(ctx->local.uri)) {
- ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
- return -1;
- }
- path += strlen(ctx->local.uri) + 1;
- }
-
- len = strlen(path);
-
- if (type == CSYNC_FTW_TYPE_SKIP) {
- excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
- } else {
- /* Check if file is excluded */
- excluded = csync_excluded_traversal(ctx->excludes, path, type);
- }
-
- if( excluded == CSYNC_NOT_EXCLUDED ) {
- /* Even if it is not excluded by a pattern, maybe it is to be ignored
- * because it's a hidden file that should not be synced.
- * This code should probably be in csync_exclude, but it does not have the fs parameter.
- * Keep it here for now */
- if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
- excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
- }
- } else {
- /* File is ignored because it's matched by a user- or system exclude pattern. */
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded);
- if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
- return 1;
- }
- if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
- return 1;
- }
- }
-
- if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
- if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) {
- return 1;
- }
- }
-
- h = _hash_of_file(ctx, file );
- if( h == 0 ) {
- return -1;
- }
- size = sizeof(csync_file_stat_t) + len + 1;
-
- st = c_malloc(size);
-
- /* Set instruction by default to none */
- st->instruction = CSYNC_INSTRUCTION_NONE;
- st->etag = NULL;
- st->child_modified = 0;
- st->has_ignored_files = 0;
- if (type == CSYNC_FTW_TYPE_FILE ) {
- if (fs->mtime == 0) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
- }
- }
-
- if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
- st->instruction = CSYNC_INSTRUCTION_IGNORE;
- if (ctx->current_fs) {
- ctx->current_fs->has_ignored_files = true;
- }
-
- goto out;
- }
-
- /* Update detection: Check if a database entry exists.
- * If not, the file is either new or has been renamed. To see if it is
- * renamed, the db gets queried by the inode of the file as that one
- * does not change on rename.
- */
- if (csync_get_statedb_exists(ctx)) {
- tmp = csync_statedb_get_stat_by_hash(ctx, h);
-
- if(_last_db_return_error(ctx)) {
- csync_file_stat_free(st);
- csync_file_stat_free(tmp);
- ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
- return -1;
- }
-
- if(tmp && tmp->phash == h ) { /* there is an entry in the database */
- /* we have an update! */
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Database entry found, compare: %" PRId64 " <-> %" PRId64
- ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
- ", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d",
- ((int64_t) fs->mtime), ((int64_t) tmp->modtime),
- fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
- (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
- if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
- st->instruction = CSYNC_INSTRUCTION_EVAL;
-
- // Preserve the EVAL flag later on if the type has changed.
- if (_csync_filetype_different(tmp, fs)) {
- st->child_modified = 1;
- }
-
- goto out;
- }
- if (ctx->current == LOCAL_REPLICA &&
- (!_csync_mtime_equal(fs->mtime, tmp->modtime)
- // zero size in statedb can happen during migration
- || (tmp->size != 0 && fs->size != tmp->size))) {
-
- // Checksum comparison at this stage is only enabled for .eml files,
- // check #4754 #4755
- bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
- if (isEmlFile && fs->size == tmp->size && tmp->checksumHeader) {
- if (ctx->callbacks.checksum_hook) {
- st->checksumHeader = ctx->callbacks.checksum_hook(
- file, tmp->checksumHeader,
- ctx->callbacks.checksum_userdata);
- }
- bool checksumIdentical = false;
- if (st->checksumHeader) {
- checksumIdentical = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0;
- }
- if (checksumIdentical) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
- st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
- goto out;
- }
- }
-
- // Preserve the EVAL flag later on if the type has changed.
- if (_csync_filetype_different(tmp, fs)) {
- st->child_modified = 1;
- }
-
- st->instruction = CSYNC_INSTRUCTION_EVAL;
- goto out;
- }
- bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
- || !c_streq(fs->remotePerm, tmp->remotePerm)))
- || (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
- if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
- && !metadata_differ && ctx->read_remote_from_db) {
- /* If both etag and file id are equal for a directory, read all contents from
- * the database.
- * The metadata comparison ensure that we fetch all the file id or permission when
- * upgrading owncloud
- */
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
- ctx->remote.read_from_db = true;
- }
- /* If it was remembered in the db that the remote dir has ignored files, store
- * that so that the reconciler can make advantage of.
- */
- if( ctx->current == REMOTE_REPLICA ) {
- st->has_ignored_files = tmp->has_ignored_files;
- }
- if (metadata_differ) {
- /* file id or permissions has changed. Which means we need to update them in the DB. */
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
- st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
- } else {
- st->instruction = CSYNC_INSTRUCTION_NONE;
- }
- } else {
- enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
-
- /* tmp might point to malloc mem, so free it here before reusing tmp */
- csync_file_stat_free(tmp);
-
- /* check if it's a file and has been renamed */
- if (ctx->current == LOCAL_REPLICA) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
-
- tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
-
- if(_last_db_return_error(ctx)) {
- csync_file_stat_free(st);
- ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
- return -1;
- }
-
- /* translate the file type between the two stat types csync has. */
- if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) {
- tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
- } else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) {
- tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
- } else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) {
- tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
- } else {
- tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
- }
-
- // Default to NEW unless we're sure it's a rename.
- st->instruction = CSYNC_INSTRUCTION_NEW;
-
- bool isRename =
- tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
- && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
-#ifdef NO_RENAME_EXTENSION
- && _csync_sameextension(tmp->path, path)
-#endif
- ;
-
-
- // Verify the checksum where possible
- if (isRename && tmp->checksumHeader && ctx->callbacks.checksum_hook
- && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) {
- st->checksumHeader = ctx->callbacks.checksum_hook(
- file, tmp->checksumHeader,
- ctx->callbacks.checksum_userdata);
- if (st->checksumHeader) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader, tmp->checksumHeader);
- isRename = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0;
- }
- }
-
- if (isRename) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
- /* inode found so the file has been renamed */
- st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
- if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
- csync_rename_record(ctx, tmp->path, path);
- }
- }
- goto out;
-
- } else {
- /* Remote Replica Rename check */
- tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
-
- if(_last_db_return_error(ctx)) {
- csync_file_stat_free(st);
- ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
- return -1;
- }
- if(tmp ) { /* tmp existing at all */
- if ( _csync_filetype_different(tmp, fs)) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "file types different is not!");
- st->instruction = CSYNC_INSTRUCTION_NEW;
- goto out;
- }
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file);
- st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
- if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
- csync_rename_record(ctx, tmp->path, path);
- } else {
- if( !c_streq(tmp->etag, fs->etag) ) {
- /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */
- /* File with different etag, don't do a rename, but download the file again */
- st->instruction = CSYNC_INSTRUCTION_NEW;
- }
- }
- goto out;
-
- } else {
- /* file not found in statedb */
- st->instruction = CSYNC_INSTRUCTION_NEW;
-
- if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
- if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
- csync_file_stat_free(st);
- return 1;
- }
- }
- goto out;
- }
- }
- }
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Unable to open statedb" );
- csync_file_stat_free(st);
- ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
- return -1;
- }
-
-out:
-
- /* Set the ignored error string. */
- if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
- if( type == CSYNC_FTW_TYPE_SLINK ) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
- } else {
- if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
- } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */
- } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */
- } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
- } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
- } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
- } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) {
- st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE;
- }
- }
- }
- if (st->instruction != CSYNC_INSTRUCTION_NONE
- && st->instruction != CSYNC_INSTRUCTION_IGNORE
- && st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
- && type != CSYNC_FTW_TYPE_DIR) {
- st->child_modified = 1;
- }
- ctx->current_fs = st;
-
- csync_file_stat_free(tmp);
- st->inode = fs->inode;
- st->mode = fs->mode;
- st->size = fs->size;
- st->modtime = fs->mtime;
- st->type = type;
- st->etag = NULL;
- if( fs->etag ) {
- SAFE_FREE(st->etag);
- st->etag = c_strdup(fs->etag);
- }
- csync_vio_set_file_id(st->file_id, fs->file_id);
- if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
- SAFE_FREE(st->directDownloadUrl);
- st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
- }
- if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
- SAFE_FREE(st->directDownloadCookies);
- st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
- }
- if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
- strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
- }
-
- // For the remote: propagate the discovered checksum
- if (fs->checksumHeader && ctx->current == REMOTE_REPLICA) {
- st->checksumHeader = c_strdup(fs->checksumHeader);
- }
-
- st->phash = h;
- st->pathlen = len;
- memcpy(st->path, (len ? path : ""), len + 1);
-
- switch (ctx->current) {
- case LOCAL_REPLICA:
- if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
- csync_file_stat_free(st);
- ctx->status_code = CSYNC_STATUS_TREE_ERROR;
- return -1;
- }
- break;
- case REMOTE_REPLICA:
- if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
- csync_file_stat_free(st);
- ctx->status_code = CSYNC_STATUS_TREE_ERROR;
- return -1;
- }
- break;
- default:
- break;
- }
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", st->path,
- csync_instruction_str(st->instruction));
-
- return 0;
-}
-
-int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
- enum csync_ftw_flags_e flag) {
- int rc = -1;
- int type = CSYNC_FTW_TYPE_SKIP;
- csync_file_stat_t *st = NULL;
- uint64_t h;
-
- if (ctx->abort) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
- ctx->status_code = CSYNC_STATUS_ABORTED;
- return -1;
- }
-
- switch (flag) {
- case CSYNC_FTW_FLAG_FILE:
- if (ctx->current == REMOTE_REPLICA) {
- if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size);
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=UNKNOWN]", file, fs->file_id);
- }
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size);
- }
- type = CSYNC_FTW_TYPE_FILE;
- break;
- case CSYNC_FTW_FLAG_DIR: /* enter directory */
- if (ctx->current == REMOTE_REPLICA) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id);
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode);
- }
- type = CSYNC_FTW_TYPE_DIR;
- break;
- case CSYNC_FTW_FLAG_NSTAT: /* not statable file */
- /* if file was here before and now is not longer stat-able, still
- * add it to the db, otherwise not. */
- h = _hash_of_file( ctx, file );
- if( h == 0 ) {
- return 0;
- }
- st = csync_statedb_get_stat_by_hash(ctx, h);
- if( !st ) {
- return 0;
- }
- csync_file_stat_free(st);
- st = NULL;
-
- type = CSYNC_FTW_TYPE_SKIP;
- break;
- case CSYNC_FTW_FLAG_SLINK:
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file);
- type = CSYNC_FTW_TYPE_SLINK;
- break;
- case CSYNC_FTW_FLAG_DNR:
- case CSYNC_FTW_FLAG_DP:
- case CSYNC_FTW_FLAG_SLN:
- default:
- return 0;
- break;
- }
-
- rc = _csync_detect_update(ctx, file, fs, type );
-
- return rc;
-}
-
-static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
-{
- if( csync_statedb_get_below_path(ctx, uri) < 0 ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!");
- return false;
- }
-
- return true;
-}
-
-/* set the current item to an ignored state.
- * If the item is set to ignored, the update phase continues, ie. its not a hard error */
-static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status )
-{
- if(!ctx) {
- return false;
- }
-
- if (ctx->current_fs) {
- ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
- ctx->current_fs->error_status = status;
- /* If a directory has ignored files, put the flag on the parent directory as well */
- if( previous_fs ) {
- previous_fs->has_ignored_files = true;
- }
- return true;
- }
- return false;
-}
-
-/* File tree walker */
-int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
- unsigned int depth) {
- char *filename = NULL;
- char *d_name = NULL;
- csync_vio_handle_t *dh = NULL;
- csync_vio_file_stat_t *dirent = NULL;
- csync_file_stat_t *previous_fs = NULL;
- int read_from_db = 0;
- int rc = 0;
- int res = 0;
-
- if (!depth) {
- mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_INDIVIDUAL_TOO_DEEP);
- goto done;
- }
-
- bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
-
- read_from_db = ctx->remote.read_from_db;
-
- // if the etag of this dir is still the same, its content is restored from the
- // database.
- if( do_read_from_db ) {
- if( ! fill_tree_from_db(ctx, uri) ) {
- errno = ENOENT;
- ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR;
- goto error;
- }
- goto done;
- }
-
- if ((dh = csync_vio_opendir(ctx, uri)) == NULL) {
- if (ctx->abort) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
- ctx->status_code = CSYNC_STATUS_ABORTED;
- goto error;
- }
- int asp = 0;
- /* permission denied */
- ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
- if (errno == EACCES) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied.");
- if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) {
- goto done;
- }
- } else if(errno == ENOENT) {
- asp = asprintf( &ctx->error_string, "%s", uri);
- if (asp < 0) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
- }
- }
- // 403 Forbidden can be sent by the server if the file firewall is active.
- // A file or directory should be ignored and sync must continue. See #3490
- else if(errno == ERRNO_FORBIDDEN) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)");
- if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) {
- goto done;
- }
- /* if current_fs is not defined here, better throw an error */
- }
- // The server usually replies with the custom "503 Storage not available"
- // if some path is temporarily unavailable. But in some cases a standard 503
- // is returned too. Thus we can't distinguish the two and will treat any
- // 503 as request to ignore the folder. See #3113 #2884.
- else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
- if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) {
- goto done;
- }
- /* if current_fs is not defined here, better throw an error */
- } else {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
- }
- goto error;
- }
-
- while ((dirent = csync_vio_readdir(ctx, dh))) {
- int flen;
- int flag;
-
- /* Conversion error */
- if (dirent->name == NULL && dirent->original_name) {
- ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
- ctx->error_string = dirent->original_name; // take ownership
- dirent->original_name = NULL;
- goto error;
- }
-
- d_name = dirent->name;
- if (d_name == NULL) {
- ctx->status_code = CSYNC_STATUS_READDIR_ERROR;
- goto error;
- }
-
- /* skip "." and ".." */
- if ( (d_name[0] == '.' && d_name[1] == '\0')
- || (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) {
- csync_vio_file_stat_destroy(dirent);
- dirent = NULL;
- continue;
- }
-
- if (uri[0] == '\0') {
- filename = c_strdup(d_name);
- flen = strlen(d_name);
- } else {
- flen = asprintf(&filename, "%s/%s", uri, d_name);
- }
- if (flen < 0 || !filename) {
- csync_vio_file_stat_destroy(dirent);
- dirent = NULL;
- ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
- goto error;
- }
-
- /* Only for the local replica we have to stat(), for the remote one we have all data already */
- if (ctx->replica == LOCAL_REPLICA) {
- res = csync_vio_stat(ctx, filename, dirent);
- } else {
- res = 0;
- }
-
- /* if the filename starts with a . we consider it a hidden file
- * For windows, the hidden state is also discovered within the vio
- * local stat function.
- */
- if( d_name[0] == '.' ) {
- if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */
- dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
- }
- }
-
- if( res == 0) {
- switch (dirent->type) {
- case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
- flag = CSYNC_FTW_FLAG_SLINK;
- break;
- case CSYNC_VIO_FILE_TYPE_DIRECTORY:
- flag = CSYNC_FTW_FLAG_DIR;
- break;
- case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE:
- case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE:
- case CSYNC_VIO_FILE_TYPE_SOCKET:
- flag = CSYNC_FTW_FLAG_SPEC;
- break;
- case CSYNC_VIO_FILE_TYPE_FIFO:
- flag = CSYNC_FTW_FLAG_SPEC;
- break;
- default:
- flag = CSYNC_FTW_FLAG_FILE;
- break;
- };
- } else {
- flag = CSYNC_FTW_FLAG_NSTAT;
- }
-
- previous_fs = ctx->current_fs;
-
- /* Call walker function for each file */
- rc = fn(ctx, filename, dirent, flag);
- /* this function may update ctx->current and ctx->read_from_db */
-
- if (rc < 0) {
- if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
- ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
- }
-
- ctx->current_fs = previous_fs;
- goto error;
- }
-
- if (flag == CSYNC_FTW_FLAG_DIR && rc == 0
- && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) {
- rc = csync_ftw(ctx, filename, fn, depth - 1);
- if (rc < 0) {
- ctx->current_fs = previous_fs;
- goto error;
- }
-
- if (ctx->current_fs && !ctx->current_fs->child_modified
- && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
- if (ctx->current == REMOTE_REPLICA) {
- ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
- } else {
- ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
- }
- }
-
- if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) {
- /* If a directory has ignored files, put the flag on the parent directory as well */
- previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files;
- }
- }
-
- if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) {
- /* If a directory has modified files, put the flag on the parent directory as well */
- previous_fs->child_modified = ctx->current_fs->child_modified;
- }
-
- ctx->current_fs = previous_fs;
- ctx->remote.read_from_db = read_from_db;
- SAFE_FREE(filename);
- csync_vio_file_stat_destroy(dirent);
- dirent = NULL;
- }
-
- csync_vio_closedir(ctx, dh);
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db);
-
-done:
- csync_vio_file_stat_destroy(dirent);
- SAFE_FREE(filename);
- return rc;
-error:
- ctx->remote.read_from_db = read_from_db;
- if (dh != NULL) {
- csync_vio_closedir(ctx, dh);
- }
- SAFE_FREE(filename);
- return -1;
-}
-
-/* vim: set ts=8 sw=2 et cindent: */
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 "config_csync.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+
+#include "c_lib.h"
+#include "c_jhash.h"
+
+#include "csync_private.h"
+#include "csync_exclude.h"
+#include "csync_statedb.h"
+#include "csync_update.h"
+#include "csync_util.h"
+#include "csync_misc.h"
+
+#include "vio/csync_vio.h"
+
+#define CSYNC_LOG_CATEGORY_NAME "csync.updater"
+#include "csync_log.h"
+#include "csync_rename.h"
+
+// Needed for PRIu64 on MinGW in C++ mode.
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+/* calculate the hash of a given uri */
+static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
+ const char *path;
+ int len;
+ uint64_t h = 0;
+
+ if( ctx && file ) {
+ path = file;
+ if (ctx->current == LOCAL_REPLICA) {
+ if (strlen(path) <= strlen(ctx->local.uri)) {
+ return 0;
+ }
+ path += strlen(ctx->local.uri) + 1;
+ }
+ len = strlen(path);
+ h = c_jhash64((uint8_t *) path, len, 0);
+ }
+ return h;
+}
+
+#ifdef NO_RENAME_EXTENSION
+/* Return true if the two path have the same extension. false otherwise. */
+static bool _csync_sameextension(const char *p1, const char *p2) {
+ /* Find pointer to the extensions */
+ const char *e1 = strrchr(p1, '.');
+ const char *e2 = strrchr(p2, '.');
+
+ /* If the found extension contains a '/', it is because the . was in the folder name
+ * => no extensions */
+ if (e1 && strchr(e1, '/')) e1 = NULL;
+ if (e2 && strchr(e2, '/')) e2 = NULL;
+
+ /* If none have extension, it is the same extension */
+ if (!e1 && !e2)
+ return true;
+
+ /* c_streq takes care of the rest */
+ return c_streq(e1, e2);
+}
+#endif
+
+static bool _last_db_return_error(CSYNC* ctx) {
+ return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW;
+}
+
+/*
+ * This static method is needed because the type members of the two structs use
+ * different enum values. A direct comparion is not neccessarily correct.
+ *
+ * tmp is csync_file_stat_t
+ * fs is csync_vio_file_stat_t with this vio type:
+ * enum csync_vio_file_type_e {
+ * CSYNC_VIO_FILE_TYPE_UNKNOWN,
+ * CSYNC_VIO_FILE_TYPE_REGULAR,
+ * CSYNC_VIO_FILE_TYPE_DIRECTORY,
+ * CSYNC_VIO_FILE_TYPE_FIFO,
+ * CSYNC_VIO_FILE_TYPE_SOCKET,
+ * CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE,
+ * CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE,
+ * CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK
+ * };
+ *
+ * csync_file_stat_t can be:
+ * CSYNC_FTW_TYPE_SKIP, CSYNC_FTW_TYPE_FILE
+ * CSYNC_FTW_TYPE_DIR, CSYNC_FTW_TYPE_SLINK
+ */
+static bool _csync_filetype_different( const csync_file_stat_t *tmp, const csync_vio_file_stat_t *fs)
+{
+ if( !(tmp && fs)) return false;
+
+ if( tmp->type == CSYNC_FTW_TYPE_SKIP ) return true;
+
+ if( tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY )
+ return true;
+ if( tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR )
+ return true;
+ if( tmp->type == CSYNC_FTW_TYPE_SLINK && fs->type != CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK )
+ return true;
+
+ return false; // both are NOT different.
+}
+
+/* Return true if two mtime are considered equal
+ * We consider mtime that are one hour difference to be equal if they are one hour appart
+ * because on some system (FAT) the date is changing when the daylight saving is changing */
+static bool _csync_mtime_equal(time_t a, time_t b)
+{
+ if (a == b)
+ return true;
+
+ /* 1h of difference +- 1 second because the accuracy of FAT is 2 seconds (#2438) */
+ if (fabs(3600 - fabs(difftime(a, b))) < 2)
+ return true;
+
+ return false;
+}
+
+/**
+ * The main function of the discovery/update pass.
+ *
+ * It's called (indirectly) by csync_update(), once for each entity in the
+ * local filesystem and once for each entity in the server data.
+ *
+ * It has two main jobs:
+ * - figure out whether anything happened compared to the sync journal
+ * and set (primarily) the instruction flag accordingly
+ * - build the ctx->local.tree / ctx->remote.tree
+ *
+ * See doc/dev/sync-algorithm.md for an overview.
+ */
+static int _csync_detect_update(CSYNC *ctx, const char *file,
+ const csync_vio_file_stat_t *fs, enum csync_ftw_type_e type) {
+ uint64_t h = 0;
+ size_t len = 0;
+ size_t size = 0;
+ const char *path = NULL;
+ csync_file_stat_t *st = NULL;
+ csync_file_stat_t *tmp = NULL;
+ CSYNC_EXCLUDE_TYPE excluded;
+
+ if ((file == NULL) || (fs == NULL)) {
+ errno = EINVAL;
+ ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
+ return -1;
+ }
+
+ path = file;
+ if (ctx->current == LOCAL_REPLICA) {
+ if (strlen(path) <= strlen(ctx->local.uri)) {
+ ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
+ return -1;
+ }
+ path += strlen(ctx->local.uri) + 1;
+ }
+
+ len = strlen(path);
+
+ if (type == CSYNC_FTW_TYPE_SKIP) {
+ excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
+ } else {
+ /* Check if file is excluded */
+ excluded = csync_excluded_traversal(ctx->excludes, path, type);
+ }
+
+ if( excluded == CSYNC_NOT_EXCLUDED ) {
+ /* Even if it is not excluded by a pattern, maybe it is to be ignored
+ * because it's a hidden file that should not be synced.
+ * This code should probably be in csync_exclude, but it does not have the fs parameter.
+ * Keep it here for now */
+ if (ctx->ignore_hidden_files && (fs->flags & CSYNC_VIO_FILE_FLAGS_HIDDEN)) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file excluded because it is a hidden file: %s", path);
+ excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
+ }
+ } else {
+ /* File is ignored because it's matched by a user- or system exclude pattern. */
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded);
+ if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
+ return 1;
+ }
+ if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
+ return 1;
+ }
+ }
+
+ if (ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncBlackListHook) {
+ if (ctx->callbacks.checkSelectiveSyncBlackListHook(ctx->callbacks.update_callback_userdata, path)) {
+ return 1;
+ }
+ }
+
+ h = _hash_of_file(ctx, file );
+ if( h == 0 ) {
+ return -1;
+ }
+ size = sizeof(csync_file_stat_t) + len + 1;
+
+ st = static_cast<csync_file_stat_t *>(c_malloc(size));
+
+ /* Set instruction by default to none */
+ st->instruction = CSYNC_INSTRUCTION_NONE;
+ st->etag = NULL;
+ st->child_modified = 0;
+ st->has_ignored_files = 0;
+ if (type == CSYNC_FTW_TYPE_FILE ) {
+ if (fs->mtime == 0) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
+ }
+ }
+
+ if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
+ st->instruction = CSYNC_INSTRUCTION_IGNORE;
+ if (ctx->current_fs) {
+ ctx->current_fs->has_ignored_files = true;
+ }
+
+ goto out;
+ }
+
+ /* Update detection: Check if a database entry exists.
+ * If not, the file is either new or has been renamed. To see if it is
+ * renamed, the db gets queried by the inode of the file as that one
+ * does not change on rename.
+ */
+ if (csync_get_statedb_exists(ctx)) {
+ tmp = csync_statedb_get_stat_by_hash(ctx, h);
+
+ if(_last_db_return_error(ctx)) {
+ csync_file_stat_free(st);
+ csync_file_stat_free(tmp);
+ ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
+ return -1;
+ }
+
+ if(tmp && tmp->phash == h ) { /* there is an entry in the database */
+ /* we have an update! */
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Database entry found, compare: %" PRId64 " <-> %" PRId64
+ ", etag: %s <-> %s, inode: %" PRId64 " <-> %" PRId64
+ ", size: %" PRId64 " <-> %" PRId64 ", perms: %s <-> %s, ignore: %d",
+ ((int64_t) fs->mtime), ((int64_t) tmp->modtime),
+ fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
+ (uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
+ if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
+ st->instruction = CSYNC_INSTRUCTION_EVAL;
+
+ // Preserve the EVAL flag later on if the type has changed.
+ if (_csync_filetype_different(tmp, fs)) {
+ st->child_modified = 1;
+ }
+
+ goto out;
+ }
+ if (ctx->current == LOCAL_REPLICA &&
+ (!_csync_mtime_equal(fs->mtime, tmp->modtime)
+ // zero size in statedb can happen during migration
+ || (tmp->size != 0 && fs->size != tmp->size))) {
+
+ // Checksum comparison at this stage is only enabled for .eml files,
+ // check #4754 #4755
+ bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
+ if (isEmlFile && fs->size == tmp->size && tmp->checksumHeader) {
+ if (ctx->callbacks.checksum_hook) {
+ st->checksumHeader = ctx->callbacks.checksum_hook(
+ file, tmp->checksumHeader,
+ ctx->callbacks.checksum_userdata);
+ }
+ bool checksumIdentical = false;
+ if (st->checksumHeader) {
+ checksumIdentical = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0;
+ }
+ if (checksumIdentical) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
+ st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+ goto out;
+ }
+ }
+
+ // Preserve the EVAL flag later on if the type has changed.
+ if (_csync_filetype_different(tmp, fs)) {
+ st->child_modified = 1;
+ }
+
+ st->instruction = CSYNC_INSTRUCTION_EVAL;
+ goto out;
+ }
+ bool metadata_differ = (ctx->current == REMOTE_REPLICA && (!c_streq(fs->file_id, tmp->file_id)
+ || !c_streq(fs->remotePerm, tmp->remotePerm)))
+ || (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
+ if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
+ && !metadata_differ && ctx->read_remote_from_db) {
+ /* If both etag and file id are equal for a directory, read all contents from
+ * the database.
+ * The metadata comparison ensure that we fetch all the file id or permission when
+ * upgrading owncloud
+ */
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
+ ctx->remote.read_from_db = true;
+ }
+ /* If it was remembered in the db that the remote dir has ignored files, store
+ * that so that the reconciler can make advantage of.
+ */
+ if( ctx->current == REMOTE_REPLICA ) {
+ st->has_ignored_files = tmp->has_ignored_files;
+ }
+ if (metadata_differ) {
+ /* file id or permissions has changed. Which means we need to update them in the DB. */
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Need to update metadata for: %s", path);
+ st->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+ } else {
+ st->instruction = CSYNC_INSTRUCTION_NONE;
+ }
+ } else {
+ enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
+
+ /* tmp might point to malloc mem, so free it here before reusing tmp */
+ csync_file_stat_free(tmp);
+
+ /* check if it's a file and has been renamed */
+ if (ctx->current == LOCAL_REPLICA) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
+
+ tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
+
+ if(_last_db_return_error(ctx)) {
+ csync_file_stat_free(st);
+ ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
+ return -1;
+ }
+
+ /* translate the file type between the two stat types csync has. */
+ if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) {
+ tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ } else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) {
+ tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
+ } else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) {
+ tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
+ } else {
+ tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
+ }
+
+ // Default to NEW unless we're sure it's a rename.
+ st->instruction = CSYNC_INSTRUCTION_NEW;
+
+ bool isRename =
+ tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
+ && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
+#ifdef NO_RENAME_EXTENSION
+ && _csync_sameextension(tmp->path, path)
+#endif
+ ;
+
+
+ // Verify the checksum where possible
+ if (isRename && tmp->checksumHeader && ctx->callbacks.checksum_hook
+ && fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) {
+ st->checksumHeader = ctx->callbacks.checksum_hook(
+ file, tmp->checksumHeader,
+ ctx->callbacks.checksum_userdata);
+ if (st->checksumHeader) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksumHeader, tmp->checksumHeader);
+ isRename = strncmp(st->checksumHeader, tmp->checksumHeader, 1000) == 0;
+ }
+ }
+
+ if (isRename) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
+ /* inode found so the file has been renamed */
+ st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
+ if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
+ csync_rename_record(ctx, tmp->path, path);
+ }
+ }
+ goto out;
+
+ } else {
+ /* Remote Replica Rename check */
+ tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
+
+ if(_last_db_return_error(ctx)) {
+ csync_file_stat_free(st);
+ ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
+ return -1;
+ }
+ if(tmp ) { /* tmp existing at all */
+ if ( _csync_filetype_different(tmp, fs)) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "file types different is not!");
+ st->instruction = CSYNC_INSTRUCTION_NEW;
+ goto out;
+ }
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "remote rename detected based on fileid %s %s", tmp->path, file);
+ st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
+ if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
+ csync_rename_record(ctx, tmp->path, path);
+ } else {
+ if( !c_streq(tmp->etag, fs->etag) ) {
+ /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "ETags are different!"); */
+ /* File with different etag, don't do a rename, but download the file again */
+ st->instruction = CSYNC_INSTRUCTION_NEW;
+ }
+ }
+ goto out;
+
+ } else {
+ /* file not found in statedb */
+ st->instruction = CSYNC_INSTRUCTION_NEW;
+
+ if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
+ if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
+ csync_file_stat_free(st);
+ return 1;
+ }
+ }
+ goto out;
+ }
+ }
+ }
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Unable to open statedb" );
+ csync_file_stat_free(st);
+ ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
+ return -1;
+ }
+
+out:
+
+ /* Set the ignored error string. */
+ if (st->instruction == CSYNC_INSTRUCTION_IGNORE) {
+ if( type == CSYNC_FTW_TYPE_SLINK ) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
+ } else {
+ if (excluded == CSYNC_FILE_EXCLUDE_LIST) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST; /* File listed on ignore list. */
+ } else if (excluded == CSYNC_FILE_EXCLUDE_INVALID_CHAR) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */
+ } else if (excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_TRAILING_SPACE; /* File ends with a trailing space. */
+ } else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
+ } else if (excluded == CSYNC_FILE_EXCLUDE_HIDDEN ) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN;
+ } else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
+ } else if (excluded == CSYNC_FILE_EXCLUDE_CONFLICT) {
+ st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_CONFLICT_FILE;
+ }
+ }
+ }
+ if (st->instruction != CSYNC_INSTRUCTION_NONE
+ && st->instruction != CSYNC_INSTRUCTION_IGNORE
+ && st->instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
+ && type != CSYNC_FTW_TYPE_DIR) {
+ st->child_modified = 1;
+ }
+ ctx->current_fs = st;
+
+ csync_file_stat_free(tmp);
+ st->inode = fs->inode;
+ st->mode = fs->mode;
+ st->size = fs->size;
+ st->modtime = fs->mtime;
+ st->type = type;
+ st->etag = NULL;
+ if( fs->etag ) {
+ SAFE_FREE(st->etag);
+ st->etag = c_strdup(fs->etag);
+ }
+ csync_vio_set_file_id(st->file_id, fs->file_id);
+ if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
+ SAFE_FREE(st->directDownloadUrl);
+ st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
+ }
+ if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
+ SAFE_FREE(st->directDownloadCookies);
+ st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
+ }
+ if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_PERM) {
+ strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
+ }
+
+ // For the remote: propagate the discovered checksum
+ if (fs->checksumHeader && ctx->current == REMOTE_REPLICA) {
+ st->checksumHeader = c_strdup(fs->checksumHeader);
+ }
+
+ st->phash = h;
+ st->pathlen = len;
+ memcpy(st->path, (len ? path : ""), len + 1);
+
+ switch (ctx->current) {
+ case LOCAL_REPLICA:
+ if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
+ csync_file_stat_free(st);
+ ctx->status_code = CSYNC_STATUS_TREE_ERROR;
+ return -1;
+ }
+ break;
+ case REMOTE_REPLICA:
+ if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
+ csync_file_stat_free(st);
+ ctx->status_code = CSYNC_STATUS_TREE_ERROR;
+ return -1;
+ }
+ break;
+ default:
+ break;
+ }
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "file: %s, instruction: %s <<=", st->path,
+ csync_instruction_str(st->instruction));
+
+ return 0;
+}
+
+int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
+ int flag) {
+ int rc = -1;
+ enum csync_ftw_type_e type = CSYNC_FTW_TYPE_SKIP;
+ csync_file_stat_t *st = NULL;
+ uint64_t h;
+
+ if (ctx->abort) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
+ ctx->status_code = CSYNC_STATUS_ABORTED;
+ return -1;
+ }
+
+ switch (flag) {
+ case CSYNC_FTW_FLAG_FILE:
+ if (ctx->current == REMOTE_REPLICA) {
+ if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size);
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=UNKNOWN]", file, fs->file_id);
+ }
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size);
+ }
+ type = CSYNC_FTW_TYPE_FILE;
+ break;
+ case CSYNC_FTW_FLAG_DIR: /* enter directory */
+ if (ctx->current == REMOTE_REPLICA) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [file_id=%s]", file, fs->file_id);
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "directory: %s [inode=%" PRIu64 "]", file, fs->inode);
+ }
+ type = CSYNC_FTW_TYPE_DIR;
+ break;
+ case CSYNC_FTW_FLAG_NSTAT: /* not statable file */
+ /* if file was here before and now is not longer stat-able, still
+ * add it to the db, otherwise not. */
+ h = _hash_of_file( ctx, file );
+ if( h == 0 ) {
+ return 0;
+ }
+ st = csync_statedb_get_stat_by_hash(ctx, h);
+ if( !st ) {
+ return 0;
+ }
+ csync_file_stat_free(st);
+ st = NULL;
+
+ type = CSYNC_FTW_TYPE_SKIP;
+ break;
+ case CSYNC_FTW_FLAG_SLINK:
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "symlink: %s - not supported", file);
+ type = CSYNC_FTW_TYPE_SLINK;
+ break;
+ case CSYNC_FTW_FLAG_DNR:
+ case CSYNC_FTW_FLAG_DP:
+ case CSYNC_FTW_FLAG_SLN:
+ default:
+ return 0;
+ break;
+ }
+
+ rc = _csync_detect_update(ctx, file, fs, type );
+
+ return rc;
+}
+
+static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
+{
+ if( csync_statedb_get_below_path(ctx, uri) < 0 ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!");
+ return false;
+ }
+
+ return true;
+}
+
+/* set the current item to an ignored state.
+ * If the item is set to ignored, the update phase continues, ie. its not a hard error */
+static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status )
+{
+ if(!ctx) {
+ return false;
+ }
+
+ if (ctx->current_fs) {
+ ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
+ ctx->current_fs->error_status = status;
+ /* If a directory has ignored files, put the flag on the parent directory as well */
+ if( previous_fs ) {
+ previous_fs->has_ignored_files = true;
+ }
+ return true;
+ }
+ return false;
+}
+
+/* File tree walker */
+int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
+ unsigned int depth) {
+ char *filename = NULL;
+ char *d_name = NULL;
+ csync_vio_handle_t *dh = NULL;
+ csync_vio_file_stat_t *dirent = NULL;
+ csync_file_stat_t *previous_fs = NULL;
+ int read_from_db = 0;
+ int rc = 0;
+ int res = 0;
+
+ bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
+
+ if (!depth) {
+ mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_INDIVIDUAL_TOO_DEEP);
+ goto done;
+ }
+
+ read_from_db = ctx->remote.read_from_db;
+
+ // if the etag of this dir is still the same, its content is restored from the
+ // database.
+ if( do_read_from_db ) {
+ if( ! fill_tree_from_db(ctx, uri) ) {
+ errno = ENOENT;
+ ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR;
+ goto error;
+ }
+ goto done;
+ }
+
+ if ((dh = csync_vio_opendir(ctx, uri)) == NULL) {
+ if (ctx->abort) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
+ ctx->status_code = CSYNC_STATUS_ABORTED;
+ goto error;
+ }
+ int asp = 0;
+ /* permission denied */
+ ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
+ if (errno == EACCES) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied.");
+ if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) {
+ goto done;
+ }
+ } else if(errno == ENOENT) {
+ asp = asprintf( &ctx->error_string, "%s", uri);
+ if (asp < 0) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
+ }
+ }
+ // 403 Forbidden can be sent by the server if the file firewall is active.
+ // A file or directory should be ignored and sync must continue. See #3490
+ else if(errno == ERRNO_FORBIDDEN) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)");
+ if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) {
+ goto done;
+ }
+ /* if current_fs is not defined here, better throw an error */
+ }
+ // The server usually replies with the custom "503 Storage not available"
+ // if some path is temporarily unavailable. But in some cases a standard 503
+ // is returned too. Thus we can't distinguish the two and will treat any
+ // 503 as request to ignore the folder. See #3113 #2884.
+ else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
+ if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) {
+ goto done;
+ }
+ /* if current_fs is not defined here, better throw an error */
+ } else {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
+ }
+ goto error;
+ }
+
+ while ((dirent = csync_vio_readdir(ctx, dh))) {
+ int flen;
+ int flag;
+
+ /* Conversion error */
+ if (dirent->name == NULL && dirent->original_name) {
+ ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
+ ctx->error_string = dirent->original_name; // take ownership
+ dirent->original_name = NULL;
+ goto error;
+ }
+
+ d_name = dirent->name;
+ if (d_name == NULL) {
+ ctx->status_code = CSYNC_STATUS_READDIR_ERROR;
+ goto error;
+ }
+
+ /* skip "." and ".." */
+ if ( (d_name[0] == '.' && d_name[1] == '\0')
+ || (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) {
+ csync_vio_file_stat_destroy(dirent);
+ dirent = NULL;
+ continue;
+ }
+
+ if (uri[0] == '\0') {
+ filename = c_strdup(d_name);
+ flen = strlen(d_name);
+ } else {
+ flen = asprintf(&filename, "%s/%s", uri, d_name);
+ }
+ if (flen < 0 || !filename) {
+ csync_vio_file_stat_destroy(dirent);
+ dirent = NULL;
+ ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
+ goto error;
+ }
+
+ /* Only for the local replica we have to stat(), for the remote one we have all data already */
+ if (ctx->replica == LOCAL_REPLICA) {
+ res = csync_vio_stat(ctx, filename, dirent);
+ } else {
+ res = 0;
+ }
+
+ /* if the filename starts with a . we consider it a hidden file
+ * For windows, the hidden state is also discovered within the vio
+ * local stat function.
+ */
+ if( d_name[0] == '.' ) {
+ if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */
+ dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
+ }
+ }
+
+ if( res == 0) {
+ switch (dirent->type) {
+ case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
+ flag = CSYNC_FTW_FLAG_SLINK;
+ break;
+ case CSYNC_VIO_FILE_TYPE_DIRECTORY:
+ flag = CSYNC_FTW_FLAG_DIR;
+ break;
+ case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE:
+ case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE:
+ case CSYNC_VIO_FILE_TYPE_SOCKET:
+ flag = CSYNC_FTW_FLAG_SPEC;
+ break;
+ case CSYNC_VIO_FILE_TYPE_FIFO:
+ flag = CSYNC_FTW_FLAG_SPEC;
+ break;
+ default:
+ flag = CSYNC_FTW_FLAG_FILE;
+ break;
+ };
+ } else {
+ flag = CSYNC_FTW_FLAG_NSTAT;
+ }
+
+ previous_fs = ctx->current_fs;
+
+ /* Call walker function for each file */
+ rc = fn(ctx, filename, dirent, flag);
+ /* this function may update ctx->current and ctx->read_from_db */
+
+ if (rc < 0) {
+ if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
+ ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
+ }
+
+ ctx->current_fs = previous_fs;
+ goto error;
+ }
+
+ if (flag == CSYNC_FTW_FLAG_DIR && rc == 0
+ && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) {
+ rc = csync_ftw(ctx, filename, fn, depth - 1);
+ if (rc < 0) {
+ ctx->current_fs = previous_fs;
+ goto error;
+ }
+
+ if (ctx->current_fs && !ctx->current_fs->child_modified
+ && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) {
+ if (ctx->current == REMOTE_REPLICA) {
+ ctx->current_fs->instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
+ } else {
+ ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE;
+ }
+ }
+
+ if (ctx->current_fs && previous_fs && ctx->current_fs->has_ignored_files) {
+ /* If a directory has ignored files, put the flag on the parent directory as well */
+ previous_fs->has_ignored_files = ctx->current_fs->has_ignored_files;
+ }
+ }
+
+ if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) {
+ /* If a directory has modified files, put the flag on the parent directory as well */
+ previous_fs->child_modified = ctx->current_fs->child_modified;
+ }
+
+ ctx->current_fs = previous_fs;
+ ctx->remote.read_from_db = read_from_db;
+ SAFE_FREE(filename);
+ csync_vio_file_stat_destroy(dirent);
+ dirent = NULL;
+ }
+
+ csync_vio_closedir(ctx, dh);
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db);
+
+done:
+ csync_vio_file_stat_destroy(dirent);
+ SAFE_FREE(filename);
+ return rc;
+error:
+ ctx->remote.read_from_db = read_from_db;
+ if (dh != NULL) {
+ csync_vio_closedir(ctx, dh);
+ }
+ SAFE_FREE(filename);
+ return -1;
+}
+
+/* vim: set ts=8 sw=2 et cindent: */
};
typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file,
- const csync_vio_file_stat_t *fs, enum csync_ftw_flags_e flag);
+ const csync_vio_file_stat_t *fs, int flag);
/**
* @brief The walker function to use in the file tree walker.
*
* @return 0 on success, < 0 on error.
*/
-int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
- enum csync_ftw_flags_e flag);
+int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs, int flag);
/**
* @brief The file tree walker.
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 "config_csync.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-
-#include "c_jhash.h"
-#include "csync_util.h"
-#include "vio/csync_vio.h"
-
-#define CSYNC_LOG_CATEGORY_NAME "csync.util"
-#include "csync_log.h"
-#include "csync_statedb.h"
-
-typedef struct {
- const char *instr_str;
- enum csync_instructions_e instr_code;
-} _instr_code_struct;
-
-static const _instr_code_struct _instr[] =
-{
- { "INSTRUCTION_NONE", CSYNC_INSTRUCTION_NONE },
- { "INSTRUCTION_EVAL", CSYNC_INSTRUCTION_EVAL },
- { "INSTRUCTION_REMOVE", CSYNC_INSTRUCTION_REMOVE },
- { "INSTRUCTION_RENAME", CSYNC_INSTRUCTION_RENAME },
- { "INSTRUCTION_EVAL_RENAME", CSYNC_INSTRUCTION_EVAL_RENAME },
- { "INSTRUCTION_NEW", CSYNC_INSTRUCTION_NEW },
- { "INSTRUCTION_CONFLICT", CSYNC_INSTRUCTION_CONFLICT },
- { "INSTRUCTION_IGNORE", CSYNC_INSTRUCTION_IGNORE },
- { "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC },
- { "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
- { "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
- { "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE },
- { "INSTRUCTION_UPDATE_METADATA", CSYNC_INSTRUCTION_UPDATE_METADATA },
- { NULL, CSYNC_INSTRUCTION_ERROR }
-};
-
-struct csync_memstat_s {
- int size;
- int resident;
- int shared;
- int trs;
- int drs;
- int lrs;
- int dt;
-};
-
-const char *csync_instruction_str(enum csync_instructions_e instr)
-{
- int idx = 0;
-
- while (_instr[idx].instr_str != NULL) {
- if (_instr[idx].instr_code == instr) {
- return _instr[idx].instr_str;
- }
- idx++;
- }
-
- return "ERROR!";
-}
-
-
-void csync_memstat_check(void) {
- int s = 0;
- struct csync_memstat_s m;
- FILE* fp;
-
- /* get process memory stats */
- fp = fopen("/proc/self/statm","r");
- if (fp == NULL) {
- return;
- }
- s = fscanf(fp, "%d%d%d%d%d%d%d", &m.size, &m.resident, &m.shared, &m.trs,
- &m.drs, &m.lrs, &m.dt);
- fclose(fp);
- if (s == EOF) {
- return;
- }
-
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Memory: %dK total size, %dK resident, %dK shared",
- m.size * 4, m.resident * 4, m.shared * 4);
-}
-
-bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
-void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
-void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
- csync_file_locked_or_open_ext = f;
-}
-
-bool csync_file_locked_or_open( const char *dir, const char *fname) {
- char *tmp_uri = NULL;
- bool ret;
- if (!csync_file_locked_or_open_ext) {
- return false;
- }
- if (asprintf(&tmp_uri, "%s/%s", dir, fname) < 0) {
- return -1;
- }
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "csync_file_locked_or_open %s", tmp_uri);
- ret = csync_file_locked_or_open_ext(tmp_uri);
- SAFE_FREE(tmp_uri);
- return ret;
-}
-
-#ifndef HAVE_TIMEGM
-#ifdef _WIN32
-static int is_leap(unsigned y) {
- y += 1900;
- return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
-}
-
-static time_t timegm(struct tm *tm) {
- static const unsigned ndays[2][12] = {
- {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
- {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} };
-
- time_t res = 0;
- int i;
-
- for (i = 70; i < tm->tm_year; ++i)
- res += is_leap(i) ? 366 : 365;
-
- for (i = 0; i < tm->tm_mon; ++i)
- res += ndays[is_leap(tm->tm_year)][i];
- res += tm->tm_mday - 1;
- res *= 24;
- res += tm->tm_hour;
- res *= 60;
- res += tm->tm_min;
- res *= 60;
- res += tm->tm_sec;
- return res;
-}
-#else
-/* A hopefully portable version of timegm */
-static time_t timegm(struct tm *tm ) {
- time_t ret;
- char *tz;
-
- tz = getenv("TZ");
- setenv("TZ", "", 1);
- tzset();
- ret = mktime(tm);
- if (tz)
- setenv("TZ", tz, 1);
- else
- unsetenv("TZ");
- tzset();
- return ret;
-}
-#endif /* Platform switch */
-#endif /* HAVE_TIMEGM */
-
-#define RFC1123_FORMAT "%3s, %02d %3s %4d %02d:%02d:%02d GMT"
-static const char short_months[12][4] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-/*
- * This function is borrowed from libneon's ne_httpdate_parse.
- * Unfortunately that one converts to local time but here UTC is
- * needed.
- * This one uses timegm instead, which returns UTC.
- */
-time_t oc_httpdate_parse( const char *date ) {
- struct tm gmt;
- char wkday[4], mon[4];
- int n;
- time_t result = 0;
-
- memset(&gmt, 0, sizeof(struct tm));
-
- /* it goes: Sun, 06 Nov 1994 08:49:37 GMT */
- n = sscanf(date, RFC1123_FORMAT,
- wkday, &gmt.tm_mday, mon, &gmt.tm_year, &gmt.tm_hour,
- &gmt.tm_min, &gmt.tm_sec);
- /* Is it portable to check n==7 here? */
- gmt.tm_year -= 1900;
- for (n=0; n<12; n++)
- if (strcmp(mon, short_months[n]) == 0)
- break;
- /* tm_mon comes out as 12 if the month is corrupt, which is desired,
- * since the mktime will then fail */
- gmt.tm_mon = n;
- gmt.tm_isdst = -1;
- result = timegm(&gmt);
- return result;
-}
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 "config_csync.h"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "c_jhash.h"
+#include "csync_util.h"
+#include "vio/csync_vio.h"
+
+#define CSYNC_LOG_CATEGORY_NAME "csync.util"
+#include "csync_log.h"
+#include "csync_statedb.h"
+
+typedef struct {
+ const char *instr_str;
+ enum csync_instructions_e instr_code;
+} _instr_code_struct;
+
+static const _instr_code_struct _instr[] =
+{
+ { "INSTRUCTION_NONE", CSYNC_INSTRUCTION_NONE },
+ { "INSTRUCTION_EVAL", CSYNC_INSTRUCTION_EVAL },
+ { "INSTRUCTION_REMOVE", CSYNC_INSTRUCTION_REMOVE },
+ { "INSTRUCTION_RENAME", CSYNC_INSTRUCTION_RENAME },
+ { "INSTRUCTION_EVAL_RENAME", CSYNC_INSTRUCTION_EVAL_RENAME },
+ { "INSTRUCTION_NEW", CSYNC_INSTRUCTION_NEW },
+ { "INSTRUCTION_CONFLICT", CSYNC_INSTRUCTION_CONFLICT },
+ { "INSTRUCTION_IGNORE", CSYNC_INSTRUCTION_IGNORE },
+ { "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC },
+ { "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
+ { "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
+ { "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE },
+ { "INSTRUCTION_UPDATE_METADATA", CSYNC_INSTRUCTION_UPDATE_METADATA },
+ { NULL, CSYNC_INSTRUCTION_ERROR }
+};
+
+struct csync_memstat_s {
+ int size;
+ int resident;
+ int shared;
+ int trs;
+ int drs;
+ int lrs;
+ int dt;
+};
+
+const char *csync_instruction_str(enum csync_instructions_e instr)
+{
+ int idx = 0;
+
+ while (_instr[idx].instr_str != NULL) {
+ if (_instr[idx].instr_code == instr) {
+ return _instr[idx].instr_str;
+ }
+ idx++;
+ }
+
+ return "ERROR!";
+}
+
+
+void csync_memstat_check(void) {
+ int s = 0;
+ struct csync_memstat_s m;
+ FILE* fp;
+
+ /* get process memory stats */
+ fp = fopen("/proc/self/statm","r");
+ if (fp == NULL) {
+ return;
+ }
+ s = fscanf(fp, "%d%d%d%d%d%d%d", &m.size, &m.resident, &m.shared, &m.trs,
+ &m.drs, &m.lrs, &m.dt);
+ fclose(fp);
+ if (s == EOF) {
+ return;
+ }
+
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Memory: %dK total size, %dK resident, %dK shared",
+ m.size * 4, m.resident * 4, m.shared * 4);
+}
+
+bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
+void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
+void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
+ csync_file_locked_or_open_ext = f;
+}
+
+bool csync_file_locked_or_open( const char *dir, const char *fname) {
+ char *tmp_uri = NULL;
+ bool ret;
+ if (!csync_file_locked_or_open_ext) {
+ return false;
+ }
+ if (asprintf(&tmp_uri, "%s/%s", dir, fname) < 0) {
+ return -1;
+ }
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "csync_file_locked_or_open %s", tmp_uri);
+ ret = csync_file_locked_or_open_ext(tmp_uri);
+ SAFE_FREE(tmp_uri);
+ return ret;
+}
+
+#ifndef HAVE_TIMEGM
+#ifdef _WIN32
+static int is_leap(unsigned y) {
+ y += 1900;
+ return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
+}
+
+static time_t timegm(struct tm *tm) {
+ static const unsigned ndays[2][12] = {
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} };
+
+ time_t res = 0;
+ int i;
+
+ for (i = 70; i < tm->tm_year; ++i)
+ res += is_leap(i) ? 366 : 365;
+
+ for (i = 0; i < tm->tm_mon; ++i)
+ res += ndays[is_leap(tm->tm_year)][i];
+ res += tm->tm_mday - 1;
+ res *= 24;
+ res += tm->tm_hour;
+ res *= 60;
+ res += tm->tm_min;
+ res *= 60;
+ res += tm->tm_sec;
+ return res;
+}
+#else
+/* A hopefully portable version of timegm */
+static time_t timegm(struct tm *tm ) {
+ time_t ret;
+ char *tz;
+
+ tz = getenv("TZ");
+ setenv("TZ", "", 1);
+ tzset();
+ ret = mktime(tm);
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return ret;
+}
+#endif /* Platform switch */
+#endif /* HAVE_TIMEGM */
+
+#define RFC1123_FORMAT "%3s, %02d %3s %4d %02d:%02d:%02d GMT"
+static const char short_months[12][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+/*
+ * This function is borrowed from libneon's ne_httpdate_parse.
+ * Unfortunately that one converts to local time but here UTC is
+ * needed.
+ * This one uses timegm instead, which returns UTC.
+ */
+time_t oc_httpdate_parse( const char *date ) {
+ struct tm gmt;
+ char wkday[4], mon[4];
+ int n;
+ time_t result = 0;
+
+ memset(&gmt, 0, sizeof(struct tm));
+
+ /* it goes: Sun, 06 Nov 1994 08:49:37 GMT */
+ n = sscanf(date, RFC1123_FORMAT,
+ wkday, &gmt.tm_mday, mon, &gmt.tm_year, &gmt.tm_hour,
+ &gmt.tm_min, &gmt.tm_sec);
+ /* Is it portable to check n==7 here? */
+ gmt.tm_year -= 1900;
+ for (n=0; n<12; n++)
+ if (strcmp(mon, short_months[n]) == 0)
+ break;
+ /* tm_mon comes out as 12 if the month is corrupt, which is desired,
+ * since the mktime will then fail */
+ gmt.tm_mon = n;
+ gmt.tm_isdst = -1;
+ result = timegm(&gmt);
+ return result;
+}
#ifndef _CSYNC_VERSION_H
#define _CSYNC_VERSION_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s)
#define CSYNC_TOSTRING(s) #s
#define MIRALL_VERSION @MIRALL_VERSION@
-#ifdef __cplusplus
-}
-#endif
-
#endif // _CSYNC_VERSION_H
#ifndef ASPRINTF_H
#define ASPRINTF_H 1
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdarg.h>
/**
int
asprintf (char **, const char *, ...);
+#ifdef __cplusplus
+}
+#endif
+
#endif
#endif
#ifndef _C_ALLOC_H
#define _C_ALLOC_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdlib.h>
#include "c_macro.h"
/**
* }@
*/
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _C_ALLOC_H */
#ifndef _C_PATH_H
#define _C_PATH_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "c_macro.h"
#include "c_private.h"
/**
* }@
*/
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _C_PATH_H */
#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;
/**
* }@
*/
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _C_RBTREE_H */
#ifndef _C_STR_H
#define _C_STR_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "c_private.h"
#include "c_macro.h"
/**
* }@
*/
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _C_STR_H */
#include "c_path.h"
#include "c_time.h"
-#ifndef _WIN32
-#include <sys/time.h>
-#endif
-
struct timespec c_tspecdiff(struct timespec time1, struct timespec time0) {
struct timespec ret;
int xsec = 0;
#ifndef _C_TIME_H
#define _C_TIME_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
#include <time.h>
+#else
+#include <sys/time.h>
+#endif
/**
* @brief Calculate time difference
int c_utimes(const char *uri, const struct timeval *times);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _C_TIME_H */
+++ /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
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "csync_private.h"
-#include "csync_util.h"
-#include "vio/csync_vio.h"
-#include "vio/csync_vio_local.h"
-#include "csync_statedb.h"
-#include "std/c_jhash.h"
-
-#define CSYNC_LOG_CATEGORY_NAME "csync.vio.main"
-
-#include "csync_log.h"
-
-csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
- switch(ctx->replica) {
- case REMOTE_REPLICA:
- if(ctx->remote.read_from_db) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
- }
- return ctx->callbacks.remote_opendir_hook(name, ctx->callbacks.vio_userdata);
- break;
- case LOCAL_REPLICA:
- if( ctx->callbacks.update_callback ) {
- ctx->callbacks.update_callback(ctx->replica, name, ctx->callbacks.update_callback_userdata);
- }
- return csync_vio_local_opendir(name);
- break;
- default:
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica);
- break;
- }
- return NULL;
-}
-
-int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
- int rc = -1;
-
- if (dhandle == NULL) {
- errno = EBADF;
- return -1;
- }
-
- switch(ctx->replica) {
- case REMOTE_REPLICA:
- if( ctx->remote.read_from_db ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
- }
- ctx->callbacks.remote_closedir_hook(dhandle, ctx->callbacks.vio_userdata);
- rc = 0;
- break;
- case LOCAL_REPLICA:
- rc = csync_vio_local_closedir(dhandle);
- break;
- default:
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica);
- break;
- }
- return rc;
-}
-
-csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
- switch(ctx->replica) {
- case REMOTE_REPLICA:
- if( ctx->remote.read_from_db ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
- }
- return ctx->callbacks.remote_readdir_hook(dhandle, ctx->callbacks.vio_userdata);
- break;
- case LOCAL_REPLICA:
- return csync_vio_local_readdir(dhandle);
- break;
- default:
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica);
- break;
- }
-
- return NULL;
-}
-
-
-int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
- int rc = -1;
-
- switch(ctx->replica) {
- case REMOTE_REPLICA:
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
- assert(ctx->replica != REMOTE_REPLICA);
- break;
- case LOCAL_REPLICA:
- rc = csync_vio_local_stat(uri, buf);
- if (rc < 0) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d for %s", errno, uri);
- }
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-char *csync_vio_get_status_string(CSYNC *ctx) {
- if(ctx->error_string) {
- return ctx->error_string;
- }
- return 0;
-}
--- /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
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "csync_private.h"
+#include "csync_util.h"
+#include "vio/csync_vio.h"
+#include "vio/csync_vio_local.h"
+#include "csync_statedb.h"
+#include "std/c_jhash.h"
+
+#define CSYNC_LOG_CATEGORY_NAME "csync.vio.main"
+
+#include "csync_log.h"
+
+csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
+ switch(ctx->replica) {
+ case REMOTE_REPLICA:
+ if(ctx->remote.read_from_db) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Read from db flag is true, should not!" );
+ }
+ return ctx->callbacks.remote_opendir_hook(name, ctx->callbacks.vio_userdata);
+ break;
+ case LOCAL_REPLICA:
+ if( ctx->callbacks.update_callback ) {
+ ctx->callbacks.update_callback(ctx->replica, name, ctx->callbacks.update_callback_userdata);
+ }
+ return csync_vio_local_opendir(name);
+ break;
+ default:
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica);
+ break;
+ }
+ return NULL;
+}
+
+int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
+ int rc = -1;
+
+ if (dhandle == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch(ctx->replica) {
+ case REMOTE_REPLICA:
+ if( ctx->remote.read_from_db ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote ReadFromDb is true, should not!");
+ }
+ ctx->callbacks.remote_closedir_hook(dhandle, ctx->callbacks.vio_userdata);
+ rc = 0;
+ break;
+ case LOCAL_REPLICA:
+ rc = csync_vio_local_closedir(dhandle);
+ break;
+ default:
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica);
+ break;
+ }
+ return rc;
+}
+
+csync_vio_file_stat_t *csync_vio_readdir(CSYNC *ctx, csync_vio_handle_t *dhandle) {
+ switch(ctx->replica) {
+ case REMOTE_REPLICA:
+ if( ctx->remote.read_from_db ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Remote readfromdb is true, should not!");
+ }
+ return ctx->callbacks.remote_readdir_hook(dhandle, ctx->callbacks.vio_userdata);
+ break;
+ case LOCAL_REPLICA:
+ return csync_vio_local_readdir(dhandle);
+ break;
+ default:
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "Invalid replica (%d)", (int)ctx->replica);
+ break;
+ }
+
+ return NULL;
+}
+
+
+int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
+ int rc = -1;
+
+ switch(ctx->replica) {
+ case REMOTE_REPLICA:
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
+ assert(ctx->replica != REMOTE_REPLICA);
+ break;
+ case LOCAL_REPLICA:
+ rc = csync_vio_local_stat(uri, buf);
+ if (rc < 0) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d for %s", errno, uri);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+char *csync_vio_get_status_string(CSYNC *ctx) {
+ if(ctx->error_string) {
+ return ctx->error_string;
+ }
+ return 0;
+}
+++ /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 "c_lib.h"
-#include "csync.h"
-#include "csync_log.h"
-
-csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
- csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
- ZERO_STRUCTP(file_stat);
- return file_stat;
-}
-
-csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) {
- csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new();
- memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t));
- if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
- file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
- }
- if (file_stat_cpy->directDownloadCookies) {
- file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies);
- }
- if (file_stat_cpy->directDownloadUrl) {
- file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl);
- }
- if (file_stat_cpy->checksumHeader) {
- file_stat_cpy->checksumHeader = c_strdup(file_stat_cpy->checksumHeader);
- }
- file_stat_cpy->name = c_strdup(file_stat_cpy->name);
- return file_stat_cpy;
-}
-
-void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
- /* FIXME: free rest */
- if (file_stat == NULL) {
- return;
- }
-
- if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
- SAFE_FREE(file_stat->etag);
- }
- SAFE_FREE(file_stat->directDownloadUrl);
- SAFE_FREE(file_stat->directDownloadCookies);
- SAFE_FREE(file_stat->name);
- SAFE_FREE(file_stat->original_name);
- SAFE_FREE(file_stat->checksumHeader);
- SAFE_FREE(file_stat);
-}
-
-void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* src ) {
-
- csync_vio_set_file_id( dst->file_id, src );
- if( c_streq( dst->file_id, "" )) {
- return;
- }
- dst->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID;
-}
-
-void csync_vio_set_file_id( char* dst, const char *src ) {
- if( src && dst ) {
- if( strlen(src) > FILE_ID_BUF_SIZE ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src);
- strcpy(dst, "");
- } else {
- strcpy(dst, src);
- }
- }
-}
--- /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 "c_lib.h"
+#include "csync.h"
+#include "csync_log.h"
+
+csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
+ csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
+ ZERO_STRUCTP(file_stat);
+ return file_stat;
+}
+
+csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) {
+ csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new();
+ memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t));
+ if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
+ file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
+ }
+ if (file_stat_cpy->directDownloadCookies) {
+ file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies);
+ }
+ if (file_stat_cpy->directDownloadUrl) {
+ file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl);
+ }
+ if (file_stat_cpy->checksumHeader) {
+ file_stat_cpy->checksumHeader = c_strdup(file_stat_cpy->checksumHeader);
+ }
+ file_stat_cpy->name = c_strdup(file_stat_cpy->name);
+ return file_stat_cpy;
+}
+
+void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
+ /* FIXME: free rest */
+ if (file_stat == NULL) {
+ return;
+ }
+
+ if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
+ SAFE_FREE(file_stat->etag);
+ }
+ SAFE_FREE(file_stat->directDownloadUrl);
+ SAFE_FREE(file_stat->directDownloadCookies);
+ SAFE_FREE(file_stat->name);
+ SAFE_FREE(file_stat->original_name);
+ SAFE_FREE(file_stat->checksumHeader);
+ SAFE_FREE(file_stat);
+}
+
+void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* src ) {
+
+ csync_vio_set_file_id( dst->file_id, src );
+ if( c_streq( dst->file_id, "" )) {
+ return;
+ }
+ dst->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID;
+}
+
+void csync_vio_set_file_id( char* dst, const char *src ) {
+ if( src && dst ) {
+ if( strlen(src) > FILE_ID_BUF_SIZE ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src);
+ strcpy(dst, "");
+ } else {
+ strcpy(dst, src);
+ }
+ }
+}
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2013- by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <stdio.h>
-
-#include "c_private.h"
-#include "c_lib.h"
-#include "c_string.h"
-#include "csync_util.h"
-#include "csync_log.h"
-#include "csync_vio.h"
-
-#include "vio/csync_vio_local.h"
-
-/*
- * directory functions
- */
-
-typedef struct dhandle_s {
- DIR *dh;
- char *path;
-} dhandle_t;
-
-csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
- dhandle_t *handle = NULL;
- mbchar_t *dirname = NULL;
-
- handle = c_malloc(sizeof(dhandle_t));
-
- dirname = c_utf8_path_to_locale(name);
-
- handle->dh = _topendir( dirname );
- if (handle->dh == NULL) {
- c_free_locale_string(dirname);
- SAFE_FREE(handle);
- return NULL;
- }
-
- handle->path = c_strdup(name);
- c_free_locale_string(dirname);
-
- return (csync_vio_handle_t *) handle;
-}
-
-int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
- dhandle_t *handle = NULL;
- int rc = -1;
-
- if (dhandle == NULL) {
- errno = EBADF;
- return -1;
- }
-
- handle = (dhandle_t *) dhandle;
- rc = _tclosedir(handle->dh);
-
- SAFE_FREE(handle->path);
- SAFE_FREE(handle);
-
- return rc;
-}
-
-csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
-
- dhandle_t *handle = NULL;
- csync_vio_file_stat_t *file_stat = NULL;
-
- handle = (dhandle_t *) dhandle;
-
- errno = 0;
- file_stat = csync_vio_file_stat_new();
- if (file_stat == NULL) {
- goto err;
- }
- file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
-
- struct _tdirent *dirent = NULL;
-
- dirent = _treaddir(handle->dh);
- if (dirent == NULL) {
- goto err;
- }
- file_stat->name = c_utf8_from_locale(dirent->d_name);
- if (file_stat->name == NULL) {
- //file_stat->original_name = c_strdup(dirent->d_name);
- if (asprintf(&file_stat->original_name, "%s/%s", handle->path, dirent->d_name) < 0) {
- goto err;
- }
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Invalid characters in file/directory name, please rename: \"%s\" (%s)",
- dirent->d_name, handle->path);
- }
-
- /* Check for availability of d_type, see manpage. */
-#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__)
- switch (dirent->d_type) {
- case DT_FIFO:
- case DT_SOCK:
- case DT_CHR:
- case DT_BLK:
- break;
- case DT_DIR:
- case DT_REG:
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
- if (dirent->d_type == DT_DIR) {
- file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
- } else {
- file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
- }
- break;
- case DT_UNKNOWN:
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
- file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
- default:
- break;
- }
-#endif
-
- return file_stat;
-
-err:
- csync_vio_file_stat_destroy(file_stat);
-
- return NULL;
-}
-
-
-int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
- csync_stat_t sb;
-
- mbchar_t *wuri = c_utf8_path_to_locale( uri );
-
- if( _tstat(wuri, &sb) < 0) {
- c_free_locale_string(wuri);
- return -1;
- }
-
- buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
-
- switch(sb.st_mode & S_IFMT) {
- case S_IFBLK:
- buf->type = CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE;
- break;
- case S_IFCHR:
- buf->type = CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE;
- break;
- case S_IFDIR:
- buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
- break;
- case S_IFIFO:
- buf->type = CSYNC_VIO_FILE_TYPE_FIFO;
- break;
- case S_IFREG:
- buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
- break;
- case S_IFLNK:
- buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
- break;
- case S_IFSOCK:
- buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
- break;
- default:
- buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
- break;
- }
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
-
- buf->mode = sb.st_mode;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE;
-
- if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) {
- /* FIXME: handle symlink */
- buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK;
- } else {
- buf->flags = CSYNC_VIO_FILE_FLAGS_NONE;
- }
-#ifdef __APPLE__
- if (sb.st_flags & UF_HIDDEN) {
- buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
- }
-#endif
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
-
- buf->inode = sb.st_ino;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
-
- buf->atime = sb.st_atime;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
-
- buf->mtime = sb.st_mtime;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
-
- buf->ctime = sb.st_ctime;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
-
- buf->size = sb.st_size;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
-
- c_free_locale_string(wuri);
- return 0;
-}
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2013- by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+
+#include "c_private.h"
+#include "c_lib.h"
+#include "c_string.h"
+#include "csync_util.h"
+#include "csync_log.h"
+#include "csync_vio.h"
+
+#include "vio/csync_vio_local.h"
+
+/*
+ * directory functions
+ */
+
+typedef struct dhandle_s {
+ DIR *dh;
+ char *path;
+} dhandle_t;
+
+csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
+ dhandle_t *handle = NULL;
+ mbchar_t *dirname = NULL;
+
+ handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
+
+ dirname = c_utf8_path_to_locale(name);
+
+ handle->dh = _topendir( dirname );
+ if (handle->dh == NULL) {
+ c_free_locale_string(dirname);
+ SAFE_FREE(handle);
+ return NULL;
+ }
+
+ handle->path = c_strdup(name);
+ c_free_locale_string(dirname);
+
+ return (csync_vio_handle_t *) handle;
+}
+
+int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
+ dhandle_t *handle = NULL;
+ int rc = -1;
+
+ if (dhandle == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ handle = (dhandle_t *) dhandle;
+ rc = _tclosedir(handle->dh);
+
+ SAFE_FREE(handle->path);
+ SAFE_FREE(handle);
+
+ return rc;
+}
+
+csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
+
+ dhandle_t *handle = NULL;
+ csync_vio_file_stat_t *file_stat = NULL;
+
+ handle = (dhandle_t *) dhandle;
+ struct _tdirent *dirent = NULL;
+
+ errno = 0;
+ file_stat = csync_vio_file_stat_new();
+ if (file_stat == NULL) {
+ goto err;
+ }
+ file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
+
+ dirent = _treaddir(handle->dh);
+ if (dirent == NULL) {
+ goto err;
+ }
+ file_stat->name = c_utf8_from_locale(dirent->d_name);
+ if (file_stat->name == NULL) {
+ //file_stat->original_name = c_strdup(dirent->d_name);
+ if (asprintf(&file_stat->original_name, "%s/%s", handle->path, dirent->d_name) < 0) {
+ goto err;
+ }
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Invalid characters in file/directory name, please rename: \"%s\" (%s)",
+ dirent->d_name, handle->path);
+ }
+
+ /* Check for availability of d_type, see manpage. */
+#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__)
+ switch (dirent->d_type) {
+ case DT_FIFO:
+ case DT_SOCK:
+ case DT_CHR:
+ case DT_BLK:
+ break;
+ case DT_DIR:
+ case DT_REG:
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+ if (dirent->d_type == DT_DIR) {
+ file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
+ } else {
+ file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ }
+ break;
+ case DT_UNKNOWN:
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+ file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
+ default:
+ break;
+ }
+#endif
+
+ return file_stat;
+
+err:
+ csync_vio_file_stat_destroy(file_stat);
+
+ return NULL;
+}
+
+
+int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
+ csync_stat_t sb;
+
+ mbchar_t *wuri = c_utf8_path_to_locale( uri );
+
+ if( _tstat(wuri, &sb) < 0) {
+ c_free_locale_string(wuri);
+ return -1;
+ }
+
+ buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
+
+ switch(sb.st_mode & S_IFMT) {
+ case S_IFBLK:
+ buf->type = CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE;
+ break;
+ case S_IFCHR:
+ buf->type = CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE;
+ break;
+ case S_IFDIR:
+ buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
+ break;
+ case S_IFIFO:
+ buf->type = CSYNC_VIO_FILE_TYPE_FIFO;
+ break;
+ case S_IFREG:
+ buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ break;
+ case S_IFLNK:
+ buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
+ break;
+ case S_IFSOCK:
+ buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
+ break;
+ default:
+ buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
+ break;
+ }
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+
+ buf->mode = sb.st_mode;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MODE;
+
+ if (buf->type == CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK) {
+ /* FIXME: handle symlink */
+ buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK;
+ } else {
+ buf->flags = CSYNC_VIO_FILE_FLAGS_NONE;
+ }
+#ifdef __APPLE__
+ if (sb.st_flags & UF_HIDDEN) {
+ buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
+ }
+#endif
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
+
+ buf->inode = sb.st_ino;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
+
+ buf->atime = sb.st_atime;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
+
+ buf->mtime = sb.st_mtime;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
+
+ buf->ctime = sb.st_ctime;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
+
+ buf->size = sb.st_size;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
+
+ c_free_locale_string(wuri);
+ return 0;
+}
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- * Copyright (c) 2013- by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-
-#include "windows.h"
-
-#include "c_private.h"
-#include "c_lib.h"
-#include "c_string.h"
-#include "csync_util.h"
-#include "csync_log.h"
-#include "csync_vio.h"
-
-#include "vio/csync_vio_local.h"
-
-
-/*
- * directory functions
- */
-
-typedef struct dhandle_s {
- WIN32_FIND_DATA ffd;
- HANDLE hFind;
- int firstFind;
- char *path;
-} dhandle_t;
-
-csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
- dhandle_t *handle = NULL;
- mbchar_t *dirname = NULL;
-
- handle = c_malloc(sizeof(dhandle_t));
-
- // the file wildcard has to be attached
- int len_name = strlen(name);
- if( len_name ) {
- char *h = NULL;
-
- // alloc an enough large buffer to take the name + '/*' + the closing zero.
- h = c_malloc(len_name+3);
- strncpy( h, name, 1+len_name);
- strncat(h, "/*", 2);
-
- dirname = c_utf8_path_to_locale(h);
- SAFE_FREE(h);
- }
-
- if( dirname ) {
- handle->hFind = FindFirstFile(dirname, &(handle->ffd));
- }
-
- if (!dirname || handle->hFind == INVALID_HANDLE_VALUE) {
- int retcode = GetLastError();
- if( retcode == ERROR_FILE_NOT_FOUND ) {
- errno = ENOENT;
- } else {
- errno = EACCES;
- }
- SAFE_FREE(handle);
- return NULL;
- }
-
- handle->firstFind = 1; // Set a flag that there first fileinfo is available.
-
- handle->path = c_strdup(name);
- c_free_locale_string(dirname);
-
- return (csync_vio_handle_t *) handle;
-}
-
-int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
- dhandle_t *handle = NULL;
- int rc = -1;
-
- if (dhandle == NULL) {
- errno = EBADF;
- return -1;
- }
-
- handle = (dhandle_t *) dhandle;
- // FindClose returns non-zero on success
- if( FindClose(handle->hFind) != 0 ) {
- rc = 0;
- } else {
- // error case, set errno
- errno = EBADF;
- }
-
- SAFE_FREE(handle->path);
- SAFE_FREE(handle);
-
- return rc;
-}
-
-
-static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder)
-{
- long long int t = filetime->dwHighDateTime;
- t <<= 32;
- t += (UINT32)filetime->dwLowDateTime;
- t -= 116444736000000000LL;
- if (t < 0)
- {
- if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
- return -1 - ((-t - 1) / 10000000);
- }
- else
- {
- if (remainder) *remainder = t % 10000000;
- return t / 10000000;
- }
-}
-
-csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
-
- dhandle_t *handle = NULL;
- csync_vio_file_stat_t *file_stat = NULL;
- DWORD rem;
-
- handle = (dhandle_t *) dhandle;
-
- errno = 0;
- file_stat = csync_vio_file_stat_new();
- if (file_stat == NULL) {
- errno = ENOMEM;
- goto err;
- }
- file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
-
- // the win32 functions get the first valid entry with the opendir
- // thus we must not jump to next entry if it was the first find.
- if( handle->firstFind ) {
- handle->firstFind = 0;
- } else {
- if( FindNextFile(handle->hFind, &(handle->ffd)) == 0 ) {
- // might be error, check!
- int dwError = GetLastError();
- if (dwError != ERROR_NO_MORE_FILES) {
- errno = EACCES; // no more files is fine. Otherwise EACCESS
- }
- goto err;
- }
- }
- file_stat->name = c_utf8_from_locale(handle->ffd.cFileName);
-
- file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE;
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
- if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- // Detect symlinks, and treat junctions as symlinks too.
- if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK
- || handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) {
- file_stat->flags |= CSYNC_VIO_FILE_FLAGS_SYMLINK;
- file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
- } else {
- // The SIS and DEDUP reparse points should be treated as
- // regular files. We don't know about the other ones yet,
- // but will also treat them normally for now.
- file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
- }
- } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE
- || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE
- || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
- file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
- } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
- } else {
- file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
- }
-
- /* Check for the hidden flag */
- if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) {
- file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
- }
-
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
-
- file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow;
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
-
- file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem);
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
-
- file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem);
- /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
-
- file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem);
- file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
-
- return file_stat;
-
-err:
- SAFE_FREE(file_stat);
-
- return NULL;
-}
-
-
-
-int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
- /* Almost nothing to do since csync_vio_local_readdir already filled up most of the information
- But we still need to fetch the file ID.
- Possible optimisation: only fetch the file id when we need it (for new files)
- */
-
- HANDLE h;
- BY_HANDLE_FILE_INFORMATION fileInfo;
- ULARGE_INTEGER FileIndex;
- mbchar_t *wuri = c_utf8_path_to_locale( uri );
-
- h = CreateFileW( wuri, 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
- NULL );
- if( h == INVALID_HANDLE_VALUE ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %s", uri );
- errno = GetLastError();
- c_free_locale_string(wuri);
- return -1;
- }
-
- if(!GetFileInformationByHandle( h, &fileInfo ) ) {
- CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "GetFileInformationByHandle failed on %s", uri );
- errno = GetLastError();
- c_free_locale_string(wuri);
- CloseHandle(h);
- return -1;
- }
-
- /* Get the Windows file id as an inode replacement. */
- FileIndex.HighPart = fileInfo.nFileIndexHigh;
- FileIndex.LowPart = fileInfo.nFileIndexLow;
- FileIndex.QuadPart &= 0x0000FFFFFFFFFFFF;
- /* printf("Index: %I64i\n", FileIndex.QuadPart); */
- buf->inode = FileIndex.QuadPart;
-
- if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE)) {
- buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow;
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
- }
- if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_MTIME)) {
- DWORD rem;
- buf->mtime = FileTimeToUnixTime(&fileInfo.ftLastWriteTime, &rem);
- /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */
- buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
- }
-
- c_free_locale_string(wuri);
- CloseHandle(h);
- return 0;
-}
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
+ * Copyright (c) 2013- by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "windows.h"
+
+#include "c_private.h"
+#include "c_lib.h"
+#include "c_string.h"
+#include "csync_util.h"
+#include "csync_log.h"
+#include "csync_vio.h"
+
+#include "vio/csync_vio_local.h"
+
+
+/*
+ * directory functions
+ */
+
+typedef struct dhandle_s {
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind;
+ int firstFind;
+ char *path;
+} dhandle_t;
+
+csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
+ dhandle_t *handle = NULL;
+ mbchar_t *dirname = NULL;
+
+ handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
+
+ // the file wildcard has to be attached
+ int len_name = strlen(name);
+ if( len_name ) {
+ char *h = NULL;
+
+ // alloc an enough large buffer to take the name + '/*' + the closing zero.
+ h = (char*)c_malloc(len_name+3);
+ strncpy( h, name, 1+len_name);
+ strncat(h, "/*", 2);
+
+ dirname = c_utf8_path_to_locale(h);
+ SAFE_FREE(h);
+ }
+
+ if( dirname ) {
+ handle->hFind = FindFirstFile(dirname, &(handle->ffd));
+ }
+
+ if (!dirname || handle->hFind == INVALID_HANDLE_VALUE) {
+ int retcode = GetLastError();
+ if( retcode == ERROR_FILE_NOT_FOUND ) {
+ errno = ENOENT;
+ } else {
+ errno = EACCES;
+ }
+ SAFE_FREE(handle);
+ return NULL;
+ }
+
+ handle->firstFind = 1; // Set a flag that there first fileinfo is available.
+
+ handle->path = c_strdup(name);
+ c_free_locale_string(dirname);
+
+ return (csync_vio_handle_t *) handle;
+}
+
+int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
+ dhandle_t *handle = NULL;
+ int rc = -1;
+
+ if (dhandle == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ handle = (dhandle_t *) dhandle;
+ // FindClose returns non-zero on success
+ if( FindClose(handle->hFind) != 0 ) {
+ rc = 0;
+ } else {
+ // error case, set errno
+ errno = EBADF;
+ }
+
+ SAFE_FREE(handle->path);
+ SAFE_FREE(handle);
+
+ return rc;
+}
+
+
+static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder)
+{
+ long long int t = filetime->dwHighDateTime;
+ t <<= 32;
+ t += (UINT32)filetime->dwLowDateTime;
+ t -= 116444736000000000LL;
+ if (t < 0)
+ {
+ if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
+ return -1 - ((-t - 1) / 10000000);
+ }
+ else
+ {
+ if (remainder) *remainder = t % 10000000;
+ return t / 10000000;
+ }
+}
+
+csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
+
+ dhandle_t *handle = NULL;
+ csync_vio_file_stat_t *file_stat = NULL;
+ DWORD rem;
+
+ handle = (dhandle_t *) dhandle;
+
+ errno = 0;
+ file_stat = csync_vio_file_stat_new();
+ if (file_stat == NULL) {
+ errno = ENOMEM;
+ goto err;
+ }
+ file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
+
+ // the win32 functions get the first valid entry with the opendir
+ // thus we must not jump to next entry if it was the first find.
+ if( handle->firstFind ) {
+ handle->firstFind = 0;
+ } else {
+ if( FindNextFile(handle->hFind, &(handle->ffd)) == 0 ) {
+ // might be error, check!
+ int dwError = GetLastError();
+ if (dwError != ERROR_NO_MORE_FILES) {
+ errno = EACCES; // no more files is fine. Otherwise EACCESS
+ }
+ goto err;
+ }
+ }
+ file_stat->name = c_utf8_from_locale(handle->ffd.cFileName);
+
+ file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE;
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+ if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ // Detect symlinks, and treat junctions as symlinks too.
+ if (handle->ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK
+ || handle->ffd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT) {
+ file_stat->flags |= CSYNC_VIO_FILE_FLAGS_SYMLINK;
+ file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
+ } else {
+ // The SIS and DEDUP reparse points should be treated as
+ // regular files. We don't know about the other ones yet,
+ // but will also treat them normally for now.
+ file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ }
+ } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE
+ || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE
+ || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
+ file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
+ } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
+ } else {
+ file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ }
+
+ /* Check for the hidden flag */
+ if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) {
+ file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
+ }
+
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+
+ file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow;
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
+
+ file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem);
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
+
+ file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem);
+ /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
+
+ file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem);
+ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
+
+ return file_stat;
+
+err:
+ SAFE_FREE(file_stat);
+
+ return NULL;
+}
+
+
+
+int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
+ /* Almost nothing to do since csync_vio_local_readdir already filled up most of the information
+ But we still need to fetch the file ID.
+ Possible optimisation: only fetch the file id when we need it (for new files)
+ */
+
+ HANDLE h;
+ BY_HANDLE_FILE_INFORMATION fileInfo;
+ ULARGE_INTEGER FileIndex;
+ mbchar_t *wuri = c_utf8_path_to_locale( uri );
+
+ h = CreateFileW( wuri, 0, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL );
+ if( h == INVALID_HANDLE_VALUE ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %s", uri );
+ errno = GetLastError();
+ c_free_locale_string(wuri);
+ return -1;
+ }
+
+ if(!GetFileInformationByHandle( h, &fileInfo ) ) {
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "GetFileInformationByHandle failed on %s", uri );
+ errno = GetLastError();
+ c_free_locale_string(wuri);
+ CloseHandle(h);
+ return -1;
+ }
+
+ /* Get the Windows file id as an inode replacement. */
+ FileIndex.HighPart = fileInfo.nFileIndexHigh;
+ FileIndex.LowPart = fileInfo.nFileIndexLow;
+ FileIndex.QuadPart &= 0x0000FFFFFFFFFFFF;
+ /* printf("Index: %I64i\n", FileIndex.QuadPart); */
+ buf->inode = FileIndex.QuadPart;
+
+ if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE)) {
+ buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow;
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
+ }
+ if (!(buf->fields & CSYNC_VIO_FILE_STAT_FIELDS_MTIME)) {
+ DWORD rem;
+ buf->mtime = FileTimeToUnixTime(&fileInfo.ftLastWriteTime, &rem);
+ /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */
+ buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
+ }
+
+ c_free_locale_string(wuri);
+ CloseHandle(h);
+ return 0;
+}
#include <QFileInfo>
-extern "C" {
#include "std/c_string.h"
#include "csync.h"
#include "csync_exclude.h"
-}
using namespace OCC;
#include <QSet>
#include <QString>
-extern "C" {
#include "std/c_string.h"
#include "csync.h"
#include "csync_exclude.h" // for CSYNC_EXCLUDE_TYPE
-}
namespace OCC {
// We use some internals of csync:
extern "C" int c_utimes(const char *, const struct timeval *);
-extern "C" void csync_win32_set_file_hidden(const char *file, bool h);
-extern "C" {
#include "csync.h"
#include "vio/csync_vio_local.h"
#include "std/c_path.h"
#include "std/c_string.h"
-}
namespace OCC {
#include <QIODevice>
#include <QMutex>
+#include "csync_util.h"
#include "syncfileitem.h"
#include "syncjournaldb.h"
#include "bandwidthmanager.h"
Q_DECLARE_LOGGING_CATEGORY(lcPropagator)
-extern "C" const char *csync_instruction_str(enum csync_instructions_e instr);
-
/** Free disk space threshold below which syncs will abort and not even start.
*/
qint64 criticalFreeSpaceLimit();
#include "ownsql.h"
-#include <inttypes.h>
-
#include "syncjournaldb.h"
#include "syncjournalfilerecord.h"
#include "utility.h"
# csync tests
# This will be rewritten soon anyway.
-#add_cmocka_test(check_logger log_tests/check_log.c ${TEST_TARGET_LIBRARIES})
+#add_cmocka_test(check_logger log_tests/check_log.cpp ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_create csync_tests/check_csync_create.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_log csync_tests/check_csync_log.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_exclude csync_tests/check_csync_exclude.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_statedb_load csync_tests/check_csync_statedb_load.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_util csync_tests/check_csync_util.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_misc csync_tests/check_csync_misc.c ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_create csync_tests/check_csync_create.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_log csync_tests/check_csync_log.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_exclude csync_tests/check_csync_exclude.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_statedb_load csync_tests/check_csync_statedb_load.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_util csync_tests/check_csync_util.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_misc csync_tests/check_csync_misc.cpp ${TEST_TARGET_LIBRARIES})
# csync tests which require init
-add_cmocka_test(check_csync_init csync_tests/check_csync_init.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_statedb_query csync_tests/check_csync_statedb_query.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_csync_commit csync_tests/check_csync_commit.c ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_init csync_tests/check_csync_init.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_statedb_query csync_tests/check_csync_statedb_query.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_commit csync_tests/check_csync_commit.cpp ${TEST_TARGET_LIBRARIES})
# vio
-add_cmocka_test(check_vio_file_stat vio_tests/check_vio_file_stat.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_vio vio_tests/check_vio.c ${TEST_TARGET_LIBRARIES})
-add_cmocka_test(check_vio_ext vio_tests/check_vio_ext.c ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_vio_file_stat vio_tests/check_vio_file_stat.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_vio vio_tests/check_vio.cpp ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_vio_ext vio_tests/check_vio_ext.cpp ${TEST_TARGET_LIBRARIES})
# sync
-add_cmocka_test(check_csync_update csync_tests/check_csync_update.c ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_csync_update csync_tests/check_csync_update.cpp ${TEST_TARGET_LIBRARIES})
# encoding
-add_cmocka_test(check_encoding_functions encoding_tests/check_encoding.c ${TEST_TARGET_LIBRARIES})
+add_cmocka_test(check_encoding_functions encoding_tests/check_encoding.cpp ${TEST_TARGET_LIBRARIES})
+++ /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 <string.h>
-
-#include "torture.h"
-
-#include "csync_private.h"
-
-static int setup(void **state) {
- CSYNC *csync;
- int rc;
-
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/check_csync1");
-
- *state = csync;
-
- return 0;
-}
-
-static int setup_module(void **state) {
- CSYNC *csync;
- int rc;
-
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/check_csync1");
-
- csync_init(csync, "foo");
- *state = csync;
-
- return 0;
-}
-
-static int teardown(void **state) {
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_destroy(csync);
-
- rc = system("rm -rf /tmp/check_csync");
- assert_int_equal(rc, 0);
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-static void check_csync_commit(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_commit(csync);
- assert_int_equal(rc, 0);
-
- assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
-}
-
-static void check_csync_commit_dummy(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_commit(csync);
- assert_int_equal(rc, 0);
-
- assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
-
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(check_csync_commit, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_commit_dummy, setup_module, teardown),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
--- /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 <string.h>
+
+#include "torture.h"
+
+#include "csync_private.h"
+
+static int setup(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ *state = csync;
+
+ return 0;
+}
+
+static int setup_module(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ csync_init(csync, "foo");
+ *state = csync;
+
+ return 0;
+}
+
+static int teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_destroy(csync);
+
+ rc = system("rm -rf /tmp/check_csync");
+ assert_int_equal(rc, 0);
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static void check_csync_commit(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_commit(csync);
+ assert_int_equal(rc, 0);
+
+ assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
+}
+
+static void check_csync_commit_dummy(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_commit(csync);
+ assert_int_equal(rc, 0);
+
+ assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
+
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_commit, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_commit_dummy, setup_module, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+++ /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 <stdlib.h>
-#include <stdio.h>
-
-#include "torture.h"
-
-#include "csync_private.h"
-
-
-static void check_csync_destroy_null(void **state)
-{
- int rc;
-
- (void) state; /* unused */
-
- rc = csync_destroy(NULL);
- assert_int_equal(rc, -1);
-}
-
-static void check_csync_create(void **state)
-{
- CSYNC *csync;
- int rc;
-
- (void) state; /* unused */
-
- csync_create(&csync, "/tmp/csync1");
-
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(check_csync_destroy_null),
- cmocka_unit_test(check_csync_create),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 <stdlib.h>
+#include <stdio.h>
+
+#include "torture.h"
+
+#include "csync_private.h"
+
+
+static void check_csync_destroy_null(void **state)
+{
+ int rc;
+
+ (void) state; /* unused */
+
+ rc = csync_destroy(NULL);
+ assert_int_equal(rc, -1);
+}
+
+static void check_csync_create(void **state)
+{
+ CSYNC *csync;
+ int rc;
+
+ (void) state; /* unused */
+
+ csync_create(&csync, "/tmp/csync1");
+
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(check_csync_destroy_null),
+ cmocka_unit_test(check_csync_create),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+++ /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 "config_csync.h"
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-
-#include "torture.h"
-
-#define CSYNC_TEST 1
-#include "csync_exclude.c"
-
-#define EXCLUDE_LIST_FILE SOURCEDIR"/../../sync-exclude.lst"
-
-static int setup(void **state) {
- CSYNC *csync;
-
- csync_create(&csync, "/tmp/check_csync1");
-
- *state = csync;
- return 0;
-}
-
-static int setup_init(void **state) {
- CSYNC *csync;
- int rc;
-
- csync_create(&csync, "/tmp/check_csync1");
-
- rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes));
- assert_int_equal(rc, 0);
-
- /* and add some unicode stuff */
- rc = _csync_exclude_add(&(csync->excludes), "*.💩");
- assert_int_equal(rc, 0);
- rc = _csync_exclude_add(&(csync->excludes), "пятницы.*");
- assert_int_equal(rc, 0);
- rc = _csync_exclude_add(&(csync->excludes), "*/*.out");
- assert_int_equal(rc, 0);
- rc = _csync_exclude_add(&(csync->excludes), "latex*/*.run.xml");
- assert_int_equal(rc, 0);
- rc = _csync_exclude_add(&(csync->excludes), "latex/*/*.tex.tmp");
- assert_int_equal(rc, 0);
-
- *state = csync;
- return 0;
-}
-
-static int teardown(void **state) {
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
- rc = system("rm -rf /tmp/check_csync2");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-static void check_csync_exclude_add(void **state)
-{
- CSYNC *csync = *state;
- _csync_exclude_add(&(csync->excludes), "/tmp/check_csync1/*");
- assert_string_equal(csync->excludes->vector[0], "/tmp/check_csync1/*");
-}
-
-static void check_csync_exclude_load(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes) );
- assert_int_equal(rc, 0);
-
- assert_string_equal(csync->excludes->vector[0], "*~");
- assert_int_not_equal(csync->excludes->count, 0);
-}
-
-static void check_csync_excluded(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_excluded_no_ctx(csync->excludes, "", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, "/", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- rc = csync_excluded_no_ctx(csync->excludes, "krawel_krawel", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, ".directory/cache-maximegalon/cache1.txt", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_no_ctx(csync->excludes, "mozilla/.directory", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- /*
- * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
- * to be found in top dir as well as in directories underneath.
- */
- rc = csync_excluded_no_ctx(csync->excludes, ".apdisk", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_no_ctx(csync->excludes, "foo/.apdisk", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_no_ctx(csync->excludes, "foo/bar/.apdisk", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, ".java", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- /* Files in the ignored dir .java will also be ignored. */
- rc = csync_excluded_no_ctx(csync->excludes, ".apdisk/totally_amazing.jar", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- /* and also in subdirs */
- rc = csync_excluded_no_ctx(csync->excludes, "projects/.apdisk/totally_amazing.jar", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- /* csync-journal is ignored in general silently. */
- rc = csync_excluded_no_ctx(csync->excludes, ".csync_journal.db", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, ".csync_journal.db.ctmp", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, "subdir/.csync_journal.db", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
-
- /* also the new form of the database name */
- rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
-
- rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
- rc = csync_excluded_no_ctx(csync->excludes, "subdir/.sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
-
-
- /* pattern ]*.directory - ignore and remove */
- rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/a_folder/my.~directory", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
-
- /* Not excluded because the pattern .netscape/cache requires directory. */
- rc = csync_excluded_no_ctx(csync->excludes, ".netscape/cache", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- /* Not excluded */
- rc = csync_excluded_no_ctx(csync->excludes, "unicode/中文.hé", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
- /* excluded */
- rc = csync_excluded_no_ctx(csync->excludes, "unicode/пятницы.txt", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
- rc = csync_excluded_no_ctx(csync->excludes, "unicode/中文.💩", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- /* path wildcards */
- rc = csync_excluded_no_ctx(csync->excludes, "foobar/my_manuscript.out", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "latex_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "word_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- rc = csync_excluded_no_ctx(csync->excludes, "latex/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- rc = csync_excluded_no_ctx(csync->excludes, "latex/songbook/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
-#ifdef _WIN32
- rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_space ", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
-
- rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_dot.", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
-
- rc = csync_excluded_no_ctx(csync->excludes, "AUX", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
-
- rc = csync_excluded_no_ctx(csync->excludes, "file_invalid_char<", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
-#endif
-}
-
-static void check_csync_excluded_traversal(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- _csync_exclude_add( &(csync->excludes), "/exclude" );
-
- /* Check toplevel dir, the pattern only works for toplevel dir. */
- rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- /* check for a file called exclude. Must still work */
- rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- /* Add an exclude for directories only: excl/ */
- _csync_exclude_add( &(csync->excludes), "excl/" );
- rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_traversal(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_traversal(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
-
- rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- _csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
-
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
-}
-
-static void check_csync_pathes(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- _csync_exclude_add( &(csync->excludes), "/exclude" );
-
- /* Check toplevel dir, the pattern only works for toplevel dir. */
- rc = csync_excluded_no_ctx(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- /* check for a file called exclude. Must still work */
- rc = csync_excluded_no_ctx(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- /* Add an exclude for directories only: excl/ */
- _csync_exclude_add( &(csync->excludes), "excl/" );
- rc = csync_excluded_no_ctx(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- _csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
-
- rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
-
- rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
- assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
-}
-
-static void check_csync_is_windows_reserved_word() {
- assert_true(csync_is_windows_reserved_word("CON"));
- assert_true(csync_is_windows_reserved_word("con"));
- assert_true(csync_is_windows_reserved_word("CON."));
- assert_true(csync_is_windows_reserved_word("con."));
- assert_true(csync_is_windows_reserved_word("CON.ference"));
- assert_false(csync_is_windows_reserved_word("CONference"));
- assert_false(csync_is_windows_reserved_word("conference"));
- assert_false(csync_is_windows_reserved_word("conf.erence"));
- assert_false(csync_is_windows_reserved_word("co"));
- assert_true(csync_is_windows_reserved_word("A:"));
- assert_true(csync_is_windows_reserved_word("a:"));
- assert_true(csync_is_windows_reserved_word("z:"));
- assert_true(csync_is_windows_reserved_word("Z:"));
- assert_true(csync_is_windows_reserved_word("M:"));
- assert_true(csync_is_windows_reserved_word("m:"));
-}
-
-static void check_csync_excluded_performance(void **state)
-{
- CSYNC *csync = *state;
-
- const int N = 10000;
- int totalRc = 0;
- int i = 0;
-
- // Being able to use QElapsedTimer for measurement would be nice...
- {
- struct timeval before, after;
- gettimeofday(&before, 0);
-
- for (i = 0; i < N; ++i) {
- totalRc += csync_excluded_no_ctx(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
- totalRc += csync_excluded_no_ctx(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
- }
- assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
-
- gettimeofday(&after, 0);
-
- const double total = (after.tv_sec - before.tv_sec)
- + (after.tv_usec - before.tv_usec) / 1.0e6;
- const double perCallMs = total / 2 / N * 1000;
- printf("csync_excluded: %f ms per call\n", perCallMs);
- }
-
- {
- struct timeval before, after;
- gettimeofday(&before, 0);
-
- for (i = 0; i < N; ++i) {
- totalRc += csync_excluded_traversal(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
- totalRc += csync_excluded_traversal(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
- }
- assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
-
- gettimeofday(&after, 0);
-
- const double total = (after.tv_sec - before.tv_sec)
- + (after.tv_usec - before.tv_usec) / 1.0e6;
- const double perCallMs = total / 2 / N * 1000;
- printf("csync_excluded_traversal: %f ms per call\n", perCallMs);
- }
-}
-
-static void check_csync_exclude_expand_escapes(void **state)
-{
- (void)state;
-
- const char *str = csync_exclude_expand_escapes(
- "keep \\' \\\" \\? \\\\ \\a \\b \\f \\n \\r \\t \\v \\z");
- assert_true(0 == strcmp(
- str, "keep ' \" ? \\ \a \b \f \n \r \t \v \\z"));
- SAFE_FREE(str);
-
- str = csync_exclude_expand_escapes("");
- assert_true(0 == strcmp(str, ""));
- SAFE_FREE(str);
-
- str = csync_exclude_expand_escapes("\\");
- assert_true(0 == strcmp(str, "\\"));
- SAFE_FREE(str);
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(check_csync_exclude_add, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_exclude_load, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
- cmocka_unit_test_setup_teardown(check_csync_excluded_traversal, setup_init, teardown),
- cmocka_unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
- cmocka_unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
- cmocka_unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
- cmocka_unit_test(check_csync_exclude_expand_escapes),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
--- /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 "config_csync.h"
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "torture.h"
+
+#define CSYNC_TEST 1
+#include "csync_exclude.cpp"
+
+#define EXCLUDE_LIST_FILE SOURCEDIR"/../../sync-exclude.lst"
+
+static int setup(void **state) {
+ CSYNC *csync;
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ *state = csync;
+ return 0;
+}
+
+static int setup_init(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes));
+ assert_int_equal(rc, 0);
+
+ /* and add some unicode stuff */
+ rc = _csync_exclude_add(&(csync->excludes), "*.💩");
+ assert_int_equal(rc, 0);
+ rc = _csync_exclude_add(&(csync->excludes), "пятницы.*");
+ assert_int_equal(rc, 0);
+ rc = _csync_exclude_add(&(csync->excludes), "*/*.out");
+ assert_int_equal(rc, 0);
+ rc = _csync_exclude_add(&(csync->excludes), "latex*/*.run.xml");
+ assert_int_equal(rc, 0);
+ rc = _csync_exclude_add(&(csync->excludes), "latex/*/*.tex.tmp");
+ assert_int_equal(rc, 0);
+
+ *state = csync;
+ return 0;
+}
+
+static int teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ rc = system("rm -rf /tmp/check_csync2");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static void check_csync_exclude_add(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ _csync_exclude_add(&(csync->excludes), "/tmp/check_csync1/*");
+ assert_string_equal(csync->excludes->vector[0], "/tmp/check_csync1/*");
+}
+
+static void check_csync_exclude_load(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes) );
+ assert_int_equal(rc, 0);
+
+ assert_string_equal(csync->excludes->vector[0], "*~");
+ assert_int_not_equal(csync->excludes->count, 0);
+}
+
+static void check_csync_excluded(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_excluded_no_ctx(csync->excludes, "", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "/", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "krawel_krawel", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, ".directory/cache-maximegalon/cache1.txt", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_no_ctx(csync->excludes, "mozilla/.directory", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /*
+ * Test for patterns in subdirs. '.beagle' is defined as a pattern and has
+ * to be found in top dir as well as in directories underneath.
+ */
+ rc = csync_excluded_no_ctx(csync->excludes, ".apdisk", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_no_ctx(csync->excludes, "foo/.apdisk", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_no_ctx(csync->excludes, "foo/bar/.apdisk", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, ".java", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* Files in the ignored dir .java will also be ignored. */
+ rc = csync_excluded_no_ctx(csync->excludes, ".apdisk/totally_amazing.jar", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /* and also in subdirs */
+ rc = csync_excluded_no_ctx(csync->excludes, "projects/.apdisk/totally_amazing.jar", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /* csync-journal is ignored in general silently. */
+ rc = csync_excluded_no_ctx(csync->excludes, ".csync_journal.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, ".csync_journal.db.ctmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "subdir/.csync_journal.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+
+ /* also the new form of the database name */
+ rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+
+ rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+ rc = csync_excluded_no_ctx(csync->excludes, "subdir/.sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
+
+
+ /* pattern ]*.directory - ignore and remove */
+ rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/a_folder/my.~directory", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_AND_REMOVE);
+
+ /* Not excluded because the pattern .netscape/cache requires directory. */
+ rc = csync_excluded_no_ctx(csync->excludes, ".netscape/cache", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* Not excluded */
+ rc = csync_excluded_no_ctx(csync->excludes, "unicode/中文.hé", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+ /* excluded */
+ rc = csync_excluded_no_ctx(csync->excludes, "unicode/пятницы.txt", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+ rc = csync_excluded_no_ctx(csync->excludes, "unicode/中文.💩", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ /* path wildcards */
+ rc = csync_excluded_no_ctx(csync->excludes, "foobar/my_manuscript.out", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "latex_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "word_tmp/my_manuscript.run.xml", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "latex/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "latex/songbook/my_manuscript.tex.tmp", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+#ifdef _WIN32
+ rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_space ", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_TRAILING_SPACE);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "file_trailing_dot.", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "AUX", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "file_invalid_char<", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_INVALID_CHAR);
+#endif
+}
+
+static void check_csync_excluded_traversal(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ _csync_exclude_add( &(csync->excludes), "/exclude" );
+
+ /* Check toplevel dir, the pattern only works for toplevel dir. */
+ rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* check for a file called exclude. Must still work */
+ rc = csync_excluded_traversal(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* Add an exclude for directories only: excl/ */
+ _csync_exclude_add( &(csync->excludes), "excl/" );
+ rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
+
+ rc = csync_excluded_traversal(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ _csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
+
+ rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_traversal(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED); // because leading dirs aren't checked!
+}
+
+static void check_csync_pathes(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ _csync_exclude_add( &(csync->excludes), "/exclude" );
+
+ /* Check toplevel dir, the pattern only works for toplevel dir. */
+ rc = csync_excluded_no_ctx(csync->excludes, "/exclude", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* check for a file called exclude. Must still work */
+ rc = csync_excluded_no_ctx(csync->excludes, "/exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/foo/exclude", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ /* Add an exclude for directories only: excl/ */
+ _csync_exclude_add( &(csync->excludes), "excl/" );
+ rc = csync_excluded_no_ctx(csync->excludes, "/excl", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "meep/excl", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/excl", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ _csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+ rc = csync_excluded_no_ctx(csync->excludes, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
+ assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+}
+
+static void check_csync_is_windows_reserved_word(void **) {
+ assert_true(csync_is_windows_reserved_word("CON"));
+ assert_true(csync_is_windows_reserved_word("con"));
+ assert_true(csync_is_windows_reserved_word("CON."));
+ assert_true(csync_is_windows_reserved_word("con."));
+ assert_true(csync_is_windows_reserved_word("CON.ference"));
+ assert_false(csync_is_windows_reserved_word("CONference"));
+ assert_false(csync_is_windows_reserved_word("conference"));
+ assert_false(csync_is_windows_reserved_word("conf.erence"));
+ assert_false(csync_is_windows_reserved_word("co"));
+ assert_true(csync_is_windows_reserved_word("A:"));
+ assert_true(csync_is_windows_reserved_word("a:"));
+ assert_true(csync_is_windows_reserved_word("z:"));
+ assert_true(csync_is_windows_reserved_word("Z:"));
+ assert_true(csync_is_windows_reserved_word("M:"));
+ assert_true(csync_is_windows_reserved_word("m:"));
+}
+
+static void check_csync_excluded_performance(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+
+ const int N = 10000;
+ int totalRc = 0;
+ int i = 0;
+
+ // Being able to use QElapsedTimer for measurement would be nice...
+ {
+ struct timeval before, after;
+ gettimeofday(&before, 0);
+
+ for (i = 0; i < N; ++i) {
+ totalRc += csync_excluded_no_ctx(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
+ totalRc += csync_excluded_no_ctx(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
+ }
+ assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
+
+ gettimeofday(&after, 0);
+
+ const double total = (after.tv_sec - before.tv_sec)
+ + (after.tv_usec - before.tv_usec) / 1.0e6;
+ const double perCallMs = total / 2 / N * 1000;
+ printf("csync_excluded: %f ms per call\n", perCallMs);
+ }
+
+ {
+ struct timeval before, after;
+ gettimeofday(&before, 0);
+
+ for (i = 0; i < N; ++i) {
+ totalRc += csync_excluded_traversal(csync->excludes, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
+ totalRc += csync_excluded_traversal(csync->excludes, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
+ }
+ assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
+
+ gettimeofday(&after, 0);
+
+ const double total = (after.tv_sec - before.tv_sec)
+ + (after.tv_usec - before.tv_usec) / 1.0e6;
+ const double perCallMs = total / 2 / N * 1000;
+ printf("csync_excluded_traversal: %f ms per call\n", perCallMs);
+ }
+}
+
+static void check_csync_exclude_expand_escapes(void **state)
+{
+ (void)state;
+
+ const char *str = csync_exclude_expand_escapes(
+ "keep \\' \\\" \\? \\\\ \\a \\b \\f \\n \\r \\t \\v \\z");
+ assert_true(0 == strcmp(
+ str, "keep ' \" ? \\ \a \b \f \n \r \t \v \\z"));
+ SAFE_FREE(str);
+
+ str = csync_exclude_expand_escapes("");
+ assert_true(0 == strcmp(str, ""));
+ SAFE_FREE(str);
+
+ str = csync_exclude_expand_escapes("\\");
+ assert_true(0 == strcmp(str, "\\"));
+ SAFE_FREE(str);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_exclude_add, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_exclude_load, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_excluded_traversal, setup_init, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
+ cmocka_unit_test(check_csync_exclude_expand_escapes),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+++ /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 <string.h>
-
-#include "torture.h"
-
-#include "csync_private.h"
-
-static int setup(void **state) {
- CSYNC *csync;
- int rc;
-
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/check_csync1");
-
- *state = csync;
- return 0;
-}
-
-static int setup_module(void **state) {
- CSYNC *csync;
- int rc;
-
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/check_csync1");
-
- *state = csync;
- return 0;
-}
-
-static int teardown(void **state) {
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_destroy(csync);
-
- rc = system("rm -rf /tmp/check_csync");
- assert_int_equal(rc, 0);
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-static void check_csync_init(void **state)
-{
- CSYNC *csync = *state;
-
- csync_init(csync, "");
-
- assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
-
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(check_csync_init, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_init, setup_module, teardown),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 <string.h>
+
+#include "torture.h"
+
+#include "csync_private.h"
+
+static int setup(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ *state = csync;
+ return 0;
+}
+
+static int setup_module(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ *state = csync;
+ return 0;
+}
+
+static int teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_destroy(csync);
+
+ rc = system("rm -rf /tmp/check_csync");
+ assert_int_equal(rc, 0);
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static void check_csync_init(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+
+ csync_init(csync, "");
+
+ assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
+
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_init, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_init, setup_module, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+++ /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 <sys/types.h>
-#include <sys/stat.h>
-
-#include "torture.h"
-
-#include "csync.h"
-#include "csync_log.c"
-#include "c_private.h"
-
-static int setup(void **state) {
- CSYNC *csync;
- int rc;
-
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/check_csync1");
-
- *state = csync;
-
- return 0;
-}
-
-static int teardown(void **state) {
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_destroy(csync);
-
- rc = system("rm -rf /tmp/check_csync");
- assert_int_equal(rc, 0);
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-static void check_log_callback(int verbosity,
- const char *function,
- const char *buffer)
-{
- int rc;
-
- assert_true(verbosity >= 0);
- assert_non_null(function);
- assert_false(function[0] == '\0');
- assert_non_null(buffer);
- assert_false(buffer[0] == '\0');
-
- rc = system("touch /tmp/check_csync1/cb_called");
- assert_int_equal(rc, 0);
-}
-
-static void check_set_log_level(void **state)
-{
- int rc;
-
- (void) state;
-
- rc = csync_set_log_level(-5);
- assert_int_equal(rc, -1);
-
- rc = csync_set_log_level(5);
- assert_int_equal(rc, 0);
-
- rc = csync_get_log_level();
- assert_int_equal(rc, 5);
-}
-
-static void check_set_auth_callback(void **state)
-{
- csync_log_callback log_fn;
- int rc;
-
- (void) state;
-
- rc = csync_set_log_callback(NULL);
- assert_int_equal(rc, -1);
-
- rc = csync_set_log_callback(check_log_callback);
- assert_int_equal(rc, 0);
-
- log_fn = csync_get_log_callback();
- assert_non_null(log_fn);
- assert_true(log_fn == &check_log_callback);
-}
-
-static void check_logging(void **state)
-{
- int rc;
- csync_stat_t sb;
- mbchar_t *path;
- path = c_utf8_path_to_locale("/tmp/check_csync1/cb_called");
-
- (void) state; /* unused */
-
- assert_non_null(path);
-
- rc = csync_set_log_level(1);
- assert_int_equal(rc, 0);
-
- rc = csync_set_log_callback(check_log_callback);
- assert_int_equal(rc, 0);
-
- csync_log(1, __func__, "rc = %d", rc);
-
- rc = _tstat(path, &sb);
-
- c_free_locale_string(path);
-
- assert_int_equal(rc, 0);
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(check_set_log_level),
- cmocka_unit_test(check_set_auth_callback),
- cmocka_unit_test_setup_teardown(check_logging, setup, teardown),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
--- /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 <sys/types.h>
+#include <sys/stat.h>
+
+#include "torture.h"
+
+#include "csync.h"
+#include "csync_log.cpp"
+#include "c_private.h"
+
+static int setup(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ *state = csync;
+
+ return 0;
+}
+
+static int teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_destroy(csync);
+
+ rc = system("rm -rf /tmp/check_csync");
+ assert_int_equal(rc, 0);
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static void check_log_callback(int verbosity,
+ const char *function,
+ const char *buffer)
+{
+ int rc;
+
+ assert_true(verbosity >= 0);
+ assert_non_null(function);
+ assert_false(function[0] == '\0');
+ assert_non_null(buffer);
+ assert_false(buffer[0] == '\0');
+
+ rc = system("touch /tmp/check_csync1/cb_called");
+ assert_int_equal(rc, 0);
+}
+
+static void check_set_log_level(void **state)
+{
+ int rc;
+
+ (void) state;
+
+ rc = csync_set_log_level(-5);
+ assert_int_equal(rc, -1);
+
+ rc = csync_set_log_level(5);
+ assert_int_equal(rc, 0);
+
+ rc = csync_get_log_level();
+ assert_int_equal(rc, 5);
+}
+
+static void check_set_auth_callback(void **state)
+{
+ csync_log_callback log_fn;
+ int rc;
+
+ (void) state;
+
+ rc = csync_set_log_callback(NULL);
+ assert_int_equal(rc, -1);
+
+ rc = csync_set_log_callback(check_log_callback);
+ assert_int_equal(rc, 0);
+
+ log_fn = csync_get_log_callback();
+ assert_non_null(log_fn);
+ assert_true(log_fn == &check_log_callback);
+}
+
+static void check_logging(void **state)
+{
+ int rc;
+ csync_stat_t sb;
+ mbchar_t *path;
+ path = c_utf8_path_to_locale("/tmp/check_csync1/cb_called");
+
+ (void) state; /* unused */
+
+ assert_non_null(path);
+
+ rc = csync_set_log_level(1);
+ assert_int_equal(rc, 0);
+
+ rc = csync_set_log_callback(check_log_callback);
+ assert_int_equal(rc, 0);
+
+ csync_log(1, __func__, "rc = %d", rc);
+
+ rc = _tstat(path, &sb);
+
+ c_free_locale_string(path);
+
+ assert_int_equal(rc, 0);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(check_set_log_level),
+ cmocka_unit_test(check_set_auth_callback),
+ cmocka_unit_test_setup_teardown(check_logging, setup, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+++ /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 "torture.h"
-
-#include "csync_misc.h"
-#include <stdlib.h>
-
-static void check_csync_normalize_etag(void **state)
-{
- char *str;
-
- (void) state; /* unused */
-
-#define CHECK_NORMALIZE_ETAG(TEST, EXPECT) \
- str = csync_normalize_etag(TEST); \
- assert_string_equal(str, EXPECT); \
- free(str);
-
-
- CHECK_NORMALIZE_ETAG("foo", "foo");
- CHECK_NORMALIZE_ETAG("\"foo\"", "foo");
- CHECK_NORMALIZE_ETAG("\"nar123\"", "nar123");
- CHECK_NORMALIZE_ETAG("", "");
- CHECK_NORMALIZE_ETAG("\"\"", "");
-
- /* Test with -gzip (all combinaison) */
- CHECK_NORMALIZE_ETAG("foo-gzip", "foo");
- CHECK_NORMALIZE_ETAG("\"foo\"-gzip", "foo");
- CHECK_NORMALIZE_ETAG("\"foo-gzip\"", "foo");
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(check_csync_normalize_etag),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 "torture.h"
+
+#include "csync_misc.h"
+#include <stdlib.h>
+
+static void check_csync_normalize_etag(void **state)
+{
+ char *str;
+
+ (void) state; /* unused */
+
+#define CHECK_NORMALIZE_ETAG(TEST, EXPECT) \
+ str = csync_normalize_etag(TEST); \
+ assert_string_equal(str, EXPECT); \
+ free(str);
+
+
+ CHECK_NORMALIZE_ETAG("foo", "foo");
+ CHECK_NORMALIZE_ETAG("\"foo\"", "foo");
+ CHECK_NORMALIZE_ETAG("\"nar123\"", "nar123");
+ CHECK_NORMALIZE_ETAG("", "");
+ CHECK_NORMALIZE_ETAG("\"\"", "");
+
+ /* Test with -gzip (all combinaison) */
+ CHECK_NORMALIZE_ETAG("foo-gzip", "foo");
+ CHECK_NORMALIZE_ETAG("\"foo\"-gzip", "foo");
+ CHECK_NORMALIZE_ETAG("\"foo-gzip\"", "foo");
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(check_csync_normalize_etag),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+++ /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 <string.h>
-
-#include "torture.h"
-
-#define CSYNC_TEST 1
-#include "csync_statedb.c"
-
-#define TESTDB "/tmp/check_csync1/test.db"
-
-static int setup(void **state) {
- CSYNC *csync;
- int rc;
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/check_csync1");
-
- csync->statedb.file = c_strdup( TESTDB );
- *state = csync;
-
- sqlite3 *db = NULL;
- rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
- assert_int_equal(rc, SQLITE_OK);
-
- rc = sqlite3_close(db);
- assert_int_equal(rc, SQLITE_OK);
-
- return 0;
-}
-
-static int teardown(void **state) {
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-static void check_csync_statedb_load(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
- assert_int_equal(rc, 0);
-
- sqlite3_close(csync->statedb.db);
-}
-
-static void check_csync_statedb_close(void **state)
-{
- CSYNC *csync = *state;
- csync_stat_t sb;
- time_t modtime;
- mbchar_t *testdb = c_utf8_path_to_locale(TESTDB);
- int rc;
-
- /* statedb not written */
- csync_statedb_load(csync, TESTDB, &csync->statedb.db);
-
- rc = _tstat(testdb, &sb);
- assert_int_equal(rc, 0);
- modtime = sb.st_mtime;
-
- rc = csync_statedb_close(csync);
- assert_int_equal(rc, 0);
-
- rc = _tstat(testdb, &sb);
- assert_int_equal(rc, 0);
- assert_int_equal(modtime, sb.st_mtime);
-
- csync_statedb_load(csync, TESTDB, &csync->statedb.db);
-
- rc = _tstat(testdb, &sb);
- assert_int_equal(rc, 0);
- modtime = sb.st_mtime;
-
- /* wait a sec or the modtime will be the same */
- sleep(1);
-
- /* statedb written */
- rc = csync_statedb_close(csync);
- assert_int_equal(rc, 0);
-
- rc = _tstat(testdb, &sb);
- assert_int_equal(rc, 0);
-
- c_free_locale_string(testdb);
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(check_csync_statedb_load, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_statedb_close, setup, teardown),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 <string.h>
+
+#include "torture.h"
+
+#define CSYNC_TEST 1
+#include "csync_statedb.cpp"
+
+#define TESTDB "/tmp/check_csync1/test.db"
+
+static int setup(void **state) {
+ CSYNC *csync;
+ int rc;
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/check_csync1");
+
+ csync->statedb.file = c_strdup( TESTDB );
+ *state = csync;
+
+ sqlite3 *db = NULL;
+ rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
+ assert_int_equal(rc, SQLITE_OK);
+
+ rc = sqlite3_close(db);
+ assert_int_equal(rc, SQLITE_OK);
+
+ return 0;
+}
+
+static int teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static void check_csync_statedb_load(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+ assert_int_equal(rc, 0);
+
+ sqlite3_close(csync->statedb.db);
+}
+
+static void check_csync_statedb_close(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_stat_t sb;
+ time_t modtime;
+ mbchar_t *testdb = c_utf8_path_to_locale(TESTDB);
+ int rc;
+
+ /* statedb not written */
+ csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+
+ rc = _tstat(testdb, &sb);
+ assert_int_equal(rc, 0);
+ modtime = sb.st_mtime;
+
+ rc = csync_statedb_close(csync);
+ assert_int_equal(rc, 0);
+
+ rc = _tstat(testdb, &sb);
+ assert_int_equal(rc, 0);
+ assert_int_equal(modtime, sb.st_mtime);
+
+ csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+
+ rc = _tstat(testdb, &sb);
+ assert_int_equal(rc, 0);
+ modtime = sb.st_mtime;
+
+ /* wait a sec or the modtime will be the same */
+ sleep(1);
+
+ /* statedb written */
+ rc = csync_statedb_close(csync);
+ assert_int_equal(rc, 0);
+
+ rc = _tstat(testdb, &sb);
+ assert_int_equal(rc, 0);
+
+ c_free_locale_string(testdb);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_statedb_load, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_statedb_close, setup, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+++ /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 "torture.h"
-
-#define CSYNC_TEST 1
-#include "csync_statedb.c"
-
-#define TESTDB "/tmp/check_csync1/test.db"
-#define TESTDBTMP "/tmp/check_csync1/test.db.ctmp"
-
-
-
-static int setup(void **state)
-{
- CSYNC *csync;
- int rc = 0;
-
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
- rc = system("mkdir -p /tmp/check_csync");
- assert_int_equal(rc, 0);
- csync_create(&csync, "/tmp/check_csync1");
- csync_init(csync, TESTDB);
-
- sqlite3 *db = NULL;
- rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
- assert_int_equal(rc, SQLITE_OK);
- rc = sqlite3_close(db);
- assert_int_equal(rc, SQLITE_OK);
-
- rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
- assert_int_equal(rc, 0);
-
- *state = csync;
-
- return 0;
-}
-
-static int setup_db(void **state)
-{
- char *errmsg;
- int rc = 0;
- sqlite3 *db = NULL;
-
- const char *sql = "CREATE TABLE IF NOT EXISTS metadata ("
- "phash INTEGER(8),"
- "pathlen INTEGER,"
- "path VARCHAR(4096),"
- "inode INTEGER,"
- "uid INTEGER,"
- "gid INTEGER,"
- "mode INTEGER,"
- "modtime INTEGER(8),"
- "type INTEGER,"
- "md5 VARCHAR(32),"
- "PRIMARY KEY(phash)"
- ");";
-
- const char *sql2 = "INSERT INTO metadata"
- "(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5) VALUES"
- "(42, 42, 'Its funny stuff', 23, 42, 43, 55, 66, 2, 54);";
-
-
- setup(state);
- rc = sqlite3_open( TESTDB, &db);
- assert_int_equal(rc, SQLITE_OK);
-
- rc = sqlite3_exec( db, sql, NULL, NULL, &errmsg );
- assert_int_equal(rc, SQLITE_OK);
-
- rc = sqlite3_exec( db, sql2, NULL, NULL, &errmsg );
- assert_int_equal(rc, SQLITE_OK);
-
- sqlite3_close(db);
-
- return 0;
-
-}
-
-static int teardown(void **state) {
- CSYNC *csync = *state;
- int rc = 0;
-
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
- rc = system("rm -rf /tmp/check_csync");
- assert_int_equal(rc, 0);
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-
-static void check_csync_statedb_query_statement(void **state)
-{
- CSYNC *csync = *state;
- c_strlist_t *result;
-
- result = csync_statedb_query(csync->statedb.db, "");
- assert_null(result);
- if (result != NULL) {
- c_strlist_destroy(result);
- }
-
- result = csync_statedb_query(csync->statedb.db, "SELECT;");
- assert_null(result);
- if (result != NULL) {
- c_strlist_destroy(result);
- }
-}
-
-static void check_csync_statedb_drop_tables(void **state)
-{
- // CSYNC *csync = *state;
- int rc = 0;
- (void) state;
-
- // rc = csync_statedb_drop_tables(csync->statedb.db);
- assert_int_equal(rc, 0);
- // rc = csync_statedb_create_tables(csync->statedb.db);
- assert_int_equal(rc, 0);
- // rc = csync_statedb_drop_tables(csync->statedb.db);
- assert_int_equal(rc, 0);
-}
-
-static void check_csync_statedb_insert_metadata(void **state)
-{
- CSYNC *csync = *state;
- 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 = c_malloc(sizeof(csync_file_stat_t) + 30 );
- snprintf(st->path, 29, "file_%d" , i );
- st->phash = i;
-
- rc = c_rbtree_insert(csync->local.tree, (void *) st);
- assert_int_equal(rc, 0);
- }
-
- // rc = csync_statedb_insert_metadata(csync, csync->statedb.db);
- assert_int_equal(rc, 0);
-}
-
-static void check_csync_statedb_write(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *st;
- int i, rc;
-
- for (i = 0; i < 100; i++) {
- st = c_malloc(sizeof(csync_file_stat_t) + 30);
- snprintf(st->path, 29, "file_%d" , i );
- st->phash = i;
-
- rc = c_rbtree_insert(csync->local.tree, (void *) st);
- assert_int_equal(rc, 0);
- }
-
- // rc = csync_statedb_write(csync, csync->statedb.db);
- assert_int_equal(rc, 0);
-}
-
-
-static void check_csync_statedb_get_stat_by_hash_not_found(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *tmp;
-
- tmp = csync_statedb_get_stat_by_hash(csync, (uint64_t) 666);
- assert_null(tmp);
-
- free(tmp);
-}
-
-
-static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *tmp;
-
- tmp = csync_statedb_get_stat_by_inode(csync, (ino_t) 666);
- assert_null(tmp);
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
- cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 "torture.h"
+
+#define CSYNC_TEST 1
+#include "csync_statedb.cpp"
+
+#define TESTDB "/tmp/check_csync1/test.db"
+#define TESTDBTMP "/tmp/check_csync1/test.db.ctmp"
+
+
+
+static int setup(void **state)
+{
+ CSYNC *csync;
+ int rc = 0;
+
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ rc = system("mkdir -p /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ csync_create(&csync, "/tmp/check_csync1");
+ csync_init(csync, TESTDB);
+
+ sqlite3 *db = NULL;
+ rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
+ assert_int_equal(rc, SQLITE_OK);
+ rc = sqlite3_close(db);
+ assert_int_equal(rc, SQLITE_OK);
+
+ rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+ assert_int_equal(rc, 0);
+
+ *state = csync;
+
+ return 0;
+}
+
+static int setup_db(void **state)
+{
+ char *errmsg;
+ int rc = 0;
+ sqlite3 *db = NULL;
+
+ const char *sql = "CREATE TABLE IF NOT EXISTS metadata ("
+ "phash INTEGER(8),"
+ "pathlen INTEGER,"
+ "path VARCHAR(4096),"
+ "inode INTEGER,"
+ "uid INTEGER,"
+ "gid INTEGER,"
+ "mode INTEGER,"
+ "modtime INTEGER(8),"
+ "type INTEGER,"
+ "md5 VARCHAR(32),"
+ "PRIMARY KEY(phash)"
+ ");";
+
+ const char *sql2 = "INSERT INTO metadata"
+ "(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5) VALUES"
+ "(42, 42, 'Its funny stuff', 23, 42, 43, 55, 66, 2, 54);";
+
+
+ setup(state);
+ rc = sqlite3_open( TESTDB, &db);
+ assert_int_equal(rc, SQLITE_OK);
+
+ rc = sqlite3_exec( db, sql, NULL, NULL, &errmsg );
+ assert_int_equal(rc, SQLITE_OK);
+
+ rc = sqlite3_exec( db, sql2, NULL, NULL, &errmsg );
+ assert_int_equal(rc, SQLITE_OK);
+
+ sqlite3_close(db);
+
+ return 0;
+
+}
+
+static int teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc = 0;
+
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+ rc = system("rm -rf /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+
+static void check_csync_statedb_query_statement(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ c_strlist_t *result;
+
+ result = csync_statedb_query(csync->statedb.db, "");
+ assert_null(result);
+ if (result != NULL) {
+ c_strlist_destroy(result);
+ }
+
+ result = csync_statedb_query(csync->statedb.db, "SELECT;");
+ assert_null(result);
+ if (result != NULL) {
+ c_strlist_destroy(result);
+ }
+}
+
+static void check_csync_statedb_drop_tables(void **state)
+{
+ // CSYNC *csync = (CSYNC*)*state;
+ int rc = 0;
+ (void) state;
+
+ // rc = csync_statedb_drop_tables(csync->statedb.db);
+ assert_int_equal(rc, 0);
+ // rc = csync_statedb_create_tables(csync->statedb.db);
+ assert_int_equal(rc, 0);
+ // rc = csync_statedb_drop_tables(csync->statedb.db);
+ assert_int_equal(rc, 0);
+}
+
+static void check_csync_statedb_insert_metadata(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ 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 = (csync_file_stat_t*)c_malloc(sizeof(csync_file_stat_t) + 30 );
+ snprintf(st->path, 29, "file_%d" , i );
+ st->phash = i;
+
+ rc = c_rbtree_insert(csync->local.tree, (void *) st);
+ assert_int_equal(rc, 0);
+ }
+
+ // rc = csync_statedb_insert_metadata(csync, csync->statedb.db);
+ assert_int_equal(rc, 0);
+}
+
+static void check_csync_statedb_write(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ int i, rc;
+
+ for (i = 0; i < 100; i++) {
+ st = (csync_file_stat_t*)c_malloc(sizeof(csync_file_stat_t) + 30);
+ snprintf(st->path, 29, "file_%d" , i );
+ st->phash = i;
+
+ rc = c_rbtree_insert(csync->local.tree, (void *) st);
+ assert_int_equal(rc, 0);
+ }
+
+ // rc = csync_statedb_write(csync, csync->statedb.db);
+ assert_int_equal(rc, 0);
+}
+
+
+static void check_csync_statedb_get_stat_by_hash_not_found(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *tmp;
+
+ tmp = csync_statedb_get_stat_by_hash(csync, (uint64_t) 666);
+ assert_null(tmp);
+
+ free(tmp);
+}
+
+
+static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *tmp;
+
+ tmp = csync_statedb_get_stat_by_inode(csync, (ino_t) 666);
+ assert_null(tmp);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+++ /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 "torture.h"
-
-#include "csync_update.c"
-
-#define TESTDB "/tmp/check_csync/journal.db"
-
-static int firstrun = 1;
-
-static void statedb_create_metadata_table(sqlite3 *db)
-{
- int rc = 0;
-
- if( db ) {
- const char *sql = "CREATE TABLE IF NOT EXISTS metadata("
- "phash INTEGER(8),"
- "pathlen INTEGER,"
- "path VARCHAR(4096),"
- "inode INTEGER,"
- "uid INTEGER,"
- "gid INTEGER,"
- "mode INTEGER,"
- "modtime INTEGER(8),"
- "type INTEGER,"
- "md5 VARCHAR(32),"
- "fileid VARCHAR(128),"
- "remotePerm VARCHAR(128),"
- "filesize BIGINT,"
- "ignoredChildrenRemote INT,"
- "contentChecksum TEXT,"
- "contentChecksumTypeId INTEGER,"
- "PRIMARY KEY(phash));";
-
- rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
- //const char *msg = sqlite3_errmsg(db);
- assert_int_equal( rc, SQLITE_OK );
-
- sql = "CREATE TABLE IF NOT EXISTS checksumtype("
- "id INTEGER PRIMARY KEY,"
- "name TEXT UNIQUE"
- ");";
- rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
- assert_int_equal( rc, SQLITE_OK );
- }
-}
-
-static void statedb_insert_metadata(sqlite3 *db)
-{
- int rc = 0;
-
- if( db ) {
- char *stmt = sqlite3_mprintf("INSERT INTO metadata"
- "(phash, pathlen, path, inode, uid, gid, mode, modtime,type,md5) VALUES"
- "(%lld, %d, '%q', %d, %d, %d, %d, %lld, %d, '%q');",
- (long long signed int)42,
- 42,
- "I_was_wurst_before_I_became_wurstsalat",
- 619070,
- 42,
- 42,
- 42,
- (long long signed int)42,
- 0,
- "4711");
-
- char *errmsg;
- rc = sqlite3_exec(db, stmt, NULL, NULL, &errmsg);
- sqlite3_free(stmt);
- assert_int_equal( rc, SQLITE_OK );
- }
-}
-
-static int setup(void **state)
-{
- CSYNC *csync;
- int rc;
-
- unlink(TESTDB);
- rc = system("mkdir -p /tmp/check_csync");
- assert_int_equal(rc, 0);
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
- csync_create(&csync, "/tmp/check_csync1");
- csync_init(csync, TESTDB);
-
- /* Create a new db with metadata */
- sqlite3 *db;
- csync->statedb.file = c_strdup(TESTDB);
- rc = sqlite3_open(csync->statedb.file, &db);
- statedb_create_metadata_table(db);
- if( firstrun ) {
- statedb_insert_metadata(db);
- firstrun = 0;
- }
- sqlite3_close(db);
-
- rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
- assert_int_equal(rc, 0);
-
- *state = csync;
-
- return 0;
-}
-
-static int setup_ftw(void **state)
-{
- CSYNC *csync;
- int rc;
-
- rc = system("mkdir -p /tmp/check_csync");
- assert_int_equal(rc, 0);
- rc = system("mkdir -p /tmp/check_csync1");
- assert_int_equal(rc, 0);
- csync_create(&csync, "/tmp");
- csync_init(csync, TESTDB);
-
- sqlite3 *db = NULL;
- rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
- assert_int_equal(rc, SQLITE_OK);
- statedb_create_metadata_table(db);
- rc = sqlite3_close(db);
- assert_int_equal(rc, SQLITE_OK);
-
- rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
- assert_int_equal(rc, 0);
-
- csync->statedb.file = c_strdup( TESTDB );
- *state = csync;
-
- return 0;
-}
-
-static int teardown(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- unlink( csync->statedb.file);
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
-
- *state = NULL;
-
- return 0;
-}
-
-static int teardown_rm(void **state) {
- int rc;
-
- teardown(state);
-
- rc = system("rm -rf /tmp/check_csync");
- assert_int_equal(rc, 0);
- rc = system("rm -rf /tmp/check_csync1");
- assert_int_equal(rc, 0);
-
- return 0;
-}
-
-/* create a file stat, caller must free memory */
-static csync_vio_file_stat_t* create_fstat(const char *name,
- ino_t inode,
- time_t mtime)
-{
- csync_vio_file_stat_t *fs = NULL;
- time_t t;
-
- fs = csync_vio_file_stat_new();
- if (fs == NULL) {
- return NULL;
- }
-
- if (name && *name) {
- fs->name = c_strdup(name);
- } else {
- fs->name = c_strdup("file.txt");
- }
-
- if (fs->name == NULL) {
- csync_vio_file_stat_destroy(fs);
- return NULL;
- }
-
- fs->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
-
- fs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
- fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
-
-
- if (inode == 0) {
- fs->inode = 619070;
- } else {
- fs->inode = inode;
- }
- fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
-
-
- fs->size = 157459;
- fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
-
-
-
- if (mtime == 0) {
- fs->atime = fs->ctime = fs->mtime = time(&t);
- } else {
- fs->atime = fs->ctime = fs->mtime = mtime;
- }
- fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
- fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
- fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
-
- return fs;
-}
-
-static int failing_fn(CSYNC *ctx,
- const char *file,
- const csync_vio_file_stat_t *fs,
- enum csync_ftw_flags_e flag)
-{
- (void) ctx;
- (void) file;
- (void) fs;
- (void) flag;
-
- return -1;
-}
-
-/* detect a new file */
-static void check_csync_detect_update(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *st;
- csync_vio_file_stat_t *fs;
- int rc;
-
- fs = create_fstat("file.txt", 0, 1217597845);
- assert_non_null(fs);
-
- rc = _csync_detect_update(csync,
- "/tmp/check_csync1/file.txt",
- fs,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, 0);
-
- /* the instruction should be set to new */
- st = c_rbtree_node_data(csync->local.tree->root);
- assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
-
- /* create a statedb */
- csync_set_status(csync, 0xFFFF);
-
- csync_vio_file_stat_destroy(fs);
-}
-
-/* Test behaviour in case no db is there. For that its important that the
- * test before this one uses teardown_rm.
- */
-static void check_csync_detect_update_db_none(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *st;
- csync_vio_file_stat_t *fs;
- int rc;
-
- fs = create_fstat("file.txt", 0, 1217597845);
- assert_non_null(fs);
-
- rc = _csync_detect_update(csync,
- "/tmp/check_csync1/file.txt",
- fs,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, 0);
-
- /* the instruction should be set to new */
- st = c_rbtree_node_data(csync->local.tree->root);
- assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
-
-
- /* create a statedb */
- csync_set_status(csync, 0xFFFF);
-
- csync_vio_file_stat_destroy(fs);
-}
-
-static void check_csync_detect_update_db_eval(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *st;
- csync_vio_file_stat_t *fs;
- int rc;
-
- fs = create_fstat("file.txt", 0, 42);
- assert_non_null(fs);
-
- rc = _csync_detect_update(csync,
- "/tmp/check_csync1/file.txt",
- fs,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, 0);
-
- /* the instruction should be set to new */
- st = c_rbtree_node_data(csync->local.tree->root);
- assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
-
- /* create a statedb */
- csync_set_status(csync, 0xFFFF);
-
- csync_vio_file_stat_destroy(fs);
-}
-
-
-static void check_csync_detect_update_db_rename(void **state)
-{
- CSYNC *csync = *state;
- // csync_file_stat_t *st;
-
- csync_vio_file_stat_t *fs;
- int rc = 0;
-
- fs = create_fstat("wurst.txt", 0, 42);
- assert_non_null(fs);
- csync_set_statedb_exists(csync, 1);
-
- rc = _csync_detect_update(csync,
- "/tmp/check_csync1/wurst.txt",
- fs,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, 0);
-
- /* the instruction should be set to rename */
- /*
- * temporarily broken.
- st = c_rbtree_node_data(csync->local.tree->root);
- assert_int_equal(st->instruction, CSYNC_INSTRUCTION_RENAME);
-
- st->instruction = CSYNC_INSTRUCTION_UPDATED;
- */
- /* create a statedb */
- csync_set_status(csync, 0xFFFF);
-
- csync_vio_file_stat_destroy(fs);
-}
-
-static void check_csync_detect_update_db_new(void **state)
-{
- CSYNC *csync = *state;
- csync_file_stat_t *st;
- csync_vio_file_stat_t *fs;
- int rc;
-
- fs = create_fstat("file.txt", 42000, 0);
- assert_non_null(fs);
-
- rc = _csync_detect_update(csync,
- "/tmp/check_csync1/file.txt",
- fs,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, 0);
-
- /* the instruction should be set to new */
- st = c_rbtree_node_data(csync->local.tree->root);
- assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
-
-
- /* create a statedb */
- csync_set_status(csync, 0xFFFF);
-
- csync_vio_file_stat_destroy(fs);
-}
-
-static void check_csync_detect_update_null(void **state)
-{
- CSYNC *csync = *state;
- csync_vio_file_stat_t *fs;
- int rc;
-
- fs = create_fstat("file.txt", 0, 0);
- assert_non_null(fs);
-
- rc = _csync_detect_update(csync,
- NULL,
- fs,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, -1);
-
- rc = _csync_detect_update(csync,
- "/tmp/check_csync1/file.txt",
- NULL,
- CSYNC_FTW_TYPE_FILE);
- assert_int_equal(rc, -1);
-
- csync_vio_file_stat_destroy(fs);
-}
-
-static void check_csync_ftw(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_ftw(csync, "/tmp", csync_walker, MAX_DEPTH);
- assert_int_equal(rc, 0);
-}
-
-static void check_csync_ftw_empty_uri(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_ftw(csync, "", csync_walker, MAX_DEPTH);
- assert_int_equal(rc, -1);
-}
-
-static void check_csync_ftw_failing_fn(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_ftw(csync, "/tmp", failing_fn, MAX_DEPTH);
- assert_int_equal(rc, -1);
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
- cmocka_unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
- cmocka_unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
- cmocka_unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
-
- cmocka_unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
- cmocka_unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
- cmocka_unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 "torture.h"
+
+#include "csync_update.cpp"
+
+#define TESTDB "/tmp/check_csync/journal.db"
+
+static int firstrun = 1;
+
+static void statedb_create_metadata_table(sqlite3 *db)
+{
+ int rc = 0;
+
+ if( db ) {
+ const char *sql = "CREATE TABLE IF NOT EXISTS metadata("
+ "phash INTEGER(8),"
+ "pathlen INTEGER,"
+ "path VARCHAR(4096),"
+ "inode INTEGER,"
+ "uid INTEGER,"
+ "gid INTEGER,"
+ "mode INTEGER,"
+ "modtime INTEGER(8),"
+ "type INTEGER,"
+ "md5 VARCHAR(32),"
+ "fileid VARCHAR(128),"
+ "remotePerm VARCHAR(128),"
+ "filesize BIGINT,"
+ "ignoredChildrenRemote INT,"
+ "contentChecksum TEXT,"
+ "contentChecksumTypeId INTEGER,"
+ "PRIMARY KEY(phash));";
+
+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+ //const char *msg = sqlite3_errmsg(db);
+ assert_int_equal( rc, SQLITE_OK );
+
+ sql = "CREATE TABLE IF NOT EXISTS checksumtype("
+ "id INTEGER PRIMARY KEY,"
+ "name TEXT UNIQUE"
+ ");";
+ rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+ assert_int_equal( rc, SQLITE_OK );
+ }
+}
+
+static void statedb_insert_metadata(sqlite3 *db)
+{
+ int rc = 0;
+
+ if( db ) {
+ char *stmt = sqlite3_mprintf("INSERT INTO metadata"
+ "(phash, pathlen, path, inode, uid, gid, mode, modtime,type,md5) VALUES"
+ "(%lld, %d, '%q', %d, %d, %d, %d, %lld, %d, '%q');",
+ (long long signed int)42,
+ 42,
+ "I_was_wurst_before_I_became_wurstsalat",
+ 619070,
+ 42,
+ 42,
+ 42,
+ (long long signed int)42,
+ 0,
+ "4711");
+
+ char *errmsg;
+ rc = sqlite3_exec(db, stmt, NULL, NULL, &errmsg);
+ sqlite3_free(stmt);
+ assert_int_equal( rc, SQLITE_OK );
+ }
+}
+
+static int setup(void **state)
+{
+ CSYNC *csync;
+ int rc;
+
+ unlink(TESTDB);
+ rc = system("mkdir -p /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ csync_create(&csync, "/tmp/check_csync1");
+ csync_init(csync, TESTDB);
+
+ /* Create a new db with metadata */
+ sqlite3 *db;
+ csync->statedb.file = c_strdup(TESTDB);
+ rc = sqlite3_open(csync->statedb.file, &db);
+ statedb_create_metadata_table(db);
+ if( firstrun ) {
+ statedb_insert_metadata(db);
+ firstrun = 0;
+ }
+ sqlite3_close(db);
+
+ rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+ assert_int_equal(rc, 0);
+
+ *state = csync;
+
+ return 0;
+}
+
+static int setup_ftw(void **state)
+{
+ CSYNC *csync;
+ int rc;
+
+ rc = system("mkdir -p /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("mkdir -p /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+ csync_create(&csync, "/tmp");
+ csync_init(csync, TESTDB);
+
+ sqlite3 *db = NULL;
+ rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
+ assert_int_equal(rc, SQLITE_OK);
+ statedb_create_metadata_table(db);
+ rc = sqlite3_close(db);
+ assert_int_equal(rc, SQLITE_OK);
+
+ rc = csync_statedb_load(csync, TESTDB, &csync->statedb.db);
+ assert_int_equal(rc, 0);
+
+ csync->statedb.file = c_strdup( TESTDB );
+ *state = csync;
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ unlink( csync->statedb.file);
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+
+ return 0;
+}
+
+static int teardown_rm(void **state) {
+ int rc;
+
+ teardown(state);
+
+ rc = system("rm -rf /tmp/check_csync");
+ assert_int_equal(rc, 0);
+ rc = system("rm -rf /tmp/check_csync1");
+ assert_int_equal(rc, 0);
+
+ return 0;
+}
+
+/* create a file stat, caller must free memory */
+static csync_vio_file_stat_t* create_fstat(const char *name,
+ ino_t inode,
+ time_t mtime)
+{
+ csync_vio_file_stat_t *fs = NULL;
+ time_t t;
+
+ fs = csync_vio_file_stat_new();
+ if (fs == NULL) {
+ return NULL;
+ }
+
+ if (name && *name) {
+ fs->name = c_strdup(name);
+ } else {
+ fs->name = c_strdup("file.txt");
+ }
+
+ if (fs->name == NULL) {
+ csync_vio_file_stat_destroy(fs);
+ return NULL;
+ }
+
+ fs->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
+
+ fs->type = CSYNC_VIO_FILE_TYPE_REGULAR;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
+
+
+ if (inode == 0) {
+ fs->inode = 619070;
+ } else {
+ fs->inode = inode;
+ }
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
+
+
+ fs->size = 157459;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
+
+
+
+ if (mtime == 0) {
+ fs->atime = fs->ctime = fs->mtime = time(&t);
+ } else {
+ fs->atime = fs->ctime = fs->mtime = mtime;
+ }
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
+ fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
+
+ return fs;
+}
+
+static int failing_fn(CSYNC *ctx,
+ const char *file,
+ const csync_vio_file_stat_t *fs,
+ int flag)
+{
+ (void) ctx;
+ (void) file;
+ (void) fs;
+ (void) flag;
+
+ return -1;
+}
+
+/* detect a new file */
+static void check_csync_detect_update(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 1217597845);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+/* Test behaviour in case no db is there. For that its important that the
+ * test before this one uses teardown_rm.
+ */
+static void check_csync_detect_update_db_none(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 1217597845);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_detect_update_db_eval(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 42);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+
+static void check_csync_detect_update_db_rename(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ // csync_file_stat_t *st;
+
+ csync_vio_file_stat_t *fs;
+ int rc = 0;
+
+ fs = create_fstat("wurst.txt", 0, 42);
+ assert_non_null(fs);
+ csync_set_statedb_exists(csync, 1);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/wurst.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, 0);
+
+ /* the instruction should be set to rename */
+ /*
+ * temporarily broken.
+ st = (csync_file_stat_t*)c_rbtree_node_data(csync->local.tree->root);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_RENAME);
+
+ st->instruction = CSYNC_INSTRUCTION_UPDATED;
+ */
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_detect_update_db_new(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_file_stat_t *st;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 42000, 0);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ 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);
+ assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
+
+
+ /* create a statedb */
+ csync_set_status(csync, 0xFFFF);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_detect_update_null(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_vio_file_stat_t *fs;
+ int rc;
+
+ fs = create_fstat("file.txt", 0, 0);
+ assert_non_null(fs);
+
+ rc = _csync_detect_update(csync,
+ NULL,
+ fs,
+ CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, -1);
+
+ rc = _csync_detect_update(csync,
+ "/tmp/check_csync1/file.txt",
+ NULL,
+ CSYNC_FTW_TYPE_FILE);
+ assert_int_equal(rc, -1);
+
+ csync_vio_file_stat_destroy(fs);
+}
+
+static void check_csync_ftw(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_ftw(csync, "/tmp", csync_walker, MAX_DEPTH);
+ assert_int_equal(rc, 0);
+}
+
+static void check_csync_ftw_empty_uri(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_ftw(csync, "", csync_walker, MAX_DEPTH);
+ assert_int_equal(rc, -1);
+}
+
+static void check_csync_ftw_failing_fn(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_ftw(csync, "/tmp", failing_fn, MAX_DEPTH);
+ assert_int_equal(rc, -1);
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
+
+ cmocka_unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
+ cmocka_unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+++ /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 "torture.h"
-
-#include "csync_util.h"
-
-static void check_csync_instruction_str(void **state)
-{
- const char *str;
-
- (void) state; /* unused */
-
- str = csync_instruction_str(CSYNC_INSTRUCTION_ERROR);
- assert_string_equal(str, "INSTRUCTION_ERROR");
-
- str = csync_instruction_str(0xFFFF);
- assert_string_equal(str, "ERROR!");
-}
-
-static void check_csync_memstat(void **state)
-{
- (void) state; /* unused */
-
- csync_memstat_check();
-}
-
-int torture_run_tests(void)
-{
- const struct CMUnitTest tests[] = {
- cmocka_unit_test(check_csync_instruction_str),
- cmocka_unit_test(check_csync_memstat),
- };
-
- return cmocka_run_group_tests(tests, NULL, NULL);
-}
-
--- /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 "torture.h"
+
+#include "csync_util.h"
+
+static void check_csync_instruction_str(void **state)
+{
+ const char *str;
+
+ (void) state; /* unused */
+
+ str = csync_instruction_str(CSYNC_INSTRUCTION_ERROR);
+ assert_string_equal(str, "INSTRUCTION_ERROR");
+
+ str = csync_instruction_str((enum csync_instructions_e)0xFFFF);
+ assert_string_equal(str, "ERROR!");
+}
+
+static void check_csync_memstat(void **state)
+{
+ (void) state; /* unused */
+
+ csync_memstat_check();
+}
+
+int torture_run_tests(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(check_csync_instruction_str),
+ cmocka_unit_test(check_csync_memstat),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 "torture.h"
-#include <stdio.h>
-#include "c_string.h"
-#include "c_path.h"
-
-#ifdef _WIN32
-#include <string.h>
-#endif
-
-
-static void setup(void **state)
-{
- (void) state; /* unused */
-}
-
-static void teardown(void **state)
-{
- (void) state; /* unused */
-}
-
-static void check_iconv_to_native_normalization(void **state)
-{
- mbchar_t *out = NULL;
- const char *in= "\x48\xc3\xa4"; // UTF8
-#ifdef __APPLE__
- const char *exp_out = "\x48\x61\xcc\x88"; // UTF-8-MAC
-#else
- const char *exp_out = "\x48\xc3\xa4"; // UTF8
-#endif
-
- out = c_utf8_path_to_locale(in);
- assert_string_equal(out, exp_out);
-
- c_free_locale_string(out);
- assert_null(out);
-
- (void) state; /* unused */
-}
-
-static void check_iconv_from_native_normalization(void **state)
-{
- char *out = NULL;
-#ifdef _WIN32
- const mbchar_t *in = L"\x48\xc3\xa4"; // UTF-8
-#else
-#ifdef __APPLE__
- const mbchar_t *in = "\x48\x61\xcc\x88"; // UTF-8-MAC
-#else
- const mbchar_t *in = "\x48\xc3\xa4"; // UTF-8
-#endif
-#endif
- const char *exp_out = "\x48\xc3\xa4"; // UTF-8
-
- out = c_utf8_from_locale(in);
- assert_string_equal(out, exp_out);
-
- c_free_locale_string(out);
- assert_null(out);
-
- (void) state; /* unused */
-}
-
-static void check_iconv_ascii(void **state)
-{
-#ifdef _WIN32
- const mbchar_t *in = L"abc/ABC\\123"; // UTF-8
-#else
-#ifdef __APPLE__
- const mbchar_t *in = "abc/ABC\\123"; // UTF-8-MAC
-#else
- const mbchar_t *in = "abc/ABC\\123"; // UTF-8
-#endif
-#endif
- char *out = NULL;
- const char *exp_out = "abc/ABC\\123";
-
- out = c_utf8_from_locale(in);
- assert_string_equal(out, exp_out);
-
- c_free_locale_string(out);
- assert_null(out);
-
- (void) state; /* unused */
-}
-
-#define TESTSTRING "#cA\\#fß§4"
-#define LTESTSTRING L"#cA\\#fß§4"
-
-static void check_to_multibyte(void **state)
-{
- int rc = -1;
-
- mbchar_t *mb_string = c_utf8_path_to_locale( TESTSTRING );
- mbchar_t *mb_null = c_utf8_path_to_locale( NULL );
-
- (void) state;
-
-#ifdef _WIN32
- assert_int_equal( wcscmp( LTESTSTRING, mb_string), 0 );
-#else
- assert_string_equal(mb_string, TESTSTRING);
-#endif
- assert_true( mb_null == NULL );
- assert_int_equal(rc, -1);
-
- c_free_locale_string(mb_string);
- c_free_locale_string(mb_null);
-}
-
-static void check_long_win_path(void **state)
-{
- (void) state; /* unused */
-
- {
- const char *path = "C://DATA/FILES/MUSIC/MY_MUSIC.mp3"; // check a short path
- const char *exp_path = "\\\\?\\C:\\\\DATA\\FILES\\MUSIC\\MY_MUSIC.mp3";
- const char *new_short = c_path_to_UNC(path);
- assert_string_equal(new_short, exp_path);
- SAFE_FREE(new_short);
- }
-
- {
- const char *path = "\\\\foo\\bar/MY_MUSIC.mp3";
- const char *exp_path = "\\\\foo\\bar\\MY_MUSIC.mp3";
- const char *new_short = c_path_to_UNC(path);
- assert_string_equal(new_short, exp_path);
- SAFE_FREE(new_short);
- }
-
- {
- const char *path = "//foo\\bar/MY_MUSIC.mp3";
- const char *exp_path = "\\\\foo\\bar\\MY_MUSIC.mp3";
- const char *new_short = c_path_to_UNC(path);
- assert_string_equal(new_short, exp_path);
- SAFE_FREE(new_short);
- }
-
- {
- const char *path = "\\foo\\bar";
- const char *exp_path = "\\\\?\\foo\\bar";
- const char *new_short = c_path_to_UNC(path);
- assert_string_equal(new_short, exp_path);
- SAFE_FREE(new_short);
- }
-
- {
- const char *path = "/foo/bar";
- const char *exp_path = "\\\\?\\foo\\bar";
- const char *new_short = c_path_to_UNC(path);
- assert_string_equal(new_short, exp_path);
- SAFE_FREE(new_short);
- }
-
- const char *longPath = "D://alonglonglonglong/blonglonglonglong/clonglonglonglong/dlonglonglonglong/"
- "elonglonglonglong/flonglonglonglong/glonglonglonglong/hlonglonglonglong/ilonglonglonglong/"
- "jlonglonglonglong/klonglonglonglong/llonglonglonglong/mlonglonglonglong/nlonglonglonglong/"
- "olonglonglonglong/file.txt";
- const char *longPathConv = "\\\\?\\D:\\\\alonglonglonglong\\blonglonglonglong\\clonglonglonglong\\dlonglonglonglong\\"
- "elonglonglonglong\\flonglonglonglong\\glonglonglonglong\\hlonglonglonglong\\ilonglonglonglong\\"
- "jlonglonglonglong\\klonglonglonglong\\llonglonglonglong\\mlonglonglonglong\\nlonglonglonglong\\"
- "olonglonglonglong\\file.txt";
-
- const char *new_long = c_path_to_UNC(longPath);
- // printf( "XXXXXXXXXXXX %s %d\n", new_long, mem_reserved);
-
- assert_string_equal(new_long, longPathConv);
-
- // printf( "YYYYYYYYYYYY %ld\n", strlen(new_long));
- assert_int_equal( strlen(new_long), 286);
- SAFE_FREE(new_long);
-}
-
-int torture_run_tests(void)
-{
- const UnitTest tests[] = {
- unit_test_setup_teardown(check_long_win_path, setup, teardown),
- unit_test_setup_teardown(check_to_multibyte, setup, teardown),
- unit_test_setup_teardown(check_iconv_ascii, setup, teardown),
- unit_test_setup_teardown(check_iconv_to_native_normalization, setup, teardown),
- unit_test_setup_teardown(check_iconv_from_native_normalization, setup, teardown),
-
- };
-
- return run_tests(tests);
-}
-
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 "torture.h"
+#include <stdio.h>
+#include "c_string.h"
+#include "c_path.h"
+
+#ifdef _WIN32
+#include <string.h>
+#endif
+
+
+static void setup(void **state)
+{
+ (void) state; /* unused */
+}
+
+static void teardown(void **state)
+{
+ (void) state; /* unused */
+}
+
+static void check_iconv_to_native_normalization(void **state)
+{
+ mbchar_t *out = NULL;
+ const char *in= "\x48\xc3\xa4"; // UTF8
+#ifdef __APPLE__
+ const char *exp_out = "\x48\x61\xcc\x88"; // UTF-8-MAC
+#else
+ const char *exp_out = "\x48\xc3\xa4"; // UTF8
+#endif
+
+ out = c_utf8_path_to_locale(in);
+ assert_string_equal(out, exp_out);
+
+ c_free_locale_string(out);
+ assert_null(out);
+
+ (void) state; /* unused */
+}
+
+static void check_iconv_from_native_normalization(void **state)
+{
+ char *out = NULL;
+#ifdef _WIN32
+ const mbchar_t *in = L"\x48\xc3\xa4"; // UTF-8
+#else
+#ifdef __APPLE__
+ const mbchar_t *in = "\x48\x61\xcc\x88"; // UTF-8-MAC
+#else
+ const mbchar_t *in = "\x48\xc3\xa4"; // UTF-8
+#endif
+#endif
+ const char *exp_out = "\x48\xc3\xa4"; // UTF-8
+
+ out = c_utf8_from_locale(in);
+ assert_string_equal(out, exp_out);
+
+ c_free_locale_string(out);
+ assert_null(out);
+
+ (void) state; /* unused */
+}
+
+static void check_iconv_ascii(void **state)
+{
+#ifdef _WIN32
+ const mbchar_t *in = L"abc/ABC\\123"; // UTF-8
+#else
+#ifdef __APPLE__
+ const mbchar_t *in = "abc/ABC\\123"; // UTF-8-MAC
+#else
+ const mbchar_t *in = "abc/ABC\\123"; // UTF-8
+#endif
+#endif
+ char *out = NULL;
+ const char *exp_out = "abc/ABC\\123";
+
+ out = c_utf8_from_locale(in);
+ assert_string_equal(out, exp_out);
+
+ c_free_locale_string(out);
+ assert_null(out);
+
+ (void) state; /* unused */
+}
+
+#define TESTSTRING "#cA\\#fß§4"
+#define LTESTSTRING L"#cA\\#fß§4"
+
+static void check_to_multibyte(void **state)
+{
+ int rc = -1;
+
+ mbchar_t *mb_string = c_utf8_path_to_locale( TESTSTRING );
+ mbchar_t *mb_null = c_utf8_path_to_locale( NULL );
+
+ (void) state;
+
+#ifdef _WIN32
+ assert_int_equal( wcscmp( LTESTSTRING, mb_string), 0 );
+#else
+ assert_string_equal(mb_string, TESTSTRING);
+#endif
+ assert_true( mb_null == NULL );
+ assert_int_equal(rc, -1);
+
+ c_free_locale_string(mb_string);
+ c_free_locale_string(mb_null);
+}
+
+static void check_long_win_path(void **state)
+{
+ (void) state; /* unused */
+
+ {
+ const char *path = "C://DATA/FILES/MUSIC/MY_MUSIC.mp3"; // check a short path
+ const char *exp_path = "\\\\?\\C:\\\\DATA\\FILES\\MUSIC\\MY_MUSIC.mp3";
+ const char *new_short = c_path_to_UNC(path);
+ assert_string_equal(new_short, exp_path);
+ SAFE_FREE(new_short);
+ }
+
+ {
+ const char *path = "\\\\foo\\bar/MY_MUSIC.mp3";
+ const char *exp_path = "\\\\foo\\bar\\MY_MUSIC.mp3";
+ const char *new_short = c_path_to_UNC(path);
+ assert_string_equal(new_short, exp_path);
+ SAFE_FREE(new_short);
+ }
+
+ {
+ const char *path = "//foo\\bar/MY_MUSIC.mp3";
+ const char *exp_path = "\\\\foo\\bar\\MY_MUSIC.mp3";
+ const char *new_short = c_path_to_UNC(path);
+ assert_string_equal(new_short, exp_path);
+ SAFE_FREE(new_short);
+ }
+
+ {
+ const char *path = "\\foo\\bar";
+ const char *exp_path = "\\\\?\\foo\\bar";
+ const char *new_short = c_path_to_UNC(path);
+ assert_string_equal(new_short, exp_path);
+ SAFE_FREE(new_short);
+ }
+
+ {
+ const char *path = "/foo/bar";
+ const char *exp_path = "\\\\?\\foo\\bar";
+ const char *new_short = c_path_to_UNC(path);
+ assert_string_equal(new_short, exp_path);
+ SAFE_FREE(new_short);
+ }
+
+ const char *longPath = "D://alonglonglonglong/blonglonglonglong/clonglonglonglong/dlonglonglonglong/"
+ "elonglonglonglong/flonglonglonglong/glonglonglonglong/hlonglonglonglong/ilonglonglonglong/"
+ "jlonglonglonglong/klonglonglonglong/llonglonglonglong/mlonglonglonglong/nlonglonglonglong/"
+ "olonglonglonglong/file.txt";
+ const char *longPathConv = "\\\\?\\D:\\\\alonglonglonglong\\blonglonglonglong\\clonglonglonglong\\dlonglonglonglong\\"
+ "elonglonglonglong\\flonglonglonglong\\glonglonglonglong\\hlonglonglonglong\\ilonglonglonglong\\"
+ "jlonglonglonglong\\klonglonglonglong\\llonglonglonglong\\mlonglonglonglong\\nlonglonglonglong\\"
+ "olonglonglonglong\\file.txt";
+
+ const char *new_long = c_path_to_UNC(longPath);
+ // printf( "XXXXXXXXXXXX %s %d\n", new_long, mem_reserved);
+
+ assert_string_equal(new_long, longPathConv);
+
+ // printf( "YYYYYYYYYYYY %ld\n", strlen(new_long));
+ assert_int_equal( strlen(new_long), 286);
+ SAFE_FREE(new_long);
+}
+
+int torture_run_tests(void)
+{
+ const UnitTest tests[] = {
+ unit_test_setup_teardown(check_long_win_path, setup, teardown),
+ unit_test_setup_teardown(check_to_multibyte, setup, teardown),
+ unit_test_setup_teardown(check_iconv_ascii, setup, teardown),
+ unit_test_setup_teardown(check_iconv_to_native_normalization, setup, teardown),
+ unit_test_setup_teardown(check_iconv_from_native_normalization, setup, teardown),
+
+ };
+
+ return run_tests(tests);
+}
+
+++ /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 <string.h>
-
-#include "support.h"
-
-#include "config_csync.h"
-#include "csync_log.h"
-
-static void setup(void) {
- csync_log_init();
-}
-
-static void teardown(void) {
- csync_log_fini();
-}
-
-START_TEST (log_create)
-{
- fail_unless((csync_log_init() == 0), NULL);
- fail_unless((csync_log_fini() == 0), NULL);
-}
-END_TEST
-
-START_TEST (log_load)
-{
- char buf[256];
- snprintf(buf, (size_t) 256 - 1, "%s/%s", SOURCEDIR, "config/ocsync_log.conf");
- fail_unless(csync_log_load(buf) == 0);
-}
-END_TEST
-
-START_TEST (log_prio)
-{
- CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTSET, "log %s", "test");
- CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", "test");
-}
-END_TEST
-
-START_TEST (log_null)
-{
- char *z = NULL;
- CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", z);
-}
-END_TEST
-
-static Suite *log_suite(void) {
- Suite *s = suite_create("Logger");
-
- create_case(s, "log_create", log_create);
- create_case_fixture(s, "log_load", log_load, setup, teardown);
- create_case_fixture(s, "log_prio", log_prio, setup, teardown);
- create_case_fixture(s, "log_null", log_null, setup, teardown);
-
- return s;
-}
-
-int main(void) {
- int nf;
-
- Suite *s = log_suite();
-
- SRunner *sr;
- sr = srunner_create(s);
- srunner_run_all(sr, CK_VERBOSE);
- nf = srunner_ntests_failed(sr);
- srunner_free(sr);
-
- return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
--- /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 <string.h>
+
+#include "support.h"
+
+#include "config_csync.h"
+#include "csync_log.h"
+
+static void setup(void) {
+ csync_log_init();
+}
+
+static void teardown(void) {
+ csync_log_fini();
+}
+
+START_TEST (log_create)
+{
+ fail_unless((csync_log_init() == 0), NULL);
+ fail_unless((csync_log_fini() == 0), NULL);
+}
+END_TEST
+
+START_TEST (log_load)
+{
+ char buf[256];
+ snprintf(buf, (size_t) 256 - 1, "%s/%s", SOURCEDIR, "config/ocsync_log.conf");
+ fail_unless(csync_log_load(buf) == 0);
+}
+END_TEST
+
+START_TEST (log_prio)
+{
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTSET, "log %s", "test");
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", "test");
+}
+END_TEST
+
+START_TEST (log_null)
+{
+ char *z = NULL;
+ CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", z);
+}
+END_TEST
+
+static Suite *log_suite(void) {
+ Suite *s = suite_create("Logger");
+
+ create_case(s, "log_create", log_create);
+ create_case_fixture(s, "log_load", log_load, setup, teardown);
+ create_case_fixture(s, "log_prio", log_prio, setup, teardown);
+ create_case_fixture(s, "log_null", log_null, setup, teardown);
+
+ return s;
+}
+
+int main(void) {
+ int nf;
+
+ Suite *s = log_suite();
+
+ SRunner *sr;
+ sr = srunner_create(s);
+ srunner_run_all(sr, CK_VERBOSE);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
#ifndef _TORTURE_H
#define _TORTURE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
*/
int torture_run_tests(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _TORTURE_H */
+++ /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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-
-#include "torture.h"
-
-#include "csync_private.h"
-#include "vio/csync_vio.h"
-
-#define CSYNC_TEST_DIR "/tmp/csync_test/"
-#define CSYNC_TEST_DIRS "/tmp/csync_test/this/is/a/mkdirs/test"
-#define CSYNC_TEST_FILE "/tmp/csync_test/file.txt"
-
-#define MKDIR_MASK (S_IRWXU |S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
-
-#define WD_BUFFER_SIZE 255
-
-static char wd_buffer[WD_BUFFER_SIZE];
-
-static void setup(void **state)
-{
- CSYNC *csync;
- int rc;
-
- assert_non_null(getcwd(wd_buffer, WD_BUFFER_SIZE));
-
- rc = system("rm -rf /tmp/csync_test");
- assert_int_equal(rc, 0);
-
- csync_create(&csync, "/tmp/csync1");
-
- csync->replica = LOCAL_REPLICA;
-
- *state = csync;
-}
-
-static void setup_dir(void **state) {
- int rc;
- mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
-
- setup(state);
-
- rc = _tmkdir(dir, MKDIR_MASK);
- c_free_locale_string(dir);
- assert_int_equal(rc, 0);
-
- assert_non_null(getcwd(wd_buffer, WD_BUFFER_SIZE));
-
- rc = chdir(CSYNC_TEST_DIR);
- assert_int_equal(rc, 0);
-}
-
-static void teardown(void **state) {
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
-
- rc = chdir(wd_buffer);
- assert_int_equal(rc, 0);
-
- rc = system("rm -rf /tmp/csync_test/");
- assert_int_equal(rc, 0);
-
- *state = NULL;
-}
-
-
-/*
- * Test directory function
- */
-
-static void check_csync_vio_opendir(void **state)
-{
- CSYNC *csync = *state;
- csync_vio_handle_t *dh;
- int rc;
-
- dh = csync_vio_opendir(csync, CSYNC_TEST_DIR);
- assert_non_null(dh);
-
- rc = csync_vio_closedir(csync, dh);
- assert_int_equal(rc, 0);
-}
-
-static void check_csync_vio_opendir_perm(void **state)
-{
- CSYNC *csync = *state;
- csync_vio_handle_t *dh;
- int rc;
- mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
-
- assert_non_null(dir);
-
- rc = _tmkdir(dir, (S_IWUSR|S_IXUSR));
- assert_int_equal(rc, 0);
-
- dh = csync_vio_opendir(csync, CSYNC_TEST_DIR);
- assert_null(dh);
- assert_int_equal(errno, EACCES);
-
- _tchmod(dir, MKDIR_MASK);
- c_free_locale_string(dir);
-}
-
-static void check_csync_vio_closedir_null(void **state)
-{
- CSYNC *csync = *state;
- int rc;
-
- rc = csync_vio_closedir(csync, NULL);
- assert_int_equal(rc, -1);
-}
-
-static void check_csync_vio_readdir(void **state)
-{
- CSYNC *csync = *state;
- csync_vio_handle_t *dh;
- csync_vio_file_stat_t *dirent;
- int rc;
-
- dh = csync_vio_opendir(csync, CSYNC_TEST_DIR);
- assert_non_null(dh);
-
- dirent = csync_vio_readdir(csync, dh);
- assert_non_null(dirent);
-
- csync_vio_file_stat_destroy(dirent);
- rc = csync_vio_closedir(csync, dh);
- assert_int_equal(rc, 0);
-}
-
-
-int torture_run_tests(void)
-{
- const UnitTest tests[] = {
- unit_test_setup_teardown(check_csync_vio_opendir, setup_dir, teardown),
- unit_test_setup_teardown(check_csync_vio_opendir_perm, setup, teardown),
- unit_test(check_csync_vio_closedir_null),
- unit_test_setup_teardown(check_csync_vio_readdir, setup_dir, teardown),
- };
-
- return run_tests(tests);
-}
-
--- /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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "torture.h"
+
+#include "csync_private.h"
+#include "vio/csync_vio.h"
+
+#define CSYNC_TEST_DIR "/tmp/csync_test/"
+#define CSYNC_TEST_DIRS "/tmp/csync_test/this/is/a/mkdirs/test"
+#define CSYNC_TEST_FILE "/tmp/csync_test/file.txt"
+
+#define MKDIR_MASK (S_IRWXU |S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+
+#define WD_BUFFER_SIZE 255
+
+static char wd_buffer[WD_BUFFER_SIZE];
+
+static void setup(void **state)
+{
+ CSYNC *csync;
+ int rc;
+
+ assert_non_null(getcwd(wd_buffer, WD_BUFFER_SIZE));
+
+ rc = system("rm -rf /tmp/csync_test");
+ assert_int_equal(rc, 0);
+
+ csync_create(&csync, "/tmp/csync1");
+
+ csync->replica = LOCAL_REPLICA;
+
+ *state = csync;
+}
+
+static void setup_dir(void **state) {
+ int rc;
+ mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
+
+ setup(state);
+
+ rc = _tmkdir(dir, MKDIR_MASK);
+ c_free_locale_string(dir);
+ assert_int_equal(rc, 0);
+
+ assert_non_null(getcwd(wd_buffer, WD_BUFFER_SIZE));
+
+ rc = chdir(CSYNC_TEST_DIR);
+ assert_int_equal(rc, 0);
+}
+
+static void teardown(void **state) {
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+
+ rc = chdir(wd_buffer);
+ assert_int_equal(rc, 0);
+
+ rc = system("rm -rf /tmp/csync_test/");
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+}
+
+
+/*
+ * Test directory function
+ */
+
+static void check_csync_vio_opendir(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_vio_handle_t *dh;
+ int rc;
+
+ dh = csync_vio_opendir(csync, CSYNC_TEST_DIR);
+ assert_non_null(dh);
+
+ rc = csync_vio_closedir(csync, dh);
+ assert_int_equal(rc, 0);
+}
+
+static void check_csync_vio_opendir_perm(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_vio_handle_t *dh;
+ int rc;
+ mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
+
+ assert_non_null(dir);
+
+ rc = _tmkdir(dir, (S_IWUSR|S_IXUSR));
+ assert_int_equal(rc, 0);
+
+ dh = csync_vio_opendir(csync, CSYNC_TEST_DIR);
+ assert_null(dh);
+ assert_int_equal(errno, EACCES);
+
+ _tchmod(dir, MKDIR_MASK);
+ c_free_locale_string(dir);
+}
+
+static void check_csync_vio_closedir_null(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ int rc;
+
+ rc = csync_vio_closedir(csync, NULL);
+ assert_int_equal(rc, -1);
+}
+
+static void check_csync_vio_readdir(void **state)
+{
+ CSYNC *csync = (CSYNC*)*state;
+ csync_vio_handle_t *dh;
+ csync_vio_file_stat_t *dirent;
+ int rc;
+
+ dh = csync_vio_opendir(csync, CSYNC_TEST_DIR);
+ assert_non_null(dh);
+
+ dirent = csync_vio_readdir(csync, dh);
+ assert_non_null(dirent);
+
+ csync_vio_file_stat_destroy(dirent);
+ rc = csync_vio_closedir(csync, dh);
+ assert_int_equal(rc, 0);
+}
+
+
+int torture_run_tests(void)
+{
+ const UnitTest tests[] = {
+ unit_test_setup_teardown(check_csync_vio_opendir, setup_dir, teardown),
+ unit_test_setup_teardown(check_csync_vio_opendir_perm, setup, teardown),
+ unit_test(check_csync_vio_closedir_null),
+ unit_test_setup_teardown(check_csync_vio_readdir, setup_dir, teardown),
+ };
+
+ return run_tests(tests);
+}
+++ /dev/null
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2015-2013 by Klaas Freitag <freitag@owncloud.com>
- *
- * 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 <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "torture.h"
-
-#include "csync_private.h"
-#include "vio/csync_vio.h"
-
-#ifdef _WIN32
-#include <windows.h>
-
-#define CSYNC_TEST_DIR "C:/tmp/csync_test"
-#else
-#define CSYNC_TEST_DIR "/tmp/csync_test"
-#endif
-#define MKDIR_MASK (S_IRWXU |S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
-
-#define WD_BUFFER_SIZE 255
-
-static mbchar_t wd_buffer[WD_BUFFER_SIZE];
-
-typedef struct {
- CSYNC *csync;
- char *result;
- char *ignored_dir;
-} statevar;
-
-/* remove the complete test dir */
-static int wipe_testdir()
-{
- int rc = 0;
-
-#ifdef _WIN32
- /* The windows system call to rd bails out if the dir is not existing
- * Check first.
- */
- WIN32_FIND_DATA FindFileData;
-
- mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
- HANDLE handle = FindFirstFile(dir, &FindFileData);
- c_free_locale_string(dir);
- int found = handle != INVALID_HANDLE_VALUE;
-
- if(found) {
- FindClose(handle);
- rc = system("rd /s /q C:\\tmp\\csync_test");
- }
-#else
- rc = system("rm -rf /tmp/csync_test/");
-#endif
- return rc;
-}
-
-static void setup_testenv(void **state) {
- int rc;
-
- rc = wipe_testdir();
- assert_int_equal(rc, 0);
-
- mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
-
- rc = _tmkdir(dir, MKDIR_MASK);
- assert_int_equal(rc, 0);
-
- assert_non_null(_tgetcwd(wd_buffer, WD_BUFFER_SIZE));
-
- rc = _tchdir(dir);
- assert_int_equal(rc, 0);
-
- c_free_locale_string(dir);
-
- /* --- initialize csync */
- statevar *mystate = malloc( sizeof(statevar) );
- mystate->result = NULL;
-
- csync_create(&(mystate->csync), "/tmp/csync1");
-
- mystate->csync->replica = LOCAL_REPLICA;
-
- *state = mystate;
-}
-
-static void output( const char *text )
-{
- mbchar_t *wtext = c_utf8_string_to_locale(text);
-
- #ifdef _WIN32
- wprintf(L"OOOO %ls (%ld)\n", wtext, strlen(text));
- #else
- printf("%s\n", wtext);
- #endif
- c_free_locale_string(wtext);
-}
-
-static void teardown(void **state) {
- statevar *sv = (statevar*) *state;
- CSYNC *csync = sv->csync;
- int rc;
-
- output("================== Tearing down!\n");
-
- rc = csync_destroy(csync);
- assert_int_equal(rc, 0);
-
- rc = _tchdir(wd_buffer);
- assert_int_equal(rc, 0);
-
- rc = wipe_testdir();
- assert_int_equal(rc, 0);
-
- *state = NULL;
-}
-
-/* This function takes a relative path, prepends it with the CSYNC_TEST_DIR
- * and creates each sub directory.
- */
-static void create_dirs( const char *path )
-{
- int rc;
- char *mypath = c_malloc( 2+strlen(CSYNC_TEST_DIR)+strlen(path));
- *mypath = '\0';
- strcat(mypath, CSYNC_TEST_DIR);
- strcat(mypath, "/");
- strcat(mypath, path);
-
- char *p = mypath+strlen(CSYNC_TEST_DIR)+1; /* start behind the offset */
- int i = 0;
-
- assert_non_null(path);
-
- while( *(p+i) ) {
- if( *(p+i) == '/' ) {
- p[i] = '\0';
-
- mbchar_t *mb_dir = c_utf8_path_to_locale(mypath);
- /* wprintf(L"OOOO %ls (%ld)\n", mb_dir, strlen(mypath)); */
- rc = _tmkdir(mb_dir, MKDIR_MASK);
- c_free_locale_string(mb_dir);
-
- assert_int_equal(rc, 0);
- p[i] = '/';
- }
- i++;
- }
- SAFE_FREE(mypath);
-}
-
-/*
- * This function uses the vio_opendir, vio_readdir and vio_closedir functions
- * to traverse a file tree that was created before by the create_dir function.
- *
- * It appends a listing to the result member of the incoming struct in *state
- * that can be compared later to what was expected in the calling functions.
- *
- * The int parameter cnt contains the number of seen files (not dirs) in the
- * whole tree.
- *
- */
-static void traverse_dir(void **state, const char *dir, int *cnt)
-{
- csync_vio_handle_t *dh;
- csync_vio_file_stat_t *dirent;
- statevar *sv = (statevar*) *state;
- CSYNC *csync = sv->csync;
- char *subdir;
- char *subdir_out;
- int rc;
- int is_dir;
-
- /* Format: Smuggle in the C: for unix platforms as its urgently needed
- * on Windows and the test can be nicely cross platform this way. */
-#ifdef _WIN32
- const char *format_str = "%s %s";
-#else
- const char *format_str = "%s C:%s";
-#endif
-
- dh = csync_vio_opendir(csync, dir);
- assert_non_null(dh);
-
- while( (dirent = csync_vio_readdir(csync, dh)) ) {
- assert_non_null(dirent);
- if (dirent->original_name) {
- sv->ignored_dir = c_strdup(dirent->original_name);
- continue;
- }
-
- assert_non_null(dirent->name);
- assert_int_equal( dirent->fields & CSYNC_VIO_FILE_STAT_FIELDS_TYPE, CSYNC_VIO_FILE_STAT_FIELDS_TYPE );
-
- if( c_streq( dirent->name, "..") || c_streq( dirent->name, "." )) {
- continue;
- }
-
- is_dir = (dirent->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) ? 1:0;
-
- assert_int_not_equal( asprintf( &subdir, "%s/%s", dir, dirent->name ), -1 );
-
- assert_int_not_equal( asprintf( &subdir_out, format_str,
- is_dir ? "<DIR>":" ",
- subdir), -1 );
-
- if( is_dir ) {
- if( !sv->result ) {
- sv->result = c_strdup( subdir_out);
- } else {
- int newlen = 1+strlen(sv->result)+strlen(subdir_out);
- char *tmp = sv->result;
- sv->result = c_malloc(newlen);
- strcpy( sv->result, tmp);
- SAFE_FREE(tmp);
-
- strcat( sv->result, subdir_out );
- }
- } else {
- *cnt = *cnt +1;
- }
- output(subdir_out);
- if( is_dir ) {
- traverse_dir( state, subdir, cnt);
- }
-
- SAFE_FREE(subdir);
- SAFE_FREE(subdir_out);
- }
-
- csync_vio_file_stat_destroy(dirent);
- rc = csync_vio_closedir(csync, dh);
- assert_int_equal(rc, 0);
-
-}
-
-static void create_file( const char *path, const char *name, const char *content)
-{
-#ifdef _WIN32
-
- char *filepath = c_malloc( 2+strlen(CSYNC_TEST_DIR)+strlen(path) + strlen(name) );
- *filepath = '\0';
- strcpy(filepath, CSYNC_TEST_DIR);
- strcat(filepath, "/");
- strcat(filepath, path);
- strcat(filepath, name);
-
- DWORD dwWritten; // number of bytes written to file
- HANDLE hFile;
-
- mbchar_t *w_fname = c_utf8_path_to_locale(filepath);
-
- hFile=CreateFile(w_fname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
-
- assert_int_equal( 0, hFile==INVALID_HANDLE_VALUE );
-
- int len = strlen(content);
- mbchar_t *dst = NULL;
-
- dst = c_utf8_string_to_locale(content);
- WriteFile(hFile, dst, len * sizeof(mbchar_t), &dwWritten, 0);
-
- CloseHandle(hFile);
- SAFE_FREE(dst);
- c_free_locale_string(w_fname);
-#else
- char *filepath = c_malloc( 1+strlen(path) + strlen(name) );
- *filepath = '\0';
-
- strcpy(filepath, path);
- strcat(filepath, name);
-
- FILE *sink;
- sink = fopen(filepath,"w");
-
- fprintf (sink, "we got: %s",content);
- fclose(sink);
- SAFE_FREE(filepath);
-#endif
-
-}
-
-static void check_readdir_shorttree(void **state)
-{
- statevar *sv = (statevar*) *state;
-
- const char *t1 = "alibaba/und/die/vierzig/räuber/";
- create_dirs( t1 );
- int files_cnt = 0;
-
- traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
-
- assert_string_equal( sv->result,
- "<DIR> C:/tmp/csync_test/alibaba"
- "<DIR> C:/tmp/csync_test/alibaba/und"
- "<DIR> C:/tmp/csync_test/alibaba/und/die"
- "<DIR> C:/tmp/csync_test/alibaba/und/die/vierzig"
- "<DIR> C:/tmp/csync_test/alibaba/und/die/vierzig/räuber" );
- assert_int_equal(files_cnt, 0);
-}
-
-static void check_readdir_with_content(void **state)
-{
- statevar *sv = (statevar*) *state;
- int files_cnt = 0;
-
- const char *t1 = "warum/nur/40/Räuber/";
- create_dirs( t1 );
-
- create_file( t1, "Räuber Max.txt", "Der Max ist ein schlimmer finger");
- create_file( t1, "пя́тница.txt", "Am Freitag tanzt der Ürk");
-
-
- traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
-
- assert_string_equal( sv->result,
- "<DIR> C:/tmp/csync_test/warum"
- "<DIR> C:/tmp/csync_test/warum/nur"
- "<DIR> C:/tmp/csync_test/warum/nur/40"
- "<DIR> C:/tmp/csync_test/warum/nur/40/Räuber");
- /* " C:/tmp/csync_test/warum/nur/40/Räuber/Räuber Max.txt"
- " C:/tmp/csync_test/warum/nur/40/Räuber/пя́тница.txt"); */
- assert_int_equal(files_cnt, 2); /* Two files in the sub dir */
-}
-
-static void check_readdir_longtree(void **state)
-{
- statevar *sv = (statevar*) *state;
-
- /* Strange things here: Compilers only support strings with length of 4k max.
- * The expected result string is longer, so it needs to be split up in r1, r2 and r3
- */
-
- /* create the test tree */
- const char *t1 = "vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI/Butteln/VOLL RUM/";
- create_dirs( t1 );
-
- const char *r1 =
-"<DIR> C:/tmp/csync_test/vierzig"
-"<DIR> C:/tmp/csync_test/vierzig/mann"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum";
-
-
- const char *r2 =
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH";
-
-
- const char *r3 =
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI/Butteln"
-"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI/Butteln/VOLL RUM";
-
- /* assemble the result string ... */
- int overall_len = 1+strlen(r1)+strlen(r2)+strlen(r3);
- int files_cnt = 0;
- char *result = c_malloc(overall_len);
- *result = '\0';
-
- strcat(result, r1);
- strcat(result, r2);
- strcat(result, r3);
-
- traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
- assert_int_equal(files_cnt, 0);
- /* and compare. */
- assert_string_equal( sv->result, result);
-}
-
-// https://github.com/owncloud/client/issues/3128 https://github.com/owncloud/client/issues/2777
-static void check_readdir_bigunicode(void **state)
-{
- statevar *sv = (statevar*) *state;
-// 1: ? ASCII: 239 - EF
-// 2: ? ASCII: 187 - BB
-// 3: ? ASCII: 191 - BF
-// 4: ASCII: 32 - 20
-
- char *p = 0;
- asprintf( &p, "%s/%s", CSYNC_TEST_DIR, "goodone/" );
- int rc = _tmkdir(p, MKDIR_MASK);
- assert_int_equal(rc, 0);
- SAFE_FREE(p);
-
- const char *t1 = "goodone/ugly\xEF\xBB\xBF\x32" ".txt"; // file with encoding error
- asprintf( &p, "%s/%s", CSYNC_TEST_DIR, t1 );
- rc = _tmkdir(p, MKDIR_MASK);
- SAFE_FREE(p);
-
- assert_int_equal(rc, 0);
-
- int files_cnt = 0;
- traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
- const char *expected_result = "<DIR> C:/tmp/csync_test/goodone"
- "<DIR> C:/tmp/csync_test/goodone/ugly\xEF\xBB\xBF\x32" ".txt"
- ;
- assert_string_equal( sv->result, expected_result);
-
- assert_int_equal(files_cnt, 0);
-}
-
-int torture_run_tests(void)
-{
- const UnitTest tests[] = {
- unit_test_setup_teardown(check_readdir_shorttree, setup_testenv, teardown),
- unit_test_setup_teardown(check_readdir_with_content, setup_testenv, teardown),
- unit_test_setup_teardown(check_readdir_longtree, setup_testenv, teardown),
- unit_test_setup_teardown(check_readdir_bigunicode, setup_testenv, teardown),
- };
-
- return run_tests(tests);
-}
--- /dev/null
+/*
+ * libcsync -- a library to sync a directory with another
+ *
+ * Copyright (c) 2015-2013 by Klaas Freitag <freitag@owncloud.com>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "torture.h"
+
+#include "csync_private.h"
+#include "vio/csync_vio.h"
+
+#ifdef _WIN32
+#include <windows.h>
+
+#define CSYNC_TEST_DIR "C:/tmp/csync_test"
+#else
+#define CSYNC_TEST_DIR "/tmp/csync_test"
+#endif
+#define MKDIR_MASK (S_IRWXU |S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+
+#define WD_BUFFER_SIZE 255
+
+static mbchar_t wd_buffer[WD_BUFFER_SIZE];
+
+typedef struct {
+ CSYNC *csync;
+ char *result;
+ char *ignored_dir;
+} statevar;
+
+/* remove the complete test dir */
+static int wipe_testdir()
+{
+ int rc = 0;
+
+#ifdef _WIN32
+ /* The windows system call to rd bails out if the dir is not existing
+ * Check first.
+ */
+ WIN32_FIND_DATA FindFileData;
+
+ mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
+ HANDLE handle = FindFirstFile(dir, &FindFileData);
+ c_free_locale_string(dir);
+ int found = handle != INVALID_HANDLE_VALUE;
+
+ if(found) {
+ FindClose(handle);
+ rc = system("rd /s /q C:\\tmp\\csync_test");
+ }
+#else
+ rc = system("rm -rf /tmp/csync_test/");
+#endif
+ return rc;
+}
+
+static void setup_testenv(void **state) {
+ int rc;
+
+ rc = wipe_testdir();
+ assert_int_equal(rc, 0);
+
+ mbchar_t *dir = c_utf8_path_to_locale(CSYNC_TEST_DIR);
+
+ rc = _tmkdir(dir, MKDIR_MASK);
+ assert_int_equal(rc, 0);
+
+ assert_non_null(_tgetcwd(wd_buffer, WD_BUFFER_SIZE));
+
+ rc = _tchdir(dir);
+ assert_int_equal(rc, 0);
+
+ c_free_locale_string(dir);
+
+ /* --- initialize csync */
+ statevar *mystate = (statevar*)malloc( sizeof(statevar) );
+ mystate->result = NULL;
+
+ csync_create(&(mystate->csync), "/tmp/csync1");
+
+ mystate->csync->replica = LOCAL_REPLICA;
+
+ *state = mystate;
+}
+
+static void output( const char *text )
+{
+ mbchar_t *wtext = c_utf8_string_to_locale(text);
+
+ #ifdef _WIN32
+ wprintf(L"OOOO %ls (%ld)\n", wtext, strlen(text));
+ #else
+ printf("%s\n", wtext);
+ #endif
+ c_free_locale_string(wtext);
+}
+
+static void teardown(void **state) {
+ statevar *sv = (statevar*) *state;
+ CSYNC *csync = sv->csync;
+ int rc;
+
+ output("================== Tearing down!\n");
+
+ rc = csync_destroy(csync);
+ assert_int_equal(rc, 0);
+
+ rc = _tchdir(wd_buffer);
+ assert_int_equal(rc, 0);
+
+ rc = wipe_testdir();
+ assert_int_equal(rc, 0);
+
+ *state = NULL;
+}
+
+/* This function takes a relative path, prepends it with the CSYNC_TEST_DIR
+ * and creates each sub directory.
+ */
+static void create_dirs( const char *path )
+{
+ int rc;
+ char *mypath = (char*)c_malloc( 2+strlen(CSYNC_TEST_DIR)+strlen(path));
+ *mypath = '\0';
+ strcat(mypath, CSYNC_TEST_DIR);
+ strcat(mypath, "/");
+ strcat(mypath, path);
+
+ char *p = mypath+strlen(CSYNC_TEST_DIR)+1; /* start behind the offset */
+ int i = 0;
+
+ assert_non_null(path);
+
+ while( *(p+i) ) {
+ if( *(p+i) == '/' ) {
+ p[i] = '\0';
+
+ mbchar_t *mb_dir = c_utf8_path_to_locale(mypath);
+ /* wprintf(L"OOOO %ls (%ld)\n", mb_dir, strlen(mypath)); */
+ rc = _tmkdir(mb_dir, MKDIR_MASK);
+ c_free_locale_string(mb_dir);
+
+ assert_int_equal(rc, 0);
+ p[i] = '/';
+ }
+ i++;
+ }
+ SAFE_FREE(mypath);
+}
+
+/*
+ * This function uses the vio_opendir, vio_readdir and vio_closedir functions
+ * to traverse a file tree that was created before by the create_dir function.
+ *
+ * It appends a listing to the result member of the incoming struct in *state
+ * that can be compared later to what was expected in the calling functions.
+ *
+ * The int parameter cnt contains the number of seen files (not dirs) in the
+ * whole tree.
+ *
+ */
+static void traverse_dir(void **state, const char *dir, int *cnt)
+{
+ csync_vio_handle_t *dh;
+ csync_vio_file_stat_t *dirent;
+ statevar *sv = (statevar*) *state;
+ CSYNC *csync = sv->csync;
+ char *subdir;
+ char *subdir_out;
+ int rc;
+ int is_dir;
+
+ /* Format: Smuggle in the C: for unix platforms as its urgently needed
+ * on Windows and the test can be nicely cross platform this way. */
+#ifdef _WIN32
+ const char *format_str = "%s %s";
+#else
+ const char *format_str = "%s C:%s";
+#endif
+
+ dh = csync_vio_opendir(csync, dir);
+ assert_non_null(dh);
+
+ while( (dirent = csync_vio_readdir(csync, dh)) ) {
+ assert_non_null(dirent);
+ if (dirent->original_name) {
+ sv->ignored_dir = c_strdup(dirent->original_name);
+ continue;
+ }
+
+ assert_non_null(dirent->name);
+ assert_int_equal( dirent->fields & CSYNC_VIO_FILE_STAT_FIELDS_TYPE, CSYNC_VIO_FILE_STAT_FIELDS_TYPE );
+
+ if( c_streq( dirent->name, "..") || c_streq( dirent->name, "." )) {
+ continue;
+ }
+
+ is_dir = (dirent->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) ? 1:0;
+
+ assert_int_not_equal( asprintf( &subdir, "%s/%s", dir, dirent->name ), -1 );
+
+ assert_int_not_equal( asprintf( &subdir_out, format_str,
+ is_dir ? "<DIR>":" ",
+ subdir), -1 );
+
+ if( is_dir ) {
+ if( !sv->result ) {
+ sv->result = c_strdup( subdir_out);
+ } else {
+ int newlen = 1+strlen(sv->result)+strlen(subdir_out);
+ char *tmp = sv->result;
+ sv->result = (char*)c_malloc(newlen);
+ strcpy( sv->result, tmp);
+ SAFE_FREE(tmp);
+
+ strcat( sv->result, subdir_out );
+ }
+ } else {
+ *cnt = *cnt +1;
+ }
+ output(subdir_out);
+ if( is_dir ) {
+ traverse_dir( state, subdir, cnt);
+ }
+
+ SAFE_FREE(subdir);
+ SAFE_FREE(subdir_out);
+ }
+
+ csync_vio_file_stat_destroy(dirent);
+ rc = csync_vio_closedir(csync, dh);
+ assert_int_equal(rc, 0);
+
+}
+
+static void create_file( const char *path, const char *name, const char *content)
+{
+#ifdef _WIN32
+
+ char *filepath = c_malloc( 2+strlen(CSYNC_TEST_DIR)+strlen(path) + strlen(name) );
+ *filepath = '\0';
+ strcpy(filepath, CSYNC_TEST_DIR);
+ strcat(filepath, "/");
+ strcat(filepath, path);
+ strcat(filepath, name);
+
+ DWORD dwWritten; // number of bytes written to file
+ HANDLE hFile;
+
+ mbchar_t *w_fname = c_utf8_path_to_locale(filepath);
+
+ hFile=CreateFile(w_fname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+
+ assert_int_equal( 0, hFile==INVALID_HANDLE_VALUE );
+
+ int len = strlen(content);
+ mbchar_t *dst = NULL;
+
+ dst = c_utf8_string_to_locale(content);
+ WriteFile(hFile, dst, len * sizeof(mbchar_t), &dwWritten, 0);
+
+ CloseHandle(hFile);
+ SAFE_FREE(dst);
+ c_free_locale_string(w_fname);
+#else
+ char *filepath = (char*)c_malloc( 1+strlen(path) + strlen(name) );
+ *filepath = '\0';
+
+ strcpy(filepath, path);
+ strcat(filepath, name);
+
+ FILE *sink;
+ sink = fopen(filepath,"w");
+
+ fprintf (sink, "we got: %s",content);
+ fclose(sink);
+ SAFE_FREE(filepath);
+#endif
+
+}
+
+static void check_readdir_shorttree(void **state)
+{
+ statevar *sv = (statevar*) *state;
+
+ const char *t1 = "alibaba/und/die/vierzig/räuber/";
+ create_dirs( t1 );
+ int files_cnt = 0;
+
+ traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
+
+ assert_string_equal( sv->result,
+ "<DIR> C:/tmp/csync_test/alibaba"
+ "<DIR> C:/tmp/csync_test/alibaba/und"
+ "<DIR> C:/tmp/csync_test/alibaba/und/die"
+ "<DIR> C:/tmp/csync_test/alibaba/und/die/vierzig"
+ "<DIR> C:/tmp/csync_test/alibaba/und/die/vierzig/räuber" );
+ assert_int_equal(files_cnt, 0);
+}
+
+static void check_readdir_with_content(void **state)
+{
+ statevar *sv = (statevar*) *state;
+ int files_cnt = 0;
+
+ const char *t1 = "warum/nur/40/Räuber/";
+ create_dirs( t1 );
+
+ create_file( t1, "Räuber Max.txt", "Der Max ist ein schlimmer finger");
+ create_file( t1, "пя́тница.txt", "Am Freitag tanzt der Ürk");
+
+
+ traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
+
+ assert_string_equal( sv->result,
+ "<DIR> C:/tmp/csync_test/warum"
+ "<DIR> C:/tmp/csync_test/warum/nur"
+ "<DIR> C:/tmp/csync_test/warum/nur/40"
+ "<DIR> C:/tmp/csync_test/warum/nur/40/Räuber");
+ /* " C:/tmp/csync_test/warum/nur/40/Räuber/Räuber Max.txt"
+ " C:/tmp/csync_test/warum/nur/40/Räuber/пя́тница.txt"); */
+ assert_int_equal(files_cnt, 2); /* Two files in the sub dir */
+}
+
+static void check_readdir_longtree(void **state)
+{
+ statevar *sv = (statevar*) *state;
+
+ /* Strange things here: Compilers only support strings with length of 4k max.
+ * The expected result string is longer, so it needs to be split up in r1, r2 and r3
+ */
+
+ /* create the test tree */
+ const char *t1 = "vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI/Butteln/VOLL RUM/";
+ create_dirs( t1 );
+
+ const char *r1 =
+"<DIR> C:/tmp/csync_test/vierzig"
+"<DIR> C:/tmp/csync_test/vierzig/mann"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum";
+
+
+ const char *r2 =
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH";
+
+
+ const char *r3 =
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI/Butteln"
+"<DIR> C:/tmp/csync_test/vierzig/mann/auf/des/toten/Mann/kiste/ooooooooooooooooooooooh/and/ne/bottle/voll/rum/und/so/singen/wir/VIERZIG/MANN/AUF/DES/TOTEN/MANNS/KISTE/OOOOOOOOH/AND/NE/BOTTLE/VOLL/RUM/undnochmalallezusammen/VierZig/MannaufDesTotenManns/KISTE/ooooooooooooooooooooooooooohhhhhh/und/BESSER/ZWEI/Butteln/VOLL RUM";
+
+ /* assemble the result string ... */
+ int overall_len = 1+strlen(r1)+strlen(r2)+strlen(r3);
+ int files_cnt = 0;
+ char *result = (char*)c_malloc(overall_len);
+ *result = '\0';
+
+ strcat(result, r1);
+ strcat(result, r2);
+ strcat(result, r3);
+
+ traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
+ assert_int_equal(files_cnt, 0);
+ /* and compare. */
+ assert_string_equal( sv->result, result);
+}
+
+// https://github.com/owncloud/client/issues/3128 https://github.com/owncloud/client/issues/2777
+static void check_readdir_bigunicode(void **state)
+{
+ statevar *sv = (statevar*) *state;
+// 1: ? ASCII: 239 - EF
+// 2: ? ASCII: 187 - BB
+// 3: ? ASCII: 191 - BF
+// 4: ASCII: 32 - 20
+
+ char *p = 0;
+ asprintf( &p, "%s/%s", CSYNC_TEST_DIR, "goodone/" );
+ int rc = _tmkdir(p, MKDIR_MASK);
+ assert_int_equal(rc, 0);
+ SAFE_FREE(p);
+
+ const char *t1 = "goodone/ugly\xEF\xBB\xBF\x32" ".txt"; // file with encoding error
+ asprintf( &p, "%s/%s", CSYNC_TEST_DIR, t1 );
+ rc = _tmkdir(p, MKDIR_MASK);
+ SAFE_FREE(p);
+
+ assert_int_equal(rc, 0);
+
+ int files_cnt = 0;
+ traverse_dir(state, CSYNC_TEST_DIR, &files_cnt);
+ const char *expected_result = "<DIR> C:/tmp/csync_test/goodone"
+ "<DIR> C:/tmp/csync_test/goodone/ugly\xEF\xBB\xBF\x32" ".txt"
+ ;
+ assert_string_equal( sv->result, expected_result);
+
+ assert_int_equal(files_cnt, 0);
+}
+
+int torture_run_tests(void)
+{
+ const UnitTest tests[] = {
+ unit_test_setup_teardown(check_readdir_shorttree, setup_testenv, teardown),
+ unit_test_setup_teardown(check_readdir_with_content, setup_testenv, teardown),
+ unit_test_setup_teardown(check_readdir_longtree, setup_testenv, teardown),
+ unit_test_setup_teardown(check_readdir_bigunicode, setup_testenv, teardown),
+ };
+
+ return run_tests(tests);
+}
+++ /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 "torture.h"
-
-#include "csync.h"
-
-static void check_csync_vio_file_stat_new(void **state)
-{
- csync_vio_file_stat_t *tstat;
-
- (void) state; /* unused */
-
- tstat = csync_vio_file_stat_new();
- assert_non_null(tstat);
-
- csync_vio_file_stat_destroy(tstat);
-}
-
-
-int torture_run_tests(void)
-{
- const UnitTest tests[] = {
- unit_test(check_csync_vio_file_stat_new),
- };
-
- return run_tests(tests);
-}
-
--- /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 "torture.h"
+
+#include "csync.h"
+
+static void check_csync_vio_file_stat_new(void **state)
+{
+ csync_vio_file_stat_t *tstat;
+
+ (void) state; /* unused */
+
+ tstat = csync_vio_file_stat_new();
+ assert_non_null(tstat);
+
+ csync_vio_file_stat_destroy(tstat);
+}
+
+
+int torture_run_tests(void)
+{
+ const UnitTest tests[] = {
+ unit_test(check_csync_vio_file_stat_new),
+ };
+
+ return run_tests(tests);
+}
+