diff --git a/config/csync.conf b/config/csync.conf index 7c74380016..e5d9e68c66 100644 --- a/config/csync.conf +++ b/config/csync.conf @@ -1,11 +1,8 @@ -[global] - # max diff time between two recplicas in seconds max_time_difference = 10 # max directory depth recursion max_depth = 50 -# NOT IN USE: -# sync symbolic links if the remote filesystem supports it. -#sync_symbolic_links = false +# create a copy for backup for the file which has a conflict +with_confilct_copies = no diff --git a/src/csync_config.c b/src/csync_config.c index 9dea67381c..f0ca67dbc2 100644 --- a/src/csync_config.c +++ b/src/csync_config.c @@ -20,6 +20,8 @@ #include "config.h" +#include + #include #include "c_lib.h" @@ -30,8 +32,40 @@ #define CSYNC_LOG_CATEGORY_NAME "csync.config" #include "csync_log.h" +enum csync_config_opcode_e { + COC_UNSUPPORTED = -1, + COC_MAX_TIMEDIFF, + COC_MAX_DEPTH, + COC_WITH_CONFLICT_COPY +}; + +struct csync_config_keyword_table_s { + const char *name; + enum csync_config_opcode_e opcode; +}; + +static struct csync_config_keyword_table_s csync_config_keyword_table[] = { + { "max_depth", COC_MAX_DEPTH }, + { "max_time_difference", COC_MAX_TIMEDIFF }, + { "with_confilct_copies", COC_WITH_CONFLICT_COPY }, + { NULL, COC_UNSUPPORTED } +}; + +static enum csync_config_opcode_e csync_config_get_opcode(char *keyword) { + int i; + + for (i = 0; csync_config_keyword_table[i].name != NULL; i++) { + if (strcasecmp(keyword, csync_config_keyword_table[i].name) == 0) { + return csync_config_keyword_table[i].opcode; + } + } + + return COC_UNSUPPORTED; +} + static int _csync_config_copy_default (const char *config) { int re = 0; + int rc; #ifdef _WIN32 /* For win32, try to copy the conf file from the directory from where the app was started. */ char buf[MAX_PATH+1]; @@ -59,10 +93,18 @@ static int _csync_config_copy_default (const char *config) { #else CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Copy %s/config/%s to %s", SYSCONFDIR, CSYNC_CONF_FILE, config); - if (c_copy(SYSCONFDIR "/csync/" CSYNC_CONF_FILE, config, 0644) < 0) { - if (c_copy(BINARYDIR "/config/" CSYNC_CONF_FILE, config, 0644) < 0) { + +# ifdef WITH_UNIT_TESTING + rc = c_copy(BINARYDIR "/config/" CSYNC_CONF_FILE, config, 0644); +# else + rc = 0; +# endif + + if (rc < 0) { + rc = c_copy(SYSCONFDIR "/csync/" CSYNC_CONF_FILE, config, 0644); + } + if (rc < 0) { re = -1; - } } #endif return re; @@ -102,4 +144,194 @@ int csync_config_load(CSYNC *ctx, const char *config) { return 0; } -/* vim: set ts=8 sw=2 et cindent: */ +static char *csync_config_get_cmd(char **str) { + register char *c; + char *r; + + /* Ignore leading spaces */ + for (c = *str; *c; c++) { + if (! isblank(*c)) { + break; + } + } + + if (*c == '\"') { + for (r = ++c; *c; c++) { + if (*c == '\"') { + *c = '\0'; + goto out; + } + } + } + + for (r = c; *c; c++) { + if (*c == '\n') { + *c = '\0'; + goto out; + } + } + +out: + *str = c + 1; + + return r; +} + +static char *csync_config_get_token(char **str) { + register char *c; + char *r; + + c = csync_config_get_cmd(str); + + for (r = c; *c; c++) { + if (isblank(*c)) { + *c = '\0'; + goto out; + } + } + +out: + *str = c + 1; + + return r; +} + +static int csync_config_get_int(char **str, int notfound) { + char *p, *endp; + int i; + + p = csync_config_get_token(str); + if (p && *p) { + i = strtol(p, &endp, 10); + if (p == endp) { + return notfound; + } + return i; + } + + return notfound; +} + +static const char *csync_config_get_str_tok(char **str, const char *def) { + char *p; + + p = csync_config_get_token(str); + if (p && *p) { + return p; + } + + return def; +} + +static int csync_config_get_yesno(char **str, int notfound) { + const char *p; + + p = csync_config_get_str_tok(str, NULL); + if (p == NULL) { + return notfound; + } + + if (strncasecmp(p, "yes", 3) == 0) { + return 1; + } else if (strncasecmp(p, "no", 2) == 0) { + return 0; + } + + return notfound; +} + +static int csync_config_parse_line(CSYNC *ctx, + const char *line, + unsigned int count) +{ + enum csync_config_opcode_e opcode; + char *s, *x; + char *keyword; + size_t len; + int i; + + x = s = c_strdup(line); + if (s == NULL) { + return -1; + } + + /* Remove trailing spaces */ + for (len = strlen(s) - 1; len > 0; len--) { + if (! isspace(s[len])) { + break; + } + s[len] = '\0'; + } + + keyword = csync_config_get_token(&s); + if (keyword == NULL || keyword[0] == '#' || + keyword[0] == '\0' || keyword[0] == '\n') { + free(x); + return 0; + } + + opcode = csync_config_get_opcode(keyword); + + switch (opcode) { + case COC_MAX_DEPTH: + i = csync_config_get_int(&s, 50); + if (i > 0) { + ctx->options.max_depth = i; + } + break; + case COC_MAX_TIMEDIFF: + i = csync_config_get_int(&s, 10); + if (i >= 0) { + ctx->options.max_time_difference = i; + } + break; + case COC_WITH_CONFLICT_COPY: + i = csync_config_get_yesno(&s, -1); + if (i > 0) { + ctx->options.with_conflict_copys = true; + } else { + ctx->options.with_conflict_copys = false; + } + break; + case COC_UNSUPPORTED: + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Unsupported option: %s, line: %d\n", + keyword, count); + break; + } + return 0; +} + +int csync_config_parse_file(CSYNC *ctx, const char *config) +{ + unsigned int count = 0; + char line[1024] = {0}; + char *s; + FILE *f; + + f = fopen(config, "r"); + if (f == NULL) { + return 0; + } + + CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, + "Reading configuration data from %s", + config); + + s = fgets(line, sizeof(line), f); + while (s != NULL) { + int rc; + count++; + + rc = csync_config_parse_line(ctx, line, count); + if (rc < 0) { + fclose(f); + return -1; + } + s = fgets(line, sizeof(line), f); + } + + fclose(f); + + return 0; +} diff --git a/src/csync_config.h b/src/csync_config.h index 382695baeb..942bb0b297 100644 --- a/src/csync_config.h +++ b/src/csync_config.h @@ -34,5 +34,7 @@ */ int csync_config_load(CSYNC *ctx, const char *config); +int csync_config_parse_file(CSYNC *ctx, const char *config); + #endif /* _CSYNC_X_H */ /* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */ diff --git a/tests/csync_tests/check_csync_config.c b/tests/csync_tests/check_csync_config.c index 554549de29..a7078ba98c 100644 --- a/tests/csync_tests/check_csync_config.c +++ b/tests/csync_tests/check_csync_config.c @@ -3,6 +3,7 @@ #include "torture.h" #define CSYNC_TEST 1 +#include "csync.h" #include "csync_config.c" #define TESTCONF "/tmp/check_csync1/csync.conf" @@ -51,8 +52,19 @@ static void check_csync_config_load(void **state) CSYNC *csync = *state; int rc; - rc = csync_config_load(csync, TESTCONF); + rc = _csync_config_copy_default(TESTCONF); assert_int_equal(rc, 0); + + /* Enable it, loading the default config should disable it */ + rc = csync_enable_conflictcopys(csync); + assert_int_equal(rc, 0); + + rc = csync_config_parse_file(csync, TESTCONF); + assert_int_equal(rc, 0); + + assert_false(csync->options.with_conflict_copys); + assert_int_equal(csync->options.max_time_difference, 10); + assert_int_equal(csync->options.max_depth, 50); } int torture_run_tests(void)