Compile almost all of csync as C++
authorJocelyn Turcotte <jturcotte@woboq.com>
Mon, 14 Aug 2017 14:19:52 +0000 (16:19 +0200)
committerRoeland Jago Douma <roeland@famdouma.nl>
Thu, 5 Oct 2017 20:01:03 +0000 (22:01 +0200)
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.

79 files changed:
csync/tests/csync_tests/check_csync_update.cpp [new file with mode: 0644]
src/csync/CMakeLists.txt
src/csync/csync.c [deleted file]
src/csync/csync.cpp [new file with mode: 0644]
src/csync/csync.h
src/csync/csync_exclude.c [deleted file]
src/csync/csync_exclude.cpp [new file with mode: 0644]
src/csync/csync_log.c [deleted file]
src/csync/csync_log.cpp [new file with mode: 0644]
src/csync/csync_misc.c [deleted file]
src/csync/csync_misc.cpp [new file with mode: 0644]
src/csync/csync_private.h
src/csync/csync_reconcile.c [deleted file]
src/csync/csync_reconcile.cpp [new file with mode: 0644]
src/csync/csync_rename.cpp
src/csync/csync_rename.h
src/csync/csync_statedb.c [deleted file]
src/csync/csync_statedb.cpp [new file with mode: 0644]
src/csync/csync_statedb.h
src/csync/csync_time.c
src/csync/csync_time.h
src/csync/csync_update.c [deleted file]
src/csync/csync_update.cpp [new file with mode: 0644]
src/csync/csync_update.h
src/csync/csync_util.c [deleted file]
src/csync/csync_util.cpp [new file with mode: 0644]
src/csync/csync_version.h.in
src/csync/std/asprintf.h
src/csync/std/c_alloc.h
src/csync/std/c_path.h
src/csync/std/c_rbtree.h
src/csync/std/c_string.h
src/csync/std/c_time.c
src/csync/std/c_time.h
src/csync/vio/csync_vio.c [deleted file]
src/csync/vio/csync_vio.cpp [new file with mode: 0644]
src/csync/vio/csync_vio_file_stat.c [deleted file]
src/csync/vio/csync_vio_file_stat.cpp [new file with mode: 0644]
src/csync/vio/csync_vio_local_unix.c [deleted file]
src/csync/vio/csync_vio_local_unix.cpp [new file with mode: 0644]
src/csync/vio/csync_vio_local_win.c [deleted file]
src/csync/vio/csync_vio_local_win.cpp [new file with mode: 0644]
src/libsync/excludedfiles.cpp
src/libsync/excludedfiles.h
src/libsync/filesystem.cpp
src/libsync/owncloudpropagator.h
src/libsync/syncjournaldb.cpp
test/csync/CMakeLists.txt
test/csync/csync_tests/check_csync_commit.c [deleted file]
test/csync/csync_tests/check_csync_commit.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_create.c [deleted file]
test/csync/csync_tests/check_csync_create.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_exclude.c [deleted file]
test/csync/csync_tests/check_csync_exclude.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_init.c [deleted file]
test/csync/csync_tests/check_csync_init.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_log.c [deleted file]
test/csync/csync_tests/check_csync_log.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_misc.c [deleted file]
test/csync/csync_tests/check_csync_misc.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_statedb_load.c [deleted file]
test/csync/csync_tests/check_csync_statedb_load.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_statedb_query.c [deleted file]
test/csync/csync_tests/check_csync_statedb_query.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_update.c [deleted file]
test/csync/csync_tests/check_csync_update.cpp [new file with mode: 0644]
test/csync/csync_tests/check_csync_util.c [deleted file]
test/csync/csync_tests/check_csync_util.cpp [new file with mode: 0644]
test/csync/encoding_tests/check_encoding.c [deleted file]
test/csync/encoding_tests/check_encoding.cpp [new file with mode: 0644]
test/csync/log_tests/check_log.c [deleted file]
test/csync/log_tests/check_log.cpp [new file with mode: 0644]
test/csync/torture.h
test/csync/vio_tests/check_vio.c [deleted file]
test/csync/vio_tests/check_vio.cpp [new file with mode: 0644]
test/csync/vio_tests/check_vio_ext.c [deleted file]
test/csync/vio_tests/check_vio_ext.cpp [new file with mode: 0644]
test/csync/vio_tests/check_vio_file_stat.c [deleted file]
test/csync/vio_tests/check_vio_file_stat.cpp [new file with mode: 0644]

diff --git a/csync/tests/csync_tests/check_csync_update.cpp b/csync/tests/csync_tests/check_csync_update.cpp
new file mode 100644 (file)
index 0000000..cc11bad
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * 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);
+}
+
+}
index 2bd60e57294497a6ff73b26f36be8029f68731f5..09f320202cc10edaa91f00f66bfba4e1c2b375e5 100644 (file)
@@ -62,30 +62,30 @@ if(NO_RENAME_EXTENSION)
 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()
 
diff --git a/src/csync/csync.c b/src/csync/csync.c
deleted file mode 100644 (file)
index 1f75ac3..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * 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);
-  }
-}
diff --git a/src/csync/csync.cpp b/src/csync/csync.cpp
new file mode 100644 (file)
index 0000000..6ef3d0d
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ * 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);
+  }
+}
index daf778c24746ed5b65246fb874edd4fb07105ee1..73eb5790ad519bc42bfba8f2a0c6cea512aeafe4 100644 (file)
 #include <sys/types.h>
 #include <config_csync.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 enum csync_status_codes_e {
   CSYNC_STATUS_OK         = 0,
 
@@ -221,7 +217,7 @@ struct csync_vio_file_stat_s {
   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
 
@@ -504,10 +500,6 @@ int  OCSYNC_EXPORT csync_abort_requested(CSYNC *ctx);
 char OCSYNC_EXPORT *csync_normalize_etag(const char *);
 time_t OCSYNC_EXPORT oc_httpdate_parse( const char *date );
 
-#ifdef __cplusplus
-}
-#endif
-
 /**
  * }@
  */
diff --git a/src/csync/csync_exclude.c b/src/csync/csync_exclude.c
deleted file mode 100644 (file)
index fea6625..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "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);
-}
-
diff --git a/src/csync/csync_exclude.cpp b/src/csync/csync_exclude.cpp
new file mode 100644 (file)
index 0000000..9ab187e
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * 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);
+}
+
diff --git a/src/csync/csync_log.c b/src/csync/csync_log.c
deleted file mode 100644 (file)
index 4a2e24a..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "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;
-}
diff --git a/src/csync/csync_log.cpp b/src/csync/csync_log.cpp
new file mode 100644 (file)
index 0000000..4a2e24a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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;
+}
diff --git a/src/csync/csync_misc.c b/src/csync/csync_misc.c
deleted file mode 100644 (file)
index d232361..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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;
-}
-
diff --git a/src/csync/csync_misc.cpp b/src/csync/csync_misc.cpp
new file mode 100644 (file)
index 0000000..cf71943
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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;
+}
+
index 2edc26019d4a5c817eeff4ca9f34c453ded7d5cd..3d1632e41a1e64ca4099e46cc39a19588fa984f8 100644 (file)
@@ -163,7 +163,7 @@ struct csync_file_stat_s {
   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 */
 
diff --git a/src/csync/csync_reconcile.c b/src/csync/csync_reconcile.c
deleted file mode 100644 (file)
index 59156e8..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "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: */
diff --git a/src/csync/csync_reconcile.cpp b/src/csync/csync_reconcile.cpp
new file mode 100644 (file)
index 0000000..3b02398
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * 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: */
index 5cc43ce22f59113261f0b2aebfac63f7b5a36d02..79bb78e346d91024880fae693fc831f866084f36 100644 (file)
  * 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>
@@ -55,7 +53,6 @@ struct csync_rename_s {
     std::vector<renameop> todo;
 };
 
-extern "C" {
 void csync_rename_destroy(CSYNC* ctx)
 {
     delete reinterpret_cast<csync_rename_s *>(ctx->rename_info);
@@ -98,5 +95,3 @@ bool csync_rename_count(CSYNC *ctx) {
     csync_rename_s* d = csync_rename_s::get(ctx);
     return d->folder_renamed_from.size();
 }
-
-}
index 53968324c95bcb2d77aa912f16ba9900126d51cd..7702a137680fd0478d6c124d3bda8bad1a374cf8 100644 (file)
 
 #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 */
@@ -34,7 +30,3 @@ void OCSYNC_EXPORT csync_rename_destroy(CSYNC *ctx);
 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
diff --git a/src/csync/csync_statedb.c b/src/csync/csync_statedb.c
deleted file mode 100644 (file)
index 056ca48..0000000
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * 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: */
diff --git a/src/csync/csync_statedb.cpp b/src/csync/csync_statedb.cpp
new file mode 100644 (file)
index 0000000..63eb813
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * 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: */
index 601e34a1b77779cdea8273dbff75b8c588a3b515..dc58a9b08890d366a035d9ea90b638f56cb08826 100644 (file)
 #ifndef _CSYNC_STATEDB_H
 #define _CSYNC_STATEDB_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "c_lib.h"
 #include "csync_private.h"
 
@@ -96,10 +92,6 @@ int csync_statedb_get_below_path(CSYNC *ctx, const char *path);
  */
 c_strlist_t *csync_statedb_query(sqlite3 *db, const char *statement);
 
-#ifdef __cplusplus
-}
-#endif
-
 /**
  * }@
  */
index 85bdd5ff4a42bd5e519ab90dc6b4c0dce930e415..3092819a3458b6747324669a07c966aa6c75a0db 100644 (file)
@@ -34,6 +34,8 @@
 #ifndef _WIN32
 #include <unistd.h>
 #include <sys/time.h>
+#else
+#include <windows.h>
 #endif
 
 #define CSYNC_LOG_CATEGORY_NAME "csync.time"
index 1492bef8d7a32f2d9463ebebd62475ed60e99aea..55aa098415440cdf79de1ae420361513f722153d 100644 (file)
 #ifndef _CSYNC_TIME_H
 #define _CSYNC_TIME_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <time.h>
 
 #include "csync_private.h"
@@ -28,4 +32,8 @@
 int csync_gettime(struct timespec *tp);
 void csync_sleep(unsigned int msecs);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _CSYNC_TIME_H */
diff --git a/src/csync/csync_update.c b/src/csync/csync_update.c
deleted file mode 100644 (file)
index 1a06944..0000000
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * 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: */
diff --git a/src/csync/csync_update.cpp b/src/csync/csync_update.cpp
new file mode 100644 (file)
index 0000000..927290b
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ * 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: */
index 4a7495e3afbad54fd96e6f49aeba95f6b7a2448a..d83ee91e83809d16855efedad670d0537503c894 100644 (file)
@@ -53,7 +53,7 @@ enum csync_ftw_flags_e {
 };
 
 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.
@@ -68,8 +68,7 @@ typedef int (*csync_walker_fn) (CSYNC *ctx, const char *file,
  *
  * @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.
diff --git a/src/csync/csync_util.c b/src/csync/csync_util.c
deleted file mode 100644 (file)
index 1bc09c3..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/csync/csync_util.cpp b/src/csync/csync_util.cpp
new file mode 100644 (file)
index 0000000..4fc13a4
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * 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;
+}
index 9471734b87fc0c04ee9c4339bb3bd8a614598c9d..3bf379db9ffaf8ae5bbb91064312bb3211c79641 100644 (file)
 #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
index d6dd2e8593dd34735745268418469a420ef8761e..21693ca89b1222d1c60efc0abfea17bc98d01896 100644 (file)
 #ifndef ASPRINTF_H
 #define ASPRINTF_H 1
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdarg.h>
 
 /**
@@ -56,5 +60,9 @@ vasprintf (char **, const char *, va_list);
 int
 asprintf (char **, const char *, ...);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 #endif
index 6eeccd69dfb3f916e26895f09cf68a90a174e8dc..8ff2eb08b74e8af4621616e7e81e2d58d918822b 100644 (file)
 #ifndef _C_ALLOC_H
 #define _C_ALLOC_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdlib.h>
 
 #include "c_macro.h"
@@ -113,4 +117,9 @@ char *c_strndup(const char *str, size_t size);
 /**
  * }@
  */
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _C_ALLOC_H */
index 291b1b8d3e1517a88d2d8d3edba74b8a2b039c02..f17c5f48043139b378c1ce0ff2492a05f6a597a0 100644 (file)
 #ifndef _C_PATH_H
 #define _C_PATH_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "c_macro.h"
 #include "c_private.h"
 
@@ -139,4 +143,9 @@ mbchar_t* c_utf8_path_to_locale(const char *str);
 /**
  * }@
  */
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _C_PATH_H */
index 635458fd29ddd607258170a936050a468efe3623..69b4c0d735ac3e95f31900e0f8ce73b1185c1093 100644 (file)
 #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;
@@ -306,4 +310,9 @@ int c_rbtree_check_sanity(c_rbtree_t *tree);
 /**
  * }@
  */
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _C_RBTREE_H */
index 304c598a23f002dbfac2e592129edff1fa6961cd..4d7d9b5990f34352fe9e31130d9cdf4893d81675 100644 (file)
 #ifndef _C_STR_H
 #define _C_STR_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "c_private.h"
 #include "c_macro.h"
 
@@ -217,5 +221,10 @@ mbchar_t* c_utf8_string_to_locale(const char *wstr);
 /**
  * }@
  */
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _C_STR_H */
 
index ad43fed022536ffc90e9d1da7772dccad64825a0..561cd47637f35dbec09b819de191542f5436a5c6 100644 (file)
 #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;
index aa8ef2f16435074e2285590eb9dc30013b361e99..67e7fcbad2509ca3421cd93106c23da52295db41 100644 (file)
 #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
@@ -52,4 +60,8 @@ double c_secdiff(struct timespec clock1, struct timespec clock0);
 
 int c_utimes(const char *uri, const struct timeval *times);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _C_TIME_H */
diff --git a/src/csync/vio/csync_vio.c b/src/csync/vio/csync_vio.c
deleted file mode 100644 (file)
index 9091178..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#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;
-}
diff --git a/src/csync/vio/csync_vio.cpp b/src/csync/vio/csync_vio.cpp
new file mode 100644 (file)
index 0000000..9091178
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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;
+}
diff --git a/src/csync/vio/csync_vio_file_stat.c b/src/csync/vio/csync_vio_file_stat.c
deleted file mode 100644 (file)
index 8ebb64f..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "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);
-        }
-    }
-}
diff --git a/src/csync/vio/csync_vio_file_stat.cpp b/src/csync/vio/csync_vio_file_stat.cpp
new file mode 100644 (file)
index 0000000..8ebb64f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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);
+        }
+    }
+}
diff --git a/src/csync/vio/csync_vio_local_unix.c b/src/csync/vio/csync_vio_local_unix.c
deleted file mode 100644 (file)
index 5d56666..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/csync/vio/csync_vio_local_unix.cpp b/src/csync/vio/csync_vio_local_unix.cpp
new file mode 100644 (file)
index 0000000..40e4794
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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;
+}
diff --git a/src/csync/vio/csync_vio_local_win.c b/src/csync/vio/csync_vio_local_win.c
deleted file mode 100644 (file)
index fc4eea5..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/csync/vio/csync_vio_local_win.cpp b/src/csync/vio/csync_vio_local_win.cpp
new file mode 100644 (file)
index 0000000..e9d2ba5
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * 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;
+}
index 074494ff8aa1e0267387ffae846a94a717b161c7..289164efb78888fc778e93fd6561608992bea06e 100644 (file)
 
 #include <QFileInfo>
 
-extern "C" {
 #include "std/c_string.h"
 #include "csync.h"
 #include "csync_exclude.h"
-}
 
 using namespace OCC;
 
index f8a18cd8d64e946bf71bdf5ffc0e5ea1d6d63365..d090f8aa63942b6d248464b6223300d98d0303b7 100644 (file)
 #include <QSet>
 #include <QString>
 
-extern "C" {
 #include "std/c_string.h"
 #include "csync.h"
 #include "csync_exclude.h" // for CSYNC_EXCLUDE_TYPE
-}
 
 namespace OCC {
 
index 18e6f800ffebee63feb163aeac685e31ea00f566..8299fcc04d7d0b9f89c3ea002e6dc9518ee49718 100644 (file)
 
 // 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 {
 
index 02145fa193f7cdee0ad25732d5decce46815fff2..b9b60034f78553c554b524a112ca01e2ee90f0f7 100644 (file)
@@ -25,6 +25,7 @@
 #include <QIODevice>
 #include <QMutex>
 
+#include "csync_util.h"
 #include "syncfileitem.h"
 #include "syncjournaldb.h"
 #include "bandwidthmanager.h"
@@ -35,8 +36,6 @@ namespace OCC {
 
 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();
index 203c149889dc953b992ebcf53cc60d4095ccada8..e46d35db615c22090319eb78287a237b39bf32b9 100644 (file)
@@ -21,8 +21,6 @@
 
 #include "ownsql.h"
 
-#include <inttypes.h>
-
 #include "syncjournaldb.h"
 #include "syncjournalfilerecord.h"
 #include "utility.h"
index e92c15e2dec8dcd834dba6c2b3ad515d77515067..a27505d12a376087dfd9f30a4303ef441836dfd6 100644 (file)
@@ -29,28 +29,28 @@ add_cmocka_test(check_std_c_time std_tests/check_std_c_time.c ${TEST_TARGET_LIBR
 
 # 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})
 
diff --git a/test/csync/csync_tests/check_csync_commit.c b/test/csync/csync_tests/check_csync_commit.c
deleted file mode 100644 (file)
index 16c89bf..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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);
-}
diff --git a/test/csync/csync_tests/check_csync_commit.cpp b/test/csync/csync_tests/check_csync_commit.cpp
new file mode 100644 (file)
index 0000000..b3d7791
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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);
+}
diff --git a/test/csync/csync_tests/check_csync_create.c b/test/csync/csync_tests/check_csync_create.c
deleted file mode 100644 (file)
index 082ef26..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_create.cpp b/test/csync/csync_tests/check_csync_create.cpp
new file mode 100644 (file)
index 0000000..082ef26
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/csync_tests/check_csync_exclude.c b/test/csync/csync_tests/check_csync_exclude.c
deleted file mode 100644 (file)
index 1d145b2..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "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);
-}
diff --git a/test/csync/csync_tests/check_csync_exclude.cpp b/test/csync/csync_tests/check_csync_exclude.cpp
new file mode 100644 (file)
index 0000000..5841edd
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * 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);
+}
diff --git a/test/csync/csync_tests/check_csync_init.c b/test/csync/csync_tests/check_csync_init.c
deleted file mode 100644 (file)
index 41876d6..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_init.cpp b/test/csync/csync_tests/check_csync_init.cpp
new file mode 100644 (file)
index 0000000..c0b4cdd
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/csync_tests/check_csync_log.c b/test/csync/csync_tests/check_csync_log.c
deleted file mode 100644 (file)
index 9523d96..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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);
-}
diff --git a/test/csync/csync_tests/check_csync_log.cpp b/test/csync/csync_tests/check_csync_log.cpp
new file mode 100644 (file)
index 0000000..c5f312f
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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);
+}
diff --git a/test/csync/csync_tests/check_csync_misc.c b/test/csync/csync_tests/check_csync_misc.c
deleted file mode 100644 (file)
index 80736b8..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_misc.cpp b/test/csync/csync_tests/check_csync_misc.cpp
new file mode 100644 (file)
index 0000000..80736b8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/csync_tests/check_csync_statedb_load.c b/test/csync/csync_tests/check_csync_statedb_load.c
deleted file mode 100644 (file)
index c4b34b5..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_statedb_load.cpp b/test/csync/csync_tests/check_csync_statedb_load.cpp
new file mode 100644 (file)
index 0000000..a7bccd7
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/csync_tests/check_csync_statedb_query.c b/test/csync/csync_tests/check_csync_statedb_query.c
deleted file mode 100644 (file)
index 603195e..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_statedb_query.cpp b/test/csync/csync_tests/check_csync_statedb_query.cpp
new file mode 100644 (file)
index 0000000..843900e
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/csync_tests/check_csync_update.c b/test/csync/csync_tests/check_csync_update.c
deleted file mode 100644 (file)
index 695616b..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_update.cpp b/test/csync/csync_tests/check_csync_update.cpp
new file mode 100644 (file)
index 0000000..237687e
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * 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);
+}
diff --git a/test/csync/csync_tests/check_csync_util.c b/test/csync/csync_tests/check_csync_util.c
deleted file mode 100644 (file)
index e55c4ce..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "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);
-}
-
diff --git a/test/csync/csync_tests/check_csync_util.cpp b/test/csync/csync_tests/check_csync_util.cpp
new file mode 100644 (file)
index 0000000..0df6377
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/encoding_tests/check_encoding.c b/test/csync/encoding_tests/check_encoding.c
deleted file mode 100644 (file)
index eb761d3..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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);
-}
-
diff --git a/test/csync/encoding_tests/check_encoding.cpp b/test/csync/encoding_tests/check_encoding.cpp
new file mode 100644 (file)
index 0000000..eb761d3
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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);
+}
+
diff --git a/test/csync/log_tests/check_log.c b/test/csync/log_tests/check_log.c
deleted file mode 100644 (file)
index f5f961f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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;
-}
-
diff --git a/test/csync/log_tests/check_log.cpp b/test/csync/log_tests/check_log.cpp
new file mode 100644 (file)
index 0000000..f5f961f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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;
+}
+
index b3272b8c1754c1e9cabab2c0c9dca7b4f85534a5..045518ecc0dc2a2759418f331757b91c84ec1c19 100644 (file)
 #ifndef _TORTURE_H
 #define _TORTURE_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>
@@ -41,4 +45,8 @@ int torture_csync_verbosity(void);
  */
 int torture_run_tests(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _TORTURE_H */
diff --git a/test/csync/vio_tests/check_vio.c b/test/csync/vio_tests/check_vio.c
deleted file mode 100644 (file)
index 6d4afd7..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <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);
-}
-
diff --git a/test/csync/vio_tests/check_vio.cpp b/test/csync/vio_tests/check_vio.cpp
new file mode 100644 (file)
index 0000000..a57637e
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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);
+}
diff --git a/test/csync/vio_tests/check_vio_ext.c b/test/csync/vio_tests/check_vio_ext.c
deleted file mode 100644 (file)
index c34e708..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * 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);
-}
diff --git a/test/csync/vio_tests/check_vio_ext.cpp b/test/csync/vio_tests/check_vio_ext.cpp
new file mode 100644 (file)
index 0000000..efa37a5
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * 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);
+}
diff --git a/test/csync/vio_tests/check_vio_file_stat.c b/test/csync/vio_tests/check_vio_file_stat.c
deleted file mode 100644 (file)
index a67255e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * libcsync -- a library to sync a directory with another
- *
- * Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "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);
-}
-
diff --git a/test/csync/vio_tests/check_vio_file_stat.cpp b/test/csync/vio_tests/check_vio_file_stat.cpp
new file mode 100644 (file)
index 0000000..a67255e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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);
+}
+