Add reconciler.

Currently only new directories are created. Other functions are prepared
bug not tested yet.
This commit is contained in:
Andreas Schneider 2008-05-16 17:30:57 +02:00
parent 84bb336e8e
commit 0be9a1e02b
5 changed files with 520 additions and 1 deletions

View file

@ -172,6 +172,9 @@ int main(int argc, char **argv) {
} }
if (arguments.propagate) { if (arguments.propagate) {
if (csync_propagate(csync) < 0) {
goto err;
}
} }
if (arguments.journal) { if (arguments.journal) {

View file

@ -44,10 +44,12 @@ set(csync_SRCS
csync_exclude.c csync_exclude.c
csync_journal.c csync_journal.c
csync_lock.c csync_lock.c
csync_reconcile.c
csync_time.c csync_time.c
csync_util.c csync_util.c
csync_update.c csync_update.c
csync_reconcile.c
csync_propagate.c
vio/csync_vio.c vio/csync_vio.c
vio/csync_vio_handle.c vio/csync_vio_handle.c

View file

@ -39,6 +39,7 @@
#include "csync_update.h" #include "csync_update.h"
#include "csync_reconcile.h" #include "csync_reconcile.h"
#include "csync_propagate.h"
#include "vio/csync_vio.h" #include "vio/csync_vio.h"
@ -382,6 +383,56 @@ int csync_reconcile(CSYNC *ctx) {
return 0; return 0;
} }
int csync_propagate(CSYNC *ctx) {
int rc = -1;
struct timespec start, finish;
if (ctx == NULL) {
errno = EBADF;
return -1;
}
/* Reconciliation for local replica */
clock_gettime(CLOCK_REALTIME, &start);
ctx->current = LOCAL_REPLICA;
ctx->replica = ctx->local.type;
rc = csync_propapate_files(ctx);
clock_gettime(CLOCK_REALTIME, &finish);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Propagation for local replica took %.2f seconds visiting %llu files.",
csync_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
if (rc < 0) {
return -1;
}
/* Reconciliation for local replica */
clock_gettime(CLOCK_REALTIME, &start);
ctx->current = REMOTE_REPLCIA;
ctx->replica = ctx->remote.type;
rc = csync_propapate_files(ctx);
clock_gettime(CLOCK_REALTIME, &finish);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Propagation for remote replica took %.2f seconds visiting %llu files.",
csync_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
if (rc < 0) {
return -1;
}
ctx->status |= CSYNC_PROPAGATE;
return 0;
}
static void tree_destructor(void *data) { static void tree_destructor(void *data) {
csync_file_stat_t *freedata = NULL; csync_file_stat_t *freedata = NULL;

435
src/csync_propagate.c Normal file
View file

@ -0,0 +1,435 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* vim: ts=2 sw=2 et cindent
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "csync_private.h"
#include "csync_propagate.h"
#include "vio/csync_vio.h"
#define CSYNC_LOG_CATEGORY_NAME "csync.propagator"
#include "csync_log.h"
static int csync_push_file(CSYNC *ctx, csync_file_stat_t *st) {
enum csync_replica_e srep;
enum csync_replica_e drep;
enum csync_replica_e rep_bak;
char *suri = NULL;
char *duri = NULL;
char *turi = NULL;
char *tdir = NULL;
csync_vio_handle_t *sfp = NULL;
csync_vio_handle_t *dfp = NULL;
csync_vio_file_stat_t *tstat = NULL;
char buf[MAX_XFER_BUF_SIZE] = {0};
ssize_t bread = 0;
ssize_t bwritten = 0;
struct timeval times[2];
int rc = -1;
rep_bak = ctx->replica;
switch (ctx->current) {
case LOCAL_REPLICA:
srep = ctx->local.type;
drep = ctx->remote.type;
if (asprintf(&suri, "%s/%s", ctx->local.uri, st->path) < 0) {
rc = -1;
goto out;
}
if (asprintf(&duri, "%s/%s", ctx->remote.uri, st->path) < 0) {
rc = -1;
goto out;
}
break;
case REMOTE_REPLCIA:
srep = ctx->remote.type;
drep = ctx->local.type;
if (asprintf(&suri, "%s/%s", ctx->remote.uri, st->path) < 0) {
rc = -1;
goto out;
}
if (asprintf(&duri, "%s/%s", ctx->local.uri, st->path) < 0) {
rc = -1;
goto out;
}
break;
default:
break;
}
if (asprintf(&turi, "%s.ctmp", duri) < 0) {
rc = -1;
goto out;
}
tdir = c_dirname(turi);
if (tdir == NULL) {
rc = -1;
goto out;
}
/* Open the source file */
ctx->replica = srep;
sfp = csync_vio_open(ctx, suri, O_RDONLY, 0);
if (sfp == NULL) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, error: %s", suri, strerror(errno));
rc = 1;
goto out;
}
/* Open the destination file */
ctx->replica = drep;
csync_vio_mkdir(ctx, tdir, 0755);
dfp = csync_vio_creat(ctx, turi, 0644);
if (dfp == NULL) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, error: %s", duri, strerror(errno));
rc = 1;
goto out;
}
/* copy file */
for (;;) {
ctx->replica = srep;
bread = csync_vio_read(ctx, sfp, buf, MAX_XFER_BUF_SIZE);
if (bread < 0) {
/* read error */
rc = 1;
goto out;
} else if (bread == 0) {
/* done */
break;
}
ctx->replica = drep;
bwritten = csync_vio_write(ctx, dfp, buf, MAX_XFER_BUF_SIZE);
if (bwritten < 0 || bread != bwritten) {
rc = 1;
goto out;
}
}
/* check filesize */
ctx->replica = drep;
tstat = csync_vio_file_stat_new();
if (csync_vio_stat(ctx, turi, tstat) < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, error: %s", duri, strerror(errno));
rc = 1;
goto out;
}
if (st->size != tstat->size) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s - error: incorrect filesize", turi);
rc = 1;
goto out;
}
/* override original file */
if (csync_vio_rename(ctx, turi, duri) < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, error: %s", duri, strerror(errno));
rc = 1;
goto out;
}
/* sync time */
times[0].tv_sec = times[1].tv_sec = st->modtime;
times[0].tv_usec = times[1].tv_usec = 0;
csync_vio_utimes(ctx, duri, times);
/* sync modes */
csync_vio_chmod(ctx, duri, st->mode);
st->instruction = CSYNC_INSTRUCTION_NONE;
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: PUSHED", duri);
ctx->replica = rep_bak;
rc = 0;
out:
ctx->replica = srep;
csync_vio_close(ctx, sfp);
ctx->replica = drep;
csync_vio_close(ctx, dfp);
csync_vio_file_stat_destroy(tstat);
SAFE_FREE(suri);
SAFE_FREE(duri);
SAFE_FREE(turi);
SAFE_FREE(tdir);
return rc;
}
static int csync_new_file(CSYNC *ctx, csync_file_stat_t *st) {
int rc = -1;
rc = csync_push_file(ctx, st);
return rc;
}
static int csync_sync_file(CSYNC *ctx, csync_file_stat_t *st) {
int rc = -1;
rc = csync_push_file(ctx, st);
return rc;
}
static int csync_remove_file(CSYNC *ctx, csync_file_stat_t *st) {
char *uri = NULL;
switch (ctx->current) {
case LOCAL_REPLICA:
if (asprintf(&uri, "%s/%s", ctx->local.uri, st->path) < 0) {
return -1;
}
break;
case REMOTE_REPLCIA:
if (asprintf(&uri, "%s/%s", ctx->remote.uri, st->path) < 0) {
return -1;
}
break;
default:
break;
}
csync_vio_unlink(ctx, uri);
st->instruction = CSYNC_INSTRUCTION_NONE;
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "file: %s, instruction: REMOVED", uri);
return 0;
}
static int csync_new_dir(CSYNC *ctx, csync_file_stat_t *st) {
enum csync_replica_e src;
enum csync_replica_e dest;
enum csync_replica_e replica_bak;
char *path = NULL;
struct timeval times[2];
replica_bak = ctx->replica;
switch (ctx->current) {
case LOCAL_REPLICA:
src = ctx->local.type;
dest = ctx->remote.type;
if (asprintf(&path, "%s/%s", ctx->remote.uri, st->path) < 0) {
return -1;
}
break;
case REMOTE_REPLCIA:
src = ctx->remote.type;
dest = ctx->local.type;
if (asprintf(&path, "%s/%s", ctx->local.uri, st->path) < 0) {
return -1;
}
break;
default:
break;
}
/* TODO: check return values and errno */
ctx->replica = dest;
csync_vio_mkdirs(ctx, path, 0755);
times[0].tv_sec = times[1].tv_sec = st->modtime;
times[0].tv_usec = times[1].tv_usec = 0;
csync_vio_utimes(ctx, path, times);
csync_vio_chmod(ctx, path, st->mode);
st->instruction = CSYNC_INSTRUCTION_NONE;
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "dir: %s, instruction: CREATED", path);
ctx->replica = replica_bak;
return 0;
}
static int csync_sync_dir(CSYNC *ctx, csync_file_stat_t *st) {
enum csync_replica_e src;
enum csync_replica_e dest;
enum csync_replica_e replica_bak;
char *path = NULL;
struct timeval times[2];
replica_bak = ctx->replica;
switch (ctx->current) {
case LOCAL_REPLICA:
src = ctx->local.type;
dest = ctx->remote.type;
if (asprintf(&path, "%s/%s", ctx->remote.uri, st->path) < 0) {
return -1;
}
break;
case REMOTE_REPLCIA:
src = ctx->remote.type;
dest = ctx->local.type;
if (asprintf(&path, "%s/%s", ctx->local.uri, st->path) < 0) {
return -1;
}
break;
default:
break;
}
ctx->replica = dest;
/* TODO: check return values */
times[0].tv_sec = times[1].tv_sec = st->modtime;
times[0].tv_usec = times[1].tv_usec = 0;
csync_vio_utimes(ctx, path, times);
csync_vio_chmod(ctx, path, st->mode);
st->instruction = CSYNC_INSTRUCTION_NONE;
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "dir: %s, instruction: SYNCED", path);
ctx->replica = replica_bak;
return 0;
}
static int csync_remove_dir(CSYNC *ctx, csync_file_stat_t *st) {
char *path = NULL;
switch (ctx->current) {
case LOCAL_REPLICA:
if (asprintf(&path, "%s/%s", ctx->local.uri, st->path) < 0) {
return -1;
}
break;
case REMOTE_REPLCIA:
if (asprintf(&path, "%s/%s", ctx->remote.uri, st->path) < 0) {
return -1;
}
break;
default:
break;
}
csync_vio_rmdir(ctx, path);
st->instruction = CSYNC_INSTRUCTION_NONE;
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "dir: %s, instruction: REMOVED", path);
return 0;
}
static int csync_propagation_visitor(void *obj, void *data) {
csync_file_stat_t *st = NULL;
CSYNC *ctx = NULL;
st = (csync_file_stat_t *) obj;
ctx = (CSYNC *) data;
switch(st->type) {
case CSYNC_FTW_TYPE_FILE:
switch (st->instruction) {
case CSYNC_INSTRUCTION_NEW:
break;
case CSYNC_INSTRUCTION_SYNC:
break;
case CSYNC_INSTRUCTION_REMOVE:
break;
default:
break;
}
break;
case CSYNC_FTW_TYPE_DIR:
switch (st->instruction) {
case CSYNC_INSTRUCTION_NEW:
if (csync_new_dir(ctx, st) < 0) {
goto err;
}
break;
case CSYNC_INSTRUCTION_SYNC:
if (csync_sync_dir(ctx, st) < 0) {
goto err;
}
break;
case CSYNC_INSTRUCTION_REMOVE:
/*
* We have to remove after the propagation,
* when the files have been removed and the
* dirs are emtpy.
*/
break;
default:
break;
}
break;
default:
break;
}
return 0;
err:
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "file: %s, error: %s", st->path, strerror(errno));
return -1;
}
int csync_propapate_files(CSYNC *ctx) {
c_rbtree_t *tree = NULL;
switch (ctx->current) {
case LOCAL_REPLICA:
tree = ctx->local.tree;
break;
case REMOTE_REPLCIA:
tree = ctx->remote.tree;
break;
default:
break;
}
if (c_rbtree_walk(tree, (void *) ctx, csync_propagation_visitor) < 0) {
return -1;
}
return 0;
}

28
src/csync_propagate.h Normal file
View file

@ -0,0 +1,28 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* vim: ft=c.doxygen ts=2 sw=2 et cindent
*/
#ifndef _CSYNC_PROPAGATE_H
#define _CSYNC_PROPAGATE_H
int csync_propapate_files(CSYNC *ctx);
#endif /* _CSYNC_PROPAGATE_H */