mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-26 23:28:14 +03:00
Add reconciler.
Currently only new directories are created. Other functions are prepared bug not tested yet.
This commit is contained in:
parent
84bb336e8e
commit
0be9a1e02b
5 changed files with 520 additions and 1 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
51
src/csync.c
51
src/csync.c
|
@ -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
435
src/csync_propagate.c
Normal 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
28
src/csync_propagate.h
Normal 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 */
|
Loading…
Reference in a new issue